001: /**
002: * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
003: *
004: * Permission is hereby granted, free of charge, to any person obtaining a copy
005: * of this software and associated documentation files (the "Software"), to deal
006: * in the Software without restriction, including without limitation the rights
007: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
008: * copies of the Software, and to permit persons to whom the Software is
009: * furnished to do so, subject to the following conditions:
010: *
011: * The above copyright notice and this permission notice shall be included in
012: * all copies or substantial portions of the Software.
013: *
014: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
017: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
019: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
020: * SOFTWARE.
021: */package com.liferay.portal.security.pwd;
022:
023: import com.liferay.portal.PwdEncryptorException;
024: import com.liferay.portal.kernel.util.Base64;
025: import com.liferay.portal.kernel.util.Digester;
026: import com.liferay.portal.kernel.util.DigesterUtil;
027: import com.liferay.portal.kernel.util.GetterUtil;
028: import com.liferay.portal.kernel.util.StringMaker;
029: import com.liferay.portal.kernel.util.Validator;
030: import com.liferay.portal.util.PropsUtil;
031:
032: import java.io.UnsupportedEncodingException;
033:
034: import java.security.MessageDigest;
035: import java.security.NoSuchAlgorithmException;
036: import java.security.SecureRandom;
037:
038: import java.util.Random;
039:
040: import org.vps.crypt.Crypt;
041:
042: /**
043: * <a href="PwdEncryptor.java.html"><b><i>View Source</i></b></a>
044: *
045: * @author Brian Wing Shun Chan
046: * @author Scott Lee
047: *
048: */
049: public class PwdEncryptor {
050:
051: public static final String PASSWORDS_ENCRYPTION_ALGORITHM = GetterUtil
052: .getString(
053: PropsUtil
054: .get(PropsUtil.PASSWORDS_ENCRYPTION_ALGORITHM))
055: .toUpperCase();
056:
057: public static final String TYPE_CRYPT = "CRYPT";
058:
059: public static final String TYPE_MD2 = "MD2";
060:
061: public static final String TYPE_MD5 = "MD5";
062:
063: public static final String TYPE_NONE = "NONE";
064:
065: public static final String TYPE_SHA = "SHA";
066:
067: public static final String TYPE_SHA_256 = "SHA-256";
068:
069: public static final String TYPE_SHA_384 = "SHA-384";
070:
071: public static final String TYPE_SSHA = "SSHA";
072:
073: public static final char[] saltChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"
074: .toCharArray();
075:
076: public static String encrypt(String clearTextPwd)
077: throws PwdEncryptorException {
078:
079: return encrypt(PASSWORDS_ENCRYPTION_ALGORITHM, clearTextPwd,
080: null);
081: }
082:
083: public static String encrypt(String clearTextPwd,
084: String currentEncPwd) throws PwdEncryptorException {
085:
086: return encrypt(PASSWORDS_ENCRYPTION_ALGORITHM, clearTextPwd,
087: currentEncPwd);
088: }
089:
090: public static String encrypt(String algorithm, String clearTextPwd,
091: String currentEncPwd) throws PwdEncryptorException {
092:
093: if (algorithm.equals(TYPE_CRYPT)) {
094: byte[] saltBytes = _getSaltFromCrypt(currentEncPwd);
095:
096: return encodePassword(algorithm, clearTextPwd, saltBytes);
097: } else if (algorithm.equals(TYPE_NONE)) {
098: return clearTextPwd;
099: } else if (algorithm.equals(TYPE_SSHA)) {
100: byte[] saltBytes = _getSaltFromSSHA(currentEncPwd);
101:
102: return encodePassword(algorithm, clearTextPwd, saltBytes);
103: } else {
104: return encodePassword(algorithm, clearTextPwd, null);
105: }
106: }
107:
108: protected static String encodePassword(String algorithm,
109: String clearTextPwd, byte[] saltBytes)
110: throws PwdEncryptorException {
111:
112: try {
113: if (algorithm.equals(TYPE_CRYPT)) {
114: return Crypt.crypt(clearTextPwd
115: .getBytes(Digester.ENCODING), saltBytes);
116: } else if (algorithm.equals(TYPE_SSHA)) {
117: byte[] clearTextPwdBytes = clearTextPwd
118: .getBytes(Digester.ENCODING);
119:
120: // Create a byte array of salt bytes appeneded to password bytes
121:
122: byte[] pwdPlusSalt = new byte[clearTextPwdBytes.length
123: + saltBytes.length];
124:
125: System.arraycopy(clearTextPwdBytes, 0, pwdPlusSalt, 0,
126: clearTextPwdBytes.length);
127:
128: System.arraycopy(saltBytes, 0, pwdPlusSalt,
129: clearTextPwdBytes.length, saltBytes.length);
130:
131: // Digest byte array
132:
133: MessageDigest sha1Digest = MessageDigest
134: .getInstance("SHA-1");
135:
136: byte[] pwdPlusSaltHash = sha1Digest.digest(pwdPlusSalt);
137:
138: // Appends salt bytes to the SHA-1 digest.
139:
140: byte[] digestPlusSalt = new byte[pwdPlusSaltHash.length
141: + saltBytes.length];
142:
143: System.arraycopy(pwdPlusSaltHash, 0, digestPlusSalt, 0,
144: pwdPlusSaltHash.length);
145:
146: System.arraycopy(saltBytes, 0, digestPlusSalt,
147: pwdPlusSaltHash.length, saltBytes.length);
148:
149: // Base64 encode and format string
150:
151: return Base64.encode(digestPlusSalt);
152: } else {
153: return DigesterUtil.digest(algorithm, clearTextPwd);
154: }
155: } catch (NoSuchAlgorithmException nsae) {
156: throw new PwdEncryptorException(nsae.getMessage());
157: } catch (UnsupportedEncodingException uee) {
158: throw new PwdEncryptorException(uee.getMessage());
159: }
160: }
161:
162: private static byte[] _getSaltFromCrypt(String cryptString)
163: throws PwdEncryptorException {
164:
165: byte[] saltBytes = new byte[2];
166:
167: try {
168: if (Validator.isNull(cryptString)) {
169:
170: // Generate random salt
171:
172: Random randomGenerator = new Random();
173:
174: int numSaltChars = saltChars.length;
175:
176: StringMaker sm = new StringMaker();
177:
178: int x = Math.abs(randomGenerator.nextInt())
179: % numSaltChars;
180: int y = Math.abs(randomGenerator.nextInt())
181: % numSaltChars;
182:
183: sm.append(saltChars[x]);
184: sm.append(saltChars[y]);
185:
186: String salt = sm.toString();
187:
188: saltBytes = salt.getBytes(Digester.ENCODING);
189: } else {
190:
191: // Extract salt from encrypted password
192:
193: String salt = cryptString.substring(0, 3);
194:
195: saltBytes = salt.getBytes(Digester.ENCODING);
196: }
197: } catch (UnsupportedEncodingException uee) {
198: throw new PwdEncryptorException(
199: "Unable to extract salt from encrypted password: "
200: + uee.getMessage());
201: }
202:
203: return saltBytes;
204: }
205:
206: private static byte[] _getSaltFromSSHA(String sshaString)
207: throws PwdEncryptorException {
208:
209: byte[] saltBytes = new byte[8];
210:
211: if (Validator.isNull(sshaString)) {
212:
213: // Generate random salt
214:
215: Random random = new SecureRandom();
216:
217: random.nextBytes(saltBytes);
218: } else {
219:
220: // Extract salt from encrypted password
221:
222: try {
223: byte[] digestPlusSalt = Base64.decode(sshaString);
224: byte[] digestBytes = new byte[digestPlusSalt.length - 8];
225:
226: System.arraycopy(digestPlusSalt, 0, digestBytes, 0,
227: digestBytes.length);
228:
229: System.arraycopy(digestPlusSalt, digestBytes.length,
230: saltBytes, 0, saltBytes.length);
231: } catch (Exception e) {
232: throw new PwdEncryptorException(
233: "Unable to extract salt from encrypted password: "
234: + e.getMessage());
235: }
236: }
237:
238: return saltBytes;
239: }
240:
241: }
|