mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Chris Ridd
08.15.2014 fa06bc80b027fb99232dd16923721ad8ed649281
Fix OPENDJ-1451: Match non-default salt sizes in SMD5 passwords
The code changes were adapted from the SSHA1 class, which was previously
updated to match against different size salts.
2 files modified
61 ■■■■ changed files
opends/src/server/org/opends/server/extensions/SaltedMD5PasswordStorageScheme.java 31 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SaltedMD5PasswordStorageSchemeTestCase.java 30 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/SaltedMD5PasswordStorageScheme.java
@@ -22,7 +22,7 @@
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions Copyright 2013 ForgeRock AS
 *      Portions Copyright 2013-2014 ForgeRock AS
 */
package org.opends.server.extensions;
@@ -82,6 +82,8 @@
   */
  private static final int NUM_SALT_BYTES = 8;
  // The number of bytes MD5 algorithm produces
  private static final int MD5_LENGTH = 16;
  // The message digest that will actually be used to generate the MD5 hashes.
@@ -279,16 +281,25 @@
  {
    // Base64-decode the stored value and take the last 8 bytes as the salt.
    byte[] saltBytes = new byte[NUM_SALT_BYTES];
    byte[] digestBytes;
    byte[] digestBytes = new byte[MD5_LENGTH];
    int saltLength = 0;
    try
    {
      byte[] decodedBytes = Base64.decode(storedPassword.toString());
      int digestLength = decodedBytes.length - NUM_SALT_BYTES;
      digestBytes = new byte[digestLength];
      System.arraycopy(decodedBytes, 0, digestBytes, 0, digestLength);
      System.arraycopy(decodedBytes, digestLength, saltBytes, 0,
                       NUM_SALT_BYTES);
      saltLength = decodedBytes.length - MD5_LENGTH;
      if (saltLength <= 0)
      {
        Message message =
                ERR_PWSCHEME_INVALID_BASE64_DECODED_STORED_PASSWORD.get(
                        storedPassword.toString());
        ErrorLogger.logError(message);
        return false;
      }
      saltBytes = new byte[saltLength];
      System.arraycopy(decodedBytes, 0, digestBytes, 0, MD5_LENGTH);
      System.arraycopy(decodedBytes, MD5_LENGTH, saltBytes, 0,
                       saltLength);
    }
    catch (Exception e)
    {
@@ -306,10 +317,10 @@
    // Use the salt to generate a digest based on the provided plain-text value.
    int plainBytesLength = plaintextPassword.length();
    byte[] plainPlusSalt = new byte[plainBytesLength + NUM_SALT_BYTES];
    byte[] plainPlusSalt = new byte[plainBytesLength + saltLength];
    plaintextPassword.copyTo(plainPlusSalt);
    System.arraycopy(saltBytes, 0,plainPlusSalt, plainBytesLength,
                     NUM_SALT_BYTES);
    System.arraycopy(saltBytes, 0, plainPlusSalt, plainBytesLength,
                     saltLength);
    byte[] userDigestBytes;
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SaltedMD5PasswordStorageSchemeTestCase.java
@@ -22,6 +22,7 @@
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions Copyright 2014 ForgeRock, AS
 */
package org.opends.server.extensions;
@@ -31,7 +32,11 @@
import org.opends.server.admin.std.meta.SaltedMD5PasswordStorageSchemeCfgDefn;
import org.opends.server.admin.std.server.SaltedMD5PasswordStorageSchemeCfg;
import org.opends.server.api.PasswordStorageScheme;
import org.opends.server.schema.UserPasswordSyntax;
import org.opends.server.types.ByteString;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
/**
@@ -72,5 +77,30 @@
    scheme.initializePasswordStorageScheme(configuration);
    return scheme;
  }
  /**
   * Tests matching with a different salt size.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test
  public void testDifferentSaltSize()
    throws Exception {
    SaltedMD5PasswordStorageScheme scheme =
      new SaltedMD5PasswordStorageScheme();
    SaltedMD5PasswordStorageSchemeCfg configuration =
      AdminTestCaseUtils.getConfiguration(
        SaltedMD5PasswordStorageSchemeCfgDefn.getInstance(),
        configEntry.getEntry()
      );
    scheme.initializePasswordStorageScheme(configuration);
    // The stored value has a 12 byte salt instead of the default 8
    assertTrue(scheme.passwordMatches(ByteString.valueOf("password"),
      ByteString.valueOf("so5s1vK3oEi4uL/oVY3bqs5LRlKjgMN+u4A4bw==")));
  }
}