You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by do...@apache.org on 2012/04/19 01:49:11 UTC

svn commit: r1327740 - /ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/HashCrypt.java

Author: doogie
Date: Wed Apr 18 23:49:10 2012
New Revision: 1327740

URL: http://svn.apache.org/viewvc?rev=1327740&view=rev
Log:
FEATURE: Add unix(glibc)-compatible password hashing, exact same output, with support for salts.

Modified:
    ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/HashCrypt.java

Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/HashCrypt.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/HashCrypt.java?rev=1327740&r1=1327739&r2=1327740&view=diff
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/HashCrypt.java (original)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/HashCrypt.java Wed Apr 18 23:49:10 2012
@@ -18,9 +18,15 @@
  *******************************************************************************/
 package org.ofbiz.base.crypto;
 
+import java.io.UnsupportedEncodingException;
 import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Random;
 
+import org.apache.commons.codec.EncoderException;
+import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.lang.RandomStringUtils;
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.GeneralRuntimeException;
 import org.ofbiz.base.util.StringUtil;
@@ -33,6 +39,84 @@ import org.ofbiz.base.util.UtilValidate;
 public class HashCrypt {
 
     public static final String module = HashCrypt.class.getName();
+    public static final String CRYPT_CHAR_SET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
+
+    public static boolean comparePassword(String crypted, String defaultCrypt, String password) {
+        try {
+            if (crypted.startsWith("{")) {
+                int typeEnd = crypted.indexOf("}");
+                String hashType = crypted.substring(1, typeEnd);
+                String hashed = crypted.substring(typeEnd + 1);
+                MessageDigest messagedigest = MessageDigest.getInstance(hashType);
+                // FIXME: should have been getBytes("UTF-8") originally
+                messagedigest.update(password.getBytes());
+                byte[] digestBytes = messagedigest.digest();
+                char[] digestChars = Hex.encodeHex(digestBytes);
+                if (hashed.equals(new String(digestChars))) {
+                    return true;
+                }
+                // This next block should be removed when all {prefix}oldFunnyHex are fixed.
+                int k = 0;
+                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;
+                }
+                if (hashed.equals(new String(digestChars))) {
+                    Debug.logWarning("Warning: detected oldFunnyHex password prefixed with a hashType; this is not valid", module);
+                    return true;
+                }
+                return false;
+            } else if (crypted.startsWith("$")) {
+                int typeEnd = crypted.indexOf("$", 1);
+                int saltEnd = crypted.indexOf("$", typeEnd + 1);
+                String hashType = crypted.substring(1, typeEnd);
+                String salt = crypted.substring(typeEnd + 1, saltEnd);
+                String hashed = crypted.substring(saltEnd + 1);
+                return hashed.equals(getCrypted(hashType, salt, password));
+            } else {
+                String hashType = defaultCrypt;
+                String hashed = crypted;
+                MessageDigest messagedigest = MessageDigest.getInstance(hashType);
+                // FIXME: should have been getBytes("UTF-8") originally
+                messagedigest.update(password.getBytes());
+                char[] digestChars = Hex.encodeHex(messagedigest.digest());
+                return hashed.equals(new String(digestChars));
+            }
+        } catch (NoSuchAlgorithmException e) {
+            throw new GeneralRuntimeException("Error while comparing password", e);
+        }
+    }
+
+    public static String cryptPassword(String hashType, String password) {
+        int saltLength = new Random().nextInt(15) + 1;
+        return cryptPassword(hashType, RandomStringUtils.random(saltLength, CRYPT_CHAR_SET), password);
+    }
+
+    public static String cryptPassword(String hashType, String salt, String password) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("$").append(hashType).append("$").append(salt).append("$");
+        sb.append(getCrypted(hashType, salt, password));
+        return sb.toString();
+    }
+
+    private static String getCrypted(String hashType, String salt, String password) {
+        try {
+            MessageDigest messagedigest = MessageDigest.getInstance(hashType);
+            messagedigest.update(salt.getBytes("UTF-8"));
+            messagedigest.update(password.getBytes("UTF-8"));
+            return Base64.encodeBase64URLSafeString(messagedigest.digest()).replace('+', '.');
+        } catch (NoSuchAlgorithmException e) {
+            throw new GeneralRuntimeException("Error while comparing password", e);
+        } catch (UnsupportedEncodingException e) {
+            throw new GeneralRuntimeException("Error while comparing password", e);
+        }
+    }
 
     public static String getDigestHash(String str) {
         return getDigestHash(str, "SHA");