Skip to content

Commit 729072d

Browse files
committed
fixup! crypto: add raw key formats support to the KeyObject APIs
1 parent 2d4a181 commit 729072d

File tree

5 files changed

+26
-24
lines changed

5 files changed

+26
-24
lines changed

doc/api/crypto.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,8 @@ repeatedly.
238238
Example: Reusing a [`KeyObject`][] across sign and verify operations:
239239

240240
```mjs
241+
import { promisify } from 'node:util';
241242
const { generateKeyPair, sign, verify } = await import('node:crypto');
242-
const { promisify } = await import('node:util');
243243

244244
const { publicKey, privateKey } = await promisify(generateKeyPair)('ed25519');
245245

@@ -253,10 +253,10 @@ verify(null, data, publicKey, signature);
253253
Example: Importing a PEM-encoded key into a [`KeyObject`][]:
254254

255255
```mjs
256+
import { promisify } from 'node:util';
256257
const {
257258
createPrivateKey, createPublicKey, generateKeyPair, sign, verify,
258259
} = await import('node:crypto');
259-
const { promisify } = await import('node:util');
260260

261261
// PEM-encoded keys, e.g. read from a file or environment variable.
262262
const generated = await promisify(generateKeyPair)('ed25519');
@@ -274,10 +274,10 @@ verify(null, data, publicKey, signature);
274274
Example: Importing a JWK into a [`KeyObject`][]:
275275

276276
```mjs
277+
import { promisify } from 'node:util';
277278
const {
278279
createPrivateKey, createPublicKey, generateKeyPair, sign, verify,
279280
} = await import('node:crypto');
280-
const { promisify } = await import('node:util');
281281

282282
// JWK objects, e.g. from a JSON configuration or API response.
283283
const generated = await promisify(generateKeyPair)('ed25519');
@@ -295,10 +295,10 @@ verify(null, data, publicKey, signature);
295295
Example: Importing a DER-encoded key into a [`KeyObject`][]:
296296

297297
```mjs
298+
import { promisify } from 'node:util';
298299
const {
299300
createPrivateKey, createPublicKey, generateKeyPair, sign, verify,
300301
} = await import('node:crypto');
301-
const { promisify } = await import('node:util');
302302

303303
// DER-encoded keys, e.g. read from binary files or hex/base64url-decoded
304304
// from environment variables.
@@ -326,8 +326,8 @@ Example: Passing PEM strings directly to [`crypto.sign()`][] and
326326
[`crypto.verify()`][]:
327327

328328
```mjs
329+
import { promisify } from 'node:util';
329330
const { generateKeyPair, sign, verify } = await import('node:crypto');
330-
const { promisify } = await import('node:util');
331331

332332
const generated = await promisify(generateKeyPair)('ed25519');
333333
const privatePem = generated.privateKey.export({ format: 'pem', type: 'pkcs8' });
@@ -343,8 +343,8 @@ Example: Passing JWK objects directly to [`crypto.sign()`][] and
343343
[`crypto.verify()`][]:
344344

345345
```mjs
346+
import { promisify } from 'node:util';
346347
const { generateKeyPair, sign, verify } = await import('node:crypto');
347-
const { promisify } = await import('node:util');
348348

349349
const generated = await promisify(generateKeyPair)('ed25519');
350350
const privateJwk = generated.privateKey.export({ format: 'jwk' });
@@ -360,8 +360,8 @@ Example: Passing raw key bytes directly to [`crypto.sign()`][] and
360360
[`crypto.verify()`][]:
361361

362362
```mjs
363+
import { promisify } from 'node:util';
363364
const { generateKeyPair, sign, verify } = await import('node:crypto');
364-
const { promisify } = await import('node:util');
365365

366366
const generated = await promisify(generateKeyPair)('ed25519');
367367
const rawPrivateKey = generated.privateKey.export({ format: 'raw-private' });
@@ -384,10 +384,10 @@ verify(null, data, {
384384
Example: Exporting raw keys and importing them:
385385

386386
```mjs
387+
import { promisify } from 'node:util';
387388
const {
388389
createPrivateKey, createPublicKey, generateKeyPair, sign, verify,
389390
} = await import('node:crypto');
390-
const { promisify } = await import('node:util');
391391

392392
const generated = await promisify(generateKeyPair)('ed25519');
393393

@@ -420,10 +420,10 @@ Example: For EC keys, the `namedCurve` option is required when importing
420420
`'raw-public'` keys:
421421

422422
```mjs
423+
import { promisify } from 'node:util';
423424
const {
424425
createPrivateKey, createPublicKey, generateKeyPair, sign, verify,
425426
} = await import('node:crypto');
426-
const { promisify } = await import('node:util');
427427

428428
const generated = await promisify(generateKeyPair)('ec', {
429429
namedCurve: 'P-256',
@@ -470,10 +470,10 @@ verify('sha256', data, publicKey, signature);
470470
Example: Exporting raw seeds and importing them:
471471

472472
```mjs
473+
import { promisify } from 'node:util';
473474
const {
474475
createPrivateKey, decapsulate, encapsulate, generateKeyPair,
475476
} = await import('node:crypto');
476-
const { promisify } = await import('node:util');
477477

