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) { |
Free forum by Nabble | Edit this page |