69
69
* @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
70
70
*/
71
71
public class Cipher extends RubyObject {
72
- private static ObjectAllocator CIPHER_ALLOCATOR = new ObjectAllocator () {
72
+
73
+ // set to enable debug output
74
+ private static final boolean DEBUG = false ;
75
+
76
+ private static ObjectAllocator CIPHER_ALLOCATOR = new ObjectAllocator () {
73
77
public IRubyObject allocate (Ruby runtime , RubyClass klass ) {
74
78
return new Cipher (runtime , klass );
75
79
}
@@ -215,14 +219,14 @@ public static BlockCipherPadding getBlockCipherPadding(String pad) {
215
219
216
220
public static BlockCipher getBlockCipher (String cipherBase , String cipherVersion , String cipherMode ) {
217
221
BlockCipher cipher ;
218
-
222
+
219
223
// get base cipher
220
224
if (cipherBase .equals ("AES" )) {
221
225
cipher = new AESEngine ();
222
226
} else if (cipherBase .equals ("aes" )) {
223
227
cipher = new AESEngine ();
224
228
} else if (cipherBase .equals ("DES" ) || cipherBase .equals ("des" )) {
225
- if (cipherVersion != null && cipherVersion .equals ("EDE3" )) {
229
+ if ("EDE3" . equals ( cipherVersion ) || "ede3" .equals (cipherVersion )) {
226
230
cipher = new DESedeEngine ();
227
231
} else {
228
232
cipher = new DESEngine ();
@@ -249,7 +253,12 @@ public static BlockCipher getBlockCipher(String cipherBase, String cipherVersion
249
253
// FIXME should be a ruby exception
250
254
return null ;
251
255
}
252
-
256
+
257
+ // see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
258
+ // for a good, widely-cited (if not necessarily definitive) description
259
+ // of block cipher modes, with test inputs/outputs.
260
+ // (however, it doesn't answer questions about the BC implementation)
261
+
253
262
// Wrap with mode-specific cipher
254
263
if (cipherMode .equalsIgnoreCase ("CBC" )) {
255
264
cipher = new CBCBlockCipher (cipher );
@@ -258,15 +267,19 @@ public static BlockCipher getBlockCipher(String cipherBase, String cipherVersion
258
267
cipher = new CFBBlockCipher (cipher , 8 );
259
268
} else if (cipherMode .equalsIgnoreCase ("CFB1" )) {
260
269
// FIXME: Does 1 mean 1 * 8?
261
- cipher = new CFBBlockCipher (cipher , 8 );
270
+ // BD: '1' means '1' (bit), but reportedly (and apparently,
271
+ // from a look at the code) this is not supported by BC,
272
+ // which only supports multiples of 8.
273
+ cipher = new CFBBlockCipher (cipher , 1 ); // this will fail
262
274
} else if (cipherMode .equalsIgnoreCase ("CFB8" )) {
263
275
// FIXME: Does 8 mean 8 * 8?
264
- cipher = new CFBBlockCipher (cipher , 8 * 8 );
276
+ // BD: '8' means '8' (bits). other common CFB modes are 64 and 128
277
+ cipher = new CFBBlockCipher (cipher , 8 );
265
278
} else if (cipherMode .equalsIgnoreCase ("OFB" )) {
266
279
// FIXME: I have no number to put here! I'm using 8.
267
280
cipher = new OFBBlockCipher (cipher , 8 );
268
281
}
269
-
282
+
270
283
return cipher ;
271
284
}
272
285
@@ -286,7 +299,7 @@ public static BufferedBlockCipher getCipher(Ruby runtime, String cipherBase, Str
286
299
}
287
300
288
301
public static KeyParameter getKeyParameter (String cipherBase , byte [] key ) {
289
- if (cipherBase .equals ("DES" )) {
302
+ if (cipherBase .equals ("DES" ) || cipherBase . equals ( "des" ) ) {
290
303
return new DESParameters (key );
291
304
} else {
292
305
return new KeyParameter (key );
@@ -314,6 +327,25 @@ public Cipher(Ruby runtime, RubyClass type) {
314
327
private byte [] key ;
315
328
private byte [] iv ;
316
329
private String padding ;
330
+
331
+ private void dumpVars () {
332
+ System .out .println ("***** Cipher instance vars ****" );
333
+ System .out .println ("name = " + name );
334
+ System .out .println ("cryptoBase = " + cryptoBase );
335
+ System .out .println ("cryptoVersion = " + cryptoVersion );
336
+ System .out .println ("cryptoMode = " + cryptoMode );
337
+ System .out .println ("padding_type = " + padding_type );
338
+ System .out .println ("realName = " + realName );
339
+ System .out .println ("keyLen = " + keyLen );
340
+ System .out .println ("ivLen = " + ivLen );
341
+ System .out .println ("ciph block size = " + ciph .getBlockSize ());
342
+ System .out .println ("encryptMode = " + encryptMode );
343
+ System .out .println ("ciphInited = " + ciphInited );
344
+ System .out .println ("key.length = " + (key == null ? 0 : key .length ));
345
+ System .out .println ("iv.length = " + (iv == null ? 0 : iv .length ));
346
+ System .out .println ("padding = " + padding );
347
+ System .out .println ("*******************************" );
348
+ }
317
349
318
350
public IRubyObject initialize (IRubyObject str , Block unusedBlock ) {
319
351
name = str .toString ();
@@ -328,31 +360,33 @@ public IRubyObject initialize(IRubyObject str, Block unusedBlock) {
328
360
329
361
if (hasLen () && null != cryptoVersion ) {
330
362
try {
331
- keyLen = Integer .parseInt (cryptoVersion );
363
+ keyLen = Integer .parseInt (cryptoVersion ) / 8 ;
332
364
} catch (NumberFormatException e ) {
333
365
keyLen = -1 ;
334
366
}
335
367
}
336
-
368
+
337
369
if (keyLen == -1 ) {
338
370
if ("DES" .equalsIgnoreCase (cryptoBase )) {
371
+ ivLen = 8 ;
339
372
if ("EDE3" .equalsIgnoreCase (cryptoVersion )) {
340
- keyLen = 168 ;
373
+ keyLen = 24 ;
341
374
} else {
342
- keyLen = 56 ;
375
+ keyLen = 8 ;
343
376
}
344
377
} else {
345
- keyLen = 128 ;
378
+ keyLen = 16 ;
346
379
}
347
380
}
348
381
349
382
if (ivLen == -1 ) {
350
383
if ("AES" .equalsIgnoreCase (cryptoBase )) {
351
- ivLen = 16 * 8 ;
384
+ ivLen = 16 ;
352
385
} else {
353
- ivLen = 8 * 8 ;
386
+ ivLen = 8 ;
354
387
}
355
388
}
389
+
356
390
return this ;
357
391
}
358
392
@@ -410,28 +444,32 @@ public IRubyObject set_key_len(IRubyObject len) {
410
444
}
411
445
412
446
public IRubyObject set_key (IRubyObject key ) {
413
- if (key .toString ().length ()*8 < keyLen ) {
414
- throw new RaiseException (getRuntime (), ciphErr , "key length to short" , true );
415
- }
447
+ byte [] keyBytes ;
416
448
try {
417
- this . key = key .convertToString ().getBytes ();
449
+ keyBytes = key .convertToString ().getBytes ();
418
450
} catch (Exception e ) {
419
451
e .printStackTrace ();
420
452
throw new RaiseException (getRuntime (), ciphErr , null , true );
421
453
}
454
+ if (keyBytes .length < keyLen ) {
455
+ throw new RaiseException (getRuntime (), ciphErr , "key length to short" , true );
456
+ }
457
+ this .key = keyBytes ;
422
458
return key ;
423
459
}
424
460
425
461
public IRubyObject set_iv (IRubyObject iv ) {
426
- if (iv .toString ().length ()*8 < ivLen ) {
427
- throw new RaiseException (getRuntime (), ciphErr , "iv length to short" , true );
428
- }
462
+ byte [] ivBytes ;
429
463
try {
430
- this . iv = iv .convertToString ().getBytes ();
464
+ ivBytes = iv .convertToString ().getBytes ();
431
465
} catch (Exception e ) {
432
466
e .printStackTrace ();
433
467
throw new RaiseException (getRuntime (), ciphErr , null , true );
434
468
}
469
+ if (ivBytes .length < ivLen ) {
470
+ throw new RaiseException (getRuntime (), ciphErr , "iv length to short" , true );
471
+ }
472
+ this .iv = ivBytes ;
435
473
return iv ;
436
474
}
437
475
@@ -502,7 +540,7 @@ public IRubyObject pkcs5_keyivgen(IRubyObject[] args) {
502
540
digest = Digest .getDigest (getRuntime (), ((Digest )vdigest ).getAlgorithm ());
503
541
}
504
542
505
- OpenSSLImpl .KeyAndIv result = OpenSSLImpl .EVP_BytesToKey (keyLen / 8 ,ivLen / 8 ,digest ,salt ,pass ,iter );
543
+ OpenSSLImpl .KeyAndIv result = OpenSSLImpl .EVP_BytesToKey (keyLen ,ivLen ,digest ,salt ,pass ,iter );
506
544
this .key = result .getKey ();
507
545
this .iv = result .getIv ();
508
546
} catch (Exception e ) {
@@ -516,11 +554,16 @@ public IRubyObject pkcs5_keyivgen(IRubyObject[] args) {
516
554
}
517
555
518
556
private void doInitialize () {
557
+
558
+ if (DEBUG ) System .out .println ("*** doInitialize" );
559
+ if (DEBUG ) dumpVars ();
560
+
519
561
ciphInited = true ;
520
562
try {
521
563
// FIXME: I had to make these >= where they were == before; why?
522
- assert key .length * 8 >= keyLen : "Key wrong length" ;
523
- assert iv .length * 8 >= ivLen : "IV wrong length" ;
564
+
565
+ assert key .length >= keyLen : "Key wrong length" ;
566
+ assert iv .length >= ivLen : "IV wrong length" ;
524
567
if (!"ECB" .equalsIgnoreCase (cryptoMode ) && this .iv != null ) {
525
568
this .ciph .init (encryptMode , new ParametersWithIV (getKeyParameter (cryptoBase , key ), iv ));
526
569
} else {
@@ -533,6 +576,8 @@ private void doInitialize() {
533
576
}
534
577
535
578
public IRubyObject update (IRubyObject data ) {
579
+ if (DEBUG ) System .out .println ("*** update [" +data +"]" );
580
+
536
581
//TODO: implement correctly
537
582
byte [] val = data .convertToString ().getBytes ();
538
583
if (val .length == 0 ) {
0 commit comments