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.StringPool;
024 import com.liferay.portal.kernel.util.Validator;
025 import com.liferay.portal.util.PropsUtil;
026
027 import java.io.UnsupportedEncodingException;
028
029 import java.security.MessageDigest;
030 import java.security.NoSuchAlgorithmException;
031 import java.security.SecureRandom;
032
033 import java.util.Random;
034
035 import jodd.util.BCrypt;
036
037 import org.vps.crypt.Crypt;
038
039
043 public class PwdEncryptor {
044
045 public static final String PASSWORDS_ENCRYPTION_ALGORITHM =
046 GetterUtil.getString(
047 PropsUtil.get(
048 PropsKeys.PASSWORDS_ENCRYPTION_ALGORITHM)).toUpperCase();
049
050 public static final char[] SALT_CHARS =
051 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./".
052 toCharArray();
053
054 public static final String TYPE_BCRYPT = "BCRYPT";
055
056
059 public static final String TYPE_CRYPT = "CRYPT";
060
061 public static final String TYPE_MD2 = "MD2";
062
063 public static final String TYPE_MD5 = "MD5";
064
065 public static final String TYPE_NONE = "NONE";
066
067 public static final String TYPE_SHA = "SHA";
068
069 public static final String TYPE_SHA_256 = "SHA-256";
070
071 public static final String TYPE_SHA_384 = "SHA-384";
072
073 public static final String TYPE_SSHA = "SSHA";
074
075 public static final String TYPE_UFC_CRYPT = "UFC-CRYPT";
076
077 public static String encrypt(String clearTextPassword)
078 throws PwdEncryptorException {
079
080 return encrypt(PASSWORDS_ENCRYPTION_ALGORITHM, clearTextPassword, null);
081 }
082
083 public static String encrypt(
084 String clearTextPassword, String currentEncryptedPassword)
085 throws PwdEncryptorException {
086
087 return encrypt(
088 PASSWORDS_ENCRYPTION_ALGORITHM, clearTextPassword,
089 currentEncryptedPassword);
090 }
091
092 public static String encrypt(
093 String algorithm, String clearTextPassword,
094 String currentEncryptedPassword)
095 throws PwdEncryptorException {
096
097 if (algorithm.equals(TYPE_BCRYPT)) {
098 byte[] saltBytes = _getSaltFromBCrypt(currentEncryptedPassword);
099
100 return encodePassword(algorithm, clearTextPassword, saltBytes);
101 }
102 else if (algorithm.equals(TYPE_CRYPT) ||
103 algorithm.equals(TYPE_UFC_CRYPT)) {
104
105 byte[] saltBytes = _getSaltFromCrypt(currentEncryptedPassword);
106
107 return encodePassword(algorithm, clearTextPassword, saltBytes);
108 }
109 else if (algorithm.equals(TYPE_NONE)) {
110 return clearTextPassword;
111 }
112 else if (algorithm.equals(TYPE_SSHA)) {
113 byte[] saltBytes = _getSaltFromSSHA(currentEncryptedPassword);
114
115 return encodePassword(algorithm, clearTextPassword, saltBytes);
116 }
117 else {
118 return encodePassword(algorithm, clearTextPassword, null);
119 }
120 }
121
122 protected static String encodePassword(
123 String algorithm, String clearTextPassword, byte[] saltBytes)
124 throws PwdEncryptorException {
125
126 try {
127 if (algorithm.equals(TYPE_BCRYPT)) {
128 String salt = new String(saltBytes);
129
130 return BCrypt.hashpw(clearTextPassword, salt);
131 }
132 else if (algorithm.equals(TYPE_CRYPT) ||
133 algorithm.equals(TYPE_UFC_CRYPT)) {
134
135 return Crypt.crypt(
136 saltBytes, clearTextPassword.getBytes(Digester.ENCODING));
137 }
138 else if (algorithm.equals(TYPE_SSHA)) {
139 byte[] clearTextPasswordBytes = clearTextPassword.getBytes(
140 Digester.ENCODING);
141
142
143
144 byte[] pwdPlusSalt =
145 new byte[clearTextPasswordBytes.length + saltBytes.length];
146
147 System.arraycopy(
148 clearTextPasswordBytes, 0, pwdPlusSalt, 0,
149 clearTextPasswordBytes.length);
150
151 System.arraycopy(
152 saltBytes, 0, pwdPlusSalt, clearTextPasswordBytes.length,
153 saltBytes.length);
154
155
156
157 MessageDigest sha1Digest = MessageDigest.getInstance("SHA-1");
158
159 byte[] pwdPlusSaltHash = sha1Digest.digest(pwdPlusSalt);
160
161
162
163 byte[] digestPlusSalt =
164 new byte[pwdPlusSaltHash.length + saltBytes.length];
165
166 System.arraycopy(
167 pwdPlusSaltHash, 0, digestPlusSalt, 0,
168 pwdPlusSaltHash.length);
169
170 System.arraycopy(
171 saltBytes, 0, digestPlusSalt, pwdPlusSaltHash.length,
172 saltBytes.length);
173
174
175
176 return Base64.encode(digestPlusSalt);
177 }
178 else {
179 return DigesterUtil.digest(algorithm, clearTextPassword);
180 }
181 }
182 catch (NoSuchAlgorithmException nsae) {
183 throw new PwdEncryptorException(nsae.getMessage());
184 }
185 catch (UnsupportedEncodingException uee) {
186 throw new PwdEncryptorException(uee.getMessage());
187 }
188 }
189
190 private static byte[] _getSaltFromBCrypt(String bcryptString)
191 throws PwdEncryptorException {
192
193 byte[] saltBytes = null;
194
195 try {
196 if (Validator.isNull(bcryptString)) {
197 String salt = BCrypt.gensalt();
198
199 saltBytes = salt.getBytes(StringPool.UTF8);
200 }
201 else {
202 String salt = bcryptString.substring(0, 29);
203
204 saltBytes = salt.getBytes(StringPool.UTF8);
205 }
206 }
207 catch (UnsupportedEncodingException uee) {
208 throw new PwdEncryptorException(
209 "Unable to extract salt from encrypted password: " +
210 uee.getMessage());
211 }
212
213 return saltBytes;
214 }
215
216 private static byte[] _getSaltFromCrypt(String cryptString)
217 throws PwdEncryptorException {
218
219 byte[] saltBytes = null;
220
221 try {
222 if (Validator.isNull(cryptString)) {
223
224
225
226 Random random = new Random();
227
228 int numSaltChars = SALT_CHARS.length;
229
230 StringBuilder sb = new StringBuilder();
231
232 int x = random.nextInt(Integer.MAX_VALUE) % numSaltChars;
233 int y = random.nextInt(Integer.MAX_VALUE) % numSaltChars;
234
235 sb.append(SALT_CHARS[x]);
236 sb.append(SALT_CHARS[y]);
237
238 String salt = sb.toString();
239
240 saltBytes = salt.getBytes(Digester.ENCODING);
241 }
242 else {
243
244
245
246 String salt = cryptString.substring(0, 2);
247
248 saltBytes = salt.getBytes(Digester.ENCODING);
249 }
250 }
251 catch (UnsupportedEncodingException uee) {
252 throw new PwdEncryptorException(
253 "Unable to extract salt from encrypted password: " +
254 uee.getMessage());
255 }
256
257 return saltBytes;
258 }
259
260 private static byte[] _getSaltFromSSHA(String sshaString)
261 throws PwdEncryptorException {
262
263 byte[] saltBytes = new byte[8];
264
265 if (Validator.isNull(sshaString)) {
266
267
268
269 Random random = new SecureRandom();
270
271 random.nextBytes(saltBytes);
272 }
273 else {
274
275
276
277 try {
278 byte[] digestPlusSalt = Base64.decode(sshaString);
279 byte[] digestBytes = new byte[digestPlusSalt.length - 8];
280
281 System.arraycopy(
282 digestPlusSalt, 0, digestBytes, 0, digestBytes.length);
283
284 System.arraycopy(
285 digestPlusSalt, digestBytes.length, saltBytes, 0,
286 saltBytes.length);
287 }
288 catch (Exception e) {
289 throw new PwdEncryptorException(
290 "Unable to extract salt from encrypted password: " +
291 e.getMessage());
292 }
293 }
294
295 return saltBytes;
296 }
297
298 }