Author: jonesde
Date: Tue Apr 29 18:58:00 2008
New Revision: 652224
URL: http://svn.apache.org/viewvc?rev=652224&view=rev
Log:
Some improvements for password encryption based on ml discussions: now supports
reading weird old password hex conversion, plus a more standard/correct hex
conversion using Apache Commons Codex Hex class, plus an attempt to encode
using a hash type in a prefix in the database; will always save the encoded
password using the default type specified in the config file and will put a
hash type prefix on it for portability
Modified:
ofbiz/trunk/framework/base/src/base/org/ofbiz/base/crypto/HashCrypt.java
ofbiz/trunk/framework/base/src/base/org/ofbiz/base/util/StringUtil.java
ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LoginServices.java
Modified:
ofbiz/trunk/framework/base/src/base/org/ofbiz/base/crypto/HashCrypt.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/base/org/ofbiz/base/crypto/HashCrypt.java?rev=652224&r1=652223&r2=652224&view=diff
==============================================================================
--- ofbiz/trunk/framework/base/src/base/org/ofbiz/base/crypto/HashCrypt.java
(original)
+++ ofbiz/trunk/framework/base/src/base/org/ofbiz/base/crypto/HashCrypt.java
Tue Apr 29 18:58:00 2008
@@ -20,8 +20,11 @@
import java.security.MessageDigest;
+import org.apache.commons.codec.binary.Hex;
import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.GeneralRuntimeException;
import org.ofbiz.base.util.StringUtil;
+import org.ofbiz.base.util.UtilValidate;
/**
* Utility class for doing SHA-1/MD5 One-Way Hash Encryption
@@ -39,27 +42,16 @@
if (str == null) return null;
try {
MessageDigest messagedigest = MessageDigest.getInstance(hashType);
- byte strBytes[] = str.getBytes();
+ byte[] strBytes = str.getBytes();
messagedigest.update(strBytes);
- byte digestBytes[] = messagedigest.digest();
- int k = 0;
- char digestChars[] = new char[digestBytes.length * 2];
-
- for (int l = 0; l < digestBytes.length; l++) {
- int i1 = digestBytes[l];
-
- if (i1 < 0)
- i1 = 127 + i1 * -1;
- StringUtil.encodeInt(i1, k, digestChars);
- k += 2;
- }
-
- return new String(digestChars, 0, digestChars.length);
+ byte[] digestBytes = messagedigest.digest();
+ char[] digestChars = Hex.encodeHex(digestBytes);
+
+ return "{" + hashType + "}" + new String(digestChars, 0,
digestChars.length);
} catch (Exception e) {
- Debug.logError(e, "Error while computing hash of type " +
hashType, module);
+ throw new GeneralRuntimeException("Error while computing hash of
type " + hashType, e);
}
- return str;
}
public static String getDigestHash(String str, String code, String
hashType) {
@@ -73,17 +65,48 @@
messagedigest.update(codeBytes);
byte digestBytes[] = messagedigest.digest();
- int i = 0;
+ char[] digestChars = Hex.encodeHex(digestBytes);;
+ return "{" + hashType + "}" + new String(digestChars, 0,
digestChars.length);
+ } catch (Exception e) {
+ throw new GeneralRuntimeException("Error while computing hash of
type " + hashType, e);
+ }
+ }
+
+ public static String getHashTypeFromPrefix(String hashString) {
+ if (UtilValidate.isEmpty(hashString) || hashString.charAt(0) != '{') {
+ return null;
+ }
+
+ return hashString.substring(1, hashString.indexOf('}'));
+ }
+
+ public static String removeHashTypePrefix(String hashString) {
+ if (UtilValidate.isEmpty(hashString) || hashString.charAt(0) != '{') {
+ return hashString;
+ }
+
+ return hashString.substring(hashString.indexOf('}') + 1);
+ }
+
+ public static String getDigestHashOldFunnyHexEncode(String str, String
hashType) {
+ if (str == null) return null;
+ try {
+ MessageDigest messagedigest = MessageDigest.getInstance(hashType);
+ byte strBytes[] = str.getBytes();
+
+ messagedigest.update(strBytes);
+ byte digestBytes[] = messagedigest.digest();
+ int k = 0;
char digestChars[] = new char[digestBytes.length * 2];
- for (int j = 0; j < digestBytes.length; j++) {
- int k = digestBytes[j];
+ for (int l = 0; l < digestBytes.length; l++) {
+ int i1 = digestBytes[l];
- if (k < 0) {
- k = 127 + k * -1;
+ if (i1 < 0) {
+ i1 = 127 + i1 * -1;
}
- StringUtil.encodeInt(k, i, digestChars);
- i += 2;
+ StringUtil.encodeInt(i1, k, digestChars);
+ k += 2;
}
return new String(digestChars, 0, digestChars.length);
Modified:
ofbiz/trunk/framework/base/src/base/org/ofbiz/base/util/StringUtil.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/base/org/ofbiz/base/util/StringUtil.java?rev=652224&r1=652223&r2=652224&view=diff
==============================================================================
--- ofbiz/trunk/framework/base/src/base/org/ofbiz/base/util/StringUtil.java
(original)
+++ ofbiz/trunk/framework/base/src/base/org/ofbiz/base/util/StringUtil.java Tue
Apr 29 18:58:00 2008
@@ -33,6 +33,9 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Hex;
+
/**
* Misc String Utility Functions
*
@@ -328,13 +331,7 @@
}
public static String toHexString(byte[] bytes) {
- StringBuilder buf = new StringBuilder(bytes.length * 2);
- for (byte b: bytes) {
- buf.append(hexChar[(b & 0xf0) >>> 4]);
- buf.append(hexChar[b & 0x0f]);
- }
- return buf.toString();
-
+ return new String(Hex.encodeHex(bytes));
}
public static String cleanHexString(String str) {
@@ -349,18 +346,11 @@
public static byte[] fromHexString(String str) {
str = cleanHexString(str);
- int stringLength = str.length();
- if ((stringLength & 0x1) != 0) {
- throw new IllegalArgumentException("fromHexString requires an even
number of hex characters");
- }
- byte[] b = new byte[stringLength / 2];
-
- for (int i = 0, j = 0; i < stringLength; i+= 2, j++) {
- int high = convertChar(str.charAt(i));
- int low = convertChar(str.charAt(i+1));
- b[j] = (byte) ((high << 4) | low);
+ try {
+ return Hex.decodeHex(str.toCharArray());
+ } catch (DecoderException e) {
+ throw new GeneralRuntimeException(e);
}
- return b;
}
private static char[] hexChar = { '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
Modified:
ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LoginServices.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LoginServices.java?rev=652224&r1=652223&r2=652224&view=diff
==============================================================================
--- ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LoginServices.java
(original)
+++ ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LoginServices.java
Tue Apr 29 18:58:00 2008
@@ -89,7 +89,6 @@
} else if (password == null || password.length() <= 0) {
errMsg =
UtilProperties.getMessage(resource,"loginservices.password_missing", locale);
} else {
- String realPassword = useEncryption ?
LoginServices.getPasswordHash(password) : password;
boolean repeat = true;
// starts at zero but it incremented at the beggining so in the
first pass passNumber will be 1
@@ -114,6 +113,18 @@
}
if (userLogin != null) {
+ String encodedPassword = useEncryption ?
HashCrypt.getDigestHash(password, getHashType()) : password;
+ String encodedPasswordOldFunnyHexEncode = useEncryption ?
HashCrypt.getDigestHashOldFunnyHexEncode(password, getHashType()) : password;
+ String encodedPasswordUsingDbHashType = encodedPassword;
+
+ String currentPassword =
userLogin.getString("currentPassword");
+ if (useEncryption && currentPassword != null &&
currentPassword.startsWith("{")) {
+ String dbHashType =
HashCrypt.getHashTypeFromPrefix(currentPassword);
+ if (dbHashType != null) {
+ encodedPasswordUsingDbHashType =
HashCrypt.getDigestHash(password, dbHashType);
+ }
+ }
+
String ldmStr =
UtilProperties.getPropertyValue("security.properties", "login.disable.minutes");
long loginDisableMinutes = 30;
@@ -155,7 +166,9 @@
// if the password.accept.encrypted.and.plain property
in security is set to true allow plain or encrypted passwords
// if this is a system account don't bother checking
the passwords
if ((userLogin.get("currentPassword") != null &&
-
(realPassword.equals(userLogin.getString("currentPassword")) ||
+
(HashCrypt.removeHashTypePrefix(encodedPassword).equals(userLogin.getString("currentPassword"))
||
+
HashCrypt.removeHashTypePrefix(encodedPasswordOldFunnyHexEncode).equals(userLogin.getString("currentPassword"))
||
+
HashCrypt.removeHashTypePrefix(encodedPasswordUsingDbHashType).equals(userLogin.getString("currentPassword"))
||
("true".equals(UtilProperties.getPropertyValue("security.properties",
"password.accept.encrypted.and.plain")) &&
password.equals(userLogin.getString("currentPassword")))))) {
Debug.logVerbose("[LoginServices.userLogin] :
Password Matched", module);
@@ -189,6 +202,8 @@
result.put("userLogin", userLogin);
result.put(ModelService.RESPONSE_MESSAGE,
ModelService.RESPOND_SUCCESS);
} else {
+ Debug.logInfo("Entered password [" +
encodedPassword + "], Entered password OldFunnyHexEncode [" +
encodedPasswordOldFunnyHexEncode + "], db password [" +
userLogin.getString("currentPassword") + "]", module);
+
// password is incorrect, but this may be the
result of a stale cache entry,
// so lets clear the cache and try again if this
is the first pass
if (isServiceAuth && passNumber <= 1) {
@@ -385,7 +400,7 @@
// save this password in history
GenericValue userLoginPwdHistToCreate =
delegator.makeValue("UserLoginPasswordHistory", UtilMisc.toMap("userLoginId",
userLoginId,"fromDate", nowTimestamp));
boolean useEncryption =
"true".equals(UtilProperties.getPropertyValue("security.properties",
"password.encrypt"));
- userLoginPwdHistToCreate.set("currentPassword", useEncryption ?
getPasswordHash(currentPassword) : currentPassword);
+ userLoginPwdHistToCreate.set("currentPassword", useEncryption ?
HashCrypt.getDigestHash(currentPassword, getHashType()) : currentPassword);
userLoginPwdHistToCreate.create();
}
@@ -448,7 +463,7 @@
userLoginToCreate.set("enabled", enabled);
userLoginToCreate.set("requirePasswordChange", requirePasswordChange);
userLoginToCreate.set("partyId", partyId);
- userLoginToCreate.set("currentPassword", useEncryption ?
getPasswordHash(currentPassword) : currentPassword);
+ userLoginToCreate.set("currentPassword", useEncryption ?
HashCrypt.getDigestHash(currentPassword, getHashType()) : currentPassword);
try {
EntityCondition condition = new EntityExpr("userLoginId", true,
EntityOperator.EQUALS, userLoginId, true);
@@ -552,7 +567,7 @@
return ServiceUtil.returnError(errorMessageList);
}
- userLoginToUpdate.set("currentPassword", useEncryption ?
getPasswordHash(newPassword) : newPassword, false);
+ userLoginToUpdate.set("currentPassword", useEncryption ?
HashCrypt.getDigestHash(newPassword, getHashType()) : newPassword, false);
userLoginToUpdate.set("passwordHint", passwordHint, false);
userLoginToUpdate.set("requirePasswordChange", "N");
@@ -767,7 +782,7 @@
String realPassword = currentPassword;
if (useEncryption && currentPassword != null) {
- realPassword = LoginServices.getPasswordHash(currentPassword);
+ realPassword = HashCrypt.getDigestHash(currentPassword,
getHashType());
}
// if the password.accept.encrypted.and.plain property in security
is set to true allow plain or encrypted passwords
boolean passwordMatches = currentPassword != null &&
(realPassword.equals(userLogin.getString("currentPassword")) ||
@@ -798,7 +813,7 @@
GenericDelegator delegator = userLogin.getDelegator();
String newPasswordHash = newPassword;
if (useEncryption) {
- newPasswordHash = LoginServices.getPasswordHash(newPassword);
+ newPasswordHash = HashCrypt.getDigestHash(newPassword,
getHashType());
}
try {
List pwdHistList =
delegator.findByAnd("UserLoginPasswordHistory",
UtilMisc.toMap("userLoginId",userLogin.getString("userLoginId"),"currentPassword",newPasswordHash));
@@ -850,15 +865,15 @@
}
}
- public static String getPasswordHash(String str) {
+ public static String getHashType() {
String hashType =
UtilProperties.getPropertyValue("security.properties",
"password.encrypt.hash.type");
if (hashType == null || hashType.length() == 0) {
Debug.logWarning("Password encrypt hash type is not specified in
security.properties, use SHA", module);
hashType = "SHA";
}
-
- return HashCrypt.getDigestHash(str, hashType);
+
+ return hashType;
}
public static Map getUserLoginSession(GenericValue userLogin) {