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/src/subtle.ts
CHANGED
|
@@ -48,6 +48,8 @@ import {
|
|
|
48
48
|
import { rsa_generateKeyPair } from './rsa';
|
|
49
49
|
import { getRandomValues } from './random';
|
|
50
50
|
import { createHmac } from './hmac';
|
|
51
|
+
import type { Kmac } from './specs/kmac.nitro';
|
|
52
|
+
import { timingSafeEqual } from './utils/timingSafeEqual';
|
|
51
53
|
import { createSign, createVerify } from './keys/signVerify';
|
|
52
54
|
import {
|
|
53
55
|
ed_generateKeyPairWebCrypto,
|
|
@@ -56,6 +58,12 @@ import {
|
|
|
56
58
|
Ed,
|
|
57
59
|
} from './ed';
|
|
58
60
|
import { mldsa_generateKeyPairWebCrypto, type MlDsaVariant } from './mldsa';
|
|
61
|
+
import {
|
|
62
|
+
mlkem_generateKeyPairWebCrypto,
|
|
63
|
+
type MlKemVariant,
|
|
64
|
+
MlKem,
|
|
65
|
+
} from './mlkem';
|
|
66
|
+
import type { EncapsulateResult } from './utils';
|
|
59
67
|
import { hkdfDeriveBits, type HkdfAlgorithm } from './hkdf';
|
|
60
68
|
// Temporary enums that need to be defined
|
|
61
69
|
|
|
@@ -699,6 +707,164 @@ async function hmacGenerateKey(
|
|
|
699
707
|
return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
|
|
700
708
|
}
|
|
701
709
|
|
|
710
|
+
async function kmacGenerateKey(
|
|
711
|
+
algorithm: SubtleAlgorithm,
|
|
712
|
+
extractable: boolean,
|
|
713
|
+
keyUsages: KeyUsage[],
|
|
714
|
+
): Promise<CryptoKey> {
|
|
715
|
+
const { name } = algorithm;
|
|
716
|
+
|
|
717
|
+
if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
|
|
718
|
+
throw lazyDOMException(
|
|
719
|
+
`Unsupported key usage for ${name} key`,
|
|
720
|
+
'SyntaxError',
|
|
721
|
+
);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
const defaultLength = name === 'KMAC128' ? 128 : 256;
|
|
725
|
+
const length = algorithm.length ?? defaultLength;
|
|
726
|
+
|
|
727
|
+
if (length === 0) {
|
|
728
|
+
throw lazyDOMException(
|
|
729
|
+
'Zero-length key is not supported',
|
|
730
|
+
'OperationError',
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
const keyBytes = new Uint8Array(Math.ceil(length / 8));
|
|
735
|
+
getRandomValues(keyBytes);
|
|
736
|
+
|
|
737
|
+
const keyObject = createSecretKey(keyBytes);
|
|
738
|
+
|
|
739
|
+
const keyAlgorithm: SubtleAlgorithm = { name: name as AnyAlgorithm, length };
|
|
740
|
+
|
|
741
|
+
return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
function kmacSignVerify(
|
|
745
|
+
key: CryptoKey,
|
|
746
|
+
data: BufferLike,
|
|
747
|
+
algorithm: SubtleAlgorithm,
|
|
748
|
+
signature?: BufferLike,
|
|
749
|
+
): ArrayBuffer | boolean {
|
|
750
|
+
const { name } = algorithm;
|
|
751
|
+
|
|
752
|
+
const defaultLength = name === 'KMAC128' ? 256 : 512;
|
|
753
|
+
const outputLengthBits = algorithm.length ?? defaultLength;
|
|
754
|
+
|
|
755
|
+
if (outputLengthBits % 8 !== 0) {
|
|
756
|
+
throw lazyDOMException(
|
|
757
|
+
'KMAC output length must be a multiple of 8',
|
|
758
|
+
'OperationError',
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
const outputLengthBytes = outputLengthBits / 8;
|
|
763
|
+
|
|
764
|
+
const keyData = key.keyObject.export();
|
|
765
|
+
|
|
766
|
+
const kmac = NitroModules.createHybridObject<Kmac>('Kmac');
|
|
767
|
+
|
|
768
|
+
let customizationBuffer: ArrayBuffer | undefined;
|
|
769
|
+
if (algorithm.customization !== undefined) {
|
|
770
|
+
customizationBuffer = bufferLikeToArrayBuffer(algorithm.customization);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
kmac.createKmac(
|
|
774
|
+
name,
|
|
775
|
+
bufferLikeToArrayBuffer(keyData),
|
|
776
|
+
outputLengthBytes,
|
|
777
|
+
customizationBuffer,
|
|
778
|
+
);
|
|
779
|
+
kmac.update(bufferLikeToArrayBuffer(data));
|
|
780
|
+
const computed = kmac.digest();
|
|
781
|
+
|
|
782
|
+
if (signature === undefined) {
|
|
783
|
+
return computed;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
const sigBuffer = bufferLikeToArrayBuffer(signature);
|
|
787
|
+
if (computed.byteLength !== sigBuffer.byteLength) {
|
|
788
|
+
return false;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
return timingSafeEqual(new Uint8Array(computed), new Uint8Array(sigBuffer));
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
async function kmacImportKey(
|
|
795
|
+
algorithm: SubtleAlgorithm,
|
|
796
|
+
format: ImportFormat,
|
|
797
|
+
data: BufferLike | JWK,
|
|
798
|
+
extractable: boolean,
|
|
799
|
+
keyUsages: KeyUsage[],
|
|
800
|
+
): Promise<CryptoKey> {
|
|
801
|
+
const { name } = algorithm;
|
|
802
|
+
|
|
803
|
+
if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
|
|
804
|
+
throw lazyDOMException(
|
|
805
|
+
`Unsupported key usage for ${name} key`,
|
|
806
|
+
'SyntaxError',
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
let keyObject: KeyObject;
|
|
811
|
+
|
|
812
|
+
if (format === 'jwk') {
|
|
813
|
+
const jwk = data as JWK;
|
|
814
|
+
|
|
815
|
+
if (!jwk || typeof jwk !== 'object') {
|
|
816
|
+
throw lazyDOMException('Invalid keyData', 'DataError');
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
if (jwk.kty !== 'oct') {
|
|
820
|
+
throw lazyDOMException('Invalid JWK format for KMAC key', 'DataError');
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
const expectedAlg = name === 'KMAC128' ? 'K128' : 'K256';
|
|
824
|
+
if (jwk.alg !== undefined && jwk.alg !== expectedAlg) {
|
|
825
|
+
throw lazyDOMException(
|
|
826
|
+
'JWK "alg" does not match the requested algorithm',
|
|
827
|
+
'DataError',
|
|
828
|
+
);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
const handle =
|
|
832
|
+
NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
|
|
833
|
+
const keyType = handle.initJwk(jwk, undefined);
|
|
834
|
+
|
|
835
|
+
if (keyType === undefined || keyType !== 0) {
|
|
836
|
+
throw lazyDOMException('Failed to import KMAC JWK', 'DataError');
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
keyObject = new SecretKeyObject(handle);
|
|
840
|
+
} else if (format === 'raw' || format === 'raw-secret') {
|
|
841
|
+
keyObject = createSecretKey(data as BinaryLike);
|
|
842
|
+
} else {
|
|
843
|
+
throw lazyDOMException(
|
|
844
|
+
`Unable to import ${name} key with format ${format}`,
|
|
845
|
+
'NotSupportedError',
|
|
846
|
+
);
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
const exported = keyObject.export();
|
|
850
|
+
const keyLength = exported.byteLength * 8;
|
|
851
|
+
|
|
852
|
+
if (keyLength === 0) {
|
|
853
|
+
throw lazyDOMException('Zero-length key is not supported', 'DataError');
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
if (algorithm.length !== undefined && algorithm.length !== keyLength) {
|
|
857
|
+
throw lazyDOMException('Invalid key length', 'DataError');
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
const keyAlgorithm: SubtleAlgorithm = {
|
|
861
|
+
name: name as AnyAlgorithm,
|
|
862
|
+
length: keyLength,
|
|
863
|
+
};
|
|
864
|
+
|
|
865
|
+
return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
|
|
866
|
+
}
|
|
867
|
+
|
|
702
868
|
function rsaImportKey(
|
|
703
869
|
format: ImportFormat,
|
|
704
870
|
data: BufferLike | JWK,
|
|
@@ -1019,6 +1185,49 @@ function edImportKey(
|
|
|
1019
1185
|
return new CryptoKey(keyObject, { name }, keyUsages, extractable);
|
|
1020
1186
|
}
|
|
1021
1187
|
|
|
1188
|
+
function pqcImportKeyObject(
|
|
1189
|
+
format: ImportFormat,
|
|
1190
|
+
data: BufferLike,
|
|
1191
|
+
name: string,
|
|
1192
|
+
): KeyObject {
|
|
1193
|
+
if (format === 'spki') {
|
|
1194
|
+
return KeyObject.createKeyObject(
|
|
1195
|
+
'public',
|
|
1196
|
+
bufferLikeToArrayBuffer(data),
|
|
1197
|
+
KFormatType.DER,
|
|
1198
|
+
KeyEncoding.SPKI,
|
|
1199
|
+
);
|
|
1200
|
+
} else if (format === 'pkcs8') {
|
|
1201
|
+
return KeyObject.createKeyObject(
|
|
1202
|
+
'private',
|
|
1203
|
+
bufferLikeToArrayBuffer(data),
|
|
1204
|
+
KFormatType.DER,
|
|
1205
|
+
KeyEncoding.PKCS8,
|
|
1206
|
+
);
|
|
1207
|
+
} else if (format === 'raw') {
|
|
1208
|
+
const handle =
|
|
1209
|
+
NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
|
|
1210
|
+
if (!handle.initPqcRaw(name, bufferLikeToArrayBuffer(data), true)) {
|
|
1211
|
+
throw lazyDOMException(
|
|
1212
|
+
`Failed to import ${name} raw public key`,
|
|
1213
|
+
'DataError',
|
|
1214
|
+
);
|
|
1215
|
+
}
|
|
1216
|
+
return new PublicKeyObject(handle);
|
|
1217
|
+
} else if (format === 'raw-seed') {
|
|
1218
|
+
const handle =
|
|
1219
|
+
NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
|
|
1220
|
+
if (!handle.initPqcRaw(name, bufferLikeToArrayBuffer(data), false)) {
|
|
1221
|
+
throw lazyDOMException(`Failed to import ${name} raw seed`, 'DataError');
|
|
1222
|
+
}
|
|
1223
|
+
return new PrivateKeyObject(handle);
|
|
1224
|
+
}
|
|
1225
|
+
throw lazyDOMException(
|
|
1226
|
+
`Unsupported format for ${name} import: ${format}`,
|
|
1227
|
+
'NotSupportedError',
|
|
1228
|
+
);
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1022
1231
|
function mldsaImportKey(
|
|
1023
1232
|
format: ImportFormat,
|
|
1024
1233
|
data: BufferLike,
|
|
@@ -1027,43 +1236,45 @@ function mldsaImportKey(
|
|
|
1027
1236
|
keyUsages: KeyUsage[],
|
|
1028
1237
|
): CryptoKey {
|
|
1029
1238
|
const { name } = algorithm;
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
|
|
1239
|
+
const isPublicFormat = format === 'spki' || format === 'raw';
|
|
1240
|
+
if (hasAnyNotIn(keyUsages, isPublicFormat ? ['verify'] : ['sign'])) {
|
|
1033
1241
|
throw lazyDOMException(
|
|
1034
1242
|
`Unsupported key usage for ${name} key`,
|
|
1035
1243
|
'SyntaxError',
|
|
1036
1244
|
);
|
|
1037
1245
|
}
|
|
1246
|
+
return new CryptoKey(
|
|
1247
|
+
pqcImportKeyObject(format, data, name),
|
|
1248
|
+
{ name },
|
|
1249
|
+
keyUsages,
|
|
1250
|
+
extractable,
|
|
1251
|
+
);
|
|
1252
|
+
}
|
|
1038
1253
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
const keyData = bufferLikeToArrayBuffer(data);
|
|
1053
|
-
keyObject = KeyObject.createKeyObject(
|
|
1054
|
-
'private',
|
|
1055
|
-
keyData,
|
|
1056
|
-
KFormatType.DER,
|
|
1057
|
-
KeyEncoding.PKCS8,
|
|
1058
|
-
);
|
|
1059
|
-
} else {
|
|
1254
|
+
function mlkemImportKey(
|
|
1255
|
+
format: ImportFormat,
|
|
1256
|
+
data: BufferLike,
|
|
1257
|
+
algorithm: SubtleAlgorithm,
|
|
1258
|
+
extractable: boolean,
|
|
1259
|
+
keyUsages: KeyUsage[],
|
|
1260
|
+
): CryptoKey {
|
|
1261
|
+
const { name } = algorithm;
|
|
1262
|
+
const isPublicFormat = format === 'spki' || format === 'raw';
|
|
1263
|
+
const allowedUsages: KeyUsage[] = isPublicFormat
|
|
1264
|
+
? ['encapsulateBits', 'encapsulateKey']
|
|
1265
|
+
: ['decapsulateBits', 'decapsulateKey'];
|
|
1266
|
+
if (hasAnyNotIn(keyUsages, allowedUsages)) {
|
|
1060
1267
|
throw lazyDOMException(
|
|
1061
|
-
`Unsupported
|
|
1062
|
-
'
|
|
1268
|
+
`Unsupported key usage for ${name} key`,
|
|
1269
|
+
'SyntaxError',
|
|
1063
1270
|
);
|
|
1064
1271
|
}
|
|
1065
|
-
|
|
1066
|
-
|
|
1272
|
+
return new CryptoKey(
|
|
1273
|
+
pqcImportKeyObject(format, data, name),
|
|
1274
|
+
{ name },
|
|
1275
|
+
keyUsages,
|
|
1276
|
+
extractable,
|
|
1277
|
+
);
|
|
1067
1278
|
}
|
|
1068
1279
|
|
|
1069
1280
|
const exportKeySpki = async (
|
|
@@ -1112,6 +1323,17 @@ const exportKeySpki = async (
|
|
|
1112
1323
|
);
|
|
1113
1324
|
}
|
|
1114
1325
|
break;
|
|
1326
|
+
case 'ML-KEM-512':
|
|
1327
|
+
// Fall through
|
|
1328
|
+
case 'ML-KEM-768':
|
|
1329
|
+
// Fall through
|
|
1330
|
+
case 'ML-KEM-1024':
|
|
1331
|
+
if (key.type === 'public') {
|
|
1332
|
+
return bufferLikeToArrayBuffer(
|
|
1333
|
+
key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.SPKI),
|
|
1334
|
+
);
|
|
1335
|
+
}
|
|
1336
|
+
break;
|
|
1115
1337
|
}
|
|
1116
1338
|
|
|
1117
1339
|
throw new Error(
|
|
@@ -1165,6 +1387,17 @@ const exportKeyPkcs8 = async (
|
|
|
1165
1387
|
);
|
|
1166
1388
|
}
|
|
1167
1389
|
break;
|
|
1390
|
+
case 'ML-KEM-512':
|
|
1391
|
+
// Fall through
|
|
1392
|
+
case 'ML-KEM-768':
|
|
1393
|
+
// Fall through
|
|
1394
|
+
case 'ML-KEM-1024':
|
|
1395
|
+
if (key.type === 'private') {
|
|
1396
|
+
return bufferLikeToArrayBuffer(
|
|
1397
|
+
key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.PKCS8),
|
|
1398
|
+
);
|
|
1399
|
+
}
|
|
1400
|
+
break;
|
|
1168
1401
|
}
|
|
1169
1402
|
|
|
1170
1403
|
throw new Error(
|
|
@@ -1189,7 +1422,22 @@ const exportKeyRaw = (key: CryptoKey): ArrayBuffer | unknown => {
|
|
|
1189
1422
|
// Fall through
|
|
1190
1423
|
case 'X448':
|
|
1191
1424
|
if (key.type === 'public') {
|
|
1192
|
-
|
|
1425
|
+
const exported = key.keyObject.handle.exportKey();
|
|
1426
|
+
return bufferLikeToArrayBuffer(exported);
|
|
1427
|
+
}
|
|
1428
|
+
break;
|
|
1429
|
+
case 'ML-KEM-512':
|
|
1430
|
+
// Fall through
|
|
1431
|
+
case 'ML-KEM-768':
|
|
1432
|
+
// Fall through
|
|
1433
|
+
case 'ML-KEM-1024':
|
|
1434
|
+
// Fall through
|
|
1435
|
+
case 'ML-DSA-44':
|
|
1436
|
+
// Fall through
|
|
1437
|
+
case 'ML-DSA-65':
|
|
1438
|
+
// Fall through
|
|
1439
|
+
case 'ML-DSA-87':
|
|
1440
|
+
if (key.type === 'public') {
|
|
1193
1441
|
const exported = key.keyObject.handle.exportKey();
|
|
1194
1442
|
return bufferLikeToArrayBuffer(exported);
|
|
1195
1443
|
}
|
|
@@ -1206,7 +1454,11 @@ const exportKeyRaw = (key: CryptoKey): ArrayBuffer | unknown => {
|
|
|
1206
1454
|
// Fall through
|
|
1207
1455
|
case 'ChaCha20-Poly1305':
|
|
1208
1456
|
// Fall through
|
|
1209
|
-
case 'HMAC':
|
|
1457
|
+
case 'HMAC':
|
|
1458
|
+
// Fall through
|
|
1459
|
+
case 'KMAC128':
|
|
1460
|
+
// Fall through
|
|
1461
|
+
case 'KMAC256': {
|
|
1210
1462
|
const exported = key.keyObject.export();
|
|
1211
1463
|
// Convert Buffer to ArrayBuffer
|
|
1212
1464
|
return exported.buffer.slice(
|
|
@@ -1243,6 +1495,12 @@ const exportKeyJWK = (key: CryptoKey): ArrayBuffer | unknown => {
|
|
|
1243
1495
|
case 'HMAC':
|
|
1244
1496
|
jwk.alg = normalizeHashName(key.algorithm.hash, HashContext.JwkHmac);
|
|
1245
1497
|
return jwk;
|
|
1498
|
+
case 'KMAC128':
|
|
1499
|
+
jwk.alg = 'K128';
|
|
1500
|
+
return jwk;
|
|
1501
|
+
case 'KMAC256':
|
|
1502
|
+
jwk.alg = 'K256';
|
|
1503
|
+
return jwk;
|
|
1246
1504
|
case 'ECDSA':
|
|
1247
1505
|
// Fall through
|
|
1248
1506
|
case 'ECDH':
|
|
@@ -1429,24 +1687,20 @@ function hmacSignVerify(
|
|
|
1429
1687
|
);
|
|
1430
1688
|
}
|
|
1431
1689
|
|
|
1432
|
-
|
|
1433
|
-
const
|
|
1434
|
-
const computedBytes = new Uint8Array(
|
|
1435
|
-
computed.buffer,
|
|
1690
|
+
const sigBuffer = bufferLikeToArrayBuffer(signature);
|
|
1691
|
+
const computedBuffer = computed.buffer.slice(
|
|
1436
1692
|
computed.byteOffset,
|
|
1437
|
-
computed.byteLength,
|
|
1693
|
+
computed.byteOffset + computed.byteLength,
|
|
1438
1694
|
);
|
|
1439
1695
|
|
|
1440
|
-
if (
|
|
1696
|
+
if (computedBuffer.byteLength !== sigBuffer.byteLength) {
|
|
1441
1697
|
return false;
|
|
1442
1698
|
}
|
|
1443
1699
|
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
}
|
|
1449
|
-
return result === 0;
|
|
1700
|
+
return timingSafeEqual(
|
|
1701
|
+
new Uint8Array(computedBuffer),
|
|
1702
|
+
new Uint8Array(sigBuffer),
|
|
1703
|
+
);
|
|
1450
1704
|
}
|
|
1451
1705
|
|
|
1452
1706
|
function rsaSignVerify(
|
|
@@ -1589,6 +1843,9 @@ const signVerify = (
|
|
|
1589
1843
|
case 'ML-DSA-65':
|
|
1590
1844
|
case 'ML-DSA-87':
|
|
1591
1845
|
return mldsaSignVerify(key, data, signature);
|
|
1846
|
+
case 'KMAC128':
|
|
1847
|
+
case 'KMAC256':
|
|
1848
|
+
return kmacSignVerify(key, data, algorithm, signature);
|
|
1592
1849
|
}
|
|
1593
1850
|
throw lazyDOMException(
|
|
1594
1851
|
`Unrecognized algorithm name '${algorithm.name}' for '${usage}'`,
|
|
@@ -1660,6 +1917,8 @@ const SUPPORTED_ALGORITHMS: Record<string, Set<string>> = {
|
|
|
1660
1917
|
'RSA-PSS',
|
|
1661
1918
|
'ECDSA',
|
|
1662
1919
|
'HMAC',
|
|
1920
|
+
'KMAC128',
|
|
1921
|
+
'KMAC256',
|
|
1663
1922
|
'Ed25519',
|
|
1664
1923
|
'Ed448',
|
|
1665
1924
|
'ML-DSA-44',
|
|
@@ -1671,13 +1930,25 @@ const SUPPORTED_ALGORITHMS: Record<string, Set<string>> = {
|
|
|
1671
1930
|
'RSA-PSS',
|
|
1672
1931
|
'ECDSA',
|
|
1673
1932
|
'HMAC',
|
|
1933
|
+
'KMAC128',
|
|
1934
|
+
'KMAC256',
|
|
1674
1935
|
'Ed25519',
|
|
1675
1936
|
'Ed448',
|
|
1676
1937
|
'ML-DSA-44',
|
|
1677
1938
|
'ML-DSA-65',
|
|
1678
1939
|
'ML-DSA-87',
|
|
1679
1940
|
]),
|
|
1680
|
-
digest: new Set([
|
|
1941
|
+
digest: new Set([
|
|
1942
|
+
'SHA-1',
|
|
1943
|
+
'SHA-256',
|
|
1944
|
+
'SHA-384',
|
|
1945
|
+
'SHA-512',
|
|
1946
|
+
'SHA3-256',
|
|
1947
|
+
'SHA3-384',
|
|
1948
|
+
'SHA3-512',
|
|
1949
|
+
'cSHAKE128',
|
|
1950
|
+
'cSHAKE256',
|
|
1951
|
+
]),
|
|
1681
1952
|
generateKey: new Set([
|
|
1682
1953
|
'RSASSA-PKCS1-v1_5',
|
|
1683
1954
|
'RSA-PSS',
|
|
@@ -1695,9 +1966,14 @@ const SUPPORTED_ALGORITHMS: Record<string, Set<string>> = {
|
|
|
1695
1966
|
'AES-OCB',
|
|
1696
1967
|
'ChaCha20-Poly1305',
|
|
1697
1968
|
'HMAC',
|
|
1969
|
+
'KMAC128',
|
|
1970
|
+
'KMAC256',
|
|
1698
1971
|
'ML-DSA-44',
|
|
1699
1972
|
'ML-DSA-65',
|
|
1700
1973
|
'ML-DSA-87',
|
|
1974
|
+
'ML-KEM-512',
|
|
1975
|
+
'ML-KEM-768',
|
|
1976
|
+
'ML-KEM-1024',
|
|
1701
1977
|
]),
|
|
1702
1978
|
importKey: new Set([
|
|
1703
1979
|
'RSASSA-PKCS1-v1_5',
|
|
@@ -1716,6 +1992,8 @@ const SUPPORTED_ALGORITHMS: Record<string, Set<string>> = {
|
|
|
1716
1992
|
'AES-OCB',
|
|
1717
1993
|
'ChaCha20-Poly1305',
|
|
1718
1994
|
'HMAC',
|
|
1995
|
+
'KMAC128',
|
|
1996
|
+
'KMAC256',
|
|
1719
1997
|
'HKDF',
|
|
1720
1998
|
'PBKDF2',
|
|
1721
1999
|
'Argon2d',
|
|
@@ -1724,6 +2002,9 @@ const SUPPORTED_ALGORITHMS: Record<string, Set<string>> = {
|
|
|
1724
2002
|
'ML-DSA-44',
|
|
1725
2003
|
'ML-DSA-65',
|
|
1726
2004
|
'ML-DSA-87',
|
|
2005
|
+
'ML-KEM-512',
|
|
2006
|
+
'ML-KEM-768',
|
|
2007
|
+
'ML-KEM-1024',
|
|
1727
2008
|
]),
|
|
1728
2009
|
exportKey: new Set([
|
|
1729
2010
|
'RSASSA-PKCS1-v1_5',
|
|
@@ -1742,9 +2023,14 @@ const SUPPORTED_ALGORITHMS: Record<string, Set<string>> = {
|
|
|
1742
2023
|
'AES-OCB',
|
|
1743
2024
|
'ChaCha20-Poly1305',
|
|
1744
2025
|
'HMAC',
|
|
2026
|
+
'KMAC128',
|
|
2027
|
+
'KMAC256',
|
|
1745
2028
|
'ML-DSA-44',
|
|
1746
2029
|
'ML-DSA-65',
|
|
1747
2030
|
'ML-DSA-87',
|
|
2031
|
+
'ML-KEM-512',
|
|
2032
|
+
'ML-KEM-768',
|
|
2033
|
+
'ML-KEM-1024',
|
|
1748
2034
|
]),
|
|
1749
2035
|
deriveBits: new Set([
|
|
1750
2036
|
'PBKDF2',
|
|
@@ -1774,6 +2060,10 @@ const SUPPORTED_ALGORITHMS: Record<string, Set<string>> = {
|
|
|
1774
2060
|
'ChaCha20-Poly1305',
|
|
1775
2061
|
'RSA-OAEP',
|
|
1776
2062
|
]),
|
|
2063
|
+
encapsulateBits: new Set(['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
|
|
2064
|
+
decapsulateBits: new Set(['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
|
|
2065
|
+
encapsulateKey: new Set(['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
|
|
2066
|
+
decapsulateKey: new Set(['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
|
|
1777
2067
|
};
|
|
1778
2068
|
|
|
1779
2069
|
const ASYMMETRIC_ALGORITHMS = new Set([
|
|
@@ -1789,6 +2079,9 @@ const ASYMMETRIC_ALGORITHMS = new Set([
|
|
|
1789
2079
|
'ML-DSA-44',
|
|
1790
2080
|
'ML-DSA-65',
|
|
1791
2081
|
'ML-DSA-87',
|
|
2082
|
+
'ML-KEM-512',
|
|
2083
|
+
'ML-KEM-768',
|
|
2084
|
+
'ML-KEM-1024',
|
|
1792
2085
|
]);
|
|
1793
2086
|
|
|
1794
2087
|
export class Subtle {
|
|
@@ -1989,6 +2282,31 @@ export class Subtle {
|
|
|
1989
2282
|
): Promise<ArrayBuffer | JWK> {
|
|
1990
2283
|
if (!key.extractable) throw new Error('key is not extractable');
|
|
1991
2284
|
|
|
2285
|
+
if (format === 'raw-seed') {
|
|
2286
|
+
const pqcAlgos = [
|
|
2287
|
+
'ML-KEM-512',
|
|
2288
|
+
'ML-KEM-768',
|
|
2289
|
+
'ML-KEM-1024',
|
|
2290
|
+
'ML-DSA-44',
|
|
2291
|
+
'ML-DSA-65',
|
|
2292
|
+
'ML-DSA-87',
|
|
2293
|
+
];
|
|
2294
|
+
if (!pqcAlgos.includes(key.algorithm.name)) {
|
|
2295
|
+
throw lazyDOMException(
|
|
2296
|
+
'raw-seed export only supported for PQC keys',
|
|
2297
|
+
'NotSupportedError',
|
|
2298
|
+
);
|
|
2299
|
+
}
|
|
2300
|
+
if (key.type !== 'private') {
|
|
2301
|
+
throw lazyDOMException(
|
|
2302
|
+
'raw-seed export requires a private key',
|
|
2303
|
+
'InvalidAccessError',
|
|
2304
|
+
);
|
|
2305
|
+
}
|
|
2306
|
+
return bufferLikeToArrayBuffer(key.keyObject.handle.exportKey());
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
// Note: 'raw-seed' is handled above; do NOT normalize it here
|
|
1992
2310
|
if (format === 'raw-secret' || format === 'raw-public') format = 'raw';
|
|
1993
2311
|
|
|
1994
2312
|
switch (format) {
|
|
@@ -2176,6 +2494,11 @@ export class Subtle {
|
|
|
2176
2494
|
case 'HMAC':
|
|
2177
2495
|
result = await hmacGenerateKey(algorithm, extractable, keyUsages);
|
|
2178
2496
|
break;
|
|
2497
|
+
case 'KMAC128':
|
|
2498
|
+
// Fall through
|
|
2499
|
+
case 'KMAC256':
|
|
2500
|
+
result = await kmacGenerateKey(algorithm, extractable, keyUsages);
|
|
2501
|
+
break;
|
|
2179
2502
|
case 'Ed25519':
|
|
2180
2503
|
// Fall through
|
|
2181
2504
|
case 'Ed448':
|
|
@@ -2208,6 +2531,18 @@ export class Subtle {
|
|
|
2208
2531
|
);
|
|
2209
2532
|
checkCryptoKeyPairUsages(result as CryptoKeyPair);
|
|
2210
2533
|
break;
|
|
2534
|
+
case 'ML-KEM-512':
|
|
2535
|
+
// Fall through
|
|
2536
|
+
case 'ML-KEM-768':
|
|
2537
|
+
// Fall through
|
|
2538
|
+
case 'ML-KEM-1024':
|
|
2539
|
+
result = await mlkem_generateKeyPairWebCrypto(
|
|
2540
|
+
algorithm.name as MlKemVariant,
|
|
2541
|
+
extractable,
|
|
2542
|
+
keyUsages,
|
|
2543
|
+
);
|
|
2544
|
+
checkCryptoKeyPairUsages(result as CryptoKeyPair);
|
|
2545
|
+
break;
|
|
2211
2546
|
default:
|
|
2212
2547
|
throw new Error(
|
|
2213
2548
|
`'subtle.generateKey()' is not implemented for ${algorithm.name}.
|
|
@@ -2240,6 +2575,7 @@ export class Subtle {
|
|
|
2240
2575
|
extractable: boolean,
|
|
2241
2576
|
keyUsages: KeyUsage[],
|
|
2242
2577
|
): Promise<CryptoKey> {
|
|
2578
|
+
// Note: 'raw-seed' is NOT normalized — PQC import functions handle it directly
|
|
2243
2579
|
if (format === 'raw-secret' || format === 'raw-public') format = 'raw';
|
|
2244
2580
|
const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'importKey');
|
|
2245
2581
|
let result: CryptoKey;
|
|
@@ -2277,6 +2613,17 @@ export class Subtle {
|
|
|
2277
2613
|
keyUsages,
|
|
2278
2614
|
);
|
|
2279
2615
|
break;
|
|
2616
|
+
case 'KMAC128':
|
|
2617
|
+
// Fall through
|
|
2618
|
+
case 'KMAC256':
|
|
2619
|
+
result = await kmacImportKey(
|
|
2620
|
+
normalizedAlgorithm,
|
|
2621
|
+
format,
|
|
2622
|
+
data as BufferLike | JWK,
|
|
2623
|
+
extractable,
|
|
2624
|
+
keyUsages,
|
|
2625
|
+
);
|
|
2626
|
+
break;
|
|
2280
2627
|
case 'AES-CTR':
|
|
2281
2628
|
// Fall through
|
|
2282
2629
|
case 'AES-CBC':
|
|
@@ -2345,6 +2692,19 @@ export class Subtle {
|
|
|
2345
2692
|
keyUsages,
|
|
2346
2693
|
);
|
|
2347
2694
|
break;
|
|
2695
|
+
case 'ML-KEM-512':
|
|
2696
|
+
// Fall through
|
|
2697
|
+
case 'ML-KEM-768':
|
|
2698
|
+
// Fall through
|
|
2699
|
+
case 'ML-KEM-1024':
|
|
2700
|
+
result = mlkemImportKey(
|
|
2701
|
+
format,
|
|
2702
|
+
data as BufferLike,
|
|
2703
|
+
normalizedAlgorithm,
|
|
2704
|
+
extractable,
|
|
2705
|
+
keyUsages,
|
|
2706
|
+
);
|
|
2707
|
+
break;
|
|
2348
2708
|
default:
|
|
2349
2709
|
throw new Error(
|
|
2350
2710
|
`"subtle.importKey()" is not implemented for ${normalizedAlgorithm.name}`,
|
|
@@ -2368,103 +2728,164 @@ export class Subtle {
|
|
|
2368
2728
|
key: CryptoKey,
|
|
2369
2729
|
data: BufferLike,
|
|
2370
2730
|
): Promise<ArrayBuffer> {
|
|
2371
|
-
|
|
2731
|
+
return signVerify(
|
|
2732
|
+
normalizeAlgorithm(algorithm, 'sign'),
|
|
2733
|
+
key,
|
|
2734
|
+
data,
|
|
2735
|
+
) as ArrayBuffer;
|
|
2736
|
+
}
|
|
2372
2737
|
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2738
|
+
async verify(
|
|
2739
|
+
algorithm: SubtleAlgorithm,
|
|
2740
|
+
key: CryptoKey,
|
|
2741
|
+
signature: BufferLike,
|
|
2742
|
+
data: BufferLike,
|
|
2743
|
+
): Promise<boolean> {
|
|
2744
|
+
return signVerify(
|
|
2745
|
+
normalizeAlgorithm(algorithm, 'verify'),
|
|
2746
|
+
key,
|
|
2747
|
+
data,
|
|
2748
|
+
signature,
|
|
2749
|
+
) as boolean;
|
|
2750
|
+
}
|
|
2381
2751
|
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
if (typeof alg.hash === 'string') {
|
|
2391
|
-
hashAlgorithm = alg.hash;
|
|
2392
|
-
} else if (alg.hash?.name) {
|
|
2393
|
-
hashAlgorithm = alg.hash.name;
|
|
2394
|
-
} else if (typeof keyAlg.hash === 'string') {
|
|
2395
|
-
hashAlgorithm = keyAlg.hash;
|
|
2396
|
-
} else if (keyAlg.hash?.name) {
|
|
2397
|
-
hashAlgorithm = keyAlg.hash.name;
|
|
2398
|
-
}
|
|
2752
|
+
private _encapsulateCore(
|
|
2753
|
+
algorithm: SubtleAlgorithm,
|
|
2754
|
+
key: CryptoKey,
|
|
2755
|
+
): EncapsulateResult {
|
|
2756
|
+
const normalizedAlgorithm = normalizeAlgorithm(
|
|
2757
|
+
algorithm,
|
|
2758
|
+
'encapsulateBits' as Operation,
|
|
2759
|
+
);
|
|
2399
2760
|
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
const hmac = createHmac(hashAlgorithm, keyData);
|
|
2403
|
-
hmac.update(bufferLikeToArrayBuffer(data));
|
|
2404
|
-
return bufferLikeToArrayBuffer(hmac.digest());
|
|
2761
|
+
if (key.algorithm.name !== normalizedAlgorithm.name) {
|
|
2762
|
+
throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
|
|
2405
2763
|
}
|
|
2406
2764
|
|
|
2407
|
-
|
|
2765
|
+
const variant = normalizedAlgorithm.name as MlKemVariant;
|
|
2766
|
+
const mlkem = new MlKem(variant);
|
|
2767
|
+
|
|
2768
|
+
const keyData = key.keyObject.handle.exportKey(
|
|
2769
|
+
KFormatType.DER,
|
|
2770
|
+
KeyEncoding.SPKI,
|
|
2771
|
+
);
|
|
2772
|
+
mlkem.setPublicKey(
|
|
2773
|
+
bufferLikeToArrayBuffer(keyData),
|
|
2774
|
+
KFormatType.DER,
|
|
2775
|
+
KeyEncoding.SPKI,
|
|
2776
|
+
);
|
|
2777
|
+
|
|
2778
|
+
return mlkem.encapsulateSync();
|
|
2408
2779
|
}
|
|
2409
2780
|
|
|
2410
|
-
|
|
2781
|
+
private _decapsulateCore(
|
|
2411
2782
|
algorithm: SubtleAlgorithm,
|
|
2412
2783
|
key: CryptoKey,
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2784
|
+
ciphertext: BufferLike,
|
|
2785
|
+
): ArrayBuffer {
|
|
2786
|
+
const normalizedAlgorithm = normalizeAlgorithm(
|
|
2787
|
+
algorithm,
|
|
2788
|
+
'decapsulateBits' as Operation,
|
|
2789
|
+
);
|
|
2417
2790
|
|
|
2418
|
-
if (
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
throw lazyDOMException(
|
|
2422
|
-
'Key does not have verify usage',
|
|
2423
|
-
'InvalidAccessError',
|
|
2424
|
-
);
|
|
2425
|
-
}
|
|
2791
|
+
if (key.algorithm.name !== normalizedAlgorithm.name) {
|
|
2792
|
+
throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
|
|
2793
|
+
}
|
|
2426
2794
|
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2430
|
-
const alg = normalizedAlgorithm as any;
|
|
2431
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2432
|
-
const keyAlg = key.algorithm as any;
|
|
2433
|
-
let hashAlgorithm = 'SHA-256';
|
|
2434
|
-
|
|
2435
|
-
if (typeof alg.hash === 'string') {
|
|
2436
|
-
hashAlgorithm = alg.hash;
|
|
2437
|
-
} else if (alg.hash?.name) {
|
|
2438
|
-
hashAlgorithm = alg.hash.name;
|
|
2439
|
-
} else if (typeof keyAlg.hash === 'string') {
|
|
2440
|
-
hashAlgorithm = keyAlg.hash;
|
|
2441
|
-
} else if (keyAlg.hash?.name) {
|
|
2442
|
-
hashAlgorithm = keyAlg.hash.name;
|
|
2443
|
-
}
|
|
2795
|
+
const variant = normalizedAlgorithm.name as MlKemVariant;
|
|
2796
|
+
const mlkem = new MlKem(variant);
|
|
2444
2797
|
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
const signatureArray = new Uint8Array(bufferLikeToArrayBuffer(signature));
|
|
2455
|
-
if (expected.length !== signatureArray.length) {
|
|
2456
|
-
return false;
|
|
2457
|
-
}
|
|
2798
|
+
const keyData = key.keyObject.handle.exportKey(
|
|
2799
|
+
KFormatType.DER,
|
|
2800
|
+
KeyEncoding.PKCS8,
|
|
2801
|
+
);
|
|
2802
|
+
mlkem.setPrivateKey(
|
|
2803
|
+
bufferLikeToArrayBuffer(keyData),
|
|
2804
|
+
KFormatType.DER,
|
|
2805
|
+
KeyEncoding.PKCS8,
|
|
2806
|
+
);
|
|
2458
2807
|
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2808
|
+
return mlkem.decapsulateSync(bufferLikeToArrayBuffer(ciphertext));
|
|
2809
|
+
}
|
|
2810
|
+
|
|
2811
|
+
async encapsulateBits(
|
|
2812
|
+
algorithm: SubtleAlgorithm,
|
|
2813
|
+
key: CryptoKey,
|
|
2814
|
+
): Promise<EncapsulateResult> {
|
|
2815
|
+
if (!key.usages.includes('encapsulateBits')) {
|
|
2816
|
+
throw lazyDOMException(
|
|
2817
|
+
'Key does not have encapsulateBits usage',
|
|
2818
|
+
'InvalidAccessError',
|
|
2819
|
+
);
|
|
2465
2820
|
}
|
|
2466
2821
|
|
|
2467
|
-
return
|
|
2822
|
+
return this._encapsulateCore(algorithm, key);
|
|
2823
|
+
}
|
|
2824
|
+
|
|
2825
|
+
async encapsulateKey(
|
|
2826
|
+
algorithm: SubtleAlgorithm,
|
|
2827
|
+
key: CryptoKey,
|
|
2828
|
+
sharedKeyAlgorithm: SubtleAlgorithm | AnyAlgorithm,
|
|
2829
|
+
extractable: boolean,
|
|
2830
|
+
usages: KeyUsage[],
|
|
2831
|
+
): Promise<{ key: CryptoKey; ciphertext: ArrayBuffer }> {
|
|
2832
|
+
if (!key.usages.includes('encapsulateKey')) {
|
|
2833
|
+
throw lazyDOMException(
|
|
2834
|
+
'Key does not have encapsulateKey usage',
|
|
2835
|
+
'InvalidAccessError',
|
|
2836
|
+
);
|
|
2837
|
+
}
|
|
2838
|
+
|
|
2839
|
+
const { sharedKey, ciphertext } = this._encapsulateCore(algorithm, key);
|
|
2840
|
+
const importedKey = await this.importKey(
|
|
2841
|
+
'raw',
|
|
2842
|
+
sharedKey,
|
|
2843
|
+
sharedKeyAlgorithm,
|
|
2844
|
+
extractable,
|
|
2845
|
+
usages,
|
|
2846
|
+
);
|
|
2847
|
+
|
|
2848
|
+
return { key: importedKey, ciphertext };
|
|
2849
|
+
}
|
|
2850
|
+
|
|
2851
|
+
async decapsulateBits(
|
|
2852
|
+
algorithm: SubtleAlgorithm,
|
|
2853
|
+
key: CryptoKey,
|
|
2854
|
+
ciphertext: BufferLike,
|
|
2855
|
+
): Promise<ArrayBuffer> {
|
|
2856
|
+
if (!key.usages.includes('decapsulateBits')) {
|
|
2857
|
+
throw lazyDOMException(
|
|
2858
|
+
'Key does not have decapsulateBits usage',
|
|
2859
|
+
'InvalidAccessError',
|
|
2860
|
+
);
|
|
2861
|
+
}
|
|
2862
|
+
|
|
2863
|
+
return this._decapsulateCore(algorithm, key, ciphertext);
|
|
2864
|
+
}
|
|
2865
|
+
|
|
2866
|
+
async decapsulateKey(
|
|
2867
|
+
algorithm: SubtleAlgorithm,
|
|
2868
|
+
key: CryptoKey,
|
|
2869
|
+
ciphertext: BufferLike,
|
|
2870
|
+
sharedKeyAlgorithm: SubtleAlgorithm | AnyAlgorithm,
|
|
2871
|
+
extractable: boolean,
|
|
2872
|
+
usages: KeyUsage[],
|
|
2873
|
+
): Promise<CryptoKey> {
|
|
2874
|
+
if (!key.usages.includes('decapsulateKey')) {
|
|
2875
|
+
throw lazyDOMException(
|
|
2876
|
+
'Key does not have decapsulateKey usage',
|
|
2877
|
+
'InvalidAccessError',
|
|
2878
|
+
);
|
|
2879
|
+
}
|
|
2880
|
+
|
|
2881
|
+
const sharedKey = this._decapsulateCore(algorithm, key, ciphertext);
|
|
2882
|
+
return this.importKey(
|
|
2883
|
+
'raw',
|
|
2884
|
+
sharedKey,
|
|
2885
|
+
sharedKeyAlgorithm,
|
|
2886
|
+
extractable,
|
|
2887
|
+
usages,
|
|
2888
|
+
);
|
|
2468
2889
|
}
|
|
2469
2890
|
}
|
|
2470
2891
|
|
|
@@ -2487,6 +2908,11 @@ function getKeyLength(algorithm: SubtleAlgorithm): number {
|
|
|
2487
2908
|
return hmacAlg.length || 256;
|
|
2488
2909
|
}
|
|
2489
2910
|
|
|
2911
|
+
case 'KMAC128':
|
|
2912
|
+
return algorithm.length || 128;
|
|
2913
|
+
case 'KMAC256':
|
|
2914
|
+
return algorithm.length || 256;
|
|
2915
|
+
|
|
2490
2916
|
default:
|
|
2491
2917
|
throw lazyDOMException(
|
|
2492
2918
|
`Cannot determine key length for ${name}`,
|