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