svn commit: r652224 - in /ofbiz/trunk/framework: base/src/base/org/ofbiz/base/crypto/HashCrypt.java base/src/base/org/ofbiz/base/util/StringUtil.java common/src/org/ofbiz/common/login/LoginServices.java

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r652224 - in /ofbiz/trunk/framework: base/src/base/org/ofbiz/base/crypto/HashCrypt.java base/src/base/org/ofbiz/base/util/StringUtil.java common/src/org/ofbiz/common/login/LoginServices.java

jonesde
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) {