react-native-quick-crypto 1.0.10 → 1.0.12
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 +16 -0
- package/cpp/argon2/HybridArgon2.cpp +103 -0
- package/cpp/argon2/HybridArgon2.hpp +32 -0
- package/cpp/certificate/HybridCertificate.cpp +42 -0
- package/cpp/certificate/HybridCertificate.hpp +16 -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 +68 -1
- package/cpp/cipher/HybridCipher.hpp +6 -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/dh/HybridDhKeyPair.cpp +179 -0
- package/cpp/dh/HybridDhKeyPair.hpp +37 -0
- package/cpp/dsa/HybridDsaKeyPair.cpp +128 -0
- package/cpp/dsa/HybridDsaKeyPair.hpp +32 -0
- package/cpp/ecdh/HybridECDH.cpp +42 -120
- package/cpp/ecdh/HybridECDH.hpp +1 -0
- package/cpp/keys/HybridKeyObjectHandle.cpp +150 -128
- 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/prime/HybridPrime.cpp +81 -0
- package/cpp/prime/HybridPrime.hpp +20 -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/argon2.js +39 -0
- package/lib/commonjs/argon2.js.map +1 -0
- package/lib/commonjs/certificate.js +35 -0
- package/lib/commonjs/certificate.js.map +1 -0
- package/lib/commonjs/cipher.js +23 -2
- package/lib/commonjs/cipher.js.map +1 -1
- package/lib/commonjs/dhKeyPair.js +109 -0
- package/lib/commonjs/dhKeyPair.js.map +1 -0
- package/lib/commonjs/dsa.js +92 -0
- package/lib/commonjs/dsa.js.map +1 -0
- package/lib/commonjs/ec.js +18 -18
- package/lib/commonjs/ec.js.map +1 -1
- package/lib/commonjs/ecdh.js +37 -0
- package/lib/commonjs/ecdh.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 +57 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/keys/classes.js +11 -9
- package/lib/commonjs/keys/classes.js.map +1 -1
- package/lib/commonjs/keys/generateKeyPair.js +11 -0
- package/lib/commonjs/keys/generateKeyPair.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/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/prime.js +84 -0
- package/lib/commonjs/prime.js.map +1 -0
- package/lib/commonjs/rsa.js +7 -7
- package/lib/commonjs/rsa.js.map +1 -1
- package/lib/commonjs/specs/argon2.nitro.js +6 -0
- package/lib/commonjs/specs/argon2.nitro.js.map +1 -0
- package/lib/commonjs/specs/certificate.nitro.js +6 -0
- package/lib/commonjs/specs/certificate.nitro.js.map +1 -0
- package/lib/commonjs/specs/dhKeyPair.nitro.js +6 -0
- package/lib/commonjs/specs/dhKeyPair.nitro.js.map +1 -0
- package/lib/commonjs/specs/dsaKeyPair.nitro.js +6 -0
- package/lib/commonjs/specs/dsaKeyPair.nitro.js.map +1 -0
- 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/prime.nitro.js +6 -0
- package/lib/commonjs/specs/prime.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 +385 -114
- 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/argon2.js +34 -0
- package/lib/module/argon2.js.map +1 -0
- package/lib/module/certificate.js +30 -0
- package/lib/module/certificate.js.map +1 -0
- package/lib/module/cipher.js +23 -3
- package/lib/module/cipher.js.map +1 -1
- package/lib/module/dhKeyPair.js +102 -0
- package/lib/module/dhKeyPair.js.map +1 -0
- package/lib/module/dsa.js +85 -0
- package/lib/module/dsa.js.map +1 -0
- package/lib/module/ec.js +6 -6
- package/lib/module/ec.js.map +1 -1
- package/lib/module/ecdh.js +37 -0
- package/lib/module/ecdh.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 +15 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/keys/classes.js +11 -9
- package/lib/module/keys/classes.js.map +1 -1
- package/lib/module/keys/generateKeyPair.js +11 -0
- package/lib/module/keys/generateKeyPair.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/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/prime.js +77 -0
- package/lib/module/prime.js.map +1 -0
- package/lib/module/rsa.js +1 -1
- package/lib/module/rsa.js.map +1 -1
- package/lib/module/specs/argon2.nitro.js +4 -0
- package/lib/module/specs/argon2.nitro.js.map +1 -0
- package/lib/module/specs/certificate.nitro.js +4 -0
- package/lib/module/specs/certificate.nitro.js.map +1 -0
- package/lib/module/specs/dhKeyPair.nitro.js +4 -0
- package/lib/module/specs/dhKeyPair.nitro.js.map +1 -0
- package/lib/module/specs/dsaKeyPair.nitro.js +4 -0
- package/lib/module/specs/dsaKeyPair.nitro.js.map +1 -0
- 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/prime.nitro.js +4 -0
- package/lib/module/specs/prime.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 +386 -116
- 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/argon2.d.ts +16 -0
- package/lib/typescript/argon2.d.ts.map +1 -0
- package/lib/typescript/certificate.d.ts +8 -0
- package/lib/typescript/certificate.d.ts.map +1 -0
- package/lib/typescript/cipher.d.ts +15 -0
- package/lib/typescript/cipher.d.ts.map +1 -1
- package/lib/typescript/dhKeyPair.d.ts +19 -0
- package/lib/typescript/dhKeyPair.d.ts.map +1 -0
- package/lib/typescript/dsa.d.ts +19 -0
- package/lib/typescript/dsa.d.ts.map +1 -0
- package/lib/typescript/ec.d.ts +1 -1
- package/lib/typescript/ec.d.ts.map +1 -1
- package/lib/typescript/ecdh.d.ts +3 -0
- package/lib/typescript/ecdh.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 +32 -4
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/keys/classes.d.ts +7 -5
- package/lib/typescript/keys/classes.d.ts.map +1 -1
- package/lib/typescript/keys/generateKeyPair.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/prime.d.ts +19 -0
- package/lib/typescript/prime.d.ts.map +1 -0
- package/lib/typescript/rsa.d.ts +1 -1
- package/lib/typescript/rsa.d.ts.map +1 -1
- package/lib/typescript/specs/argon2.nitro.d.ts +9 -0
- package/lib/typescript/specs/argon2.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/certificate.nitro.d.ts +10 -0
- package/lib/typescript/specs/certificate.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/cipher.nitro.d.ts +9 -0
- package/lib/typescript/specs/cipher.nitro.d.ts.map +1 -1
- package/lib/typescript/specs/dhKeyPair.nitro.d.ts +14 -0
- package/lib/typescript/specs/dhKeyPair.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/dsaKeyPair.nitro.d.ts +13 -0
- package/lib/typescript/specs/dsaKeyPair.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/ecdh.nitro.d.ts +1 -0
- package/lib/typescript/specs/ecdh.nitro.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/prime.nitro.d.ts +11 -0
- package/lib/typescript/specs/prime.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 +12 -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 +25 -9
- 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 +8 -0
- package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +80 -0
- package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +80 -0
- package/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp +12 -0
- package/nitrogen/generated/shared/c++/CipherInfo.hpp +104 -0
- package/nitrogen/generated/shared/c++/HybridArgon2Spec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridArgon2Spec.hpp +66 -0
- package/nitrogen/generated/shared/c++/HybridCertificateSpec.cpp +23 -0
- package/nitrogen/generated/shared/c++/HybridCertificateSpec.hpp +64 -0
- package/nitrogen/generated/shared/c++/HybridCipherSpec.cpp +1 -0
- package/nitrogen/generated/shared/c++/HybridCipherSpec.hpp +4 -0
- package/nitrogen/generated/shared/c++/HybridDhKeyPairSpec.cpp +27 -0
- package/nitrogen/generated/shared/c++/HybridDhKeyPairSpec.hpp +69 -0
- package/nitrogen/generated/shared/c++/HybridDsaKeyPairSpec.cpp +26 -0
- package/nitrogen/generated/shared/c++/HybridDsaKeyPairSpec.hpp +68 -0
- package/nitrogen/generated/shared/c++/HybridECDHSpec.cpp +1 -0
- package/nitrogen/generated/shared/c++/HybridECDHSpec.hpp +1 -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++/HybridPrimeSpec.cpp +24 -0
- package/nitrogen/generated/shared/c++/HybridPrimeSpec.hpp +67 -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/argon2.ts +83 -0
- package/src/certificate.ts +41 -0
- package/src/cipher.ts +41 -3
- package/src/dhKeyPair.ts +156 -0
- package/src/dsa.ts +129 -0
- package/src/ec.ts +9 -9
- package/src/ecdh.ts +59 -0
- package/src/ed.ts +2 -2
- package/src/hash.ts +34 -11
- package/src/hkdf.ts +2 -7
- package/src/index.ts +16 -0
- package/src/keys/classes.ts +26 -14
- package/src/keys/generateKeyPair.ts +14 -0
- package/src/keys/index.ts +37 -2
- package/src/keys/signVerify.ts +0 -5
- package/src/mlkem.ts +350 -0
- package/src/pbkdf2.ts +34 -5
- package/src/prime.ts +134 -0
- package/src/rsa.ts +1 -1
- package/src/specs/argon2.nitro.ts +29 -0
- package/src/specs/certificate.nitro.ts +8 -0
- package/src/specs/cipher.nitro.ts +14 -0
- package/src/specs/dhKeyPair.nitro.ts +14 -0
- package/src/specs/dsaKeyPair.nitro.ts +13 -0
- package/src/specs/ecdh.nitro.ts +1 -0
- 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/prime.nitro.ts +18 -0
- package/src/specs/x509certificate.nitro.ts +38 -0
- package/src/subtle.ts +821 -136
- package/src/utils/conversion.ts +10 -4
- package/src/utils/hashnames.ts +33 -2
- package/src/utils/types.ts +64 -8
- package/src/x509certificate.ts +277 -0
package/lib/module/subtle.js
CHANGED
|
@@ -5,27 +5,24 @@ import { Buffer as SBuffer } from 'safe-buffer';
|
|
|
5
5
|
import { KFormatType, KeyEncoding, KeyType } from './utils';
|
|
6
6
|
import { CryptoKey, KeyObject, PublicKeyObject, PrivateKeyObject, SecretKeyObject } from './keys';
|
|
7
7
|
import { bufferLikeToArrayBuffer } from './utils/conversion';
|
|
8
|
+
import { argon2Sync } from './argon2';
|
|
8
9
|
import { lazyDOMException } from './utils/errors';
|
|
9
10
|
import { normalizeHashName, HashContext } from './utils/hashnames';
|
|
10
11
|
import { validateMaxBufferLength } from './utils/validation';
|
|
11
12
|
import { asyncDigest } from './hash';
|
|
12
|
-
import { createSecretKey } from './keys';
|
|
13
|
+
import { createSecretKey, createPublicKey } from './keys';
|
|
13
14
|
import { NitroModules } from 'react-native-nitro-modules';
|
|
14
15
|
import { pbkdf2DeriveBits } from './pbkdf2';
|
|
15
16
|
import { ecImportKey, ecdsaSignVerify, ec_generateKeyPair, ecDeriveBits } from './ec';
|
|
16
17
|
import { rsa_generateKeyPair } from './rsa';
|
|
17
18
|
import { getRandomValues } from './random';
|
|
18
19
|
import { createHmac } from './hmac';
|
|
20
|
+
import { timingSafeEqual } from './utils/timingSafeEqual';
|
|
19
21
|
import { createSign, createVerify } from './keys/signVerify';
|
|
20
22
|
import { ed_generateKeyPairWebCrypto, x_generateKeyPairWebCrypto, xDeriveBits, Ed } from './ed';
|
|
21
23
|
import { mldsa_generateKeyPairWebCrypto } from './mldsa';
|
|
24
|
+
import { mlkem_generateKeyPairWebCrypto, MlKem } from './mlkem';
|
|
22
25
|
import { hkdfDeriveBits } from './hkdf';
|
|
23
|
-
// import { pbkdf2DeriveBits } from './pbkdf2';
|
|
24
|
-
// import { aesCipher, aesGenerateKey, aesImportKey, getAlgorithmName } from './aes';
|
|
25
|
-
// import { rsaCipher, rsaExportKey, rsaImportKey, rsaKeyGenerate } from './rsa';
|
|
26
|
-
// import { normalizeAlgorithm, type Operation } from './algorithms';
|
|
27
|
-
// import { hmacImportKey } from './mac';
|
|
28
|
-
|
|
29
26
|
// Temporary enums that need to be defined
|
|
30
27
|
var KWebCryptoKeyFormat = /*#__PURE__*/function (KWebCryptoKeyFormat) {
|
|
31
28
|
KWebCryptoKeyFormat[KWebCryptoKeyFormat["kWebCryptoKeyFormatRaw"] = 0] = "kWebCryptoKeyFormatRaw";
|
|
@@ -71,15 +68,15 @@ function getAlgorithmName(name, length) {
|
|
|
71
68
|
// Placeholder implementations for missing functions
|
|
72
69
|
function ecExportKey(key, format) {
|
|
73
70
|
const keyObject = key.keyObject;
|
|
74
|
-
if (format === KWebCryptoKeyFormat.
|
|
75
|
-
|
|
71
|
+
if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatRaw) {
|
|
72
|
+
return bufferLikeToArrayBuffer(keyObject.handle.exportKey());
|
|
73
|
+
} else if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatSPKI) {
|
|
76
74
|
const exported = keyObject.export({
|
|
77
75
|
format: 'der',
|
|
78
76
|
type: 'spki'
|
|
79
77
|
});
|
|
80
78
|
return bufferLikeToArrayBuffer(exported);
|
|
81
79
|
} else if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatPKCS8) {
|
|
82
|
-
// Export private key in PKCS8 format
|
|
83
80
|
const exported = keyObject.export({
|
|
84
81
|
format: 'der',
|
|
85
82
|
type: 'pkcs8'
|
|
@@ -488,6 +485,100 @@ async function hmacGenerateKey(algorithm, extractable, keyUsages) {
|
|
|
488
485
|
};
|
|
489
486
|
return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
|
|
490
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
|
+
}
|
|
491
582
|
function rsaImportKey(format, data, algorithm, extractable, keyUsages) {
|
|
492
583
|
const {
|
|
493
584
|
name
|
|
@@ -725,28 +816,48 @@ function edImportKey(format, data, algorithm, extractable, keyUsages) {
|
|
|
725
816
|
name
|
|
726
817
|
}, keyUsages, extractable);
|
|
727
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
|
+
}
|
|
728
839
|
function mldsaImportKey(format, data, algorithm, extractable, keyUsages) {
|
|
729
840
|
const {
|
|
730
841
|
name
|
|
731
842
|
} = algorithm;
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
|
|
843
|
+
const isPublicFormat = format === 'spki' || format === 'raw';
|
|
844
|
+
if (hasAnyNotIn(keyUsages, isPublicFormat ? ['verify'] : ['sign'])) {
|
|
735
845
|
throw lazyDOMException(`Unsupported key usage for ${name} key`, 'SyntaxError');
|
|
736
846
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
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');
|
|
748
859
|
}
|
|
749
|
-
return new CryptoKey(
|
|
860
|
+
return new CryptoKey(pqcImportKeyObject(format, data, name), {
|
|
750
861
|
name
|
|
751
862
|
}, keyUsages, extractable);
|
|
752
863
|
}
|
|
@@ -790,6 +901,15 @@ const exportKeySpki = async key => {
|
|
|
790
901
|
return bufferLikeToArrayBuffer(key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.SPKI));
|
|
791
902
|
}
|
|
792
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;
|
|
793
913
|
}
|
|
794
914
|
throw new Error(`Unable to export a spki ${key.algorithm.name} ${key.type} key`);
|
|
795
915
|
};
|
|
@@ -833,6 +953,15 @@ const exportKeyPkcs8 = async key => {
|
|
|
833
953
|
return bufferLikeToArrayBuffer(key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.PKCS8));
|
|
834
954
|
}
|
|
835
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;
|
|
836
965
|
}
|
|
837
966
|
throw new Error(`Unable to export a pkcs8 ${key.algorithm.name} ${key.type} key`);
|
|
838
967
|
};
|
|
@@ -853,7 +982,22 @@ const exportKeyRaw = key => {
|
|
|
853
982
|
// Fall through
|
|
854
983
|
case 'X448':
|
|
855
984
|
if (key.type === 'public') {
|
|
856
|
-
|
|
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') {
|
|
857
1001
|
const exported = key.keyObject.handle.exportKey();
|
|
858
1002
|
return bufferLikeToArrayBuffer(exported);
|
|
859
1003
|
}
|
|
@@ -871,6 +1015,10 @@ const exportKeyRaw = key => {
|
|
|
871
1015
|
case 'ChaCha20-Poly1305':
|
|
872
1016
|
// Fall through
|
|
873
1017
|
case 'HMAC':
|
|
1018
|
+
// Fall through
|
|
1019
|
+
case 'KMAC128':
|
|
1020
|
+
// Fall through
|
|
1021
|
+
case 'KMAC256':
|
|
874
1022
|
{
|
|
875
1023
|
const exported = key.keyObject.export();
|
|
876
1024
|
// Convert Buffer to ArrayBuffer
|
|
@@ -897,6 +1045,12 @@ const exportKeyJWK = key => {
|
|
|
897
1045
|
case 'HMAC':
|
|
898
1046
|
jwk.alg = normalizeHashName(key.algorithm.hash, HashContext.JwkHmac);
|
|
899
1047
|
return jwk;
|
|
1048
|
+
case 'KMAC128':
|
|
1049
|
+
jwk.alg = 'K128';
|
|
1050
|
+
return jwk;
|
|
1051
|
+
case 'KMAC256':
|
|
1052
|
+
jwk.alg = 'K256';
|
|
1053
|
+
return jwk;
|
|
900
1054
|
case 'ECDSA':
|
|
901
1055
|
// Fall through
|
|
902
1056
|
case 'ECDH':
|
|
@@ -984,6 +1138,37 @@ const checkCryptoKeyPairUsages = pair => {
|
|
|
984
1138
|
}
|
|
985
1139
|
throw lazyDOMException('Usages cannot be empty when creating a key.', 'SyntaxError');
|
|
986
1140
|
};
|
|
1141
|
+
function argon2DeriveBits(algorithm, baseKey, length) {
|
|
1142
|
+
if (length === 0 || length % 8 !== 0) {
|
|
1143
|
+
throw lazyDOMException('Invalid Argon2 derived key length', 'OperationError');
|
|
1144
|
+
}
|
|
1145
|
+
if (length < 32) {
|
|
1146
|
+
throw lazyDOMException('Argon2 derived key length must be at least 32 bits', 'OperationError');
|
|
1147
|
+
}
|
|
1148
|
+
const {
|
|
1149
|
+
nonce,
|
|
1150
|
+
parallelism,
|
|
1151
|
+
memory,
|
|
1152
|
+
passes,
|
|
1153
|
+
secretValue,
|
|
1154
|
+
associatedData
|
|
1155
|
+
} = algorithm;
|
|
1156
|
+
const tagLength = length / 8;
|
|
1157
|
+
const message = baseKey.keyObject.export();
|
|
1158
|
+
const algName = algorithm.name.toLowerCase();
|
|
1159
|
+
const result = argon2Sync(algName, {
|
|
1160
|
+
message,
|
|
1161
|
+
nonce: nonce ?? new Uint8Array(0),
|
|
1162
|
+
parallelism: parallelism ?? 1,
|
|
1163
|
+
tagLength,
|
|
1164
|
+
memory: memory ?? 65536,
|
|
1165
|
+
passes: passes ?? 3,
|
|
1166
|
+
secret: secretValue,
|
|
1167
|
+
associatedData,
|
|
1168
|
+
version: algorithm.version
|
|
1169
|
+
});
|
|
1170
|
+
return bufferLikeToArrayBuffer(result);
|
|
1171
|
+
}
|
|
987
1172
|
|
|
988
1173
|
// Type guard to check if result is CryptoKeyPair
|
|
989
1174
|
export function isCryptoKeyPair(result) {
|
|
@@ -1004,20 +1189,12 @@ function hmacSignVerify(key, data, signature) {
|
|
|
1004
1189
|
// Sign operation - return the HMAC as ArrayBuffer
|
|
1005
1190
|
return computed.buffer.slice(computed.byteOffset, computed.byteOffset + computed.byteLength);
|
|
1006
1191
|
}
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
const computedBytes = new Uint8Array(computed.buffer, computed.byteOffset, computed.byteLength);
|
|
1011
|
-
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) {
|
|
1012
1195
|
return false;
|
|
1013
1196
|
}
|
|
1014
|
-
|
|
1015
|
-
// Constant-time comparison to prevent timing attacks
|
|
1016
|
-
let result = 0;
|
|
1017
|
-
for (let i = 0; i < computedBytes.length; i++) {
|
|
1018
|
-
result |= computedBytes[i] ^ sigBytes[i];
|
|
1019
|
-
}
|
|
1020
|
-
return result === 0;
|
|
1197
|
+
return timingSafeEqual(new Uint8Array(computedBuffer), new Uint8Array(sigBuffer));
|
|
1021
1198
|
}
|
|
1022
1199
|
function rsaSignVerify(key, data, padding, signature, saltLength) {
|
|
1023
1200
|
// Get hash algorithm from key
|
|
@@ -1120,6 +1297,9 @@ const signVerify = (algorithm, key, data, signature) => {
|
|
|
1120
1297
|
case 'ML-DSA-65':
|
|
1121
1298
|
case 'ML-DSA-87':
|
|
1122
1299
|
return mldsaSignVerify(key, data, signature);
|
|
1300
|
+
case 'KMAC128':
|
|
1301
|
+
case 'KMAC256':
|
|
1302
|
+
return kmacSignVerify(key, data, algorithm, signature);
|
|
1123
1303
|
}
|
|
1124
1304
|
throw lazyDOMException(`Unrecognized algorithm name '${algorithm.name}' for '${usage}'`, 'NotSupportedError');
|
|
1125
1305
|
};
|
|
@@ -1145,7 +1325,53 @@ const cipherOrWrap = async (mode, algorithm, key, data, op) => {
|
|
|
1145
1325
|
return chaCha20Poly1305Cipher(mode, key, data, algorithm);
|
|
1146
1326
|
}
|
|
1147
1327
|
};
|
|
1328
|
+
const SUPPORTED_ALGORITHMS = {
|
|
1329
|
+
encrypt: new Set(['RSA-OAEP', 'AES-CTR', 'AES-CBC', 'AES-GCM', 'AES-OCB', 'ChaCha20-Poly1305']),
|
|
1330
|
+
decrypt: new Set(['RSA-OAEP', 'AES-CTR', 'AES-CBC', 'AES-GCM', 'AES-OCB', 'ChaCha20-Poly1305']),
|
|
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']),
|
|
1337
|
+
deriveBits: new Set(['PBKDF2', 'HKDF', 'ECDH', 'X25519', 'X448', 'Argon2d', 'Argon2i', 'Argon2id']),
|
|
1338
|
+
wrapKey: 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'])
|
|
1344
|
+
};
|
|
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']);
|
|
1148
1346
|
export class Subtle {
|
|
1347
|
+
static supports(operation, algorithm, _lengthOrAdditionalAlgorithm) {
|
|
1348
|
+
let normalizedAlgorithm;
|
|
1349
|
+
try {
|
|
1350
|
+
normalizedAlgorithm = normalizeAlgorithm(algorithm, operation === 'getPublicKey' ? 'exportKey' : operation);
|
|
1351
|
+
} catch {
|
|
1352
|
+
return false;
|
|
1353
|
+
}
|
|
1354
|
+
const name = normalizedAlgorithm.name;
|
|
1355
|
+
if (operation === 'getPublicKey') {
|
|
1356
|
+
return ASYMMETRIC_ALGORITHMS.has(name);
|
|
1357
|
+
}
|
|
1358
|
+
if (operation === 'deriveKey') {
|
|
1359
|
+
// deriveKey decomposes to deriveBits + importKey of additional algorithm
|
|
1360
|
+
if (!SUPPORTED_ALGORITHMS.deriveBits?.has(name)) return false;
|
|
1361
|
+
if (_lengthOrAdditionalAlgorithm != null) {
|
|
1362
|
+
try {
|
|
1363
|
+
const additionalAlg = normalizeAlgorithm(_lengthOrAdditionalAlgorithm, 'importKey');
|
|
1364
|
+
return SUPPORTED_ALGORITHMS.importKey?.has(additionalAlg.name) ?? false;
|
|
1365
|
+
} catch {
|
|
1366
|
+
return false;
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
return true;
|
|
1370
|
+
}
|
|
1371
|
+
const supported = SUPPORTED_ALGORITHMS[operation];
|
|
1372
|
+
if (!supported) return false;
|
|
1373
|
+
return supported.has(name);
|
|
1374
|
+
}
|
|
1149
1375
|
async decrypt(algorithm, key, data) {
|
|
1150
1376
|
const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'decrypt');
|
|
1151
1377
|
return cipherOrWrap(CipherOrWrapMode.kWebCryptoCipherDecrypt, normalizedAlgorithm, key, bufferLikeToArrayBuffer(data), 'decrypt');
|
|
@@ -1171,6 +1397,10 @@ export class Subtle {
|
|
|
1171
1397
|
return ecDeriveBits(algorithm, baseKey, length);
|
|
1172
1398
|
case 'HKDF':
|
|
1173
1399
|
return hkdfDeriveBits(algorithm, baseKey, length);
|
|
1400
|
+
case 'Argon2d':
|
|
1401
|
+
case 'Argon2i':
|
|
1402
|
+
case 'Argon2id':
|
|
1403
|
+
return argon2DeriveBits(algorithm, baseKey, length);
|
|
1174
1404
|
}
|
|
1175
1405
|
throw new Error(`'subtle.deriveBits()' for ${algorithm.name} is not implemented.`);
|
|
1176
1406
|
}
|
|
@@ -1201,6 +1431,11 @@ export class Subtle {
|
|
|
1201
1431
|
case 'HKDF':
|
|
1202
1432
|
derivedBits = hkdfDeriveBits(algorithm, baseKey, length);
|
|
1203
1433
|
break;
|
|
1434
|
+
case 'Argon2d':
|
|
1435
|
+
case 'Argon2i':
|
|
1436
|
+
case 'Argon2id':
|
|
1437
|
+
derivedBits = argon2DeriveBits(algorithm, baseKey, length);
|
|
1438
|
+
break;
|
|
1204
1439
|
default:
|
|
1205
1440
|
throw new Error(`'subtle.deriveKey()' for ${algorithm.name} is not implemented.`);
|
|
1206
1441
|
}
|
|
@@ -1214,7 +1449,19 @@ export class Subtle {
|
|
|
1214
1449
|
}
|
|
1215
1450
|
async exportKey(format, key) {
|
|
1216
1451
|
if (!key.extractable) throw new Error('key is not extractable');
|
|
1217
|
-
if (format === 'raw-
|
|
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
|
|
1464
|
+
if (format === 'raw-secret' || format === 'raw-public') format = 'raw';
|
|
1218
1465
|
switch (format) {
|
|
1219
1466
|
case 'spki':
|
|
1220
1467
|
return await exportKeySpki(key);
|
|
@@ -1339,6 +1586,11 @@ export class Subtle {
|
|
|
1339
1586
|
case 'HMAC':
|
|
1340
1587
|
result = await hmacGenerateKey(algorithm, extractable, keyUsages);
|
|
1341
1588
|
break;
|
|
1589
|
+
case 'KMAC128':
|
|
1590
|
+
// Fall through
|
|
1591
|
+
case 'KMAC256':
|
|
1592
|
+
result = await kmacGenerateKey(algorithm, extractable, keyUsages);
|
|
1593
|
+
break;
|
|
1342
1594
|
case 'Ed25519':
|
|
1343
1595
|
// Fall through
|
|
1344
1596
|
case 'Ed448':
|
|
@@ -1359,14 +1611,33 @@ export class Subtle {
|
|
|
1359
1611
|
result = await x_generateKeyPairWebCrypto(algorithm.name.toLowerCase(), extractable, keyUsages);
|
|
1360
1612
|
checkCryptoKeyPairUsages(result);
|
|
1361
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;
|
|
1362
1622
|
default:
|
|
1363
1623
|
throw new Error(`'subtle.generateKey()' is not implemented for ${algorithm.name}.
|
|
1364
1624
|
Unrecognized algorithm name`);
|
|
1365
1625
|
}
|
|
1366
1626
|
return result;
|
|
1367
1627
|
}
|
|
1628
|
+
async getPublicKey(key, keyUsages) {
|
|
1629
|
+
if (key.type === 'secret') {
|
|
1630
|
+
throw lazyDOMException('key must be a private key', 'NotSupportedError');
|
|
1631
|
+
}
|
|
1632
|
+
if (key.type !== 'private') {
|
|
1633
|
+
throw lazyDOMException('key must be a private key', 'InvalidAccessError');
|
|
1634
|
+
}
|
|
1635
|
+
const publicKeyObject = createPublicKey(key.keyObject);
|
|
1636
|
+
return publicKeyObject.toCryptoKey(key.algorithm, true, keyUsages);
|
|
1637
|
+
}
|
|
1368
1638
|
async importKey(format, data, algorithm, extractable, keyUsages) {
|
|
1369
|
-
|
|
1639
|
+
// Note: 'raw-seed' is NOT normalized — PQC import functions handle it directly
|
|
1640
|
+
if (format === 'raw-secret' || format === 'raw-public') format = 'raw';
|
|
1370
1641
|
const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'importKey');
|
|
1371
1642
|
let result;
|
|
1372
1643
|
switch (normalizedAlgorithm.name) {
|
|
@@ -1385,6 +1656,11 @@ export class Subtle {
|
|
|
1385
1656
|
case 'HMAC':
|
|
1386
1657
|
result = await hmacImportKey(normalizedAlgorithm, format, data, extractable, keyUsages);
|
|
1387
1658
|
break;
|
|
1659
|
+
case 'KMAC128':
|
|
1660
|
+
// Fall through
|
|
1661
|
+
case 'KMAC256':
|
|
1662
|
+
result = await kmacImportKey(normalizedAlgorithm, format, data, extractable, keyUsages);
|
|
1663
|
+
break;
|
|
1388
1664
|
case 'AES-CTR':
|
|
1389
1665
|
// Fall through
|
|
1390
1666
|
case 'AES-CBC':
|
|
@@ -1399,6 +1675,9 @@ export class Subtle {
|
|
|
1399
1675
|
result = await aesImportKey(normalizedAlgorithm, format, data, extractable, keyUsages);
|
|
1400
1676
|
break;
|
|
1401
1677
|
case 'PBKDF2':
|
|
1678
|
+
case 'Argon2d':
|
|
1679
|
+
case 'Argon2i':
|
|
1680
|
+
case 'Argon2id':
|
|
1402
1681
|
result = await importGenericSecretKey(normalizedAlgorithm, format, data, extractable, keyUsages);
|
|
1403
1682
|
break;
|
|
1404
1683
|
case 'HKDF':
|
|
@@ -1420,6 +1699,13 @@ export class Subtle {
|
|
|
1420
1699
|
case 'ML-DSA-87':
|
|
1421
1700
|
result = mldsaImportKey(format, data, normalizedAlgorithm, extractable, keyUsages);
|
|
1422
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;
|
|
1423
1709
|
default:
|
|
1424
1710
|
throw new Error(`"subtle.importKey()" is not implemented for ${normalizedAlgorithm.name}`);
|
|
1425
1711
|
}
|
|
@@ -1429,85 +1715,65 @@ export class Subtle {
|
|
|
1429
1715
|
return result;
|
|
1430
1716
|
}
|
|
1431
1717
|
async sign(algorithm, key, data) {
|
|
1432
|
-
|
|
1433
|
-
if (normalizedAlgorithm.name === 'HMAC') {
|
|
1434
|
-
// Validate key usage
|
|
1435
|
-
if (!key.usages.includes('sign')) {
|
|
1436
|
-
throw lazyDOMException('Key does not have sign usage', 'InvalidAccessError');
|
|
1437
|
-
}
|
|
1438
|
-
|
|
1439
|
-
// Get hash algorithm from key or algorithm params
|
|
1440
|
-
// Hash can be either a string or an object with name property
|
|
1441
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1442
|
-
const alg = normalizedAlgorithm;
|
|
1443
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1444
|
-
const keyAlg = key.algorithm;
|
|
1445
|
-
let hashAlgorithm = 'SHA-256';
|
|
1446
|
-
if (typeof alg.hash === 'string') {
|
|
1447
|
-
hashAlgorithm = alg.hash;
|
|
1448
|
-
} else if (alg.hash?.name) {
|
|
1449
|
-
hashAlgorithm = alg.hash.name;
|
|
1450
|
-
} else if (typeof keyAlg.hash === 'string') {
|
|
1451
|
-
hashAlgorithm = keyAlg.hash;
|
|
1452
|
-
} else if (keyAlg.hash?.name) {
|
|
1453
|
-
hashAlgorithm = keyAlg.hash.name;
|
|
1454
|
-
}
|
|
1455
|
-
|
|
1456
|
-
// Create HMAC and sign
|
|
1457
|
-
const keyData = key.keyObject.export();
|
|
1458
|
-
const hmac = createHmac(hashAlgorithm, keyData);
|
|
1459
|
-
hmac.update(bufferLikeToArrayBuffer(data));
|
|
1460
|
-
return bufferLikeToArrayBuffer(hmac.digest());
|
|
1461
|
-
}
|
|
1462
|
-
return signVerify(normalizedAlgorithm, key, data);
|
|
1718
|
+
return signVerify(normalizeAlgorithm(algorithm, 'sign'), key, data);
|
|
1463
1719
|
}
|
|
1464
1720
|
async verify(algorithm, key, signature, data) {
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
// Get hash algorithm
|
|
1473
|
-
// Hash can be either a string or an object with name property
|
|
1474
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1475
|
-
const alg = normalizedAlgorithm;
|
|
1476
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1477
|
-
const keyAlg = key.algorithm;
|
|
1478
|
-
let hashAlgorithm = 'SHA-256';
|
|
1479
|
-
if (typeof alg.hash === 'string') {
|
|
1480
|
-
hashAlgorithm = alg.hash;
|
|
1481
|
-
} else if (alg.hash?.name) {
|
|
1482
|
-
hashAlgorithm = alg.hash.name;
|
|
1483
|
-
} else if (typeof keyAlg.hash === 'string') {
|
|
1484
|
-
hashAlgorithm = keyAlg.hash;
|
|
1485
|
-
} else if (keyAlg.hash?.name) {
|
|
1486
|
-
hashAlgorithm = keyAlg.hash.name;
|
|
1487
|
-
}
|
|
1488
|
-
|
|
1489
|
-
// Create HMAC and compute expected signature
|
|
1490
|
-
const keyData = key.keyObject.export();
|
|
1491
|
-
const hmac = createHmac(hashAlgorithm, keyData);
|
|
1492
|
-
const dataBuffer = bufferLikeToArrayBuffer(data);
|
|
1493
|
-
hmac.update(dataBuffer);
|
|
1494
|
-
const expectedDigest = hmac.digest();
|
|
1495
|
-
const expected = new Uint8Array(bufferLikeToArrayBuffer(expectedDigest));
|
|
1496
|
-
|
|
1497
|
-
// Constant-time comparison
|
|
1498
|
-
const signatureArray = new Uint8Array(bufferLikeToArrayBuffer(signature));
|
|
1499
|
-
if (expected.length !== signatureArray.length) {
|
|
1500
|
-
return false;
|
|
1501
|
-
}
|
|
1502
|
-
|
|
1503
|
-
// Manual constant-time comparison
|
|
1504
|
-
let result = 0;
|
|
1505
|
-
for (let i = 0; i < expected.length; i++) {
|
|
1506
|
-
result |= expected[i] ^ signatureArray[i];
|
|
1507
|
-
}
|
|
1508
|
-
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');
|
|
1509
1727
|
}
|
|
1510
|
-
|
|
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');
|
|
1748
|
+
}
|
|
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);
|
|
1511
1777
|
}
|
|
1512
1778
|
}
|
|
1513
1779
|
export const subtle = new Subtle();
|
|
@@ -1526,6 +1792,10 @@ function getKeyLength(algorithm) {
|
|
|
1526
1792
|
const hmacAlg = algorithm;
|
|
1527
1793
|
return hmacAlg.length || 256;
|
|
1528
1794
|
}
|
|
1795
|
+
case 'KMAC128':
|
|
1796
|
+
return algorithm.length || 128;
|
|
1797
|
+
case 'KMAC256':
|
|
1798
|
+
return algorithm.length || 256;
|
|
1529
1799
|
default:
|
|
1530
1800
|
throw lazyDOMException(`Cannot determine key length for ${name}`, 'NotSupportedError');
|
|
1531
1801
|
}
|