From 7d8b8ce1db386a7f930aa8680ade1dee876b8994 Mon Sep 17 00:00:00 2001
From: Jean-Noël Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Fri, 01 Jul 2016 12:10:44 +0000
Subject: [PATCH] CryptoManagerImpl: cleanly separated cipher and MAC functions

---
 opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java |  468 +++++++++++++++++++++++++---------------------------------
 1 files changed, 204 insertions(+), 264 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java b/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java
index a70073e..6d74601 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java
@@ -113,8 +113,6 @@
 import org.opends.server.util.ServerConstants;
 import org.opends.server.util.StaticUtils;
 
-import net.jcip.annotations.GuardedBy;
-
 import static org.opends.messages.CoreMessages.*;
 import static org.opends.server.config.ConfigConstants.*;
 import static org.opends.server.protocols.internal.InternalClientConnection.*;
@@ -163,13 +161,10 @@
 
   /** The DN of the local truststore backend. */
   private static DN localTruststoreDN;
-
   /** The DN of the ADS instance keys container. */
   private static DN instanceKeysDN;
-
   /** The DN of the ADS secret keys container. */
   private static DN secretKeysDN;
-
   /** The DN of the ADS servers container. */
   private static DN serversDN;
 
@@ -190,44 +185,8 @@
    */
   private static final int CIPHERTEXT_PROLOGUE_VERSION = 1 ;
 
-  private final Lock cipherKeyEntryLock = new ReentrantLock();
-  /**
-   * The map from encryption key ID to CipherKeyEntry (cache). The cache is
-   * accessed by methods that request by ID, publish, and import keys.
-   * It contains all keys, even compromised, to be able to access old data.
-   */
-  @GuardedBy("cipherKeyEntryLock")
-  private final Map<KeyEntryID, CipherKeyEntry> cipherKeyEntryCache = new ConcurrentHashMap<>();
-  /**
-   * Keys imported or generated to use for encryption, mapped by transformation/key length.
-   * Only one cipher key per transformation/key length (used as a key for the map, for example
-   * "AES/CBC/PKCS5Padding/128") is recorded, the last in temporal order to be imported or
-   * generated.
-   * Cipher keys belonging to this map also belong in the cache Map, they are used as keys for
-   * encrypting new data.
-   *
-   */
-  @GuardedBy("cipherKeyEntryLock")
-  private final Map<String, CipherKeyEntry> mostRecentCipherKeys = new ConcurrentHashMap<>();
-
-  private final Lock macKeyEntryLock = new ReentrantLock();
-  /**
-   * The map from encryption key ID to MacKeyEntry (cache). The cache is
-   * accessed by methods that request by ID, publish, and import keys.
-   * It contains all keys, even compromised, to be able to access old data.
-   */
-  @GuardedBy("macKeyEntryLock")
-  private final Map<KeyEntryID, MacKeyEntry> macKeyEntryCache = new ConcurrentHashMap<>();
-  /**
-   * Keys imported or generated for MAC operations, mapped by algorithm/key length.
-   * Only one MAC key per algorithm/key length (used as a key for the map, for example
-   * "HmacSHA1/128") is recorded, the last in temporal order to be imported or
-   * generated.
-   * MAC keys belonging to this map also belong in the cache Map, they are
-   * used for computing new MAC digests.
-   */
-  @GuardedBy("macKeyEntryLock")
-  private final Map<String, MacKeyEntry> mostRecentMacKeys = new ConcurrentHashMap<>();
+  private final CipherKeyManager cipherCryptoManager = new CipherKeyManager();
+  private final MacKeyManager macCryptoManager = new MacKeyManager();
 
   /** The preferred key wrapping transformation. */
   private String preferredKeyWrappingTransformation;
@@ -241,13 +200,11 @@
 
   /** The preferred cipher for the Directory Server. */
   private String preferredCipherTransformation;
-
   /** The preferred key length for the preferred cipher. */
   private int preferredCipherTransformationKeyLengthBits;
 
   /** The preferred MAC algorithm for the Directory Server. */
   private String preferredMACAlgorithm;
-
   /** The preferred key length for the preferred MAC algorithm. */
   private int preferredMACAlgorithmKeyLengthBits;
 
@@ -257,13 +214,10 @@
 
   /** The names of the local certificates to use for SSL. */
   private final SortedSet<String> sslCertNicknames;
-
   /** Whether replication sessions use SSL encryption. */
   private final boolean sslEncryption;
-
   /** The set of SSL protocols enabled or null for the default set. */
   private final SortedSet<String> sslProtocols;
-
   /** The set of SSL cipher suites enabled or null for the default set. */
   private final SortedSet<String> sslCipherSuites;
 
@@ -338,8 +292,7 @@
     boolean isAcceptable = true;
 
     // Requested digest validation.
