From: Brian Candler Date: 2003-08-16T04:50:22+09:00 Subject: Re: ruby-mcrypt ? --lrZ03NoBR/3+SXJZ Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Wed, Aug 13, 2003 at 07:02:04AM +0900, Meino Christian Cramer wrote: > does anyone know of a working version of ruby-mcrypt > for ruby 1.8 ??? > > The version (0.2) I got does "encrypt" but does not decrypt ever back > ... I've been having a look at this. The answer seems to be: (1) ruby-mcrypt does work, it's testmcrypt.rb which is wrong (simple patch attached; it's not resetting the IV each time. ruby-mcrypt really ought to provide a way to call mcrypt_generic_init to reset an existing module) (2) however, a simple code inspection shows that ruby-mcrypt.c is very badly and dangerously written, and IMO should not be used at all. Example: ivsize = mcrypt_enc_get_iv_size( td ); if ( ivsize == 0 ) { iv = NULL; } else { iv = malloc( ivsize ); memset( iv, 0, ivsize ); memcpy( iv, RSTRING( ivec )->ptr, RSTRING( ivec )->len ); } Here, the code asks how big an IV it should have (say 16 bytes), malloc's that amount of memory, and then blindly memcpy's whatever String you pass in on top of it. So if you pass it a Ruby string which is 100 bytes long, say, then you will be overwriting some random object on the heap. It also passes in 'free' to Data_Wrap_Struct, which it should not do. On my FreeBSD box this gives a number of warnings when the program finishes: ruby in free(): warning: chunk is already free ruby in free(): warning: chunk is already free ... but some other Unixes would probably crash. A simple fix here is: --- ruby-mcrypt.c.orig Wed Jun 20 13:39:55 2001 +++ ruby-mcrypt.c Fri Aug 15 20:42:02 2003 @@ -93,7 +93,7 @@ rb_raise( rb_eRuntimeError, mcrypt_strerror( i ) ); } - obj = Data_Wrap_Struct( class, 0, free, td ); + obj = Data_Wrap_Struct( class, 0, 0, td ); if ( iv != NULL ) { free( iv ); but then programs which use mcrypt would leak memory. I think the proper fix is more complicated; it would involve calling mcrypt_generic_deinit and/or mcrypt_module_close, but only if they have not been called already. So basically, don't use this code unless you like programs which are insecure and crash your machine. Regards, Brian. --lrZ03NoBR/3+SXJZ Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="testmcrypt.patch" --- testmcrypt.rb.orig Wed Jun 20 13:38:10 2001 +++ testmcrypt.rb Fri Aug 15 20:46:24 2003 @@ -50,7 +50,9 @@ enc = mc.mcrypt_generic( PLAINTEXT ) print( "enc: %s\n" % [hexstring( enc )] ) +mc.mcrypt_generic_end +mc = MCrypt.new( "twofish", nil, "cfb", nil, KEY, IVEC ) dec = mc.mdecrypt_generic( enc ) print( "dec: %s\n" % [dec] ) @@ -72,7 +74,9 @@ enc = mc.mcrypt_generic( PLAINTEXT ) print( "enc: %s\n" % [hexstring( enc )] ) +mc.mcrypt_generic_end +mc = MCrypt.new( "twofish", nil, "cbc", nil, KEY, IVEC ) dec = mc.mdecrypt_generic( enc ) print( "dec: %s\n" % [dec] ) @@ -94,7 +98,9 @@ enc = mc.mcrypt_generic( PLAINTEXT ) print( "enc: %s\n" % [hexstring( enc )] ) +mc.mcrypt_generic_end +mc = MCrypt.new( "twofish", nil, "ecb", nil, KEY, nil ) dec = mc.mdecrypt_generic( enc ) print( "dec: %s\n" % [dec] ) @@ -116,7 +122,9 @@ enc = mc.mcrypt_generic( PLAINTEXT ) print( "enc: %s\n" % [hexstring( enc )] ) +mc.mcrypt_generic_end +mc = MCrypt.new( "rijndael-128", nil, "cfb", nil, KEY, IVEC ) dec = mc.mdecrypt_generic( enc ) print( "dec: %s\n" % [dec] ) @@ -138,7 +146,9 @@ enc = mc.mcrypt_generic( PLAINTEXT ) print( "enc: %s\n" % [hexstring( enc )] ) +mc.mcrypt_generic_end +mc = MCrypt.new( "rijndael-128", nil, "cbc", nil, KEY, IVEC ) dec = mc.mdecrypt_generic( enc ) print( "dec: %s\n" % [dec] ) --lrZ03NoBR/3+SXJZ--