From 0b85fb3e6530e91e62c332e987c3283f50a3e2b1 Mon Sep 17 00:00:00 2001
From: david_page <david_page@localhost>
Date: Sun, 14 Oct 2007 01:32:43 +0000
Subject: [PATCH] No issue. CryptoManager Step 3. Factor interface from CryptoManager implementation.

---
 opends/src/server/org/opends/server/crypto/CryptoManagerImpl.java | 1697 ++++++++++++++++++++++++----------------------------------
 1 files changed, 703 insertions(+), 994 deletions(-)

diff --git a/opends/src/server/org/opends/server/crypto/CryptoManager.java b/opends/src/server/org/opends/server/crypto/CryptoManagerImpl.java
similarity index 88%
rename from opends/src/server/org/opends/server/crypto/CryptoManager.java
rename to opends/src/server/org/opends/server/crypto/CryptoManagerImpl.java
index 8ec0244..d1a7a3c 100644
--- a/opends/src/server/org/opends/server/crypto/CryptoManager.java
+++ b/opends/src/server/org/opends/server/crypto/CryptoManagerImpl.java
@@ -103,19 +103,15 @@
  are a lot of similarities and it is conceivable at some point that
  accelerated compression may be available just as it is for
  cryptographic operations.
-
+ <p>
+ Other components of CryptoManager:
  @see "src/admin/defn/org/opends/server/admin/std\
                                       /CryptoManagerConfiguration.xml"
  @see org.opends.server.crypto.CryptoManagerSync
  @see org.opends.server.crypto.GetSymmetricKeyExtendedOperation
  */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.VOLATILE,
