Skip to content

Commit

Permalink
Merge pull request #4894 from ysbaddaden/std-merge-secure-random-into…
Browse files Browse the repository at this point in the history
…-random

Merge SecureRandom into Random and Random::Secure

- Renames Random::System to Random::Secure.
- Removes SecureRandom.
- Moves #uuid, #hex and #base64 methods to Random.
- Moves SecureRandom#random_bytes(slice) to Random::Secure.
- Implements generic Random#random_bytes(slice).
  • Loading branch information
ysbaddaden authored Sep 26, 2017
2 parents 2eca01b + 79d0358 commit 78b4355
Show file tree
Hide file tree
Showing 19 changed files with 253 additions and 232 deletions.
9 changes: 5 additions & 4 deletions spec/std/crypto/bcrypt_spec.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "spec"
require "crypto/bcrypt"
require "random/secure"

describe "Crypto::Bcrypt" do
latin1_pound_sign = String.new(Bytes.new(1, 0xa3_u8))
Expand Down Expand Up @@ -28,16 +29,16 @@ describe "Crypto::Bcrypt" do

it "validates salt size" do
expect_raises(Crypto::Bcrypt::Error, /Invalid salt size/) do
Crypto::Bcrypt.new("abcd", SecureRandom.hex(7))
Crypto::Bcrypt.new("abcd", Random::Secure.hex(7))
end

expect_raises(Crypto::Bcrypt::Error, /Invalid salt size/) do
Crypto::Bcrypt.new("abcd", SecureRandom.hex(9))
Crypto::Bcrypt.new("abcd", Random::Secure.hex(9))
end
end

it "validates cost" do
salt = SecureRandom.hex(8)
salt = Random::Secure.hex(8)

expect_raises(Crypto::Bcrypt::Error, /Invalid cost/) do
Crypto::Bcrypt.new("abcd", salt, 3)
Expand All @@ -49,7 +50,7 @@ describe "Crypto::Bcrypt" do
end

it "validates password size" do
salt = SecureRandom.random_bytes(16)
salt = Random::Secure.random_bytes(16)

expect_raises(Crypto::Bcrypt::Error, /Invalid password size/) do
Crypto::Bcrypt.new("".to_slice, salt)
Expand Down
5 changes: 3 additions & 2 deletions spec/std/http/web_socket_spec.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "spec"
require "http/web_socket"
require "random/secure"

private def assert_text_packet(packet, size, final = false)
assert_packet packet, HTTP::WebSocket::Protocol::Opcode::TEXT, size, final: final
Expand Down Expand Up @@ -320,7 +321,7 @@ describe HTTP::WebSocket do

ws2 = HTTP::WebSocket.new("ws://127.0.0.1:#{listen_port}")

random = SecureRandom.hex
random = Random::Secure.hex
ws2.on_message do |str|
str.should eq("pong #{random}")
ws2.close
Expand Down Expand Up @@ -361,7 +362,7 @@ describe HTTP::WebSocket do
client_context = OpenSSL::SSL::Context::Client.insecure
ws2 = HTTP::WebSocket.new("127.0.0.1", port: listen_port, path: "/", tls: client_context)

random = SecureRandom.hex
random = Random::Secure.hex
ws2.on_message do |str|
str.should eq("pong #{random}")
ws2.close
Expand Down
20 changes: 20 additions & 0 deletions spec/std/random/secure_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require "spec"
require "random/secure"

describe "Random::Secure" do
it "returns random number from a secure system source" do
Random::Secure.next_u.should be_a(Int::Unsigned)

x = Random::Secure.rand(123456...654321)
x.should be >= 123456
x.should be < 654321

Random::Secure.rand(Int64::MAX / 2).should be <= (Int64::MAX / 2)
end

it "fully fills a large buffer" do
# mostly testing the linux getrandom calls
bytes = Random::Secure.random_bytes(10000)
bytes[9990, 10].should_not eq(Bytes.new(10))
end
end
14 changes: 0 additions & 14 deletions spec/std/random/system_spec.cr

This file was deleted.

79 changes: 79 additions & 0 deletions spec/std/random_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,83 @@ describe "Random" do
rng.rand(Int8::MIN..Int8::MAX).should eq expected
end
end

describe "random_bytes" do
it "generates random bytes" do
rng = TestRNG.new([0xfa19443eu32, 1u32, 0x12345678u32])
rng.random_bytes(9).should eq Bytes[0x3e, 0x44, 0x19, 0xfa, 1, 0, 0, 0, 0x78]
rng.random_bytes(1).should eq Bytes[0x3e]
rng.random_bytes(4).should eq Bytes[1, 0, 0, 0]
rng.random_bytes(3).should eq Bytes[0x78, 0x56, 0x34]
rng.random_bytes(0).should eq Bytes.new(0)

rng = TestRNG.new([12u8, 255u8, 11u8, 5u8, 122u8, 200u8, 192u8])
rng.random_bytes(7).should eq Bytes[12, 255, 11, 5, 122, 200, 192]
end

it "gets random bytes with default number of digits" do
bytes = TestRNG.new(RNG_DATA_32).random_bytes
bytes.size.should eq(16)
end

it "gets random bytes with requested number of digits" do
bytes = TestRNG.new(RNG_DATA_32).random_bytes(50)
bytes.size.should eq(50)
end

it "fills given buffer with random bytes" do
bytes = Bytes.new(2000)
TestRNG.new(RNG_DATA_32).random_bytes(bytes)
bytes.size.should eq 2000
bytes[1990, 10].should eq(UInt8.slice(0, 0, 1, 0, 0, 0, 234, 0, 0, 0))
end
end

