diff dcrypt/crypto/modes/CBC.d @ 27:8b5eaf3c2979

Fixed error in hash message padding reported by Glenn Haecker.
author Thomas Dixon <reikon@reikon.us>
date Sat, 09 May 2009 23:29:20 -0400
parents 176c933827a8
children ad687db713a4
line wrap: on
line diff
--- a/dcrypt/crypto/modes/CBC.d	Sun Mar 01 13:06:48 2009 -0500
+++ b/dcrypt/crypto/modes/CBC.d	Sat May 09 23:29:20 2009 -0400
@@ -11,34 +11,41 @@
 import dcrypt.crypto.BlockCipher;
 public import dcrypt.crypto.params.ParametersWithIV;
 
-debug (UnitTest) {
+debug (UnitTest)
+{
     import dcrypt.crypto.ciphers.XTEA;
     import dcrypt.misc.ByteConverter;
 }
 
 /** This class implements the cipher block chaining (CBC) block mode. */
-class CBC : BlockCipher {
-    private BlockCipher wrappedCipher;
-    private ubyte[] iv,
-                    previousCiphertext,
-                    cbcOutput;
-    private bool encrypt,
-                 initialized;
+class CBC : BlockCipher
+{
+    private
+    {
+         BlockCipher wrappedCipher;
+         
+         ubyte[] iv,
+                 previousBlock,
+                 currentBlock;
+    }
     
     /**
      * Params:
      *     cipher = Block cipher to wrap.
      */
-    this (BlockCipher cipher) {
+    this (BlockCipher cipher)
+    {
         wrappedCipher = cipher;
     }
     
     /** Returns: The underlying cipher we are wrapping. */
-    BlockCipher cipher() {
+    BlockCipher cipher()
+    {
         return wrappedCipher;
     }
     
-    char[] name() {
+    char[] name()
+    {
         return wrappedCipher.name~"/CBC";
     }
     
@@ -46,7 +53,8 @@
      * Throws: dcrypt.crypto.errors.InvalidParameterError if params aren't 
      *         an instance of dcrypt.crypto.params.ParametersWithIV.
      */
-    void init(bool encrypt, CipherParameters params) {
+    void init(bool encrypt, CipherParameters params)
+    {
         ParametersWithIV ivParams = cast(ParametersWithIV)params;
         
         if (!ivParams)
@@ -56,21 +64,23 @@
             throw new InvalidParameterError(
                     name()~": IV must be same length as cipher block size");
                     
-        this.encrypt = encrypt;
-        wrappedCipher.init(encrypt, ivParams.parameters);
+        _encrypt = encrypt;
+        
+        wrappedCipher.init(_encrypt, ivParams.parameters);
         
         iv = ivParams.iv[0..blockSize];
-        previousCiphertext = new ubyte[blockSize];
-        previousCiphertext[] = iv; // C_0 = IV
-        cbcOutput = new ubyte[blockSize]; // Output buffer for E_k/D_k(...)
         
-        initialized = true;
+        currentBlock = new ubyte[blockSize];
+        previousBlock = new ubyte[blockSize];
+        previousBlock[] = iv; // C_0 = IV
+        
+        _initialized = true;
     }
     
-    uint update(void[] input_, void[] output_) {
-        if (!initialized)
-            throw new NotInitializedError(
-                    name()~": Block mode not initialized");
+    uint update(void[] input_, void[] output_)
+    {
+        if (!_initialized)
+            throw new NotInitializedError(name()~": Block mode not initialized");
             
         ubyte[] input = cast(ubyte[]) input_,
                 output = cast(ubyte[]) output_;
@@ -81,49 +91,53 @@
         if (output.length < blockSize)
             throw new ShortBufferError(name()~": Output buffer too short");
         
-        if (encrypt) {
+        if (_encrypt)
+        {
             // P_i XOR C_i-1
             for (int i = 0; i < blockSize; i++)
-                previousCiphertext[i] ^= input[i];
+                previousBlock[i] ^= input[i];
                 
-            // E_k(P_i XOR C_i-1)
-            wrappedCipher.update(previousCiphertext, cbcOutput);
-            
-            // Store C_i for next block
-            previousCiphertext[] = cbcOutput;
+            // E_k(P_i XOR C_i-1) and store C_i for the next block
+            wrappedCipher.update(previousBlock, previousBlock);
             
             // C_i = E_k(P_i XOR C_i-1)
-            output[0..blockSize] = cbcOutput;            
-        } else {
-            // Temporarily store C_i
-            ubyte[] t = input[0..blockSize];
+            output[0..blockSize] = previousBlock;            
+        }
+        else
+        {
+            // Local reference to C_i
+            ubyte[] temp = input[0..blockSize];
 
             // D_k(C_i)
-            wrappedCipher.update(t, cbcOutput);
+            wrappedCipher.update(temp, currentBlock);
             
             // P_i = D_k(C_i) XOR C_i-1
             for (int i = 0; i < blockSize; i++)
-                output[i] = (cbcOutput[i] ^ previousCiphertext[i]);
+                output[i] = (currentBlock[i] ^ previousBlock[i]);
              
             // Store C_i for next block
-            previousCiphertext[] = t;
+            previousBlock[] = temp;
        }
         
         return blockSize;
     }
     
-    uint blockSize() {
+    uint blockSize()
+    {
         return wrappedCipher.blockSize;
     }
     
-    void reset() {
-        previousCiphertext[] = iv;
+    void reset()
+    {
+        previousBlock[] = iv;
         wrappedCipher.reset();
     }
     
     /** Test vectors for CBC mode. Assumes XTEA passes test vectors. */
-    debug (UnitTest) {
-        unittest {
+    debug (UnitTest)
+    {
+        unittest
+        {
             static const char[][] test_keys = [
                 "00000000000000000000000000000000",            
                 "00000000000000000000000000000000",
@@ -152,27 +166,27 @@
                 "f26fa5a0b6b63ba0f7ebf2f8735f85e3"
             ];
 
-            XTEA x = new XTEA();
-            CBC c = new CBC(x);
-            ubyte[] iv = new ubyte[x.blockSize], // Initialized to 0
+            CBC c = new CBC(new XTEA);
+            ubyte[] iv = new ubyte[c.blockSize], // Initialized to 0
                     buffer = new ubyte[32];
             char[] result;
-            for (int i = 0; i < test_keys.length; i++) {
+            for (int i = 0; i < test_keys.length; i++)
+            {
                 SymmetricKey key = new SymmetricKey(ByteConverter.hexDecode(test_keys[i]));
                 ParametersWithIV params = new ParametersWithIV(key, iv);
                 
                 // Encryption
                 c.init(true, params);
-                for (int j = 0; j < 32; j+=x.blockSize)
-                    c.update(ByteConverter.hexDecode(test_plaintexts[i])[j..j+x.blockSize], buffer[j..j+x.blockSize]);
+                for (int j = 0; j < 32; j+=c.blockSize)
+                    c.update(ByteConverter.hexDecode(test_plaintexts[i])[j..j+c.blockSize], buffer[j..j+c.blockSize]);
                 result = ByteConverter.hexEncode(buffer);
                 assert(result == test_ciphertexts[i],
                         c.name()~": ("~result~") != ("~test_ciphertexts[i]~")");           
                 
                 // Decryption
                 c.init(false, params);
-                for (int j = 0; j < 32; j+=x.blockSize)
-                    c.update(ByteConverter.hexDecode(test_ciphertexts[i])[j..j+x.blockSize], buffer[j..j+x.blockSize]);
+                for (int j = 0; j < 32; j+=c.blockSize)
+                    c.update(ByteConverter.hexDecode(test_ciphertexts[i])[j..j+c.blockSize], buffer[j..j+c.blockSize]);
                 result = ByteConverter.hexEncode(buffer);
                 assert(result == test_plaintexts[i],
                         c.name()~": ("~result~") != ("~test_plaintexts[i]~")");