I am using node.js 22.
The secure curves in webcrypto spec (scroll down to 'Export Key') says raw
is a supported export format for Ed25519:
import { webcrypto } from "node:crypto";
const keyPair = (await webcrypto.subtle.generateKey("Ed25519", true, [
"sign",
"verify",
])) as webcrypto.CryptoKeyPair;
const privateKeyBytes = await webcrypto.subtle.exportKey(
"raw",
keyPair.privateKey,
);
This fails with:
DOMException [InvalidAccessError]: Unable to export a raw Ed25519 private key
at exportKeyRaw (node:internal/crypto/webcrypto:435:9)
at SubtleCrypto.exportKey (node:internal/crypto/webcrypto:520:24)
The message is not particularly helpful - is it saying that this feature is not yet implemented or am I doing something wrong?
Other formats, eg pkcs8
export fine, and I can hack around the problem by manually converting the output, but I'd rather understand what is going wrong.
Only the public Ed25519 key can be exported in raw
format, not the private one.
From Secure Curves in the Web Cryptography API, sec. Export Key, step 3:
If format is "raw":
- If the [[type]] internal slot of key is not "public", then throw an InvalidAccessError.
Other export formats for the public Ed25519 key are spki
and jwk
. The allowed export formats for the private Ed25519 key are pkcs8
and jwk
.
The 32 bytes raw private Ed25519 key can easily be derived from the PKCS#8 key (by removing the Ed25519 PKCS#8 prefix 0x302e020100300506032b657004220420
) or from the private JWK (by Base64url decoding of d
).
E.g. for pkcs8
:
import { webcrypto } from "node:crypto";
const keyPair = (await webcrypto.subtle.generateKey("Ed25519", true, [
"sign",
"verify",
])) as webcrypto.CryptoKeyPair;
const pkcs8Bytes = await webcrypto.subtle.exportKey(
"pkcs8",
keyPair.privateKey,
);
const rawPrivateKeyBytes = pkcs8Bytes.slice(16);