Mercurial > projects > dcrypt
annotate dcrypt/crypto/ciphers/RC6.d @ 14:5ce3012f1def
Removed some redundancy in code. Added NotSupportedError, a base PRNG class and a class which creates a PRNG from a hash function. Changed the MAC class' finalization methods to digest and hexDigest instead of finish and hexFinish respectively. Also added a base Checksum class, crc32 and adler32 in dcrypt.misc as per request.
author | Thomas Dixon <reikon@reikon.us> |
---|---|
date | Tue, 18 Nov 2008 18:03:40 -0500 |
parents | 8c7f8fecdd75 |
children | ec23779ee794 |
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 } |
0 | 37 |
38 char[] name() { | |
39 return "RC6"; | |
40 } | |
41 | |
42 uint blockSize() { | |
43 return BLOCK_SIZE; | |
44 } | |
45 | |
46 void init(bool encrypt, CipherParameters params) { | |
47 SymmetricKey keyParams = cast(SymmetricKey)params; | |
48 if (!keyParams) | |
49 throw new InvalidParameterError( | |
50 name()~": Invalid parameter passed to init"); | |
14
5ce3012f1def
Removed some redundancy in code. Added NotSupportedError, a base PRNG class and a class which creates a PRNG from a hash function. Changed the MAC class' finalization methods to digest and hexDigest instead of finish and hexFinish respectively. Also added a base Checksum class, crc32 and adler32 in dcrypt.misc as per request.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
51 _encrypt = encrypt; |
0 | 52 |
53 uint len = keyParams.key.length; | |
54 if (len != 16 && len != 24 && len != 32) | |
55 throw new InvalidKeyError( | |
56 name()~": Invalid key length (requires 16/24/32 bytes)"); | |
57 | |
58 S = new uint[2*ROUNDS+4]; | |
59 | |
60 workingKey = keyParams.key; | |
61 setup(workingKey); | |
62 | |
14
5ce3012f1def
Removed some redundancy in code. Added NotSupportedError, a base PRNG class and a class which creates a PRNG from a hash function. Changed the MAC class' finalization methods to digest and hexDigest instead of finish and hexFinish respectively. Also added a base Checksum class, crc32 and adler32 in dcrypt.misc as per request.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
63 _initialized = true; |
0 | 64 } |
65 | |
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
|
66 uint update(void[] input_, void[] output_) { |
14
5ce3012f1def
Removed some redundancy in code. Added NotSupportedError, a base PRNG class and a class which creates a PRNG from a hash function. Changed the MAC class' finalization methods to digest and hexDigest instead of finish and hexFinish respectively. Also added a base Checksum class, crc32 and adler32 in dcrypt.misc as per request.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
67 if (!_initialized) |
0 | 68 throw new NotInitializedError(name()~": Cipher not initialized"); |
69 | |
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
|
70 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
|
71 output = cast(ubyte[]) output_; |
0 | 72 |
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
|
73 if (input.length < BLOCK_SIZE) |
0 | 74 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
|
75 |
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 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
|
77 throw new ShortBufferError(name()~": Output buffer too short"); |
0 | 78 |
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
|
79 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
|
80 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
|
81 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
|
82 D = Util.ubytesToUintLittle(input, 12), |
0 | 83 t, |
84 u; | |
85 | |
14
5ce3012f1def
Removed some redundancy in code. Added NotSupportedError, a base PRNG class and a class which creates a PRNG from a hash function. Changed the MAC class' finalization methods to digest and hexDigest instead of finish and hexFinish respectively. Also added a base Checksum class, crc32 and adler32 in dcrypt.misc as per request.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
86 if (_encrypt) { |
0 | 87 B += S[0]; |
88 D += S[1]; | |
89 for (int i = 1; i <= ROUNDS; i++) { | |
90 t = Util.rotateLeft(B*((B<<1)+1), 5); | |
91 u = Util.rotateLeft(D*((D<<1)+1), 5); | |
92 A = Util.rotateLeft(A^t, u) + S[i<<1]; | |
93 C = Util.rotateLeft(C^u, t) + S[(i<<1)+1]; | |
94 t = A; | |
95 A = B; | |
96 B = C; | |
97 C = D; | |
98 D = t; | |
99 } | |
100 A += S[2*ROUNDS+2]; | |
101 C += S[2*ROUNDS+3]; | |
102 } else { | |
103 C -= S[2*ROUNDS+3]; | |
104 A -= S[2*ROUNDS+2]; | |
105 for (int i = ROUNDS; i >= 1; i--) { | |
106 t = D; | |
107 D = C; | |
108 C = B; | |
109 B = A; | |
110 A = t; | |
111 u = Util.rotateLeft(D*((D<<1)+1), 5); | |
112 t = Util.rotateLeft(B*((B<<1)+1), 5); | |
113 C = Util.rotateRight(C-S[(i<<1)+1], t) ^ u; | |
114 A = Util.rotateRight(A-S[i<<1], u) ^ t; | |
115 } | |
116 D -= S[1]; | |
117 B -= S[0]; | |
118 } | |
119 | |
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
|
120 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
|
121 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
|
122 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
|
123 Util.uintToUbytesLittle(D, output, 12); |
0 | 124 |
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
|
125 return BLOCK_SIZE; |
0 | 126 } |
127 | |
128 void reset() { | |
129 setup(workingKey); | |
130 } | |
131 | |
132 void setup(ubyte[] key) { | |
133 uint c = key.length/4; | |
134 uint[] L = new uint[c]; | |
135 for (int i = 0, j = 0; i < c; i++, j+=4) | |
136 L[i] = Util.ubytesToUintLittle(key, j); | |
137 S[0] = P; | |
138 for (int i = 1; i <= 2*ROUNDS+3; i++) | |
139 S[i] = S[i-1] + Q; | |
140 uint A, B, i, j, v = 3*(2*ROUNDS+4); // Relying on ints initializing to 0 | |
141 for (int s = 1; s <= v; s++) { | |
142 A = S[i] = Util.rotateLeft(S[i]+A+B, 3); | |
143 B = L[j] = Util.rotateLeft(L[j]+A+B, A+B); | |
144 i = (i + 1) % (2*ROUNDS+4); | |
145 j = (j + 1) % c; | |
146 } | |
147 } | |
148 | |
149 /** Some RC6 test vectors from the spec. */ | |
150 version (UnitTest) { | |
151 unittest { | |
152 static const char[][] test_keys = [ | |
153 "00000000000000000000000000000000", | |
154 | |
155 "0123456789abcdef0112233445566778", | |
156 | |
157 "00000000000000000000000000000000"~ | |
158 "0000000000000000", | |
159 | |
160 "0123456789abcdef0112233445566778"~ | |
161 "899aabbccddeeff0", | |
162 | |
163 "00000000000000000000000000000000"~ | |
164 "00000000000000000000000000000000", | |
165 | |
166 "0123456789abcdef0112233445566778"~ | |
167 "899aabbccddeeff01032547698badcfe" | |
168 ]; | |
169 | |
170 static const char[][] test_plaintexts = [ | |
171 "00000000000000000000000000000000", | |
172 "02132435465768798a9bacbdcedfe0f1", | |
173 "00000000000000000000000000000000", | |
174 "02132435465768798a9bacbdcedfe0f1", | |
175 "00000000000000000000000000000000", | |
176 "02132435465768798a9bacbdcedfe0f1" | |
177 ]; | |
178 | |
179 static const char[][] test_ciphertexts = [ | |
180 "8fc3a53656b1f778c129df4e9848a41e", | |
181 "524e192f4715c6231f51f6367ea43f18", | |
182 "6cd61bcb190b30384e8a3f168690ae82", | |
183 "688329d019e505041e52e92af95291d4", | |
184 "8f5fbd0510d15fa893fa3fda6e857ec2", | |
185 "c8241816f0d7e48920ad16a1674e5d48" | |
186 ]; | |
187 | |
188 RC6 t = new RC6(); | |
189 foreach (uint i, char[] test_key; test_keys) { | |
190 ubyte[] buffer = new ubyte[t.blockSize]; | |
191 char[] result; | |
192 SymmetricKey key = new SymmetricKey(Util.hexToUbytes(test_key)); | |
193 | |
194 // Encryption | |
195 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
|
196 t.update(Util.hexToUbytes(test_plaintexts[i]), buffer); |
0 | 197 result = Util.ubytesToHex(buffer); |
198 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
|
199 t.name~": ("~result~") != ("~test_ciphertexts[i]~")"); |
0 | 200 |
201 // Decryption | |
202 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
|
203 t.update(Util.hexToUbytes(test_ciphertexts[i]), buffer); |
0 | 204 result = Util.ubytesToHex(buffer); |
205 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
|
206 t.name~": ("~result~") != ("~test_plaintexts[i]~")"); |
0 | 207 } |
208 } | |
209 } | |
210 } |