Mercurial > projects > dcrypt
annotate dcrypt/crypto/ciphers/RC6.d @ 6:5cb17e09d685
Minor edits to the unittests of hash functions and ciphers. Added AES and test vectors.
author | Thomas Dixon <reikon@reikon.us> |
---|---|
date | Sat, 16 Aug 2008 22:43:22 -0400 |
parents | 71aae178f89a |
children | 23c62e28b3a4 |
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 | |
68 uint processBlock(void[] input_, uint inOff, void[] output_, uint outOff) { | |
69 if (!initialized) | |
70 throw new NotInitializedError(name()~": Cipher not initialized"); | |
71 | |
72 ubyte[] input = cast(ubyte[]) input_; | |
73 ubyte[] output = cast(ubyte[]) output_; | |
74 | |
75 if ((inOff + BLOCK_SIZE) > input.length) | |
76 throw new ShortBufferError(name()~": Input buffer too short"); | |
77 | |
78 if ((outOff + BLOCK_SIZE) > output.length) | |
79 throw new ShortBufferError(name()~": Output buffer too short"); | |
80 | |
81 uint A = Util.ubytesToUintLittle(input, inOff), | |
82 B = Util.ubytesToUintLittle(input, inOff+4), | |
83 C = Util.ubytesToUintLittle(input, inOff+8), | |
84 D = Util.ubytesToUintLittle(input, inOff+12), | |
85 t, | |
86 u; | |
87 | |
88 if (encrypt) { | |
89 B += S[0]; | |
90 D += S[1]; | |
91 for (int i = 1; i <= ROUNDS; i++) { | |
92 t = Util.rotateLeft(B*((B<<1)+1), 5); | |
93 u = Util.rotateLeft(D*((D<<1)+1), 5); | |
94 A = Util.rotateLeft(A^t, u) + S[i<<1]; | |
95 C = Util.rotateLeft(C^u, t) + S[(i<<1)+1]; | |
96 t = A; | |
97 A = B; | |
98 B = C; | |
99 C = D; | |
100 D = t; | |
101 } | |
102 A += S[2*ROUNDS+2]; | |
103 C += S[2*ROUNDS+3]; | |
104 } else { | |
105 C -= S[2*ROUNDS+3]; | |
106 A -= S[2*ROUNDS+2]; | |
107 for (int i = ROUNDS; i >= 1; i--) { | |
108 t = D; | |
109 D = C; | |
110 C = B; | |
111 B = A; | |
112 A = t; | |
113 u = Util.rotateLeft(D*((D<<1)+1), 5); | |
114 t = Util.rotateLeft(B*((B<<1)+1), 5); | |
115 C = Util.rotateRight(C-S[(i<<1)+1], t) ^ u; | |
116 A = Util.rotateRight(A-S[i<<1], u) ^ t; | |
117 } | |
118 D -= S[1]; | |
119 B -= S[0]; | |
120 } | |
121 | |
122 Util.uintToUbytesLittle(A, output, outOff); | |
123 Util.uintToUbytesLittle(B, output, outOff+4); | |
124 Util.uintToUbytesLittle(C, output, outOff+8); | |
125 Util.uintToUbytesLittle(D, output, outOff+12); | |
126 | |
127 return BLOCK_SIZE; | |
128 } | |
129 | |
130 void reset() { | |
131 setup(workingKey); | |
132 } | |
133 | |
134 void setup(ubyte[] key) { | |
135 uint c = key.length/4; | |
136 uint[] L = new uint[c]; | |
137 for (int i = 0, j = 0; i < c; i++, j+=4) | |
138 L[i] = Util.ubytesToUintLittle(key, j); | |
139 S[0] = P; | |
140 for (int i = 1; i <= 2*ROUNDS+3; i++) | |
141 S[i] = S[i-1] + Q; | |
142 uint A, B, i, j, v = 3*(2*ROUNDS+4); // Relying on ints initializing to 0 | |
143 for (int s = 1; s <= v; s++) { | |
144 A = S[i] = Util.rotateLeft(S[i]+A+B, 3); | |
145 B = L[j] = Util.rotateLeft(L[j]+A+B, A+B); | |
146 i = (i + 1) % (2*ROUNDS+4); | |
147 j = (j + 1) % c; | |
148 } | |
149 } | |
150 | |
151 /** Some RC6 test vectors from the spec. */ | |
152 version (UnitTest) { | |
153 unittest { | |
154 static const char[][] test_keys = [ | |
155 "00000000000000000000000000000000", | |
156 | |
157 "0123456789abcdef0112233445566778", | |
158 | |
159 "00000000000000000000000000000000"~ | |
160 "0000000000000000", | |
161 | |
162 "0123456789abcdef0112233445566778"~ | |
163 "899aabbccddeeff0", | |
164 | |
165 "00000000000000000000000000000000"~ | |
166 "00000000000000000000000000000000", | |
167 | |
168 "0123456789abcdef0112233445566778"~ | |
169 "899aabbccddeeff01032547698badcfe" | |
170 ]; | |
171 | |
172 static const char[][] test_plaintexts = [ | |
173 "00000000000000000000000000000000", | |
174 "02132435465768798a9bacbdcedfe0f1", | |
175 "00000000000000000000000000000000", | |
176 "02132435465768798a9bacbdcedfe0f1", | |
177 "00000000000000000000000000000000", | |
178 "02132435465768798a9bacbdcedfe0f1" | |
179 ]; | |
180 | |
181 static const char[][] test_ciphertexts = [ | |
182 "8fc3a53656b1f778c129df4e9848a41e", | |
183 "524e192f4715c6231f51f6367ea43f18", | |
184 "6cd61bcb190b30384e8a3f168690ae82", | |
185 "688329d019e505041e52e92af95291d4", | |
186 "8f5fbd0510d15fa893fa3fda6e857ec2", | |
187 "c8241816f0d7e48920ad16a1674e5d48" | |
188 ]; | |
189 | |
190 RC6 t = new RC6(); | |
191 foreach (uint i, char[] test_key; test_keys) { | |
192 ubyte[] buffer = new ubyte[t.blockSize]; | |
193 char[] result; | |
194 SymmetricKey key = new SymmetricKey(Util.hexToUbytes(test_key)); | |
195 | |
196 // Encryption | |
197 t.init(true, key); | |
198 t.processBlock(Util.hexToUbytes(test_plaintexts[i]), 0, buffer, 0); | |
199 result = Util.ubytesToHex(buffer); | |
200 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
|
201 t.name~": ("~result~") != ("~test_ciphertexts[i]~")"); |
0 | 202 |
203 // Decryption | |
204 t.init(false, key); | |
205 t.processBlock(Util.hexToUbytes(test_ciphertexts[i]), 0, buffer, 0); | |
206 result = Util.ubytesToHex(buffer); | |
207 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
|
208 t.name~": ("~result~") != ("~test_plaintexts[i]~")"); |
0 | 209 } |
210 } | |
211 } | |
212 } |