6969 * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
7070 */
7171public 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 () {
7377 public IRubyObject allocate (Ruby runtime , RubyClass klass ) {
7478 return new Cipher (runtime , klass );
7579 }
@@ -215,14 +219,14 @@ public static BlockCipherPadding getBlockCipherPadding(String pad) {
215219
216220 public static BlockCipher getBlockCipher (String cipherBase , String cipherVersion , String cipherMode ) {
217221 BlockCipher cipher ;
218-
222+
219223 // get base cipher
220224 if (cipherBase .equals ("AES" )) {
221225 cipher = new AESEngine ();
222226 } else if (cipherBase .equals ("aes" )) {
223227 cipher = new AESEngine ();
224228 } else if (cipherBase .equals ("DES" ) || cipherBase .equals ("des" )) {
225- if (cipherVersion != null && cipherVersion .equals ("EDE3" )) {
229+ if ("EDE3" . equals ( cipherVersion ) || "ede3" .equals (cipherVersion )) {
226230 cipher = new DESedeEngine ();
227231 } else {
228232 cipher = new DESEngine ();
@@ -249,7 +253,12 @@ public static BlockCipher getBlockCipher(String cipherBase, String cipherVersion
249253 // FIXME should be a ruby exception
250254 return null ;
251255 }
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+
253262 // Wrap with mode-specific cipher
254263 if (cipherMode .equalsIgnoreCase ("CBC" )) {
255264 cipher = new CBCBlockCipher (cipher );
@@ -258,15 +267,19 @@ public static BlockCipher getBlockCipher(String cipherBase, String cipherVersion
258267 cipher = new CFBBlockCipher (cipher , 8 );
259268 } else if (cipherMode .equalsIgnoreCase ("CFB1" )) {
260269 // 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
262274 } else if (cipherMode .equalsIgnoreCase ("CFB8" )) {
263275 // 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 );
265278 } else if (cipherMode .equalsIgnoreCase ("OFB" )) {
266279 // FIXME: I have no number to put here! I'm using 8.
267280 cipher = new OFBBlockCipher (cipher , 8 );
268281 }
269-
282+
270283 return cipher ;
271284 }
272285
@@ -286,7 +299,7 @@ public static BufferedBlockCipher getCipher(Ruby runtime, String cipherBase, Str
286299 }
287300
288301 public static KeyParameter getKeyParameter (String cipherBase , byte [] key ) {
289- if (cipherBase .equals ("DES" )) {
302+ if (cipherBase .equals ("DES" ) || cipherBase . equals ( "des" ) ) {
290303 return new DESParameters (key );
291304 } else {
292305 return new KeyParameter (key );
@@ -314,6 +327,25 @@ public Cipher(Ruby runtime, RubyClass type) {
314327 private byte [] key ;
315328 private byte [] iv ;
316329 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+ }
317349
318350 public IRubyObject initialize (IRubyObject str , Block unusedBlock ) {
319351 name = str .toString ();
@@ -328,31 +360,33 @@ public IRubyObject initialize(IRubyObject str, Block unusedBlock) {
328360
329361 if (hasLen () && null != cryptoVersion ) {
330362 try {
331- keyLen = Integer .parseInt (cryptoVersion );
363+ keyLen = Integer .parseInt (cryptoVersion ) / 8 ;
332364 } catch (NumberFormatException e ) {
333365 keyLen = -1 ;
334366 }
335367 }
336-
368+
337369 if (keyLen == -1 ) {
338370 if ("DES" .equalsIgnoreCase (cryptoBase )) {
371+ ivLen = 8 ;
339372 if ("EDE3" .equalsIgnoreCase (cryptoVersion )) {
340- keyLen = 168 ;
373+ keyLen = 24 ;
341374 } else {
342- keyLen = 56 ;
375+ keyLen = 8 ;
343376 }
344377 } else {
345- keyLen = 128 ;
378+ keyLen = 16 ;
346379 }
347380 }
348381
349382 if (ivLen == -1 ) {
350383 if ("AES" .equalsIgnoreCase (cryptoBase )) {
351- ivLen = 16 * 8 ;
384+ ivLen = 16 ;
352385 } else {
353- ivLen = 8 * 8 ;
386+ ivLen = 8 ;
354387 }
355388 }
389+
356390 return this ;
357391 }
358392
@@ -410,28 +444,32 @@ public IRubyObject set_key_len(IRubyObject len) {
410444 }
411445
412446 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 ;
416448 try {
417- this . key = key .convertToString ().getBytes ();
449+ keyBytes = key .convertToString ().getBytes ();
418450 } catch (Exception e ) {
419451 e .printStackTrace ();
420452 throw new RaiseException (getRuntime (), ciphErr , null , true );
421453 }
454+ if (keyBytes .length < keyLen ) {
455+ throw new RaiseException (getRuntime (), ciphErr , "key length to short" , true );
456+ }
457+ this .key = keyBytes ;
422458 return key ;
423459 }
424460
425461 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 ;
429463 try {
430- this . iv = iv .convertToString ().getBytes ();
464+ ivBytes = iv .convertToString ().getBytes ();
431465 } catch (Exception e ) {
432466 e .printStackTrace ();
433467 throw new RaiseException (getRuntime (), ciphErr , null , true );
434468 }
469+ if (ivBytes .length < ivLen ) {
470+ throw new RaiseException (getRuntime (), ciphErr , "iv length to short" , true );
471+ }
472+ this .iv = ivBytes ;
435473 return iv ;
436474 }
437475
@@ -502,7 +540,7 @@ public IRubyObject pkcs5_keyivgen(IRubyObject[] args) {
502540 digest = Digest .getDigest (getRuntime (), ((Digest )vdigest ).getAlgorithm ());
503541 }
504542
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 );
506544 this .key = result .getKey ();
507545 this .iv = result .getIv ();
508546 } catch (Exception e ) {
@@ -516,11 +554,16 @@ public IRubyObject pkcs5_keyivgen(IRubyObject[] args) {
516554 }
517555
518556 private void doInitialize () {
557+
558+ if (DEBUG ) System .out .println ("*** doInitialize" );
559+ if (DEBUG ) dumpVars ();
560+
519561 ciphInited = true ;
520562 try {
521563 // 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" ;
524567 if (!"ECB" .equalsIgnoreCase (cryptoMode ) && this .iv != null ) {
525568 this .ciph .init (encryptMode , new ParametersWithIV (getKeyParameter (cryptoBase , key ), iv ));
526569 } else {
@@ -533,6 +576,8 @@ private void doInitialize() {
533576 }
534577
535578 public IRubyObject update (IRubyObject data ) {
579+ if (DEBUG ) System .out .println ("*** update [" +data +"]" );
580+
536581 //TODO: implement correctly
537582 byte [] val = data .convertToString ().getBytes ();
538583 if (val .length == 0 ) {
0 commit comments