This is an automated email from the ASF dual-hosted git repository.

mridulpathak pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git


The following commit(s) were added to refs/heads/trunk by this push:
     new b40ed9a861 Fixed: HashCrypt compares non-PBKDF2 password hashes with 
variable-time String.equals() (OFBIZ-13615)
b40ed9a861 is described below

commit b40ed9a861e20ef6f37555d3e8f4fb6225e7e8d9
Author: Mridul Pathak <[email protected]>
AuthorDate: Sat Sep 26 17:33:06 2026 +0530

    Fixed: HashCrypt compares non-PBKDF2 password hashes with variable-time 
String.equals() (OFBIZ-13615)
    
    doCompareTypePrefix(), doComparePosix() and doCompareBare() compared the 
computed hash to the stored hash with String.equals(), which returns at the 
first differing character. They now use MessageDigest.isEqual() through a small 
helper, matching the constant-time comparison already used by 
doComparePbkdf2(). The result of every comparison is unchanged.
---
 .../main/java/org/apache/ofbiz/base/crypto/HashCrypt.java | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git 
a/framework/base/src/main/java/org/apache/ofbiz/base/crypto/HashCrypt.java 
b/framework/base/src/main/java/org/apache/ofbiz/base/crypto/HashCrypt.java
index 4be9e7d564..f425b2bf8f 100644
--- a/framework/base/src/main/java/org/apache/ofbiz/base/crypto/HashCrypt.java
+++ b/framework/base/src/main/java/org/apache/ofbiz/base/crypto/HashCrypt.java
@@ -85,11 +85,11 @@ public class HashCrypt {
         byte[] digestBytes = messagedigest.digest();
         char[] digestChars = Hex.encodeHex(digestBytes);
         String checkCrypted = new String(digestChars);
-        if (hashed.equals(checkCrypted)) {
+        if (isEqual(hashed, checkCrypted)) {
             return true;
         }
         // This next block should be removed when all {prefix}oldFunnyHex are 
fixed.
-        if (hashed.equals(oldFunnyHex(digestBytes))) {
+        if (isEqual(hashed, oldFunnyHex(digestBytes))) {
             Debug.logWarning("Warning: detected oldFunnyHex password prefixed 
with a hashType; this is not valid, please update the value "
                     + "in the database with ({%s}%s)", MODULE, hashType, 
checkCrypted);
             return true;
@@ -103,7 +103,7 @@ public class HashCrypt {
         String hashType = crypted.substring(1, typeEnd);
         String salt = crypted.substring(typeEnd + 1, saltEnd);
         String hashed = crypted.substring(saltEnd + 1);
-        return hashed.equals(getCryptedBytes(hashType, salt, bytes));
+        return isEqual(hashed, getCryptedBytes(hashType, salt, bytes));
     }
 
     private static boolean doCompareBare(String crypted, String defaultCrypt, 
byte[] bytes) {
@@ -111,7 +111,14 @@ public class HashCrypt {
         String hashed = crypted;
         MessageDigest messagedigest = getMessageDigest(hashType);
         messagedigest.update(bytes);
-        return hashed.equals(oldFunnyHex(messagedigest.digest()));
+        return isEqual(hashed, oldFunnyHex(messagedigest.digest()));
+    }
+
+    /**
+     * Compares two hash strings in constant time, so the comparison does not 
stop at the first differing character.
+     */
+    private static boolean isEqual(String hashed, String computed) {
+        return MessageDigest.isEqual(hashed.getBytes(StandardCharsets.UTF_8), 
computed.getBytes(StandardCharsets.UTF_8));
     }
 
     /*

Reply via email to