@opentdf/sdk 0.12.0 → 0.13.0-beta.122
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/dist/cjs/src/auth/dpop.js +4 -4
- package/dist/cjs/src/auth/oidc.js +5 -3
- package/dist/cjs/src/version.js +1 -1
- package/dist/cjs/tdf3/src/crypto/core/ec.js +88 -0
- package/dist/cjs/tdf3/src/crypto/core/key-format.js +359 -0
- package/dist/cjs/tdf3/src/crypto/core/keys.js +85 -0
- package/dist/cjs/tdf3/src/crypto/core/rsa.js +120 -0
- package/dist/cjs/tdf3/src/crypto/core/signing.js +178 -0
- package/dist/cjs/tdf3/src/crypto/core/symmetric.js +205 -0
- package/dist/cjs/tdf3/src/crypto/index.js +69 -1051
- package/dist/types/src/auth/oidc.d.ts +1 -1
- package/dist/types/src/auth/oidc.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +1 -1
- package/dist/types/tdf3/src/crypto/core/ec.d.ts +11 -0
- package/dist/types/tdf3/src/crypto/core/ec.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/core/key-format.d.ts +41 -0
- package/dist/types/tdf3/src/crypto/core/key-format.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/core/keys.d.ts +27 -0
- package/dist/types/tdf3/src/crypto/core/keys.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/core/rsa.d.ts +35 -0
- package/dist/types/tdf3/src/crypto/core/rsa.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/core/signing.d.ts +10 -0
- package/dist/types/tdf3/src/crypto/core/signing.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/core/symmetric.d.ts +68 -0
- package/dist/types/tdf3/src/crypto/core/symmetric.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/index.d.ts +11 -164
- package/dist/types/tdf3/src/crypto/index.d.ts.map +1 -1
- package/dist/web/src/auth/dpop.js +4 -4
- package/dist/web/src/auth/oidc.js +5 -3
- package/dist/web/src/version.js +1 -1
- package/dist/web/tdf3/src/crypto/core/ec.js +84 -0
- package/dist/web/tdf3/src/crypto/core/key-format.js +348 -0
- package/dist/web/tdf3/src/crypto/core/keys.js +78 -0
- package/dist/web/tdf3/src/crypto/core/rsa.js +112 -0
- package/dist/web/tdf3/src/crypto/core/signing.js +174 -0
- package/dist/web/tdf3/src/crypto/core/symmetric.js +192 -0
- package/dist/web/tdf3/src/crypto/index.js +13 -994
- package/package.json +1 -1
- package/src/auth/dpop.ts +3 -3
- package/src/auth/oidc.ts +5 -3
- package/src/version.ts +1 -1
- package/tdf3/src/crypto/core/ec.ts +118 -0
- package/tdf3/src/crypto/core/key-format.ts +420 -0
- package/tdf3/src/crypto/core/keys.ts +86 -0
- package/tdf3/src/crypto/core/rsa.ts +144 -0
- package/tdf3/src/crypto/core/signing.ts +214 -0
- package/tdf3/src/crypto/core/symmetric.ts +265 -0
- package/tdf3/src/crypto/index.ts +71 -1239
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wrapPublicKey = wrapPublicKey;
|
|
4
|
+
exports.wrapPrivateKey = wrapPrivateKey;
|
|
5
|
+
exports.unwrapKey = unwrapKey;
|
|
6
|
+
exports.wrapSymmetricKey = wrapSymmetricKey;
|
|
7
|
+
exports.unwrapSymmetricKey = unwrapSymmetricKey;
|
|
8
|
+
/**
|
|
9
|
+
* Wrap a CryptoKey as an opaque PublicKey.
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
function wrapPublicKey(key, algorithm) {
|
|
13
|
+
const result = {
|
|
14
|
+
_brand: 'PublicKey',
|
|
15
|
+
algorithm,
|
|
16
|
+
_internal: key,
|
|
17
|
+
};
|
|
18
|
+
if (algorithm.startsWith('rsa:')) {
|
|
19
|
+
result.modulusBits = parseInt(algorithm.split(':')[1], 10);
|
|
20
|
+
}
|
|
21
|
+
else if (algorithm.startsWith('ec:')) {
|
|
22
|
+
const curvePart = algorithm.split(':')[1];
|
|
23
|
+
result.curve =
|
|
24
|
+
curvePart === 'secp256r1'
|
|
25
|
+
? 'P-256'
|
|
26
|
+
: curvePart === 'secp384r1'
|
|
27
|
+
? 'P-384'
|
|
28
|
+
: curvePart === 'secp521r1'
|
|
29
|
+
? 'P-521'
|
|
30
|
+
: undefined;
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Wrap a CryptoKey as an opaque PrivateKey.
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
38
|
+
function wrapPrivateKey(key, algorithm) {
|
|
39
|
+
const result = {
|
|
40
|
+
_brand: 'PrivateKey',
|
|
41
|
+
algorithm,
|
|
42
|
+
_internal: key,
|
|
43
|
+
};
|
|
44
|
+
if (algorithm.startsWith('rsa:')) {
|
|
45
|
+
result.modulusBits = parseInt(algorithm.split(':')[1], 10);
|
|
46
|
+
}
|
|
47
|
+
else if (algorithm.startsWith('ec:')) {
|
|
48
|
+
const curvePart = algorithm.split(':')[1];
|
|
49
|
+
result.curve =
|
|
50
|
+
curvePart === 'secp256r1'
|
|
51
|
+
? 'P-256'
|
|
52
|
+
: curvePart === 'secp384r1'
|
|
53
|
+
? 'P-384'
|
|
54
|
+
: curvePart === 'secp521r1'
|
|
55
|
+
? 'P-521'
|
|
56
|
+
: undefined;
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Unwrap an opaque key to get the internal CryptoKey.
|
|
62
|
+
* @internal
|
|
63
|
+
*/
|
|
64
|
+
function unwrapKey(key) {
|
|
65
|
+
return key._internal;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Wrap raw key bytes as an opaque SymmetricKey.
|
|
69
|
+
* @internal
|
|
70
|
+
*/
|
|
71
|
+
function wrapSymmetricKey(keyBytes) {
|
|
72
|
+
return {
|
|
73
|
+
_brand: 'SymmetricKey',
|
|
74
|
+
length: keyBytes.length * 8, // bits
|
|
75
|
+
_internal: keyBytes,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Unwrap an opaque SymmetricKey to get raw bytes.
|
|
80
|
+
* @internal
|
|
81
|
+
*/
|
|
82
|
+
function unwrapSymmetricKey(key) {
|
|
83
|
+
return key._internal;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2V5cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3RkZjMvc3JjL2NyeXB0by9jb3JlL2tleXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFXQSxzQ0FvQkM7QUFNRCx3Q0FvQkM7QUFNRCw4QkFFQztBQU1ELDRDQU1DO0FBTUQsZ0RBRUM7QUE5RUQ7OztHQUdHO0FBQ0gsU0FBZ0IsYUFBYSxDQUFDLEdBQWMsRUFBRSxTQUF1QjtJQUNuRSxNQUFNLE1BQU0sR0FBUTtRQUNsQixNQUFNLEVBQUUsV0FBVztRQUNuQixTQUFTO1FBQ1QsU0FBUyxFQUFFLEdBQUc7S0FDZixDQUFDO0lBQ0YsSUFBSSxTQUFTLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7UUFDakMsTUFBTSxDQUFDLFdBQVcsR0FBRyxRQUFRLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUM3RCxDQUFDO1NBQU0sSUFBSSxTQUFTLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDdkMsTUFBTSxTQUFTLEdBQUcsU0FBUyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUMxQyxNQUFNLENBQUMsS0FBSztZQUNWLFNBQVMsS0FBSyxXQUFXO2dCQUN2QixDQUFDLENBQUMsT0FBTztnQkFDVCxDQUFDLENBQUMsU0FBUyxLQUFLLFdBQVc7b0JBQ3pCLENBQUMsQ0FBQyxPQUFPO29CQUNULENBQUMsQ0FBQyxTQUFTLEtBQUssV0FBVzt3QkFDekIsQ0FBQyxDQUFDLE9BQU87d0JBQ1QsQ0FBQyxDQUFDLFNBQVMsQ0FBQztJQUN0QixDQUFDO0lBQ0QsT0FBTyxNQUFtQixDQUFDO0FBQzdCLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFnQixjQUFjLENBQUMsR0FBYyxFQUFFLFNBQXVCO0lBQ3BFLE1BQU0sTUFBTSxHQUFRO1FBQ2xCLE1BQU0sRUFBRSxZQUFZO1FBQ3BCLFNBQVM7UUFDVCxTQUFTLEVBQUUsR0FBRztLQUNmLENBQUM7SUFDRixJQUFJLFNBQVMsQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztRQUNqQyxNQUFNLENBQUMsV0FBVyxHQUFHLFFBQVEsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzdELENBQUM7U0FBTSxJQUFJLFNBQVMsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUN2QyxNQUFNLFNBQVMsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzFDLE1BQU0sQ0FBQyxLQUFLO1lBQ1YsU0FBUyxLQUFLLFdBQVc7Z0JBQ3ZCLENBQUMsQ0FBQyxPQUFPO2dCQUNULENBQUMsQ0FBQyxTQUFTLEtBQUssV0FBVztvQkFDekIsQ0FBQyxDQUFDLE9BQU87b0JBQ1QsQ0FBQyxDQUFDLFNBQVMsS0FBSyxXQUFXO3dCQUN6QixDQUFDLENBQUMsT0FBTzt3QkFDVCxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ3RCLENBQUM7SUFDRCxPQUFPLE1BQW9CLENBQUM7QUFDOUIsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLFNBQVMsQ0FBQyxHQUEyQjtJQUNuRCxPQUFRLEdBQVcsQ0FBQyxTQUFTLENBQUM7QUFDaEMsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLGdCQUFnQixDQUFDLFFBQW9CO0lBQ25ELE9BQU87UUFDTCxNQUFNLEVBQUUsY0FBYztRQUN0QixNQUFNLEVBQUUsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsT0FBTztRQUNwQyxTQUFTLEVBQUUsUUFBUTtLQUNKLENBQUM7QUFDcEIsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLGtCQUFrQixDQUFDLEdBQWlCO0lBQ2xELE9BQVEsR0FBVyxDQUFDLFNBQVMsQ0FBQztBQUNoQyxDQUFDIn0=
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rsaOaepSha1 = rsaOaepSha1;
|
|
4
|
+
exports.rsaPkcs1Sha256 = rsaPkcs1Sha256;
|
|
5
|
+
exports.generateKeyPair = generateKeyPair;
|
|
6
|
+
exports.generateSigningKeyPair = generateSigningKeyPair;
|
|
7
|
+
exports.encryptWithPublicKey = encryptWithPublicKey;
|
|
8
|
+
exports.decryptWithPrivateKey = decryptWithPrivateKey;
|
|
9
|
+
const binary_js_1 = require("../../binary.js");
|
|
10
|
+
const declarations_js_1 = require("../declarations.js");
|
|
11
|
+
const errors_js_1 = require("../../../../src/errors.js");
|
|
12
|
+
const keys_js_1 = require("./keys.js");
|
|
13
|
+
const ENC_DEC_METHODS = ['encrypt', 'decrypt'];
|
|
14
|
+
const SIGN_VERIFY_METHODS = ['sign', 'verify'];
|
|
15
|
+
/**
|
|
16
|
+
* Get a DOMString representing the algorithm to use for an
|
|
17
|
+
* asymmetric key generation.
|
|
18
|
+
*/
|
|
19
|
+
function rsaOaepSha1(modulusLength = declarations_js_1.MIN_ASYMMETRIC_KEY_SIZE_BITS) {
|
|
20
|
+
if (!modulusLength || modulusLength < declarations_js_1.MIN_ASYMMETRIC_KEY_SIZE_BITS) {
|
|
21
|
+
throw new errors_js_1.ConfigurationError('Invalid key size requested');
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
name: 'RSA-OAEP',
|
|
25
|
+
hash: {
|
|
26
|
+
name: 'SHA-1',
|
|
27
|
+
},
|
|
28
|
+
modulusLength,
|
|
29
|
+
// 24 bit representation of 65537
|
|
30
|
+
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function rsaPkcs1Sha256(modulusLength = declarations_js_1.MIN_ASYMMETRIC_KEY_SIZE_BITS) {
|
|
34
|
+
if (!modulusLength || modulusLength < declarations_js_1.MIN_ASYMMETRIC_KEY_SIZE_BITS) {
|
|
35
|
+
throw new errors_js_1.ConfigurationError('Invalid key size requested');
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
name: 'RSASSA-PKCS1-v1_5',
|
|
39
|
+
hash: {
|
|
40
|
+
name: 'SHA-256',
|
|
41
|
+
},
|
|
42
|
+
modulusLength,
|
|
43
|
+
// 24 bit representation of 65537
|
|
44
|
+
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Generate an RSA key pair
|
|
49
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey}
|
|
50
|
+
* @param size in bits
|
|
51
|
+
*/
|
|
52
|
+
async function generateKeyPair(size) {
|
|
53
|
+
const keySize = size || declarations_js_1.MIN_ASYMMETRIC_KEY_SIZE_BITS;
|
|
54
|
+
const algoDomString = rsaOaepSha1(keySize);
|
|
55
|
+
const keyPair = await crypto.subtle.generateKey(algoDomString, true, ENC_DEC_METHODS);
|
|
56
|
+
// Map to supported algorithm sizes
|
|
57
|
+
let algorithm;
|
|
58
|
+
if (keySize === 2048) {
|
|
59
|
+
algorithm = 'rsa:2048';
|
|
60
|
+
}
|
|
61
|
+
else if (keySize === 4096) {
|
|
62
|
+
algorithm = 'rsa:4096';
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
throw new errors_js_1.ConfigurationError(`Unsupported RSA key size: ${keySize}. Only 2048 and 4096 are supported.`);
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
publicKey: (0, keys_js_1.wrapPublicKey)(keyPair.publicKey, algorithm),
|
|
69
|
+
privateKey: (0, keys_js_1.wrapPrivateKey)(keyPair.privateKey, algorithm),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Generate an RSA key pair suitable for signatures
|
|
74
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey}
|
|
75
|
+
*/
|
|
76
|
+
async function generateSigningKeyPair() {
|
|
77
|
+
const rsaParams = rsaPkcs1Sha256(2048);
|
|
78
|
+
const keyPair = await crypto.subtle.generateKey(rsaParams, true, SIGN_VERIFY_METHODS);
|
|
79
|
+
const algorithm = 'rsa:2048';
|
|
80
|
+
return {
|
|
81
|
+
publicKey: (0, keys_js_1.wrapPublicKey)(keyPair.publicKey, algorithm),
|
|
82
|
+
privateKey: (0, keys_js_1.wrapPrivateKey)(keyPair.privateKey, algorithm),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Encrypt using a public key (RSA-OAEP).
|
|
87
|
+
* Accepts Binary or SymmetricKey for key wrapping.
|
|
88
|
+
* @param payload Payload to encrypt (Binary) or symmetric key to wrap (SymmetricKey)
|
|
89
|
+
* @param publicKey Opaque public key
|
|
90
|
+
* @return Encrypted payload
|
|
91
|
+
*/
|
|
92
|
+
async function encryptWithPublicKey(payload, publicKey) {
|
|
93
|
+
let payloadBuffer;
|
|
94
|
+
// Handle SymmetricKey unwrapping
|
|
95
|
+
if ('_brand' in payload && payload._brand === 'SymmetricKey') {
|
|
96
|
+
// Pass Uint8Array directly — Web Crypto respects byteOffset/byteLength on typed array views.
|
|
97
|
+
payloadBuffer = (0, keys_js_1.unwrapSymmetricKey)(payload);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
// Binary payload
|
|
101
|
+
payloadBuffer = payload.asArrayBuffer();
|
|
102
|
+
}
|
|
103
|
+
const cryptoKey = (0, keys_js_1.unwrapKey)(publicKey);
|
|
104
|
+
const result = await crypto.subtle.encrypt({ name: 'RSA-OAEP' }, cryptoKey, payloadBuffer);
|
|
105
|
+
return binary_js_1.Binary.fromArrayBuffer(result);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Decrypt a public-key encrypted payload with a private key
|
|
109
|
+
* @param encryptedPayload Payload to decrypt
|
|
110
|
+
* @param privateKey Opaque private key
|
|
111
|
+
* @return Decrypted payload
|
|
112
|
+
*/
|
|
113
|
+
async function decryptWithPrivateKey(encryptedPayload, privateKey) {
|
|
114
|
+
console.assert(typeof encryptedPayload === 'object', 'encryptedPayload must be object');
|
|
115
|
+
const cryptoKey = (0, keys_js_1.unwrapKey)(privateKey);
|
|
116
|
+
const payload = await crypto.subtle.decrypt({ name: 'RSA-OAEP' }, cryptoKey, encryptedPayload.asArrayBuffer());
|
|
117
|
+
const bufferView = new Uint8Array(payload);
|
|
118
|
+
return binary_js_1.Binary.fromArrayBuffer(bufferView.buffer);
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnNhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vdGRmMy9zcmMvY3J5cHRvL2NvcmUvcnNhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBbUJBLGtDQWVDO0FBRUQsd0NBZUM7QUFPRCwwQ0FxQkM7QUFNRCx3REFTQztBQVNELG9EQWtCQztBQVFELHNEQWNDO0FBL0lELCtDQUF5QztBQUN6Qyx3REFPNEI7QUFDNUIseURBQStEO0FBQy9ELHVDQUF5RjtBQUV6RixNQUFNLGVBQWUsR0FBZSxDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FBQztBQUMzRCxNQUFNLG1CQUFtQixHQUFlLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0FBRTNEOzs7R0FHRztBQUNILFNBQWdCLFdBQVcsQ0FDekIsZ0JBQXdCLDhDQUE0QjtJQUVwRCxJQUFJLENBQUMsYUFBYSxJQUFJLGFBQWEsR0FBRyw4Q0FBNEIsRUFBRSxDQUFDO1FBQ25FLE1BQU0sSUFBSSw4QkFBa0IsQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFDRCxPQUFPO1FBQ0wsSUFBSSxFQUFFLFVBQVU7UUFDaEIsSUFBSSxFQUFFO1lBQ0osSUFBSSxFQUFFLE9BQU87U0FDZDtRQUNELGFBQWE7UUFDYixpQ0FBaUM7UUFDakMsY0FBYyxFQUFFLElBQUksVUFBVSxDQUFDLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztLQUNuRCxDQUFDO0FBQ0osQ0FBQztBQUVELFNBQWdCLGNBQWMsQ0FDNUIsZ0JBQXdCLDhDQUE0QjtJQUVwRCxJQUFJLENBQUMsYUFBYSxJQUFJLGFBQWEsR0FBRyw4Q0FBNEIsRUFBRSxDQUFDO1FBQ25FLE1BQU0sSUFBSSw4QkFBa0IsQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFDRCxPQUFPO1FBQ0wsSUFBSSxFQUFFLG1CQUFtQjtRQUN6QixJQUFJLEVBQUU7WUFDSixJQUFJ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
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sign = sign;
|
|
4
|
+
exports.verify = verify;
|
|
5
|
+
const errors_js_1 = require("../../../../src/errors.js");
|
|
6
|
+
const keys_js_1 = require("./keys.js");
|
|
7
|
+
/**
|
|
8
|
+
* Get the Web Crypto algorithm parameters for a signing algorithm.
|
|
9
|
+
*/
|
|
10
|
+
function getSigningAlgorithmParams(algorithm) {
|
|
11
|
+
switch (algorithm) {
|
|
12
|
+
case 'RS256':
|
|
13
|
+
return {
|
|
14
|
+
importParams: { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' },
|
|
15
|
+
signParams: 'RSASSA-PKCS1-v1_5',
|
|
16
|
+
};
|
|
17
|
+
case 'ES256':
|
|
18
|
+
return {
|
|
19
|
+
importParams: { name: 'ECDSA', namedCurve: 'P-256' },
|
|
20
|
+
signParams: { name: 'ECDSA', hash: 'SHA-256' },
|
|
21
|
+
};
|
|
22
|
+
case 'ES384':
|
|
23
|
+
return {
|
|
24
|
+
importParams: { name: 'ECDSA', namedCurve: 'P-384' },
|
|
25
|
+
signParams: { name: 'ECDSA', hash: 'SHA-384' },
|
|
26
|
+
};
|
|
27
|
+
case 'ES512':
|
|
28
|
+
return {
|
|
29
|
+
importParams: { name: 'ECDSA', namedCurve: 'P-521' },
|
|
30
|
+
signParams: { name: 'ECDSA', hash: 'SHA-512' },
|
|
31
|
+
};
|
|
32
|
+
default:
|
|
33
|
+
throw new errors_js_1.ConfigurationError(`Unsupported signing algorithm: ${algorithm}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Convert IEEE P1363 signature format (used by WebCrypto ECDSA) to DER format (used by JWT).
|
|
38
|
+
* RS256 signatures don't need conversion.
|
|
39
|
+
*/
|
|
40
|
+
function ieeeP1363ToDer(signature, algorithm) {
|
|
41
|
+
if (algorithm === 'RS256') {
|
|
42
|
+
return signature;
|
|
43
|
+
}
|
|
44
|
+
// IEEE P1363: r || s where each is padded to key size
|
|
45
|
+
const halfLen = signature.length / 2;
|
|
46
|
+
const r = signature.slice(0, halfLen);
|
|
47
|
+
const s = signature.slice(halfLen);
|
|
48
|
+
// Remove leading zeros but keep one if the high bit is set
|
|
49
|
+
const trimLeadingZeros = (arr) => {
|
|
50
|
+
let i = 0;
|
|
51
|
+
while (i < arr.length - 1 && arr[i] === 0)
|
|
52
|
+
i++;
|
|
53
|
+
return arr.slice(i);
|
|
54
|
+
};
|
|
55
|
+
let rTrimmed = trimLeadingZeros(r);
|
|
56
|
+
let sTrimmed = trimLeadingZeros(s);
|
|
57
|
+
// Add leading zero if high bit is set (to keep positive in DER)
|
|
58
|
+
if (rTrimmed[0] & 0x80) {
|
|
59
|
+
const padded = new Uint8Array(rTrimmed.length + 1);
|
|
60
|
+
padded.set(rTrimmed, 1);
|
|
61
|
+
rTrimmed = padded;
|
|
62
|
+
}
|
|
63
|
+
if (sTrimmed[0] & 0x80) {
|
|
64
|
+
const padded = new Uint8Array(sTrimmed.length + 1);
|
|
65
|
+
padded.set(sTrimmed, 1);
|
|
66
|
+
sTrimmed = padded;
|
|
67
|
+
}
|
|
68
|
+
// DER SEQUENCE: 0x30 [length] [r INTEGER] [s INTEGER]
|
|
69
|
+
// INTEGER: 0x02 [length] [value]
|
|
70
|
+
const rDer = new Uint8Array([0x02, rTrimmed.length, ...rTrimmed]);
|
|
71
|
+
const sDer = new Uint8Array([0x02, sTrimmed.length, ...sTrimmed]);
|
|
72
|
+
const seqLen = rDer.length + sDer.length;
|
|
73
|
+
// DER length: short-form for < 128, long-form (0x81 nn) for 128-255.
|
|
74
|
+
// ECDSA sequences never exceed 255 bytes for any supported curve.
|
|
75
|
+
const lenBytes = seqLen < 128 ? new Uint8Array([seqLen]) : new Uint8Array([0x81, seqLen]);
|
|
76
|
+
const result = new Uint8Array(1 + lenBytes.length + seqLen);
|
|
77
|
+
result[0] = 0x30;
|
|
78
|
+
result.set(lenBytes, 1);
|
|
79
|
+
result.set(rDer, 1 + lenBytes.length);
|
|
80
|
+
result.set(sDer, 1 + lenBytes.length + rDer.length);
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Convert DER signature format (used by JWT) to IEEE P1363 format (used by WebCrypto ECDSA).
|
|
85
|
+
* RS256 signatures don't need conversion.
|
|
86
|
+
*/
|
|
87
|
+
function derToIeeeP1363(signature, algorithm) {
|
|
88
|
+
if (algorithm === 'RS256') {
|
|
89
|
+
return signature;
|
|
90
|
+
}
|
|
91
|
+
// Determine the expected component length based on algorithm
|
|
92
|
+
let componentLen;
|
|
93
|
+
switch (algorithm) {
|
|
94
|
+
case 'ES256':
|
|
95
|
+
componentLen = 32;
|
|
96
|
+
break;
|
|
97
|
+
case 'ES384':
|
|
98
|
+
componentLen = 48;
|
|
99
|
+
break;
|
|
100
|
+
case 'ES512':
|
|
101
|
+
componentLen = 66;
|
|
102
|
+
break;
|
|
103
|
+
default:
|
|
104
|
+
throw new errors_js_1.ConfigurationError(`Unsupported algorithm for DER conversion: ${algorithm}`);
|
|
105
|
+
}
|
|
106
|
+
if (signature[0] !== 0x30) {
|
|
107
|
+
throw new errors_js_1.ConfigurationError('Invalid DER signature: expected SEQUENCE');
|
|
108
|
+
}
|
|
109
|
+
// Skip SEQUENCE tag, then parse DER length (short- or long-form).
|
|
110
|
+
let offset = 1;
|
|
111
|
+
if (signature[offset] & 0x80) {
|
|
112
|
+
// Long-form: low 7 bits = number of subsequent length bytes.
|
|
113
|
+
const lenBytesCount = signature[offset] & 0x7f;
|
|
114
|
+
if (lenBytesCount === 0 || lenBytesCount > 4) {
|
|
115
|
+
throw new errors_js_1.ConfigurationError('Invalid DER signature: invalid long-form length');
|
|
116
|
+
}
|
|
117
|
+
offset += 1 + lenBytesCount;
|
|
118
|
+
if (offset > signature.length) {
|
|
119
|
+
throw new errors_js_1.ConfigurationError('Invalid DER signature: length bytes exceed signature length');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
// Short-form: single length byte.
|
|
124
|
+
offset += 1;
|
|
125
|
+
}
|
|
126
|
+
// Parse r INTEGER
|
|
127
|
+
if (signature[offset] !== 0x02) {
|
|
128
|
+
throw new errors_js_1.ConfigurationError('Invalid DER signature: expected INTEGER for r');
|
|
129
|
+
}
|
|
130
|
+
const rLen = signature[offset + 1];
|
|
131
|
+
offset += 2;
|
|
132
|
+
let r = signature.slice(offset, offset + rLen);
|
|
133
|
+
offset += rLen;
|
|
134
|
+
// Parse s INTEGER
|
|
135
|
+
if (signature[offset] !== 0x02) {
|
|
136
|
+
throw new errors_js_1.ConfigurationError('Invalid DER signature: expected INTEGER for s');
|
|
137
|
+
}
|
|
138
|
+
const sLen = signature[offset + 1];
|
|
139
|
+
offset += 2;
|
|
140
|
+
let s = signature.slice(offset, offset + sLen);
|
|
141
|
+
// Remove leading zero padding if present
|
|
142
|
+
if (r[0] === 0 && r.length > componentLen) {
|
|
143
|
+
r = r.slice(1);
|
|
144
|
+
}
|
|
145
|
+
if (s[0] === 0 && s.length > componentLen) {
|
|
146
|
+
s = s.slice(1);
|
|
147
|
+
}
|
|
148
|
+
// Pad to component length
|
|
149
|
+
const result = new Uint8Array(componentLen * 2);
|
|
150
|
+
result.set(r, componentLen - r.length);
|
|
151
|
+
result.set(s, componentLen * 2 - s.length);
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Sign data with an asymmetric private key.
|
|
156
|
+
*/
|
|
157
|
+
async function sign(data, privateKey, algorithm) {
|
|
158
|
+
const { signParams } = getSigningAlgorithmParams(algorithm);
|
|
159
|
+
// Unwrap the internal CryptoKey
|
|
160
|
+
const key = (0, keys_js_1.unwrapKey)(privateKey);
|
|
161
|
+
// Sign the data
|
|
162
|
+
const signature = await crypto.subtle.sign(signParams, key, data);
|
|
163
|
+
// Convert from IEEE P1363 to DER for EC algorithms
|
|
164
|
+
return ieeeP1363ToDer(new Uint8Array(signature), algorithm);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Verify signature with an asymmetric public key.
|
|
168
|
+
*/
|
|
169
|
+
async function verify(data, signature, publicKey, algorithm) {
|
|
170
|
+
const { signParams } = getSigningAlgorithmParams(algorithm);
|
|
171
|
+
// Unwrap the internal CryptoKey
|
|
172
|
+
const key = (0, keys_js_1.unwrapKey)(publicKey);
|
|
173
|
+
// Convert from DER to IEEE P1363 for EC algorithms
|
|
174
|
+
const ieeeSignature = derToIeeeP1363(signature, algorithm);
|
|
175
|
+
// Verify the signature
|
|
176
|
+
return crypto.subtle.verify(signParams, key, ieeeSignature, data);
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnbmluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3RkZjMvc3JjL2NyeXB0by9jb3JlL3NpZ25pbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFpTEEsb0JBZUM7QUFLRCx3QkFnQkM7QUFoTkQseURBQStEO0FBQy9ELHVDQUFzQztBQUV0Qzs7R0FFRztBQUNILFNBQVMseUJBQXlCLENBQUMsU0FBcUM7SUFJdEUsUUFBUSxTQUFTLEVBQUUsQ0FBQztRQUNsQixLQUFLLE9BQU87WUFDVixPQUFPO2dCQUNMLFlBQVksRUFBRSxFQUFFLElBQUksRUFBRSxtQkFBbUIsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFO2dCQUM1RCxVQUFVLEVBQUUsbUJBQW1CO2FBQ2hDLENBQUM7UUFDSixLQUFLLE9BQU87WUFDVixPQUFPO2dCQUNMLFlBQVksRUFBRSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRTtnQkFDcEQsVUFBVSxFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFpQjthQUM5RCxDQUFDO1FBQ0osS0FBSyxPQUFPO1lBQ1YsT0FBTztnQkFDTCxZQUFZLEVBQUUsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUU7Z0JBQ3BELFVBQVUsRUFBRSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBaUI7YUFDOUQsQ0FBQztRQUNKLEtBQUssT0FBTztZQUNWLE9BQU87Z0JBQ0wsWUFBWSxFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFO2dCQUNwRCxVQUFVLEVBQUUsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQWlCO2FBQzlELENBQUM7UUFDSjtZQUNFLE1BQU0sSUFBSSw4QkFBa0IsQ0FBQyxrQ0FBa0MsU0FB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
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateKey = generateKey;
|
|
4
|
+
exports.randomBytes = randomBytes;
|
|
5
|
+
exports.randomBytesAsHex = randomBytesAsHex;
|
|
6
|
+
exports.decrypt = decrypt;
|
|
7
|
+
exports.encrypt = encrypt;
|
|
8
|
+
exports.hex2Ab = hex2Ab;
|
|
9
|
+
exports.digest = digest;
|
|
10
|
+
exports.hmac = hmac;
|
|
11
|
+
exports.verifyHmac = verifyHmac;
|
|
12
|
+
exports.importSymmetricKey = importSymmetricKey;
|
|
13
|
+
exports.mergeSymmetricKeys = mergeSymmetricKeys;
|
|
14
|
+
const algorithms_js_1 = require("../../ciphers/algorithms.js");
|
|
15
|
+
const binary_js_1 = require("../../binary.js");
|
|
16
|
+
const errors_js_1 = require("../../../../src/errors.js");
|
|
17
|
+
const hex_js_1 = require("../../../../src/encodings/hex.js");
|
|
18
|
+
const keysplit_js_1 = require("../../utils/keysplit.js");
|
|
19
|
+
const keys_js_1 = require("./keys.js");
|
|
20
|
+
const ENC_DEC_METHODS = ['encrypt', 'decrypt'];
|
|
21
|
+
/**
|
|
22
|
+
* Generate a random symmetric key (opaque).
|
|
23
|
+
* @param length - Key length in bytes (default 32 for AES-256)
|
|
24
|
+
* @return Opaque symmetric key
|
|
25
|
+
*/
|
|
26
|
+
async function generateKey(length) {
|
|
27
|
+
const keyBytes = await randomBytes(length || 32);
|
|
28
|
+
return (0, keys_js_1.wrapSymmetricKey)(keyBytes);
|
|
29
|
+
}
|
|
30
|
+
async function randomBytes(byteLength) {
|
|
31
|
+
const r = new Uint8Array(byteLength);
|
|
32
|
+
crypto.getRandomValues(r);
|
|
33
|
+
return r;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Returns a promise to the encryption key as a binary string.
|
|
37
|
+
*
|
|
38
|
+
* Note: This function should almost never fail as it includes a fallback
|
|
39
|
+
* if for some reason the native generate key fails.
|
|
40
|
+
*
|
|
41
|
+
* @param length The key length, defaults to 256
|
|
42
|
+
*
|
|
43
|
+
* @returns The hex string.
|
|
44
|
+
*/
|
|
45
|
+
async function randomBytesAsHex(length) {
|
|
46
|
+
// Create a typed array of the correct length to fill
|
|
47
|
+
const r = new Uint8Array(length);
|
|
48
|
+
crypto.getRandomValues(r);
|
|
49
|
+
return (0, hex_js_1.encodeArrayBuffer)(r.buffer);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Decrypt content synchronously
|
|
53
|
+
* @param payload The payload to decrypt
|
|
54
|
+
* @param key The symmetric encryption key (opaque)
|
|
55
|
+
* @param iv The initialization vector
|
|
56
|
+
* @param algorithm The algorithm to use for encryption
|
|
57
|
+
* @param authTag The authentication tag for authenticated crypto.
|
|
58
|
+
*/
|
|
59
|
+
function decrypt(payload, key, iv, algorithm, authTag) {
|
|
60
|
+
return _doDecrypt(payload, key, iv, algorithm, authTag);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Encrypt content synchronously
|
|
64
|
+
* @param payload The payload to encrypt
|
|
65
|
+
* @param key The encryption key
|
|
66
|
+
* @param iv The initialization vector
|
|
67
|
+
* @param algorithm The algorithm to use for encryption
|
|
68
|
+
*/
|
|
69
|
+
function encrypt(payload, key, iv, algorithm) {
|
|
70
|
+
return _doEncrypt(payload, key, iv, algorithm);
|
|
71
|
+
}
|
|
72
|
+
async function _doEncrypt(payload, key, iv, algorithm) {
|
|
73
|
+
console.assert(payload != null);
|
|
74
|
+
console.assert(key != null);
|
|
75
|
+
console.assert(iv != null);
|
|
76
|
+
// Handle both Binary and SymmetricKey payloads
|
|
77
|
+
let payloadBuffer;
|
|
78
|
+
if ('_brand' in payload && payload._brand === 'SymmetricKey') {
|
|
79
|
+
// Pass Uint8Array directly — Web Crypto respects byteOffset/byteLength on typed array views.
|
|
80
|
+
payloadBuffer = (0, keys_js_1.unwrapSymmetricKey)(payload);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Binary payload
|
|
84
|
+
payloadBuffer = payload.asArrayBuffer();
|
|
85
|
+
}
|
|
86
|
+
const algoDomString = getSymmetricAlgoDomString(iv, algorithm);
|
|
87
|
+
const keyBytes = (0, keys_js_1.unwrapSymmetricKey)(key);
|
|
88
|
+
const importedKey = await _importKey(keyBytes, algoDomString);
|
|
89
|
+
const encrypted = await crypto.subtle.encrypt(algoDomString, importedKey, payloadBuffer);
|
|
90
|
+
if (algoDomString.name === 'AES-GCM') {
|
|
91
|
+
return {
|
|
92
|
+
payload: binary_js_1.Binary.fromArrayBuffer(encrypted.slice(0, -16)),
|
|
93
|
+
authTag: binary_js_1.Binary.fromArrayBuffer(encrypted.slice(-16)),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
payload: binary_js_1.Binary.fromArrayBuffer(encrypted),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
async function _doDecrypt(payload, key, iv, algorithm, authTag) {
|
|
101
|
+
console.assert(payload != null);
|
|
102
|
+
console.assert(key != null);
|
|
103
|
+
console.assert(iv != null);
|
|
104
|
+
let payloadBuffer = payload.asArrayBuffer();
|
|
105
|
+
// Concat the the auth tag to the payload for decryption
|
|
106
|
+
if (authTag) {
|
|
107
|
+
const authTagBuffer = authTag.asArrayBuffer();
|
|
108
|
+
const gcmPayload = new Uint8Array(payloadBuffer.byteLength + authTagBuffer.byteLength);
|
|
109
|
+
gcmPayload.set(new Uint8Array(payloadBuffer), 0);
|
|
110
|
+
gcmPayload.set(new Uint8Array(authTagBuffer), payloadBuffer.byteLength);
|
|
111
|
+
payloadBuffer = gcmPayload.buffer;
|
|
112
|
+
}
|
|
113
|
+
const algoDomString = getSymmetricAlgoDomString(iv, algorithm);
|
|
114
|
+
const keyBytes = (0, keys_js_1.unwrapSymmetricKey)(key);
|
|
115
|
+
const importedKey = await _importKey(keyBytes, algoDomString);
|
|
116
|
+
algoDomString.iv = iv.asArrayBuffer();
|
|
117
|
+
const decrypted = await crypto.subtle
|
|
118
|
+
.decrypt(algoDomString, importedKey, payloadBuffer)
|
|
119
|
+
// Catching this error so we can specifically check for OperationError
|
|
120
|
+
.catch((err) => {
|
|
121
|
+
if (err.name === 'OperationError') {
|
|
122
|
+
throw new errors_js_1.DecryptError(err);
|
|
123
|
+
}
|
|
124
|
+
throw err;
|
|
125
|
+
});
|
|
126
|
+
return { payload: binary_js_1.Binary.fromArrayBuffer(decrypted) };
|
|
127
|
+
}
|
|
128
|
+
function _importKey(keyBytes, algorithm) {
|
|
129
|
+
return crypto.subtle.importKey('raw', keyBytes, algorithm, true, ENC_DEC_METHODS);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Get a DOMString representing the algorithm to use for a crypto
|
|
133
|
+
* operation. Defaults to AES-CBC.
|
|
134
|
+
* @param {String|undefined} algorithm
|
|
135
|
+
* @return {DOMString} Algorithm to use
|
|
136
|
+
*/
|
|
137
|
+
function getSymmetricAlgoDomString(iv, algorithm) {
|
|
138
|
+
let nativeAlgorithm = 'AES-CBC';
|
|
139
|
+
if (algorithm === algorithms_js_1.Algorithms.AES_256_GCM) {
|
|
140
|
+
nativeAlgorithm = 'AES-GCM';
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
name: nativeAlgorithm,
|
|
144
|
+
iv: iv.asArrayBuffer(),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Create an ArrayBuffer from a hex string.
|
|
149
|
+
* https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String?hl=en
|
|
150
|
+
* @param hex - Hex string
|
|
151
|
+
*/
|
|
152
|
+
function hex2Ab(hex) {
|
|
153
|
+
const buffer = new ArrayBuffer(hex.length / 2);
|
|
154
|
+
const bufferView = new Uint8Array(buffer);
|
|
155
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
156
|
+
bufferView[i / 2] = parseInt(hex.substr(i, 2), 16);
|
|
157
|
+
}
|
|
158
|
+
return buffer;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Compute hash digest.
|
|
162
|
+
*/
|
|
163
|
+
async function digest(algorithm, data) {
|
|
164
|
+
const validAlgorithms = ['SHA-256', 'SHA-384', 'SHA-512'];
|
|
165
|
+
if (!validAlgorithms.includes(algorithm)) {
|
|
166
|
+
throw new errors_js_1.ConfigurationError(`Unsupported hash algorithm: ${algorithm}`);
|
|
167
|
+
}
|
|
168
|
+
const hashBuffer = await crypto.subtle.digest(algorithm, data);
|
|
169
|
+
return new Uint8Array(hashBuffer);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Compute HMAC-SHA256 of data with a symmetric key.
|
|
173
|
+
*/
|
|
174
|
+
async function hmac(data, key) {
|
|
175
|
+
const keyBytes = (0, keys_js_1.unwrapSymmetricKey)(key);
|
|
176
|
+
const cryptoKey = await crypto.subtle.importKey('raw', keyBytes, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
177
|
+
const signature = await crypto.subtle.sign('HMAC', cryptoKey, data);
|
|
178
|
+
return new Uint8Array(signature);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Verify HMAC-SHA256.
|
|
182
|
+
* Standalone utility — not part of CryptoService interface.
|
|
183
|
+
*/
|
|
184
|
+
async function verifyHmac(data, signature, key) {
|
|
185
|
+
const keyBytes = (0, keys_js_1.unwrapSymmetricKey)(key);
|
|
186
|
+
const cryptoKey = await crypto.subtle.importKey('raw', keyBytes, { name: 'HMAC', hash: 'SHA-256' }, false, ['verify']);
|
|
187
|
+
return crypto.subtle.verify('HMAC', cryptoKey, signature, data);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Import raw key bytes as an opaque symmetric key.
|
|
191
|
+
* Used for external keys (e.g., unwrapped from KAS).
|
|
192
|
+
*/
|
|
193
|
+
async function importSymmetricKey(keyBytes) {
|
|
194
|
+
return (0, keys_js_1.wrapSymmetricKey)(keyBytes);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Merge symmetric key shares back into the original key using XOR.
|
|
198
|
+
* Key bytes are extracted internally for merging.
|
|
199
|
+
*/
|
|
200
|
+
async function mergeSymmetricKeys(shares) {
|
|
201
|
+
const splitBytes = shares.map(keys_js_1.unwrapSymmetricKey);
|
|
202
|
+
const merged = (0, keysplit_js_1.keyMerge)(splitBytes);
|
|
203
|
+
return (0, keys_js_1.wrapSymmetricKey)(merged);
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3ltbWV0cmljLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vdGRmMy9zcmMvY3J5cHRvL2NvcmUvc3ltbWV0cmljLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBb0JBLGtDQUdDO0FBRUQsa0NBSUM7QUFZRCw0Q0FLQztBQVVELDBCQVFDO0FBU0QsMEJBT0M7QUEyR0Qsd0JBU0M7QUFLRCx3QkFRQztBQUtELG9CQVlDO0FBTUQsZ0NBY0M7QUFNRCxnREFFQztBQU1ELGdEQUlDO0FBeFFELCtEQUE0RTtBQUM1RSwrQ0FBeUM7QUFPekMseURBQTZFO0FBQzdFLDZEQUFrRjtBQUNsRix5REFBbUQ7QUFDbkQsdUNBQWlFO0FBRWpFLE1BQU0sZUFBZSxHQUFlLENBQUMsU0FBUyxFQUFFLFNBQVMsQ0FBQyxDQUFDO0FBRTNEOzs7O0dBSUc7QUFDSSxLQUFLLFVBQVUsV0FBVyxDQUFDLE1BQWU7SUFDL0MsTUFBTSxRQUFRLEdBQUcsTUFBTSxXQUFXLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ2pELE9BQU8sSUFBQSwwQkFBZ0IsRUFBQyxRQUFRLENBQUMsQ0FBQztBQUNwQyxDQUFDO0FBRU0sS0FBSyxVQUFVLFdBQVcsQ0FBQyxVQUFrQjtJQUNsRCxNQUFNLENBQUMsR0FBRyxJQUFJLFVBQVUsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNyQyxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzFCLE9BQU8sQ0FBQyxDQUFDO0FBQ1gsQ0FBQztBQUVEOzs7Ozs7Ozs7R0FTRztBQUNJLEtBQUssVUFBVSxnQkFBZ0IsQ0FBQyxNQUFjO0lBQ25ELHFEQUFxRDtJQUNyRCxNQUFNLENBQUMsR0FBRyxJQUFJLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNqQyxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzFCLE9BQU8sSUFBQSwwQkFBUyxFQUFDLENBQUMsQ0FBQyxN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
|