changeset 14:5ce3012f1def

Removed some redundancy in code. Added NotSupportedError, a base PRNG class and a class which creates a PRNG from a hash function. Changed the MAC class' finalization methods to digest and hexDigest instead of finish and hexFinish respectively. Also added a base Checksum class, crc32 and adler32 in dcrypt.misc as per request.
author Thomas Dixon <reikon@reikon.us>
date Tue, 18 Nov 2008 18:03:40 -0500
parents 7ea528b61802
children 0de48552be35
files dcrypt/crypto/Cipher.d dcrypt/crypto/Hash.d dcrypt/crypto/MAC.d dcrypt/crypto/PRNG.d dcrypt/crypto/ciphers/AES.d dcrypt/crypto/ciphers/Blowfish.d dcrypt/crypto/ciphers/RC4.d dcrypt/crypto/ciphers/RC6.d dcrypt/crypto/ciphers/TEA.d dcrypt/crypto/ciphers/XTEA.d dcrypt/crypto/errors/NotSupportedError.d dcrypt/crypto/macs/HMAC.d dcrypt/crypto/params/ParametersWithIV.d dcrypt/crypto/params/SymmetricKey.d dcrypt/crypto/prngs/PRNGFromHash.d dcrypt/misc/Checksum.d dcrypt/misc/checksums/Adler32.d dcrypt/misc/checksums/CRC32.d dsss.conf
diffstat 19 files changed, 385 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/dcrypt/crypto/Cipher.d	Fri Sep 12 05:20:43 2008 -0400
+++ b/dcrypt/crypto/Cipher.d	Tue Nov 18 18:03:40 2008 -0500
@@ -19,6 +19,9 @@
 abstract class Cipher {
     static const bool ENCRYPT = true,
                       DECRYPT = false;
+                      
+    protected bool _initialized,
+                   _encrypt;
     
     /**
      * Initialize a cipher.
@@ -44,6 +47,11 @@
     /** Returns: The name of the algorithm of this cipher. */
     char[] name();
     
+    /** Returns: Whether or not the cipher has been initialized. */
+    bool initialized() {
+        return _initialized;
+    }
+    
     /** Reset cipher to its state immediately subsequent the last init. */
     void reset();
 }
--- a/dcrypt/crypto/Hash.d	Fri Sep 12 05:20:43 2008 -0400
+++ b/dcrypt/crypto/Hash.d	Tue Nov 18 18:03:40 2008 -0500
@@ -100,7 +100,7 @@
     
     /**
      * Process all data, pad and finalize. This method will
-     * reset the digest to its original state ofr subsequent use.
+     * reset the digest to its original state for subsequent use.
      * 
      * Returns: Binary representation of the hash in bytes.
      */
--- a/dcrypt/crypto/MAC.d	Fri Sep 12 05:20:43 2008 -0400
+++ b/dcrypt/crypto/MAC.d	Tue Nov 18 18:03:40 2008 -0500
@@ -43,10 +43,10 @@
     uint macSize();
     
     /** Returns: The computed MAC. */
-    ubyte[] finish();
+    ubyte[] digest();
     
     /** Returns: The computed MAC in hexadecimal. */
