In Progress
Unit 1, Lesson 21
In Progress

Secure Random

Video transcript & code

In episode 310 we introduced the SecureRandom module, which gives us a direct interface to the operating system facilities for generating cryptographically-sound random data. While we're on the subject, I thought we might briefly round out our knowledge of this class.

SecureRandom is a module in the Ruby standard library, not the core libraries. So we have to require it in order to make it available.

We've already seen the random_number method in the last episode. Like the ruby core rand method, by default it generates a floating point number between zero and one.

Also like the standard rand method, we can give it a max argument as an integer, and it will switch to generating integers between zero and one less than the given max.

Unfortunately, unlike the standard rand method, we can't supply a range to it.

require "securerandom"

SecureRandom.random_number      # => 0.6578788068017444
SecureRandom.random_number(100) # => 99
SecureRandom.random_number(1..6) # => ArgumentError: comparison of Fixnum wit...

# ~> ArgumentError
# ~> comparison of Fixnum with Range failed
# ~>
# ~> /home/avdi/.rubies/ruby-2.1.3/lib/ruby/2.1.0/securerandom.rb:210:in `<'
# ~> /home/avdi/.rubies/ruby-2.1.3/lib/ruby/2.1.0/securerandom.rb:210:in `ran...
# ~> xmptmp-in34708kR.rb:5:in `<main>'

This isn't as big a problem as it might seem, though, because usually when we have a need for cryptographically secure data, we're not looking for individual random numbers. More often, we need it for large blocks of chaotic data for things like security tokens, nonce values, and access keys.

The SecureRandom method I use most often is one that generates hexadecimal strings. For instance, let's say we need to generate a unique sign-up token and send it to a user in an email. We can send the .hex message to SecureRandom, along with the number of hexadecimal bytes we want, in this case 16. The result is a 32-character-long string, since it takes two characters to represent a single hex byte. we can then merge this into our URL template.

require "securerandom"
signup_url = "http://example.com/signup?token="
token      = SecureRandom.hex(16)
signup_url + token
# => "http://example.com/signup?token=2feef1979ddb8b64b123d1e5ca520a71"

Another common format to want a block of random data in is base64 encoding, for example when generating a cryptographic certificate. SecureRandom has a dedicated method for this, which just like the .hex method takes an argument indicating the number of bytes of data to generate. There is also a .urlsafe_base64 variant in case we want to be able to use the resulting string as part of a URL.

require "securerandom"

SecureRandom.base64(64)
# => "E12L2DCFvHe0tQr8eHKPSumQS+bsnj/lEFq3eeFx3jsrfXUBrPl4Gw6ouPC4X9+YEIWoCJ3...

SecureRandom.urlsafe_base64(64)
# => "PQEb5eiTTCPD91xa-YZI-0acuKI4MtDP73uarP1SvqdAxxVwzSieFM_R3B6VsEJDLsBWFEc...

All of the methods we've seen so far are effectively convenience methods, which anticipate common needs for random data. But in some cases, we might just want raw data, without any special format. For that scenario, SecureRandom provides a random_bytes method, which simply returns the desired number of bytes-worth of cryptographically-secure random data in the form of a string. Since these are raw bytes, many of the characters in the string may be unprintable.

require "securerandom"

SecureRandom.random_bytes(24)
# => "\x15\xE8\x9C\xDAN\xE2\xBD@\xAEt\x1A\"\xF6)\x9D\xD4\xA7\x81\xF0 c\x88\xC...

Finally, there is also a method for generating UUIDs. However, Ruby has another whole library dedicated to generating UUIDs, so I'm not sure that SecureRandom should be the first place we look in that case. I'm just including it for completeness.

require "securerandom"

SecureRandom.uuid               # => "c0e5d67e-2ccc-4878-bc6c-f6e478e4b260"

So that's the SecureRandom library. If nothing else, it's a great tool for easily generating hexadecimal security tokens, and it's worth knowing about for that reason alone. Happy hacking!

Responses