changeset 4:3de3a2de13a0

Added MAC base class and HMAC. Added StreamCipherWrapper as part of the work on the high-level cipher API. Running on fumes, so hopefully there isn't too much stupid mixed into the code.
author Thomas Dixon <reikon@reikon.us>
date Thu, 14 Aug 2008 01:45:24 -0400
parents a5789a7b3b3b
children cff9960a019c
files dcrypt/crypto/MAC.d dcrypt/crypto/StreamCipherWrapper.d dcrypt/crypto/macs/HMAC.d
diffstat 3 files changed, 251 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dcrypt/crypto/MAC.d	Thu Aug 14 01:45:24 2008 -0400
@@ -0,0 +1,52 @@
+/**
+ * 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.MAC;
+
+public import dcrypt.crypto.params.CipherParameters;
+public import dcrypt.crypto.errors.InvalidParameterError;
+import dcrypt.misc.Util;
+
+/** Base MAC class */
+abstract class MAC {
+    /**
+     * Initialize a MAC.
+     * 
+     * Params:
+     *     params  = Parameters to be passed to the MAC. (Key, etc.)
+     */
+    void init(CipherParameters params);
+    
+    /**
+     * Introduce data into the MAC.
+     * 
+     * Params:
+     *     input_ = Data to be processed.
+     */
+    void update(void[] input_);
+    
+    /** Returns: The name of this MAC. */
+    char[] name();
+    
+    /** Reset MAC to its state immediately subsequent the last init. */
+    void reset();
+    
+    /** Returns: The block size in bytes that this MAC will operate on. */
+    uint blockSize();
+    
+    /** Returns: The output size of the MAC in bytes. */
+    uint macSize();
+    
+    /** Returns: The computed MAC. */
+    ubyte[] finish();
+    
+    /** Returns: The computed MAC in hexadecimal. */
+    char[] hexFinish() {
+        return Util.ubytesToHex(finish());
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dcrypt/crypto/StreamCipherWrapper.d	Thu Aug 14 01:45:24 2008 -0400
@@ -0,0 +1,44 @@
+/**
+ * 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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dcrypt/crypto/macs/HMAC.d	Thu Aug 14 01:45:24 2008 -0400
@@ -0,0 +1,155 @@
+/**
+ * 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.macs.HMAC;
+
+import dcrypt.crypto.MAC;
+import dcrypt.crypto.Hash;
+import dcrypt.crypto.params.SymmetricKey;
+import dcrypt.crypto.errors.NotInitializedError;
+
+version (UnitTest) {
+    import dcrypt.crypto.hashes.SHA1;
+}
+
+/** Conforms: RFC2104 */
+class HMAC : MAC {
+    private {
+        ubyte[] ipad, opad, key;
+        Hash inner, outer;
+        bool initialized;
+    }
+    
+    this (Hash hash, void[] key=null) {
+        hash.reset();
+        
+        inner = hash;
+        outer = hash.copy();
+        
+        ipad = new ubyte[blockSize];
+        opad = new ubyte[blockSize];
+        
+        reset();
+        
+        if (key)
+            init(new SymmetricKey(key)); // I'm lazy.
+    }
+    
+    void init(CipherParameters params) {
+        SymmetricKey keyParams = cast(SymmetricKey)params;
+        if (!keyParams)
+            throw new InvalidParameterError(
+                    name()~": Invalid parameter passed to init");
+        
+        if (keyParams.key.length > blockSize) {
+            inner.update(keyParams.key);
+            key = inner.digest();
+        } else
+            key = keyParams.key;
+        
+        foreach (uint i, ubyte j; key) {
+            ipad[i] ^= j;
+            opad[i] ^= j;
+        }
+        
+        inner.update(ipad);
+        outer.update(opad);
+        
+        initialized = true;
+    }
+    
+    void update(void[] input_) {
+        if (!initialized)
+            throw new NotInitializedError(
+                name()~": MAC not initialized.");
+        inner.update(input_);
+    }
+    
+    char[] name() {
+        return inner.name~"/HMAC";
+    }
+    
+    void reset() {
+        ipad[] = 0x36;
+        opad[] = 0x5c;
+        
+        inner.reset();
+        outer.reset();
+    }
+    
+    uint blockSize() {
+        return inner.blockSize;
+    }
+    
+    uint macSize() {
+        return inner.digestSize;
+    }
+    
+    ubyte[] finish() {
+        outer.update(inner.digest());
+        ubyte[] r = outer.digest();
+        reset();
+        return r;
+    }
+    
+    char[] hexFinish() {
+        return Util.ubytesToHex(finish());
+    }
+    
+    HMAC copy() {
+        // Ghetto... oh so ghetto :\
+        HMAC h = new HMAC(inner.copy());
+        h.inner = inner.copy();
+        h.outer = outer.copy();
+        h.initialized = true;
+        return h;
+    }
+    
+    version (UnitTest) {
+        unittest {
+            static char[][] test_keys = [
+                "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+                "4a656665", // Jefe?
+                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"~
+                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"~
+                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"~
+                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+            ];
+            
+            static char[][] test_inputs = [
+                "4869205468657265",
+                "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+                "dd",
+                "54657374205573696e67204c6172676572205468616e20426c6f63"~
+                "6b2d53697a65204b6579202d2048617368204b6579204669727374"
+            ];
+            
+            static const int[] test_repeat = [
+                1, 1, 50, 1
+            ];
+            
+            static const char[][] test_results = [
+                "b617318655057264e28bc0b6fb378c8ef146be00",
+                "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79",
+                "125d7342b9ac11cd91a39af48aa17b4f63f175d3",
+                "aa4ae5e15272d00e95705637ce8a3b55ed402112"
+            ];
+            
+            HMAC h = new HMAC(new SHA1());
+            foreach (uint i, char[] k; test_keys) {
+                h.init(new SymmetricKey(Util.hexToUbytes(k)));
+                for (int j = 0; j < test_repeat[i]; j++)
+                    h.update(Util.hexToUbytes(test_inputs[i]));
+                char[] mac = h.hexFinish();
+                assert(mac == test_results[i], 
+                        h.name~": ("~mac~") != ("~test_results[i]~")");
+            }
+        }
+    }
+}
\ No newline at end of file