From e3deb8b9b6b1e1fbf53309380f5b30da848c507f Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Fri, 12 Sep 2014 14:36:55 +0000
Subject: [PATCH] CR-4097 Big code cleanup of some storage schemes.
---
opendj3-server-dev/src/server/org/opends/server/extensions/PBKDF2PasswordStorageScheme.java | 215 +++++++++++++++++++++++------------------------------
1 files changed, 94 insertions(+), 121 deletions(-)
diff --git a/opendj3-server-dev/src/server/org/opends/server/extensions/PBKDF2PasswordStorageScheme.java b/opendj3-server-dev/src/server/org/opends/server/extensions/PBKDF2PasswordStorageScheme.java
index a842995..b3a1908 100644
--- a/opendj3-server-dev/src/server/org/opends/server/extensions/PBKDF2PasswordStorageScheme.java
+++ b/opendj3-server-dev/src/server/org/opends/server/extensions/PBKDF2PasswordStorageScheme.java
@@ -62,14 +62,14 @@
* implementation uses a configurable number of iterations.
*/
public class PBKDF2PasswordStorageScheme
- extends PasswordStorageScheme<PBKDF2PasswordStorageSchemeCfg>
- implements ConfigurationChangeListener<PBKDF2PasswordStorageSchemeCfg>
+ extends PasswordStorageScheme<PBKDF2PasswordStorageSchemeCfg>
+ implements ConfigurationChangeListener<PBKDF2PasswordStorageSchemeCfg>
{
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
/** The fully-qualified name of this class. */
private static final String CLASS_NAME =
- "org.opends.server.extensions.PBKDF2PasswordStorageScheme";
+ "org.opends.server.extensions.PBKDF2PasswordStorageScheme";
/**
@@ -93,7 +93,6 @@
/** The current configuration for this storage scheme. */
private volatile PBKDF2PasswordStorageSchemeCfg config;
-
/**
* Creates a new instance of this password storage scheme. Note that no
* initialization should be performed here, as all initialization should be
@@ -107,8 +106,8 @@
/** {@inheritDoc} */
@Override
public void initializePasswordStorageScheme(
- PBKDF2PasswordStorageSchemeCfg configuration)
- throws ConfigException, InitializationException
+ PBKDF2PasswordStorageSchemeCfg configuration)
+ throws ConfigException, InitializationException
{
try
{
@@ -152,18 +151,13 @@
/** {@inheritDoc} */
@Override
public ByteString encodePassword(ByteSequence plaintext)
- throws DirectoryException
+ throws DirectoryException
{
byte[] saltBytes = new byte[NUM_SALT_BYTES];
int iterations = config.getPBKDF2Iterations();
- byte[] digestBytes = getDigestBytes(plaintext, saltBytes, iterations);
- // Append the salt to the hashed value and base64-the whole thing.
- byte[] hashPlusSalt = new byte[digestBytes.length + NUM_SALT_BYTES];
-
- System.arraycopy(digestBytes, 0, hashPlusSalt, 0, digestBytes.length);
- System.arraycopy(saltBytes, 0, hashPlusSalt, digestBytes.length,
- NUM_SALT_BYTES);
+ byte[] digestBytes = encodeWithRandomSalt(plaintext, saltBytes, iterations);
+ byte[] hashPlusSalt = concatenateHashPlusSalt(saltBytes, digestBytes);
return ByteString.valueOf(iterations + ":" + Base64.encode(hashPlusSalt));
}
@@ -171,7 +165,7 @@
/** {@inheritDoc} */
@Override
public ByteString encodePasswordWithScheme(ByteSequence plaintext)
- throws DirectoryException
+ throws DirectoryException
{
return ByteString.valueOf('{' + STORAGE_SCHEME_NAME_PBKDF2 + '}'
+ encodePassword(plaintext));
@@ -186,8 +180,8 @@
// Base64-decode the remaining value and take the last 8 bytes as the salt.
try
{
- String stored = storedPassword.toString();
- int pos = stored.indexOf(':');
+ final String stored = storedPassword.toString();
+ final int pos = stored.indexOf(':');
if (pos == -1)
{
throw new Exception();
@@ -217,43 +211,6 @@
}
}
- private boolean encodeAndMatch(ByteSequence plaintextPassword,
- final byte[] saltBytes, byte[] digestBytes, int iterations)
- {
- // Use the salt to generate a digest based on the provided plain-text value.
- int plainBytesLength = plaintextPassword.length();
- byte[] plainPlusSalt = new byte[plainBytesLength + saltBytes.length];
- plaintextPassword.copyTo(plainPlusSalt);
- System.arraycopy(saltBytes, 0, plainPlusSalt, plainBytesLength, saltBytes.length);
-
-
- char[] plaintextChars = null;
- synchronized (factoryLock)
- {
- try
- {
- plaintextChars = plaintextPassword.toString().toCharArray();
- KeySpec spec = new PBEKeySpec(
- plaintextChars, saltBytes,
- iterations, SHA1_LENGTH * 8);
- final byte[] userDigestBytes = factory.generateSecret(spec).getEncoded();
- return Arrays.equals(digestBytes, userDigestBytes);
- }
- catch (Exception e)
- {
- logger.traceException(e);
- return false;
- }
- finally
- {
- if (plaintextChars != null)
- {
- Arrays.fill(plaintextChars, '0');
- }
- }
- }
- }
-
/** {@inheritDoc} */
@Override
public boolean supportsAuthPasswordSyntax()
@@ -271,11 +228,11 @@
/** {@inheritDoc} */
@Override
public ByteString encodeAuthPassword(ByteSequence plaintext)
- throws DirectoryException
+ throws DirectoryException
{
byte[] saltBytes = new byte[NUM_SALT_BYTES];
int iterations = config.getPBKDF2Iterations();
- byte[] digestBytes = getDigestBytes(plaintext, saltBytes, iterations);
+ byte[] digestBytes = encodeWithRandomSalt(plaintext, saltBytes, iterations);
// Encode and return the value.
return ByteString.valueOf(AUTH_PASSWORD_SCHEME_NAME_PBKDF2 + '$'
@@ -283,41 +240,6 @@
+ Base64.encode(digestBytes));
}
- private byte[] getDigestBytes(ByteSequence plaintext, byte[] saltBytes,
- int iterations) throws DirectoryException
- {
- char[] plaintextChars = null;
- synchronized (factoryLock)
- {
- try
- {
- random.nextBytes(saltBytes);
-
- plaintextChars = plaintext.toString().toCharArray();
- KeySpec spec = new PBEKeySpec(
- plaintextChars, saltBytes,
- iterations, SHA1_LENGTH * 8);
- return factory.generateSecret(spec).getEncoded();
- }
- catch (Exception e)
- {
- logger.traceException(e);
-
- LocalizableMessage message = ERR_PWSCHEME_CANNOT_ENCODE_PASSWORD.get(
- CLASS_NAME, getExceptionMessage(e));
- throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
- message, e);
- }
- finally
- {
- if (plaintextChars != null)
- {
- Arrays.fill(plaintextChars, '0');
- }
- }
- }
- }
-
/** {@inheritDoc} */
@Override
public boolean authPasswordMatches(ByteSequence plaintextPassword,
@@ -352,7 +274,7 @@
/** {@inheritDoc} */
@Override
public ByteString getPlaintextValue(ByteSequence storedPassword)
- throws DirectoryException
+ throws DirectoryException
{
LocalizableMessage message =
ERR_PWSCHEME_NOT_REVERSIBLE.get(STORAGE_SCHEME_NAME_PBKDF2);
@@ -363,7 +285,7 @@
@Override
public ByteString getAuthPasswordPlaintextValue(String authInfo,
String authValue)
- throws DirectoryException
+ throws DirectoryException
{
LocalizableMessage message =
ERR_PWSCHEME_NOT_REVERSIBLE.get(AUTH_PASSWORD_SCHEME_NAME_PBKDF2);
@@ -386,54 +308,56 @@
* user password).
*
* @param passwordBytes The bytes that make up the clear-text password.
- *
* @return The encoded password string, including the scheme name in curly
* braces.
- *
* @throws DirectoryException If a problem occurs during processing.
*/
public static String encodeOffline(byte[] passwordBytes)
- throws DirectoryException
+ throws DirectoryException
{
byte[] saltBytes = new byte[NUM_SALT_BYTES];
int iterations = 10000;
- byte[] digestBytes = getDigestBytes(passwordBytes, saltBytes, iterations);
- // Append the salt to the hashed value and base64-the whole thing.
- byte[] hashPlusSalt = new byte[digestBytes.length + NUM_SALT_BYTES];
+ final ByteString password = ByteString.wrap(passwordBytes);
+ byte[] digestBytes = encodeWithRandomSalt(password, saltBytes, iterations);
+ byte[] hashPlusSalt = concatenateHashPlusSalt(saltBytes, digestBytes);
- System.arraycopy(digestBytes, 0, hashPlusSalt, 0, digestBytes.length);
- System.arraycopy(saltBytes, 0, hashPlusSalt, digestBytes.length,
- NUM_SALT_BYTES);
-
- return '{' + STORAGE_SCHEME_NAME_PBKDF2 + '}' + iterations + ':' +
- Base64.encode(hashPlusSalt);
+ return '{' + STORAGE_SCHEME_NAME_PBKDF2 + '}' + iterations + ':'
+ + Base64.encode(hashPlusSalt);
}
- private static byte[] getDigestBytes(byte[] plaintext, byte[] saltBytes,
+ private static byte[] encodeWithRandomSalt(ByteString plaintext, byte[] saltBytes,
int iterations) throws DirectoryException
{
- char[] plaintextChars = null;
try
{
- SecureRandom.getInstance(SECURE_PRNG_SHA1).nextBytes(saltBytes);
-
- plaintextChars = plaintext.toString().toCharArray();
- KeySpec spec = new PBEKeySpec(
- plaintextChars, saltBytes,
- iterations, SHA1_LENGTH * 8);
- return SecretKeyFactory
- .getInstance(MESSAGE_DIGEST_ALGORITHM_PBKDF2)
- .generateSecret(spec).getEncoded();
+ final SecureRandom random = SecureRandom.getInstance(SECURE_PRNG_SHA1);
+ final SecretKeyFactory factory = SecretKeyFactory.getInstance(MESSAGE_DIGEST_ALGORITHM_PBKDF2);
+ return encodeWithRandomSalt(plaintext, saltBytes, iterations, random, factory);
+ }
+ catch (DirectoryException e)
+ {
+ throw e;
}
catch (Exception e)
{
- logger.traceException(e);
+ throw cannotEncodePassword(e);
+ }
+ }
- LocalizableMessage message = ERR_PWSCHEME_CANNOT_ENCODE_PASSWORD.get(
- CLASS_NAME, getExceptionMessage(e));
- throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
- message, e);
+ private static byte[] encodeWithSalt(ByteSequence plaintext, byte[] saltBytes,
+ int iterations, final SecretKeyFactory factory) throws DirectoryException
+ {
+ final char[] plaintextChars = plaintext.toString().toCharArray();
+ try
+ {
+ KeySpec spec =
+ new PBEKeySpec(plaintextChars, saltBytes, iterations, SHA1_LENGTH * 8);
+ return factory.generateSecret(spec).getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw cannotEncodePassword(e);
}
finally
{
@@ -444,4 +368,53 @@
}
}
+ private boolean encodeAndMatch(ByteSequence plaintext, byte[] saltBytes,
+ byte[] digestBytes, int iterations)
+ {
+ synchronized (factoryLock)
+ {
+ try
+ {
+ final byte[] userDigestBytes =
+ encodeWithSalt(plaintext, saltBytes, iterations, factory);
+ return Arrays.equals(digestBytes, userDigestBytes);
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ }
+ }
+
+ private byte[] encodeWithRandomSalt(ByteSequence plaintext, byte[] saltBytes,
+ int iterations) throws DirectoryException
+ {
+ synchronized (factoryLock)
+ {
+ return encodeWithRandomSalt(plaintext, saltBytes, iterations, random, factory);
+ }
+ }
+
+ private static byte[] encodeWithRandomSalt(ByteSequence plaintext, byte[] saltBytes,
+ int iterations, SecureRandom random, final SecretKeyFactory factory) throws DirectoryException
+ {
+ random.nextBytes(saltBytes);
+ return encodeWithSalt(plaintext, saltBytes, iterations, factory);
+ }
+
+ private static DirectoryException cannotEncodePassword(Exception e)
+ {
+ logger.traceException(e);
+
+ LocalizableMessage message = ERR_PWSCHEME_CANNOT_ENCODE_PASSWORD.get(CLASS_NAME, getExceptionMessage(e));
+ return new DirectoryException(DirectoryServer.getServerErrorResultCode(), message, e);
+ }
+
+ private static byte[] concatenateHashPlusSalt(byte[] saltBytes, byte[] digestBytes) {
+ final byte[] hashPlusSalt = new byte[digestBytes.length + NUM_SALT_BYTES];
+ System.arraycopy(digestBytes, 0, hashPlusSalt, 0, digestBytes.length);
+ System.arraycopy(saltBytes, 0, hashPlusSalt, digestBytes.length, NUM_SALT_BYTES);
+ return hashPlusSalt;
+ }
+
}
--
Gitblit v1.10.0