- 1_8_6_287
- 1_8_7_72
- 1_8_7_330
- 1_9_1_378
- 1_9_2_180
- 1_9_3_125
- 1_9_3_392
- 2_1_10
- 2_2_9
- 2_4_6
- 2_5_5 (0)
- 2_6_3 (0)
- What's this?
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:
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.