Mercurial > projects > dcrypt
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:0e08791a1418 |
---|---|
1 /** | |
2 * This file is part of the dcrypt project. | |
3 * | |
4 * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. | |
5 * License: MIT | |
6 * Authors: Thomas Dixon | |
7 */ | |
8 | |
9 module dcrypt.crypto.ciphers.XTEA; | |
10 | |
11 import dcrypt.misc.Util; | |
12 import dcrypt.crypto.BlockCipher; | |
13 | |
14 /** Implementation of the XTEA cipher designed by | |
15 David Wheeler and Roger Needham. */ | |
16 class XTEA : BlockCipher { | |
17 private const uint ROUNDS = 32, | |
18 KEY_SIZE = 16, | |
19 BLOCK_SIZE = 8, | |
20 DELTA = 0x9e3779b9; | |
21 private uint[] subkeys, | |
22 sum0, | |
23 sum1; | |
24 private bool initialized, | |
25 encrypt; | |
26 | |
27 void reset(){} | |
28 | |
29 char[] name() { | |
30 return "XTEA"; | |
31 } | |
32 | |
33 uint blockSize() { | |
34 return BLOCK_SIZE; | |
35 } | |
36 | |
37 void init(bool encrypt, CipherParameters params) { | |
38 SymmetricKey keyParams = cast(SymmetricKey)params; | |
39 if (!keyParams) | |
40 throw new InvalidParameterError( | |
41 name()~": Invalid parameter passed to init"); | |
42 this.encrypt = encrypt; | |
43 | |
44 if (keyParams.key.length != KEY_SIZE) | |
45 throw new InvalidKeyError( | |
46 name()~": Invalid key length (requires 16 bytes)"); | |
47 | |
48 subkeys = new uint[4]; | |
49 sum0 = new uint[32]; | |
50 sum1 = new uint[32]; | |
51 | |
52 int i, j; | |
53 for (i = j = 0; i < 4; i++, j+=4) | |
54 subkeys[i] = Util.ubytesToUintBig(keyParams.key, j); | |
55 | |
56 // Precompute the values of sum + k[] to speed up encryption | |
57 for (i = j = 0; i < ROUNDS; i++) { | |
58 sum0[i] = (j + subkeys[j & 3]); | |
59 j += DELTA; | |
60 sum1[i] = (j + subkeys[j >> 11 & 3]); | |
61 } | |
62 initialized = true; | |
63 } | |
64 | |
65 uint processBlock(void[] input_, uint inOff, void[] output_, uint outOff) { | |
66 if (!initialized) | |
67 throw new NotInitializedError(name()~": Cipher not initialized"); | |
68 | |
69 ubyte[] input = cast(ubyte[]) input_; | |
70 ubyte[] output = cast(ubyte[]) output_; | |
71 | |
72 if ((inOff + BLOCK_SIZE) > input.length) | |
73 throw new ShortBufferError(name()~": Input buffer too short"); | |
74 | |
75 if ((outOff + BLOCK_SIZE) > output.length) | |
76 throw new ShortBufferError(name()~": Output buffer too short"); | |
77 | |
78 uint v0 = Util.ubytesToUintBig(input, inOff), | |
79 v1 = Util.ubytesToUintBig(input, inOff+4); | |
80 | |
81 if (encrypt) { | |
82 for (int i = 0; i < ROUNDS; i++) { | |
83 v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ sum0[i]; | |
84 v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^ sum1[i]; | |
85 } | |
86 } else { | |
87 for (int i = ROUNDS-1; i >= 0; i--) { | |
88 v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ sum1[i]; | |
89 v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ sum0[i]; | |
90 } | |
91 } | |
92 | |
93 Util.uintToUbytesBig(v0, output, outOff); | |
94 Util.uintToUbytesBig(v1, output, outOff+4); | |
95 | |
96 return BLOCK_SIZE; | |
97 } | |
98 | |
99 /** Some XTEA test vectors. */ | |
100 version (UnitTest) { | |
101 unittest { | |
102 static const char[][] test_keys = [ | |
103 "00000000000000000000000000000000", | |
104 "00000000000000000000000000000000", | |
105 "0123456712345678234567893456789a", | |
106 "0123456712345678234567893456789a", | |
107 "00000000000000000000000000000001", | |
108 "01010101010101010101010101010101", | |
109 "0123456789abcdef0123456789abcdef", | |
110 "0123456789abcdef0123456789abcdef", | |
111 "00000000000000000000000000000000", | |
112 "00000000000000000000000000000000" | |
113 ]; | |
114 | |
115 static const char[][] test_plaintexts = [ | |
116 "0000000000000000", | |
117 "0102030405060708", | |
118 "0000000000000000", | |
119 "0102030405060708", | |
120 "0000000000000001", | |
121 "0101010101010101", | |
122 "0123456789abcdef", | |
123 "0000000000000000", | |
124 "0123456789abcdef", | |
125 "4141414141414141" | |
126 ]; | |
127 | |
128 static const char[][] test_ciphertexts = [ | |
129 "dee9d4d8f7131ed9", | |
130 "065c1b8975c6a816", | |
131 "1ff9a0261ac64264", | |
132 "8c67155b2ef91ead", | |
133 "9f25fa5b0f86b758", | |
134 "c2eca7cec9b7f992", | |
135 "27e795e076b2b537", | |
136 "5c8eddc60a95b3e1", | |
137 "7e66c71c88897221", | |
138 "ed23375a821a8c2d" | |
139 ]; | |
140 | |
141 XTEA t = new XTEA(); | |
142 foreach (uint i, char[] test_key; test_keys) { | |
143 ubyte[] buffer = new ubyte[t.blockSize]; | |
144 char[] result; | |
145 SymmetricKey key = new SymmetricKey(Util.hexToUbytes(test_key)); | |
146 | |
147 // Encryption | |
148 t.init(true, key); | |
149 t.processBlock(Util.hexToUbytes(test_plaintexts[i]), 0, buffer, 0); | |
150 result = Util.ubytesToHex(buffer); | |
151 assert(result == test_ciphertexts[i], | |
152 t.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); | |
153 | |
154 // Decryption | |
155 t.init(false, key); | |
156 t.processBlock(Util.hexToUbytes(test_ciphertexts[i]), 0, buffer, 0); | |
157 result = Util.ubytesToHex(buffer); | |
158 assert(result == test_plaintexts[i], | |
159 t.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); | |
160 } | |
161 } | |
162 } | |
163 } |