From a154e82793542ac49a19feab045fa52348faa81d Mon Sep 17 00:00:00 2001 From: Stephen Veiss Date: Tue, 22 Jul 2008 22:33:43 +0100 Subject: [PATCH] Add OpenSSL::Random#random_bytes and #pseudo_bytes. * Implements the above two methods via FFI. * Adds OpenSSL::OpenSSLError exception class. * Allows spec/ruby/1.8/library/openssl/random/*_spec.rb to pass. Note that the behaviour of #pseudo_bytes does not quite match that of ext/openssl as distributed with MRI: According to man RAND_bytes(3), the return value of RAND_bytes indicates if an error occurred. However, the return value of RAND_pseudo_bytes indicates if the returned bytes are cryptographically secure or not. ext/openssl appears to treat both cases the same -- raising an OpenSSLError if the return value is 0. For the RAND_pseudo_bytes case, this return value indicates that the returned bytes are not cryptographically secure -- which is reasonable, as the user has specifically requested this! I think that the behaviour of MRI's ext/openssl is a bug; however, I don't think I have access to a system where RAND_pseudo_bytes returns cryptographically insecure bytes against which to check... --- lib/openssl.rb | 3 +++ lib/openssl/random.rb | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 0 deletions(-) create mode 100644 lib/openssl/random.rb diff --git a/lib/openssl.rb b/lib/openssl.rb index 45ceb25..95ff456 100644 --- a/lib/openssl.rb +++ b/lib/openssl.rb @@ -1,6 +1,9 @@ module OpenSSL autoload :HMAC, "openssl/hmac" autoload :Digest, "openssl/digest" + autoload :Random, "openssl/random" + + class OpenSSLError < StandardError ; end # Used by the various hexdigest implementations def self.digest_to_hex(digest) diff --git a/lib/openssl/random.rb b/lib/openssl/random.rb new file mode 100644 index 0000000..999f9e7 --- /dev/null +++ b/lib/openssl/random.rb @@ -0,0 +1,46 @@ +module OpenSSL + class Random + + module Foreign + set_ffi_lib "libcrypto" + # RAND_bytes(unsigned char* buf, int num) + attach_function "RAND_bytes", :ossl_bytes, + [:string, :int], :int + + # RAND_pseudo_bytes(unsigned char* buf, int num) + attach_function "RAND_pseudo_bytes", :ossl_pseudo_bytes, + [:string, :int], :int + end + + def self.random_bytes(n) + if n < 0 + raise ArgumentError.new('negative string size') + end + + random_string = ' ' * n + ret = Foreign.ossl_bytes(random_string, n) + + raise OpenSSLError.new('random_bytes unsupported by current RAND method') if ret == -1 + raise OpenSSLError.new('call to RAND_bytes(3) failed') if ret == 0 + + random_string + end + + def self.pseudo_bytes(n) + if n < 0 + raise ArgumentError.new('negative string size') + end + + random_string = ' ' * n + ret = Foreign.ossl_pseudo_bytes(random_string, n) + + raise OpenSSLError.new('random_bytes unsupported by current RAND method') if ret == -1 + # per man RAND_bytes(3), RAND_pseudo_bytes doesn't appear to + # signal errors -- the return value signifies if the bytes + # returned are cryptographically secure, NOT if the function + # succeeded or not ... + + random_string + end + end +end -- 1.5.6.1