GeezerVison is showing github.com — crypto: support ML-DSA spki/pkcs8 key formats in Web Cryptography · nodejs/node@4fe383e
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/webcrypto.md +6-6Lines changed: 6 additions & 6 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -939,9 +939,9 @@ specification. | 939 | 939 | | `'Ed25519'` | ✔ | ✔ | ✔ | ✔ | | ✔ | | | 940 | 940 | | `'Ed448'`[^secure-curves] | ✔ | ✔ | ✔ | ✔ | | ✔ | | | 941 | 941 | | `'HMAC'` | | | ✔ | ✔ | ✔ | | | | 942 | | -| `'ML-DSA-44'`[^modern-algos] | | | ✔ | | | ✔ | ✔ | | 943 | | -| `'ML-DSA-65'`[^modern-algos] | | | ✔ | | | ✔ | ✔ | | 944 | | -| `'ML-DSA-87'`[^modern-algos] | | | ✔ | | | ✔ | ✔ | | | 942 | +| `'ML-DSA-44'`[^modern-algos] | ✔ | ✔ | ✔ | | | ✔ | ✔ | | | 943 | +| `'ML-DSA-65'`[^modern-algos] | ✔ | ✔ | ✔ | | | ✔ | ✔ | | | 944 | +| `'ML-DSA-87'`[^modern-algos] | ✔ | ✔ | ✔ | | | ✔ | ✔ | | 945 | 945 | | `'RSA-OAEP'` | ✔ | ✔ | ✔ | | | | | | 946 | 946 | | `'RSA-PSS'` | ✔ | ✔ | ✔ | | | | | | 947 | 947 | | `'RSASSA-PKCS1-v1_5'` | ✔ | ✔ | ✔ | | | | | | @@ -1070,9 +1070,9 @@ The algorithms currently supported include: | 1070 | 1070 | | `'Ed448'`[^secure-curves] | ✔ | ✔ | ✔ | ✔ | | ✔ | | | 1071 | 1071 | | `'HDKF'` | | | | ✔ | ✔ | | | | 1072 | 1072 | | `'HMAC'` | | | ✔ | ✔ | ✔ | | | | 1073 | | -| `'ML-DSA-44'`[^modern-algos] | | | ✔ | | | ✔ | ✔ | | 1074 | | -| `'ML-DSA-65'`[^modern-algos] | | | ✔ | | | ✔ | ✔ | | 1075 | | -| `'ML-DSA-87'`[^modern-algos] | | | ✔ | | | ✔ | ✔ | | | 1073 | +| `'ML-DSA-44'`[^modern-algos] | ✔ | ✔ | ✔ | | | ✔ | ✔ | | | 1074 | +| `'ML-DSA-65'`[^modern-algos] | ✔ | ✔ | ✔ | | | ✔ | ✔ | | | 1075 | +| `'ML-DSA-87'`[^modern-algos] | ✔ | ✔ | ✔ | | | ✔ | ✔ | | 1076 | 1076 | | `'PBKDF2'` | | | | ✔ | ✔ | | | | 1077 | 1077 | | `'RSA-OAEP'` | ✔ | ✔ | ✔ | | | | | | 1078 | 1078 | | `'RSA-PSS'` | ✔ | ✔ | ✔ | | | | | | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/crypto/ml_dsa.js +73-7Lines changed: 73 additions & 7 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 2 | 2 |
| 3 | 3 | const { | 4 | 4 | SafeSet, | | 5 | + Uint8Array, | 5 | 6 | } = primordials; | 6 | 7 |
| 7 | 8 | const { Buffer } = require('buffer'); | @@ -14,6 +15,10 @@ const { | 14 | 15 | kKeyTypePublic, | 15 | 16 | kSignJobModeSign, | 16 | 17 | kSignJobModeVerify, | | 18 | + kKeyFormatDER, | | 19 | + kWebCryptoKeyFormatRaw, | | 20 | + kWebCryptoKeyFormatPKCS8, | | 21 | + kWebCryptoKeyFormatSPKI, | 17 | 22 | } = internalBinding('crypto'); | 18 | 23 |
| 19 | 24 | const { | @@ -44,6 +49,7 @@ const { | 44 | 49 | InternalCryptoKey, | 45 | 50 | PrivateKeyObject, | 46 | 51 | PublicKeyObject, | | 52 | + createPrivateKey, | 47 | 53 | createPublicKey, | 48 | 54 | } = require('internal/crypto/keys'); | 49 | 55 |
| @@ -106,15 +112,47 @@ async function mlDsaGenerateKey(algorithm, extractable, keyUsages) { | 106 | 112 | return { __proto__: null, privateKey, publicKey }; | 107 | 113 | } | 108 | 114 |
| 109 | | -function mlDsaExportKey(key) { | | 115 | +function mlDsaExportKey(key, format) { | 110 | 116 | try { | 111 | | - if (key.type === 'private') { | 112 | | - const { priv } = key[kKeyObject][kHandle].exportJwk({}, false); | 113 | | - return Buffer.alloc(32, priv, 'base64url').buffer; | 114 | | - } | | 117 | + switch (format) { | | 118 | + case kWebCryptoKeyFormatRaw: { | | 119 | + if (key.type === 'private') { | | 120 | + const { priv } = key[kKeyObject][kHandle].exportJwk({}, false); | | 121 | + return Buffer.alloc(32, priv, 'base64url').buffer; | | 122 | + } | 115 | 123 |
| 116 | | - const { pub } = key[kKeyObject][kHandle].exportJwk({}, false); | 117 | | - return Buffer.alloc(Buffer.byteLength(pub, 'base64url'), pub, 'base64url').buffer; | | 124 | + const { pub } = key[kKeyObject][kHandle].exportJwk({}, false); | | 125 | + return Buffer.alloc(Buffer.byteLength(pub, 'base64url'), pub, 'base64url').buffer; | | 126 | + } | | 127 | + case kWebCryptoKeyFormatSPKI: { | | 128 | + return key[kKeyObject][kHandle].export(kKeyFormatDER, kWebCryptoKeyFormatSPKI).buffer; | | 129 | + } | | 130 | + case kWebCryptoKeyFormatPKCS8: { | | 131 | + const { priv } = key[kKeyObject][kHandle].exportJwk({}, false); | | 132 | + const seed = Buffer.alloc(32, priv, 'base64url'); | | 133 | + const buffer = new Uint8Array(54); | | 134 | + buffer.set([ | | 135 | + 0x30, 0x34, 0x02, 0x01, 0x00, 0x30, 0x0B, 0x06, | | 136 | + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, | | 137 | + 0x03, 0x00, 0x04, 0x22, 0x80, 0x20, | | 138 | + ], 0); | | 139 | + switch (key.algorithm.name) { | | 140 | + case 'ML-DSA-44': | | 141 | + buffer.set([0x11], 17); | | 142 | + break; | | 143 | + case 'ML-DSA-65': | | 144 | + buffer.set([0x12], 17); | | 145 | + break; | | 146 | + case 'ML-DSA-87': | | 147 | + buffer.set([0x13], 17); | | 148 | + break; | | 149 | + } | | 150 | + buffer.set(seed, 22); | | 151 | + return buffer.buffer; | | 152 | + } | | 153 | + default: | | 154 | + return undefined; | | 155 | + } | 118 | 156 | } catch (err) { | 119 | 157 | throw lazyDOMException( | 120 | 158 | 'The operation failed for an operation-specific reason', | @@ -138,6 +176,34 @@ function mlDsaImportKey( | 138 | 176 | keyObject = keyData; | 139 | 177 | break; | 140 | 178 | } | | 179 | + case 'spki': { | | 180 | + verifyAcceptableMlDsaKeyUse(name, true, usagesSet); | | 181 | + try { | | 182 | + keyObject = createPublicKey({ | | 183 | + key: keyData, | | 184 | + format: 'der', | | 185 | + type: 'spki', | | 186 | + }); | | 187 | + } catch (err) { | | 188 | + throw lazyDOMException( | | 189 | + 'Invalid keyData', { name: 'DataError', cause: err }); | | 190 | + } | | 191 | + break; | | 192 | + } | | 193 | + case 'pkcs8': { | | 194 | + verifyAcceptableMlDsaKeyUse(name, false, usagesSet); | | 195 | + try { | | 196 | + keyObject = createPrivateKey({ | | 197 | + key: keyData, | | 198 | + format: 'der', | | 199 | + type: 'pkcs8', | | 200 | + }); | | 201 | + } catch (err) { | | 202 | + throw lazyDOMException( | | 203 | + 'Invalid keyData', { name: 'DataError', cause: err }); | | 204 | + } | | 205 | + break; | | 206 | + } | 141 | 207 | case 'jwk': { | 142 | 208 | if (!keyData.kty) | 143 | 209 | throw lazyDOMException('Invalid keyData', 'DataError'); | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/crypto/webcrypto.js +16Lines changed: 16 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -357,6 +357,14 @@ async function exportKeySpki(key) { | 357 | 357 | case 'X448': | 358 | 358 | return require('internal/crypto/cfrg') | 359 | 359 | .cfrgExportKey(key, kWebCryptoKeyFormatSPKI); | | 360 | + case 'ML-DSA-44': | | 361 | + // Fall through | | 362 | + case 'ML-DSA-65': | | 363 | + // Fall through | | 364 | + case 'ML-DSA-87': { | | 365 | + return require('internal/crypto/ml_dsa') | | 366 | + .mlDsaExportKey(key, kWebCryptoKeyFormatSPKI); | | 367 | + } | 360 | 368 | default: | 361 | 369 | return undefined; | 362 | 370 | } | @@ -385,6 +393,14 @@ async function exportKeyPkcs8(key) { | 385 | 393 | case 'X448': | 386 | 394 | return require('internal/crypto/cfrg') | 387 | 395 | .cfrgExportKey(key, kWebCryptoKeyFormatPKCS8); | | 396 | + case 'ML-DSA-44': | | 397 | + // Fall through | | 398 | + case 'ML-DSA-65': | | 399 | + // Fall through | | 400 | + case 'ML-DSA-87': { | | 401 | + return require('internal/crypto/ml_dsa') | | 402 | + .mlDsaExportKey(key, kWebCryptoKeyFormatPKCS8); | | 403 | + } | 388 | 404 | default: | 389 | 405 | return undefined; | 390 | 406 | } | |
|