From 4adb907371925d48ff3cd42cedbd644080b064c2 Mon Sep 17 00:00:00 2001
From: david_page <david_page@localhost>
Date: Mon, 15 Oct 2007 17:37:06 +0000
Subject: [PATCH] no issue CryptoManager Add a single-byte version number prefix to the ciphertext prologue to allow for configurable options (e.g., signed hash in the backup stream). The current version produced and accepted is 0x01.

---
 opends/src/server/org/opends/server/crypto/CryptoManagerImpl.java |  107 ++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 80 insertions(+), 27 deletions(-)

diff --git a/opends/src/server/org/opends/server/crypto/CryptoManagerImpl.java b/opends/src/server/org/opends/server/crypto/CryptoManagerImpl.java
index d1a7a3c..a455682 100644
--- a/opends/src/server/org/opends/server/crypto/CryptoManagerImpl.java
+++ b/opends/src/server/org/opends/server/crypto/CryptoManagerImpl.java
@@ -159,6 +159,15 @@
   // The preferred message digest algorithm for the Directory Server.
   private String preferredDigestAlgorithm;
 
+  // The first byte in any ciphertext produced by CryptoManager is the
+  // prologue version. At present, this constant is both the version written
+  // and the expected version. If a new version is introduced (e.g., to allow
+  // embedding the HMAC key identifier and signature in a signed backup) the
+  // prologue version will likely need to be configurable at the granularity
+  // of the CryptoManager client (e.g., password encryption might use version 1,
+  // while signed backups might use version 2.
+  private static final int CIPHERTEXT_PROLOGUE_VERSION = 1 ;
+
   // The map from encryption key ID to MacKeyEntry (cache). The cache
   // is accessed by methods that request, publish, and import keys.
   private final Map<KeyEntryID, MacKeyEntry> macKeyEntryCache
@@ -2802,25 +2811,28 @@
   {
     Validator.ensureNotNull(cipherTransformation, data);
 
-    CipherKeyEntry keyEntry = CipherKeyEntry.getKeyEntry(
-            this, cipherTransformation, keyLengthBits);
+    CipherKeyEntry keyEntry = CipherKeyEntry.getKeyEntry(this,
+            cipherTransformation, keyLengthBits);
     if (null == keyEntry) {
-      keyEntry = CipherKeyEntry.generateKeyEntry(this,
-              cipherTransformation, keyLengthBits);
+      keyEntry = CipherKeyEntry.generateKeyEntry(this, cipherTransformation,
+              keyLengthBits);
     }
 
-    final Cipher cipher
-            = getCipher(keyEntry, Cipher.ENCRYPT_MODE, null);
+    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);
+            = /* version */ 1 + 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);
+    int writeIndex = 0;
+    cipherText[writeIndex++] = CIPHERTEXT_PROLOGUE_VERSION;
+    System.arraycopy(keyID, 0, cipherText, writeIndex, keyID.length);
+    writeIndex += keyID.length;
     if (null != iv) {
-      System.arraycopy(iv, 0, cipherText, keyID.length, iv.length);
+      System.arraycopy(iv, 0, cipherText, writeIndex, iv.length);
+      writeIndex += iv.length;
     }
     System.arraycopy(cipher.doFinal(data), 0, cipherText,
                      prologueLength, dataLength);
@@ -2848,14 +2860,14 @@
     CipherKeyEntry keyEntry = CipherKeyEntry.getKeyEntry(
             this, cipherTransformation, keyLengthBits);
     if (null == keyEntry) {
-      keyEntry = CipherKeyEntry.generateKeyEntry(this,
-              cipherTransformation, keyLengthBits);
+      keyEntry = CipherKeyEntry.generateKeyEntry(this, cipherTransformation,
+              keyLengthBits);
     }
 
