001
014
015 package com.liferay.portal.security.pwd;
016
017 import com.liferay.portal.PwdEncryptorException;
018 import com.liferay.portal.kernel.util.Base64;
019 import com.liferay.portal.kernel.util.Digester;
020 import com.liferay.portal.kernel.util.DigesterUtil;
021 import com.liferay.portal.kernel.util.GetterUtil;
022 import com.liferay.portal.kernel.util.PropsKeys;
023 import com.liferay.portal.kernel.util.Validator;
024 import com.liferay.portal.util.PropsUtil;
025
026 import java.io.UnsupportedEncodingException;
027
028 import java.security.MessageDigest;
029 import java.security.NoSuchAlgorithmException;
030 import java.security.SecureRandom;
031
032 import java.util.Random;
033
034 import org.vps.crypt.Crypt;
035
036
040 public class PwdEncryptor {
041
042 public static final String PASSWORDS_ENCRYPTION_ALGORITHM =
043 GetterUtil.getString(PropsUtil.get(
044 PropsKeys.PASSWORDS_ENCRYPTION_ALGORITHM)).toUpperCase();
045
046 public static final String TYPE_CRYPT = "CRYPT";
047
048 public static final String TYPE_MD2 = "MD2";
049
050 public static final String TYPE_MD5 = "MD5";
051
052 public static final String TYPE_NONE = "NONE";
053
054 public static final String TYPE_SHA = "SHA";
055
056 public static final String TYPE_SHA_256 = "SHA-256";
057
058 public static final String TYPE_SHA_384 = "SHA-384";
059
060 public static final String TYPE_SSHA = "SSHA";
061
062 public static final char[] saltChars =
063 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"
064 .toCharArray();
065
066 public static String encrypt(String clearTextPassword)
067 throws PwdEncryptorException {
068
069 return encrypt(PASSWORDS_ENCRYPTION_ALGORITHM, clearTextPassword, null);
070 }
071
072 public static String encrypt(
073 String clearTextPassword, String currentEncryptedPassword)
074 throws PwdEncryptorException {
075
076 return encrypt(
077 PASSWORDS_ENCRYPTION_ALGORITHM, clearTextPassword,
078 currentEncryptedPassword);
079 }
080
081 public static String encrypt(
082 String algorithm, String clearTextPassword,
083 String currentEncryptedPassword)
084 throws PwdEncryptorException {
085
086 if (algorithm.equals(TYPE_CRYPT)) {
087 byte[] saltBytes = _getSaltFromCrypt(currentEncryptedPassword);
088
089 return encodePassword(algorithm, clearTextPassword, saltBytes);
090 }
091 else if (algorithm.equals(TYPE_NONE)) {
092 return clearTextPassword;
093 }
094 else if (algorithm.equals(TYPE_SSHA)) {
095 byte[] saltBytes = _getSaltFromSSHA(currentEncryptedPassword);
096
097 return encodePassword(algorithm, clearTextPassword, saltBytes);
098 }
099 else {
100 return encodePassword(algorithm, clearTextPassword, null);
101 }
102 }
103
104 protected static String encodePassword(
105 String algorithm, String clearTextPassword, byte[] saltBytes)
106 throws PwdEncryptorException {
107
108 try {
109 if (algorithm.equals(TYPE_CRYPT)) {
110 return Crypt.crypt(
111 saltBytes, clearTextPassword.getBytes(Digester.ENCODING));
112 }
113 else if (algorithm.equals(TYPE_SSHA)) {
114 byte[] clearTextPasswordBytes =
115 clearTextPassword.getBytes(Digester.ENCODING);
116
117
118
119 byte[] pwdPlusSalt =
120 new byte[clearTextPasswordBytes.length + saltBytes.length];
121
122 System.arraycopy(
123 clearTextPasswordBytes, 0, pwdPlusSalt, 0,
124 clearTextPasswordBytes.length);
125
126 System.arraycopy(
127 saltBytes, 0, pwdPlusSalt, clearTextPasswordBytes.length,
128 saltBytes.length);
129
130
131
132 MessageDigest sha1Digest = MessageDigest.getInstance("SHA-1");
133
134 byte[] pwdPlusSaltHash = sha1Digest.digest(pwdPlusSalt);
135
136
137
138 byte[] digestPlusSalt =
139 new byte[pwdPlusSaltHash.length + saltBytes.length];
140
141 System.arraycopy(
142 pwdPlusSaltHash, 0, digestPlusSalt, 0,
143 pwdPlusSaltHash.length);
144
145 System.arraycopy(
146 saltBytes, 0, digestPlusSalt, pwdPlusSaltHash.length,
147 saltBytes.length);
148
149
150
151 return Base64.encode(digestPlusSalt);
152 }
153 else {
154 return DigesterUtil.digest(algorithm, clearTextPassword);
155 }
156 }
157 catch (NoSuchAlgorithmException nsae) {
158 throw new PwdEncryptorException(nsae.getMessage());
159 }
160 catch (UnsupportedEncodingException uee) {
161 throw new PwdEncryptorException(uee.getMessage());
162 }
163 }
164
165 private static byte[] _getSaltFromCrypt(String cryptString)
166 throws PwdEncryptorException {
167
168 byte[] saltBytes = null;
169
170 try {
171 if (Validator.isNull(cryptString)) {
172
173
174
175 Random random = new Random();
176
177 int numSaltChars = saltChars.length;
178
179 StringBuilder sb = new StringBuilder();
180
181 int x = random.nextInt(Integer.MAX_VALUE) % numSaltChars;
182 int y = random.nextInt(Integer.MAX_VALUE) % numSaltChars;
183
184 sb.append(saltChars[x]);
185 sb.append(saltChars[y]);
186
187 String salt = sb.toString();
188
189 saltBytes = salt.getBytes(Digester.ENCODING);
190 }
191 else {
192
193
194
195 String salt = cryptString.substring(0, 2);
196
197 saltBytes = salt.getBytes(Digester.ENCODING);
198 }
199 }
200 catch (UnsupportedEncodingException uee) {
201 throw new PwdEncryptorException(
202 "Unable to extract salt from encrypted password: " +
203 uee.getMessage());
204 }
205
206 return saltBytes;
207 }
208
209 private static byte[] _getSaltFromSSHA(String sshaString)
210 throws PwdEncryptorException {
211
212 byte[] saltBytes = new byte[8];
213
214 if (Validator.isNull(sshaString)) {
215
216
217
218 Random random = new SecureRandom();
219
220 random.nextBytes(saltBytes);
221 }
222 else {
223
224
225
226 try {
227 byte[] digestPlusSalt = Base64.decode(sshaString);
228 byte[] digestBytes = new byte[digestPlusSalt.length - 8];
229
230 System.arraycopy(
231 digestPlusSalt, 0, digestBytes, 0, digestBytes.length);
232
233 System.arraycopy(
234 digestPlusSalt, digestBytes.length, saltBytes, 0,
235 saltBytes.length);
236 }
237 catch (Exception e) {
238 throw new PwdEncryptorException(
239 "Unable to extract salt from encrypted password: " +
240 e.getMessage());
241 }
242 }
243
244 return saltBytes;
245 }
246
247 }