-     mayInstantiate=false,
-     mayExtend=false,
-     mayInvoke=true)
-public class CryptoManager
-     implements ConfigurationChangeListener<CryptoManagerCfg>
+public class CryptoManagerImpl
+        implements ConfigurationChangeListener<CryptoManagerCfg>, CryptoManager
 {
   /**
    * The tracer object for the debug logger.
@@ -131,7 +127,7 @@
   private static AttributeType attrInitVectorLength;
   private static AttributeType attrKeyLength;
   private static AttributeType attrCompromisedTime;
-  private static ObjectClass ocCertRequest;
+  private static ObjectClass   ocCertRequest;
   private static ObjectClass   ocInstanceKey;
   private static ObjectClass   ocCipherKey;
   private static ObjectClass   ocMacKey;
@@ -215,7 +211,7 @@
    occurs while creating this {@code CryptoManager} that is not the result of a
    problem in the configuration.
    */
-  public CryptoManager(CryptoManagerCfg cfg)
+  public CryptoManagerImpl(CryptoManagerCfg cfg)
          throws ConfigException, InitializationException {
     if (!schemaInitDone) {
       // Initialize various schema references.
@@ -464,6 +460,35 @@
 
 
   /**
+   * Retrieve the ADS trust store backend.
+   * @return The ADS trust store backend.
+   * @throws ConfigException If the ADS trust store backend is
+   *                         not configured.
+   */
+  private TrustStoreBackend getTrustStoreBackend()
+       throws ConfigException
+  {
+    Backend b = DirectoryServer.getBackend(
+         ConfigConstants.ID_ADS_TRUST_STORE_BACKEND);
+    if (b == null)
+    {
+      Message msg =
+           ERR_CRYPTOMGR_ADS_TRUST_STORE_BACKEND_NOT_ENABLED.get(
+                ConfigConstants.ID_ADS_TRUST_STORE_BACKEND);
+      throw new ConfigException(msg);
+    }
+    if (!(b instanceof TrustStoreBackend))
+    {
+      Message msg =
+           ERR_CRYPTOMGR_ADS_TRUST_STORE_BACKEND_WRONG_CLASS.get(
+                ConfigConstants.ID_ADS_TRUST_STORE_BACKEND);
+      throw new ConfigException(msg);
+    }
+    return (TrustStoreBackend)b;
+  }
+
+
+  /**
    * Returns this instance's instance-key public-key certificate from
    * the local keystore (i.e., from the truststore-backend and not
    * from the ADS backed keystore). If the certificate entry does not
@@ -1014,878 +1039,120 @@
 
 
   /**
-   * Retrieves the name of the preferred message digest algorithm.
+   * Given a set of other servers' symmetric key values for
+   * a given secret key, use the Get Symmetric Key extended
+   * operation to request this server's symmetric key value.
    *
-   * @return  The name of the preferred message digest algorithm
+   * @param  symmetricKeys  The known symmetric key values for
+   *                        a given secret key.
+   *
+   * @return The symmetric key value for this server, or null if
+   *         none could be obtained.
    */
-  public String getPreferredMessageDigestAlgorithm()
+  private String getSymmetricKey(List<String> symmetricKeys)
   {
-    return preferredDigestAlgorithm;
-  }
-
-
-  /**
-   * Retrieves a <CODE>MessageDigest</CODE> object that may be used to
-   * generate digests using the preferred digest algorithm.
-   *
-   * @return  A <CODE>MessageDigest</CODE> object that may be used to
-   *          generate digests using the preferred digest algorithm.
-   *
-   * @throws  NoSuchAlgorithmException  If the requested algorithm is
-   *                                    not supported or is
-   *                                    unavailable.
-   */
-  public MessageDigest getPreferredMessageDigest()
-         throws NoSuchAlgorithmException
-  {
-    return MessageDigest.getInstance(preferredDigestAlgorithm);
-  }
-
-
-
-  /**
-   * Retrieves a <CODE>MessageDigest</CODE> object that may be used to
-   * generate digests using the specified algorithm.
-   *
-   * @param  digestAlgorithm  The algorithm to use to generate the
-   *                          message digest.
-   *
-   * @return  A <CODE>MessageDigest</CODE> object that may be used to
-   *          generate digests using the specified algorithm.
-   *
-   * @throws  NoSuchAlgorithmException  If the requested algorithm is
-   *                                    not supported or is
-   *                                    unavailable.
-   */
-  public MessageDigest getMessageDigest(String digestAlgorithm)
-         throws NoSuchAlgorithmException
-  {
-    return MessageDigest.getInstance(digestAlgorithm);
-  }
-
-
-
-  /**
-   * Retrieves a byte array containing a message digest based on the
-   * provided data, using the preferred digest algorithm.
-   *
-   * @param  data  The data to be digested.
-   *
-   * @return  A byte array containing the generated message digest.
-   *
-   * @throws  NoSuchAlgorithmException  If the requested algorithm is
-   *                                    not supported or is
-   *                                    unavailable.
-   */
-  public byte[] digest(byte[] data)
-         throws NoSuchAlgorithmException
-  {
-    return MessageDigest.getInstance(preferredDigestAlgorithm).
-                digest(data);
-  }
-
-
-
-  /**
-   * Retrieves a byte array containing a message digest based on the
-   * provided data, using the requested digest algorithm.
-   *
-   * @param  digestAlgorithm  The algorithm to use to generate the
-   *                          message digest.
-   * @param  data             The data to be digested.
-   *
-   * @return  A byte array containing the generated message digest.
-   *
-   * @throws  NoSuchAlgorithmException  If the requested algorithm is
-   *                                    not supported or is
-   *                                    unavailable.
-   */
-  public byte[] digest(String digestAlgorithm, byte[] data)
-         throws NoSuchAlgorithmException
-  {
-    return MessageDigest.getInstance(digestAlgorithm).digest(data);
-  }
-
-
-
-  /**
-   * Retrieves a byte array containing a message digest based on the
-   * data read from the provided input stream, using the preferred
-   * digest algorithm.  Data will be read until the end of the stream
-   * is reached.
-   *
-   * @param  inputStream  The input stream from which the data is to
-   *                      be read.
-   *
-   * @return  A byte array containing the generated message digest.
-   *
-   * @throws  IOException  If a problem occurs while reading data from
-   *                       the provided stream.
-   *
-   * @throws  NoSuchAlgorithmException  If the requested algorithm is
-   *                                    not supported or is
-   *                                    unavailable.
-   */
-  public byte[] digest(InputStream inputStream)
-         throws IOException, NoSuchAlgorithmException
-  {
-    MessageDigest digest =
-         MessageDigest.getInstance(preferredDigestAlgorithm);
-
-    byte[] buffer = new byte[8192];
-    while (true)
+    InternalClientConnection internalConnection =
+         InternalClientConnection.getRootConnection();
+    for (String symmetricKey : symmetricKeys)
     {
-      int bytesRead = inputStream.read(buffer);
-      if (bytesRead < 0)
+      try
       {
-        break;
-      }
+        // Get the server instance key ID from the symmetric key.
+        String[] elements = symmetricKey.split(":", 0);
+        String instanceKeyID = elements[0];
 
-      digest.update(buffer, 0, bytesRead);
-    }
+        // Find the server entry from the instance key ID.
+        String filter = "(" +
+             ConfigConstants.ATTR_CRYPTO_KEY_ID + "=" +
+             instanceKeyID + ")";
+        InternalSearchOperation internalSearch =
+             internalConnection.processSearch(
+                  serversDN, SearchScope.SUBORDINATE_SUBTREE,
+                  SearchFilter.createFilterFromString(filter));
+        if (internalSearch.getResultCode() != ResultCode.SUCCESS)
+          continue;
 
-    return digest.digest();
-  }
-
-
-
-  /**
-   * Retrieves a byte array containing a message digest based on the
-   * data read from the provided input stream, using the requested
-   * digest algorithm.  Data will be read until the end of the stream
-   * is reached.
-   *
-   * @param  digestAlgorithm  The algorithm to use to generate the
-   *                          message digest.
-   * @param  inputStream      The input stream from which the data is
-   *                          to be read.
-   *
-   * @return  A byte array containing the generated message digest.
-   *
-   * @throws  IOException  If a problem occurs while reading data from
-   *                       the provided stream.
-   *
-   * @throws  NoSuchAlgorithmException  If the requested algorithm is
-   *                                    not supported or is
-   *                                    unavailable.
-   */
-  public byte[] digest(String digestAlgorithm,
-                       InputStream inputStream)
-         throws IOException, NoSuchAlgorithmException
-  {
-    MessageDigest digest = MessageDigest.getInstance(digestAlgorithm);
-
-    byte[] buffer = new byte[8192];
-    while (true)
-    {
-      int bytesRead = inputStream.read(buffer);
-      if (bytesRead < 0)
-      {
-        break;
-      }
-
-      digest.update(buffer, 0, bytesRead);
-    }
-
-    return digest.digest();
-  }
-
-
-
-  /**
-   * For the current preferred MAC algorithm and key length, return
-   * the identifier of the corresponding key entry. Note: the result
-   * (key identifier) might change across invocations, due to either
-   * of the perferred parameters changing, or because the original
-   * key was marked compromised and a replacement key generated.
-   *
-   * @return A String representation of the identifier of a key entry
-   * corresponding to the preferred MAC algorithm and key length.
-   *
-   * @throws CryptoManagerException In case one or more of the key
-   * parameters is invalid, or there is a problem instantiating the
-   * key entry in case it does not already exist.
-   */
-  public String getMacEngineKeyEntryID()
-          throws CryptoManagerException
-  {
-    return getMacEngineKeyEntryID(preferredMACAlgorithm,
-            preferredMACAlgorithmKeyLengthBits);
-  }
-
-
-  /**
-   * For the specified MAC algorithm and key length, return
-   * the identifier of the corresponding key entry. Note: the result
-   * (key identifier) might change across invocations, due to either
-   * of the perferred parameters changing, or because the original
-   * key was marked compromised and a replacement key generated.
-   *
-   * @param  macAlgorithm  The algorithm to use for the MAC engine.
-   *
-   * @param  keyLengthBits  The key length in bits to use with the
-   *         specified algorithm.
-   *
-   * @return A String representation of the identifier of a key entry
-   * corresponding to the specified MAC algorithm and key length.
-   *
-   * @throws CryptoManagerException In case one or more of the key
-   * parameters is invalid, or there is a problem instantiating the
-   * key entry in case it does not already exist.
-   */
-  public String getMacEngineKeyEntryID(final String macAlgorithm,
-                                       final int keyLengthBits)
-         throws CryptoManagerException {
-    Validator.ensureNotNull(macAlgorithm);
-
-    MacKeyEntry keyEntry = MacKeyEntry.getKeyEntry(this, macAlgorithm,
-                                                   keyLengthBits);
-    if (null == keyEntry) {
-      keyEntry = MacKeyEntry.generateKeyEntry(this, macAlgorithm,
-                                              keyLengthBits);
-    }
-
-    return keyEntry.getKeyID().getStringValue();
-  }
-
-
-  /**
-   * For the specified key entry identifier, instantiate a MAC engine.
-   *
-   * @param keyEntryID The identifier of the key entry containing the
-   * desired MAC algorithm name and key length.
-   *
-   * @return The MAC engine instantiated with the parameters from the
-   * referenced key entry, or null if no such entry exists.
-   *
-   * @throws CryptoManagerException  In case the key entry identifier
-   * is invalid or there is a problem instatiating the MAC engine from
-   * the parameters in the referenced key entry.
-   */
-  public Mac getMacEngine(String keyEntryID)
-          throws CryptoManagerException
-  {
-    final MacKeyEntry keyEntry = MacKeyEntry.getKeyEntry(this,
-            new KeyEntryID(keyEntryID));
-    return (null == keyEntry) ? null : getMacEngine(keyEntry);
-  }
-
-
-  /**
-   * This method produces an initialized MAC engine based on the
-   * supplied MacKeyEntry's state.
-   *
-   * @param keyEntry The MacKeyEntry specifying the Mac properties.
-   *
-   * @return  An initialized Mac object.
-   *
-   * @throws CryptoManagerException  In case there was a error
-   * instantiating the Mac object.
-   */
-  private static Mac getMacEngine(MacKeyEntry keyEntry)
-          throws CryptoManagerException
-  {
-    Mac mac;
-    try {
-      mac = Mac.getInstance(keyEntry.getType());
-    }
-    catch (NoSuchAlgorithmException ex){
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, ex);
-      }
-      throw new CryptoManagerException(
-              ERR_CRYPTOMGR_GET_MAC_ENGINE_INVALID_MAC_ALGORITHM.get(
-                      keyEntry.getType(), getExceptionMessage(ex)),
-              ex);
-    }
-
-    try {
-      mac.init(keyEntry.getSecretKey());
-    }
-    catch (InvalidKeyException ex) {
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, ex);
-      }
-      throw new CryptoManagerException(
-           ERR_CRYPTOMGR_GET_MAC_ENGINE_CANNOT_INITIALIZE.get(
-                   getExceptionMessage(ex)), ex);
-    }
-
-    return mac;
-  }
-
-
-  /**
-   * This method produces an initialized Cipher based on the supplied
-   * CipherKeyEntry's state.
-   *
-   * @param keyEntry  The secret key entry containing the cipher
-   * transformation and secret key for which to instantiate
-   * the cipher.
-   *
-   * @param mode  Either Cipher.ENCRYPT_MODE or Cipher.DECRYPT_MODE.
-   *
-   * @param initializationVector  For Cipher.DECRYPT_MODE, supply
-   * any initialzation vector used in the corresponding encryption
-   * cipher. May be null.
-   *
-   * @return  The initialized cipher object.
-   *
-   * @throws  CryptoManagerException In case of a problem creating
-   * or initializing the requested cipher object. Possible causes
-   * include NoSuchAlgorithmException, NoSuchPaddingException,
-   * InvalidKeyException, and InvalidAlgorithmParameterException.
-   */
-  private static Cipher getCipher(final CipherKeyEntry keyEntry,
-                                  final int mode,
-                                  final byte[] initializationVector)
-          throws CryptoManagerException {
-    Validator.ensureTrue(Cipher.ENCRYPT_MODE == mode
-            || Cipher.DECRYPT_MODE == mode);
-    Validator.ensureTrue(Cipher.ENCRYPT_MODE != mode
-            || null == initializationVector);
-    Validator.ensureTrue(-1 != keyEntry.getIVLengthBits()
-            || Cipher.ENCRYPT_MODE == mode);
-    Validator.ensureTrue(null == initializationVector
-            || initializationVector.length * Byte.SIZE
-                                       == keyEntry.getIVLengthBits());
-
-    Cipher cipher;
-    try {
-      cipher = Cipher.getInstance(keyEntry.getType());
-    }
-    catch (GeneralSecurityException ex) {
-      // NoSuchAlgorithmException, NoSuchPaddingException
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, ex);
-      }
-      throw new CryptoManagerException(
-           ERR_CRYPTOMGR_GET_CIPHER_INVALID_CIPHER_TRANSFORMATION.get(
-                   keyEntry.getType(), getExceptionMessage(ex)), ex);
-    }
-
-    try {
-      if (0 < keyEntry.getIVLengthBits()) {
-          byte[] iv;
-          if (Cipher.ENCRYPT_MODE == mode
-                  && null == initializationVector) {
-            iv = new byte[keyEntry.getIVLengthBits() / Byte.SIZE];
-            pseudoRandom.nextBytes(iv);
-          }
-          else {
-            iv = initializationVector;
-          }
-          cipher.init(mode, keyEntry.getSecretKey(),
-                  new IvParameterSpec(iv));
-      }
-      else {
-        cipher.init(mode, keyEntry.getSecretKey());
-      }
-    }
-    catch (GeneralSecurityException ex) {
-      // InvalidKeyException, InvalidAlgorithmParameterException
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, ex);
-      }
-      throw new CryptoManagerException(
-              ERR_CRYPTOMGR_GET_CIPHER_CANNOT_INITIALIZE.get(
-                      getExceptionMessage(ex)), ex);
-    }
-
-    return cipher;
-  }
-
-
-  /**
-   * Encrypts the data in the provided byte array using the preferred
-   * cipher transformation.
-   *
-   * @param  data  The plain-text data to be encrypted.
-   *
-   * @return  A byte array containing the encrypted representation of
-   *          the provided data.
-   *
-   * @throws  GeneralSecurityException  If a problem occurs while
-   *          encrypting the data.
-   *
-   * @throws  CryptoManagerException  If a problem occurs managing the
-   *          encryption key or producing the cipher.
-   */
-  public byte[] encrypt(byte[] data)
-         throws GeneralSecurityException, CryptoManagerException
-  {
-    return encrypt(preferredCipherTransformation,
-            preferredCipherTransformationKeyLengthBits, data);
-  }
-
-
-  /**
-   * Encrypts the data in the provided byte array using the requested
-   * cipher algorithm.
-   *
-   * @param  cipherTransformation  The algorithm/mode/padding to use
-   *         for the cipher.
-   *
-   * @param  keyLengthBits  The length in bits of the encryption key
-   *         this method is to use. Note the specified key length and
-   *         transformation must be compatible.
-   *
-   * @param  data  The plain-text data to be encrypted.
-   *
-   * @return  A byte array containing the encrypted representation of
-   *          the provided data.
-   *
-   * @throws  GeneralSecurityException  If a problem occurs while
-   *          encrypting the data.
-   *
-   * @throws  CryptoManagerException  If a problem occurs managing the
-   *          encryption key or producing the cipher.
-   */
-  public byte[] encrypt(String cipherTransformation,
-                        int keyLengthBits,
-                        byte[] data)
-         throws GeneralSecurityException, CryptoManagerException
-  {
-    Validator.ensureNotNull(cipherTransformation, data);
-
-    CipherKeyEntry keyEntry = CipherKeyEntry.getKeyEntry(
-            this, cipherTransformation, keyLengthBits);
-    if (null == keyEntry) {
-      keyEntry = CipherKeyEntry.generateKeyEntry(this,
-              cipherTransformation, keyLengthBits);
-    }
-
-    final Cipher cipher
-            = getCipher(keyEntry, Cipher.ENCRYPT_MODE, null);
-
-    final byte[] keyID = keyEntry.getKeyID().getByteValue();
-    final byte[] iv = cipher.getIV();
-    final int prologueLength
-            = keyID.length + ((null == iv) ? 0 : iv.length);
-    final int dataLength = cipher.getOutputSize(data.length);
-    final byte[] cipherText = new byte[prologueLength + dataLength];
-    System.arraycopy(keyID, 0, cipherText, 0, keyID.length);
-    if (null != iv) {
-      System.arraycopy(iv, 0, cipherText, keyID.length, iv.length);
-    }
-    System.arraycopy(cipher.doFinal(data), 0, cipherText,
-                     prologueLength, dataLength);
-    return cipherText;
-  }
-
-
-  /**
-   * Writes encrypted data to the provided output stream using the
-   * preferred cipher transformation.
-   *
-   * @param  outputStream The output stream to be wrapped by the
-   *         returned cipher output stream.
-   *
-   * @return  The output stream wrapped with a CipherOutputStream.
-   *
-   * @throws  CryptoManagerException  If a problem occurs managing the
-   *          encryption key or producing the cipher.
-   */
-  public CipherOutputStream getCipherOutputStream(
-          OutputStream outputStream) throws CryptoManagerException
-  {
-    return getCipherOutputStream(preferredCipherTransformation,
-            preferredCipherTransformationKeyLengthBits, outputStream);
-  }
-
-
-  /**
-   * Writes encrypted data to the provided output stream using the
-   * requested cipher transformation.
-   *
-   * @param  cipherTransformation  The algorithm/mode/padding to use
-   *         for the cipher.
-   *
-   * @param  keyLengthBits  The length in bits of the encryption key
-   *         this method will generate. Note the specified key length
-   *         must be compatible with the transformation.
-   *
-   * @param  outputStream The output stream to be wrapped by the
-   *         returned cipher output stream.
-   *
-   * @return  The output stream wrapped with a CipherOutputStream.
-   *
-   * @throws  CryptoManagerException  If a problem occurs managing the
-   *          encryption key or producing the cipher.
-   */
-  public CipherOutputStream getCipherOutputStream(
-          String cipherTransformation, int keyLengthBits,
-          OutputStream outputStream)
-         throws CryptoManagerException
-  {
-    Validator.ensureNotNull(cipherTransformation, outputStream);
-
-    CipherKeyEntry keyEntry = CipherKeyEntry.getKeyEntry(
-            this, cipherTransformation, keyLengthBits);
-    if (null == keyEntry) {
-      keyEntry = CipherKeyEntry.generateKeyEntry(this,
-              cipherTransformation, keyLengthBits);
-    }
-
-    final Cipher cipher
-            = getCipher(keyEntry, Cipher.ENCRYPT_MODE, null);
-    final byte[] keyID = keyEntry.getKeyID().getByteValue();
-    try {
-      outputStream.write(keyID);
-      if (null != cipher.getIV()) {
-        outputStream.write(cipher.getIV());
-      }
-    }
-    catch (IOException ex) {
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, ex);
-      }
-      throw new CryptoManagerException(
-             ERR_CRYPTOMGR_GET_CIPHER_STREAM_PROLOGUE_WRITE_ERROR.get(
-                     getExceptionMessage(ex)), ex);
-    }
-
-    return new CipherOutputStream(outputStream, cipher);
-  }
-
-
-  /**
-   * Decrypts the data in the provided byte array using cipher
-   * specified by the key identifier prologue to the data.
-   * cipher.
-   *
-   * @param  data  The cipher-text data to be decrypted.
-   *
-   * @return  A byte array containing the clear-text representation of
-   *          the provided data.
-   *
-   * @throws  GeneralSecurityException  If a problem occurs while
-   *          encrypting the data.
-   *
-   * @throws  CryptoManagerException  If a problem occurs reading the
-   *          key identifier or initialization vector from the data
-   *          prologue, or using these values to initialize a Cipher.
-   */
-  public byte[] decrypt(byte[] data)
-         throws GeneralSecurityException,
-                CryptoManagerException
-  {
-    KeyEntryID keyID;
-    try {
-      final byte[] keyIDBytes
-              = new byte[KeyEntryID.getByteValueLength()];
-      System.arraycopy(data, 0, keyIDBytes, 0, keyIDBytes.length);
-      keyID = new KeyEntryID(keyIDBytes);
-    }
-    catch (Exception ex) {
-      // IndexOutOfBoundsException, ArrayStoreException, ...
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, ex);
-      }
-      throw new CryptoManagerException(
-           ERR_CRYPTOMGR_DECRYPT_FAILED_TO_READ_KEY_IDENTIFIER.get(),
-              ex);
-    }
-
-    CipherKeyEntry keyEntry = CipherKeyEntry.getKeyEntry(this, keyID);
-    if (null == keyEntry) {
-      throw new CryptoManagerException(
-              ERR_CRYPTOMGR_DECRYPT_UNKNOWN_KEY_IDENTIFIER.get());
-    }
-
-    byte[] iv = null;
-    if (0 < keyEntry.getIVLengthBits()) {
-      iv = new byte[keyEntry.getIVLengthBits()/Byte.SIZE];
-      try {
-        System.arraycopy(data, KeyEntryID.getByteValueLength(), iv, 0,
-                iv.length);
-      }
-      catch (Exception ex) {
-        // IndexOutOfBoundsException, ArrayStoreException, ...
-        if (debugEnabled()) {
-          TRACER.debugCaught(DebugLogLevel.ERROR, ex);
-        }
-        throw new CryptoManagerException(
-               ERR_CRYPTOMGR_DECRYPT_FAILED_TO_READ_IV.get(), ex);
-      }
-    }
-
-    final Cipher cipher = getCipher(keyEntry, Cipher.DECRYPT_MODE,
-            iv);
-    final int prologueLength = KeyEntryID.getByteValueLength()
-                                     + ((null == iv) ? 0 : iv.length);
-    return cipher.doFinal(data, prologueLength,
-                          data.length - prologueLength);
-  }
-
-
-
-  /**
-   * Returns a CipherInputStream instantiated with a cipher
-   * corresponding to the key identifier prologue to the data.
-   *
-   * @param  inputStream The input stream be wrapped with the
-   *         CipherInputStream.
-   *
-   * @return The CiperInputStream instantiated as specified.
-   *
-   * @throws  CryptoManagerException If there is a problem reading the
-   *          key ID or initialization vector from the input stream,
-   *          or using these values to inititalize a Cipher.
-   */
-  public CipherInputStream getCipherInputStream(
-          InputStream inputStream) throws CryptoManagerException
-  {
-    CipherKeyEntry keyEntry;
-    byte[] iv = null;
-    try {
-      final byte[] keyID = new byte[KeyEntryID.getByteValueLength()];
-      if (keyID.length != inputStream.read(keyID)){
-        throw new CryptoManagerException(
-           ERR_CRYPTOMGR_DECRYPT_FAILED_TO_READ_KEY_IDENTIFIER.get());
-      }
-      keyEntry = CipherKeyEntry.getKeyEntry(this,
-              new KeyEntryID(keyID));
-      if (null == keyEntry) {
-        throw new CryptoManagerException(
-                ERR_CRYPTOMGR_DECRYPT_UNKNOWN_KEY_IDENTIFIER.get());
-      }
-
-      if (0 < keyEntry.getIVLengthBits()) {
-        iv = new byte[keyEntry.getIVLengthBits() / Byte.SIZE];
-        if (iv.length != inputStream.read(iv)) {
-          throw new CryptoManagerException(
-                  ERR_CRYPTOMGR_DECRYPT_FAILED_TO_READ_IV.get());
-        }
-      }
-    }
-    catch (IOException ex) {
-      throw new CryptoManagerException(
-             ERR_CRYPTOMGR_DECRYPT_CIPHER_INPUT_STREAM_ERROR.get(
-                     getExceptionMessage(ex)), ex);
-    }
-
-    return new CipherInputStream(inputStream,
-            getCipher(keyEntry, Cipher.DECRYPT_MODE, iv));
-  }
-
-
-  /**
-   * Attempts to compress the data in the provided source array into
-   * the given destination array.  If the compressed data will fit
-   * into the destination array, then this method will return the
-   * number of bytes of compressed data in the array.  Otherwise, it
-   * will return -1 to indicate that the compression was not
-   * successful.  Note that if -1 is returned, then the data in the
-   * destination array should be considered invalid.
-   *
-   * @param  src  The array containing the raw data to compress.
-   * @param  dst  The array into which the compressed data should be
-   *              written.
-   *
-   * @return  The number of bytes of compressed data, or -1 if it was
-   *          not possible to actually compress the data.
-   */
-  public int compress(byte[] src, byte[] dst)
-  {
-    Deflater deflater = new Deflater();
-    try
-    {
-      deflater.setInput(src);
-      deflater.finish();
-
-      int compressedLength = deflater.deflate(dst);
-      if (deflater.finished())
-      {
-        return compressedLength;
-      }
-      else
-      {
-        return -1;
-      }
-    }
-    finally
-    {
-      deflater.end();
-    }
-  }
-
-
-
-  /**
-   * Attempts to uncompress the data in the provided source array into
-   * the given destination array.  If the uncompressed data will fit
-   * into the given destination array, then this method will return
-   * the number of bytes of uncompressed data written into the
-   * destination buffer.  Otherwise, it will return a negative value
-   * to indicate that the destination buffer was not large enough.
-   * The absolute value of that negative return value will indicate
-   * the buffer size required to fully decompress the data.  Note that
-   * if a negative value is returned, then the data in the destination
-   * array should be considered invalid.
-   *
-   * @param  src  The array containing the compressed data.
-   * @param  dst  The array into which the uncompressed data should be
-   *              written.
-   *
-   * @return  A positive value containing the number of bytes of
-   *          uncompressed data written into the destination buffer,
-   *          or a negative value whose absolute value is the size of
-   *          the destination buffer required to fully decompress the
-   *          provided data.
-   *
-   * @throws  DataFormatException  If a problem occurs while
-   *                               attempting to uncompress the data.
-   */
-  public int uncompress(byte[] src, byte[] dst)
-         throws DataFormatException
-  {
-    Inflater inflater = new Inflater();
-    try
-    {
-      inflater.setInput(src);
-
-      int decompressedLength = inflater.inflate(dst);
-      if (inflater.finished())
-      {
-        return decompressedLength;
-      }
-      else
-      {
-        int totalLength = decompressedLength;
-
-        while (! inflater.finished())
+        LinkedList<SearchResultEntry> resultEntries =
+             internalSearch.getSearchEntries();
+        for (SearchResultEntry resultEntry : resultEntries)
         {
-          totalLength += inflater.inflate(dst);
+          AttributeType hostnameAttr =
+               DirectoryServer.getAttributeType("hostname", true);
+          String hostname = resultEntry.getAttributeValue(
+               hostnameAttr, DirectoryStringSyntax.DECODER);
+          AttributeType ldapPortAttr =
+               DirectoryServer.getAttributeType("ldapport", true);
+          Integer ldapPort = resultEntry.getAttributeValue(
+               ldapPortAttr, IntegerSyntax.DECODER);
+
+          // Connect to the server.
+          AtomicInteger nextMessageID = new AtomicInteger(1);
+          LDAPConnectionOptions connectionOptions =
+               new LDAPConnectionOptions();
+          PrintStream nullPrintStream =
+               new PrintStream(new OutputStream() {
+                 public void write ( int b ) { }
+               });
+          LDAPConnection connection =
+               new LDAPConnection(hostname, ldapPort,
+                                  connectionOptions,
+                                  nullPrintStream,
+                                  nullPrintStream);
+
+          connection.connectToHost(null, null, nextMessageID);
+
+          try
+          {
+            LDAPReader reader = connection.getLDAPReader();
+            LDAPWriter writer = connection.getLDAPWriter();
+
+            // Send the Get Symmetric Key extended request.
+
+            ASN1OctetString requestValue =
+                 GetSymmetricKeyExtendedOperation.encodeRequestValue(
+                      symmetricKey, getInstanceKeyID());
+
+            ExtendedRequestProtocolOp extendedRequest =
+                 new ExtendedRequestProtocolOp(
+                      ServerConstants.
+                           OID_GET_SYMMETRIC_KEY_EXTENDED_OP,
+                      requestValue);
+
+            ArrayList<LDAPControl> controls =
+                 new ArrayList<LDAPControl>();
+            LDAPMessage requestMessage =
+                 new LDAPMessage(nextMessageID.getAndIncrement(),
+                                 extendedRequest, controls);
+            writer.writeMessage(requestMessage);
+            LDAPMessage responseMessage = reader.readMessage();
+
+            ExtendedResponseProtocolOp extendedResponse =
+                 responseMessage.getExtendedResponseProtocolOp();
+            if (extendedResponse.getResultCode() ==
+                 LDAPResultCode.SUCCESS)
+            {
+              // Got our symmetric key value.
+              return extendedResponse.getValue().stringValue();
+            }
+          }
+          finally
+          {
+            connection.close(nextMessageID);
+          }
         }
-
-        return -totalLength;
       }
-    }
-    finally
-    {
-      inflater.end();
-    }
-  }
-
-
-  /**
-   * Retrieve the ADS trust store backend.
-   * @return The ADS trust store backend.
-   * @throws ConfigException If the ADS trust store backend is
-   *                         not configured.
-   */
-  private TrustStoreBackend getTrustStoreBackend()
-       throws ConfigException
-  {
-    Backend b = DirectoryServer.getBackend(
-         ConfigConstants.ID_ADS_TRUST_STORE_BACKEND);
-    if (b == null)
-    {
-      Message msg =
-           ERR_CRYPTOMGR_ADS_TRUST_STORE_BACKEND_NOT_ENABLED.get(
-                ConfigConstants.ID_ADS_TRUST_STORE_BACKEND);
-      throw new ConfigException(msg);
-    }
-    if (!(b instanceof TrustStoreBackend))
-    {
-      Message msg =
-           ERR_CRYPTOMGR_ADS_TRUST_STORE_BACKEND_WRONG_CLASS.get(
-                ConfigConstants.ID_ADS_TRUST_STORE_BACKEND);
-      throw new ConfigException(msg);
-    }
-    return (TrustStoreBackend)b;
-  }
-
-  /**
-   * Create an SSL context that may be used for communication to
-   * another ADS component.
-   *
-   * @param sslCertNickname The name of the local certificate to use,
-   *                        or null if none is specified.
-   * @return A new SSL Context.
-   * @throws ConfigException If the context could not be created.
-   */
-  public SSLContext getSslContext(String sslCertNickname)
-       throws ConfigException
-  {
-    SSLContext sslContext;
-    try
-    {
-      TrustStoreBackend trustStoreBackend = getTrustStoreBackend();
-      KeyManager[] keyManagers = trustStoreBackend.getKeyManagers();
-      TrustManager[] trustManagers =
-           trustStoreBackend.getTrustManagers();
-
-      sslContext = SSLContext.getInstance("TLS");
-
-      if (sslCertNickname == null)
+      catch (Exception e)
       {
-        sslContext.init(keyManagers, trustManagers, null);
-      }
-      else
-      {
-        X509ExtendedKeyManager[] extendedKeyManagers =
-             SelectableCertificateKeyManager.wrap(
-                  keyManagers,
-                  sslCertNickname);
-        sslContext.init(extendedKeyManagers, trustManagers, null);
+        // Just try another server.
       }
     }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
 
-      Message message =
-           ERR_CRYPTOMGR_SSL_CONTEXT_CANNOT_INITIALIZE.get(
-                getExceptionMessage(e));
-      throw new ConfigException(message, e);
-    }
-
-    return sslContext;
+    // Give up.
+    return null;
   }
 
 
   /**
-   * Get the name of the local certificate to use for SSL.
-   * @return The name of the local certificate to use for SSL.
-   */
-  public String getSslCertNickname()
-  {
-    return sslCertNickname;
-  }
-
-  /**
-   * Determine whether SSL encryption is enabled.
-   * @return true if SSL encryption is enabled.
-   */
-  public boolean isSslEncryption()
-  {
-    return sslEncryption;
-  }
-
-  /**
-   * Get the set of enabled SSL protocols.
-   * @return The set of enabled SSL protocols.
-   */
-  public SortedSet<String> getSslProtocols()
-  {
-    return sslProtocols;
-  }
-
-  /**
-   * Get the set of enabled SSL cipher suites.
-   * @return The set of enabled SSL cipher suites.
-   */
-  public SortedSet<String> getSslCipherSuites()
-  {
-    return sslCipherSuites;
-  }
-
-  /**
    * Imports a cipher key entry from an entry in ADS.
    *
    * @param entry  The ADS cipher key entry to be imported.
@@ -1999,119 +1266,6 @@
     }
   }
 
-  /**
-   * Given a set of other servers' symmetric key values for
-   * a given secret key, use the Get Symmetric Key extended
-   * operation to request this server's symmetric key value.
-   *
-   * @param  symmetricKeys  The known symmetric key values for
-   *                        a given secret key.
-   *
-   * @return The symmetric key value for this server, or null if
-   *         none could be obtained.
-   */
-  private String getSymmetricKey(List<String> symmetricKeys)
-  {
-    InternalClientConnection internalConnection =
-         InternalClientConnection.getRootConnection();
-    for (String symmetricKey : symmetricKeys)
-    {
-      try
-      {
-        // Get the server instance key ID from the symmetric key.
-        String[] elements = symmetricKey.split(":", 0);
-        String instanceKeyID = elements[0];
-
-        // Find the server entry from the instance key ID.
-        String filter = "(" +
-             ConfigConstants.ATTR_CRYPTO_KEY_ID + "=" +
-             instanceKeyID + ")";
-        InternalSearchOperation internalSearch =
-             internalConnection.processSearch(
-                  serversDN, SearchScope.SUBORDINATE_SUBTREE,
-                  SearchFilter.createFilterFromString(filter));
-        if (internalSearch.getResultCode() != ResultCode.SUCCESS)
-          continue;
-
-        LinkedList<SearchResultEntry> resultEntries =
-             internalSearch.getSearchEntries();
-        for (SearchResultEntry resultEntry : resultEntries)
-        {
-          AttributeType hostnameAttr =
-               DirectoryServer.getAttributeType("hostname", true);
-          String hostname = resultEntry.getAttributeValue(
-               hostnameAttr, DirectoryStringSyntax.DECODER);
-          AttributeType ldapPortAttr =
-               DirectoryServer.getAttributeType("ldapport", true);
-          Integer ldapPort = resultEntry.getAttributeValue(
-               ldapPortAttr, IntegerSyntax.DECODER);
-
-          // Connect to the server.
-          AtomicInteger nextMessageID = new AtomicInteger(1);
-          LDAPConnectionOptions connectionOptions =
-               new LDAPConnectionOptions();
-          PrintStream nullPrintStream =
-               new PrintStream(new OutputStream() {
-                 public void write ( int b ) { }
-               });
-          LDAPConnection connection =
-               new LDAPConnection(hostname, ldapPort,
-                                  connectionOptions,
-                                  nullPrintStream,
-                                  nullPrintStream);
-
-          connection.connectToHost(null, null, nextMessageID);
-
-          try
-          {
-            LDAPReader reader = connection.getLDAPReader();
-            LDAPWriter writer = connection.getLDAPWriter();
-
-            // Send the Get Symmetric Key extended request.
-
-            ASN1OctetString requestValue =
-                 GetSymmetricKeyExtendedOperation.encodeRequestValue(
-                      symmetricKey, getInstanceKeyID());
-
-            ExtendedRequestProtocolOp extendedRequest =
-                 new ExtendedRequestProtocolOp(
-                      ServerConstants.
-                           OID_GET_SYMMETRIC_KEY_EXTENDED_OP,
-                      requestValue);
-
-            ArrayList<LDAPControl> controls =
-                 new ArrayList<LDAPControl>();
-            LDAPMessage requestMessage =
-                 new LDAPMessage(nextMessageID.getAndIncrement(),
-                                 extendedRequest, controls);
-            writer.writeMessage(requestMessage);
-            LDAPMessage responseMessage = reader.readMessage();
-
-            ExtendedResponseProtocolOp extendedResponse =
-                 responseMessage.getExtendedResponseProtocolOp();
-            if (extendedResponse.getResultCode() ==
-                 LDAPResultCode.SUCCESS)
-            {
-              // Got our symmetric key value.
-              return extendedResponse.getValue().stringValue();
-            }
-          }
-          finally
-          {
-            connection.close(nextMessageID);
-          }
-        }
-      }
-      catch (Exception e)
-      {
-        // Just try another server.
-      }
-    }
-
-    // Give up.
-    return null;
-  }
-
 
   /**
    * Imports a mac key entry from an entry in ADS.
@@ -2219,6 +1373,7 @@
     }
   }
 
+
   /**
    * This class implements a utility interface to the unique
    * identifier corresponding to a cryptographic key. For each key
@@ -2517,10 +1672,10 @@
      * instantiating a Cipher object in order to validate the supplied
      * parameters when creating a new entry.
      *
-     * @see CipherKeyEntry#getKeyEntry(CryptoManager, String, int)
+     * @see CipherKeyEntry#getKeyEntry(CryptoManagerImpl, String, int)
      */
     public static CipherKeyEntry generateKeyEntry(
-            final CryptoManager cryptoManager,
+            final CryptoManagerImpl cryptoManager,
             final String transformation,
             final int keyLengthBits)
     throws CryptoManagerException {
@@ -2563,7 +1718,7 @@
      *                       If the key entry could not be added to
      *                       ADS.
      */
-    private static void publishKeyEntry(CryptoManager cryptoManager,
+    private static void publishKeyEntry(CryptoManagerImpl cryptoManager,
                                         CipherKeyEntry keyEntry)
          throws CryptoManagerException
     {
@@ -2644,7 +1799,7 @@
 
       // Need to add our own instance certificate.
       byte[] instanceKeyCertificate =
-         CryptoManager.getInstanceKeyCertificateFromLocalTruststore();
+         CryptoManagerImpl.getInstanceKeyCertificateFromLocalTruststore();
       trustedCerts.put(getInstanceKeyID(instanceKeyCertificate),
                        instanceKeyCertificate);
 
@@ -2720,7 +1875,7 @@
      * parameters used to initialize or validate the key entry.
      */
     public static CipherKeyEntry importCipherKeyEntry(
-            final CryptoManager cryptoManager,
+            final CryptoManagerImpl cryptoManager,
             final String keyIDString,
             final String transformation,
             final SecretKey secretKey,
@@ -2791,7 +1946,7 @@
      * {@code null} if no such entry exists.
      */
     public static CipherKeyEntry getKeyEntry(
-            final CryptoManager cryptoManager,
+            final CryptoManagerImpl cryptoManager,
             final String transformation,
             final int keyLengthBits) {
       Validator.ensureNotNull(cryptoManager, transformation);
@@ -2838,12 +1993,12 @@
      * @return  The key entry associated with the key identifier, or
      * {@code null} if no such entry exists.
      *
-     * @see org.opends.server.crypto.CryptoManager.MacKeyEntry
+     * @see CryptoManagerImpl.MacKeyEntry
      *  #getKeyEntry(org.opends.server.types.CryptoManager,
      *               java.lang.String, int)
      */
     public static CipherKeyEntry getKeyEntry(
-            CryptoManager cryptoManager,
+            CryptoManagerImpl cryptoManager,
             final KeyEntryID keyID) {
       return cryptoManager.cipherKeyEntryCache.get(keyID);
     }
@@ -2983,6 +2138,86 @@
   }
 
 
+  /**
+   * This method produces an initialized Cipher based on the supplied
+   * CipherKeyEntry's state.
+   *
+   * @param keyEntry  The secret key entry containing the cipher
+   * transformation and secret key for which to instantiate
+   * the cipher.
+   *
+   * @param mode  Either Cipher.ENCRYPT_MODE or Cipher.DECRYPT_MODE.
+   *
+   * @param initializationVector  For Cipher.DECRYPT_MODE, supply
+   * any initialzation vector used in the corresponding encryption
+   * cipher. May be null.
+   *
+   * @return  The initialized cipher object.
+   *
+   * @throws  CryptoManagerException In case of a problem creating
+   * or initializing the requested cipher object. Possible causes
+   * include NoSuchAlgorithmException, NoSuchPaddingException,
+   * InvalidKeyException, and InvalidAlgorithmParameterException.
+   */
+  private static Cipher getCipher(final CipherKeyEntry keyEntry,
+                                  final int mode,
+                                  final byte[] initializationVector)
+          throws CryptoManagerException {
+    Validator.ensureTrue(Cipher.ENCRYPT_MODE == mode
+            || Cipher.DECRYPT_MODE == mode);
+    Validator.ensureTrue(Cipher.ENCRYPT_MODE != mode
+            || null == initializationVector);
+    Validator.ensureTrue(-1 != keyEntry.getIVLengthBits()
+            || Cipher.ENCRYPT_MODE == mode);
+    Validator.ensureTrue(null == initializationVector
+            || initializationVector.length * Byte.SIZE
+                                       == keyEntry.getIVLengthBits());
+
+    Cipher cipher;
+    try {
+      cipher = Cipher.getInstance(keyEntry.getType());
+    }
+    catch (GeneralSecurityException ex) {
+      // NoSuchAlgorithmException, NoSuchPaddingException
+      if (debugEnabled()) {
+        TRACER.debugCaught(DebugLogLevel.ERROR, ex);
+      }
+      throw new CryptoManagerException(
+           ERR_CRYPTOMGR_GET_CIPHER_INVALID_CIPHER_TRANSFORMATION.get(
+                   keyEntry.getType(), getExceptionMessage(ex)), ex);
+    }
+
+    try {
+      if (0 < keyEntry.getIVLengthBits()) {
+          byte[] iv;
+          if (Cipher.ENCRYPT_MODE == mode
+                  && null == initializationVector) {
+            iv = new byte[keyEntry.getIVLengthBits() / Byte.SIZE];
+            pseudoRandom.nextBytes(iv);
+          }
+          else {
+            iv = initializationVector;
+          }
+          cipher.init(mode, keyEntry.getSecretKey(),
+                  new IvParameterSpec(iv));
+      }
+      else {
+        cipher.init(mode, keyEntry.getSecretKey());
+      }
+    }
+    catch (GeneralSecurityException ex) {
+      // InvalidKeyException, InvalidAlgorithmParameterException
+      if (debugEnabled()) {
+        TRACER.debugCaught(DebugLogLevel.ERROR, ex);
+      }
+      throw new CryptoManagerException(
+              ERR_CRYPTOMGR_GET_CIPHER_CANNOT_INITIALIZE.get(
+                      getExceptionMessage(ex)), ex);
+    }
+
+    return cipher;
+  }
+
 
   /**
    * This class corresponds to the MAC key entry in ADS. It is
@@ -3014,10 +2249,10 @@
      * instantiating a Mac object in order to validate the supplied
      * parameters when creating a new entry.
      *
-     * @see MacKeyEntry#getKeyEntry(CryptoManager, String, int)
+     * @see MacKeyEntry#getKeyEntry(CryptoManagerImpl, String, int)
      */
     public static MacKeyEntry generateKeyEntry(
-            final CryptoManager cryptoManager,
+            final CryptoManagerImpl cryptoManager,
             final String algorithm,
             final int keyLengthBits)
     throws CryptoManagerException {
@@ -3056,7 +2291,7 @@
      *                       If the key entry could not be added to
      *                       ADS.
      */
-    private static void publishKeyEntry(CryptoManager cryptoManager,
+    private static void publishKeyEntry(CryptoManagerImpl cryptoManager,
                                         MacKeyEntry keyEntry)
          throws CryptoManagerException
     {
@@ -3123,7 +2358,7 @@
 
       // Need to add our own instance certificate.
       byte[] instanceKeyCertificate =
-         CryptoManager.getInstanceKeyCertificateFromLocalTruststore();
+         CryptoManagerImpl.getInstanceKeyCertificateFromLocalTruststore();
       trustedCerts.put(getInstanceKeyID(instanceKeyCertificate),
                        instanceKeyCertificate);
 
@@ -3193,7 +2428,7 @@
      * parameters used to initialize or validate the key entry.
      */
     public static MacKeyEntry importMacKeyEntry(
-            final CryptoManager cryptoManager,
+            final CryptoManagerImpl cryptoManager,
             final String keyIDString,
             final String algorithm,
             final SecretKey secretKey,
@@ -3257,7 +2492,7 @@
      * {@code null} if no such entry exists.
      */
     public static MacKeyEntry getKeyEntry(
-            final CryptoManager cryptoManager,
+            final CryptoManagerImpl cryptoManager,
             final String algorithm,
             final int keyLengthBits) {
       Validator.ensureNotNull(cryptoManager, algorithm);
@@ -3304,12 +2539,12 @@
      * @return  The key entry associated with the key identifier, or
      * {@code null} if no such entry exists.
      *
-     * @see org.opends.server.crypto.CryptoManager.CipherKeyEntry
+     * @see CryptoManagerImpl.CipherKeyEntry
      *     #getKeyEntry(org.opends.server.types.CryptoManager,
      *                  java.lang.String, int)
      */
     public static MacKeyEntry getKeyEntry(
-            final CryptoManager cryptoManager,
+            final CryptoManagerImpl cryptoManager,
             final KeyEntryID keyID) {
       return cryptoManager.macKeyEntryCache.get(keyID);
     }
@@ -3379,8 +2614,482 @@
       return fType;
     }
 
-
     // state
     private final String fType;
   }
+
+
+  /**
+   * This method produces an initialized MAC engine based on the
+   * supplied MacKeyEntry's state.
+   *
+   * @param keyEntry The MacKeyEntry specifying the Mac properties.
+   *
+   * @return  An initialized Mac object.
+   *
+   * @throws CryptoManagerException  In case there was a error
+   * instantiating the Mac object.
+   */
+  private static Mac getMacEngine(MacKeyEntry keyEntry)
+          throws CryptoManagerException
+  {
+    Mac mac;
+    try {
+      mac = Mac.getInstance(keyEntry.getType());
+    }
+    catch (NoSuchAlgorithmException ex){
+      if (debugEnabled()) {
+        TRACER.debugCaught(DebugLogLevel.ERROR, ex);
+      }
+      throw new CryptoManagerException(
+              ERR_CRYPTOMGR_GET_MAC_ENGINE_INVALID_MAC_ALGORITHM.get(
+                      keyEntry.getType(), getExceptionMessage(ex)),
+              ex);
+    }
+
+    try {
+      mac.init(keyEntry.getSecretKey());
+    }
+    catch (InvalidKeyException ex) {
+      if (debugEnabled()) {
+        TRACER.debugCaught(DebugLogLevel.ERROR, ex);
+      }
+      throw new CryptoManagerException(
+           ERR_CRYPTOMGR_GET_MAC_ENGINE_CANNOT_INITIALIZE.get(
+                   getExceptionMessage(ex)), ex);
+    }
+
+    return mac;
+  }
+
+
+  /** {@inheritDoc} */
+  public String getPreferredMessageDigestAlgorithm()
+  {
+    return preferredDigestAlgorithm;
+  }
+
+
+  /** {@inheritDoc} */
+  public MessageDigest getPreferredMessageDigest()
+         throws NoSuchAlgorithmException
+  {
+    return MessageDigest.getInstance(preferredDigestAlgorithm);
+  }
+
+
+  /** {@inheritDoc} */
+  public MessageDigest getMessageDigest(String digestAlgorithm)
+         throws NoSuchAlgorithmException
+  {
+    return MessageDigest.getInstance(digestAlgorithm);
+  }
+
+
+  /** {@inheritDoc} */
+  public byte[] digest(byte[] data)
+         throws NoSuchAlgorithmException
+  {
+    return MessageDigest.getInstance(preferredDigestAlgorithm).
+                digest(data);
+  }
+
+
+  /** {@inheritDoc} */
+  public byte[] digest(String digestAlgorithm, byte[] data)
+         throws NoSuchAlgorithmException
+  {
+    return MessageDigest.getInstance(digestAlgorithm).digest(data);
+  }
+
+
+  /** {@inheritDoc} */
+  public byte[] digest(InputStream inputStream)
+         throws IOException, NoSuchAlgorithmException
+  {
+    MessageDigest digest =
+         MessageDigest.getInstance(preferredDigestAlgorithm);
+
+    byte[] buffer = new byte[8192];
+    while (true)
+    {
+      int bytesRead = inputStream.read(buffer);
+      if (bytesRead < 0)
+      {
+        break;
+      }
+
+      digest.update(buffer, 0, bytesRead);
+    }
+
+    return digest.digest();
+  }
+
+
+  /** {@inheritDoc} */
+  public byte[] digest(String digestAlgorithm,
+                       InputStream inputStream)
+         throws IOException, NoSuchAlgorithmException
+  {
+    MessageDigest digest = MessageDigest.getInstance(digestAlgorithm);
+
+    byte[] buffer = new byte[8192];
+    while (true)
+    {
+      int bytesRead = inputStream.read(buffer);
+      if (bytesRead < 0)
+      {
+        break;
+      }
+
+      digest.update(buffer, 0, bytesRead);
+    }
+
+    return digest.digest();
+  }
+
+
+  /** {@inheritDoc} */
+  public String getMacEngineKeyEntryID()
+          throws CryptoManagerException
+  {
+    return getMacEngineKeyEntryID(preferredMACAlgorithm,
+            preferredMACAlgorithmKeyLengthBits);
+  }
+
+
+  /** {@inheritDoc} */
+  public String getMacEngineKeyEntryID(final String macAlgorithm,
+                                       final int keyLengthBits)
+         throws CryptoManagerException {
+    Validator.ensureNotNull(macAlgorithm);
+
+    MacKeyEntry keyEntry = MacKeyEntry.getKeyEntry(this, macAlgorithm,
+                                                   keyLengthBits);
+    if (null == keyEntry) {
+      keyEntry = MacKeyEntry.generateKeyEntry(this, macAlgorithm,
+                                              keyLengthBits);
+    }
+
+    return keyEntry.getKeyID().getStringValue();
+  }
+
+
+  /** {@inheritDoc} */
+  public Mac getMacEngine(String keyEntryID)
+          throws CryptoManagerException
+  {
+    final MacKeyEntry keyEntry = MacKeyEntry.getKeyEntry(this,
+            new KeyEntryID(keyEntryID));
+    return (null == keyEntry) ? null : getMacEngine(keyEntry);
+  }
+
+
+  /** {@inheritDoc} */
+  public byte[] encrypt(byte[] data)
+         throws GeneralSecurityException, CryptoManagerException
+  {
+    return encrypt(preferredCipherTransformation,
+            preferredCipherTransformationKeyLengthBits, data);
+  }
+
+
+  /** {@inheritDoc} */
+  public byte[] encrypt(String cipherTransformation,
+                        int keyLengthBits,
+                        byte[] data)
+         throws GeneralSecurityException, CryptoManagerException
+  {
+    Validator.ensureNotNull(cipherTransformation, data);
+
+    CipherKeyEntry keyEntry = CipherKeyEntry.getKeyEntry(
+            this, cipherTransformation, keyLengthBits);
+    if (null == keyEntry) {
+      keyEntry = CipherKeyEntry.generateKeyEntry(this,
+              cipherTransformation, keyLengthBits);
+    }
+
+    final Cipher cipher
+            = getCipher(keyEntry, Cipher.ENCRYPT_MODE, null);
+
+    final byte[] keyID = keyEntry.getKeyID().getByteValue();
+    final byte[] iv = cipher.getIV();
+    final int prologueLength
+            = keyID.length + ((null == iv) ? 0 : iv.length);
+    final int dataLength = cipher.getOutputSize(data.length);
+    final byte[] cipherText = new byte[prologueLength + dataLength];
+    System.arraycopy(keyID, 0, cipherText, 0, keyID.length);
+    if (null != iv) {
+      System.arraycopy(iv, 0, cipherText, keyID.length, iv.length);
+    }
+    System.arraycopy(cipher.doFinal(data), 0, cipherText,
+                     prologueLength, dataLength);
+    return cipherText;
+  }
+
+
+  /** {@inheritDoc} */
+  public CipherOutputStream getCipherOutputStream(
+          OutputStream outputStream) throws CryptoManagerException
+  {
+    return getCipherOutputStream(preferredCipherTransformation,
+            preferredCipherTransformationKeyLengthBits, outputStream);
+  }
+
+
+  /** {@inheritDoc} */
+  public CipherOutputStream getCipherOutputStream(
+          String cipherTransformation, int keyLengthBits,
+          OutputStream outputStream)
+         throws CryptoManagerException
+  {
+    Validator.ensureNotNull(cipherTransformation, outputStream);
+
+    CipherKeyEntry keyEntry = CipherKeyEntry.getKeyEntry(
+            this, cipherTransformation, keyLengthBits);
+    if (null == keyEntry) {
+      keyEntry = CipherKeyEntry.generateKeyEntry(this,
+              cipherTransformation, keyLengthBits);
+    }
+
+    final Cipher cipher
+            = getCipher(keyEntry, Cipher.ENCRYPT_MODE, null);
+    final byte[] keyID = keyEntry.getKeyID().getByteValue();
+    try {
+      outputStream.write(keyID);
+      if (null != cipher.getIV()) {
+        outputStream.write(cipher.getIV());
+      }
+    }
+    catch (IOException ex) {
+      if (debugEnabled()) {
+        TRACER.debugCaught(DebugLogLevel.ERROR, ex);
+      }
+      throw new CryptoManagerException(
+             ERR_CRYPTOMGR_GET_CIPHER_STREAM_PROLOGUE_WRITE_ERROR.get(
+                     getExceptionMessage(ex)), ex);
+    }
+
+    return new CipherOutputStream(outputStream, cipher);
+  }
+
+
+  /** {@inheritDoc} */
+  public byte[] decrypt(byte[] data)
+         throws GeneralSecurityException,
+                CryptoManagerException
+  {
+    KeyEntryID keyID;
+    try {
+      final byte[] keyIDBytes
+              = new byte[KeyEntryID.getByteValueLength()];
+      System.arraycopy(data, 0, keyIDBytes, 0, keyIDBytes.length);
+      keyID = new KeyEntryID(keyIDBytes);
+    }
+    catch (Exception ex) {
+      // IndexOutOfBoundsException, ArrayStoreException, ...
+      if (debugEnabled()) {
+        TRACER.debugCaught(DebugLogLevel.ERROR, ex);
+      }
+      throw new CryptoManagerException(
+           ERR_CRYPTOMGR_DECRYPT_FAILED_TO_READ_KEY_IDENTIFIER.get(),
+              ex);
+    }
+
+    CipherKeyEntry keyEntry = CipherKeyEntry.getKeyEntry(this, keyID);
+    if (null == keyEntry) {
+      throw new CryptoManagerException(
+              ERR_CRYPTOMGR_DECRYPT_UNKNOWN_KEY_IDENTIFIER.get());
+    }
+
+    byte[] iv = null;
+    if (0 < keyEntry.getIVLengthBits()) {
+      iv = new byte[keyEntry.getIVLengthBits()/Byte.SIZE];
+      try {
+        System.arraycopy(data, KeyEntryID.getByteValueLength(), iv, 0,
+                iv.length);
+      }
+      catch (Exception ex) {
+        // IndexOutOfBoundsException, ArrayStoreException, ...
+        if (debugEnabled()) {
+          TRACER.debugCaught(DebugLogLevel.ERROR, ex);
+        }
+        throw new CryptoManagerException(
+               ERR_CRYPTOMGR_DECRYPT_FAILED_TO_READ_IV.get(), ex);
+      }
+    }
+
+    final Cipher cipher = getCipher(keyEntry, Cipher.DECRYPT_MODE,
+            iv);
+    final int prologueLength = KeyEntryID.getByteValueLength()
+                                     + ((null == iv) ? 0 : iv.length);
+    return cipher.doFinal(data, prologueLength,
+                          data.length - prologueLength);
+  }
+
+
+ /** {@inheritDoc} */
+  public CipherInputStream getCipherInputStream(
+          InputStream inputStream) throws CryptoManagerException
+  {
+    CipherKeyEntry keyEntry;
+    byte[] iv = null;
+    try {
+      final byte[] keyID = new byte[KeyEntryID.getByteValueLength()];
+      if (keyID.length != inputStream.read(keyID)){
+        throw new CryptoManagerException(
+           ERR_CRYPTOMGR_DECRYPT_FAILED_TO_READ_KEY_IDENTIFIER.get());
+      }
+      keyEntry = CipherKeyEntry.getKeyEntry(this,
+              new KeyEntryID(keyID));
+      if (null == keyEntry) {
+        throw new CryptoManagerException(
+                ERR_CRYPTOMGR_DECRYPT_UNKNOWN_KEY_IDENTIFIER.get());
+      }
+
+      if (0 < keyEntry.getIVLengthBits()) {
+        iv = new byte[keyEntry.getIVLengthBits() / Byte.SIZE];
+        if (iv.length != inputStream.read(iv)) {
+          throw new CryptoManagerException(
+                  ERR_CRYPTOMGR_DECRYPT_FAILED_TO_READ_IV.get());
+        }
+      }
+    }
+    catch (IOException ex) {
+      throw new CryptoManagerException(
+             ERR_CRYPTOMGR_DECRYPT_CIPHER_INPUT_STREAM_ERROR.get(
+                     getExceptionMessage(ex)), ex);
+    }
+
+    return new CipherInputStream(inputStream,
+            getCipher(keyEntry, Cipher.DECRYPT_MODE, iv));
+  }
+
+
+  /** {@inheritDoc} */
+  public int compress(byte[] src, byte[] dst)
+  {
+    Deflater deflater = new Deflater();
+    try
+    {
+      deflater.setInput(src);
+      deflater.finish();
+
+      int compressedLength = deflater.deflate(dst);
+      if (deflater.finished())
+      {
+        return compressedLength;
+      }
+      else
+      {
+        return -1;
+      }
+    }
+    finally
+    {
+      deflater.end();
+    }
+  }
+
+
+  /** {@inheritDoc} */
+  public int uncompress(byte[] src, byte[] dst)
+         throws DataFormatException
+  {
+    Inflater inflater = new Inflater();
+    try
+    {
+      inflater.setInput(src);
+
+      int decompressedLength = inflater.inflate(dst);
+      if (inflater.finished())
+      {
+        return decompressedLength;
+      }
+      else
+      {
+        int totalLength = decompressedLength;
+
+        while (! inflater.finished())
+        {
+          totalLength += inflater.inflate(dst);
+        }
+
+        return -totalLength;
+      }
+    }
+    finally
+    {
+      inflater.end();
+    }
+  }
+
+
+  /** {@inheritDoc} */
+  public SSLContext getSslContext(String sslCertNickname)
+       throws ConfigException
+  {
+    SSLContext sslContext;
+    try
+    {
+      TrustStoreBackend trustStoreBackend = getTrustStoreBackend();
+      KeyManager[] keyManagers = trustStoreBackend.getKeyManagers();
+      TrustManager[] trustManagers =
+           trustStoreBackend.getTrustManagers();
+
+      sslContext = SSLContext.getInstance("TLS");
+
+      if (sslCertNickname == null)
+      {
+        sslContext.init(keyManagers, trustManagers, null);
+      }
+      else
+      {
+        X509ExtendedKeyManager[] extendedKeyManagers =
+             SelectableCertificateKeyManager.wrap(
+                  keyManagers,
+                  sslCertNickname);
+        sslContext.init(extendedKeyManagers, trustManagers, null);
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+           ERR_CRYPTOMGR_SSL_CONTEXT_CANNOT_INITIALIZE.get(
+                getExceptionMessage(e));
+      throw new ConfigException(message, e);
+    }
+
+    return sslContext;
+  }
+
+
+  /** {@inheritDoc} */
+  public String getSslCertNickname()
+  {
+    return sslCertNickname;
+  }
+
+  /** {@inheritDoc} */
+  public boolean isSslEncryption()
+  {
+    return sslEncryption;
+  }
+
+  /** {@inheritDoc} */
+  public SortedSet<String> getSslProtocols()
+  {
+    return sslProtocols;
+  }
+
+  /** {@inheritDoc} */
+  public SortedSet<String> getSslCipherSuites()
+  {
+    return sslCipherSuites;
+  }
 }

--
Gitblit v1.10.0