-    char[] hexFinish() {
-        return Util.ubytesToHex(finish());
+    char[] hexDigest() {
+        return Util.ubytesToHex(digest());
     }
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dcrypt/crypto/PRNG.d	Tue Nov 18 18:03:40 2008 -0500
@@ -0,0 +1,45 @@
+/**
+ * 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.PRNG;
+
+public import dcrypt.crypto.errors.ShortBufferError;
+public import dcrypt.crypto.errors.NotInitializedError;
+public import dcrypt.crypto.errors.InvalidParameterError;
+public import dcrypt.crypto.errors.NotSupportedError;
+
+/** Relatively simple interface for PRNGs. */
+abstract class PRNG {
+    
+    protected bool _initialized;
+    
+    /** Returns: The name of the PRNG. */
+    char[] name();
+    
+    /** Returns: Whether or not the PRNG has been initialized. */
+    bool initialized() {
+        return _initialized;
+    }
+    
+    /**
+     * Introduce entropy into the PRNG. An initial call to this is
+     * usually required for seeding.
+     * 
+     * Params:
+     *     input = Bytes to introduce into the PRNG as entropy
+     */
+    void addEntropy(ubyte[] input);
+    
+    /**
+     * Read bytes from the keystream of the PRNG into output.
+     * 
+     * Params:
+     *     output = Array to fill with the next bytes of the keystream
+     */
+    uint read(ubyte[] output);
+}
--- a/dcrypt/crypto/ciphers/AES.d	Fri Sep 12 05:20:43 2008 -0400
+++ b/dcrypt/crypto/ciphers/AES.d	Tue Nov 18 18:03:40 2008 -0500
@@ -640,9 +640,7 @@
              s0, s1, s2, s3; // State
         uint[] w; // Expanded key
         ubyte[] workingKey;
-        
-        bool initialized,
-             encrypt;
+       
     } // end private
     
     char[] name() {
@@ -650,7 +648,7 @@
     }
     
     uint rounds() {
-        if (!initialized)
+        if (!_initialized)
             throw new NotInitializedError(name()~": Cipher not initialized.");
         return ROUNDS;
     }
@@ -664,7 +662,7 @@
         if (!keyParams)
             throw new InvalidParameterError(
                     name()~": Invalid parameter passed to init");
-        this.encrypt = encrypt;
+        _encrypt = encrypt;
         
         uint len = keyParams.key.length;
         if (len != 16 && len != 24 && len != 32)
@@ -674,7 +672,7 @@
         
         setup(workingKey);
         
-        initialized = true;
+        _initialized = true;
     }
     
     private void encryptBlock() {
@@ -801,7 +799,7 @@
     }
     
     uint update(void[] input_, void[] output_) {
-        if (!initialized)
+        if (!_initialized)
             throw new NotInitializedError(name()~": Cipher not initialized.");
         
         ubyte[] input = cast(ubyte[]) input_,
@@ -818,7 +816,7 @@
         s2 = w[2] ^ Util.ubytesToUintBig(input, 8);
         s3 = w[3] ^ Util.ubytesToUintBig(input, 12);
              
-        if (encrypt) encryptBlock(); else decryptBlock();
+        if (_encrypt) encryptBlock(); else decryptBlock();
 
         Util.uintToUbytesBig(s0, output, 0);
         Util.uintToUbytesBig(s1, output, 4);
@@ -855,7 +853,7 @@
             w[i] = w[i-nk] ^ t;
         }
         
