1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
|
Description: Fixes CVE-2015-3250: Timing Attack vulnerability
This patch can be removed after upgrading to the version 1.0.0-M31 or later
Origin: backport, https://svn.apache.org/r1688300
--- a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/password/PasswordUtil.java
+++ b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/password/PasswordUtil.java
@@ -25,7 +25,6 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
-import java.util.Arrays;
import java.util.Date;
import org.apache.directory.api.ldap.model.constants.LdapSecurityConstants;
@@ -254,14 +253,51 @@
byte[] userPassword = PasswordUtil.encryptPassword( receivedCredentials, encryptionMethod.getAlgorithm(),
encryptionMethod.getSalt() );
- // Now, compare the two passwords.
- return Arrays.equals( userPassword, encryptedStored );
+ return compareBytes( userPassword, encryptedStored );
}
else
{
- return Arrays.equals( storedCredentials, receivedCredentials );
+ return compareBytes( receivedCredentials, storedCredentials );
}
}
+
+
+ /**
+ * Compare two byte[] in a constant time. This is necessary because using an Array.equals() is
+ * not Timing attack safe ([1], [2] and [3]), a breach that can be exploited to break some hashes.
+ *
+ * [1] https://en.wikipedia.org/wiki/Timing_attack
+ * [2] http://rdist.root.org/2009/05/28/timing-attack-in-google-keyczar-library/
+ * [3] https://cryptocoding.net/index.php/Coding_rules
+ */
+ private static boolean compareBytes( byte[] provided, byte[] stored )
+ {
+ if ( stored == null )
+ {
+ return provided == null;
+ }
+ else if ( provided == null )
+ {
+ return false;
+ }
+
+ // Now, compare the two passwords, using a constant time method
+ if ( stored.length != provided.length )
+ {
+ return false;
+ }
+
+ // loop on *every* byte in both passwords, and at the end, if one char at least is different, return false.
+ int result = 0;
+
+ for ( int i = 0; i < stored.length; i++ )
+ {
+ // If both bytes are equal, xor will be == 0, otherwise it will be != 0 and so will result.
+ result |= ( stored[i] ^ provided[i] );
+ }
+
+ return result == 0;
+ }
/**
|