Skip to content

Customize password-based KDF in KeyObject#export #53359

Open
@Phoenix35

Description

@Phoenix35

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

  1. A derivedKey parameter that excludes passphrase. In this case, no KDF is performed, and it is strongly emphasised to pass a key derived with scrypt, pbkdf2, or argon2id (node.js support one day 🤞) (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>}
}
  1. 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
}
  1. 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)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    cryptoIssues and PRs related to the crypto subsystem.feature requestIssues that request new features to be added to Node.js.

    Type

    No type

    Projects

    • Status

      Awaiting Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions