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