Repository navigation
Conversation
With OpenSSL 3.0 and later, derive the key with EVP_KDF_fetch() and EVP_KDF_derive(), passing all arguments as OSSL_PARAMs, including OSSL_KDF_PARAM_PKCS5. The new pkcs5: keyword argument controls the SP 800-132 lower bound checks: 0 enforces them, and 1 (the default) bypasses them. The default matches the behavior of PKCS5_PBKDF2_HMAC() prior to the OpenSSL 4.0 release, and allows existing data to be decrypted, such as Active Record encrypted attributes, which use a salt that is too short by default (rails/rails#58937). Other libraries continue to use PKCS5_PBKDF2_HMAC() and ignore the argument. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Generally, ruby/openssl should respect OpenSSL's defaults, which in this case seems to mean leaving the We should expose the option if needed, but I'm leaning towards a generic interface to I'll try to make time to finish #906. |
Ack! I didn't know if ruby wants to be explicit or not, will adjust - because openssl default is quite finiky:
Will adjust to match that verbatim.
the pkcs5 arg is specific to that PBKDF2 derive; there are other more generic params such as key-check / size-check etc to enforce input key lengths; and output key lengths - those are more generic params but again provider dependent "ignored by default provider, have some action with fips provider". At least the pkcs5 param does actually do something with both default and fips providers.
Yeah generic EVP_KDF would be nice; but we may still need to expose and allow setting pkcs5 param - because as it stands all existing ActiveRecord encrypted cookies and secrets fail - and "rails new" fails on a fips system with ruby and openssl4. See rails/rails#58937 |
With OpenSSL 3.0 and later,
OpenSSL::KDF.pbkdf2_hmacnow derives the key withEVP_KDF_fetch()andEVP_KDF_derive(), passing all arguments asOSSL_PARAMs (asossl_pkcs5_pbkdf2_hmac_ex()does in OpenSSL), includingOSSL_KDF_PARAM_PKCS5.The new
pkcs5:keyword argument controls OpenSSL's SP 800-132 lower bound checks:pkcs5: 0enforces them: iterations >= 1000, salt >= 128 bits, derived key >= 112 bits, non-empty password (>= 8 bytes with the FIPS provider).pkcs5: 1(the default) bypasses them.The default matches the behavior of
PKCS5_PBKDF2_HMAC()prior to the OpenSSL 4.0 release, and allows existing data to be decrypted, such as Active Record encrypted attributes, which use a salt that is too short by default (rails/rails#58937).With the FIPS provider, bypassing the checks might still block the operation, or raise the non-approved usage indicator. Other libraries (LibreSSL, AWS-LC, OpenSSL < 3.0) keep using
PKCS5_PBKDF2_HMAC()and ignore the argument.The docs also note that OpenSSL's lower bounds are minimums, and point to the OWASP Password Storage Cheat Sheet for security-sensitive parameters.
Tested against OpenSSL 3.5.5 (via a ruby/ruby build):
test/openssl/test_kdf.rbpasses, including a new test thatpkcs5: 0rejects the RFC 6070 c=1 parameters andpkcs5: 1derives the expected value. Not tested with FIPS, LibreSSL or AWS-LC.🤖 Generated with Claude Code