478478
const generated = await promisify(generateKeyPair)('ml-kem-768');
479479

lib/internal/crypto/cfrg.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,9 @@ function cfrgExportKey(key, format) {
203203
try {
204204
switch (format) {
205205
case kWebCryptoKeyFormatRaw: {
206-
if (key[kKeyType] === 'private') {
207-
return TypedArrayPrototypeGetBuffer(key[kKeyObject][kHandle].rawPrivateKey());
208-
}
209-
return TypedArrayPrototypeGetBuffer(key[kKeyObject][kHandle].rawPublicKey());
206+
const handle = key[kKeyObject][kHandle];
207+
return TypedArrayPrototypeGetBuffer(
208+
key[kKeyType] === 'private' ? handle.rawPrivateKey() : handle.rawPublicKey());
210209
}
211210
case kWebCryptoKeyFormatSPKI: {
212211
return TypedArrayPrototypeGetBuffer(

lib/internal/crypto/ec.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ function ecExportKey(key, format) {
163163
// WebCrypto requires uncompressed point format for SPKI exports.
164164
// This is a very rare edge case dependent on the imported key
165165
// using compressed point format.
166+
// Expected SPKI DER byte lengths with uncompressed points:
167+
// P-256: 91 = 26 bytes of SPKI ASN.1 + 65-byte uncompressed point.
168+
// P-384: 120 = 23 bytes of SPKI ASN.1 + 97-byte uncompressed point.
169+
// P-521: 158 = 25 bytes of SPKI ASN.1 + 133-byte uncompressed point.
170+
// Difference in initial SPKI ASN.1 is caused by OIDs and length encoding.
166171
if (TypedArrayPrototypeGetByteLength(spki) !== {
167172
'__proto__': null, 'P-256': 91, 'P-384': 120, 'P-521': 158,
168173
}[key[kAlgorithm].namedCurve]) {

lib/internal/crypto/ml_dsa.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,9 @@ function mlDsaExportKey(key, format) {
122122
try {
123123
switch (format) {
124124
case kWebCryptoKeyFormatRaw: {
125-
if (key[kKeyType] === 'private') {
126-
return TypedArrayPrototypeGetBuffer(key[kKeyObject][kHandle].rawSeed());
127-
}
128-
129-
return TypedArrayPrototypeGetBuffer(key[kKeyObject][kHandle].rawPublicKey());
125+
const handle = key[kKeyObject][kHandle];
126+
return TypedArrayPrototypeGetBuffer(
127+
key[kKeyType] === 'private' ? handle.rawSeed() : handle.rawPublicKey());
130128
}
131129
case kWebCryptoKeyFormatSPKI: {
132130
return TypedArrayPrototypeGetBuffer(key[kKeyObject][kHandle].export(kKeyFormatDER, kWebCryptoKeyFormatSPKI));
@@ -135,6 +133,7 @@ function mlDsaExportKey(key, format) {
135133
const pkcs8 = key[kKeyObject][kHandle].export(kKeyFormatDER, kWebCryptoKeyFormatPKCS8, null, null);
136134
// Edge case only possible when user creates a seedless KeyObject
137135
// first and converts it with KeyObject.prototype.toCryptoKey.
136+
// 54 = 22 bytes of PKCS#8 ASN.1 + 32-byte seed.
138137
if (TypedArrayPrototypeGetByteLength(pkcs8) !== 54) {
139138
throw lazyDOMException(
140139
'The operation failed for an operation-specific reason',

lib/internal/crypto/ml_kem.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,9 @@ function mlKemExportKey(key, format) {
9393
try {
9494
switch (format) {
9595
case kWebCryptoKeyFormatRaw: {
96-
if (key[kKeyType] === 'private') {
97-
return TypedArrayPrototypeGetBuffer(key[kKeyObject][kHandle].rawSeed());
98-
}
99-
100-
return TypedArrayPrototypeGetBuffer(key[kKeyObject][kHandle].rawPublicKey());
96+
const handle = key[kKeyObject][kHandle];
97+
return TypedArrayPrototypeGetBuffer(
98+
key[kKeyType] === 'private' ? handle.rawSeed() : handle.rawPublicKey());
10199
}
102100
case kWebCryptoKeyFormatSPKI: {
103101
return TypedArrayPrototypeGetBuffer(key[kKeyObject][kHandle].export(kKeyFormatDER, kWebCryptoKeyFormatSPKI));
@@ -106,6 +104,7 @@ function mlKemExportKey(key, format) {
106104
const pkcs8 = key[kKeyObject][kHandle].export(kKeyFormatDER, kWebCryptoKeyFormatPKCS8, null, null);
107105
// Edge case only possible when user creates a seedless KeyObject
108106
// first and converts it with KeyObject.prototype.toCryptoKey.
107+
// 86 = 22 bytes of PKCS#8 ASN.1 + 64-byte seed.
109108
if (TypedArrayPrototypeGetByteLength(pkcs8) !== 86) {
110109
throw lazyDOMException(
111110
'The operation failed for an operation-specific reason',

0 commit comments

Comments
 (0)