module

OpenSSL::KDF

ruby latest stable

Provides functionality of various KDFs (key derivation function).

KDF is typically used for securely deriving arbitrary length symmetric keys to be used with an OpenSSL::Cipher from passwords. Another use case is for storing passwords: Due to the ability to tweak the effort of computation by increasing the iteration count, computation can be slowed down artificially in order to render possible attacks infeasible.

Currently, OpenSSL::KDF provides implementations for the following KDF:

  • PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in combination with HMAC

  • scrypt

  • HKDF

Examples

Generating a 128 bit key for a Cipher (e.g. AES)

pass = "secret"
salt = OpenSSL::Random.random_bytes(16)
iter = 20_000
key_len = 16
key = OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter,
                               length: key_len, hash: "sha1")

Storing Passwords

pass = "secret"
# store this with the generated value
salt = OpenSSL::Random.random_bytes(16)
iter = 20_000
hash = OpenSSL::Digest::SHA256.new
len = hash.digest_length
# the final value to be stored
value = OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter,
                                 length: len, hash: hash)

Important Note on Checking Passwords

When comparing passwords provided by the user with previously stored values, a common mistake made is comparing the two values using “==”. Typically, “==” short-circuits on evaluation, and is therefore vulnerable to timing attacks. The proper way is to use a method that always takes the same amount of time when comparing two values, thus not leaking any information to potential attackers. To compare two values, the following could be used:

def eql_time_cmp(a, b)
  unless a.length == b.length
    return false
  end
  cmp = b.bytes
  result = 0
  a.bytes.each_with_index {|c,i|
    result |= c ^ cmp[i]
  }
  result == 0
end

Please note that the premature return in case of differing lengths typically does not leak valuable information - when using PBKDF2, the length of the values to be compared is of fixed size.

Files

  • ext/openssl/ossl.c