Skip to content

node:crypto: expose KeyObject class, from(), and asymmetric toCryptoKey #2565

@andrewtdiz

Description

@andrewtdiz

Summary

Perry has useful KeyObject-compatible surrogates for selected crypto flows, but it does not expose Node's crypto.KeyObject class/static surface or the full KeyObject#toCryptoKey() conversion behavior. This leaves feature checks such as typeof crypto.KeyObject, typeof crypto.KeyObject.from, key instanceof crypto.KeyObject, and asymmetric-key key.toCryptoKey(...) incompatible even when the underlying key operation itself works.

Evidence

Current Node documents KeyObject as an exported class, says createSecretKey(), createPublicKey(), and createPrivateKey() create KeyObject instances, documents KeyObject.from(key) for converting a CryptoKey back to a KeyObject, and documents keyObject.toCryptoKey(algorithm, extractable, keyUsages) returning a CryptoKey.

A local Node probe confirms the observable shape:

$ NO_COLOR=1 FORCE_COLOR=0 node keyobject-shape.js
typeof KeyObject: function
typeof KeyObject.from: function
secret instanceof KeyObject: true
secret type: secret
secret toCryptoKey typeof: function
private instanceof KeyObject: true
private type: private
private toCryptoKey typeof: function
public instanceof KeyObject: true
public type: public
public toCryptoKey typeof: function

KeyObject.from(CryptoKey) also returns an exportable KeyObject:

KeyObject.from CryptoKey type: secret
KeyObject.from CryptoKey instanceof: true
export hex: 000102030405060708090a0b0c0d0e0f

On origin/main, the manifest and native module value-read table expose crypto factories such as createSecretKey, createPrivateKey, and createPublicKey, but not crypto.KeyObject or crypto.KeyObject.from:

  • crates/perry-api-manifest/src/entries.rs has no class("crypto", "KeyObject") or method("crypto.KeyObject", "from", ...) entry.
  • docs/api/perry.d.ts exports ECDH, X509Certificate, Certificate, and crypto factory functions, but no KeyObject class.
  • crates/perry-runtime/src/object/native_module.rs lists many ("crypto", ...) value reads but no ("crypto", "KeyObject") entry.

The current runtime representation is intentionally surrogate-based:

  • crates/perry-stdlib/src/crypto/keys.rs comments state that createSecretKey() returns a marked BufferHeader even though Node returns a KeyObject.
  • crates/perry-stdlib/src/crypto/sign.rs and crates/perry-runtime/src/object/native_call_method.rs model asymmetric KeyObjects as string-backed PEM/internal surrogates for export/sign/verify flows.
  • crates/perry-runtime/src/object/buffer_dispatch.rs dispatches toCryptoKey only when crate::buffer::is_secret_key(addr) is true; string-backed asymmetric key surrogates have export and equals dispatch, but no toCryptoKey path.
  • test-parity/node-suite/crypto/README.md lists exact CryptoKey / KeyObject.toCryptoKey() asymmetric object identity/prototype behavior as known follow-up work.

Expected compatibility

Perry should provide Node-compatible KeyObject API shape around the existing key implementations:

  • crypto.KeyObject is exported as a class-like value with KeyObject.from(CryptoKey).
  • keys returned by createSecretKey(), createPrivateKey(), createPublicKey(), generateKeySync(), and generateKeyPairSync() have Node-compatible instanceof crypto.KeyObject behavior where feasible.
  • KeyObject.from() converts supported CryptoKey values back to exportable KeyObject-compatible values.
  • keyObject.toCryptoKey() works for supported asymmetric KeyObjects as well as the existing secret-key path, with Node-compatible algorithm/use validation.

Notes

This is separate from #2480's encrypted PEM/DER import/export option work, #2518's WebCrypto algorithm expansion, and #2552's util.types.isKeyObject() predicate tracker. I could not run a fresh Perry binary in this issue-creator checkout; confirmation is from origin/main source, current Node docs, current parity README notes, and local Node probes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions