Skip to content

fix(ext/node): improve Node.js crypto compatibility#32690

Merged
bartlomieju merged 12 commits intodenoland:mainfrom
bartlomieju:fix/crypto-oaep-zero-length
Mar 17, 2026
Merged

fix(ext/node): improve Node.js crypto compatibility#32690
bartlomieju merged 12 commits intodenoland:mainfrom
bartlomieju:fix/crypto-oaep-zero-length

Conversation

@bartlomieju
Copy link
Copy Markdown
Member

@bartlomieju bartlomieju commented Mar 13, 2026

Summary

  • Implement crypto.publicDecrypt and fix crypto.privateEncrypt to use correct RSA private key operation (PKCS1 type 1 padding)
  • Support KeyObject in publicEncrypt/privateDecrypt options object
  • Support options object in crypto.hash() for XOF digests (shake128/shake256)
  • Use proper NodeError class with OpenSSL-compatible error codes and reason property for cipher padding errors (ERR_OSSL_EVP_WRONG_FINAL_BLOCK_LENGTH, ERR_OSSL_EVP_BAD_DECRYPT)
  • Fix RSA-PSS asymmetricKeyDetails to use camelCase property names and enable SPKI DER export
  • Fix JWK export error messages/codes for unsupported EC curves and key types

Newly passing Node.js compat tests

  • test-crypto-oaep-zero-length.js
  • test-crypto-oneshot-hash-xof.js
  • test-crypto-padding.js
  • test-crypto-keygen-no-rsassa-pss-params.js
  • test-crypto-keygen-invalid-parameter-encoding-ec.js
  • test-crypto-keygen-invalid-parameter-encoding-dsa.js

Note: test-crypto-publicDecrypt-fails-first-time.js requires encrypted PEM export support (cipher+passphrase in privateKeyEncoding) which is not yet implemented — left as a TODO.

Test plan

  • All newly enabled Node.js compat tests pass
  • Existing cipher unit tests pass (./x test-node crypto_cipher)
  • Format and lint clean

🤖 Generated with Claude Code

bartlomieju and others added 8 commits March 13, 2026 15:07
When passing an options object like `{ key: keyObject, padding: ... }`
to `crypto.publicEncrypt` or `crypto.privateDecrypt`, the `prepareKey`
function now correctly handles `KeyObject` instances in the `key`
property. Previously it only accepted strings and buffers, throwing
"Invalid key type" for KeyObjects.

Enables the `test-crypto-oaep-zero-length.js` Node.js compat test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The `crypto.hash()` function now accepts an options object as the third
argument with `outputEncoding` and `outputLength` properties, matching
Node.js behavior. This enables XOF hash functions (SHAKE128/256) to
specify custom output lengths via `crypto.hash()`.

For non-XOF algorithms, validates that `outputLength` matches the
algorithm's actual digest size, throwing a descriptive error otherwise.

Enables the `test-crypto-oneshot-hash-xof.js` Node.js compat test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…errors

Match Node.js error format for cipher/decipher padding errors by using
proper OpenSSL error codes (ERR_OSSL_EVP_WRONG_FINAL_BLOCK_LENGTH,
ERR_OSSL_EVP_BAD_DECRYPT) and adding reason property to errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement crypto.publicDecrypt using raw RSA public key operation with
PKCS1 type 1 unpadding. Fix privateEncrypt to use actual private key
RSA operation instead of incorrectly delegating to public key encrypt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix asymmetricKeyDetails for RSA-PSS keys without params to use
camelCase property names (modulusLength, publicExponent) by adding
missing serde rename_all attribute. Implement RSA-PSS public key
SPKI DER export.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d curves/key types

Use Node.js-compatible error codes (ERR_CRYPTO_JWK_UNSUPPORTED_CURVE,
ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE) and messages for JWK export
errors. Change error class from TypeError to Error to match Node.js.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Default DSA divisorLength to 160 for modulusLength <= 1024 to match
OpenSSL/Node.js behavior. Fix clippy needless-range-loop warning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@bartlomieju bartlomieju requested a review from littledivy March 14, 2026 06:59
…ecrypt

KeyObject was listed in the buffer parameter type but never handled —
getArrayBufferOrView would throw at runtime. The buffer parameter is
data to encrypt/decrypt, not a key.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@kajukitli kajukitli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the changes. No issues found.

Copy link
Copy Markdown
Member

@nathanwhit nathanwhit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM aside from not using proper node errors

if (!this._autoPadding && this._cache.cache.byteLength != bs) {
throw new Error("Invalid final block size");
const err = new Error("wrong final block length");
(err as any).code = "ERR_OSSL_EVP_WRONG_FINAL_BLOCK_LENGTH";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a proper node error class instead of just a plain error

Copy link
Copy Markdown
Member

@littledivy littledivy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good

bartlomieju and others added 3 commits March 17, 2026 08:16
Use proper NodeError class instead of plain Error with manual .code
assignment for cipher final block and decrypt errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Node.js tests expect a `reason` property on OpenSSL-style errors.
Add an opensslError helper that creates a NodeError and sets reason.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This test requires encrypted PEM export support (cipher+passphrase
in privateKeyEncoding) which is not yet implemented.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bartlomieju bartlomieju enabled auto-merge (squash) March 17, 2026 11:20
@bartlomieju bartlomieju merged commit 4b0474c into denoland:main Mar 17, 2026
221 of 223 checks passed
@bartlomieju bartlomieju deleted the fix/crypto-oaep-zero-length branch March 17, 2026 11:53
Copy link
Copy Markdown
Contributor

@kajukitli kajukitli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the changes with full repo context. No issues found.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants