changeset 10:cd376996cdb3

Renamed SymmetricCipher back to Cipher (we don't support any other kind atm, I'll deal with it when we do.). Added BlockCipherWrapper for the encryption of arbitrary streams with or without padding. Removed hashByName, and replaced it with createHash. Re-did the high-level API, and filled out Crypto. Added cipher creation via createCipher. Added dsk to the CONTRIBUTORS file for helping with the design of the high-level API.
author Thomas Dixon <reikon@reikon.us>
date Wed, 20 Aug 2008 20:08:07 -0400
parents 29b910949588
children 02970e63257d
files CONTRIBUTORS dcrypt/crypto/BlockCipher.d dcrypt/crypto/BlockCipherPadding.d dcrypt/crypto/BlockCipherWrapper.d dcrypt/crypto/Cipher.d dcrypt/crypto/Crypto.d dcrypt/crypto/StreamCipher.d dcrypt/crypto/StreamCipherWrapper.d dcrypt/crypto/SymmetricCipher.d dcrypt/crypto/hashes/MD5.d dcrypt/crypto/modes/CTR.d dcrypt/crypto/padding/NullByte.d dcrypt/crypto/padding/PKCS7.d dcrypt/crypto/padding/RFC1321.d dcrypt/crypto/padding/X923.d dcrypt/misc/Util.d dsss.conf
diffstat 17 files changed, 313 insertions(+), 165 deletions(-) [+]
line wrap: on
line diff
--- a/CONTRIBUTORS	Mon Aug 18 01:19:18 2008 -0400
+++ b/CONTRIBUTORS	Wed Aug 20 20:08:07 2008 -0400
@@ -1,1 +1,2 @@
 Thomas Dixon <reikon@reikon.us>
+Daniel Korsgaard <#d @ irc.freenode.net>
--- a/dcrypt/crypto/BlockCipher.d	Mon Aug 18 01:19:18 2008 -0400
+++ b/dcrypt/crypto/BlockCipher.d	Wed Aug 20 20:08:07 2008 -0400
@@ -8,11 +8,11 @@
  
 module dcrypt.crypto.BlockCipher;
 
-public import dcrypt.crypto.SymmetricCipher;
+public import dcrypt.crypto.Cipher;
 public import dcrypt.crypto.params.SymmetricKey;
 
 /** Interface for a standard block cipher. */
-abstract class BlockCipher : SymmetricCipher {
+abstract class BlockCipher : Cipher {
     
     /** Returns: The block size in bytes that this cipher will operate on. */
     uint blockSize();
--- a/dcrypt/crypto/BlockCipherPadding.d	Mon Aug 18 01:19:18 2008 -0400
+++ b/dcrypt/crypto/BlockCipherPadding.d	Wed Aug 20 20:08:07 2008 -0400
@@ -16,15 +16,14 @@
      char[] name();
      
      /**
-      * Pad the (last) block of plaintext to block length.
+      * Generate padding to a specific length.
       *
       * Params:
-      *     input_ = Plaintext block to be padded.
-      *     inOffset = Offset at which to begin padding input_.
+      *     len = Length of padding to generate
       *
-      * Returns: The number of padding bytes added.
+      * Returns: The padding bytes to be added.
       */ 
-     uint padBlock(void[] input_, uint inOff);
+     ubyte[] pad(uint len);
      
      /**
       * Return the number of pad bytes in the block.
@@ -37,5 +36,5 @@
       * Throws: dcrypt.crypto.errors.InvalidPaddingError if 
       *         pad length cannot be discerned.
       */
-     uint padLength(void[] input_);
+     uint unpad(void[] input_);
  }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dcrypt/crypto/BlockCipherWrapper.d	Wed Aug 20 20:08:07 2008 -0400
@@ -0,0 +1,85 @@
+/**
+ * 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.BlockCipherWrapper;
+
+import dcrypt.crypto.BlockCipher;
+import dcrypt.crypto.BlockCipherPadding;
+
+/** 
+ * Wraps a block cipher, enabling the encryption of a stream
+ * whose length is a multiple of blockSize. Padding, if specified,
+ * is to be applied otherwise and the result subsequently processed.
+ */
+class BlockCipherWrapper : BlockCipher {
+    BlockCipher cipher;
+    BlockCipherPadding padding;
+    bool encrypt;
+    
+    this(BlockCipher c, BlockCipherPadding p=null) {
+        cipher = c;
+        padding = p; // null signifies no padding is to be applied
+    }
+    
+    void init(bool encrypt, CipherParameters params) {
+        this.encrypt = encrypt;
+        cipher.init(encrypt, params);
+    }
+    
+    char[] name() {
+        if (padding !is null)
+            return cipher.name~"/"~padding.name;
+        return cipher.name;
+    }
+    
+    uint blockSize() {
+        return cipher.blockSize;
+    }
+    
+    ubyte[] process(void[] input_) {
+        ubyte[] input = cast(ubyte[]) input_;
+        
+        uint padLen = blockSize - (input.length % blockSize);
+        if (padding !is null && !encrypt && padLen != blockSize)
+            throw new ShortBufferError(
+                    name()~": Encrypted padded block should be multiple of block size.");
+        
+        ubyte[] output = new ubyte[input.length];
+        
+        uint len = input.length,
+             i = 0;
+        while (len >= blockSize) {
+            output[i..i+blockSize] = cipher.process(input[i..i+blockSize]);
+            len -= blockSize;
+            i += blockSize;
+        }
+                
+        if (padding !is null) {
+            if (encrypt) {
+                output.length = output.length + padLen;
+                ubyte[] t = new ubyte[blockSize];
+                if (len > 0) {
+                    t[0..len] = input[i..i+len];
+                    t[len..blockSize] = padding.pad(padLen);
+                } else
+                    t[] = padding.pad(padLen);
+                output[i..i+blockSize] = cipher.process(t);
+            } else {
+                output.length = output.length - padding.unpad(output);
+            }
+        } else
+            if (len > 0)
+                output[i..i+len] = cipher.process(input[i..i+len]);
+            
+        return output;
+    }
+    
+    void reset() {
+        cipher.reset();
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dcrypt/crypto/Cipher.d	Wed Aug 20 20:08:07 2008 -0400
@@ -0,0 +1,48 @@
+/**
+ * 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.Cipher;
+
+public import dcrypt.crypto.errors.InvalidKeyError;
+public import dcrypt.crypto.errors.ShortBufferError;
+public import dcrypt.crypto.errors.NotInitializedError;
+public import dcrypt.crypto.errors.InvalidParameterError;
+
+public import dcrypt.crypto.params.CipherParameters;
+
+/** Base symmetric cipher class */
+abstract class Cipher {
+    static const bool ENCRYPT = true,
+                      DECRYPT = false;
+    
+    /**
+     * Initialize a cipher.
+     * 
+     * Params:
+     *     encrypt = True if we are encrypting.
+     *     params  = Parameters to be passed to the cipher. (Key, rounds, etc.)
+     */
+    void init(bool encrypt, CipherParameters params);
+    
+    /**
+     * Process a block of plaintext data from the input array
+     * and return the encrypted data.
+     *
+     * Params:
+     *     input_  = Array containing input data.
+     *
+     * Returns: The encrypted data.
+     */
+    ubyte[] process(void[] input_);
+    
+    /** Returns: The name of the algorithm of this cipher. */
+    char[] name();
+    
+    /** Reset cipher to its state immediately subsequent the last init. */
+    void reset();
+}
--- a/dcrypt/crypto/Crypto.d	Mon Aug 18 01:19:18 2008 -0400
+++ b/dcrypt/crypto/Crypto.d	Wed Aug 20 20:08:07 2008 -0400
@@ -8,10 +8,6 @@
 
 module dcrypt.crypto.Crypto;
 
-import dcrypt.crypto.SymmetricCipher;
-
-import dcrypt.misc.Util;
-
 // Hash functions
 public import dcrypt.crypto.Hash;
 import dcrypt.crypto.hashes.MD5;
@@ -21,23 +17,147 @@
 import dcrypt.crypto.hashes.SHA384;
 import dcrypt.crypto.hashes.SHA512;
 
+// Params
+public import dcrypt.crypto.params.SymmetricKey;
+public import dcrypt.crypto.params.ParametersWithIV;
+
+
+// Ciphers
+public import dcrypt.crypto.Cipher;
+public import dcrypt.crypto.BlockCipher;
+public import dcrypt.crypto.StreamCipher;
+public import dcrypt.crypto.BlockCipherWrapper;
+import dcrypt.crypto.ciphers.Blowfish;
+import dcrypt.crypto.ciphers.RC6;
+import dcrypt.crypto.ciphers.TEA;
+import dcrypt.crypto.ciphers.XTEA;
+import dcrypt.crypto.ciphers.RC4;
+import dcrypt.crypto.ciphers.AES;
+
+// Block modes
+import dcrypt.crypto.modes.CBC;
+import dcrypt.crypto.modes.CTR;
+
+// Block padding
+public import dcrypt.crypto.BlockCipherPadding;
+import dcrypt.crypto.padding.NullByte;
+import dcrypt.crypto.padding.X923;
+import dcrypt.crypto.padding.PKCS7;
+import dcrypt.crypto.padding.RFC1321;
+
+enum Hashes {
+    MD5=0,
+    SHA1,
+    SHA224,
+    SHA256,
+    SHA384,
+    SHA512
+}
+
+enum Ciphers {
+    // Block ciphers
+    Blowfish=0,
+    AES,
+    RC6,
+    TEA,
+    XTEA,
+    
+    // Stream ciphers
+    RC4
+}
+
+enum Modes {
+    ECB=-1,
+    CTR,
+    CBC
+}
+
+enum Padding {
+    None=-1,
+    NullByte, // lol
+    X923,
+    PKCS7,
+    RFC1321
+}
+
 struct Crypto {
-    static Hash hashByName(char[] name) {
-        switch (Util.stringToAlphanumeric(Util.stringToUpper(name))) {
-            case "MD5":
-                return new MD5();
-            case "SHA1":
-                return new SHA1();
-            case "SHA224":
-                return new SHA224();
-            case "SHA256":
-                return new SHA256();
-            case "SHA384":
-                return new SHA384();
-            case "SHA512":
-                return new SHA512();
+    static Hash createHash(uint hash) {
+        switch (hash) {
+            case Hashes.MD5:
+                return new MD5;
+            case Hashes.SHA1:
+                return new SHA1;
+            case Hashes.SHA224:
+                return new SHA224;
+            case Hashes.SHA256:
+                return new SHA256;
+            case Hashes.SHA384:
+                return new SHA384;
+            case Hashes.SHA512:
+                return new SHA512;
             default:
-                throw new InvalidParameterError("Unknown hash function: "~name);
+                throw new InvalidParameterError("Unknown hash function passed to createHash()");
         }
     }
+    
+    static Cipher createCipher(uint cipher, uint mode=Modes.ECB, uint padding=Padding.None) {
+        BlockCipher c = null,
+                    m = null;
+        BlockCipherPadding p = null;
+        switch (cipher) {
+            case Ciphers.Blowfish:
+                c = new Blowfish;
+                break;
+            case Ciphers.AES:
+                c = new AES;
+                break;
+            case Ciphers.RC6:
+                c = new RC6;
+                break;
+            case Ciphers.TEA:
+                c = new TEA;
+                break;
+            case Ciphers.XTEA:
+                c = new XTEA;
+                break;
+            case Ciphers.RC4:
+                return new RC4; // Note the return
+            default:
+                throw new InvalidParameterError("Unknown cipher passed to createCipher()");
+        }
+        
+        switch (mode) {
+            case Modes.ECB:
+                break;
+            case Modes.CTR:
+                m = new CTR(c);
+                break;
+            case Modes.CBC:
+                m = new CBC(c);
+                break;
+            default:
+                throw new InvalidParameterError("Unknown mode passed to createCipher()");
+        }
+        
+        switch (padding) {
+            case Padding.None:
+                break;
+            case Padding.NullByte:
+                p = new NullByte;
+                break;
+            case Padding.X923:
+                p = new X923;
+                break;
+            case Padding.PKCS7:
+                p = new PKCS7;
+                break;
+            case Padding.RFC1321:
+                p = new RFC1321;
+                break;
+            default:
+                throw new InvalidParameterError("Unknown padding passed to createCipher()");
+        }
+        
+        return new BlockCipherWrapper(((m is null) ? c : m), p);
+    }
 }
--- a/dcrypt/crypto/StreamCipher.d	Mon Aug 18 01:19:18 2008 -0400
+++ b/dcrypt/crypto/StreamCipher.d	Wed Aug 20 20:08:07 2008 -0400
@@ -8,12 +8,12 @@
 
 module dcrypt.crypto.StreamCipher;
 
-public import dcrypt.crypto.SymmetricCipher;
+public import dcrypt.crypto.Cipher;
 public import dcrypt.crypto.params.CipherParameters;
 public import dcrypt.crypto.params.SymmetricKey;
 
 /** Interface for a standard stream cipher. */
-abstract class StreamCipher : SymmetricCipher {   
+abstract class StreamCipher : Cipher {   
     /**
      * Process one byte of input.
      *
--- a/dcrypt/crypto/StreamCipherWrapper.d	Mon Aug 18 01:19:18 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/**
- * 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.StreamCipherWrapper;
-
-import dcrypt.crypto.SymmetricCipher;
-import dcrypt.crypto.StreamCipher;
-public import dcrypt.crypto.params.CipherParameters;
-
-/** High-level API for stream ciphers. */
-class StreamCipherWrapper : SymmetricCipher {
-    private StreamCipher cipher;
-    
-    this(StreamCipher sc) {
-        cipher = sc;
-    }
-    
-    void init(bool encrypt, CipherParameters params) {
-        cipher.init(encrypt, params);
-    }
-
-    uint update(void[] input_, uint inOff, 
-                    uint len, void[] output_, uint outOff) {
-        cipher.processBytes(input_, inOff, len, output_, outOff);
-        return len;
-    }
-    
-    uint finish(void[] output_, uint outOff) {
-        return 0;
-    }
-    
-    void reset() {
-        cipher.reset();
-    }
-    
-    char[] name() {
-        return cipher.name;
-    }
-}
--- a/dcrypt/crypto/SymmetricCipher.d	Mon Aug 18 01:19:18 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/**
- * 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.SymmetricCipher;
-
-public import dcrypt.crypto.errors.InvalidKeyError;
-public import dcrypt.crypto.errors.ShortBufferError;
-public import dcrypt.crypto.errors.NotInitializedError;
-public import dcrypt.crypto.errors.InvalidParameterError;
-
-public import dcrypt.crypto.params.CipherParameters;
-
-/** Base symmetric cipher class */
-abstract class SymmetricCipher {
-    static const bool ENCRYPT = true,
-                      DECRYPT = false;
-    
-    /**
-     * Initialize a cipher.
-     * 
-     * Params:
-     *     encrypt = True if we are encrypting.
-     *     params  = Parameters to be passed to the cipher. (Key, rounds, etc.)
-     */
-    void init(bool encrypt, CipherParameters params);
-    
-    /**
-     * Process a block of plaintext data from the input array
-     * and return the encrypted data.
-     *
-     * Params:
-     *     input_  = Array containing input data.
-     *
-     * Returns: The encrypted data.
-     */
-    ubyte[] process(void[] input_);
-    
-    /** Returns: The name of the algorithm of this cipher. */
-    char[] name();
-    
-    /** Reset cipher to its state immediately subsequent the last init. */
-    void reset();
-}
--- a/dcrypt/crypto/hashes/MD5.d	Mon Aug 18 01:19:18 2008 -0400
+++ b/dcrypt/crypto/hashes/MD5.d	Wed Aug 20 20:08:07 2008 -0400
@@ -16,6 +16,7 @@
  * Conforms: RFC 1321
  * References: http://www.faqs.org/rfcs/rfc1321.html
  * Bugs: MD5 is not cryptographically secure.
+ * Throws: InsecureAlgorithmError upon instantiation.
  */
 class MD5 : Hash {
 	private uint h0, h1, h2, h3;
--- a/dcrypt/crypto/modes/CTR.d	Mon Aug 18 01:19:18 2008 -0400
+++ b/dcrypt/crypto/modes/CTR.d	Wed Aug 20 20:08:07 2008 -0400
@@ -68,19 +68,20 @@
                     name()~": Block mode not initialized");
             
         ubyte[] input = cast(ubyte[]) input_;
+        uint len = (counter.length > input.length) ? input.length : counter.length;
         
         // Encrypt the counter
         counterOutput[] = m_cipher.process(counter);
         
         // XOR output with plaintext to create ciphertext
-        for (int i = 0; i < counter.length; i++)
+        for (int i = 0; i < len; i++)
             counterOutput[i] ^= input[i];
             
         // Increment the counter
         for (int i = counter.length-1; i >= 0; i--)
             if (++counter[i]) break;
 
-        return counterOutput;  
+        return counterOutput[0..len];  
     }
     
     uint blockSize() {
--- a/dcrypt/crypto/padding/NullByte.d	Mon Aug 18 01:19:18 2008 -0400
+++ b/dcrypt/crypto/padding/NullByte.d	Wed Aug 20 20:08:07 2008 -0400
@@ -19,20 +19,15 @@
         return "NullByte";   
     }
     
-    /* Assumes input_ is a multiple of the underlying
-     * block cipher's block size.
-     */
-    uint padBlock(void[] input_, uint inOff) {
-        ubyte[] input = cast(ubyte[]) input_;
+    ubyte[] pad(uint len) {
+        ubyte[] output = new ubyte[len];
+        
+        output[0..output.length] = 0;
 
-        uint len = (input.length - inOff);
-        
-        input[inOff..input.length] = 0;
-
-        return len;
+        return output;
     }
     
-    uint padLength(void[] input_) {
+    uint unpad(void[] input_) {
         ubyte[] input = cast(ubyte[]) input_;
         
         uint len = input.length;
--- a/dcrypt/crypto/padding/PKCS7.d	Mon Aug 18 01:19:18 2008 -0400
+++ b/dcrypt/crypto/padding/PKCS7.d	Wed Aug 20 20:08:07 2008 -0400
@@ -19,20 +19,15 @@
         return "PKCS7";   
     }
     
-    /* Assumes input_ is a multiple of the underlying
-     * block cipher's block size.
-     */
-    uint padBlock(void[] input_, uint inOff) {
-        ubyte[] input = cast(ubyte[]) input_;
+    ubyte[] pad(uint len) {
+        ubyte[] output = new ubyte[len];
+        
+        output[0..output.length] = cast(byte)len;
 
-        ubyte len = (input.length - inOff);
-        
-        input[inOff..input.length] = len;
-
-        return len;
+        return output;
     }
     
-    uint padLength(void[] input_) {
+    uint unpad(void[] input_) {
         ubyte[] input = cast(ubyte[]) input_;
         
         ubyte len = input[input.length-1];
--- a/dcrypt/crypto/padding/RFC1321.d	Mon Aug 18 01:19:18 2008 -0400
+++ b/dcrypt/crypto/padding/RFC1321.d	Wed Aug 20 20:08:07 2008 -0400
@@ -18,22 +18,17 @@
     char[] name() {
         return "RFC1321";   
     }
-    
-    /* Assumes input_ is a multiple of the underlying
-     * block cipher's block size.
-     */
-    uint padBlock(void[] input_, uint inOff) {
-        ubyte[] input = cast(ubyte[]) input_;
 
-        uint len = (input.length - inOff);
+    ubyte[] pad(uint len) {
+        ubyte[] output = new ubyte[len];
         
-        input[inOff++] = 0x80;
-        input[inOff..input.length] = 0;
+        output[0] = 0x80;
+        output[1..output.length] = 0;
 
-        return len;
+        return output;
     }
     
-    uint padLength(void[] input_) {
+    uint unpad(void[] input_) {
         ubyte[] input = cast(ubyte[]) input_;
         
         uint len = input.length;
--- a/dcrypt/crypto/padding/X923.d	Mon Aug 18 01:19:18 2008 -0400
+++ b/dcrypt/crypto/padding/X923.d	Wed Aug 20 20:08:07 2008 -0400
@@ -22,18 +22,16 @@
     /* Assumes input_ is a multiple of the underlying
      * block cipher's block size.
      */
-    uint padBlock(void[] input_, uint inOff) {
-        ubyte[] input = cast(ubyte[]) input_;
-
-        ubyte len = (input.length - inOff);
+    ubyte[] pad(uint len) {
+        ubyte[] output = new ubyte[len];
         
-        input[inOff..input.length-1] = 0;
-        input[input.length-1] = len;
+        output[0..len-1] = 0;
+        output[output.length-1] = cast(ubyte)len;
 
-        return len;
+        return output;
     }
     
-    uint padLength(void[] input_) {
+    uint unpad(void[] input_) {
         ubyte[] input = cast(ubyte[]) input_;
         
         ubyte len = input[input.length-1];
--- a/dcrypt/misc/Util.d	Mon Aug 18 01:19:18 2008 -0400
+++ b/dcrypt/misc/Util.d	Wed Aug 20 20:08:07 2008 -0400
@@ -6,7 +6,7 @@
  * Authors:   Thomas Dixon
  */
 
-// TODO: WRITE DOCS, IMPLEMENT TO/FROM HEX FUNCTIONS, SIMPLIFY UNITTESTS 
+// TODO: WRITE DOCS 
 module dcrypt.misc.Util;
 
 /** Utility functions */
--- a/dsss.conf	Mon Aug 18 01:19:18 2008 -0400
+++ b/dsss.conf	Wed Aug 20 20:08:07 2008 -0400
@@ -1,2 +1,4 @@
 name = dcrypt
 [dcrypt]
+target = dcrypt
+