Mercurial > projects > dcrypt
view dcrypt/crypto/ciphers/XTEA.d @ 1:483e4467b5f6
Added Blowfish with test vectors. Minor cleanup of other cipher classes (should probably clean more). Continued work on high-level cipher API (didn't get very far).
author | Thomas Dixon <reikon@reikon.us> |
---|---|
date | Tue, 12 Aug 2008 05:48:06 -0400 |
parents | 0e08791a1418 |
children | 71aae178f89a |
line wrap: on
line source
/** * 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; uint[] subkeys, sum0, sum1; 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]~")"); } } } }