From 31f5a4301e2f268718ed4cef28110fc25e8f7782 Mon Sep 17 00:00:00 2001
From: david_page <david_page@localhost>
Date: Sun, 09 Sep 2007 03:04:33 +0000
Subject: [PATCH] Issue 466 partial CryptoManager Refactor to separate key and key entry generation from key retrieval.
---
opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java | 10
opends/src/server/org/opends/server/types/CryptoManager.java | 570 ++++++++++++++++++++++++++++++++++++--------------------
2 files changed, 367 insertions(+), 213 deletions(-)
diff --git a/opends/src/server/org/opends/server/types/CryptoManager.java b/opends/src/server/org/opends/server/types/CryptoManager.java
index 8c23199..786cf44 100644
--- a/opends/src/server/org/opends/server/types/CryptoManager.java
+++ b/opends/src/server/org/opends/server/types/CryptoManager.java
@@ -33,7 +33,6 @@
import java.io.IOException;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
-import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -94,9 +93,9 @@
private static final Random pseudoRandom
= new Random(secureRandom.nextLong());
- // The map from encryption key ID to KeyEntry (cache).
- private final HashMap<ByteArray, KeyEntry> keyEntryMap
- = new HashMap<ByteArray, KeyEntry>();
+ // The map from encryption key ID to SecretKeyEntry (cache).
+ private final HashMap<ByteArray, SecretKeyEntry> secretKeyEntryMap
+ = new HashMap<ByteArray, SecretKeyEntry>();
// The preferred cipher for the Directory Server.
private final String preferredCipherTransformation;
@@ -141,7 +140,7 @@
public CryptoManager(CryptoManagerCfg cfg)
throws ConfigException, InitializationException
{
- // FIXME -- Get the defaults from the configuration rather than
+ // TODO -- Get the defaults from the configuration rather than
// hard-coding them.
preferredDigestAlgorithm = "SHA-1";
preferredMACAlgorithm = "HmacSHA1";
@@ -172,10 +171,11 @@
getExceptionMessage(e).toString()), e);
}
- byte[] keyValue = new byte[16];
- secureRandom.nextBytes(keyValue);
try
{
+ // TODO: wrap like encryption
+ byte[] keyValue = new byte[16];
+ secureRandom.nextBytes(keyValue);
Mac mac = Mac.getInstance(preferredMACAlgorithm);
mac.init(new SecretKeySpec(keyValue, preferredMACAlgorithm));
}
@@ -194,12 +194,9 @@
try
{
- Cipher cipher
- = Cipher.getInstance(preferredCipherTransformation);
- cipher.init(Cipher.ENCRYPT_MODE,
- new SecretKeySpec(keyValue,
- preferredCipherTransformation.substring(0,
- preferredCipherTransformation.indexOf('/'))));
+ SecretKeyEntry.generateKeyEntry(null,
+ preferredCipherTransformation,
+ preferredCipherTransformationKeyLength);
}
catch (Exception e)
{
@@ -216,7 +213,6 @@
}
-
/**
* Converts a UUID string into a compact byte[16] representation.
*
@@ -245,11 +241,10 @@
}
-
/**
- * Converts a UUID string into a compact byte[16] representation.
+ * Converts a UUID instance into a compact byte[16] representation.
*
- * @param uuid A UUID.
+ * @param uuid A UUID instance.
*
* @return A new byte[16] containing the binary representation of
* the UUID.
@@ -269,7 +264,6 @@
}
-
/**
* Retrieves the name of the preferred message digest algorithm.
*
@@ -281,7 +275,6 @@
}
-
/**
* Retrieves a <CODE>MessageDigest</CODE> object that may be used to
* generate digests using the preferred digest algorithm.
@@ -649,19 +642,20 @@
* used in the local cache of key entries that have been requested
* by CryptoManager clients.
*/
- private static class KeyEntry
+ private static class SecretKeyEntry
{
/**
- * Retrieve a KeyEntry from the KeyEntry Map based on cipher
- * transformation name and key length. If the parameters are valid
- * but a corresponding entry does not exist in the supplied map,
- * create the entry and add it to the map.
+ * This method generates a key according to the key parameters,
+ * and creates a key entry and registers it in the supplied map.
*
- * @param map The KeyEntry Map containing the key.
+ * @param map The SecretKeyEntry Map in which the key is to be
+ * stored. Pass null as the argument to this parameter in order to
+ * validate a proposed cipher transformation and key length.
*
- * @param transformation The cipher transformation.
+ * @param transformation The cipher transformation for which the
+ * key is to be produced.
*
- * @param keyLengthBits The cipher key length in bits.
+ * @param keyLengthBits The cipher key length in bits.
*
* @return The key entry corresponding to the parameters.
*
@@ -669,48 +663,67 @@
* instantiating a Cipher object in order to validate the supplied
* parameters when creating a new entry.
*/
- public static KeyEntry getKeyEntry(
- final Map<ByteArray,KeyEntry> map,
+ public static SecretKeyEntry generateKeyEntry(
+ final Map<ByteArray, SecretKeyEntry> map,
final String transformation,
final int keyLengthBits)
- throws CryptoManagerException {
- KeyEntry keyEntry = null;
+ throws CryptoManagerException {
- // search for existing key satisfying request
- for (Map.Entry<ByteArray, KeyEntry> i: map.entrySet()) {
- KeyEntry entry = i.getValue();
- if (! entry.fIsCompromised
- && entry.fTransformation.equals(transformation)
- && entry.fKey.length * Byte.SIZE == keyLengthBits) {
- assert Arrays.equals(i.getKey().array(), entry.fKeyID);
- keyEntry = entry;
- break;
+ SecretKeyEntry keyEntry;
+
+ // check for existing uncompromised key.
+ if (null != map) {
+ keyEntry = getKeyEntry(map, transformation, keyLengthBits);
+ if (null != keyEntry) {
+ return keyEntry;
}
}
- if (null == keyEntry) {
- if (0 != keyLengthBits % Byte.SIZE) {
- throw new CryptoManagerException(
- // TODO: i18n
- Message.raw("keyLength parameter must be evenly " +
- "divisible by %d.", Byte.SIZE));
- }
+ // generate a new key
+ if (0 != keyLengthBits % Byte.SIZE) {
+ throw new CryptoManagerException(
+ // TODO: i18n
+ Message.raw("keyLengthBits argument must be evenly"
+ + " divisible by %d.", Byte.SIZE));
+ }
- // TODO: Does ADS monitoring thread keep map updated with keys
- // produced at other sites? Otherwise, search ADS for suitable
- // key.
+ // In case a transformation is supplied instead of an algorithm:
+ // E.g., AES/CBC/PKCS5Padding -> AES
+ final int separatorIndex = transformation.indexOf('/');
+ final String keyAlgorithm = (0 < separatorIndex)
+ ? transformation.substring(0, separatorIndex)
+ : transformation;
+ KeyGenerator keyGen;
+ try {
+ keyGen = KeyGenerator.getInstance(keyAlgorithm);
+ }
+ catch (NoSuchAlgorithmException ex) {
+ throw new CryptoManagerException(
+ // TODO: i18n
+ Message.raw("Unable to produce key generator from" +
+ " cipher transformation argument %s",
+ transformation), ex);
+ }
+ keyGen.init(keyLengthBits, secureRandom);
+ final byte[] key = keyGen.generateKey().getEncoded();
- // generate a new key
- final byte[] keyID = uuidToBytes(UUID.randomUUID());
- final byte[] key = new byte[keyLengthBits / Byte.SIZE];
- secureRandom.nextBytes(key);
- keyEntry = new KeyEntry(keyID, transformation, key,
- /* compute IV length */ -1);
+ // generate the key entry
+ final byte[] keyID = uuidToBytes(UUID.randomUUID());
+ keyEntry = new SecretKeyEntry(keyID, transformation,
+ keyAlgorithm, key, /* compute IV length */ -1, false);
+ // Validate the entry. Pass the keyAlgorithm for the cipher
+ // transformation.
+ final Cipher cipher
+ = getCipher(keyEntry, Cipher.ENCRYPT_MODE, null);
+ final byte[] iv = cipher.getIV();
+ keyEntry.setIVLengthBits(
+ (null == iv) ? 0 : iv.length * Byte.SIZE);
+
+ if (null != map) {
map.put(new ByteArray(keyID), keyEntry);
-
- // TODO: publish key to ADS. (mark key "blocked" in map until
- // registered?)
+ // TODO: publish key to ADS. (mark key "blocked" in map
+ // until registered?)
}
return keyEntry;
@@ -718,7 +731,132 @@
/**
- * Given a key identifier, return the associated key entry.
+ * Initializes a secret key entry from the supplied parameters,
+ * validates it, and registers it in the supplied map. The
+ * anticipated use of this method is to import a key entry from
+ * ADS.
+ *
+ * @param map The secret key map.
+ *
+ * @param keyID The key identifier.
+ *
+ * @param transformation The cipher transformation for which the
+ * key entry was produced.
+ *
+ * @param keyAlgorithm The cipher algorithm for which the key was
+ * produced.
+ *
+ * @param key The cipher key.
+ *
+ * @param ivLengthBits The length of the initialization vector,
+ * which will be zero in the case of any stream cipher algorithm,
+ * or any block cipher algorithm for which the transformation mode
+ * does not use an initialization vector.
+ *
+ * @param isCompromised Mark the key as compromised, so that it
+ * will not subsequently be used for encryption. The key must be
+ * maintained in order to decrypt existing ciphertext.
+ *
+ * @return The key entry, if one was successfully produced.
+ *
+ * @throws CryptoManagerException In case of an error in the
+ * parameters used to initialize or validate the key entry.
+ */
+ public static SecretKeyEntry setKeyEntry(
+ final Map<ByteArray, SecretKeyEntry> map,
+ final byte[] keyID,
+ final String transformation,
+ final String keyAlgorithm,
+ final byte[] key,
+ final int ivLengthBits,
+ final boolean isCompromised)
+ throws CryptoManagerException {
+ Validator.ensureNotNull(keyID, transformation, keyAlgorithm,
+ key);
+ Validator.ensureTrue(16 == keyID.length);
+ Validator.ensureTrue(0 <= ivLengthBits);
+
+ // Check map for existing key entry with the supplied keyID.
+ SecretKeyEntry keyEntry = getKeyEntry(map, keyID);
+ if (null != keyEntry) {
+ // TODO: compare keyEntry with supplied parameters to ensure
+ // equal.
+ return keyEntry;
+ }
+
+ // Instantiate new entry.
+ keyEntry = new SecretKeyEntry(keyID, transformation,
+ keyAlgorithm, key, ivLengthBits, isCompromised);
+
+ // Validate the entry. Pass the keyAlgorithm for the cipher
+ // transformation.
+ byte[] iv = null;
+ if (0 < ivLengthBits) {
+ iv = new byte[ivLengthBits * Byte.SIZE];
+ pseudoRandom.nextBytes(iv);
+ }
+ getCipher(keyEntry, Cipher.DECRYPT_MODE, iv);
+
+ map.put(new ByteArray(keyID), keyEntry);
+
+ return keyEntry;
+ }
+
+
+ /**
+ * Retrieve a SecretKeyEntry from the SecretKeyEntry Map based on
+ * cipher algorithm name and key length.
+ *
+ * @param map The SecretKeyEntry Map in which the key is stored.
+ *
+ * @param transformation The cipher algorithm for which the key
+ * was produced.
+ *
+ * @param keyLengthBits The cipher key length in bits.
+ *
+ * @return The key entry corresponding to the parameters, or null
+ * if no such entry exists.
+ */
+ public static SecretKeyEntry getKeyEntry(
+ final Map<ByteArray, SecretKeyEntry> map,
+ final String transformation,
+ final int keyLengthBits) {
+ Validator.ensureNotNull(map, transformation);
+ Validator.ensureTrue(0 < keyLengthBits);
+
+ SecretKeyEntry keyEntry = null;
+
+ // search for an existing key that satisfies the request
+ for (Map.Entry<ByteArray, SecretKeyEntry> i: map.entrySet()) {
+ SecretKeyEntry entry = i.getValue();
+ if (! entry.fIsCompromised
+ && entry.getTransformation().equals(transformation)
+ && entry.fKeyLengthBits == keyLengthBits) {
+ assert Arrays.equals(i.getKey().array(), entry.fKeyID);
+ keyEntry = entry;
+ break;
+ }
+ }
+
+ // TODO: if (null == keyEntry) Does ADS monitoring thread keep
+ // map updated with keys produced at other sites? Otherwise,
+ // search ADS for suitable key.
+
+ // TODO: if (null == keyEntry) consider generating key here.
+
+ if (null != keyEntry) {
+ Validator.ensureTrue(0 <= keyEntry.getIVLength(),
+ "SecretKeyEntry initialization is not complete.");
+ }
+
+ return keyEntry;
+ }
+
+
+ /**
+ * Given a key identifier, return the associated secret key entry
+ * from the supplied map. This method would typically be used by
+ * a decryption routine.
*
* @param map The local cache of key entries.
*
@@ -726,8 +864,8 @@
*
* @return The key entry associated with the key identifier.
*/
- public static KeyEntry getKeyEntry(Map<ByteArray,KeyEntry> map,
- byte[] keyID) {
+ public static SecretKeyEntry getKeyEntry(
+ Map<ByteArray, SecretKeyEntry> map, byte[] keyID) {
return map.get(new ByteArray(keyID));
/* TODO: Does ADS monitorying thread keep map updated with keys
produced at other sites? If not, fetch from ADS and update
@@ -737,16 +875,21 @@
/**
- * Construct an instance of KeyEntry using the specified
- * parameters. This constructor may be used for both locally
- * generated (new) keys and keys imported from ADS. The parameters
- * are validated by using them to create and initialize a Cipher
- * object.
+ * Construct an instance of SecretKeyEntry using the specified
+ * parameters. This constructor would typically be used for key
+ * entries imported from ADS, for which the full set of paramters
+ * is known, and for a new key entry, for which the initialization
+ * vector length might not yet be known, but which must be set
+ * before use.
*
* @param keyID The unique identifier of this cipher
- * transformation/key pair.
+ * transformation/key pair.
*
- * @param transformation The cipher transformation name.
+ * @param transformation The secret-key cipher transformation for
+ * which the key entry is to be produced.
+ *
+ * @param keyAlgorithm The secret key cipher algorithm for which
+ * the key was produced.
*
* @param key The cipher key.
*
@@ -757,28 +900,43 @@
* the cipher block size and then, if the cipher block size is
* non-zero, using 0 (i.e., no initialization vector).
*
+ * @param isCompromised If the key
+ *
* @throws CryptoManagerException If there is a problem
* instantiating a Cipher object in order to validate the supplied
* parameters when creating a new entry.
*/
- public KeyEntry( final byte[] keyID, final String transformation,
- final byte[] key, final int ivLengthBits)
+ private SecretKeyEntry( final byte[] keyID,
+ final String transformation,
+ final String keyAlgorithm,
+ final byte[] key,
+ final int ivLengthBits,
+ final boolean isCompromised)
throws CryptoManagerException {
+ Validator.ensureNotNull(keyID, transformation, key);
+ Validator.ensureTrue(16 == keyID.length); // FIXME: const for id
+
// copy arguments
this.fKeyID = new byte[keyID.length];
System.arraycopy(keyID, 0, this.fKeyID, 0, keyID.length);
this.fTransformation = new String(transformation);
- this.fKey = new byte[key.length];
- System.arraycopy(key, 0,
- this.fKey, 0, key.length);
+ this.fKeySpec = new SecretKeySpec(key, keyAlgorithm);
+ this.fKeyLengthBits = key.length * Byte.SIZE;
this.fIVLengthBits = ivLengthBits;
-
- // validate the entry.
- getCipher(Cipher.ENCRYPT_MODE, null);
+ this.fIsCompromised = isCompromised;
}
/**
+ * The cipher transformation for which the key entry was created.
+ *
+ * @return The cipher transformation.
+ */
+ public String getTransformation() {
+ return fTransformation;
+ }
+
+ /**
* The unique identifier of this cipher transformation/key pair.
*
* @return The unique identifier of this cipher transformation/key
@@ -790,22 +948,12 @@
/**
- * The cipher transformation name.
+ * The secret key spec containing the secret key.
*
- * @return The cipher transformation name.
+ * @return The secret key spec containing the secret key.
*/
- public String getTransformation() {
- return fTransformation;
- }
-
-
- /**
- * The cipher key.
- *
- * @return The cipher key.
- */
- public byte[] getKey() {
- return fKey;
+ public SecretKeySpec getKeySpec() {
+ return fKeySpec;
}
@@ -813,112 +961,28 @@
* The initialization vector length in bits: 0 is a stream cipher
* or a block cipher that does not use an IV (e.g., ECB); or a
* positive integer, typically the block size of the cipher.
+ * <p>
+ * This method returns -1 if the object initialization has not
+ * been completed.
*
* @return The initialization vector length.
*/
public int getIVLength() {
- assert 0 <= fIVLengthBits : "The field was not initialized.";
return fIVLengthBits;
}
/**
- * This method produces and initialized Cipher based on this
- * KeyEntry's state and the method parameters.
+ * Set the algorithm/key pair's required initialization vector
+ * length in bits. Typically, this will be the cipher's block
+ * size, or 0 for a stream cipher or a block cipher mode that does
+ * not use an initialization vector (e.g., ECB).
*
- * @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.
+ * @param ivLengthBits The initiazliation vector length in bits.
*/
- public Cipher getCipher(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 != fIVLengthBits
- || Cipher.ENCRYPT_MODE == mode);
- Validator.ensureTrue(null == initializationVector
- || initializationVector.length * Byte.SIZE
- == fIVLengthBits);
-
- Cipher cipher;
- try {
- cipher = Cipher.getInstance(fTransformation);
- }
- catch (GeneralSecurityException ex) {
- // NoSuchAlgorithmException, NoSuchPaddingException
- throw new CryptoManagerException(
- // TODO: i18n
- Message.raw("Invalid cipher transformation %s.",
- fTransformation), ex);
- }
-
- try {
- if (-1 == fIVLengthBits) {
- /* Unknown initialization vector length on encryption. This
- method will first try the cipher block size, then, if
- that is non-zero and rejected, retry without an
- initialization vector. */
- fIVLengthBits = cipher.getBlockSize() * Byte.SIZE;
- }
-
- // E.g., AES/CBC/PKCS5Padding -> AES
- final int separatorIndex = fTransformation.indexOf('/');
- final String cipherAlgorithm = (0 < separatorIndex)
- ? fTransformation.substring(0, separatorIndex)
- : fTransformation;
-
- if (0 < fIVLengthBits) {
- try {
- byte[] iv;
- if (Cipher.ENCRYPT_MODE == mode
- && null == initializationVector) {
- iv = new byte[fIVLengthBits / Byte.SIZE];
- pseudoRandom.nextBytes(iv);
- }
- else {
- iv = initializationVector;
- }
- cipher.init(mode,
- new SecretKeySpec(fKey, cipherAlgorithm),
- new IvParameterSpec(iv));
- }
- catch (InvalidAlgorithmParameterException ex) {
- if (Cipher.ENCRYPT_MODE == mode) {
- /* Some block cipher modes (e.g., ECB) and all stream
- ciphers do not use an initialization vector. Set
- length to 0 and retry below */
- fIVLengthBits = 0;
- }
- else {
- throw ex;
- }
- }
- }
-
- if (0 == fIVLengthBits) {
- cipher.init(mode, new SecretKeySpec(fKey, cipherAlgorithm));
- }
- }
- catch (GeneralSecurityException ex) {
- // InvalidKeyException, InvalidAlgorithmParameterException
- throw new CryptoManagerException(
- // TODO: i18n
- Message.raw("Error initializing cipher."), ex);
- }
-
- return cipher;
+ private void setIVLengthBits(int ivLengthBits) {
+ Validator.ensureTrue(-1 == fIVLengthBits && 0 <= ivLengthBits);
+ fIVLengthBits = ivLengthBits;
}
@@ -934,13 +998,90 @@
// state
private final byte[] fKeyID;
private final String fTransformation;
- private final byte[] fKey;
+ private final SecretKeySpec fKeySpec;
+ private final int fKeyLengthBits;
private int fIVLengthBits;
private boolean fIsCompromised = false;
}
/**
+ * This method produces and initialized Cipher based on this
+ * SecretKeyEntry's state and the method parameters.
+ *
+ * @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 SecretKeyEntry 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.getIVLength()
+ || Cipher.ENCRYPT_MODE == mode);
+ Validator.ensureTrue(null == initializationVector
+ || initializationVector.length * Byte.SIZE
+ == keyEntry.getIVLength());
+
+ Cipher cipher;
+ try {
+ cipher = Cipher.getInstance(keyEntry.getTransformation());
+ }
+ catch (GeneralSecurityException ex) {
+ // NoSuchAlgorithmException, NoSuchPaddingException
+ throw new CryptoManagerException(
+ // TODO: i18n
+ Message.raw("Invalid cipher transformation specified"
+ + " %s.", keyEntry.getTransformation()), ex);
+ }
+
+ try {
+ if (0 < keyEntry.getIVLength()) {
+ byte[] iv;
+ if (Cipher.ENCRYPT_MODE == mode
+ && null == initializationVector) {
+ iv = new byte[keyEntry.getIVLength() / Byte.SIZE];
+ pseudoRandom.nextBytes(iv);
+ }
+ else {
+ iv = initializationVector;
+ }
+ cipher.init(mode, keyEntry.getKeySpec(),
+ new IvParameterSpec(iv));
+ }
+ else {
+ cipher.init(mode, keyEntry.getKeySpec());
+ }
+ }
+ catch (GeneralSecurityException ex) {
+ // InvalidKeyException, InvalidAlgorithmParameterException
+ throw new CryptoManagerException(
+ // TODO: i18n
+ Message.raw("Error initializing cipher."), ex);
+ }
+
+ return cipher;
+ }
+
+
+ /**
* Encrypts the data in the provided byte array using the preferred
* cipher transformation.
*
@@ -970,8 +1111,8 @@
* @param cipherTransformation The algorithm/mode/padding to use
* for the cipher.
*
- * @param keyLength The length in bits of the encryption key this
- * method is to use. Note the specified key length and
+ * @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.
@@ -985,16 +1126,23 @@
* @throws CryptoManagerException If a problem occurs managing the
* encryption key or producing the cipher.
*/
- public byte[] encrypt(String cipherTransformation, int keyLength,
+ public byte[] encrypt(String cipherTransformation,
+ int keyLengthBits,
byte[] data)
throws GeneralSecurityException, CryptoManagerException
{
- Validator.ensureNotNull(cipherTransformation, keyLength, data);
+ Validator.ensureNotNull(cipherTransformation, data);
- final KeyEntry keyEntry = KeyEntry.getKeyEntry(keyEntryMap,
- cipherTransformation, keyLength);
+ SecretKeyEntry keyEntry = SecretKeyEntry.getKeyEntry(
+ secretKeyEntryMap, cipherTransformation, keyLengthBits);
+ if (null == keyEntry) {
+ keyEntry = SecretKeyEntry.generateKeyEntry(secretKeyEntryMap,
+ cipherTransformation, keyLengthBits);
+ }
+
final Cipher cipher
- = keyEntry.getCipher(Cipher.ENCRYPT_MODE, null);
+ = getCipher(keyEntry, Cipher.ENCRYPT_MODE, null);
+
final byte[] keyID = keyEntry.getKeyID();
final byte[] iv = cipher.getIV();
final int prologueLength
@@ -1038,9 +1186,9 @@
* @param cipherTransformation The algorithm/mode/padding to use
* for the cipher.
*
- * @param keyLength The length in bits of the encryption key this
- * method will generate. Note the specified key length must
- * be compatible with the transformation.
+ * @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.
@@ -1051,17 +1199,21 @@
* encryption key or producing the cipher.
*/
public CipherOutputStream getCipherOutputStream(
- String cipherTransformation, int keyLength,
+ String cipherTransformation, int keyLengthBits,
OutputStream outputStream)
throws CryptoManagerException
{
- Validator.ensureNotNull(cipherTransformation, keyLength,
- outputStream);
+ Validator.ensureNotNull(cipherTransformation, outputStream);
- final KeyEntry keyEntry = KeyEntry.getKeyEntry(keyEntryMap,
- cipherTransformation, keyLength);
+ SecretKeyEntry keyEntry = SecretKeyEntry.getKeyEntry(
+ secretKeyEntryMap, cipherTransformation, keyLengthBits);
+ if (null == keyEntry) {
+ keyEntry = SecretKeyEntry.generateKeyEntry(secretKeyEntryMap,
+ cipherTransformation, keyLengthBits);
+ }
+
final Cipher cipher
- = keyEntry.getCipher(Cipher.ENCRYPT_MODE, null);
+ = getCipher(keyEntry, Cipher.ENCRYPT_MODE, null);
final byte[] keyID = keyEntry.getKeyID();
try {
outputStream.write(keyID);
@@ -1113,7 +1265,8 @@
" data prologue."), ex);
}
- KeyEntry keyEntry = KeyEntry.getKeyEntry(keyEntryMap, keyID);
+ SecretKeyEntry keyEntry
+ = SecretKeyEntry.getKeyEntry(secretKeyEntryMap, keyID);
if (null == keyEntry) {
throw new CryptoManagerException(
// TODO: i18N
@@ -1135,7 +1288,8 @@
}
}
- final Cipher cipher = keyEntry.getCipher(Cipher.DECRYPT_MODE, iv);
+ final Cipher cipher
+ = getCipher(keyEntry, Cipher.DECRYPT_MODE, iv);
final int prologueLength
= keyID.length + ((null == iv) ? 0 : iv.length);
return cipher.doFinal(data, prologueLength,
@@ -1160,7 +1314,7 @@
public CipherInputStream getCipherInputStream(
InputStream inputStream) throws CryptoManagerException
{
- KeyEntry keyEntry;
+ SecretKeyEntry keyEntry;
byte[] iv = null;
try {
final byte[] keyID = new byte[16]; //FIXME: key length constant
@@ -1171,7 +1325,7 @@
" identifier from data prologue."));
}
- keyEntry = KeyEntry.getKeyEntry(keyEntryMap, keyID);
+ keyEntry = SecretKeyEntry.getKeyEntry(secretKeyEntryMap, keyID);
if (null == keyEntry) {
throw new CryptoManagerException(
// TODO: i18N
@@ -1197,7 +1351,7 @@
}
return new CipherInputStream(inputStream,
- keyEntry.getCipher(Cipher.DECRYPT_MODE, iv));
+ getCipher(keyEntry, Cipher.DECRYPT_MODE, iv));
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java
index a1480f5..794970e 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java
@@ -150,7 +150,7 @@
tempFile.deleteOnExit();
OutputStream os = new FileOutputStream(tempFile);
- os = cm.getCipherOutputStream("Blowfish/CFB/NoPadding", 64, os);
+ os = cm.getCipherOutputStream("Blowfish/CFB/NoPadding", 128, os);
os.write(secretMessage.getBytes());
os.close();
@@ -223,7 +223,7 @@
final CryptoManager cm = DirectoryServer.getCryptoManager();
final String secretMessage = "1234";
- final byte[] cipherText = cm.encrypt("DES/CFB/NoPadding", 64,
+ final byte[] cipherText = cm.encrypt("DES/CFB/NoPadding", 56,
secretMessage.getBytes());
assertEquals(-1, (new String(cipherText)).indexOf(secretMessage));
@@ -246,7 +246,7 @@
tempFile.deleteOnExit();
OutputStream os = new FileOutputStream(tempFile);
- os = cm.getCipherOutputStream("DES/CFB/NoPadding", 64, os);
+ os = cm.getCipherOutputStream("DES/CFB/NoPadding", 56, os);
os.write(secretMessage.getBytes());
os.close();
@@ -271,7 +271,7 @@
final CryptoManager cm = DirectoryServer.getCryptoManager();
final String secretMessage = "1234";
- final byte[] cipherText = cm.encrypt("DES/ECB/PKCS5Padding", 64,
+ final byte[] cipherText = cm.encrypt("DESede/ECB/PKCS5Padding", 168,
secretMessage.getBytes());
assertEquals(-1, (new String(cipherText)).indexOf(secretMessage));
@@ -294,7 +294,7 @@
tempFile.deleteOnExit();
OutputStream os = new FileOutputStream(tempFile);
- os = cm.getCipherOutputStream("DES/ECB/PKCS5Padding", 64, os);
+ os = cm.getCipherOutputStream("DESede/ECB/PKCS5Padding", 168, os);
os.write(secretMessage.getBytes());
os.close();
--
Gitblit v1.10.0