comparison dcrypt/crypto/ciphers/Blowfish.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
13 import dcrypt.misc.ByteConverter; 13 import dcrypt.misc.ByteConverter;
14 import dcrypt.misc.Bitwise; 14 import dcrypt.misc.Bitwise;
15 import dcrypt.crypto.BlockCipher; 15 import dcrypt.crypto.BlockCipher;
16 16
17 /** Implementation of the Blowfish cipher designed by Bruce Schneier. */ 17 /** Implementation of the Blowfish cipher designed by Bruce Schneier. */
18 class Blowfish : BlockCipher { 18 class Blowfish : BlockCipher
19 private { 19 {
20 private
21 {
20 static const uint[1024] S_INIT = [ 22 static const uint[1024] S_INIT = [
21 0xd1310ba6u, 0x98dfb5acu, 0x2ffd72dbu, 0xd01adfb7u, 0xb8e1afedu, 0x6a267e96u, 23 0xd1310ba6u, 0x98dfb5acu, 0x2ffd72dbu, 0xd01adfb7u, 0xb8e1afedu, 0x6a267e96u,
22 0xba7c9045u, 0xf12c7f99u, 0x24a19947u, 0xb3916cf7u, 0x0801f2e2u, 0x858efc16u, 24 0xba7c9045u, 0xf12c7f99u, 0x24a19947u, 0xb3916cf7u, 0x0801f2e2u, 0x858efc16u,
23 0x636920d8u, 0x71574e69u, 0xa458fea3u, 0xf4933d7eu, 0x0d95748fu, 0x728eb658u, 25 0x636920d8u, 0x71574e69u, 0xa458fea3u, 0xf4933d7eu, 0x0d95748fu, 0x728eb658u,
24 0x718bcd58u, 0x82154aeeu, 0x7b54a41du, 0xc25a59b5u, 0x9c30d539u, 0x2af26013u, 26 0x718bcd58u, 0x82154aeeu, 0x7b54a41du, 0xc25a59b5u, 0x9c30d539u, 0x2af26013u,
210 uint[18] P; 212 uint[18] P;
211 uint[256] S0, S1, S2, S3; 213 uint[256] S0, S1, S2, S3;
212 ubyte[] workingKey; 214 ubyte[] workingKey;
213 } // end private 215 } // end private
214 216
215 char[] name() { 217 char[] name()
218 {
216 return "Blowfish"; 219 return "Blowfish";
217 } 220 }
218 221
219 uint blockSize() { 222 uint blockSize()
223 {
220 return BLOCK_SIZE; 224 return BLOCK_SIZE;
221 } 225 }
222 226
223 void init(bool encrypt, CipherParameters params) { 227 void init(bool encrypt, CipherParameters params)
228 {
224 SymmetricKey keyParams = cast(SymmetricKey)params; 229 SymmetricKey keyParams = cast(SymmetricKey)params;
225 if (!keyParams) 230 if (!keyParams)
226 throw new InvalidParameterError( 231 throw new InvalidParameterError(
227 name()~": Invalid parameter passed to init"); 232 name()~": Invalid parameter passed to init");
233
228 _encrypt = encrypt; 234 _encrypt = encrypt;
229 235
230 uint len = keyParams.key.length; 236 uint len = keyParams.key.length;
231 if (len < MIN_KEY_SIZE || len > MAX_KEY_SIZE) 237 if (len < MIN_KEY_SIZE || len > MAX_KEY_SIZE)
232 throw new InvalidKeyError( 238 throw new InvalidKeyError(
241 247
242 if (!_encrypt) 248 if (!_encrypt)
243 P.reverse; // Oh yes I did. 249 P.reverse; // Oh yes I did.
244 } 250 }
245 251
246 private uint F(uint x) { 252 private uint F(uint x)
253 {
247 return (((S0[(x >> 24)] 254 return (((S0[(x >> 24)]
248 + S1[cast(ubyte)(x >> 16)]) 255 + S1[cast(ubyte)(x >> 16)])
249 ^ S2[cast(ubyte)(x >> 8)]) 256 ^ S2[cast(ubyte)(x >> 8)])
250 + S3[cast(ubyte)x]); 257 + S3[cast(ubyte)x]);
251 } 258 }
252 259
253 uint update(void[] input_, void[] output_) { 260 uint update(void[] input_, void[] output_)
261 {
254 if (!_initialized) 262 if (!_initialized)
255 throw new NotInitializedError(name()~": Cipher not initialized."); 263 throw new NotInitializedError(name()~": Cipher not initialized.");
256 264
257 ubyte[] input = cast(ubyte[]) input_, 265 ubyte[] input = cast(ubyte[]) input_,
258 output = cast(ubyte[]) output_; 266 output = cast(ubyte[]) output_;
266 uint xl = ByteConverter.BigEndian.to!(uint)(input[0..4]), 274 uint xl = ByteConverter.BigEndian.to!(uint)(input[0..4]),
267 xr = ByteConverter.BigEndian.to!(uint)(input[4..8]), 275 xr = ByteConverter.BigEndian.to!(uint)(input[4..8]),
268 i = 0; 276 i = 0;
269 277
270 xl ^= P[i++]; 278 xl ^= P[i++];
271 for (; i < ROUNDS;) { 279 for (; i < ROUNDS;)
280 {
272 xr ^= F(xl) ^ P[i++]; 281 xr ^= F(xl) ^ P[i++];
273 xl ^= F(xr) ^ P[i++]; 282 xl ^= F(xr) ^ P[i++];
274 } 283 }
275 xr ^= P[i]; 284 xr ^= P[i];
276 285
278 output[4..8] = ByteConverter.BigEndian.from!(uint)(xl); 287 output[4..8] = ByteConverter.BigEndian.from!(uint)(xl);
279 288
280 return BLOCK_SIZE; 289 return BLOCK_SIZE;
281 } 290 }
282 291
283 void reset() { 292 void reset()
293 {
284 setup(workingKey); 294 setup(workingKey);
285 } 295 }
286 296
287 private void setup(ubyte[] key) { 297 private void setup(ubyte[] key)
298 {
288 S0[] = S_INIT[0..256]; 299 S0[] = S_INIT[0..256];
289 S1[] = S_INIT[256..512]; 300 S1[] = S_INIT[256..512];
290 S2[] = S_INIT[512..768]; 301 S2[] = S_INIT[512..768];
291 S3[] = S_INIT[768..1024]; 302 S3[] = S_INIT[768..1024];
292 P[] = P_INIT[]; 303 P[] = P_INIT[];
293 304
294 uint index = 0; 305 uint index = 0;
295 306
296 for (int i = 0; i < PBOX_SIZE; i++) { 307 for (int i = 0; i < PBOX_SIZE; i++)
308 {
297 uint x = 0; 309 uint x = 0;
298 for (int j = 0; j < 4; j++) { 310 for (int j = 0; j < 4; j++)
311 {
299 x = (x << 8) | key[index++]; 312 x = (x << 8) | key[index++];
300 if (index == key.length) 313 if (index == key.length)
301 index = 0; 314 index = 0;
302 } 315 }
316
303 P[i] ^= x; 317 P[i] ^= x;
304 } 318 }
305 319
306 ubyte[] t = new ubyte[BLOCK_SIZE]; // Initialized to 0's 320 ubyte[] t = new ubyte[BLOCK_SIZE]; // Initialized to 0's
307 for (int i = 0; i < PBOX_SIZE;) { 321 for (int i = 0; i < PBOX_SIZE;)
322 {
308 update(t, t); 323 update(t, t);
309 P[i++] = ByteConverter.BigEndian.to!(uint)(t[0..4]); 324 P[i++] = ByteConverter.BigEndian.to!(uint)(t[0..4]);
310 P[i++] = ByteConverter.BigEndian.to!(uint)(t[4..8]); 325 P[i++] = ByteConverter.BigEndian.to!(uint)(t[4..8]);
311 } 326 }
312 327
313 for (int i = 0; i < SBOX_SIZE;) { 328 for (int i = 0; i < SBOX_SIZE;)
329 {
314 update(t, t); 330 update(t, t);
315 S0[i++] = ByteConverter.BigEndian.to!(uint)(t[0..4]); 331 S0[i++] = ByteConverter.BigEndian.to!(uint)(t[0..4]);
316 S0[i++] = ByteConverter.BigEndian.to!(uint)(t[4..8]); 332 S0[i++] = ByteConverter.BigEndian.to!(uint)(t[4..8]);
317 } 333 }
318 334
319 for (int i = 0; i < SBOX_SIZE;) { 335 for (int i = 0; i < SBOX_SIZE;)
336 {
320 update(t, t); 337 update(t, t);
321 S1[i++] = ByteConverter.BigEndian.to!(uint)(t[0..4]); 338 S1[i++] = ByteConverter.BigEndian.to!(uint)(t[0..4]);
322 S1[i++] = ByteConverter.BigEndian.to!(uint)(t[4..8]); 339 S1[i++] = ByteConverter.BigEndian.to!(uint)(t[4..8]);
323 } 340 }
324 341
325 for (int i = 0; i < SBOX_SIZE;) { 342 for (int i = 0; i < SBOX_SIZE;)
343 {
326 update(t, t); 344 update(t, t);
327 S2[i++] = ByteConverter.BigEndian.to!(uint)(t[0..4]); 345 S2[i++] = ByteConverter.BigEndian.to!(uint)(t[0..4]);
328 S2[i++] = ByteConverter.BigEndian.to!(uint)(t[4..8]); 346 S2[i++] = ByteConverter.BigEndian.to!(uint)(t[4..8]);
329 } 347 }
330 348
331 for (int i = 0; i < SBOX_SIZE;) { 349 for (int i = 0; i < SBOX_SIZE;)
350 {
332 update(t, t); 351 update(t, t);
333 S3[i++] = ByteConverter.BigEndian.to!(uint)(t[0..4]); 352 S3[i++] = ByteConverter.BigEndian.to!(uint)(t[0..4]);
334 S3[i++] = ByteConverter.BigEndian.to!(uint)(t[4..8]); 353 S3[i++] = ByteConverter.BigEndian.to!(uint)(t[4..8]);
335 } 354 }
336 } 355 }
337 356
338 /** Some Blowfish test vectors from Schneier's site. */ 357 /** Some Blowfish test vectors from Schneier's site. */
339 debug (UnitTest) { 358 debug (UnitTest)
340 unittest { 359 {
360 unittest
361 {
341 static const char[][] test_keys = [ 362 static const char[][] test_keys = [
342 "0000000000000000", 363 "0000000000000000",
343 "ffffffffffffffff", 364 "ffffffffffffffff",
344 "57686f206973204a6f686e2047616c743f", // I don't know, do you? 365 "57686f206973204a6f686e2047616c743f", // I don't know, do you?
345 "1111111111111111", 366 "1111111111111111",
367 "7d0cc630afda1ec7", 388 "7d0cc630afda1ec7",
368 "0aceab0fc6a0a28d" 389 "0aceab0fc6a0a28d"
369 ]; 390 ];
370 391
371 Blowfish t = new Blowfish(); 392 Blowfish t = new Blowfish();
372 foreach (uint i, char[] test_key; test_keys) { 393 foreach (uint i, char[] test_key; test_keys)
394 {
373 ubyte[] buffer = new ubyte[t.blockSize]; 395 ubyte[] buffer = new ubyte[t.blockSize];
374 char[] result; 396 char[] result;
375 SymmetricKey key = new SymmetricKey(ByteConverter.hexDecode(test_key)); 397 SymmetricKey key = new SymmetricKey(ByteConverter.hexDecode(test_key));
376 398
377 // Encryption 399 // Encryption