Mercurial > projects > dcrypt
diff dcrypt/crypto/ciphers/XTEA.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/XTEA.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,163 @@ +/** + * 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.XTEA; + +import dcrypt.misc.Util; +import dcrypt.crypto.BlockCipher; + +/** Implementation of the XTEA cipher designed by + David Wheeler and Roger Needham. */ +class XTEA : BlockCipher { + private const uint ROUNDS = 32, + KEY_SIZE = 16, + BLOCK_SIZE = 8, + DELTA = 0x9e3779b9; + private uint[] subkeys, + sum0, + sum1; + private bool initialized, + encrypt; + + void reset(){} + + char[] name() { + return "XTEA"; + } + + 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)"); + + subkeys = new uint[4]; + sum0 = new uint[32]; + sum1 = new uint[32]; + + int i, j; + for (i = j = 0; i < 4; i++, j+=4) + subkeys[i] = Util.ubytesToUintBig(keyParams.key, j); + + // Precompute the values of sum + k[] to speed up encryption + for (i = j = 0; i < ROUNDS; i++) { + sum0[i] = (j + subkeys[j & 3]); + j += DELTA; + sum1[i] = (j + subkeys[j >> 11 & 3]); + } + 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); + + 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]; + } + } else { + for (int i = ROUNDS-1; i >= 0; i--) { + v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ sum1[i]; + v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ sum0[i]; + } + } + + Util.uintToUbytesBig(v0, output, outOff); + Util.uintToUbytesBig(v1, output, outOff+4); + + return BLOCK_SIZE; + } + + /** Some XTEA test vectors. */ + version (UnitTest) { + unittest { + static const char[][] test_keys = [ + "00000000000000000000000000000000", + "00000000000000000000000000000000", + "0123456712345678234567893456789a", + "0123456712345678234567893456789a", + "00000000000000000000000000000001", + "01010101010101010101010101010101", + "0123456789abcdef0123456789abcdef", + "0123456789abcdef0123456789abcdef", + "00000000000000000000000000000000", + "00000000000000000000000000000000" + ]; + + static const char[][] test_plaintexts = [ + "0000000000000000", + "0102030405060708", + "0000000000000000", + "0102030405060708", + "0000000000000001", + "0101010101010101", + "0123456789abcdef", + "0000000000000000", + "0123456789abcdef", + "4141414141414141" + ]; + + static const char[][] test_ciphertexts = [ + "dee9d4d8f7131ed9", + "065c1b8975c6a816", + "1ff9a0261ac64264", + "8c67155b2ef91ead", + "9f25fa5b0f86b758", + "c2eca7cec9b7f992", + "27e795e076b2b537", + "5c8eddc60a95b3e1", + "7e66c71c88897221", + "ed23375a821a8c2d" + ]; + + XTEA t = new XTEA(); + 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]~")"); + } + } + } +}