-    String requestedDigestAlgorithm =
-         cfg.getDigestAlgorithm();
+    String requestedDigestAlgorithm = cfg.getDigestAlgorithm();
     if (! requestedDigestAlgorithm.equals(this.preferredDigestAlgorithm))
     {
       try{
@@ -355,10 +308,8 @@
     }
 
     // Requested encryption cipher validation.
-    String requestedCipherTransformation =
-         cfg.getCipherTransformation();
-    Integer requestedCipherTransformationKeyLengthBits =
-         cfg.getCipherKeyLength();
+    String requestedCipherTransformation = cfg.getCipherTransformation();
+    Integer requestedCipherTransformationKeyLengthBits = cfg.getCipherKeyLength();
     if (! requestedCipherTransformation.equals(
             this.preferredCipherTransformation) ||
         requestedCipherTransformationKeyLengthBits !=
@@ -371,7 +322,7 @@
       }
       else {
         try {
-          CipherKeyEntry.generateKeyEntry(null,
+          cipherCryptoManager.generateKeyEntry(
                   requestedCipherTransformation,
                   requestedCipherTransformationKeyLengthBits);
         }
@@ -387,15 +338,13 @@
 
     // Requested MAC algorithm validation.
     String requestedMACAlgorithm = cfg.getMacAlgorithm();
-    Integer requestedMACAlgorithmKeyLengthBits =
-         cfg.getMacKeyLength();
+    Integer requestedMACAlgorithmKeyLengthBits = cfg.getMacKeyLength();
     if (!requestedMACAlgorithm.equals(this.preferredMACAlgorithm) ||
          requestedMACAlgorithmKeyLengthBits !=
               this.preferredMACAlgorithmKeyLengthBits)
     {
       try {
-        MacKeyEntry.generateKeyEntry(
-             null,
+        macCryptoManager.generateKeyEntry(
              requestedMACAlgorithm,
              requestedMACAlgorithmKeyLengthBits);
       }
@@ -409,8 +358,7 @@
     }
     // Requested secret key wrapping cipher and validation. Validation
     // depends on MAC cipher for secret key.
-    String requestedKeyWrappingTransformation
-            = cfg.getKeyWrappingTransformation();
+    String requestedKeyWrappingTransformation = cfg.getKeyWrappingTransformation();
     if (! requestedKeyWrappingTransformation.equals(
             this.preferredKeyWrappingTransformation)) {
       if (3 != requestedKeyWrappingTransformation.split("/", 0).length) {
@@ -439,7 +387,7 @@
                 "lplX1Iq+BrQJAmteiPtwhdZD+EIghe51CaseImjlLlY2ZK8w==";
           final byte[] certificate = Base64.decode(certificateBase64);
           final String keyID = getInstanceKeyID(certificate);
-          final SecretKey macKey = MacKeyEntry.generateKeyEntry(null,
+          final SecretKey macKey = macCryptoManager.generateKeyEntry(
                   requestedMACAlgorithm,
                   requestedMACAlgorithmKeyLengthBits).getSecretKey();
           encodeSymmetricKeyAttribute(requestedKeyWrappingTransformation,
@@ -1084,7 +1032,7 @@
       // Find the symmetric key value that was wrapped using our instance key.
       SecretKey secretKey = decodeSymmetricKeyAttribute(symmetricKeys);
       if (null != secretKey) {
-        CipherKeyEntry.importCipherKeyEntry(this, keyID, transformation,
+        cipherCryptoManager.importCipherKeyEntry(keyID, transformation,
                 secretKey, keyLengthBits, ivLengthBits, isCompromised);
         return;
       }
@@ -1097,7 +1045,7 @@
                 ERR_CRYPTOMGR_IMPORT_KEY_ENTRY_FAILED_TO_DECODE.get(entry.getName()));
       }
       secretKey = decodeSymmetricKeyAttribute(symmetricKey);
-      CipherKeyEntry.importCipherKeyEntry(this, keyID, transformation,
+      cipherCryptoManager.importCipherKeyEntry(keyID, transformation,
               secretKey, keyLengthBits, ivLengthBits, isCompromised);
 
       writeValueToEntry(entry, symmetricKey);
@@ -1169,7 +1117,7 @@
       SecretKey secretKey = decodeSymmetricKeyAttribute(symmetricKeys);
       if (secretKey != null)
       {
-        MacKeyEntry.importMacKeyEntry(this, keyID, algorithm, secretKey, keyLengthBits, isCompromised);
+        macCryptoManager.importMacKeyEntry(keyID, algorithm, secretKey, keyLengthBits, isCompromised);
         return;
       }
 
@@ -1181,7 +1129,7 @@
              ERR_CRYPTOMGR_IMPORT_KEY_ENTRY_FAILED_TO_DECODE.get(entry.getName()));
       }
       secretKey = decodeSymmetricKeyAttribute(symmetricKey);
-      MacKeyEntry.importMacKeyEntry(this, keyID, algorithm, secretKey, keyLengthBits, isCompromised);
+      macCryptoManager.importMacKeyEntry(keyID, algorithm, secretKey, keyLengthBits, isCompromised);
 
       writeValueToEntry(entry, symmetricKey);
     }
@@ -1503,22 +1451,30 @@
     attrs.put(type, Attributes.createAsList(type, value));
   }
 
-  /**
-   * This class corresponds to the cipher key entry in ADS. It is
-   * used in the local cache of key entries that have been requested
-   * by CryptoManager clients.
-   */
-  private static class CipherKeyEntry extends SecretKeyEntry
+  /** Encapsulates cipher-related functions of the {@link CryptoManager}. */
+  private final class CipherKeyManager
   {
+    /** Ensures atomic updates to both {@link #cipherKeyEntryCache} and {@link #mostRecentCipherKeys}. */
+    private final Lock cipherKeyEntryLock = new ReentrantLock();
+    /**
+     * The map from encryption key ID to CipherKeyEntry (cache). The cache is accessed by methods
+     * that request by ID, publish, and import keys. It contains all keys, even compromised, to be
+     * able to access old data.
+     */
+    private final Map<KeyEntryID, CipherKeyEntry> cipherKeyEntryCache = new ConcurrentHashMap<>();
+    /**
+     * Keys imported or generated to use for encryption, mapped by transformation/key length. Only
+     * one cipher key per transformation/key length (used as a key for the map, for example
+     * "AES/CBC/PKCS5Padding/128") is recorded, the last in temporal order to be imported or
+     * generated. Cipher keys belonging to this map also belong in the cache Map, they are used as
+     * keys for encrypting new data.
+     */
+    private final Map<String, CipherKeyEntry> mostRecentCipherKeys = new ConcurrentHashMap<>();
+
     /**
      * This method generates a key according to the key parameters,
      * and creates a key entry and registers it in the supplied map.
      *
-     * @param  cryptoManager The CryptoManager instance for which the
-     * key is to be generated. Pass {@code null} as the argument to
-     * this parameter in order to validate a proposed cipher
-     * transformation and key length without publishing the key.
-     *
      * @param transformation  The cipher transformation for which the
      * key is to be produced. This argument is required.
      *
@@ -1530,19 +1486,26 @@
      * @throws CryptoManagerException If there is a problem
      * instantiating a Cipher object in order to validate the supplied
      * parameters when creating a new entry.
-     *
-     * @see MacKeyEntry#getMacKeyEntryOrNull(CryptoManagerImpl, String, int)
      */
-    public static CipherKeyEntry generateKeyEntry(
-            final CryptoManagerImpl cryptoManager,
-            final String transformation,
-            final int keyLengthBits)
+    private CipherKeyEntry generateAndPublishKeyEntry(final String transformation, final int keyLengthBits)
     throws CryptoManagerException {
-      final Map<KeyEntryID, CipherKeyEntry> cache =
-          cryptoManager != null ? cryptoManager.cipherKeyEntryCache : null;
+      CipherKeyEntry keyEntry = generateKeyEntry(transformation, keyLengthBits);
 
-      CipherKeyEntry keyEntry = new CipherKeyEntry(transformation,
-              keyLengthBits);
+      /* The key is published to ADS before making it available in the local
+         cache with the intention to ensure the key is persisted before use.
+         This ordering allows the possibility that data encrypted at another
+         instance could arrive at this instance before the key is available in
+         the local cache to decode the data. */
+      publishKeyEntry(keyEntry);
+      cipherKeyEntryCache.put(keyEntry.getKeyID(), keyEntry);
+
+      return keyEntry;
+    }
+
+    private CipherKeyEntry generateKeyEntry(final String transformation, final int keyLengthBits)
+        throws CryptoManagerException
+    {
+      CipherKeyEntry keyEntry = new CipherKeyEntry(transformation, keyLengthBits);
 
       // Validate the key entry. Record the initialization vector length, if any
       final Cipher cipher = getCipher(keyEntry, Cipher.ENCRYPT_MODE, null);
@@ -1550,32 +1513,17 @@
       final byte[] iv = cipher.getIV();
       keyEntry.setIVLengthBits(null == iv ? 0 : iv.length * Byte.SIZE);
 
-      if (null != cache) {
-        /* The key is published to ADS before making it available in the local
-           cache with the intention to ensure the key is persisted before use.
-           This ordering allows the possibility that data encrypted at another
-           instance could arrive at this instance before the key is available in
-           the local cache to decode the data. */
-        publishKeyEntry(cryptoManager, keyEntry);
-        cache.put(keyEntry.getKeyID(), keyEntry);
-      }
-
       return keyEntry;
     }
 
 
     /**
      * Publish a new cipher key by adding an entry into ADS.
-     * @param  cryptoManager The CryptoManager instance for which the
-     *                       key was generated.
      * @param  keyEntry      The cipher key to be published.
      * @throws CryptoManagerException
-     *                       If the key entry could not be added to
-     *                       ADS.
+     *                       If the key entry could not be added to ADS.
      */
-    private static void publishKeyEntry(CryptoManagerImpl cryptoManager,
-                                        CipherKeyEntry keyEntry)
-         throws CryptoManagerException
+    private void publishKeyEntry(CipherKeyEntry keyEntry) throws CryptoManagerException
     {
       // Construct the key entry DN.
       ByteString distinguishedValue =
@@ -1596,7 +1544,7 @@
           String.valueOf(keyEntry.getIVLengthBits()));
       putSingleValueAttribute(userAttrs, attrKeyLength,
           String.valueOf(keyEntry.getKeyLengthBits()));
-      userAttrs.put(attrSymmetricKey, buildSymetricKeyAttributes(cryptoManager, keyEntry.getSecretKey()));
+      userAttrs.put(attrSymmetricKey, buildSymetricKeyAttributes(keyEntry.getSecretKey()));
 
       // Create the entry.
       LinkedHashMap<AttributeType, List<Attribute>> opAttrs = new LinkedHashMap<>(0);
@@ -1615,7 +1563,6 @@
      * validates it, and registers it in the supplied map.
      * The anticipated use of this method is to import a key entry from ADS.
      *
-     * @param cryptoManager  The CryptoManager instance.
      * @param keyIDString  The key identifier.
      * @param transformation The cipher transformation for which the key entry was produced.
      * @param secretKey  The cipher key.
@@ -1631,8 +1578,7 @@
      * @throws CryptoManagerException  In case of an error in the
      * parameters used to initialize or validate the key entry.
      */
-    public static CipherKeyEntry importCipherKeyEntry(
-            final CryptoManagerImpl cryptoManager,
+    private CipherKeyEntry importCipherKeyEntry(
             final String keyIDString,
             final String transformation,
             final SecretKey secretKey,
@@ -1646,7 +1592,7 @@
       final KeyEntryID keyID = new KeyEntryID(keyIDString);
 
       // Check map for existing key entry with the supplied keyID.
-      CipherKeyEntry keyEntry = getCipherKeyEntryOrNull(cryptoManager, keyID);
+      CipherKeyEntry keyEntry = getCipherKeyEntryOrNull(keyID);
       if (null != keyEntry) {
         // Paranoiac check to ensure exact type match.
         if (!keyEntry.getType().equals(transformation)
@@ -1675,21 +1621,43 @@
       getCipher(keyEntry, Cipher.DECRYPT_MODE, iv);
 
       // Cache new entry
-      cryptoManager.cipherKeyEntryLock.lock();
+      cipherKeyEntryLock.lock();
       try
       {
-        cryptoManager.cipherKeyEntryCache.put(keyEntry.getKeyID(), keyEntry);
-        cryptoManager.mostRecentCipherKeys.put(cryptoManager.getKeyFullSpec(transformation, secretKeyLengthBits),
-            keyEntry);
+        cipherKeyEntryCache.put(keyEntry.getKeyID(), keyEntry);
+        mostRecentCipherKeys.put(getKeyFullSpec(transformation, secretKeyLengthBits), keyEntry);
       }
       finally
       {
-        cryptoManager.cipherKeyEntryLock.unlock();
+        cipherKeyEntryLock.unlock();
       }
 
       return keyEntry;
     }
 
+    private CipherKeyEntry getCipherKeyEntry(String cipherTransformation, int keyLengthBits)
+        throws CryptoManagerException
+    {
+      final String keyFullSpec = getKeyFullSpec(cipherTransformation, keyLengthBits);
+      CipherKeyEntry keyEntry = getCipherKeyEntryOrNull(keyFullSpec);
+      if (keyEntry == null) {
+        cipherKeyEntryLock.lock();
+        try
+        {
+          keyEntry = getCipherKeyEntryOrNull(keyFullSpec);
+          if (keyEntry == null)
+          {
+            keyEntry = generateAndPublishKeyEntry(cipherTransformation, keyLengthBits);
+            mostRecentCipherKeys.put(keyFullSpec, keyEntry);
+          }
+        }
+        finally
+        {
+          cipherKeyEntryLock.unlock();
+        }
+      }
+      return keyEntry;
+    }
 
     /**
      * Retrieve a CipherKeyEntry from the CipherKeyEntry Map based on
@@ -1699,28 +1667,16 @@
      * specifications is not found. Instead, the ADS monitoring thread
      * is responsible for asynchronous updates to the key map.
      *
-     * @param cryptoManager  The CryptoManager instance with which the
-     * key entry is associated.
-     * @param transformation  The cipher transformation for which the
-     * key was produced.
-     * @param keyLengthBits  The cipher key length in bits.
-     *
+     * @param keyFullSpec The key full spec for which the key was produced.
      * @return  The key entry corresponding to the parameters, or
      * {@code null} if no such entry exists or has been compromised
      */
-    public static CipherKeyEntry getCipherKeyEntryOrNull(
-        final CryptoManagerImpl cryptoManager,
-        final String transformation,
-        final int keyLengthBits) {
-      Reject.ifNull(cryptoManager, transformation);
-      Reject.ifFalse(0 < keyLengthBits);
-
-      CipherKeyEntry key = cryptoManager.mostRecentCipherKeys.get(cryptoManager.getKeyFullSpec(transformation,
-          keyLengthBits));
+    private CipherKeyEntry getCipherKeyEntryOrNull(String keyFullSpec)
+    {
+      CipherKeyEntry key = mostRecentCipherKeys.get(keyFullSpec);
       return key != null && !key.isCompromised() ? key : null;
     }
 
-
     /**
      * Given a key identifier, return the associated cipher key entry
      * from the supplied map. This method would typically be used by
@@ -1737,20 +1693,23 @@
      * the set of instances and querying them. Instead, the caller
      * must retry the operation requesting the decryption.
      *
-     * @param cryptoManager  The CryptoManager instance with which the
-     * key entry is associated.
      * @param keyID  The key identifier.
      *
      * @return  The key entry associated with the key identifier, or
      * {@code null} if no such entry exists.
-     *
-     * @see CryptoManagerImpl.MacKeyEntry
-     *  #getMacKeyEntryOrNull(CryptoManagerImpl, String, int)
      */
-    public static CipherKeyEntry getCipherKeyEntryOrNull(CryptoManagerImpl cryptoManager, final KeyEntryID keyID) {
-      return cryptoManager.cipherKeyEntryCache.get(keyID);
+    private CipherKeyEntry getCipherKeyEntryOrNull(final KeyEntryID keyID) {
+      return cipherKeyEntryCache.get(keyID);
     }
+  }
 
+  /**
+   * This class corresponds to the cipher key entry in ADS. It is
+   * used in the local cache of key entries that have been requested
+   * by CryptoManager clients.
+   */
+  private static class CipherKeyEntry extends SecretKeyEntry
+  {
     /**
      In case a transformation is supplied instead of an algorithm:
      E.g., AES/CBC/PKCS5Padding -> AES.
@@ -1972,24 +1931,30 @@
     return cipher;
   }
 
-
-  /**
-   * This class corresponds to the MAC key entry in ADS. It is
-   * used in the local cache of key entries that have been requested
-   * by CryptoManager clients.
-   */
-  private static class MacKeyEntry extends SecretKeyEntry
+  /** Encapsulates MAC-related functions of the {@link CryptoManager}. */
+  private final class MacKeyManager
   {
+    /** Ensures atomic updates to both {@link #macKeyEntryCache} and {@link #mostRecentMacKeys}. */
+    private final Lock macKeyEntryLock = new ReentrantLock();
+    /**
+     * The map from encryption key ID to MacKeyEntry (cache). The cache is accessed by methods that
+     * request by ID, publish, and import keys. It contains all keys, even compromised, to be able
+     * to access old data.
+     */
+    private final Map<KeyEntryID, MacKeyEntry> macKeyEntryCache = new ConcurrentHashMap<>();
+    /**
+     * Keys imported or generated for MAC operations, mapped by algorithm/key length. Only one MAC
+     * key per algorithm/key length (used as a key for the map, for example "HmacSHA1/128") is
+     * recorded, the last in temporal order to be imported or generated. MAC keys belonging to this
+     * map also belong in the cache Map, they are used for computing new MAC digests.
+     */
+    private final Map<String, MacKeyEntry> mostRecentMacKeys = new ConcurrentHashMap<>();
+
     /**
      * This method generates a key according to the key parameters,
      * creates a key entry, and optionally registers it in the
      * supplied CryptoManager context.
      *
-     * @param  cryptoManager The CryptoManager instance for which the
-     * key is to be generated. Pass {@code null} as the argument to
-     * this parameter in order to validate a proposed MAC algorithm
-     * and key length, but not publish the key entry.
-     *
      * @param algorithm  The MAC algorithm for which the
      * key is to be produced. This argument is required.
      *
@@ -2001,50 +1966,43 @@
      * @throws CryptoManagerException If there is a problem
      * instantiating a Mac object in order to validate the supplied
      * parameters when creating a new entry.
-     *
-     * @see CipherKeyEntry#getCipherKeyEntryOrNull(CryptoManagerImpl, String, int)
      */
-    public static MacKeyEntry generateKeyEntry(
-            final CryptoManagerImpl cryptoManager,
-            final String algorithm,
-            final int keyLengthBits)
+    private MacKeyEntry generateAndPublishKeyEntry(final String algorithm, final int keyLengthBits)
     throws CryptoManagerException {
       Reject.ifNull(algorithm);
 
-      final Map<KeyEntryID, MacKeyEntry> cache =
-          cryptoManager != null ? cryptoManager.macKeyEntryCache : null;
+      final MacKeyEntry keyEntry = generateKeyEntry(algorithm, keyLengthBits);
 
+      /* The key is published to ADS before making it available in the local
+         cache with the intention to ensure the key is persisted before use.
+         This ordering allows the possibility that data encrypted at another
+         instance could arrive at this instance before the key is available in
+         the local cache to decode the data. */
+      publishKeyEntry(keyEntry);
+      macKeyEntryCache.put(keyEntry.getKeyID(), keyEntry);
+
+      return keyEntry;
+    }
+
+
+    private MacKeyEntry generateKeyEntry(final String algorithm, final int keyLengthBits)
+        throws CryptoManagerException
+    {
       final MacKeyEntry keyEntry = new MacKeyEntry(algorithm, keyLengthBits);
 
       // Validate the key entry.
       getMacEngine(keyEntry);
-
-      if (null != cache) {
-        /* The key is published to ADS before making it available in the local
-           cache with the intention to ensure the key is persisted before use.
-           This ordering allows the possibility that data encrypted at another
-           instance could arrive at this instance before the key is available in
-           the local cache to decode the data. */
-        publishKeyEntry(cryptoManager, keyEntry);
-        cache.put(keyEntry.getKeyID(), keyEntry);
-      }
-
       return keyEntry;
     }
 
 
     /**
      * Publish a new mac key by adding an entry into ADS.
-     * @param  cryptoManager The CryptoManager instance for which the
-     *                       key was generated.
      * @param  keyEntry      The mac key to be published.
      * @throws CryptoManagerException
-     *                       If the key entry could not be added to
-     *                       ADS.
+     *                       If the key entry could not be added to ADS.
      */
-    private static void publishKeyEntry(CryptoManagerImpl cryptoManager,
-                                        MacKeyEntry keyEntry)
-         throws CryptoManagerException
+    private void publishKeyEntry(MacKeyEntry keyEntry) throws CryptoManagerException
     {
       // Construct the key entry DN.
       ByteString distinguishedValue =
@@ -2062,7 +2020,7 @@
       userAttrs.put(attrKeyID, Attributes.createAsList(attrKeyID, distinguishedValue));
       putSingleValueAttribute(userAttrs, attrMacAlgorithm, keyEntry.getType());
       putSingleValueAttribute(userAttrs, attrKeyLength, String.valueOf(keyEntry.getKeyLengthBits()));
-      userAttrs.put(attrSymmetricKey, buildSymetricKeyAttributes(cryptoManager, keyEntry.getSecretKey()));
+      userAttrs.put(attrSymmetricKey, buildSymetricKeyAttributes(keyEntry.getSecretKey()));
 
       // Create the entry.
       LinkedHashMap<AttributeType, List<Attribute>> opAttrs = new LinkedHashMap<>(0);
@@ -2081,7 +2039,6 @@
      * validates it, and registers it in the supplied map.
      * The anticipated use of this method is to import a key entry from ADS.
      *
-     * @param cryptoManager  The CryptoManager instance.
      * @param keyIDString  The key identifier.
      * @param algorithm  The name of the MAC algorithm for which the
      * key entry is to be produced.
@@ -2094,8 +2051,7 @@
      * @throws CryptoManagerException  In case of an error in the
      * parameters used to initialize or validate the key entry.
      */
-    public static MacKeyEntry importMacKeyEntry(
-            final CryptoManagerImpl cryptoManager,
+    private MacKeyEntry importMacKeyEntry(
             final String keyIDString,
             final String algorithm,
             final SecretKey secretKey,
@@ -2107,7 +2063,7 @@
       final KeyEntryID keyID = new KeyEntryID(keyIDString);
 
       // Check map for existing key entry with the supplied keyID.
-      MacKeyEntry keyEntry = getMacKeyEntryOrNull(cryptoManager, keyID);
+      MacKeyEntry keyEntry = getMacKeyEntryOrNull(keyID);
       if (null != keyEntry) {
         // Paranoiac check to ensure exact type match.
         if (! (keyEntry.getType().equals(algorithm)
@@ -2131,15 +2087,15 @@
       getMacEngine(keyEntry);
 
       // Cache new entry
-      cryptoManager.macKeyEntryLock.lock();
+      macKeyEntryLock.lock();
       try
       {
-        cryptoManager.macKeyEntryCache.put(keyEntry.getKeyID(), keyEntry);
-        cryptoManager.mostRecentMacKeys.put(cryptoManager.getKeyFullSpec(algorithm, secretKeyLengthBits), keyEntry);
+        macKeyEntryCache.put(keyEntry.getKeyID(), keyEntry);
+        mostRecentMacKeys.put(getKeyFullSpec(algorithm, secretKeyLengthBits), keyEntry);
       }
       finally
       {
-        cryptoManager.macKeyEntryLock.unlock();
+        macKeyEntryLock.unlock();
       }
       return keyEntry;
     }
@@ -2153,26 +2109,15 @@
      * specifications is not found. Instead, the ADS monitoring thread
      * is responsible for asynchronous updates to the key map.
      *
-     * @param cryptoManager  The CryptoManager instance with which the
-     * key entry is associated.
-     * @param algorithm  The MAC algorithm for which the key was produced.
-     * @param keyLengthBits  The MAC key length in bits.
-     *
+     * @param keyFullSpec The key full spec for which the key was produced.
      * @return  The key entry corresponding to the parameters, or
      * {@code null} if no such entry exists or has been compromised
      */
-    public static MacKeyEntry getMacKeyEntryOrNull(
-        final CryptoManagerImpl cryptoManager,
-        final String algorithm,
-        final int keyLengthBits) {
-      Reject.ifNull(cryptoManager, algorithm);
-      Reject.ifFalse(0 < keyLengthBits);
-
-      MacKeyEntry key =cryptoManager.mostRecentMacKeys.get(cryptoManager.getKeyFullSpec(algorithm, keyLengthBits));
+    private MacKeyEntry getMacKeyEntryOrNull(String keyFullSpec) {
+      MacKeyEntry key = mostRecentMacKeys.get(keyFullSpec);
       return key != null && !key.isCompromised() ? key : null;
     }
 
-
     /**
      * Given a key identifier, return the associated cipher key entry
      * from the supplied map. This method would typically be used by
@@ -2189,20 +2134,50 @@
      * the set of instances and querying them. Instead, the caller
      * must retry the operation requesting the decryption.
      *
-     * @param cryptoManager  The CryptoManager instance with which the
-     * key entry is associated.
      * @param keyID  The key identifier.
      *
      * @return  The key entry associated with the key identifier, or
      * {@code null} if no such entry exists.
-     *
-     * @see CryptoManagerImpl.MacKeyEntry
-     *     #getMacKeyEntryOrNull(CryptoManagerImpl, String, int)
      */
-    public static MacKeyEntry getMacKeyEntryOrNull(final CryptoManagerImpl cryptoManager, final KeyEntryID keyID) {
-      return cryptoManager.macKeyEntryCache.get(keyID);
+    private MacKeyEntry getMacKeyEntryOrNull(final KeyEntryID keyID)
+    {
+      return macKeyEntryCache.get(keyID);
     }
 
+    private String getMacEngineKeyEntryID(final String macAlgorithm, final int keyLengthBits)
+        throws CryptoManagerException
+    {
+      final String keyFullSpec = getKeyFullSpec(macAlgorithm, keyLengthBits);
+      MacKeyEntry keyEntry = getMacKeyEntryOrNull(keyFullSpec);
+      if (keyEntry == null)
+      {
+        macKeyEntryLock.lock();
+        try
+        {
+          keyEntry = getMacKeyEntryOrNull(keyFullSpec);
+          if (keyEntry == null)
+          {
+            keyEntry = generateAndPublishKeyEntry(macAlgorithm, keyLengthBits);
+            mostRecentMacKeys.put(keyFullSpec, keyEntry);
+          }
+        }
+        finally
+        {
+          macKeyEntryLock.unlock();
+        }
+      }
+
+      return keyEntry.getKeyID().toString();
+    }
+  }
+
+  /**
+   * This class corresponds to the MAC key entry in ADS. It is
+   * used in the local cache of key entries that have been requested
+   * by CryptoManager clients.
+   */
+  private static class MacKeyEntry extends SecretKeyEntry
+  {
     /**
      * Construct an instance of {@code MacKeyEntry} using the
      * specified parameters. This constructor would typically be used
@@ -2266,10 +2241,9 @@
     private final String fType;
   }
 
-  private static List<Attribute> buildSymetricKeyAttributes(CryptoManagerImpl cryptoManager, SecretKey secretKey)
-      throws CryptoManagerException
+  private List<Attribute> buildSymetricKeyAttributes(SecretKey secretKey) throws CryptoManagerException
   {
-    Map<String, byte[]> trustedCerts = cryptoManager.getTrustedCertificates();
+    Map<String, byte[]> trustedCerts = getTrustedCertificates();
 
     // Need to add our own instance certificate.
     byte[] instanceKeyCertificate = CryptoManagerImpl.getInstanceKeyCertificateFromLocalTruststore();
@@ -2278,8 +2252,7 @@
     AttributeBuilder builder = new AttributeBuilder(attrSymmetricKey);
     for (Map.Entry<String, byte[]> mapEntry : trustedCerts.entrySet())
     {
-      String symmetricKey =
-          cryptoManager.encodeSymmetricKeyAttribute(mapEntry.getKey(), mapEntry.getValue(), secretKey);
+      String symmetricKey = encodeSymmetricKeyAttribute(mapEntry.getKey(), mapEntry.getValue(), secretKey);
       builder.add(symmetricKey);
     }
     return builder.toAttributeList();
@@ -2397,35 +2370,13 @@
   public String getMacEngineKeyEntryID(final String macAlgorithm,
                                        final int keyLengthBits)
          throws CryptoManagerException {
-    Reject.ifNull(macAlgorithm);
-
-    MacKeyEntry keyEntry = MacKeyEntry.getMacKeyEntryOrNull(this, macAlgorithm, keyLengthBits);
-    if (keyEntry == null)
-    {
-      macKeyEntryLock.lock();
-      try
-      {
-        keyEntry = MacKeyEntry.getMacKeyEntryOrNull(this, macAlgorithm, keyLengthBits);
-        if (keyEntry == null)
-        {
-          keyEntry = MacKeyEntry.generateKeyEntry(this, macAlgorithm, keyLengthBits);
-          mostRecentMacKeys.put(getKeyFullSpec(macAlgorithm, keyLengthBits), keyEntry);
-        }
-      }
-      finally
-      {
-        macKeyEntryLock.unlock();
-      }
-    }
-
-    return keyEntry.getKeyID().toString();
+    return macCryptoManager.getMacEngineKeyEntryID(macAlgorithm, keyLengthBits);
   }
 
   @Override
-  public Mac getMacEngine(String keyEntryID)
-          throws CryptoManagerException
+  public Mac getMacEngine(String keyEntryID) throws CryptoManagerException
   {
-    final MacKeyEntry keyEntry = MacKeyEntry.getMacKeyEntryOrNull(this, new KeyEntryID(keyEntryID));
+    final MacKeyEntry keyEntry = macCryptoManager.getMacKeyEntryOrNull(new KeyEntryID(keyEntryID));
     return keyEntry != null ? getMacEngine(keyEntry) : null;
   }
 
@@ -2445,7 +2396,7 @@
   {
     Reject.ifNull(cipherTransformation, data);
 
-    CipherKeyEntry keyEntry = getCipherKeyEntry(cipherTransformation, keyLengthBits);
+    CipherKeyEntry keyEntry = cipherCryptoManager.getCipherKeyEntry(cipherTransformation, keyLengthBits);
     final Cipher cipher = getCipher(keyEntry, Cipher.ENCRYPT_MODE, null);
     final byte[] keyID = keyEntry.getKeyID().getByteValue();
     final byte[] iv = cipher.getIV();
@@ -2482,7 +2433,7 @@
   {
     Reject.ifNull(cipherTransformation, outputStream);
 
-    CipherKeyEntry keyEntry = getCipherKeyEntry(cipherTransformation, keyLengthBits);
+    CipherKeyEntry keyEntry = cipherCryptoManager.getCipherKeyEntry(cipherTransformation, keyLengthBits);
     final Cipher cipher = getCipher(keyEntry, Cipher.ENCRYPT_MODE, null);
     final byte[] keyID = keyEntry.getKeyID().getByteValue();
 
@@ -2506,34 +2457,23 @@
   @Override
   public void ensureCipherKeyIsAvailable(String cipherTransformation, int cipherKeyLength) throws CryptoManagerException
   {
-    getCipherKeyEntry(cipherTransformation, cipherKeyLength);
+    cipherCryptoManager.getCipherKeyEntry(cipherTransformation, cipherKeyLength);
   }
 
-  private CipherKeyEntry getCipherKeyEntry(String cipherTransformation, int keyLengthBits) throws CryptoManagerException
+  /**
+   * Returns the key full spec for the provided algorithm name and key length.
+   *
+   * @param transformation
+   *          The cipher transformation for which the key was produced.
+   * @param keyLengthBits
+   *          The cipher key length in bits.
+   * @return The key full spec for the provided algorithm name and key length
+   */
+  private String getKeyFullSpec(final String transformation, final int keyLengthBits)
   {
-    CipherKeyEntry keyEntry = CipherKeyEntry.getCipherKeyEntryOrNull(this, cipherTransformation, keyLengthBits);
-    if (keyEntry == null) {
-      cipherKeyEntryLock.lock();
-      try
-      {
-        keyEntry = CipherKeyEntry.getCipherKeyEntryOrNull(this, cipherTransformation, keyLengthBits);
-        if (keyEntry == null)
-        {
-          keyEntry = CipherKeyEntry.generateKeyEntry(this, cipherTransformation, keyLengthBits);
-          mostRecentCipherKeys.put(getKeyFullSpec(cipherTransformation, keyLengthBits), keyEntry);
-        }
-      }
-      finally
-      {
-        cipherKeyEntryLock.unlock();
-      }
-    }
-    return keyEntry;
-  }
-
-  private String getKeyFullSpec(String transformation, int keyLength)
-  {
-    return transformation + "/" + keyLength;
+    Reject.ifNull(transformation);
+    Reject.ifFalse(0 < keyLengthBits);
+    return transformation + "/" + keyLengthBits;
   }
 
   @Override
@@ -2580,7 +2520,7 @@
                    ex.getMessage()), ex);
     }
 
-    CipherKeyEntry keyEntry = CipherKeyEntry.getCipherKeyEntryOrNull(this, keyID);
+    CipherKeyEntry keyEntry = cipherCryptoManager.getCipherKeyEntryOrNull(keyID);
     if (null == keyEntry) {
       throw new CryptoManagerException(
               ERR_CRYPTOMGR_DECRYPT_UNKNOWN_KEY_IDENTIFIER.get());
@@ -2645,7 +2585,7 @@
            ERR_CRYPTOMGR_DECRYPT_FAILED_TO_READ_KEY_IDENTIFIER.get(
                    "stream underflow"));
       }
-      keyEntry = CipherKeyEntry.getCipherKeyEntryOrNull(this, new KeyEntryID(keyID));
+      keyEntry = cipherCryptoManager.getCipherKeyEntryOrNull(new KeyEntryID(keyID));
       if (null == keyEntry) {
         throw new CryptoManagerException(
                 ERR_CRYPTOMGR_DECRYPT_UNKNOWN_KEY_IDENTIFIER.get());

--
Gitblit v1.10.0