node
node copied to clipboard
Customize password-based KDF in `KeyObject#export`
What is the problem this feature will solve?
At the moment, node.js uses OpenSSL defaults when exporting a key object
const { privateKey } = generateKeyPairSync("ec", {
namedCurve: "P-384",
privateKeyEncoding: {
type: "pkcs8",
format: "pem",
cipher: "aes-256-cbc",
passphrase: "something secret",
},
});
generates a PEM-encoded encrypted private key with 2048 iterations of PBKDF2-HMAC-SHA256. OWASP recommends way more (600k).
What is the feature you are proposing to solve the problem?
In OpenSSL CLI openssl pkcs8 -topk8
, the iterations are customizable with the -iter
option.
Alternatively, one can choose -scrypt
(and relevant -scrypt_N/r/p
params) as the KDF in OpenSSL but not in node.js.
The PRF can also be a different HMAC-SHAxxx but that's less relevant in my opinion
I open the discussion for extending KeyObject#export
and related interfaces with one of the following
- A
derivedKey
parameter that excludespassphrase
. In this case, no KDF is performed, and it is strongly emphasised to pass a key derived withscrypt
,pbkdf2
, orargon2id
(node.js support one day :crossed_fingers:) (EDIT: support for argon2id introduced in OpenSSL 3.2.0)
privateKeyEncoding: {
...
cipher: "aes-256-cbc",
derivedKey: await promisifiedScrypt(weakUserPassphrase, salt, 32, { p: 5 }) // {@link <https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#scrypt>}
}
- Extend
cipher
to be an object
cipher: {
alg: "aes-256-cbc",
kdf: "pbkdf2",
iter: 600_000,
/* prf: "hmacWithSHA256" */
// mutually exclusive
alg: "aes-256-cbc",
kdf: "scrypt",
cost: ...,
// same options as with crypto.scrypt
}
- Change the default iterations count to follow OWASP guidelines. This loses parity with OpenSSL defaults, which can be confusing for users, and there is no extensibility in case OWASP removes pbkdf2 from its recommandation. I am strongly against it, but its implementation would seem the less painful of all
What alternatives have you considered?
Install OpenSSL on operating systems that don't provide it (hello Windows) and encrypt with its CLI (via child_process
or a terminal)