Mercurial > projects > dcrypt
annotate dcrypt/crypto/ciphers/RC6.d @ 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.
author | Thomas Dixon <reikon@reikon.us> |
---|---|
date | Mon, 18 Aug 2008 01:14:37 -0400 |
parents | 5cb17e09d685 |
children | 8c7f8fecdd75 |
rev | line source |
---|---|
0 | 1 /** |
2 * This file is part of the dcrypt project. | |
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
|
3 * |
0 | 4 * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. |
5 * License: MIT | |
6 * Authors: Thomas Dixon | |
7 */ | |
8 | |
9 module dcrypt.crypto.ciphers.RC6; | |
10 | |
11 import dcrypt.misc.Util; | |
12 import dcrypt.crypto.BlockCipher; | |
13 | |
14 /** | |
15 * Implementation of the RC6-32/20/b cipher designed by | |
16 * Ron Rivest et al. of RSA Security. | |
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
|
17 * |
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
|
18 * It should be noted that this algorithm is very similar to RC5. |
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
|
19 * Currently there are no plans to implement RC5, but should that change |
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
|
20 * in the future, it may be wise to rewrite both RC5 and RC6 to use some |
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
|
21 * kind of template or base class. |
0 | 22 * |
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
|
23 * This algorithm is patented and trademarked. |
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
|
24 * |
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
|
25 * References: http://people.csail.mit.edu/rivest/Rc6.pdf |
0 | 26 */ |
27 class RC6 : 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
|
28 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
|
29 const uint ROUNDS = 20, |
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
|
30 BLOCK_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
|
31 // Magic constants for a 32 bit word size |
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
|
32 P = 0xb7e15163, |
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
|
33 Q = 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
|
34 uint[] S; |
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
|
35 ubyte[] workingKey; |
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
|
36 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
|
37 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
|
38 } |
0 | 39 |
40 char[] name() { | |
41 return "RC6"; | |
42 } | |
43 | |
44 uint blockSize() { | |
45 return BLOCK_SIZE; | |
46 } | |
47 | |
48 void init(bool encrypt, CipherParameters params) { | |
49 SymmetricKey keyParams = cast(SymmetricKey)params; | |
50 if (!keyParams) | |
51 throw new InvalidParameterError( | |
52 name()~": Invalid parameter passed to init"); | |
53 this.encrypt = encrypt; | |
54 | |
55 uint len = keyParams.key.length; | |
56 if (len != 16 && len != 24 && len != 32) | |
57 throw new InvalidKeyError( | |
58 name()~": Invalid key length (requires 16/24/32 bytes)"); | |
59 | |
60 S = new uint[2*ROUNDS+4]; | |
61 | |
62 workingKey = keyParams.key; | |
63 setup(workingKey); | |
64 | |
65 initialized = true; | |
66 } | |
67 | |
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
|
68 ubyte[] process(void[] input_) { |
0 | 69 if (!initialized) |
70 throw new NotInitializedError(name()~": Cipher not initialized"); | |
71 | |
72 ubyte[] input = cast(ubyte[]) input_; | |
73 | |
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
|
74 if (input.length > blockSize) |
0 | 75 throw new ShortBufferError(name()~": Input buffer too short"); |
76 | |
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
|
77 uint A = Util.ubytesToUintLittle(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
|
78 B = Util.ubytesToUintLittle(input, 4), |
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
|
79 C = Util.ubytesToUintLittle(input, 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 D = Util.ubytesToUintLittle(input, 12), |
0 | 81 t, |
82 u; | |
83 | |
84 if (encrypt) { | |
85 B += S[0]; | |
86 D += S[1]; | |
87 for (int i = 1; i <= ROUNDS; i++) { | |
88 t = Util.rotateLeft(B*((B<<1)+1), 5); | |
89 u = Util.rotateLeft(D*((D<<1)+1), 5); | |
90 A = Util.rotateLeft(A^t, u) + S[i<<1]; | |
91 C = Util.rotateLeft(C^u, t) + S[(i<<1)+1]; | |
92 t = A; | |
93 A = B; | |
94 B = C; | |
95 C = D; | |
96 D = t; | |
97 } | |
98 A += S[2*ROUNDS+2]; | |
99 C += S[2*ROUNDS+3]; | |
100 } else { | |
101 C -= S[2*ROUNDS+3]; | |
102 A -= S[2*ROUNDS+2]; | |
103 for (int i = ROUNDS; i >= 1; i--) { | |
104 t = D; | |
105 D = C; | |
106 C = B; | |
107 B = A; | |
108 A = t; | |
109 u = Util.rotateLeft(D*((D<<1)+1), 5); | |
110 t = Util.rotateLeft(B*((B<<1)+1), 5); | |
111 C = Util.rotateRight(C-S[(i<<1)+1], t) ^ u; | |
112 A = Util.rotateRight(A-S[i<<1], u) ^ t; | |
113 } | |
114 D -= S[1]; | |
115 B -= S[0]; | |
116 } | |
117 | |
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
|
118 ubyte[] output = new ubyte[blockSize]; |
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
|
119 Util.uintToUbytesLittle(A, 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
|
120 Util.uintToUbytesLittle(B, output, 4); |
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
|
121 Util.uintToUbytesLittle(C, output, 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
|
122 Util.uintToUbytesLittle(D, output, 12); |
0 | 123 |
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
|
124 return output; |
0 | 125 } |
126 | |
127 void reset() { | |
128 setup(workingKey); | |
129 } | |
130 | |
131 void setup(ubyte[] key) { | |
132 uint c = key.length/4; | |
133 uint[] L = new uint[c]; | |
134 for (int i = 0, j = 0; i < c; i++, j+=4) | |
135 L[i] = Util.ubytesToUintLittle(key, j); | |
136 S[0] = P; | |
137 for (int i = 1; i <= 2*ROUNDS+3; i++) | |
138 S[i] = S[i-1] + Q; | |
139 uint A, B, i, j, v = 3*(2*ROUNDS+4); // Relying on ints initializing to 0 | |
140 for (int s = 1; s <= v; s++) { | |
141 A = S[i] = Util.rotateLeft(S[i]+A+B, 3); | |
142 B = L[j] = Util.rotateLeft(L[j]+A+B, A+B); | |
143 i = (i + 1) % (2*ROUNDS+4); | |
144 j = (j + 1) % c; | |
145 } | |
146 } | |
147 | |
148 /** Some RC6 test vectors from the spec. */ | |
149 version (UnitTest) { | |
150 unittest { | |
151 static const char[][] test_keys = [ | |
152 "00000000000000000000000000000000", | |
153 | |
154 "0123456789abcdef0112233445566778", | |
155 | |
156 "00000000000000000000000000000000"~ | |
157 "0000000000000000", | |
158 | |
159 "0123456789abcdef0112233445566778"~ | |
160 "899aabbccddeeff0", | |
161 | |
162 "00000000000000000000000000000000"~ | |
163 "00000000000000000000000000000000", | |
164 | |
165 "0123456789abcdef0112233445566778"~ | |
166 "899aabbccddeeff01032547698badcfe" | |
167 ]; | |
168 | |
169 static const char[][] test_plaintexts = [ | |
170 "00000000000000000000000000000000", | |
171 "02132435465768798a9bacbdcedfe0f1", | |
172 "00000000000000000000000000000000", | |
173 "02132435465768798a9bacbdcedfe0f1", | |
174 "00000000000000000000000000000000", | |
175 "02132435465768798a9bacbdcedfe0f1" | |
176 ]; | |
177 | |
178 static const char[][] test_ciphertexts = [ | |
179 "8fc3a53656b1f778c129df4e9848a41e", | |
180 "524e192f4715c6231f51f6367ea43f18", | |
181 "6cd61bcb190b30384e8a3f168690ae82", | |
182 "688329d019e505041e52e92af95291d4", | |
183 "8f5fbd0510d15fa893fa3fda6e857ec2", | |
184 "c8241816f0d7e48920ad16a1674e5d48" | |
185 ]; | |
186 | |
187 RC6 t = new RC6(); | |
188 foreach (uint i, char[] test_key; test_keys) { | |
189 ubyte[] buffer = new ubyte[t.blockSize]; | |
190 char[] result; | |
191 SymmetricKey key = new SymmetricKey(Util.hexToUbytes(test_key)); | |
192 | |
193 // Encryption | |
194 t.init(true, key); | |
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
|
195 buffer = t.process(Util.hexToUbytes(test_plaintexts[i])); |
0 | 196 result = Util.ubytesToHex(buffer); |
197 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
|
198 t.name~": ("~result~") != ("~test_ciphertexts[i]~")"); |
0 | 199 |
200 // Decryption | |
201 t.init(false, key); | |
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
|
202 buffer = t.process(Util.hexToUbytes(test_ciphertexts[i])); |
0 | 203 result = Util.ubytesToHex(buffer); |
204 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
|
205 t.name~": ("~result~") != ("~test_plaintexts[i]~")"); |
0 | 206 } |
207 } | |
208 } | |
209 } |