Mercurial > projects > dcrypt
annotate dcrypt/crypto/ciphers/XTEA.d @ 12:8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
author | Thomas Dixon <reikon@reikon.us> |
---|---|
date | Sat, 30 Aug 2008 14:38:23 -0400 |
parents | 23c62e28b3a4 |
children | 5ce3012f1def |
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 | |
12
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
67 uint update(void[] input_, void[] output_) { |
0 | 68 if (!initialized) |
69 throw new NotInitializedError(name()~": Cipher not initialized"); | |
70 | |
12
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
71 ubyte[] input = cast(ubyte[]) input_, |
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
72 output = cast(ubyte[]) output_; |
0 | 73 |
12
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
74 if (input.length < BLOCK_SIZE) |
0 | 75 throw new ShortBufferError(name()~": Input buffer too short"); |
12
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
76 |
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
77 if (output.length < BLOCK_SIZE) |
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
78 throw new ShortBufferError(name()~": Output buffer too short"); |
0 | 79 |
8
23c62e28b3a4
Reworked symmetric cipher classes to have SymmetricCipher as their superclass, and follow the general interface of init(), process(), etc. Made sure everything still passed test vectors. Removed Cipher class. I'll worry about that shit when we support something other than symmetric ciphers.
Thomas Dixon <reikon@reikon.us>
parents:
6
diff
changeset
|
80 uint v0 = Util.ubytesToUintBig(input, 0), |
23c62e28b3a4
Reworked symmetric cipher classes to have SymmetricCipher as their superclass, and follow the general interface of init(), process(), etc. Made sure everything still passed test vectors. Removed Cipher class. I'll worry about that shit when we support something other than symmetric ciphers.
Thomas Dixon <reikon@reikon.us>
parents:
6
diff
changeset
|
81 v1 = Util.ubytesToUintBig(input, 4); |
0 | 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 | |
8
23c62e28b3a4
Reworked symmetric cipher classes to have SymmetricCipher as their superclass, and follow the general interface of init(), process(), etc. Made sure everything still passed test vectors. Removed Cipher class. I'll worry about that shit when we support something other than symmetric ciphers.
Thomas Dixon <reikon@reikon.us>
parents:
6
diff
changeset
|
95 Util.uintToUbytesBig(v0, output, 0); |
23c62e28b3a4
Reworked symmetric cipher classes to have SymmetricCipher as their superclass, and follow the general interface of init(), process(), etc. Made sure everything still passed test vectors. Removed Cipher class. I'll worry about that shit when we support something other than symmetric ciphers.
Thomas Dixon <reikon@reikon.us>
parents:
6
diff
changeset
|
96 Util.uintToUbytesBig(v1, output, 4); |
0 | 97 |
12
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
98 return BLOCK_SIZE; |
0 | 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); | |
12
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
151 t.update(Util.hexToUbytes(test_plaintexts[i]), buffer); |
0 | 152 result = Util.ubytesToHex(buffer); |
153 assert(result == test_ciphertexts[i], | |
2
71aae178f89a
Added copy() to hash functions. Modified some code style.
Thomas Dixon <reikon@reikon.us>
parents:
1
diff
changeset
|
154 t.name~": ("~result~") != ("~test_ciphertexts[i]~")"); |
0 | 155 |
156 // Decryption | |
157 t.init(false, key); | |
12
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
158 t.update(Util.hexToUbytes(test_ciphertexts[i]), buffer); |
0 | 159 result = Util.ubytesToHex(buffer); |
160 assert(result == test_plaintexts[i], | |
6
5cb17e09d685
Minor edits to the unittests of hash functions and ciphers. Added AES and test vectors.
Thomas Dixon <reikon@reikon.us>
parents:
2
diff
changeset
|
161 t.name~": ("~result~") != ("~test_plaintexts[i]~")"); |
0 | 162 } |
163 } | |
164 } | |
165 } |