-        if (!encrypt) {
+        if (!_encrypt) {
             for (uint i = 0; i <= 4*ROUNDS; i+=4)
                 w[i..i+4].reverse;
             w.reverse;
@@ -922,4 +920,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
--- a/dcrypt/crypto/ciphers/Blowfish.d	Fri Sep 12 05:20:43 2008 -0400
+++ b/dcrypt/crypto/ciphers/Blowfish.d	Tue Nov 18 18:03:40 2008 -0500
@@ -209,8 +209,6 @@
         uint[18] P;
         uint[256] S0, S1, S2, S3;
         ubyte[] workingKey;
-        bool initialized,
-             encrypt;
     } // end private
     
     char[] name() {
@@ -226,7 +224,7 @@
         if (!keyParams)
             throw new InvalidParameterError(
                     name()~": Invalid parameter passed to init");
-        this.encrypt = encrypt;
+        _encrypt = encrypt;
         
         uint len = keyParams.key.length;
         if (len < MIN_KEY_SIZE || len > MAX_KEY_SIZE)
@@ -241,10 +239,10 @@
         
         workingKey = keyParams.key;
         // Yes, this is ghetto. I know.
-        initialized = true;
+        _initialized = true;
         setup(workingKey);
         
-        if (!encrypt)
+        if (!_encrypt)
             P.reverse; // Oh yes I did.
     }
     
@@ -256,7 +254,7 @@
     }
     
     uint update(void[] input_, void[] output_) {
-        if (!initialized)
+        if (!_initialized)
             throw new NotInitializedError(name()~": Cipher not initialized.");
         
         ubyte[] input = cast(ubyte[]) input_,
--- a/dcrypt/crypto/ciphers/RC4.d	Fri Sep 12 05:20:43 2008 -0400
+++ b/dcrypt/crypto/ciphers/RC4.d	Tue Nov 18 18:03:40 2008 -0500
@@ -20,7 +20,6 @@
         ubyte[] state,
                 workingKey;
         ubyte x, y;
-        bool initialized;
     }
     
     void init(bool encrypt, CipherParameters params) {
@@ -34,7 +33,8 @@
         workingKey = keyParams.key;
         state = new ubyte[256];
         setup(workingKey);
-        initialized = true;
+        _encrypt = true;
+        _initialized = true;
     }
     
     char[] name() {
@@ -50,7 +50,7 @@
     }
     
     uint update(void[] input_, void[] output_) {
-        if (!initialized)
+        if (!_initialized)
             throw new NotInitializedError(name()~": Cipher not initialized");
             
         ubyte[] input = cast(ubyte[]) input_,
--- a/dcrypt/crypto/ciphers/RC6.d	Fri Sep 12 05:20:43 2008 -0400
+++ b/dcrypt/crypto/ciphers/RC6.d	Tue Nov 18 18:03:40 2008 -0500
@@ -33,8 +33,6 @@
                    Q = 0x9e3779b9;
         uint[] S;
         ubyte[] workingKey;
-        bool initialized,
-             encrypt;
     }
     
     char[] name() {
@@ -50,7 +48,7 @@
         if (!keyParams)
             throw new InvalidParameterError(
                     name()~": Invalid parameter passed to init");
-        this.encrypt = encrypt;
+        _encrypt = encrypt;
         
         uint len = keyParams.key.length;
         if (len != 16 && len != 24 && len != 32)
@@ -62,11 +60,11 @@
         workingKey = keyParams.key;
         setup(workingKey);
         
-        initialized = true;
+        _initialized = true;
     }
     
     uint update(void[] input_, void[] output_) {
-        if (!initialized)
+        if (!_initialized)
             throw new NotInitializedError(name()~": Cipher not initialized");
             
         ubyte[] input = cast(ubyte[]) input_,
@@ -85,7 +83,7 @@
              t,
              u;
              
-        if (encrypt) {
+        if (_encrypt) {
             B += S[0];
             D += S[1];
             for (int i = 1; i <= ROUNDS; i++) {
--- a/dcrypt/crypto/ciphers/TEA.d	Fri Sep 12 05:20:43 2008 -0400
+++ b/dcrypt/crypto/ciphers/TEA.d	Tue Nov 18 18:03:40 2008 -0500
@@ -21,8 +21,6 @@
                    DELTA = 0x9e3779b9,
                    DECRYPT_SUM = 0xc6ef3720;
         uint sk0, sk1, sk2, sk3, sum;
-        bool initialized,
-             encrypt;
     }
     
     void reset(){}
@@ -40,7 +38,7 @@
         if (!keyParams)
             throw new InvalidParameterError(
                     name()~": Invalid parameter passed to init");
-        this.encrypt = encrypt;
+        _encrypt = encrypt;
                     
         if (keyParams.key.length != KEY_SIZE)
             throw new InvalidKeyError(
@@ -51,11 +49,11 @@
         sk2 = Util.ubytesToUintBig(keyParams.key, 8);
         sk3 = Util.ubytesToUintBig(keyParams.key, 12);
 
-        initialized = true;
+        _initialized = true;
     }
     
     uint update(void[] input_, void[] output_) {
-        if (!initialized)
+        if (!_initialized)
             throw new NotInitializedError(name()~": Cipher not initialized");
             
         ubyte[] input = cast(ubyte[]) input_,
@@ -70,9 +68,9 @@
         uint v0 = Util.ubytesToUintBig(input, 0),
              v1 = Util.ubytesToUintBig(input, 4);
         
-        sum = encrypt ? 0 : DECRYPT_SUM;
+        sum = _encrypt ? 0 : DECRYPT_SUM;
         for (int i = 0; i < ROUNDS; i++) {
-            if (encrypt) {
+            if (_encrypt) {
                 sum += DELTA;
                 v0 += ((v1 << 4) + sk0) ^ (v1 + sum) ^ ((v1 >> 5) + sk1);
                 v1 += ((v0 << 4) + sk2) ^ (v0 + sum) ^ ((v0 >> 5) + sk3);
--- a/dcrypt/crypto/ciphers/XTEA.d	Fri Sep 12 05:20:43 2008 -0400
+++ b/dcrypt/crypto/ciphers/XTEA.d	Tue Nov 18 18:03:40 2008 -0500
@@ -22,8 +22,6 @@
         uint[] subkeys,
                sum0,
                sum1;
-        bool initialized,
-             encrypt;
     }
     
     void reset(){}
@@ -41,7 +39,7 @@
         if (!keyParams)
             throw new InvalidParameterError(
                     name()~": Invalid parameter passed to init");
-        this.encrypt = encrypt;
+        _encrypt = encrypt;
                     
         if (keyParams.key.length != KEY_SIZE)
             throw new InvalidKeyError(
@@ -61,11 +59,11 @@
             j += DELTA;
             sum1[i] = (j + subkeys[j >> 11 & 3]);
         }
-        initialized = true;
+        _initialized = true;
     }
     
     uint update(void[] input_, void[] output_) {
-        if (!initialized)
+        if (!_initialized)
             throw new NotInitializedError(name()~": Cipher not initialized");
             
         ubyte[] input = cast(ubyte[]) input_,
@@ -80,7 +78,7 @@
         uint v0 = Util.ubytesToUintBig(input, 0),
              v1 = Util.ubytesToUintBig(input, 4);
              
-        if (encrypt) {
+        if (_encrypt) {
             for (int i = 0; i < ROUNDS; i++) {
                 v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ sum0[i];
                 v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^ sum1[i];
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dcrypt/crypto/errors/NotSupportedError.d	Tue Nov 18 18:03:40 2008 -0500
@@ -0,0 +1,13 @@
+/**
+ * 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.errors.NotSupportedError;
+
+class NotSupportedError : Exception {
+    this(char[] msg) { super(msg); }
+}
--- a/dcrypt/crypto/macs/HMAC.d	Fri Sep 12 05:20:43 2008 -0400
+++ b/dcrypt/crypto/macs/HMAC.d	Tue Nov 18 18:03:40 2008 -0500
@@ -95,14 +95,14 @@
         return inner.digestSize;
     }
     
-    ubyte[] finish() {
+    ubyte[] digest() {
         outer.update(inner.digest());
         ubyte[] r = outer.digest();
         reset();
         return r;
     }
     
-    char[] hexFinish() {
+    char[] hexDigest() {
         return Util.ubytesToHex(finish());
     }
     
@@ -151,7 +151,7 @@
                 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();
+                char[] mac = h.hexDigest();
                 assert(mac == test_results[i], 
                         h.name~": ("~mac~") != ("~test_results[i]~")");
             }
--- a/dcrypt/crypto/params/ParametersWithIV.d	Fri Sep 12 05:20:43 2008 -0400
+++ b/dcrypt/crypto/params/ParametersWithIV.d	Tue Nov 18 18:03:40 2008 -0500
@@ -12,25 +12,22 @@
 
 /** Wrap cipher parameters and IV. */
 class ParametersWithIV : CipherParameters {
-    private ubyte[] m_iv;
-    private CipherParameters m_params;
+    private ubyte[] _iv;
+    private CipherParameters _params;
     
     /**
      * Params:
      *     params = Parameters to wrap.
      *     iv     = IV to be held.
      */
-    this (CipherParameters params=null, ubyte[] iv_=null) {
-        if (params)
-            m_params = params;
-        ubyte[] iv = cast(ubyte[]) iv_;
-        if (iv)
-            m_iv = iv;
+    this (CipherParameters params=null, ubyte[] iv=null) {
+        _params = params;
+        _iv = cast(ubyte[]) iv;
     }
     
     /** Returns: The IV. */
     ubyte[] iv() {
-        return m_iv;
+        return _iv;
     }
     
     /**
@@ -40,14 +37,13 @@
      *     newIV = The new IV for this parameter object.
      * Returns: The new IV.
      */
-    ubyte[] iv(void[] newIV_) {
-        ubyte[] newIV = cast(ubyte[]) newIV_;
-        return m_iv = newIV;
+    ubyte[] iv(void[] newIV) {;
+        return _iv = cast(ubyte[]) newIV;
     }
     
     /** Returns: The parameters for this object. */
     CipherParameters parameters() {
-        return m_params;
+        return _params;
     }
     
     /**
@@ -58,6 +54,6 @@
      * Returns: The new parameters.
      */
     CipherParameters parameters(CipherParameters newParams) {
-        return m_params = newParams;
+        return _params = newParams;
     }
 }
--- a/dcrypt/crypto/params/SymmetricKey.d	Fri Sep 12 05:20:43 2008 -0400
+++ b/dcrypt/crypto/params/SymmetricKey.d	Tue Nov 18 18:03:40 2008 -0500
@@ -9,24 +9,23 @@
 module dcrypt.crypto.params.SymmetricKey;
 
 import dcrypt.crypto.params.CipherParameters;
+import dcrypt.crypto.errors.InvalidParameterError;
 
 /** Object representing and wrapping a symmetric key in bytes. */
 class SymmetricKey : CipherParameters {
-    private ubyte[] m_key;
+    private ubyte[] _key;
     
     /**
      * Params:
      *     key = Key to be held.
      */
-    this(void[] key_=null) {
-        ubyte[] key = cast(ubyte[]) key_;
-        if (key)
-            m_key = key;
+    this(void[] key=null) {
+        _key = cast(ubyte[]) key;
     }
     
     /** Returns: Key in ubytes held by this object. */
     ubyte[] key() {
-        return m_key;
+        return _key;
     }
     
     /**
@@ -36,8 +35,7 @@
      *     newKey = New key to be held.
      * Returns: The new key.
      */
-    ubyte[] key(void[] newKey_) {
-        ubyte[] newKey = cast(ubyte[])newKey_;
-        return m_key = newKey;
+    ubyte[] key(void[] newKey) {
+        return _key = cast(ubyte[]) newKey;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dcrypt/crypto/prngs/PRNGFromHash.d	Tue Nov 18 18:03:40 2008 -0500
@@ -0,0 +1,74 @@
+/**
+ * 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.prngs.PRNGFromHash;
+
+import dcrypt.crypto.PRNG;
+import dcrypt.crypto.Hash;
+import dcrypt.crypto.hashes.SHA256;
+
+/** Creates a PRNG from a hash function. */
+class PRNGFromHash : PRNG {
+    private {
+        const uint COUNTER_SIZE = 32;
+        
+        Hash hash;
+        ubyte[] counter,
+                seed,
+                state;
+        uint index;
+    }
+    
+    char[] name() {
+        if (hash is null)
+            throw new NotInitializedError(name()~": PRNG not initialized");
+        
+        return hash.name~"PRNG";
+    }
+    
+    this(Hash hash=null) {
+        this.hash = (hash is null) ? new SHA256() : hash;
+        this.hash.reset();
+        
+        counter = new ubyte[COUNTER_SIZE];
+        seed = new ubyte[this.hash.digestSize];
+        state = new ubyte[this.hash.digestSize];
+        
+        index = this.hash.digestSize; // to force updating of the state
+    }
+    
+    void addEntropy(ubyte[] input) {
+        if (!_initialized) {
+            hash.update(input);
+            seed = hash.digest();
+            _initialized = true;
+        } else
+            throw new NotSupportedError(name()~": state is immutable once initialized");
+    }
+    
+    uint read(ubyte[] output) {
+        if (!_initialized)
+            throw new NotInitializedError(name()~": PRNG not initialized");
+        
+        for (uint i = 0; i < output.length; i++) {
+            if (index == state.length) {
+                hash.update(seed);
+                hash.update(counter);
+                state = hash.digest();
+                
+                // Increment the counter
+                for (uint j = COUNTER_SIZE-1; j >= 0; j--)
+                    if (++counter[j]) break;
+                
+                index = 0;
+            }
+            output[i] = state[index++];
+        }
+        return output.length;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dcrypt/misc/Checksum.d	Tue Nov 18 18:03:40 2008 -0500
@@ -0,0 +1,26 @@
+/**
+ * This file is part of the dcrypt project.
+ *
+ * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved.
+ * License:   MIT
+ * Authors:   Thomas Dixon
+ */
+
+module dcrypt.misc.Checksum;
+
+/** Base class for 32-bit checksums */
+abstract class Checksum {
+    /**
+     * Compute a checksum.
+     * 
+     * Params:
+     *     input_ = Data to be processed.
+     *     start = Starting value for the checksum.
+     *     
+     * Returns: The computed 32 bit checksum.
+     */
+    uint compute(void[] input_, uint start);
+    
+    /** Returns: The name of the checksum algorithm. */
+    char[] name();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dcrypt/misc/checksums/Adler32.d	Tue Nov 18 18:03:40 2008 -0500
@@ -0,0 +1,61 @@
+/**
+ * This file is part of the dcrypt project.
+ *
+ * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved.
+ * License:   MIT
+ * Authors:   Thomas Dixon
+ */
+
+module dcrypt.misc.checksums.Adler32;
+
+import dcrypt.misc.Checksum;
+
+/**
+ * Implementation of Mark Adler's Adler32 checksum.
+ * 
+ * Conforms: RFC 1950
+ * References: http://tools.ietf.org/html/rfc1950#page-10
+ */
+class Adler32 : Checksum {
+    private static const uint BASE = 65521;
+    
+    uint compute(void[] input_, uint start=1) {
+        ubyte[] input = cast(ubyte[])input_;
+        uint adler = start,
+             s1 = adler & 0xffff,
+             s2 = (adler >> 16) & 0xffff;
+        
+        foreach (ubyte i; input) {
+            s1 = (s1 + i) % BASE;
+            s2 = (s2 + s1) % BASE;
+        }
+        
+        return (s2 << 16) + s1;
+    }
+    
+    char[] name() {
+        return "Adler32";
+    }
+    
+    version (UnitTest) {
+        unittest {
+            static char[][] test_inputs = [
+                "",
+                "a",
+                "checksum",
+                "chexksum"
+            ];
+            
+            static const uint[] test_results = [
+                0x1u,
+                0x620062u,
+                0xea10354u,
+                0xf0a0369u
+            ];
+            
+            Adler32 adler32 = new Adler32;
+            foreach (uint i, char[] j; test_inputs)
+                assert(adler32.compute(j) == test_results[i], adler32.name);
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dcrypt/misc/checksums/CRC32.d	Tue Nov 18 18:03:40 2008 -0500
@@ -0,0 +1,105 @@
+/**
+ * This file is part of the dcrypt project.
+ *
+ * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved.
+ * License:   MIT
+ * Authors:   Thomas Dixon
+ */
+
+module dcrypt.misc.checksums.CRC32;
+
+import dcrypt.misc.Checksum;
+
+class CRC32 : Checksum {
+    // Polynomial used is 0xedb88320.
+    private static const uint[256] table = [
+        0x00000000u, 0x77073096u, 0xee0e612cu, 0x990951bau, 0x076dc419u,
+        0x706af48fu, 0xe963a535u, 0x9e6495a3u, 0x0edb8832u, 0x79dcb8a4u,
+        0xe0d5e91eu, 0x97d2d988u, 0x09b64c2bu, 0x7eb17cbdu, 0xe7b82d07u,
+        0x90bf1d91u, 0x1db71064u, 0x6ab020f2u, 0xf3b97148u, 0x84be41deu,
+        0x1adad47du, 0x6ddde4ebu, 0xf4d4b551u, 0x83d385c7u, 0x136c9856u,
+        0x646ba8c0u, 0xfd62f97au, 0x8a65c9ecu, 0x14015c4fu, 0x63066cd9u,
+        0xfa0f3d63u, 0x8d080df5u, 0x3b6e20c8u, 0x4c69105eu, 0xd56041e4u,
+        0xa2677172u, 0x3c03e4d1u, 0x4b04d447u, 0xd20d85fdu, 0xa50ab56bu,
+        0x35b5a8fau, 0x42b2986cu, 0xdbbbc9d6u, 0xacbcf940u, 0x32d86ce3u,
+        0x45df5c75u, 0xdcd60dcfu, 0xabd13d59u, 0x26d930acu, 0x51de003au,
+        0xc8d75180u, 0xbfd06116u, 0x21b4f4b5u, 0x56b3c423u, 0xcfba9599u,
+        0xb8bda50fu, 0x2802b89eu, 0x5f058808u, 0xc60cd9b2u, 0xb10be924u,
+        0x2f6f7c87u, 0x58684c11u, 0xc1611dabu, 0xb6662d3du, 0x76dc4190u,
+        0x01db7106u, 0x98d220bcu, 0xefd5102au, 0x71b18589u, 0x06b6b51fu,
+        0x9fbfe4a5u, 0xe8b8d433u, 0x7807c9a2u, 0x0f00f934u, 0x9609a88eu,
+        0xe10e9818u, 0x7f6a0dbbu, 0x086d3d2du, 0x91646c97u, 0xe6635c01u,
+        0x6b6b51f4u, 0x1c6c6162u, 0x856530d8u, 0xf262004eu, 0x6c0695edu,
+        0x1b01a57bu, 0x8208f4c1u, 0xf50fc457u, 0x65b0d9c6u, 0x12b7e950u,
+        0x8bbeb8eau, 0xfcb9887cu, 0x62dd1ddfu, 0x15da2d49u, 0x8cd37cf3u,
+        0xfbd44c65u, 0x4db26158u, 0x3ab551ceu, 0xa3bc0074u, 0xd4bb30e2u,
+        0x4adfa541u, 0x3dd895d7u, 0xa4d1c46du, 0xd3d6f4fbu, 0x4369e96au,
+        0x346ed9fcu, 0xad678846u, 0xda60b8d0u, 0x44042d73u, 0x33031de5u,
+        0xaa0a4c5fu, 0xdd0d7cc9u, 0x5005713cu, 0x270241aau, 0xbe0b1010u,
+        0xc90c2086u, 0x5768b525u, 0x206f85b3u, 0xb966d409u, 0xce61e49fu,
+        0x5edef90eu, 0x29d9c998u, 0xb0d09822u, 0xc7d7a8b4u, 0x59b33d17u,
+        0x2eb40d81u, 0xb7bd5c3bu, 0xc0ba6cadu, 0xedb88320u, 0x9abfb3b6u,
+        0x03b6e20cu, 0x74b1d29au, 0xead54739u, 0x9dd277afu, 0x04db2615u,
+        0x73dc1683u, 0xe3630b12u, 0x94643b84u, 0x0d6d6a3eu, 0x7a6a5aa8u,
+        0xe40ecf0bu, 0x9309ff9du, 0x0a00ae27u, 0x7d079eb1u, 0xf00f9344u,
+        0x8708a3d2u, 0x1e01f268u, 0x6906c2feu, 0xf762575du, 0x806567cbu,
+        0x196c3671u, 0x6e6b06e7u, 0xfed41b76u, 0x89d32be0u, 0x10da7a5au,
+        0x67dd4accu, 0xf9b9df6fu, 0x8ebeeff9u, 0x17b7be43u, 0x60b08ed5u,
+        0xd6d6a3e8u, 0xa1d1937eu, 0x38d8c2c4u, 0x4fdff252u, 0xd1bb67f1u,
+        0xa6bc5767u, 0x3fb506ddu, 0x48b2364bu, 0xd80d2bdau, 0xaf0a1b4cu,
+        0x36034af6u, 0x41047a60u, 0xdf60efc3u, 0xa867df55u, 0x316e8eefu,
+        0x4669be79u, 0xcb61b38cu, 0xbc66831au, 0x256fd2a0u, 0x5268e236u,
+        0xcc0c7795u, 0xbb0b4703u, 0x220216b9u, 0x5505262fu, 0xc5ba3bbeu,
+        0xb2bd0b28u, 0x2bb45a92u, 0x5cb36a04u, 0xc2d7ffa7u, 0xb5d0cf31u,
+        0x2cd99e8bu, 0x5bdeae1du, 0x9b64c2b0u, 0xec63f226u, 0x756aa39cu,
+        0x026d930au, 0x9c0906a9u, 0xeb0e363fu, 0x72076785u, 0x05005713u,
+        0x95bf4a82u, 0xe2b87a14u, 0x7bb12baeu, 0x0cb61b38u, 0x92d28e9bu,
+        0xe5d5be0du, 0x7cdcefb7u, 0x0bdbdf21u, 0x86d3d2d4u, 0xf1d4e242u,
+        0x68ddb3f8u, 0x1fda836eu, 0x81be16cdu, 0xf6b9265bu, 0x6fb077e1u,
+        0x18b74777u, 0x88085ae6u, 0xff0f6a70u, 0x66063bcau, 0x11010b5cu,
+        0x8f659effu, 0xf862ae69u, 0x616bffd3u, 0x166ccf45u, 0xa00ae278u,
+        0xd70dd2eeu, 0x4e048354u, 0x3903b3c2u, 0xa7672661u, 0xd06016f7u,
+        0x4969474du, 0x3e6e77dbu, 0xaed16a4au, 0xd9d65adcu, 0x40df0b66u,
+        0x37d83bf0u, 0xa9bcae53u, 0xdebb9ec5u, 0x47b2cf7fu, 0x30b5ffe9u,
+        0xbdbdf21cu, 0xcabac28au, 0x53b39330u, 0x24b4a3a6u, 0xbad03605u,
+        0xcdd70693u, 0x54de5729u, 0x23d967bfu, 0xb3667a2eu, 0xc4614ab8u,
+        0x5d681b02u, 0x2a6f2b94u, 0xb40bbe37u, 0xc30c8ea1u, 0x5a05df1bu,
+        0x2d02ef8du
+    ];
+    
+    uint compute(void[] input_, uint start=0) {
+        ubyte[] input = cast(ubyte[])input_;
+        uint crc = (start ^ 0xffffffff);
+        
+        foreach (ubyte i; input)
+            crc = table[cast(ubyte)(crc ^ i)] ^ (crc >> 8);
+          
+        return (crc ^ 0xffffffff);
+    }
+    
+    char[] name() {
+        return "CRC32";
+    }
+    
+    version (UnitTest) {
+        unittest {
+            static char[][] test_inputs = [
+                "",
+                "a",
+                "checksum",
+                "chexksum"
+            ];
+            
+            static const uint[] test_results = [
+                0x0u,
+                0xe8b7be43u,
+                0xde6fdf9au,
+                0xc95f7909u
+            ];
+            
+            CRC32 crc32 = new CRC32;
+            foreach (uint i, char[] j; test_inputs)
+                assert(crc32.compute(j) == test_results[i], crc32.name);
+        }
+    }
+}
\ No newline at end of file
--- a/dsss.conf	Fri Sep 12 05:20:43 2008 -0400
+++ b/dsss.conf	Tue Nov 18 18:03:40 2008 -0500
@@ -1,3 +1,4 @@
 name = dcrypt
 [dcrypt]
+buildflags = -O
 target = dcrypt