001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright Andy Armstrong, andy@tagish.com
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or 1any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
018: * USA
019: *
020: * Initial developer: Andy Armstrong, andy@tagish.com
021: * --------------------------------------------------------------------------
022: * $Id: HashHelper.java 4641 2004-04-22 13:09:07Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas.security.realm.lib;
025:
026: import java.security.MessageDigest;
027: import java.security.NoSuchAlgorithmException;
028:
029: /**
030: * Methods to hash Strings. All the methods in here are static so HashHelper
031: * should never be instantiated.
032: * @author Andy Armstrong, <A HREF="mailto:andy@tagish.com">andy@tagish.com </A>
033: * @author Yann Petiot for the modifications
034: * @author Florent Benoit modifications for integration in JOnAS
035: */
036: public class HashHelper {
037:
038: /**
039: * Constant for conversion of hex to string
040: */
041: private static final int HEX_CONSTANT = 0xFF;
042:
043: /**
044: * Because of java 1.3, there are only 3 types of algorithms SHA == SHA-1
045: */
046: private static final String[] ALGORITHM = { "MD5", "MD2", "SHA-1",
047: "SHA" };
048:
049: /**
050: * Algorithm are recognized as this
051: */
052: private static final String[] SEPARATOR_ALGORITHM = { "MD5:",
053: "MD2:", "SHA-1:", "SHA:" };
054:
055: /**
056: * Algorithm are recognized as this too
057: */
058: private static final String[] SEPARATOR_ALGORITHM_BIS = { "{MD5}",
059: "{MD2}", "{SHA-1}", "{SHA}" };
060:
061: /**
062: * The default algorithm
063: */
064: public static final String DEFAULT_ALGO = "MD5";
065:
066: /**
067: * Can't make this: all the methods are static
068: */
069: private HashHelper() {
070: }
071:
072: /**
073: * In order to use a specified algorithm, it is necessary to check if it is
074: * in ALGORITHM[]
075: * @param algo the String to check if it's a valid algorithm
076: * @return boolean <ul><li>true if it's valid</li><li>false if it isn't
077: * </li></ul>
078: */
079: private static boolean isAValidAlgorithm(String algo) {
080: for (int i = 0; i < ALGORITHM.length; i++) {
081: if (algo.equalsIgnoreCase(ALGORITHM[i])) {
082: return true;
083: }
084: }
085: return false;
086: }
087:
088: /**
089: * Return the haspassword object from a string. It extracts algorithm and
090: * password from the string
091: * @param password contain password and algorithm
092: * @return the haspassword object
093: */
094: public static HashPassword getHashPassword(String password) {
095: String pass = null;
096: String algo = null;
097: //Check with the format ALGO:
098: for (int i = 0; i < ALGORITHM.length; i++) {
099: if (password.toUpperCase().startsWith(
100: SEPARATOR_ALGORITHM[i])) {
101: pass = password.substring(SEPARATOR_ALGORITHM[i]
102: .length());
103: algo = password.substring(0, SEPARATOR_ALGORITHM[i]
104: .length() - 1);
105: return new HashPassword(pass, algo);
106: }
107: if (password.toUpperCase().startsWith(
108: SEPARATOR_ALGORITHM_BIS[i])) {
109: pass = password.substring(SEPARATOR_ALGORITHM_BIS[i]
110: .length());
111: algo = password.substring(1, SEPARATOR_ALGORITHM_BIS[i]
112: .length() - 1);
113: return new HashPassword(pass, algo);
114: }
115: }
116:
117: //Return a haspassword without algorithm (clear password)
118: return new HashPassword(password, null);
119: }
120:
121: /**
122: * Turn a byte array into a char array containing a printable hex
123: * representation of the bytes. Each byte in the source array contributes a
124: * pair of hex digits to the output array.
125: * @param src the source array
126: * @return a char array containing a printable version of the source data
127: */
128: public static char[] hexDump(byte[] src) {
129: char[] buf = new char[src.length * 2];
130:
131: for (int b = 0; b < src.length; b++) {
132: String byt = Integer.toHexString(src[b] & HEX_CONSTANT);
133:
134: if (byt.length() < 2) {
135: buf[b * 2 + 0] = '0';
136: buf[b * 2 + 1] = byt.charAt(0);
137: } else {
138: buf[b * 2 + 0] = byt.charAt(0);
139: buf[b * 2 + 1] = byt.charAt(1);
140: }
141: }
142: return buf;
143: }
144:
145: /**
146: * Zero the contents of the specified array. Typically used to erase
147: * temporary storage that has held plaintext passwords so that we don't
148: * leave them lying around in memory.
149: * @param pwd the array to zero
150: */
151: public static void smudge(char[] pwd) {
152: if (pwd != null) {
153: for (int b = 0; b < pwd.length; b++) {
154: pwd[b] = 0;
155: }
156: }
157: }
158:
159: /**
160: * Zero the contents of the specified array.
161: * @param pwd the array to zero
162: */
163: public static void smudge(byte[] pwd) {
164: if (pwd != null) {
165: for (int b = 0; b < pwd.length; b++) {
166: pwd[b] = 0;
167: }
168: }
169: }
170:
171: /**
172: * Performs the default algorithm hashing on the supplied password and
173: * return a char array containing the password as a printable string. The
174: * hash is computed on the low 8 bits of each character.
175: * @param pwd The password to hash
176: * @return a string representation of the hash password
177: * @throws NoSuchAlgorithmException if this is not a valid algorithm
178: */
179: public static String hashPassword(char[] pwd)
180: throws NoSuchAlgorithmException {
181: return hashPassword(pwd, DEFAULT_ALGO);
182: }
183:
184: /**
185: * Performs an algorithm specified by the user hashing on the supplied
186: * password and return a char array containing the encrypted password as a
187: * printable string. The hash is computed on the low 8 bits of each
188: * character.
189: * @param pwd The password to hash
190: * @param algo The type of Message Digest Algorithms
191: * @return a string representation of the hash password
192: * @throws NoSuchAlgorithmException if the algorithm can not be found
193: */
194: public static String hashPassword(char[] pwd, String algo)
195: throws NoSuchAlgorithmException {
196:
197: if (!isAValidAlgorithm(algo)) {
198: throw new NoSuchAlgorithmException(
199: "Your algorithm isn't valid or not yet supported.");
200: }
201: MessageDigest md = MessageDigest.getInstance(algo);
202: md.reset();
203:
204: byte[] pwdb = new byte[pwd.length];
205: byte[] crypt = null;
206: for (int b = 0; b < pwd.length; b++) {
207: pwdb[b] = (byte) pwd[b];
208: }
209: crypt = md.digest(pwdb);
210: smudge(pwdb);
211: return new String(Base64.encode(crypt));
212: }
213:
214: /**
215: * Performs an algorithm specified by the user hashing on the supplied
216: * password and return a char array containing the encrypted password as a
217: * printable string. The hash is computed on the low 8 bits of each
218: * character.
219: * @param string The password to hash
220: * @param algo The type of Message Digest Algorithms
221: * @return a string representation of the hash password
222: * @throws NoSuchAlgorithmException if the algorithm can not be found
223: */
224: public static String hashPassword(String string, String algo)
225: throws NoSuchAlgorithmException {
226: return hashPassword(string.toCharArray(), algo);
227: }
228: }
|