From 7fc458b7be71111b4c4a6e91f7b3ed6642b104a1 Mon Sep 17 00:00:00 2001
From: Chris Ridd <chris.ridd@forgerock.com>
Date: Tue, 16 Jul 2013 14:12:20 +0000
Subject: [PATCH] CR-2005 Fix OPENDJ-1036 Cleanup passwords in memory?

---
 opends/src/server/org/opends/server/extensions/PBKDF2PasswordStorageScheme.java |   57 ++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 46 insertions(+), 11 deletions(-)

diff --git a/opends/src/server/org/opends/server/extensions/PBKDF2PasswordStorageScheme.java b/opends/src/server/org/opends/server/extensions/PBKDF2PasswordStorageScheme.java
index 37dbf7c..6c7b98a 100644
--- a/opends/src/server/org/opends/server/extensions/PBKDF2PasswordStorageScheme.java
+++ b/opends/src/server/org/opends/server/extensions/PBKDF2PasswordStorageScheme.java
@@ -177,9 +177,10 @@
   public ByteString encodePassword(ByteSequence plaintext)
          throws DirectoryException
   {
-    byte[] saltBytes     = new byte[NUM_SALT_BYTES];
+    byte[] saltBytes      = new byte[NUM_SALT_BYTES];
     byte[] digestBytes;
-    int    iterations    = config.getPBKDF2Iterations();
+    char[] plaintextChars = null;
+    int    iterations     = config.getPBKDF2Iterations();
 
     synchronized(factoryLock)
     {
@@ -187,7 +188,8 @@
       {
         random.nextBytes(saltBytes);
 
-        KeySpec spec = new PBEKeySpec(plaintext.toString().toCharArray(),
+        plaintextChars = plaintext.toString().toCharArray();
+        KeySpec spec = new PBEKeySpec(plaintextChars,
             saltBytes, iterations, SHA1_LENGTH * 8);
         digestBytes = factory.generateSecret(spec).getEncoded();
       }
@@ -203,6 +205,11 @@
         throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                      message, e);
       }
+      finally
+      {
+        if (plaintextChars != null)
+          Arrays.fill(plaintextChars, '0');
+      }
     }
     // Append the salt to the hashed value and base64-the whole thing.
     byte[] hashPlusSalt = new byte[digestBytes.length + NUM_SALT_BYTES];
@@ -304,13 +311,15 @@
                      saltLength);
 
     byte[] userDigestBytes;
+    char[] plaintextChars = null;
 
     synchronized (factoryLock)
     {
       try
       {
+        plaintextChars = plaintextPassword.toString().toCharArray();
         KeySpec spec = new PBEKeySpec(
-            plaintextPassword.toString().toCharArray(), saltBytes,
+            plaintextChars, saltBytes,
             iterations, SHA1_LENGTH * 8);
         userDigestBytes = factory.generateSecret(spec).getEncoded();
       }
@@ -323,6 +332,11 @@
 
         return false;
       }
+      finally
+      {
+        if (plaintextChars != null)
+          Arrays.fill(plaintextChars, '0');
+      }
     }
 
     return Arrays.equals(digestBytes, userDigestBytes);
@@ -360,9 +374,10 @@
   public ByteString encodeAuthPassword(ByteSequence plaintext)
          throws DirectoryException
   {
-    byte[] saltBytes     = new byte[NUM_SALT_BYTES];
+    byte[] saltBytes      = new byte[NUM_SALT_BYTES];
     byte[] digestBytes;
-    int    iterations    = config.getPBKDF2Iterations();
+    char[] plaintextChars = null;
+    int    iterations     = config.getPBKDF2Iterations();
 
     synchronized(factoryLock)
     {
@@ -370,8 +385,9 @@
       {
         random.nextBytes(saltBytes);
 
+        plaintextChars = plaintext.toString().toCharArray();
         KeySpec spec = new PBEKeySpec(
-            plaintext.toString().toCharArray(), saltBytes,
+            plaintextChars, saltBytes,
             iterations, SHA1_LENGTH * 8);
         digestBytes = factory.generateSecret(spec).getEncoded();
       }
@@ -387,6 +403,11 @@
         throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                      message, e);
       }
+      finally
+      {
+        if (plaintextChars != null)
+          Arrays.fill(plaintextChars, '0');
+      }
     }
     // Encode and return the value.
     StringBuilder authPWValue = new StringBuilder();
@@ -446,13 +467,15 @@
                      saltBytes.length);
 
     byte[] userDigestBytes;
+    char[] plaintextChars = null;
 
     synchronized (factoryLock)
     {
       try
       {
+        plaintextChars = plaintextPassword.toString().toCharArray();
         KeySpec spec = new PBEKeySpec(
-            plaintextPassword.toString().toCharArray(), saltBytes,
+            plaintextChars, saltBytes,
             iterations, SHA1_LENGTH * 8);
         userDigestBytes = factory.generateSecret(spec).getEncoded();
       }
@@ -465,6 +488,11 @@
 
         return false;
       }
+      finally
+      {
+        if (plaintextChars != null)
+          Arrays.fill(plaintextChars, '0');
+      }
     }
 
     return Arrays.equals(digestBytes, userDigestBytes);
@@ -540,16 +568,18 @@
   public static String encodeOffline(byte[] passwordBytes)
          throws DirectoryException
   {
-    byte[] saltBytes     = new byte[NUM_SALT_BYTES];
+    byte[] saltBytes      = new byte[NUM_SALT_BYTES];
     byte[] digestBytes;
-    int    iterations    = 10000;
+    char[] plaintextChars = null;
+    int    iterations     = 10000;
 
     try
     {
       SecureRandom.getInstance(SECURE_PRNG_SHA1).nextBytes(saltBytes);
 
+      plaintextChars = passwordBytes.toString().toCharArray();
       KeySpec spec = new PBEKeySpec(
-          passwordBytes.toString().toCharArray(), saltBytes,
+          plaintextChars, saltBytes,
           iterations, SHA1_LENGTH * 8);
       digestBytes = SecretKeyFactory
           .getInstance(MESSAGE_DIGEST_ALGORITHM_PBKDF2)
@@ -567,6 +597,11 @@
       throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
           message, e);
     }
+    finally
+    {
+      if (plaintextChars != null)
+        Arrays.fill(plaintextChars, '0');
+    }
 
     // Append the salt to the hashed value and base64-the whole thing.
     byte[] hashPlusSalt = new byte[digestBytes.length + NUM_SALT_BYTES];

--
Gitblit v1.10.0