diff dcrypt/crypto/modes/CTR.d @ 0:0e08791a1418

Initial import.
author Thomas Dixon <reikon@reikon.us>
date Sun, 10 Aug 2008 14:20:17 -0400
parents
children 23c62e28b3a4
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dcrypt/crypto/modes/CTR.d	Sun Aug 10 14:20:17 2008 -0400
@@ -0,0 +1,95 @@
+/**
+ * This file is part of the dcrypt project.
+ *
+ * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved.
+ * License:   MIT
+ * Authors:   Thomas Dixon
+ */
+
+module dcrypt.crypto.modes.CTR;
+
+import dcrypt.crypto.BlockCipher;
+import dcrypt.crypto.params.ParametersWithIV;
+
+
+/** This class implements the counter (CTR/SIC/ICM) block mode,
+    treating the counter as a big endian integer. */
+class CTR : BlockCipher {
+    private BlockCipher m_cipher;
+    private ubyte[] iv,
+                    counter,
+                    counterOutput;
+    private bool initialized = false;
+    
+    /**
+     * Params:
+     *     cipher = Block cipher to wrap.
+     */
+    this (BlockCipher cipher) {
+        m_cipher = cipher;
+    }
+    
+    /** Returns: The underlying cipher we are wrapping. */
+    BlockCipher cipher() {
+        return m_cipher;
+    }
+    
+    char[] name() {
+        return m_cipher.name~"/CTR";
+    }
+    
+    /** 
+     * Throws: dcrypt.crypto.errors.InvalidParameterError if params aren't 
+     *          an instance of dcrypt.crypto.params.ParametersWithIV.
+     */
+    void init(bool encrypt, CipherParameters params) {
+        ParametersWithIV ivParams = cast(ParametersWithIV)params;
+        
+        if (!ivParams)
+            throw new InvalidParameterError(
+                    name()~": Block mode requires IV (use ParametersWithIV)");
+        if (ivParams.iv.length != blockSize)
+            throw new InvalidParameterError(
+                    name()~": IV must be same length as cipher block size");
+                    
+        m_cipher.init(true, ivParams.parameters);
+        
+        iv = ivParams.iv[0..blockSize];
+        counter = new ubyte[blockSize];
+        counter[] = iv;
+        counterOutput = new ubyte[blockSize];
+        
+        initialized = true;
+    }
+    
+    uint processBlock(void[] input_, uint inOff, void[] output_, uint outOff) {
+        if (!initialized)
+            throw new NotInitializedError(
+                    name()~": Block mode not initialized");
+            
+        ubyte[] input = cast(ubyte[]) input_;
+        ubyte[] output = cast(ubyte[]) output_;
+        
+        // Encrypt the counter
+        m_cipher.processBlock(counter, 0, counterOutput, 0);
+        
+        // XOR output with plaintext to create ciphertext
+        for (int i = 0; i < counter.length; i++)
+            output[outOff++] = (counterOutput[i] ^ input[inOff++]);
+            
+        // Increment the counter
+        for (int i = counter.length-1; i >= 0; i--)
+            if (++counter[i]) break;
+
+        return counter.length;  
+    }
+    
+    uint blockSize() {
+        return m_cipher.blockSize;
+    }
+    
+    void reset() {
+        counter[] = iv;
+        m_cipher.reset();
+    }
+}