react-native-quick-crypto 1.0.11 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/CMakeLists.txt +7 -0
- package/cpp/cipher/CCMCipher.cpp +4 -1
- package/cpp/cipher/ChaCha20Cipher.cpp +3 -1
- package/cpp/cipher/ChaCha20Poly1305Cipher.cpp +5 -5
- package/cpp/cipher/ChaCha20Poly1305Cipher.hpp +1 -2
- package/cpp/cipher/HybridCipher.cpp +10 -1
- package/cpp/cipher/HybridCipher.hpp +2 -0
- package/cpp/cipher/HybridRsaCipher.cpp +0 -13
- package/cpp/cipher/XChaCha20Poly1305Cipher.cpp +7 -5
- package/cpp/cipher/XChaCha20Poly1305Cipher.hpp +1 -2
- package/cpp/cipher/XSalsa20Cipher.cpp +4 -0
- package/cpp/cipher/XSalsa20Poly1305Cipher.cpp +7 -5
- package/cpp/cipher/XSalsa20Poly1305Cipher.hpp +1 -2
- package/cpp/ecdh/HybridECDH.cpp +20 -133
- package/cpp/keys/HybridKeyObjectHandle.cpp +144 -141
- package/cpp/keys/HybridKeyObjectHandle.hpp +6 -3
- package/cpp/keys/KeyObjectData.hpp +2 -0
- package/cpp/kmac/HybridKmac.cpp +83 -0
- package/cpp/kmac/HybridKmac.hpp +31 -0
- package/cpp/mldsa/HybridMlDsaKeyPair.cpp +11 -20
- package/cpp/mldsa/HybridMlDsaKeyPair.hpp +4 -2
- package/cpp/mlkem/HybridMlKemKeyPair.cpp +319 -0
- package/cpp/mlkem/HybridMlKemKeyPair.hpp +48 -0
- package/cpp/sign/SignUtils.hpp +9 -26
- package/cpp/utils/QuickCryptoUtils.cpp +44 -0
- package/cpp/utils/QuickCryptoUtils.hpp +39 -0
- package/cpp/x509/HybridX509Certificate.cpp +174 -0
- package/cpp/x509/HybridX509Certificate.hpp +51 -0
- package/lib/commonjs/cipher.js +15 -2
- package/lib/commonjs/cipher.js.map +1 -1
- package/lib/commonjs/dhKeyPair.js +3 -3
- package/lib/commonjs/dhKeyPair.js.map +1 -1
- package/lib/commonjs/dsa.js +3 -3
- package/lib/commonjs/dsa.js.map +1 -1
- package/lib/commonjs/ec.js +18 -18
- package/lib/commonjs/ec.js.map +1 -1
- package/lib/commonjs/ed.js +9 -9
- package/lib/commonjs/ed.js.map +1 -1
- package/lib/commonjs/hash.js +17 -12
- package/lib/commonjs/hash.js.map +1 -1
- package/lib/commonjs/hkdf.js.map +1 -1
- package/lib/commonjs/index.js +22 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/keys/classes.js +2 -2
- package/lib/commonjs/keys/classes.js.map +1 -1
- package/lib/commonjs/keys/index.js +24 -0
- package/lib/commonjs/keys/index.js.map +1 -1
- package/lib/commonjs/keys/publicCipher.js +2 -2
- package/lib/commonjs/keys/publicCipher.js.map +1 -1
- package/lib/commonjs/keys/signVerify.js +0 -2
- package/lib/commonjs/keys/signVerify.js.map +1 -1
- package/lib/commonjs/mlkem.js +219 -0
- package/lib/commonjs/mlkem.js.map +1 -0
- package/lib/commonjs/pbkdf2.js +18 -1
- package/lib/commonjs/pbkdf2.js.map +1 -1
- package/lib/commonjs/rsa.js +7 -7
- package/lib/commonjs/rsa.js.map +1 -1
- package/lib/commonjs/specs/kmac.nitro.js +6 -0
- package/lib/commonjs/specs/kmac.nitro.js.map +1 -0
- package/lib/commonjs/specs/mlKemKeyPair.nitro.js +6 -0
- package/lib/commonjs/specs/mlKemKeyPair.nitro.js.map +1 -0
- package/lib/commonjs/specs/x509certificate.nitro.js +6 -0
- package/lib/commonjs/specs/x509certificate.nitro.js.map +1 -0
- package/lib/commonjs/subtle.js +292 -112
- package/lib/commonjs/subtle.js.map +1 -1
- package/lib/commonjs/utils/conversion.js +3 -3
- package/lib/commonjs/utils/conversion.js.map +1 -1
- package/lib/commonjs/utils/hashnames.js +31 -0
- package/lib/commonjs/utils/hashnames.js.map +1 -1
- package/lib/commonjs/utils/types.js.map +1 -1
- package/lib/commonjs/x509certificate.js +189 -0
- package/lib/commonjs/x509certificate.js.map +1 -0
- package/lib/module/cipher.js +16 -3
- package/lib/module/cipher.js.map +1 -1
- package/lib/module/dhKeyPair.js +1 -1
- package/lib/module/dhKeyPair.js.map +1 -1
- package/lib/module/dsa.js +1 -1
- package/lib/module/dsa.js.map +1 -1
- package/lib/module/ec.js +6 -6
- package/lib/module/ec.js.map +1 -1
- package/lib/module/ed.js +1 -1
- package/lib/module/ed.js.map +1 -1
- package/lib/module/hash.js +17 -12
- package/lib/module/hash.js.map +1 -1
- package/lib/module/hkdf.js.map +1 -1
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/keys/classes.js +2 -2
- package/lib/module/keys/classes.js.map +1 -1
- package/lib/module/keys/index.js +25 -1
- package/lib/module/keys/index.js.map +1 -1
- package/lib/module/keys/publicCipher.js +2 -2
- package/lib/module/keys/publicCipher.js.map +1 -1
- package/lib/module/keys/signVerify.js +0 -2
- package/lib/module/keys/signVerify.js.map +1 -1
- package/lib/module/mlkem.js +211 -0
- package/lib/module/mlkem.js.map +1 -0
- package/lib/module/pbkdf2.js +18 -1
- package/lib/module/pbkdf2.js.map +1 -1
- package/lib/module/rsa.js +1 -1
- package/lib/module/rsa.js.map +1 -1
- package/lib/module/specs/kmac.nitro.js +4 -0
- package/lib/module/specs/kmac.nitro.js.map +1 -0
- package/lib/module/specs/mlKemKeyPair.nitro.js +4 -0
- package/lib/module/specs/mlKemKeyPair.nitro.js.map +1 -0
- package/lib/module/specs/x509certificate.nitro.js +4 -0
- package/lib/module/specs/x509certificate.nitro.js.map +1 -0
- package/lib/module/subtle.js +292 -112
- package/lib/module/subtle.js.map +1 -1
- package/lib/module/utils/conversion.js +3 -4
- package/lib/module/utils/conversion.js.map +1 -1
- package/lib/module/utils/hashnames.js +31 -0
- package/lib/module/utils/hashnames.js.map +1 -1
- package/lib/module/utils/types.js.map +1 -1
- package/lib/module/x509certificate.js +184 -0
- package/lib/module/x509certificate.js.map +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/typescript/cipher.d.ts +3 -0
- package/lib/typescript/cipher.d.ts.map +1 -1
- package/lib/typescript/dhKeyPair.d.ts +1 -1
- package/lib/typescript/dhKeyPair.d.ts.map +1 -1
- package/lib/typescript/dsa.d.ts +1 -1
- package/lib/typescript/dsa.d.ts.map +1 -1
- package/lib/typescript/ec.d.ts +1 -1
- package/lib/typescript/ec.d.ts.map +1 -1
- package/lib/typescript/ed.d.ts +1 -1
- package/lib/typescript/ed.d.ts.map +1 -1
- package/lib/typescript/hash.d.ts.map +1 -1
- package/lib/typescript/hkdf.d.ts +2 -6
- package/lib/typescript/hkdf.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +15 -4
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/keys/classes.d.ts +5 -5
- package/lib/typescript/keys/classes.d.ts.map +1 -1
- package/lib/typescript/keys/index.d.ts +2 -2
- package/lib/typescript/keys/index.d.ts.map +1 -1
- package/lib/typescript/keys/signVerify.d.ts.map +1 -1
- package/lib/typescript/mlkem.d.ts +30 -0
- package/lib/typescript/mlkem.d.ts.map +1 -0
- package/lib/typescript/pbkdf2.d.ts +2 -2
- package/lib/typescript/pbkdf2.d.ts.map +1 -1
- package/lib/typescript/rsa.d.ts +1 -1
- package/lib/typescript/rsa.d.ts.map +1 -1
- package/lib/typescript/specs/keyObjectHandle.nitro.d.ts +1 -0
- package/lib/typescript/specs/keyObjectHandle.nitro.d.ts.map +1 -1
- package/lib/typescript/specs/kmac.nitro.d.ts +10 -0
- package/lib/typescript/specs/kmac.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/mlKemKeyPair.nitro.d.ts +18 -0
- package/lib/typescript/specs/mlKemKeyPair.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/x509certificate.nitro.d.ts +34 -0
- package/lib/typescript/specs/x509certificate.nitro.d.ts.map +1 -0
- package/lib/typescript/subtle.d.ts +10 -0
- package/lib/typescript/subtle.d.ts.map +1 -1
- package/lib/typescript/utils/conversion.d.ts.map +1 -1
- package/lib/typescript/utils/hashnames.d.ts +1 -1
- package/lib/typescript/utils/hashnames.d.ts.map +1 -1
- package/lib/typescript/utils/types.d.ts +13 -7
- package/lib/typescript/utils/types.d.ts.map +1 -1
- package/lib/typescript/x509certificate.d.ts +64 -0
- package/lib/typescript/x509certificate.d.ts.map +1 -0
- package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +3 -0
- package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +30 -0
- package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +30 -0
- package/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp +12 -0
- package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp +1 -0
- package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp +1 -0
- package/nitrogen/generated/shared/c++/HybridKmacSpec.cpp +23 -0
- package/nitrogen/generated/shared/c++/HybridKmacSpec.hpp +66 -0
- package/nitrogen/generated/shared/c++/HybridMlKemKeyPairSpec.cpp +31 -0
- package/nitrogen/generated/shared/c++/HybridMlKemKeyPairSpec.hpp +74 -0
- package/nitrogen/generated/shared/c++/HybridX509CertificateHandleSpec.cpp +46 -0
- package/nitrogen/generated/shared/c++/HybridX509CertificateHandleSpec.hpp +96 -0
- package/package.json +4 -1
- package/src/cipher.ts +17 -3
- package/src/dhKeyPair.ts +1 -1
- package/src/dsa.ts +1 -1
- package/src/ec.ts +9 -9
- package/src/ed.ts +2 -2
- package/src/hash.ts +34 -11
- package/src/hkdf.ts +2 -7
- package/src/index.ts +7 -0
- package/src/keys/classes.ts +10 -9
- package/src/keys/index.ts +37 -2
- package/src/keys/publicCipher.ts +2 -2
- package/src/keys/signVerify.ts +0 -5
- package/src/mlkem.ts +350 -0
- package/src/pbkdf2.ts +34 -5
- package/src/rsa.ts +1 -1
- package/src/specs/keyObjectHandle.nitro.ts +5 -0
- package/src/specs/kmac.nitro.ts +12 -0
- package/src/specs/mlKemKeyPair.nitro.ts +32 -0
- package/src/specs/x509certificate.nitro.ts +38 -0
- package/src/subtle.ts +551 -125
- package/src/utils/conversion.ts +10 -4
- package/src/utils/hashnames.ts +33 -2
- package/src/utils/types.ts +42 -5
- package/src/x509certificate.ts +277 -0
package/lib/module/subtle.js
CHANGED
|
@@ -17,9 +17,11 @@ import { ecImportKey, ecdsaSignVerify, ec_generateKeyPair, ecDeriveBits } from '
|
|
|
17
17
|
import { rsa_generateKeyPair } from './rsa';
|
|
18
18
|
import { getRandomValues } from './random';
|
|
19
19
|
import { createHmac } from './hmac';
|
|
20
|
+
import { timingSafeEqual } from './utils/timingSafeEqual';
|
|
20
21
|
import { createSign, createVerify } from './keys/signVerify';
|
|
21
22
|
import { ed_generateKeyPairWebCrypto, x_generateKeyPairWebCrypto, xDeriveBits, Ed } from './ed';
|
|
22
23
|
import { mldsa_generateKeyPairWebCrypto } from './mldsa';
|
|
24
|
+
import { mlkem_generateKeyPairWebCrypto, MlKem } from './mlkem';
|
|
23
25
|
import { hkdfDeriveBits } from './hkdf';
|
|
24
26
|
// Temporary enums that need to be defined
|
|
25
27
|
var KWebCryptoKeyFormat = /*#__PURE__*/function (KWebCryptoKeyFormat) {
|
|
@@ -483,6 +485,100 @@ async function hmacGenerateKey(algorithm, extractable, keyUsages) {
|
|
|
483
485
|
};
|
|
484
486
|
return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
|
|
485
487
|
}
|
|
488
|
+
async function kmacGenerateKey(algorithm, extractable, keyUsages) {
|
|
489
|
+
const {
|
|
490
|
+
name
|
|
491
|
+
} = algorithm;
|
|
492
|
+
if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
|
|
493
|
+
throw lazyDOMException(`Unsupported key usage for ${name} key`, 'SyntaxError');
|
|
494
|
+
}
|
|
495
|
+
const defaultLength = name === 'KMAC128' ? 128 : 256;
|
|
496
|
+
const length = algorithm.length ?? defaultLength;
|
|
497
|
+
if (length === 0) {
|
|
498
|
+
throw lazyDOMException('Zero-length key is not supported', 'OperationError');
|
|
499
|
+
}
|
|
500
|
+
const keyBytes = new Uint8Array(Math.ceil(length / 8));
|
|
501
|
+
getRandomValues(keyBytes);
|
|
502
|
+
const keyObject = createSecretKey(keyBytes);
|
|
503
|
+
const keyAlgorithm = {
|
|
504
|
+
name: name,
|
|
505
|
+
length
|
|
506
|
+
};
|
|
507
|
+
return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
|
|
508
|
+
}
|
|
509
|
+
function kmacSignVerify(key, data, algorithm, signature) {
|
|
510
|
+
const {
|
|
511
|
+
name
|
|
512
|
+
} = algorithm;
|
|
513
|
+
const defaultLength = name === 'KMAC128' ? 256 : 512;
|
|
514
|
+
const outputLengthBits = algorithm.length ?? defaultLength;
|
|
515
|
+
if (outputLengthBits % 8 !== 0) {
|
|
516
|
+
throw lazyDOMException('KMAC output length must be a multiple of 8', 'OperationError');
|
|
517
|
+
}
|
|
518
|
+
const outputLengthBytes = outputLengthBits / 8;
|
|
519
|
+
const keyData = key.keyObject.export();
|
|
520
|
+
const kmac = NitroModules.createHybridObject('Kmac');
|
|
521
|
+
let customizationBuffer;
|
|
522
|
+
if (algorithm.customization !== undefined) {
|
|
523
|
+
customizationBuffer = bufferLikeToArrayBuffer(algorithm.customization);
|
|
524
|
+
}
|
|
525
|
+
kmac.createKmac(name, bufferLikeToArrayBuffer(keyData), outputLengthBytes, customizationBuffer);
|
|
526
|
+
kmac.update(bufferLikeToArrayBuffer(data));
|
|
527
|
+
const computed = kmac.digest();
|
|
528
|
+
if (signature === undefined) {
|
|
529
|
+
return computed;
|
|
530
|
+
}
|
|
531
|
+
const sigBuffer = bufferLikeToArrayBuffer(signature);
|
|
532
|
+
if (computed.byteLength !== sigBuffer.byteLength) {
|
|
533
|
+
return false;
|
|
534
|
+
}
|
|
535
|
+
return timingSafeEqual(new Uint8Array(computed), new Uint8Array(sigBuffer));
|
|
536
|
+
}
|
|
537
|
+
async function kmacImportKey(algorithm, format, data, extractable, keyUsages) {
|
|
538
|
+
const {
|
|
539
|
+
name
|
|
540
|
+
} = algorithm;
|
|
541
|
+
if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
|
|
542
|
+
throw lazyDOMException(`Unsupported key usage for ${name} key`, 'SyntaxError');
|
|
543
|
+
}
|
|
544
|
+
let keyObject;
|
|
545
|
+
if (format === 'jwk') {
|
|
546
|
+
const jwk = data;
|
|
547
|
+
if (!jwk || typeof jwk !== 'object') {
|
|
548
|
+
throw lazyDOMException('Invalid keyData', 'DataError');
|
|
549
|
+
}
|
|
550
|
+
if (jwk.kty !== 'oct') {
|
|
551
|
+
throw lazyDOMException('Invalid JWK format for KMAC key', 'DataError');
|
|
552
|
+
}
|
|
553
|
+
const expectedAlg = name === 'KMAC128' ? 'K128' : 'K256';
|
|
554
|
+
if (jwk.alg !== undefined && jwk.alg !== expectedAlg) {
|
|
555
|
+
throw lazyDOMException('JWK "alg" does not match the requested algorithm', 'DataError');
|
|
556
|
+
}
|
|
557
|
+
const handle = NitroModules.createHybridObject('KeyObjectHandle');
|
|
558
|
+
const keyType = handle.initJwk(jwk, undefined);
|
|
559
|
+
if (keyType === undefined || keyType !== 0) {
|
|
560
|
+
throw lazyDOMException('Failed to import KMAC JWK', 'DataError');
|
|
561
|
+
}
|
|
562
|
+
keyObject = new SecretKeyObject(handle);
|
|
563
|
+
} else if (format === 'raw' || format === 'raw-secret') {
|
|
564
|
+
keyObject = createSecretKey(data);
|
|
565
|
+
} else {
|
|
566
|
+
throw lazyDOMException(`Unable to import ${name} key with format ${format}`, 'NotSupportedError');
|
|
567
|
+
}
|
|
568
|
+
const exported = keyObject.export();
|
|
569
|
+
const keyLength = exported.byteLength * 8;
|
|
570
|
+
if (keyLength === 0) {
|
|
571
|
+
throw lazyDOMException('Zero-length key is not supported', 'DataError');
|
|
572
|
+
}
|
|
573
|
+
if (algorithm.length !== undefined && algorithm.length !== keyLength) {
|
|
574
|
+
throw lazyDOMException('Invalid key length', 'DataError');
|
|
575
|
+
}
|
|
576
|
+
const keyAlgorithm = {
|
|
577
|
+
name: name,
|
|
578
|
+
length: keyLength
|
|
579
|
+
};
|
|
580
|
+
return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
|
|
581
|
+
}
|
|
486
582
|
function rsaImportKey(format, data, algorithm, extractable, keyUsages) {
|
|
487
583
|
const {
|
|
488
584
|
name
|
|
@@ -720,28 +816,48 @@ function edImportKey(format, data, algorithm, extractable, keyUsages) {
|
|
|
720
816
|
name
|
|
721
817
|
}, keyUsages, extractable);
|
|
722
818
|
}
|
|
819
|
+
function pqcImportKeyObject(format, data, name) {
|
|
820
|
+
if (format === 'spki') {
|
|
821
|
+
return KeyObject.createKeyObject('public', bufferLikeToArrayBuffer(data), KFormatType.DER, KeyEncoding.SPKI);
|
|
822
|
+
} else if (format === 'pkcs8') {
|
|
823
|
+
return KeyObject.createKeyObject('private', bufferLikeToArrayBuffer(data), KFormatType.DER, KeyEncoding.PKCS8);
|
|
824
|
+
} else if (format === 'raw') {
|
|
825
|
+
const handle = NitroModules.createHybridObject('KeyObjectHandle');
|
|
826
|
+
if (!handle.initPqcRaw(name, bufferLikeToArrayBuffer(data), true)) {
|
|
827
|
+
throw lazyDOMException(`Failed to import ${name} raw public key`, 'DataError');
|
|
828
|
+
}
|
|
829
|
+
return new PublicKeyObject(handle);
|
|
830
|
+
} else if (format === 'raw-seed') {
|
|
831
|
+
const handle = NitroModules.createHybridObject('KeyObjectHandle');
|
|
832
|
+
if (!handle.initPqcRaw(name, bufferLikeToArrayBuffer(data), false)) {
|
|
833
|
+
throw lazyDOMException(`Failed to import ${name} raw seed`, 'DataError');
|
|
834
|
+
}
|
|
835
|
+
return new PrivateKeyObject(handle);
|
|
836
|
+
}
|
|
837
|
+
throw lazyDOMException(`Unsupported format for ${name} import: ${format}`, 'NotSupportedError');
|
|
838
|
+
}
|
|
723
839
|
function mldsaImportKey(format, data, algorithm, extractable, keyUsages) {
|
|
724
840
|
const {
|
|
725
841
|
name
|
|
726
842
|
} = algorithm;
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
|
|
843
|
+
const isPublicFormat = format === 'spki' || format === 'raw';
|
|
844
|
+
if (hasAnyNotIn(keyUsages, isPublicFormat ? ['verify'] : ['sign'])) {
|
|
730
845
|
throw lazyDOMException(`Unsupported key usage for ${name} key`, 'SyntaxError');
|
|
731
846
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
847
|
+
return new CryptoKey(pqcImportKeyObject(format, data, name), {
|
|
848
|
+
name
|
|
849
|
+
}, keyUsages, extractable);
|
|
850
|
+
}
|
|
851
|
+
function mlkemImportKey(format, data, algorithm, extractable, keyUsages) {
|
|
852
|
+
const {
|
|
853
|
+
name
|
|
854
|
+
} = algorithm;
|
|
855
|
+
const isPublicFormat = format === 'spki' || format === 'raw';
|
|
856
|
+
const allowedUsages = isPublicFormat ? ['encapsulateBits', 'encapsulateKey'] : ['decapsulateBits', 'decapsulateKey'];
|
|
857
|
+
if (hasAnyNotIn(keyUsages, allowedUsages)) {
|
|
858
|
+
throw lazyDOMException(`Unsupported key usage for ${name} key`, 'SyntaxError');
|
|
743
859
|
}
|
|
744
|
-
return new CryptoKey(
|
|
860
|
+
return new CryptoKey(pqcImportKeyObject(format, data, name), {
|
|
745
861
|
name
|
|
746
862
|
}, keyUsages, extractable);
|
|
747
863
|
}
|
|
@@ -785,6 +901,15 @@ const exportKeySpki = async key => {
|
|
|
785
901
|
return bufferLikeToArrayBuffer(key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.SPKI));
|
|
786
902
|
}
|
|
787
903
|
break;
|
|
904
|
+
case 'ML-KEM-512':
|
|
905
|
+
// Fall through
|
|
906
|
+
case 'ML-KEM-768':
|
|
907
|
+
// Fall through
|
|
908
|
+
case 'ML-KEM-1024':
|
|
909
|
+
if (key.type === 'public') {
|
|
910
|
+
return bufferLikeToArrayBuffer(key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.SPKI));
|
|
911
|
+
}
|
|
912
|
+
break;
|
|
788
913
|
}
|
|
789
914
|
throw new Error(`Unable to export a spki ${key.algorithm.name} ${key.type} key`);
|
|
790
915
|
};
|
|
@@ -828,6 +953,15 @@ const exportKeyPkcs8 = async key => {
|
|
|
828
953
|
return bufferLikeToArrayBuffer(key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.PKCS8));
|
|
829
954
|
}
|
|
830
955
|
break;
|
|
956
|
+
case 'ML-KEM-512':
|
|
957
|
+
// Fall through
|
|
958
|
+
case 'ML-KEM-768':
|
|
959
|
+
// Fall through
|
|
960
|
+
case 'ML-KEM-1024':
|
|
961
|
+
if (key.type === 'private') {
|
|
962
|
+
return bufferLikeToArrayBuffer(key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.PKCS8));
|
|
963
|
+
}
|
|
964
|
+
break;
|
|
831
965
|
}
|
|
832
966
|
throw new Error(`Unable to export a pkcs8 ${key.algorithm.name} ${key.type} key`);
|
|
833
967
|
};
|
|
@@ -848,7 +982,22 @@ const exportKeyRaw = key => {
|
|
|
848
982
|
// Fall through
|
|
849
983
|
case 'X448':
|
|
850
984
|
if (key.type === 'public') {
|
|
851
|
-
|
|
985
|
+
const exported = key.keyObject.handle.exportKey();
|
|
986
|
+
return bufferLikeToArrayBuffer(exported);
|
|
987
|
+
}
|
|
988
|
+
break;
|
|
989
|
+
case 'ML-KEM-512':
|
|
990
|
+
// Fall through
|
|
991
|
+
case 'ML-KEM-768':
|
|
992
|
+
// Fall through
|
|
993
|
+
case 'ML-KEM-1024':
|
|
994
|
+
// Fall through
|
|
995
|
+
case 'ML-DSA-44':
|
|
996
|
+
// Fall through
|
|
997
|
+
case 'ML-DSA-65':
|
|
998
|
+
// Fall through
|
|
999
|
+
case 'ML-DSA-87':
|
|
1000
|
+
if (key.type === 'public') {
|
|
852
1001
|
const exported = key.keyObject.handle.exportKey();
|
|
853
1002
|
return bufferLikeToArrayBuffer(exported);
|
|
854
1003
|
}
|
|
@@ -866,6 +1015,10 @@ const exportKeyRaw = key => {
|
|
|
866
1015
|
case 'ChaCha20-Poly1305':
|
|
867
1016
|
// Fall through
|
|
868
1017
|
case 'HMAC':
|
|
1018
|
+
// Fall through
|
|
1019
|
+
case 'KMAC128':
|
|
1020
|
+
// Fall through
|
|
1021
|
+
case 'KMAC256':
|
|
869
1022
|
{
|
|
870
1023
|
const exported = key.keyObject.export();
|
|
871
1024
|
// Convert Buffer to ArrayBuffer
|
|
@@ -892,6 +1045,12 @@ const exportKeyJWK = key => {
|
|
|
892
1045
|
case 'HMAC':
|
|
893
1046
|
jwk.alg = normalizeHashName(key.algorithm.hash, HashContext.JwkHmac);
|
|
894
1047
|
return jwk;
|
|
1048
|
+
case 'KMAC128':
|
|
1049
|
+
jwk.alg = 'K128';
|
|
1050
|
+
return jwk;
|
|
1051
|
+
case 'KMAC256':
|
|
1052
|
+
jwk.alg = 'K256';
|
|
1053
|
+
return jwk;
|
|
895
1054
|
case 'ECDSA':
|
|
896
1055
|
// Fall through
|
|
897
1056
|
case 'ECDH':
|
|
@@ -1030,20 +1189,12 @@ function hmacSignVerify(key, data, signature) {
|
|
|
1030
1189
|
// Sign operation - return the HMAC as ArrayBuffer
|
|
1031
1190
|
return computed.buffer.slice(computed.byteOffset, computed.byteOffset + computed.byteLength);
|
|
1032
1191
|
}
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
const computedBytes = new Uint8Array(computed.buffer, computed.byteOffset, computed.byteLength);
|
|
1037
|
-
if (computedBytes.length !== sigBytes.length) {
|
|
1192
|
+
const sigBuffer = bufferLikeToArrayBuffer(signature);
|
|
1193
|
+
const computedBuffer = computed.buffer.slice(computed.byteOffset, computed.byteOffset + computed.byteLength);
|
|
1194
|
+
if (computedBuffer.byteLength !== sigBuffer.byteLength) {
|
|
1038
1195
|
return false;
|
|
1039
1196
|
}
|
|
1040
|
-
|
|
1041
|
-
// Constant-time comparison to prevent timing attacks
|
|
1042
|
-
let result = 0;
|
|
1043
|
-
for (let i = 0; i < computedBytes.length; i++) {
|
|
1044
|
-
result |= computedBytes[i] ^ sigBytes[i];
|
|
1045
|
-
}
|
|
1046
|
-
return result === 0;
|
|
1197
|
+
return timingSafeEqual(new Uint8Array(computedBuffer), new Uint8Array(sigBuffer));
|
|
1047
1198
|
}
|
|
1048
1199
|
function rsaSignVerify(key, data, padding, signature, saltLength) {
|
|
1049
1200
|
// Get hash algorithm from key
|
|
@@ -1146,6 +1297,9 @@ const signVerify = (algorithm, key, data, signature) => {
|
|
|
1146
1297
|
case 'ML-DSA-65':
|
|
1147
1298
|
case 'ML-DSA-87':
|
|
1148
1299
|
return mldsaSignVerify(key, data, signature);
|
|
1300
|
+
case 'KMAC128':
|
|
1301
|
+
case 'KMAC256':
|
|
1302
|
+
return kmacSignVerify(key, data, algorithm, signature);
|
|
1149
1303
|
}
|
|
1150
1304
|
throw lazyDOMException(`Unrecognized algorithm name '${algorithm.name}' for '${usage}'`, 'NotSupportedError');
|
|
1151
1305
|
};
|
|
@@ -1174,17 +1328,21 @@ const cipherOrWrap = async (mode, algorithm, key, data, op) => {
|
|
|
1174
1328
|
const SUPPORTED_ALGORITHMS = {
|
|
1175
1329
|
encrypt: new Set(['RSA-OAEP', 'AES-CTR', 'AES-CBC', 'AES-GCM', 'AES-OCB', 'ChaCha20-Poly1305']),
|
|
1176
1330
|
decrypt: new Set(['RSA-OAEP', 'AES-CTR', 'AES-CBC', 'AES-GCM', 'AES-OCB', 'ChaCha20-Poly1305']),
|
|
1177
|
-
sign: new Set(['RSASSA-PKCS1-v1_5', 'RSA-PSS', 'ECDSA', 'HMAC', 'Ed25519', 'Ed448', 'ML-DSA-44', 'ML-DSA-65', 'ML-DSA-87']),
|
|
1178
|
-
verify: new Set(['RSASSA-PKCS1-v1_5', 'RSA-PSS', 'ECDSA', 'HMAC', 'Ed25519', 'Ed448', 'ML-DSA-44', 'ML-DSA-65', 'ML-DSA-87']),
|
|
1179
|
-
digest: new Set(['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512']),
|
|
1180
|
-
generateKey: new Set(['RSASSA-PKCS1-v1_5', 'RSA-PSS', 'RSA-OAEP', 'ECDSA', 'ECDH', 'Ed25519', 'Ed448', 'X25519', 'X448', 'AES-CTR', 'AES-CBC', 'AES-GCM', 'AES-KW', 'AES-OCB', 'ChaCha20-Poly1305', 'HMAC', 'ML-DSA-44', 'ML-DSA-65', 'ML-DSA-87']),
|
|
1181
|
-
importKey: new Set(['RSASSA-PKCS1-v1_5', 'RSA-PSS', 'RSA-OAEP', 'ECDSA', 'ECDH', 'Ed25519', 'Ed448', 'X25519', 'X448', 'AES-CTR', 'AES-CBC', 'AES-GCM', 'AES-KW', 'AES-OCB', 'ChaCha20-Poly1305', 'HMAC', 'HKDF', 'PBKDF2', 'Argon2d', 'Argon2i', 'Argon2id', 'ML-DSA-44', 'ML-DSA-65', 'ML-DSA-87']),
|
|
1182
|
-
exportKey: new Set(['RSASSA-PKCS1-v1_5', 'RSA-PSS', 'RSA-OAEP', 'ECDSA', 'ECDH', 'Ed25519', 'Ed448', 'X25519', 'X448', 'AES-CTR', 'AES-CBC', 'AES-GCM', 'AES-KW', 'AES-OCB', 'ChaCha20-Poly1305', 'HMAC', 'ML-DSA-44', 'ML-DSA-65', 'ML-DSA-87']),
|
|
1331
|
+
sign: new Set(['RSASSA-PKCS1-v1_5', 'RSA-PSS', 'ECDSA', 'HMAC', 'KMAC128', 'KMAC256', 'Ed25519', 'Ed448', 'ML-DSA-44', 'ML-DSA-65', 'ML-DSA-87']),
|
|
1332
|
+
verify: new Set(['RSASSA-PKCS1-v1_5', 'RSA-PSS', 'ECDSA', 'HMAC', 'KMAC128', 'KMAC256', 'Ed25519', 'Ed448', 'ML-DSA-44', 'ML-DSA-65', 'ML-DSA-87']),
|
|
1333
|
+
digest: new Set(['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512', 'SHA3-256', 'SHA3-384', 'SHA3-512', 'cSHAKE128', 'cSHAKE256']),
|
|
1334
|
+
generateKey: new Set(['RSASSA-PKCS1-v1_5', 'RSA-PSS', 'RSA-OAEP', 'ECDSA', 'ECDH', 'Ed25519', 'Ed448', 'X25519', 'X448', 'AES-CTR', 'AES-CBC', 'AES-GCM', 'AES-KW', 'AES-OCB', 'ChaCha20-Poly1305', 'HMAC', 'KMAC128', 'KMAC256', 'ML-DSA-44', 'ML-DSA-65', 'ML-DSA-87', 'ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
|
|
1335
|
+
importKey: new Set(['RSASSA-PKCS1-v1_5', 'RSA-PSS', 'RSA-OAEP', 'ECDSA', 'ECDH', 'Ed25519', 'Ed448', 'X25519', 'X448', 'AES-CTR', 'AES-CBC', 'AES-GCM', 'AES-KW', 'AES-OCB', 'ChaCha20-Poly1305', 'HMAC', 'KMAC128', 'KMAC256', 'HKDF', 'PBKDF2', 'Argon2d', 'Argon2i', 'Argon2id', 'ML-DSA-44', 'ML-DSA-65', 'ML-DSA-87', 'ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
|
|
1336
|
+
exportKey: new Set(['RSASSA-PKCS1-v1_5', 'RSA-PSS', 'RSA-OAEP', 'ECDSA', 'ECDH', 'Ed25519', 'Ed448', 'X25519', 'X448', 'AES-CTR', 'AES-CBC', 'AES-GCM', 'AES-KW', 'AES-OCB', 'ChaCha20-Poly1305', 'HMAC', 'KMAC128', 'KMAC256', 'ML-DSA-44', 'ML-DSA-65', 'ML-DSA-87', 'ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
|
|
1183
1337
|
deriveBits: new Set(['PBKDF2', 'HKDF', 'ECDH', 'X25519', 'X448', 'Argon2d', 'Argon2i', 'Argon2id']),
|
|
1184
1338
|
wrapKey: new Set(['AES-CTR', 'AES-CBC', 'AES-GCM', 'AES-KW', 'AES-OCB', 'ChaCha20-Poly1305', 'RSA-OAEP']),
|
|
1185
|
-
unwrapKey: new Set(['AES-CTR', 'AES-CBC', 'AES-GCM', 'AES-KW', 'AES-OCB', 'ChaCha20-Poly1305', 'RSA-OAEP'])
|
|
1339
|
+
unwrapKey: new Set(['AES-CTR', 'AES-CBC', 'AES-GCM', 'AES-KW', 'AES-OCB', 'ChaCha20-Poly1305', 'RSA-OAEP']),
|
|
1340
|
+
encapsulateBits: new Set(['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
|
|
1341
|
+
decapsulateBits: new Set(['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
|
|
1342
|
+
encapsulateKey: new Set(['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
|
|
1343
|
+
decapsulateKey: new Set(['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024'])
|
|
1186
1344
|
};
|
|
1187
|
-
const ASYMMETRIC_ALGORITHMS = new Set(['RSASSA-PKCS1-v1_5', 'RSA-PSS', 'RSA-OAEP', 'ECDSA', 'ECDH', 'Ed25519', 'Ed448', 'X25519', 'X448', 'ML-DSA-44', 'ML-DSA-65', 'ML-DSA-87']);
|
|
1345
|
+
const ASYMMETRIC_ALGORITHMS = new Set(['RSASSA-PKCS1-v1_5', 'RSA-PSS', 'RSA-OAEP', 'ECDSA', 'ECDH', 'Ed25519', 'Ed448', 'X25519', 'X448', 'ML-DSA-44', 'ML-DSA-65', 'ML-DSA-87', 'ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']);
|
|
1188
1346
|
export class Subtle {
|
|
1189
1347
|
static supports(operation, algorithm, _lengthOrAdditionalAlgorithm) {
|
|
1190
1348
|
let normalizedAlgorithm;
|
|
@@ -1291,6 +1449,18 @@ export class Subtle {
|
|
|
1291
1449
|
}
|
|
1292
1450
|
async exportKey(format, key) {
|
|
1293
1451
|
if (!key.extractable) throw new Error('key is not extractable');
|
|
1452
|
+
if (format === 'raw-seed') {
|
|
1453
|
+
const pqcAlgos = ['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024', 'ML-DSA-44', 'ML-DSA-65', 'ML-DSA-87'];
|
|
1454
|
+
if (!pqcAlgos.includes(key.algorithm.name)) {
|
|
1455
|
+
throw lazyDOMException('raw-seed export only supported for PQC keys', 'NotSupportedError');
|
|
1456
|
+
}
|
|
1457
|
+
if (key.type !== 'private') {
|
|
1458
|
+
throw lazyDOMException('raw-seed export requires a private key', 'InvalidAccessError');
|
|
1459
|
+
}
|
|
1460
|
+
return bufferLikeToArrayBuffer(key.keyObject.handle.exportKey());
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
// Note: 'raw-seed' is handled above; do NOT normalize it here
|
|
1294
1464
|
if (format === 'raw-secret' || format === 'raw-public') format = 'raw';
|
|
1295
1465
|
switch (format) {
|
|
1296
1466
|
case 'spki':
|
|
@@ -1416,6 +1586,11 @@ export class Subtle {
|
|
|
1416
1586
|
case 'HMAC':
|
|
1417
1587
|
result = await hmacGenerateKey(algorithm, extractable, keyUsages);
|
|
1418
1588
|
break;
|
|
1589
|
+
case 'KMAC128':
|
|
1590
|
+
// Fall through
|
|
1591
|
+
case 'KMAC256':
|
|
1592
|
+
result = await kmacGenerateKey(algorithm, extractable, keyUsages);
|
|
1593
|
+
break;
|
|
1419
1594
|
case 'Ed25519':
|
|
1420
1595
|
// Fall through
|
|
1421
1596
|
case 'Ed448':
|
|
@@ -1436,6 +1611,14 @@ export class Subtle {
|
|
|
1436
1611
|
result = await x_generateKeyPairWebCrypto(algorithm.name.toLowerCase(), extractable, keyUsages);
|
|
1437
1612
|
checkCryptoKeyPairUsages(result);
|
|
1438
1613
|
break;
|
|
1614
|
+
case 'ML-KEM-512':
|
|
1615
|
+
// Fall through
|
|
1616
|
+
case 'ML-KEM-768':
|
|
1617
|
+
// Fall through
|
|
1618
|
+
case 'ML-KEM-1024':
|
|
1619
|
+
result = await mlkem_generateKeyPairWebCrypto(algorithm.name, extractable, keyUsages);
|
|
1620
|
+
checkCryptoKeyPairUsages(result);
|
|
1621
|
+
break;
|
|
1439
1622
|
default:
|
|
1440
1623
|
throw new Error(`'subtle.generateKey()' is not implemented for ${algorithm.name}.
|
|
1441
1624
|
Unrecognized algorithm name`);
|
|
@@ -1453,6 +1636,7 @@ export class Subtle {
|
|
|
1453
1636
|
return publicKeyObject.toCryptoKey(key.algorithm, true, keyUsages);
|
|
1454
1637
|
}
|
|
1455
1638
|
async importKey(format, data, algorithm, extractable, keyUsages) {
|
|
1639
|
+
// Note: 'raw-seed' is NOT normalized — PQC import functions handle it directly
|
|
1456
1640
|
if (format === 'raw-secret' || format === 'raw-public') format = 'raw';
|
|
1457
1641
|
const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'importKey');
|
|
1458
1642
|
let result;
|
|
@@ -1472,6 +1656,11 @@ export class Subtle {
|
|
|
1472
1656
|
case 'HMAC':
|
|
1473
1657
|
result = await hmacImportKey(normalizedAlgorithm, format, data, extractable, keyUsages);
|
|
1474
1658
|
break;
|
|
1659
|
+
case 'KMAC128':
|
|
1660
|
+
// Fall through
|
|
1661
|
+
case 'KMAC256':
|
|
1662
|
+
result = await kmacImportKey(normalizedAlgorithm, format, data, extractable, keyUsages);
|
|
1663
|
+
break;
|
|
1475
1664
|
case 'AES-CTR':
|
|
1476
1665
|
// Fall through
|
|
1477
1666
|
case 'AES-CBC':
|
|
@@ -1510,6 +1699,13 @@ export class Subtle {
|
|
|
1510
1699
|
case 'ML-DSA-87':
|
|
1511
1700
|
result = mldsaImportKey(format, data, normalizedAlgorithm, extractable, keyUsages);
|
|
1512
1701
|
break;
|
|
1702
|
+
case 'ML-KEM-512':
|
|
1703
|
+
// Fall through
|
|
1704
|
+
case 'ML-KEM-768':
|
|
1705
|
+
// Fall through
|
|
1706
|
+
case 'ML-KEM-1024':
|
|
1707
|
+
result = mlkemImportKey(format, data, normalizedAlgorithm, extractable, keyUsages);
|
|
1708
|
+
break;
|
|
1513
1709
|
default:
|
|
1514
1710
|
throw new Error(`"subtle.importKey()" is not implemented for ${normalizedAlgorithm.name}`);
|
|
1515
1711
|
}
|
|
@@ -1519,85 +1715,65 @@ export class Subtle {
|
|
|
1519
1715
|
return result;
|
|
1520
1716
|
}
|
|
1521
1717
|
async sign(algorithm, key, data) {
|
|
1522
|
-
|
|
1523
|
-
if (normalizedAlgorithm.name === 'HMAC') {
|
|
1524
|
-
// Validate key usage
|
|
1525
|
-
if (!key.usages.includes('sign')) {
|
|
1526
|
-
throw lazyDOMException('Key does not have sign usage', 'InvalidAccessError');
|
|
1527
|
-
}
|
|
1528
|
-
|
|
1529
|
-
// Get hash algorithm from key or algorithm params
|
|
1530
|
-
// Hash can be either a string or an object with name property
|
|
1531
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1532
|
-
const alg = normalizedAlgorithm;
|
|
1533
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1534
|
-
const keyAlg = key.algorithm;
|
|
1535
|
-
let hashAlgorithm = 'SHA-256';
|
|
1536
|
-
if (typeof alg.hash === 'string') {
|
|
1537
|
-
hashAlgorithm = alg.hash;
|
|
1538
|
-
} else if (alg.hash?.name) {
|
|
1539
|
-
hashAlgorithm = alg.hash.name;
|
|
1540
|
-
} else if (typeof keyAlg.hash === 'string') {
|
|
1541
|
-
hashAlgorithm = keyAlg.hash;
|
|
1542
|
-
} else if (keyAlg.hash?.name) {
|
|
1543
|
-
hashAlgorithm = keyAlg.hash.name;
|
|
1544
|
-
}
|
|
1545
|
-
|
|
1546
|
-
// Create HMAC and sign
|
|
1547
|
-
const keyData = key.keyObject.export();
|
|
1548
|
-
const hmac = createHmac(hashAlgorithm, keyData);
|
|
1549
|
-
hmac.update(bufferLikeToArrayBuffer(data));
|
|
1550
|
-
return bufferLikeToArrayBuffer(hmac.digest());
|
|
1551
|
-
}
|
|
1552
|
-
return signVerify(normalizedAlgorithm, key, data);
|
|
1718
|
+
return signVerify(normalizeAlgorithm(algorithm, 'sign'), key, data);
|
|
1553
1719
|
}
|
|
1554
1720
|
async verify(algorithm, key, signature, data) {
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
const dataBuffer = bufferLikeToArrayBuffer(data);
|
|
1583
|
-
hmac.update(dataBuffer);
|
|
1584
|
-
const expectedDigest = hmac.digest();
|
|
1585
|
-
const expected = new Uint8Array(bufferLikeToArrayBuffer(expectedDigest));
|
|
1586
|
-
|
|
1587
|
-
// Constant-time comparison
|
|
1588
|
-
const signatureArray = new Uint8Array(bufferLikeToArrayBuffer(signature));
|
|
1589
|
-
if (expected.length !== signatureArray.length) {
|
|
1590
|
-
return false;
|
|
1591
|
-
}
|
|
1592
|
-
|
|
1593
|
-
// Manual constant-time comparison
|
|
1594
|
-
let result = 0;
|
|
1595
|
-
for (let i = 0; i < expected.length; i++) {
|
|
1596
|
-
result |= expected[i] ^ signatureArray[i];
|
|
1597
|
-
}
|
|
1598
|
-
return result === 0;
|
|
1721
|
+
return signVerify(normalizeAlgorithm(algorithm, 'verify'), key, data, signature);
|
|
1722
|
+
}
|
|
1723
|
+
_encapsulateCore(algorithm, key) {
|
|
1724
|
+
const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'encapsulateBits');
|
|
1725
|
+
if (key.algorithm.name !== normalizedAlgorithm.name) {
|
|
1726
|
+
throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
|
|
1727
|
+
}
|
|
1728
|
+
const variant = normalizedAlgorithm.name;
|
|
1729
|
+
const mlkem = new MlKem(variant);
|
|
1730
|
+
const keyData = key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.SPKI);
|
|
1731
|
+
mlkem.setPublicKey(bufferLikeToArrayBuffer(keyData), KFormatType.DER, KeyEncoding.SPKI);
|
|
1732
|
+
return mlkem.encapsulateSync();
|
|
1733
|
+
}
|
|
1734
|
+
_decapsulateCore(algorithm, key, ciphertext) {
|
|
1735
|
+
const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'decapsulateBits');
|
|
1736
|
+
if (key.algorithm.name !== normalizedAlgorithm.name) {
|
|
1737
|
+
throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
|
|
1738
|
+
}
|
|
1739
|
+
const variant = normalizedAlgorithm.name;
|
|
1740
|
+
const mlkem = new MlKem(variant);
|
|
1741
|
+
const keyData = key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.PKCS8);
|
|
1742
|
+
mlkem.setPrivateKey(bufferLikeToArrayBuffer(keyData), KFormatType.DER, KeyEncoding.PKCS8);
|
|
1743
|
+
return mlkem.decapsulateSync(bufferLikeToArrayBuffer(ciphertext));
|
|
1744
|
+
}
|
|
1745
|
+
async encapsulateBits(algorithm, key) {
|
|
1746
|
+
if (!key.usages.includes('encapsulateBits')) {
|
|
1747
|
+
throw lazyDOMException('Key does not have encapsulateBits usage', 'InvalidAccessError');
|
|
1599
1748
|
}
|
|
1600
|
-
return
|
|
1749
|
+
return this._encapsulateCore(algorithm, key);
|
|
1750
|
+
}
|
|
1751
|
+
async encapsulateKey(algorithm, key, sharedKeyAlgorithm, extractable, usages) {
|
|
1752
|
+
if (!key.usages.includes('encapsulateKey')) {
|
|
1753
|
+
throw lazyDOMException('Key does not have encapsulateKey usage', 'InvalidAccessError');
|
|
1754
|
+
}
|
|
1755
|
+
const {
|
|
1756
|
+
sharedKey,
|
|
1757
|
+
ciphertext
|
|
1758
|
+
} = this._encapsulateCore(algorithm, key);
|
|
1759
|
+
const importedKey = await this.importKey('raw', sharedKey, sharedKeyAlgorithm, extractable, usages);
|
|
1760
|
+
return {
|
|
1761
|
+
key: importedKey,
|
|
1762
|
+
ciphertext
|
|
1763
|
+
};
|
|
1764
|
+
}
|
|
1765
|
+
async decapsulateBits(algorithm, key, ciphertext) {
|
|
1766
|
+
if (!key.usages.includes('decapsulateBits')) {
|
|
1767
|
+
throw lazyDOMException('Key does not have decapsulateBits usage', 'InvalidAccessError');
|
|
1768
|
+
}
|
|
1769
|
+
return this._decapsulateCore(algorithm, key, ciphertext);
|
|
1770
|
+
}
|
|
1771
|
+
async decapsulateKey(algorithm, key, ciphertext, sharedKeyAlgorithm, extractable, usages) {
|
|
1772
|
+
if (!key.usages.includes('decapsulateKey')) {
|
|
1773
|
+
throw lazyDOMException('Key does not have decapsulateKey usage', 'InvalidAccessError');
|
|
1774
|
+
}
|
|
1775
|
+
const sharedKey = this._decapsulateCore(algorithm, key, ciphertext);
|
|
1776
|
+
return this.importKey('raw', sharedKey, sharedKeyAlgorithm, extractable, usages);
|
|
1601
1777
|
}
|
|
1602
1778
|
}
|
|
1603
1779
|
export const subtle = new Subtle();
|
|
@@ -1616,6 +1792,10 @@ function getKeyLength(algorithm) {
|
|
|
1616
1792
|
const hmacAlg = algorithm;
|
|
1617
1793
|
return hmacAlg.length || 256;
|
|
1618
1794
|
}
|
|
1795
|
+
case 'KMAC128':
|
|
1796
|
+
return algorithm.length || 128;
|
|
1797
|
+
case 'KMAC256':
|
|
1798
|
+
return algorithm.length || 256;
|
|
1619
1799
|
default:
|
|
1620
1800
|
throw lazyDOMException(`Cannot determine key length for ${name}`, 'NotSupportedError');
|
|
1621
1801
|
}
|