-    final Cipher cipher
-            = getCipher(keyEntry, Cipher.ENCRYPT_MODE, null);
+    final Cipher cipher = getCipher(keyEntry, Cipher.ENCRYPT_MODE, null);
     final byte[] keyID = keyEntry.getKeyID().getByteValue();
     try {
+      outputStream.write((byte)CIPHERTEXT_PROLOGUE_VERSION);
       outputStream.write(keyID);
       if (null != cipher.getIV()) {
         outputStream.write(cipher.getIV());
@@ -2879,11 +2891,37 @@
          throws GeneralSecurityException,
                 CryptoManagerException
   {
+    int readIndex = 0;
+
+    int version;
+    try {
+      version = data[readIndex++];
+    }
+    catch (Exception ex) {
+      // IndexOutOfBoundsException, ArrayStoreException, ...
+      if (debugEnabled()) {
+        TRACER.debugCaught(DebugLogLevel.ERROR, ex);
+      }
+      throw new CryptoManagerException(
+              ERR_CRYPTOMGR_DECRYPT_FAILED_TO_READ_PROLOGUE_VERSION.get(
+                      ex.getMessage()), ex);
+    }
+    switch (version) {
+      case CIPHERTEXT_PROLOGUE_VERSION:
+        // Encryption key identifier only in the data prologue.
+        break;
+
+      default:
+        throw new CryptoManagerException(
+                ERR_CRYPTOMGR_DECRYPT_UNKNOWN_PROLOGUE_VERSION.get(version));
+    }
+
     KeyEntryID keyID;
     try {
       final byte[] keyIDBytes
               = new byte[KeyEntryID.getByteValueLength()];
-      System.arraycopy(data, 0, keyIDBytes, 0, keyIDBytes.length);
+      System.arraycopy(data, readIndex, keyIDBytes, 0, keyIDBytes.length);
+      readIndex += keyIDBytes.length;
       keyID = new KeyEntryID(keyIDBytes);
     }
     catch (Exception ex) {
@@ -2892,8 +2930,8 @@
         TRACER.debugCaught(DebugLogLevel.ERROR, ex);
       }
       throw new CryptoManagerException(
-           ERR_CRYPTOMGR_DECRYPT_FAILED_TO_READ_KEY_IDENTIFIER.get(),
-              ex);
+           ERR_CRYPTOMGR_DECRYPT_FAILED_TO_READ_KEY_IDENTIFIER.get(
+                   ex.getMessage()), ex);
     }
 
     CipherKeyEntry keyEntry = CipherKeyEntry.getKeyEntry(this, keyID);
@@ -2906,8 +2944,8 @@
     if (0 < keyEntry.getIVLengthBits()) {
       iv = new byte[keyEntry.getIVLengthBits()/Byte.SIZE];
       try {
-        System.arraycopy(data, KeyEntryID.getByteValueLength(), iv, 0,
-                iv.length);
+        System.arraycopy(data, readIndex, iv, 0, iv.length);
+        readIndex += iv.length;
       }
       catch (Exception ex) {
         // IndexOutOfBoundsException, ArrayStoreException, ...
@@ -2919,12 +2957,8 @@
       }
     }
 
-    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);
+    final Cipher cipher = getCipher(keyEntry, Cipher.DECRYPT_MODE, iv);
+    return cipher.doFinal(data, readIndex, data.length - readIndex);
   }
 
 
@@ -2932,13 +2966,32 @@
   public CipherInputStream getCipherInputStream(
           InputStream inputStream) throws CryptoManagerException
   {
+    int version;
     CipherKeyEntry keyEntry;
     byte[] iv = null;
     try {
-      final byte[] keyID = new byte[KeyEntryID.getByteValueLength()];
-      if (keyID.length != inputStream.read(keyID)){
+      final byte[] rawVersion = new byte[1];
+      if (rawVersion.length != inputStream.read(rawVersion)) {
         throw new CryptoManagerException(
-           ERR_CRYPTOMGR_DECRYPT_FAILED_TO_READ_KEY_IDENTIFIER.get());
+                ERR_CRYPTOMGR_DECRYPT_FAILED_TO_READ_PROLOGUE_VERSION.get(
+                      "stream underflow"));
+      }
+      version = rawVersion[0];
+      switch (version) {
+        case CIPHERTEXT_PROLOGUE_VERSION:
+          // Encryption key identifier only in the data prologue.
+          break;
+
+        default:
+          throw new CryptoManagerException(
+                  ERR_CRYPTOMGR_DECRYPT_UNKNOWN_PROLOGUE_VERSION.get(version));
+      }
+
+      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(
+                   "stream underflow"));
       }
       keyEntry = CipherKeyEntry.getKeyEntry(this,
               new KeyEntryID(keyID));

--
Gitblit v1.10.0