describe "base64" do
it "gets base64 with default number of digits" do
base64 = TestRNG.new(RNG_DATA_32).base64
base64.should eq("y0jhAQAAAAABAAAA6gAAAA==")
end

it "gets base64 with requested number of digits" do
base64 = TestRNG.new(RNG_DATA_64).base64(50)
base64.should eq("n9hX9GKDEAL//////////wAAAAAAAAAA6I06MNtOcwAhuKXjOwIAADYvUY4HAAAAYto=")
end
end

describe "urlsafe_base64" do
it "gets urlsafe base64 with default number of digits" do
base64 = TestRNG.new(RNG_DATA_32).urlsafe_base64
base64.should eq("y0jhAQAAAAABAAAA6gAAAA")
end

it "gets urlsafe base64 with requested number of digits" do
base64 = TestRNG.new(RNG_DATA_64).urlsafe_base64(50)
base64.should eq("n9hX9GKDEAL__________wAAAAAAAAAA6I06MNtOcwAhuKXjOwIAADYvUY4HAAAAYto")
end

it "keeps padding" do
base64 = TestRNG.new(RNG_DATA_32).urlsafe_base64(padding: true)
base64.should eq("y0jhAQAAAAABAAAA6gAAAA==")
end
end

describe "hex" do
it "gets hex with default number of digits" do
hex = TestRNG.new(RNG_DATA_32).hex
hex.should eq("cb48e1010000000001000000ea000000")
end

it "gets hex with requested number of digits" do
hex = TestRNG.new(RNG_DATA_64).hex(50)
hex.should eq("9fd857f462831002ffffffffffffffff0000000000000000e88d3a30db4e730021b8a5e33b020000362f518e0700000062da")
end
end

describe "uuid" do
it "gets uuid" do
uuid = TestRNG.new(RNG_DATA_8).uuid
uuid.should eq("ea990000-7f80-4fff-aa99-00007f80ffff")
end
end
end
86 changes: 0 additions & 86 deletions spec/std/secure_random_spec.cr

This file was deleted.

4 changes: 2 additions & 2 deletions src/crypto/bcrypt.cr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
require "secure_random"
require "random/secure"
require "./subtle"

# Pure Crystal implementation of the Bcrypt algorithm by Niels Provos and David
Expand Down Expand Up @@ -46,7 +46,7 @@ class Crypto::Bcrypt
def self.hash_secret(password, cost = DEFAULT_COST) : String
# We make a clone here to we don't keep a mutable reference to the original string
passwordb = password.to_unsafe.to_slice(password.bytesize + 1).clone # include leading 0
saltb = SecureRandom.random_bytes(SALT_SIZE)
saltb = Random::Secure.random_bytes(SALT_SIZE)
new(passwordb, saltb, cost).to_s
end

Expand Down
1 change: 0 additions & 1 deletion src/docs_main.cr
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ require "./option_parser"
require "./partial_comparable"
require "./random/**"
require "./readline"
require "./secure_random"
require "./signal"
require "./string_pool"
require "./string_scanner"
Expand Down
3 changes: 2 additions & 1 deletion src/http/multipart.cr
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require "random/secure"
require "./multipart/*"

# The `HTTP::Multipart` module contains utilities for parsing MIME multipart
Expand Down Expand Up @@ -89,7 +90,7 @@ module HTTP::Multipart
# HTTP::Multipart.generate_boundary # => "---------------------------dQu6bXHYb4m5zrRC3xPTGwV"
# ```
def self.generate_boundary
"--------------------------#{SecureRandom.urlsafe_base64(18)}"
"--------------------------#{Random::Secure.urlsafe_base64(18)}"
end

class Error < Exception
Expand Down
2 changes: 0 additions & 2 deletions src/http/multipart/builder.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
require "secure_random"

module HTTP::Multipart
# Builds a multipart MIME message.
#
Expand Down
2 changes: 1 addition & 1 deletion src/oauth.cr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "http/client"
require "http/params"
require "uri"
require "secure_random"
require "random/secure"
require "openssl/hmac"
require "base64"
require "./oauth/**"
2 changes: 1 addition & 1 deletion src/oauth/oauth.cr
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ module OAuth

private def self.oauth_header(client, request, token, token_secret, consumer_key, consumer_secret, extra_params)
ts = Time.now.epoch.to_s
nonce = SecureRandom.hex
nonce = Random::Secure.hex

signature = Signature.new consumer_key, consumer_secret, token, token_secret, extra_params
signature.authorization_header request, client.tls?, ts, nonce
Expand Down
4 changes: 2 additions & 2 deletions src/oauth2/access_token/mac.cr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
require "secure_random"
require "random/secure"
require "openssl/hmac"
require "base64"
require "./access_token"
Expand All @@ -22,7 +22,7 @@ class OAuth2::AccessToken::Mac < OAuth2::AccessToken

def authenticate(request : HTTP::Request, tls)
ts = Time.now.epoch
nonce = "#{ts - @issued_at}:#{SecureRandom.hex}"
nonce = "#{ts - @issued_at}:#{Random::Secure.hex}"
method = request.method
uri = request.resource
host, port = host_and_port request, tls
Expand Down
5 changes: 3 additions & 2 deletions src/openssl/cipher.cr
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require "random/secure"
require "openssl"

class OpenSSL::Cipher
Expand Down Expand Up @@ -37,12 +38,12 @@ class OpenSSL::Cipher
end

def random_key
key = SecureRandom.random_bytes key_len
key = Random::Secure.random_bytes key_len
self.key = key
end

def random_iv
iv = SecureRandom.random_bytes iv_len
iv = Random::Secure.random_bytes iv_len
self.iv = iv
end

Expand Down
Loading

0 comments on commit 78b4355

Please sign in to comment.