react-native-quick-crypto 1.0.0-beta.21 → 1.0.0-beta.22
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/QuickCrypto.podspec +11 -1
- package/android/CMakeLists.txt +2 -0
- package/cpp/cipher/GCMCipher.cpp +68 -0
- package/cpp/cipher/GCMCipher.hpp +14 -0
- package/cpp/cipher/HybridCipherFactory.hpp +8 -0
- package/cpp/cipher/HybridRsaCipher.cpp +229 -0
- package/cpp/cipher/HybridRsaCipher.hpp +23 -0
- package/cpp/keys/HybridKeyObjectHandle.cpp +508 -9
- package/cpp/keys/HybridKeyObjectHandle.hpp +10 -1
- package/cpp/utils/base64.h +309 -0
- package/lib/commonjs/ec.js +85 -17
- package/lib/commonjs/ec.js.map +1 -1
- package/lib/commonjs/specs/rsaCipher.nitro.js +6 -0
- package/lib/commonjs/specs/rsaCipher.nitro.js.map +1 -0
- package/lib/commonjs/subtle.js +420 -17
- package/lib/commonjs/subtle.js.map +1 -1
- package/lib/commonjs/utils/conversion.js +1 -1
- package/lib/commonjs/utils/conversion.js.map +1 -1
- package/lib/module/ec.js +86 -18
- package/lib/module/ec.js.map +1 -1
- package/lib/module/specs/rsaCipher.nitro.js +4 -0
- package/lib/module/specs/rsaCipher.nitro.js.map +1 -0
- package/lib/module/subtle.js +421 -18
- package/lib/module/subtle.js.map +1 -1
- package/lib/module/utils/conversion.js +1 -1
- package/lib/module/utils/conversion.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/typescript/ec.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/rsaCipher.nitro.d.ts +26 -0
- package/lib/typescript/specs/rsaCipher.nitro.d.ts.map +1 -0
- package/lib/typescript/subtle.d.ts.map +1 -1
- package/lib/typescript/utils/conversion.d.ts.map +1 -1
- package/lib/typescript/utils/types.d.ts +1 -1
- package/lib/typescript/utils/types.d.ts.map +1 -1
- package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +1 -0
- package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +10 -0
- package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +10 -0
- package/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp +104 -0
- package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp +1 -0
- package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp +5 -4
- package/nitrogen/generated/shared/c++/HybridRsaCipherSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridRsaCipherSpec.hpp +70 -0
- package/package.json +1 -1
- package/src/ec.ts +122 -20
- package/src/specs/keyObjectHandle.nitro.ts +1 -0
- package/src/specs/rsaCipher.nitro.ts +35 -0
- package/src/subtle.ts +550 -45
- package/src/utils/conversion.ts +3 -1
- package/src/utils/types.ts +6 -6
- package/nitrogen/generated/shared/c++/CFRGKeyPairType.hpp +0 -84
package/lib/module/ec.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { NitroModules } from 'react-native-nitro-modules';
|
|
4
|
-
import { CryptoKey, KeyObject } from './keys';
|
|
4
|
+
import { CryptoKey, KeyObject, PublicKeyObject, PrivateKeyObject } from './keys';
|
|
5
5
|
import { bufferLikeToArrayBuffer, getUsagesUnion, hasAnyNotIn, kNamedCurveAliases, lazyDOMException, normalizeHashName, HashContext, KeyEncoding, KFormatType } from './utils';
|
|
6
6
|
export class Ec {
|
|
7
7
|
constructor(curve) {
|
|
@@ -84,32 +84,100 @@ export function ecImportKey(format, keyData, algorithm, extractable, keyUsages)
|
|
|
84
84
|
if (!namedCurve || !kNamedCurveAliases[namedCurve]) {
|
|
85
85
|
throw lazyDOMException('Unrecognized namedCurve', 'NotSupportedError');
|
|
86
86
|
}
|
|
87
|
+
|
|
88
|
+
// Handle JWK format
|
|
89
|
+
if (format === 'jwk') {
|
|
90
|
+
const jwk = keyData;
|
|
91
|
+
|
|
92
|
+
// Validate JWK
|
|
93
|
+
if (jwk.kty !== 'EC') {
|
|
94
|
+
throw lazyDOMException('Invalid JWK "kty" Parameter', 'DataError');
|
|
95
|
+
}
|
|
96
|
+
if (jwk.crv !== namedCurve) {
|
|
97
|
+
throw lazyDOMException('JWK "crv" does not match the requested algorithm', 'DataError');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Check use parameter if present
|
|
101
|
+
if (jwk.use !== undefined) {
|
|
102
|
+
const expectedUse = name === 'ECDH' ? 'enc' : 'sig';
|
|
103
|
+
if (jwk.use !== expectedUse) {
|
|
104
|
+
throw lazyDOMException('Invalid JWK "use" Parameter', 'DataError');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Check alg parameter if present
|
|
109
|
+
if (jwk.alg !== undefined) {
|
|
110
|
+
let expectedAlg;
|
|
111
|
+
if (name === 'ECDSA') {
|
|
112
|
+
// Map namedCurve to expected ECDSA algorithm
|
|
113
|
+
expectedAlg = namedCurve === 'P-256' ? 'ES256' : namedCurve === 'P-384' ? 'ES384' : namedCurve === 'P-521' ? 'ES512' : undefined;
|
|
114
|
+
} else if (name === 'ECDH') {
|
|
115
|
+
// ECDH uses ECDH-ES algorithm
|
|
116
|
+
expectedAlg = 'ECDH-ES';
|
|
117
|
+
}
|
|
118
|
+
if (expectedAlg && jwk.alg !== expectedAlg) {
|
|
119
|
+
throw lazyDOMException('JWK "alg" does not match the requested algorithm', 'DataError');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Import using C++ layer
|
|
124
|
+
const handle = NitroModules.createHybridObject('KeyObjectHandle');
|
|
125
|
+
const keyType = handle.initJwk(jwk, namedCurve);
|
|
126
|
+
if (keyType === undefined) {
|
|
127
|
+
throw lazyDOMException('Invalid JWK', 'DataError');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Create the appropriate KeyObject based on type
|
|
131
|
+
let keyObject;
|
|
132
|
+
if (keyType === 1) {
|
|
133
|
+
keyObject = new PublicKeyObject(handle);
|
|
134
|
+
} else if (keyType === 2) {
|
|
135
|
+
keyObject = new PrivateKeyObject(handle);
|
|
136
|
+
} else {
|
|
137
|
+
throw lazyDOMException('Unexpected key type from JWK import', 'DataError');
|
|
138
|
+
}
|
|
139
|
+
return new CryptoKey(keyObject, algorithm, keyUsages, extractable);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Handle binary formats (spki, pkcs8, raw)
|
|
87
143
|
if (format !== 'spki' && format !== 'pkcs8' && format !== 'raw') {
|
|
88
144
|
throw lazyDOMException(`Unsupported format: ${format}`, 'NotSupportedError');
|
|
89
145
|
}
|
|
90
146
|
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
147
|
+
// Determine expected key type based on format
|
|
148
|
+
const expectedKeyType = format === 'spki' || format === 'raw' ? 'public' : 'private';
|
|
149
|
+
|
|
150
|
+
// Validate usages for the key type
|
|
151
|
+
const isPublicKey = expectedKeyType === 'public';
|
|
152
|
+
let validUsages;
|
|
153
|
+
if (name === 'ECDSA') {
|
|
154
|
+
validUsages = isPublicKey ? ['verify'] : ['sign'];
|
|
155
|
+
} else if (name === 'ECDH') {
|
|
156
|
+
validUsages = isPublicKey ? [] : ['deriveKey', 'deriveBits'];
|
|
157
|
+
} else {
|
|
158
|
+
throw lazyDOMException('Unsupported algorithm', 'NotSupportedError');
|
|
159
|
+
}
|
|
160
|
+
if (hasAnyNotIn(keyUsages, validUsages)) {
|
|
161
|
+
throw lazyDOMException(`Unsupported key usage for a ${name} key`, 'SyntaxError');
|
|
94
162
|
}
|
|
95
163
|
|
|
96
164
|
// Convert keyData to ArrayBuffer
|
|
97
165
|
const keyBuffer = bufferLikeToArrayBuffer(keyData);
|
|
98
166
|
|
|
99
|
-
// Create
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
167
|
+
// Create KeyObject directly using the appropriate format
|
|
168
|
+
let keyObject;
|
|
169
|
+
if (format === 'raw') {
|
|
170
|
+
// Raw format is only for public keys - use specialized EC raw import
|
|
171
|
+
const handle = NitroModules.createHybridObject('KeyObjectHandle');
|
|
172
|
+
const curveAlias = kNamedCurveAliases[namedCurve];
|
|
173
|
+
if (!handle.initECRaw(curveAlias, keyBuffer)) {
|
|
174
|
+
throw lazyDOMException('Failed to import EC raw key', 'DataError');
|
|
175
|
+
}
|
|
176
|
+
keyObject = new PublicKeyObject(handle);
|
|
177
|
+
} else {
|
|
178
|
+
// Use standard DER import for spki/pkcs8
|
|
179
|
+
keyObject = KeyObject.createKeyObject(expectedKeyType, keyBuffer, 'der', format);
|
|
180
|
+
}
|
|
113
181
|
return new CryptoKey(keyObject, algorithm, keyUsages, extractable);
|
|
114
182
|
// // // verifyAcceptableEcKeyUse(name, true, usagesSet);
|
|
115
183
|
// // try {
|
package/lib/module/ec.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NitroModules","CryptoKey","KeyObject","bufferLikeToArrayBuffer","getUsagesUnion","hasAnyNotIn","kNamedCurveAliases","lazyDOMException","normalizeHashName","HashContext","KeyEncoding","KFormatType","Ec","constructor","curve","native","createHybridObject","setCurve","generateKeyPair","publicKey","getPublicKey","privateKey","getPrivateKey","generateKeyPairSync","ecImportKey","format","keyData","algorithm","extractable","keyUsages","name","namedCurve","
|
|
1
|
+
{"version":3,"names":["NitroModules","CryptoKey","KeyObject","PublicKeyObject","PrivateKeyObject","bufferLikeToArrayBuffer","getUsagesUnion","hasAnyNotIn","kNamedCurveAliases","lazyDOMException","normalizeHashName","HashContext","KeyEncoding","KFormatType","Ec","constructor","curve","native","createHybridObject","setCurve","generateKeyPair","publicKey","getPublicKey","privateKey","getPrivateKey","generateKeyPairSync","ecImportKey","format","keyData","algorithm","extractable","keyUsages","name","namedCurve","jwk","kty","crv","use","undefined","expectedUse","alg","expectedAlg","handle","keyType","initJwk","keyObject","expectedKeyType","isPublicKey","validUsages","keyBuffer","curveAlias","initECRaw","createKeyObject","ecdsaSignVerify","key","data","hash","signature","isSign","type","hashName","normalizedHashName","WebCrypto","ec","encoding","PKCS8","SPKI","exportKey","DER","importKey","usages","dataBuffer","sign","signatureBuffer","verify","ec_generateKeyPair","_options","Object","keys","includes","publicUsages","privateUsages","keyAlgorithm","publicKeyData","privateKeyData","pub","privateEncoding","priv"],"sourceRoot":"../../src","sources":["ec.ts"],"mappings":"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AAiB,CAAC;IACrE,MAAMgC,UAAU,GACd1C,kBAAkB,CAACyB,UAAU,CAAoC;IACnE,IAAI,CAACS,MAAM,CAACS,SAAS,CAACD,UAAU,EAAED,SAAS,CAAC,EAAE;MAC5C,MAAMxC,gBAAgB,CAAC,6BAA6B,EAAE,WAAW,CAAC;IACpE;IACAoC,SAAS,GAAG,IAAI1C,eAAe,CAACuC,MAAM,CAAC;EACzC,CAAC,MAAM;IACL;IACAG,SAAS,GAAG3C,SAAS,CAACkD,eAAe,CACnCN,eAAe,EACfG,SAAS,EACT,KAAK,EACLtB,MACF,CAAC;EACH;EAEA,OAAO,IAAI1B,SAAS,CAAC4C,SAAS,EAAEhB,SAAS,EAAEE,SAAS,EAAED,WAAW,CAAC;EAClE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AACF;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,OAAO,MAAMuB,eAAe,GAAGA,CAC7BC,GAAc,EACdC,IAAgB,EAChB;EAAEC;AAAsB,CAAC,EACzBC,SAAsB,KACI;EAC1B,MAAMC,MAAM,GAAGD,SAAS,KAAKnB,SAAS;EACtC,MAAMQ,eAAe,GAAGY,MAAM,GAAG,SAAS,GAAG,QAAQ;EAErD,IAAIJ,GAAG,CAACK,IAAI,KAAK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","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../../src","sources":["specs/rsaCipher.nitro.ts"],"mappings":"","ignoreList":[]}
|
package/lib/module/subtle.js
CHANGED
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
4
4
|
import { Buffer as SBuffer } from 'safe-buffer';
|
|
5
|
-
import { CryptoKey } from './keys';
|
|
5
|
+
import { CryptoKey, KeyObject, PublicKeyObject, PrivateKeyObject, SecretKeyObject } from './keys';
|
|
6
6
|
import { bufferLikeToArrayBuffer } from './utils/conversion';
|
|
7
7
|
import { lazyDOMException } from './utils/errors';
|
|
8
8
|
import { normalizeHashName, HashContext } from './utils/hashnames';
|
|
9
9
|
import { validateMaxBufferLength } from './utils/validation';
|
|
10
10
|
import { asyncDigest } from './hash';
|
|
11
11
|
import { createSecretKey } from './keys';
|
|
12
|
+
import { NitroModules } from 'react-native-nitro-modules';
|
|
12
13
|
import { pbkdf2DeriveBits } from './pbkdf2';
|
|
13
14
|
import { ecImportKey, ecdsaSignVerify, ec_generateKeyPair } from './ec';
|
|
14
15
|
import { rsa_generateKeyPair } from './rsa';
|
|
16
|
+
import { getRandomValues } from './random';
|
|
15
17
|
// import { pbkdf2DeriveBits } from './pbkdf2';
|
|
16
18
|
// import { aesCipher, aesGenerateKey, aesImportKey, getAlgorithmName } from './aes';
|
|
17
19
|
// import { rsaCipher, rsaExportKey, rsaImportKey, rsaKeyGenerate } from './rsa';
|
|
@@ -46,29 +48,426 @@ function getAlgorithmName(name, length) {
|
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
// Placeholder implementations for missing functions
|
|
49
|
-
function ecExportKey(
|
|
50
|
-
|
|
51
|
+
function ecExportKey(key, format) {
|
|
52
|
+
const keyObject = key.keyObject;
|
|
53
|
+
if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatSPKI) {
|
|
54
|
+
// Export public key in SPKI format
|
|
55
|
+
const exported = keyObject.export({
|
|
56
|
+
format: 'der',
|
|
57
|
+
type: 'spki'
|
|
58
|
+
});
|
|
59
|
+
return bufferLikeToArrayBuffer(exported);
|
|
60
|
+
} else if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatPKCS8) {
|
|
61
|
+
// Export private key in PKCS8 format
|
|
62
|
+
const exported = keyObject.export({
|
|
63
|
+
format: 'der',
|
|
64
|
+
type: 'pkcs8'
|
|
65
|
+
});
|
|
66
|
+
return bufferLikeToArrayBuffer(exported);
|
|
67
|
+
} else {
|
|
68
|
+
throw new Error(`Unsupported EC export format: ${format}`);
|
|
69
|
+
}
|
|
51
70
|
}
|
|
52
|
-
function rsaExportKey(
|
|
53
|
-
|
|
71
|
+
function rsaExportKey(key, format) {
|
|
72
|
+
const keyObject = key.keyObject;
|
|
73
|
+
if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatSPKI) {
|
|
74
|
+
// Export public key in SPKI format
|
|
75
|
+
const exported = keyObject.export({
|
|
76
|
+
format: 'der',
|
|
77
|
+
type: 'spki'
|
|
78
|
+
});
|
|
79
|
+
return bufferLikeToArrayBuffer(exported);
|
|
80
|
+
} else if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatPKCS8) {
|
|
81
|
+
// Export private key in PKCS8 format
|
|
82
|
+
const exported = keyObject.export({
|
|
83
|
+
format: 'der',
|
|
84
|
+
type: 'pkcs8'
|
|
85
|
+
});
|
|
86
|
+
return bufferLikeToArrayBuffer(exported);
|
|
87
|
+
} else {
|
|
88
|
+
throw new Error(`Unsupported RSA export format: ${format}`);
|
|
89
|
+
}
|
|
54
90
|
}
|
|
55
|
-
function rsaCipher(
|
|
56
|
-
|
|
91
|
+
async function rsaCipher(mode, key, data, algorithm) {
|
|
92
|
+
const rsaParams = algorithm;
|
|
93
|
+
|
|
94
|
+
// Validate key type matches operation
|
|
95
|
+
const expectedType = mode === CipherOrWrapMode.kWebCryptoCipherEncrypt ? 'public' : 'private';
|
|
96
|
+
if (key.type !== expectedType) {
|
|
97
|
+
throw lazyDOMException('The requested operation is not valid for the provided key', 'InvalidAccessError');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Get hash algorithm from key
|
|
101
|
+
const hashAlgorithm = normalizeHashName(key.algorithm.hash);
|
|
102
|
+
|
|
103
|
+
// Prepare label (optional)
|
|
104
|
+
const label = rsaParams.label ? bufferLikeToArrayBuffer(rsaParams.label) : undefined;
|
|
105
|
+
|
|
106
|
+
// Create RSA cipher instance
|
|
107
|
+
const rsaCipherModule = NitroModules.createHybridObject('RsaCipher');
|
|
108
|
+
if (mode === CipherOrWrapMode.kWebCryptoCipherEncrypt) {
|
|
109
|
+
// Encrypt with public key
|
|
110
|
+
return rsaCipherModule.encrypt(key.keyObject.handle, data, hashAlgorithm, label);
|
|
111
|
+
} else {
|
|
112
|
+
// Decrypt with private key
|
|
113
|
+
return rsaCipherModule.decrypt(key.keyObject.handle, data, hashAlgorithm, label);
|
|
114
|
+
}
|
|
57
115
|
}
|
|
58
|
-
function aesCipher(
|
|
59
|
-
|
|
116
|
+
async function aesCipher(mode, key, data, algorithm) {
|
|
117
|
+
const {
|
|
118
|
+
name
|
|
119
|
+
} = algorithm;
|
|
120
|
+
switch (name) {
|
|
121
|
+
case 'AES-CTR':
|
|
122
|
+
return aesCtrCipher(mode, key, data, algorithm);
|
|
123
|
+
case 'AES-CBC':
|
|
124
|
+
return aesCbcCipher(mode, key, data, algorithm);
|
|
125
|
+
case 'AES-GCM':
|
|
126
|
+
return aesGcmCipher(mode, key, data, algorithm);
|
|
127
|
+
default:
|
|
128
|
+
throw lazyDOMException(`Unsupported AES algorithm: ${name}`, 'NotSupportedError');
|
|
129
|
+
}
|
|
60
130
|
}
|
|
61
|
-
async function
|
|
62
|
-
|
|
131
|
+
async function aesCtrCipher(mode, key, data, algorithm) {
|
|
132
|
+
// Validate counter and length
|
|
133
|
+
if (!algorithm.counter || algorithm.counter.byteLength !== 16) {
|
|
134
|
+
throw lazyDOMException('AES-CTR algorithm.counter must be 16 bytes', 'OperationError');
|
|
135
|
+
}
|
|
136
|
+
if (algorithm.length < 1 || algorithm.length > 128) {
|
|
137
|
+
throw lazyDOMException('AES-CTR algorithm.length must be between 1 and 128', 'OperationError');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Get cipher type based on key length
|
|
141
|
+
const keyLength = key.algorithm.length;
|
|
142
|
+
const cipherType = `aes-${keyLength}-ctr`;
|
|
143
|
+
|
|
144
|
+
// Create cipher
|
|
145
|
+
const factory = NitroModules.createHybridObject('CipherFactory');
|
|
146
|
+
const cipher = factory.createCipher({
|
|
147
|
+
isCipher: mode === CipherOrWrapMode.kWebCryptoCipherEncrypt,
|
|
148
|
+
cipherType,
|
|
149
|
+
cipherKey: bufferLikeToArrayBuffer(key.keyObject.export()),
|
|
150
|
+
iv: bufferLikeToArrayBuffer(algorithm.counter)
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Process data
|
|
154
|
+
const updated = cipher.update(data);
|
|
155
|
+
const final = cipher.final();
|
|
156
|
+
|
|
157
|
+
// Concatenate results
|
|
158
|
+
const result = new Uint8Array(updated.byteLength + final.byteLength);
|
|
159
|
+
result.set(new Uint8Array(updated), 0);
|
|
160
|
+
result.set(new Uint8Array(final), updated.byteLength);
|
|
161
|
+
return result.buffer;
|
|
63
162
|
}
|
|
64
|
-
function
|
|
65
|
-
|
|
163
|
+
async function aesCbcCipher(mode, key, data, algorithm) {
|
|
164
|
+
// Validate IV
|
|
165
|
+
const iv = bufferLikeToArrayBuffer(algorithm.iv);
|
|
166
|
+
if (iv.byteLength !== 16) {
|
|
167
|
+
throw lazyDOMException('algorithm.iv must contain exactly 16 bytes', 'OperationError');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Get cipher type based on key length
|
|
171
|
+
const keyLength = key.algorithm.length;
|
|
172
|
+
const cipherType = `aes-${keyLength}-cbc`;
|
|
173
|
+
|
|
174
|
+
// Create cipher
|
|
175
|
+
const factory = NitroModules.createHybridObject('CipherFactory');
|
|
176
|
+
const cipher = factory.createCipher({
|
|
177
|
+
isCipher: mode === CipherOrWrapMode.kWebCryptoCipherEncrypt,
|
|
178
|
+
cipherType,
|
|
179
|
+
cipherKey: bufferLikeToArrayBuffer(key.keyObject.export()),
|
|
180
|
+
iv
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Process data
|
|
184
|
+
const updated = cipher.update(data);
|
|
185
|
+
const final = cipher.final();
|
|
186
|
+
|
|
187
|
+
// Concatenate results
|
|
188
|
+
const result = new Uint8Array(updated.byteLength + final.byteLength);
|
|
189
|
+
result.set(new Uint8Array(updated), 0);
|
|
190
|
+
result.set(new Uint8Array(final), updated.byteLength);
|
|
191
|
+
return result.buffer;
|
|
66
192
|
}
|
|
67
|
-
async function
|
|
68
|
-
|
|
193
|
+
async function aesGcmCipher(mode, key, data, algorithm) {
|
|
194
|
+
const {
|
|
195
|
+
tagLength = 128
|
|
196
|
+
} = algorithm;
|
|
197
|
+
|
|
198
|
+
// Validate tag length
|
|
199
|
+
const validTagLengths = [32, 64, 96, 104, 112, 120, 128];
|
|
200
|
+
if (!validTagLengths.includes(tagLength)) {
|
|
201
|
+
throw lazyDOMException(`${tagLength} is not a valid AES-GCM tag length`, 'OperationError');
|
|
202
|
+
}
|
|
203
|
+
const tagByteLength = tagLength / 8;
|
|
204
|
+
|
|
205
|
+
// Get cipher type based on key length
|
|
206
|
+
const keyLength = key.algorithm.length;
|
|
207
|
+
const cipherType = `aes-${keyLength}-gcm`;
|
|
208
|
+
|
|
209
|
+
// Create cipher
|
|
210
|
+
const factory = NitroModules.createHybridObject('CipherFactory');
|
|
211
|
+
const cipher = factory.createCipher({
|
|
212
|
+
isCipher: mode === CipherOrWrapMode.kWebCryptoCipherEncrypt,
|
|
213
|
+
cipherType,
|
|
214
|
+
cipherKey: bufferLikeToArrayBuffer(key.keyObject.export()),
|
|
215
|
+
iv: bufferLikeToArrayBuffer(algorithm.iv),
|
|
216
|
+
authTagLen: tagByteLength
|
|
217
|
+
});
|
|
218
|
+
let processData;
|
|
219
|
+
let authTag;
|
|
220
|
+
if (mode === CipherOrWrapMode.kWebCryptoCipherDecrypt) {
|
|
221
|
+
// For decryption, extract auth tag from end of data
|
|
222
|
+
const dataView = new Uint8Array(data);
|
|
223
|
+
if (dataView.byteLength < tagByteLength) {
|
|
224
|
+
throw lazyDOMException('The provided data is too small.', 'OperationError');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Split data and tag
|
|
228
|
+
const ciphertextLength = dataView.byteLength - tagByteLength;
|
|
229
|
+
processData = dataView.slice(0, ciphertextLength).buffer;
|
|
230
|
+
authTag = dataView.slice(ciphertextLength).buffer;
|
|
231
|
+
|
|
232
|
+
// Set auth tag for verification
|
|
233
|
+
cipher.setAuthTag(authTag);
|
|
234
|
+
} else {
|
|
235
|
+
processData = data;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Set additional authenticated data if provided
|
|
239
|
+
if (algorithm.additionalData) {
|
|
240
|
+
cipher.setAAD(bufferLikeToArrayBuffer(algorithm.additionalData));
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Process data
|
|
244
|
+
const updated = cipher.update(processData);
|
|
245
|
+
const final = cipher.final();
|
|
246
|
+
if (mode === CipherOrWrapMode.kWebCryptoCipherEncrypt) {
|
|
247
|
+
// For encryption, append auth tag to result
|
|
248
|
+
const tag = cipher.getAuthTag();
|
|
249
|
+
const result = new Uint8Array(updated.byteLength + final.byteLength + tag.byteLength);
|
|
250
|
+
result.set(new Uint8Array(updated), 0);
|
|
251
|
+
result.set(new Uint8Array(final), updated.byteLength);
|
|
252
|
+
result.set(new Uint8Array(tag), updated.byteLength + final.byteLength);
|
|
253
|
+
return result.buffer;
|
|
254
|
+
} else {
|
|
255
|
+
// For decryption, just concatenate plaintext
|
|
256
|
+
const result = new Uint8Array(updated.byteLength + final.byteLength);
|
|
257
|
+
result.set(new Uint8Array(updated), 0);
|
|
258
|
+
result.set(new Uint8Array(final), updated.byteLength);
|
|
259
|
+
return result.buffer;
|
|
260
|
+
}
|
|
69
261
|
}
|
|
70
|
-
async function
|
|
71
|
-
|
|
262
|
+
async function aesGenerateKey(algorithm, extractable, keyUsages) {
|
|
263
|
+
const {
|
|
264
|
+
length
|
|
265
|
+
} = algorithm;
|
|
266
|
+
const name = algorithm.name;
|
|
267
|
+
if (!name) {
|
|
268
|
+
throw lazyDOMException('Algorithm name is required', 'OperationError');
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Validate key length
|
|
272
|
+
if (![128, 192, 256].includes(length)) {
|
|
273
|
+
throw lazyDOMException(`Invalid AES key length: ${length}. Must be 128, 192, or 256.`, 'OperationError');
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Validate usages
|
|
277
|
+
const validUsages = ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey'];
|
|
278
|
+
if (hasAnyNotIn(keyUsages, validUsages)) {
|
|
279
|
+
throw lazyDOMException(`Unsupported key usage for ${name}`, 'SyntaxError');
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Generate random key bytes
|
|
283
|
+
const keyBytes = new Uint8Array(length / 8);
|
|
284
|
+
getRandomValues(keyBytes);
|
|
285
|
+
|
|
286
|
+
// Create secret key
|
|
287
|
+
const keyObject = createSecretKey(keyBytes);
|
|
288
|
+
|
|
289
|
+
// Construct algorithm object with guaranteed name
|
|
290
|
+
const keyAlgorithm = {
|
|
291
|
+
name,
|
|
292
|
+
length
|
|
293
|
+
};
|
|
294
|
+
return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
|
|
295
|
+
}
|
|
296
|
+
function rsaImportKey(format, data, algorithm, extractable, keyUsages) {
|
|
297
|
+
const {
|
|
298
|
+
name
|
|
299
|
+
} = algorithm;
|
|
300
|
+
|
|
301
|
+
// Validate usages
|
|
302
|
+
let checkSet;
|
|
303
|
+
switch (name) {
|
|
304
|
+
case 'RSASSA-PKCS1-v1_5':
|
|
305
|
+
case 'RSA-PSS':
|
|
306
|
+
checkSet = ['sign', 'verify'];
|
|
307
|
+
break;
|
|
308
|
+
case 'RSA-OAEP':
|
|
309
|
+
checkSet = ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey'];
|
|
310
|
+
break;
|
|
311
|
+
default:
|
|
312
|
+
throw new Error(`Unsupported RSA algorithm: ${name}`);
|
|
313
|
+
}
|
|
314
|
+
if (hasAnyNotIn(keyUsages, checkSet)) {
|
|
315
|
+
throw new Error(`Unsupported key usage for ${name}`);
|
|
316
|
+
}
|
|
317
|
+
let keyObject;
|
|
318
|
+
if (format === 'jwk') {
|
|
319
|
+
const jwk = data;
|
|
320
|
+
|
|
321
|
+
// Validate JWK
|
|
322
|
+
if (jwk.kty !== 'RSA') {
|
|
323
|
+
throw new Error('Invalid JWK format for RSA key');
|
|
324
|
+
}
|
|
325
|
+
const handle = NitroModules.createHybridObject('KeyObjectHandle');
|
|
326
|
+
const keyType = handle.initJwk(jwk, undefined);
|
|
327
|
+
if (keyType === undefined) {
|
|
328
|
+
throw new Error('Failed to import RSA JWK');
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Create the appropriate KeyObject based on type
|
|
332
|
+
if (keyType === 1) {
|
|
333
|
+
keyObject = new PublicKeyObject(handle);
|
|
334
|
+
} else if (keyType === 2) {
|
|
335
|
+
keyObject = new PrivateKeyObject(handle);
|
|
336
|
+
} else {
|
|
337
|
+
throw new Error('Unexpected key type from RSA JWK import');
|
|
338
|
+
}
|
|
339
|
+
} else if (format === 'spki') {
|
|
340
|
+
const keyData = bufferLikeToArrayBuffer(data);
|
|
341
|
+
keyObject = KeyObject.createKeyObject('public', keyData, 'der', 'spki');
|
|
342
|
+
} else if (format === 'pkcs8') {
|
|
343
|
+
const keyData = bufferLikeToArrayBuffer(data);
|
|
344
|
+
keyObject = KeyObject.createKeyObject('private', keyData, 'der', 'pkcs8');
|
|
345
|
+
} else {
|
|
346
|
+
throw new Error(`Unsupported format for RSA import: ${format}`);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Get the modulus length from the key and add it to the algorithm
|
|
350
|
+
const keyDetails = keyObject.asymmetricKeyDetails;
|
|
351
|
+
|
|
352
|
+
// Convert publicExponent number to big-endian byte array
|
|
353
|
+
let publicExponentBytes;
|
|
354
|
+
if (keyDetails?.publicExponent) {
|
|
355
|
+
const exp = keyDetails.publicExponent;
|
|
356
|
+
// Convert number to big-endian bytes
|
|
357
|
+
const bytes = [];
|
|
358
|
+
let value = exp;
|
|
359
|
+
while (value > 0) {
|
|
360
|
+
bytes.unshift(value & 0xff);
|
|
361
|
+
value = Math.floor(value / 256);
|
|
362
|
+
}
|
|
363
|
+
publicExponentBytes = new Uint8Array(bytes.length > 0 ? bytes : [0]);
|
|
364
|
+
}
|
|
365
|
+
const algorithmWithDetails = {
|
|
366
|
+
...algorithm,
|
|
367
|
+
modulusLength: keyDetails?.modulusLength,
|
|
368
|
+
publicExponent: publicExponentBytes
|
|
369
|
+
};
|
|
370
|
+
return new CryptoKey(keyObject, algorithmWithDetails, keyUsages, extractable);
|
|
371
|
+
}
|
|
372
|
+
async function hmacImportKey(algorithm, format, data, extractable, keyUsages) {
|
|
373
|
+
// Validate usages
|
|
374
|
+
if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
|
|
375
|
+
throw new Error('Unsupported key usage for an HMAC key');
|
|
376
|
+
}
|
|
377
|
+
let keyObject;
|
|
378
|
+
if (format === 'jwk') {
|
|
379
|
+
const jwk = data;
|
|
380
|
+
|
|
381
|
+
// Validate JWK
|
|
382
|
+
if (!jwk || typeof jwk !== 'object') {
|
|
383
|
+
throw new Error('Invalid keyData');
|
|
384
|
+
}
|
|
385
|
+
if (jwk.kty !== 'oct') {
|
|
386
|
+
throw new Error('Invalid JWK format for HMAC key');
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Validate key length if specified
|
|
390
|
+
if (algorithm.length !== undefined) {
|
|
391
|
+
if (!jwk.k) {
|
|
392
|
+
throw new Error('JWK missing key data');
|
|
393
|
+
}
|
|
394
|
+
// Decode to check length
|
|
395
|
+
const decoded = SBuffer.from(jwk.k, 'base64');
|
|
396
|
+
const keyBitLength = decoded.length * 8;
|
|
397
|
+
if (algorithm.length === 0) {
|
|
398
|
+
throw new Error('Zero-length key is not supported');
|
|
399
|
+
}
|
|
400
|
+
if (algorithm.length !== keyBitLength) {
|
|
401
|
+
throw new Error('Invalid key length');
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
const handle = NitroModules.createHybridObject('KeyObjectHandle');
|
|
405
|
+
const keyType = handle.initJwk(jwk, undefined);
|
|
406
|
+
if (keyType === undefined || keyType !== 0) {
|
|
407
|
+
throw new Error('Failed to import HMAC JWK');
|
|
408
|
+
}
|
|
409
|
+
keyObject = new SecretKeyObject(handle);
|
|
410
|
+
} else if (format === 'raw') {
|
|
411
|
+
keyObject = createSecretKey(data);
|
|
412
|
+
} else {
|
|
413
|
+
throw new Error(`Unable to import HMAC key with format ${format}`);
|
|
414
|
+
}
|
|
415
|
+
return new CryptoKey(keyObject, {
|
|
416
|
+
...algorithm,
|
|
417
|
+
name: 'HMAC'
|
|
418
|
+
}, keyUsages, extractable);
|
|
419
|
+
}
|
|
420
|
+
async function aesImportKey(algorithm, format, data, extractable, keyUsages) {
|
|
421
|
+
const {
|
|
422
|
+
name,
|
|
423
|
+
length
|
|
424
|
+
} = algorithm;
|
|
425
|
+
|
|
426
|
+
// Validate usages
|
|
427
|
+
const validUsages = ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey'];
|
|
428
|
+
if (hasAnyNotIn(keyUsages, validUsages)) {
|
|
429
|
+
throw new Error(`Unsupported key usage for ${name}`);
|
|
430
|
+
}
|
|
431
|
+
let keyObject;
|
|
432
|
+
let actualLength;
|
|
433
|
+
if (format === 'jwk') {
|
|
434
|
+
const jwk = data;
|
|
435
|
+
|
|
436
|
+
// Validate JWK
|
|
437
|
+
if (jwk.kty !== 'oct') {
|
|
438
|
+
throw new Error('Invalid JWK format for AES key');
|
|
439
|
+
}
|
|
440
|
+
const handle = NitroModules.createHybridObject('KeyObjectHandle');
|
|
441
|
+
const keyType = handle.initJwk(jwk, undefined);
|
|
442
|
+
if (keyType === undefined || keyType !== 0) {
|
|
443
|
+
throw new Error('Failed to import AES JWK');
|
|
444
|
+
}
|
|
445
|
+
keyObject = new SecretKeyObject(handle);
|
|
446
|
+
|
|
447
|
+
// Get actual key length from imported key
|
|
448
|
+
const exported = keyObject.export();
|
|
449
|
+
actualLength = exported.byteLength * 8;
|
|
450
|
+
} else if (format === 'raw') {
|
|
451
|
+
const keyData = bufferLikeToArrayBuffer(data);
|
|
452
|
+
actualLength = keyData.byteLength * 8;
|
|
453
|
+
|
|
454
|
+
// Validate key length
|
|
455
|
+
if (![128, 192, 256].includes(actualLength)) {
|
|
456
|
+
throw new Error('Invalid AES key length');
|
|
457
|
+
}
|
|
458
|
+
keyObject = createSecretKey(keyData);
|
|
459
|
+
} else {
|
|
460
|
+
throw new Error(`Unsupported format for AES import: ${format}`);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Validate length if specified
|
|
464
|
+
if (length !== undefined && length !== actualLength) {
|
|
465
|
+
throw new Error(`Key length mismatch: expected ${length}, got ${actualLength}`);
|
|
466
|
+
}
|
|
467
|
+
return new CryptoKey(keyObject, {
|
|
468
|
+
name,
|
|
469
|
+
length: actualLength
|
|
470
|
+
}, keyUsages, extractable);
|
|
72
471
|
}
|
|
73
472
|
const exportKeySpki = async key => {
|
|
74
473
|
switch (key.algorithm.name) {
|
|
@@ -130,7 +529,11 @@ const exportKeyRaw = key => {
|
|
|
130
529
|
case 'AES-KW':
|
|
131
530
|
// Fall through
|
|
132
531
|
case 'HMAC':
|
|
133
|
-
|
|
532
|
+
{
|
|
533
|
+
const exported = key.keyObject.export();
|
|
534
|
+
// Convert Buffer to ArrayBuffer
|
|
535
|
+
return exported.buffer.slice(exported.byteOffset, exported.byteOffset + exported.byteLength);
|
|
536
|
+
}
|
|
134
537
|
}
|
|
135
538
|
throw lazyDOMException(`Unable to export a raw ${key.algorithm.name} ${key.type} key`, 'InvalidAccessError');
|
|
136
539
|
};
|