comparison dcrypt/crypto/ciphers/RC6.d @ 27:8b5eaf3c2979

Fixed error in hash message padding reported by Glenn Haecker.
author Thomas Dixon <reikon@reikon.us>
date Sat, 09 May 2009 23:29:20 -0400
parents 176c933827a8
children ad687db713a4
comparison
equal deleted inserted replaced
26:176c933827a8 27:8b5eaf3c2979
23 * 23 *
24 * This algorithm is patented and trademarked. 24 * This algorithm is patented and trademarked.
25 * 25 *
26 * References: http://people.csail.mit.edu/rivest/Rc6.pdf 26 * References: http://people.csail.mit.edu/rivest/Rc6.pdf
27 */ 27 */
28 class RC6 : BlockCipher { 28 class RC6 : BlockCipher
29 private { 29 {
30 private
31 {
30 const uint ROUNDS = 20, 32 const uint ROUNDS = 20,
31 BLOCK_SIZE = 16, 33 BLOCK_SIZE = 16,
32 // Magic constants for a 32 bit word size 34 // Magic constants for a 32 bit word size
33 P = 0xb7e15163, 35 P = 0xb7e15163,
34 Q = 0x9e3779b9; 36 Q = 0x9e3779b9;
35 uint[] S; 37 uint[] S;
36 ubyte[] workingKey; 38 ubyte[] workingKey;
37 } 39 }
38 40
39 char[] name() { 41 char[] name()
42 {
40 return "RC6"; 43 return "RC6";
41 } 44 }
42 45
43 uint blockSize() { 46 uint blockSize()
47 {
44 return BLOCK_SIZE; 48 return BLOCK_SIZE;
45 } 49 }
46 50
47 void init(bool encrypt, CipherParameters params) { 51 void init(bool encrypt, CipherParameters params)
52 {
48 SymmetricKey keyParams = cast(SymmetricKey)params; 53 SymmetricKey keyParams = cast(SymmetricKey)params;
49 if (!keyParams) 54 if (!keyParams)
50 throw new InvalidParameterError( 55 throw new InvalidParameterError(
51 name()~": Invalid parameter passed to init"); 56 name()~": Invalid parameter passed to init");
57
52 _encrypt = encrypt; 58 _encrypt = encrypt;
53 59
54 uint len = keyParams.key.length; 60 uint len = keyParams.key.length;
55 if (len != 16 && len != 24 && len != 32) 61 if (len != 16 && len != 24 && len != 32)
56 throw new InvalidKeyError( 62 throw new InvalidKeyError(
82 C = ByteConverter.LittleEndian.to!(uint)(input[8..12]), 88 C = ByteConverter.LittleEndian.to!(uint)(input[8..12]),
83 D = ByteConverter.LittleEndian.to!(uint)(input[12..16]), 89 D = ByteConverter.LittleEndian.to!(uint)(input[12..16]),
84 t, 90 t,
85 u; 91 u;
86 92
87 if (_encrypt) { 93 if (_encrypt)
94 {
88 B += S[0]; 95 B += S[0];
89 D += S[1]; 96 D += S[1];
90 for (int i = 1; i <= ROUNDS; i++) { 97
98 for (int i = 1; i <= ROUNDS; i++)
99 {
91 t = Bitwise.rotateLeft(B*((B<<1)+1), 5); 100 t = Bitwise.rotateLeft(B*((B<<1)+1), 5);
92 u = Bitwise.rotateLeft(D*((D<<1)+1), 5); 101 u = Bitwise.rotateLeft(D*((D<<1)+1), 5);
93 A = Bitwise.rotateLeft(A^t, u) + S[i<<1]; 102 A = Bitwise.rotateLeft(A^t, u) + S[i<<1];
94 C = Bitwise.rotateLeft(C^u, t) + S[(i<<1)+1]; 103 C = Bitwise.rotateLeft(C^u, t) + S[(i<<1)+1];
95 t = A; 104 t = A;
96 A = B; 105 A = B;
97 B = C; 106 B = C;
98 C = D; 107 C = D;
99 D = t; 108 D = t;
100 } 109 }
110
101 A += S[2*ROUNDS+2]; 111 A += S[2*ROUNDS+2];
102 C += S[2*ROUNDS+3]; 112 C += S[2*ROUNDS+3];
103 } else { 113 }
114 else
115 {
104 C -= S[2*ROUNDS+3]; 116 C -= S[2*ROUNDS+3];
105 A -= S[2*ROUNDS+2]; 117 A -= S[2*ROUNDS+2];
106 for (int i = ROUNDS; i >= 1; i--) { 118
119 for (int i = ROUNDS; i >= 1; i--)
120 {
107 t = D; 121 t = D;
108 D = C; 122 D = C;
109 C = B; 123 C = B;
110 B = A; 124 B = A;
111 A = t; 125 A = t;
112 u = Bitwise.rotateLeft(D*((D<<1)+1), 5); 126 u = Bitwise.rotateLeft(D*((D<<1)+1), 5);
113 t = Bitwise.rotateLeft(B*((B<<1)+1), 5); 127 t = Bitwise.rotateLeft(B*((B<<1)+1), 5);
114 C = Bitwise.rotateRight(C-S[(i<<1)+1], t) ^ u; 128 C = Bitwise.rotateRight(C-S[(i<<1)+1], t) ^ u;
115 A = Bitwise.rotateRight(A-S[i<<1], u) ^ t; 129 A = Bitwise.rotateRight(A-S[i<<1], u) ^ t;
116 } 130 }
131
117 D -= S[1]; 132 D -= S[1];
118 B -= S[0]; 133 B -= S[0];
119 } 134 }
120 135
121 output[0..4] = ByteConverter.LittleEndian.from!(uint)(A); 136 output[0..4] = ByteConverter.LittleEndian.from!(uint)(A);
124 output[12..16] = ByteConverter.LittleEndian.from!(uint)(D); 139 output[12..16] = ByteConverter.LittleEndian.from!(uint)(D);
125 140
126 return BLOCK_SIZE; 141 return BLOCK_SIZE;
127 } 142 }
128 143
129 void reset() { 144 void reset()
145 {
130 setup(workingKey); 146 setup(workingKey);
131 } 147 }
132 148
133 void setup(ubyte[] key) { 149 void setup(ubyte[] key)
150 {
134 uint c = key.length/4; 151 uint c = key.length/4;
135 uint[] L = new uint[c]; 152 uint[] L = new uint[c];
136 for (int i = 0, j = 0; i < c; i++, j+=4) 153 for (int i = 0, j = 0; i < c; i++, j+=4)
137 L[i] = ByteConverter.LittleEndian.to!(uint)(key[j..j+int.sizeof]); 154 L[i] = ByteConverter.LittleEndian.to!(uint)(key[j..j+int.sizeof]);
138 155
139 S[0] = P; 156 S[0] = P;
140 for (int i = 1; i <= 2*ROUNDS+3; i++) 157 for (int i = 1; i <= 2*ROUNDS+3; i++)
141 S[i] = S[i-1] + Q; 158 S[i] = S[i-1] + Q;
142 159
143 uint A, B, i, j, v = 3*(2*ROUNDS+4); // Relying on ints initializing to 0 160 uint A, B, i, j, v = 3*(2*ROUNDS+4); // Relying on ints initializing to 0
144 for (int s = 1; s <= v; s++) { 161 for (int s = 1; s <= v; s++)
162 {
145 A = S[i] = Bitwise.rotateLeft(S[i]+A+B, 3); 163 A = S[i] = Bitwise.rotateLeft(S[i]+A+B, 3);
146 B = L[j] = Bitwise.rotateLeft(L[j]+A+B, A+B); 164 B = L[j] = Bitwise.rotateLeft(L[j]+A+B, A+B);
147 i = (i + 1) % (2*ROUNDS+4); 165 i = (i + 1) % (2*ROUNDS+4);
148 j = (j + 1) % c; 166 j = (j + 1) % c;
149 } 167 }
150 } 168 }
151 169
152 /** Some RC6 test vectors from the spec. */ 170 /** Some RC6 test vectors from the spec. */
153 debug (UnitTest) { 171 debug (UnitTest)
154 unittest { 172 {
173 unittest
174 {
155 static const char[][] test_keys = [ 175 static const char[][] test_keys = [
156 "00000000000000000000000000000000", 176 "00000000000000000000000000000000",
157 "0123456789abcdef0112233445566778", 177 "0123456789abcdef0112233445566778",
158 "00000000000000000000000000000000"~ 178 "00000000000000000000000000000000"~
159 "0000000000000000", 179 "0000000000000000",
182 "8f5fbd0510d15fa893fa3fda6e857ec2", 202 "8f5fbd0510d15fa893fa3fda6e857ec2",
183 "c8241816f0d7e48920ad16a1674e5d48" 203 "c8241816f0d7e48920ad16a1674e5d48"
184 ]; 204 ];
185 205
186 RC6 t = new RC6(); 206 RC6 t = new RC6();
187 foreach (uint i, char[] test_key; test_keys) { 207 foreach (uint i, char[] test_key; test_keys)
208 {
188 ubyte[] buffer = new ubyte[t.blockSize]; 209 ubyte[] buffer = new ubyte[t.blockSize];
189 char[] result; 210 char[] result;
190 SymmetricKey key = new SymmetricKey(ByteConverter.hexDecode(test_key)); 211 SymmetricKey key = new SymmetricKey(ByteConverter.hexDecode(test_key));
191 212
192 // Encryption 213 // Encryption