Mercurial > projects > dcrypt
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 |