diff dcrypt/crypto/ciphers/TEA.d @ 0:0e08791a1418

Initial import.
author Thomas Dixon <reikon@reikon.us>
date Sun, 10 Aug 2008 14:20:17 -0400
parents
children 483e4467b5f6
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dcrypt/crypto/ciphers/TEA.d	Sun Aug 10 14:20:17 2008 -0400
@@ -0,0 +1,135 @@
+/**
+ * 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.ciphers.TEA;
+
+import dcrypt.misc.Util;
+import dcrypt.crypto.BlockCipher;
+
+/** Implementation of the TEA cipher designed by
+    David Wheeler and Roger Needham. */
+class TEA : BlockCipher {
+    private const uint ROUNDS = 32,
+                       KEY_SIZE = 16,
+                       BLOCK_SIZE = 8,
+                       DELTA = 0x9e3779b9,
+                       DECRYPT_SUM = 0xc6ef3720;
+    private uint sk0, sk1, sk2, sk3, sum;
+    private bool initialized,
+                 encrypt;
+    
+    void reset(){}
+    
+    char[] name() {
+        return "TEA";
+    }
+    
+    uint blockSize() {
+        return BLOCK_SIZE;
+    }
+    
+    void init(bool encrypt, CipherParameters params) {
+        SymmetricKey keyParams = cast(SymmetricKey)params;
+        if (!keyParams)
+            throw new InvalidParameterError(
+                    name()~": Invalid parameter passed to init");
+        this.encrypt = encrypt;
+                    
+        if (keyParams.key.length != KEY_SIZE)
+            throw new InvalidKeyError(
+                    name()~": Invalid key length (requires 16 bytes)");
+        
+        sk0 = Util.ubytesToUintBig(keyParams.key, 0);
+        sk1 = Util.ubytesToUintBig(keyParams.key, 4);
+        sk2 = Util.ubytesToUintBig(keyParams.key, 8);
+        sk3 = Util.ubytesToUintBig(keyParams.key, 12);
+
+        initialized = true;
+    }
+    
+    uint processBlock(void[] input_, uint inOff, void[] output_, uint outOff) {
+        if (!initialized)
+            throw new NotInitializedError(name()~": Cipher not initialized");
+            
+        ubyte[] input = cast(ubyte[]) input_;
+        ubyte[] output = cast(ubyte[]) output_;
+                    
+        if ((inOff + BLOCK_SIZE) > input.length)
+            throw new ShortBufferError(name()~": Input buffer too short");
+            
+        if ((outOff + BLOCK_SIZE) > output.length)
+            throw new ShortBufferError(name()~": Output buffer too short");
+        
+        uint v0 = Util.ubytesToUintBig(input, inOff),
+             v1 = Util.ubytesToUintBig(input, inOff+4);
+        
+        sum = encrypt ? 0 : DECRYPT_SUM;
+        for (int i = 0; i < ROUNDS; i++) {
+            if (encrypt) {
+                sum += DELTA;
+                v0 += ((v1 << 4) + sk0) ^ (v1 + sum) ^ ((v1 >> 5) + sk1);
+                v1 += ((v0 << 4) + sk2) ^ (v0 + sum) ^ ((v0 >> 5) + sk3);
+            } else {
+                v1 -= ((v0 << 4) + sk2) ^ (v0 + sum) ^ ((v0 >> 5) + sk3);
+                v0 -= ((v1 << 4) + sk0) ^ (v1 + sum) ^ ((v1 >> 5) + sk1);
+                sum -= DELTA;
+            }
+        }
+        
+        Util.uintToUbytesBig(v0, output, outOff);
+        Util.uintToUbytesBig(v1, output, outOff+4);
+        
+        return BLOCK_SIZE;
+    }
+    
+    /** Some TEA test vectors. */
+    unittest {
+        static const char[][] test_keys = [
+            "00000000000000000000000000000000",
+            "00000000000000000000000000000000",
+            "0123456712345678234567893456789a",
+            "0123456712345678234567893456789a"
+        ];
+             
+        static const char[][] test_plaintexts = [
+            "0000000000000000",
+            "0102030405060708",
+            "0000000000000000",
+            "0102030405060708"
+        ];
+            
+        static const char[][] test_ciphertexts = [
+            "41ea3a0a94baa940",
+            "6a2f9cf3fccf3c55",
+            "34e943b0900f5dcb",
+            "773dc179878a81c0"
+        ];
+            
+        
+        TEA t = new TEA();
+        foreach (uint i, char[] test_key; test_keys) {
+            ubyte[] buffer = new ubyte[t.blockSize];
+            char[] result;
+            SymmetricKey key = new SymmetricKey(Util.hexToUbytes(test_key));
+            
+            // Encryption
+            t.init(true, key);
+            t.processBlock(Util.hexToUbytes(test_plaintexts[i]), 0, buffer, 0);
+            result = Util.ubytesToHex(buffer);
+            assert(result == test_ciphertexts[i],
+                    t.name()~": ("~result~") != ("~test_ciphertexts[i]~")");
+
+            // Decryption
+            t.init(false, key);
+            t.processBlock(Util.hexToUbytes(test_ciphertexts[i]), 0, buffer, 0);
+            result = Util.ubytesToHex(buffer);
+            assert(result == test_plaintexts[i],
+                    t.name()~": ("~result~") != ("~test_ciphertexts[i]~")");
+        }
+    }
+}