@credo-ts/node 0.8.0-alpha-20261020190607 → 0.8.0-alpha-20261021192900
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/build/kms/NodeKeyManagementService.d.mts.map +1 -1
- package/build/kms/NodeKeyManagementService.mjs +72 -33
- package/build/kms/NodeKeyManagementService.mjs.map +1 -1
- package/build/kms/crypto/deriveKey.mjs +73 -58
- package/build/kms/crypto/deriveKey.mjs.map +1 -1
- package/build/kms/crypto/encrypt.mjs +5 -5
- package/build/kms/crypto/encrypt.mjs.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeKeyManagementService.d.mts","names":[],"sources":["../../src/kms/NodeKeyManagementService.ts"],"mappings":";;;qBAoBa,oCAAoC,IAAI;;WACnC;EAIG,YAAA,SAAS;EAIrB,qBAAqB,eAAe,cAAc,WAAW,IAAI;EAmGjE,YAAY,eAAe,cAAc,SAAS,IAAI,wBAAwB,IAAI;EAI5E,aAAa,cAAc,cAAc,gBAAgB,QAAQ,IAAI;EAOrE,UAAU,YAAY,IAAI,eACrC,cAAc,cACd,SAAS,IAAI,oBAAoB,OAChC,QAAQ,IAAI,mBAAmB;EAyDrB,UAAU,cAAc,cAAc,SAAS,IAAI,sBAAsB;EAIzE,UAAU,aAAa,IAAI,kBACtC,cAAc,cACd,SAAS,IAAI,oBAAoB,QAChC,QAAQ,IAAI,mBAAmB;EAuCrB,KAAK,cAAc,cAAc,SAAS,IAAI,iBAAiB,QAAQ,IAAI;EAwB3E,OAAO,cAAc,cAAc,SAAS,IAAI,mBAAmB,QAAQ,IAAI;EA2C/E,QAAQ,cAAc,cAAc,SAAS,IAAI,oBAAoB,QAAQ,IAAI;
|
|
1
|
+
{"version":3,"file":"NodeKeyManagementService.d.mts","names":[],"sources":["../../src/kms/NodeKeyManagementService.ts"],"mappings":";;;qBAoBa,oCAAoC,IAAI;;WACnC;EAIG,YAAA,SAAS;EAIrB,qBAAqB,eAAe,cAAc,WAAW,IAAI;EAmGjE,YAAY,eAAe,cAAc,SAAS,IAAI,wBAAwB,IAAI;EAI5E,aAAa,cAAc,cAAc,gBAAgB,QAAQ,IAAI;EAOrE,UAAU,YAAY,IAAI,eACrC,cAAc,cACd,SAAS,IAAI,oBAAoB,OAChC,QAAQ,IAAI,mBAAmB;EAyDrB,UAAU,cAAc,cAAc,SAAS,IAAI,sBAAsB;EAIzE,UAAU,aAAa,IAAI,kBACtC,cAAc,cACd,SAAS,IAAI,oBAAoB,QAChC,QAAQ,IAAI,mBAAmB;EAuCrB,KAAK,cAAc,cAAc,SAAS,IAAI,iBAAiB,QAAQ,IAAI;EAwB3E,OAAO,cAAc,cAAc,SAAS,IAAI,mBAAmB,QAAQ,IAAI;EA2C/E,QAAQ,cAAc,cAAc,SAAS,IAAI,oBAAoB,QAAQ,IAAI;EA+HjF,QAAQ,cAAc,cAAc,SAAS,IAAI,oBAAoB,QAAQ,IAAI;UA0FhF;UASA"}
|
|
@@ -3,8 +3,8 @@ import _classPrivateFieldGet2 from "../_virtual/_@oxc-project_runtime@0.154.0/he
|
|
|
3
3
|
import { assertNodeSupportedEcCrv, assertNodeSupportedOctAlgorithm, assertNodeSupportedOkpCrv, createEcKey, createOctKey, createOkpKey, createRsaKey } from "./crypto/createKey.mjs";
|
|
4
4
|
import { nodeSupportedJwaAlgorithm, performSign } from "./crypto/sign.mjs";
|
|
5
5
|
import { performDecrypt } from "./crypto/decrypt.mjs";
|
|
6
|
-
import { deriveDecryptionKey, deriveEncryptionKey, nodeSupportedKeyAgreementAlgorithms } from "./crypto/deriveKey.mjs";
|
|
7
6
|
import { nodeSupportedEncryptionAlgorithms, performEncrypt } from "./crypto/encrypt.mjs";
|
|
7
|
+
import { deriveDecryptionKey, encryptEcdh, nodeSupportedKeyAgreementAlgorithms } from "./crypto/deriveKey.mjs";
|
|
8
8
|
import { hpkeOpen, hpkeSeal, nodeSupportedHpkeAlgorithms } from "./crypto/hpke.mjs";
|
|
9
9
|
import { performVerify } from "./crypto/verify.mjs";
|
|
10
10
|
import _classPrivateFieldSet2 from "../_virtual/_@oxc-project_runtime@0.154.0/helpers/esm/classPrivateFieldSet2.mjs";
|
|
@@ -63,13 +63,16 @@ var NodeKeyManagementService = class {
|
|
|
63
63
|
if (operation.operation === "sign" || operation.operation === "verify") return nodeSupportedJwaAlgorithm.includes(operation.algorithm);
|
|
64
64
|
if (operation.operation === "encrypt" || operation.operation === "decrypt") {
|
|
65
65
|
const encryption = operation.operation === "encrypt" ? operation.encryption : operation.decryption;
|
|
66
|
-
if (operation.keyAgreement
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
if (operation.keyAgreement) {
|
|
67
|
+
const { keyAgreement } = operation;
|
|
68
|
+
for (const publicJwk of Kms.keyAgreementPublicJwks(keyAgreement)) {
|
|
69
|
+
try {
|
|
70
|
+
if (publicJwk.kty === "EC") assertNodeSupportedEcCrv(publicJwk);
|
|
71
|
+
else assertNodeSupportedOkpCrv(publicJwk);
|
|
72
|
+
} catch {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
if (!Kms.supportedKeyDerivationAlgsForKey(publicJwk).includes(keyAgreement.algorithm)) return false;
|
|
73
76
|
}
|
|
74
77
|
}
|
|
75
78
|
if (encryption.algorithm === "HPKE") {
|
|
@@ -226,37 +229,70 @@ var NodeKeyManagementService = class {
|
|
|
226
229
|
}
|
|
227
230
|
}
|
|
228
231
|
Kms.assertSupportedEncryptionAlgorithm(encryption, nodeSupportedEncryptionAlgorithms, this.backend);
|
|
232
|
+
const aad = "aad" in encryption ? encryption.aad : void 0;
|
|
233
|
+
if (key.keyAgreement) {
|
|
234
|
+
const { keyAgreement } = key;
|
|
235
|
+
Kms.assertSupportedKeyAgreementAlgorithm(keyAgreement, nodeSupportedKeyAgreementAlgorithms, this.backend);
|
|
236
|
+
const recipientJwks = Kms.keyAgreementPublicJwks(keyAgreement);
|
|
237
|
+
for (const recipientJwk of recipientJwks) {
|
|
238
|
+
Kms.assertAllowedKeyDerivationAlgForKey(recipientJwk, keyAgreement.algorithm);
|
|
239
|
+
Kms.assertKeyAllowsDerive(recipientJwk);
|
|
240
|
+
}
|
|
241
|
+
let senderPrivateJwk;
|
|
242
|
+
if (keyAgreement.algorithm === "ECDH-1PU+A256KW") {
|
|
243
|
+
const privateJwk = await this.getKeyAsserted(agentContext, keyAgreement.keyId);
|
|
244
|
+
Kms.assertJwkAsymmetric(privateJwk, keyAgreement.keyId);
|
|
245
|
+
Kms.assertAllowedKeyDerivationAlgForKey(privateJwk, keyAgreement.algorithm);
|
|
246
|
+
Kms.assertKeyAllowsDerive(privateJwk);
|
|
247
|
+
Kms.assertAsymmetricJwkKeyTypeMatches(privateJwk, recipientJwks[0]);
|
|
248
|
+
senderPrivateJwk = privateJwk;
|
|
249
|
+
}
|
|
250
|
+
const recipientPublicJwk = recipientJwks[0];
|
|
251
|
+
const ephemeral = recipientPublicJwk.kty === "OKP" ? await createOkpKey({
|
|
252
|
+
kty: "OKP",
|
|
253
|
+
crv: "X25519"
|
|
254
|
+
}) : await createEcKey({
|
|
255
|
+
kty: "EC",
|
|
256
|
+
crv: recipientPublicJwk.crv
|
|
257
|
+
});
|
|
258
|
+
const ephemeralPublicJwk = ephemeral.publicJwk;
|
|
259
|
+
const contentAad = typeof aad === "function" ? aad({ ephemeralPublicJwk }) : aad;
|
|
260
|
+
if (contentAad !== void 0 && !(contentAad instanceof Uint8Array)) throw new Kms.KeyManagementError(`'encryption.aad' callback must return a Uint8Array`);
|
|
261
|
+
try {
|
|
262
|
+
const { encrypted, iv, tag, encryptedKeys } = await encryptEcdh({
|
|
263
|
+
keyAgreement,
|
|
264
|
+
encryption,
|
|
265
|
+
aad: contentAad,
|
|
266
|
+
ephemeralPrivateJwk: ephemeral.privateJwk,
|
|
267
|
+
senderPrivateJwk,
|
|
268
|
+
data
|
|
269
|
+
});
|
|
270
|
+
return {
|
|
271
|
+
encrypted: new Uint8Array(encrypted),
|
|
272
|
+
iv: new Uint8Array(iv),
|
|
273
|
+
tag: tag ? new Uint8Array(tag) : void 0,
|
|
274
|
+
ephemeralPublicJwk,
|
|
275
|
+
encryptedKeys
|
|
276
|
+
};
|
|
277
|
+
} catch (error) {
|
|
278
|
+
if (error instanceof Kms.KeyManagementError) throw error;
|
|
279
|
+
throw new Kms.KeyManagementError("Error encrypting", { cause: error });
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (typeof aad === "function") throw new Kms.KeyManagementError(`'encryption.aad' can only be a callback with ECDH key agreement`);
|
|
229
283
|
let encryptionKey;
|
|
230
|
-
let encryptedKey;
|
|
231
284
|
if (key.keyId) encryptionKey = await this.getKeyAsserted(agentContext, key.keyId);
|
|
232
285
|
else if (key.privateJwk) encryptionKey = key.privateJwk;
|
|
233
|
-
else
|
|
234
|
-
Kms.assertAllowedKeyDerivationAlgForKey(key.keyAgreement.externalPublicJwk, key.keyAgreement.algorithm);
|
|
235
|
-
Kms.assertKeyAllowsDerive(key.keyAgreement.externalPublicJwk);
|
|
236
|
-
Kms.assertSupportedKeyAgreementAlgorithm(key.keyAgreement, nodeSupportedKeyAgreementAlgorithms, this.backend);
|
|
237
|
-
const privateJwk = await this.getKeyAsserted(agentContext, key.keyAgreement.keyId);
|
|
238
|
-
Kms.assertJwkAsymmetric(privateJwk, key.keyAgreement.keyId);
|
|
239
|
-
Kms.assertAllowedKeyDerivationAlgForKey(privateJwk, key.keyAgreement.algorithm);
|
|
240
|
-
Kms.assertKeyAllowsDerive(privateJwk);
|
|
241
|
-
Kms.assertAsymmetricJwkKeyTypeMatches(privateJwk, key.keyAgreement.externalPublicJwk);
|
|
242
|
-
const { contentEncryptionKey, encryptedContentEncryptionKey } = await deriveEncryptionKey({
|
|
243
|
-
keyAgreement: key.keyAgreement,
|
|
244
|
-
encryption,
|
|
245
|
-
privateJwk
|
|
246
|
-
});
|
|
247
|
-
encryptionKey = contentEncryptionKey;
|
|
248
|
-
encryptedKey = encryptedContentEncryptionKey;
|
|
249
|
-
} else throw new Kms.KeyManagementError("Unexpected key parameter for encrypt");
|
|
286
|
+
else throw new Kms.KeyManagementError("Unexpected key parameter for encrypt");
|
|
250
287
|
if (encryptionKey.kty !== "oct") throw new Kms.KeyManagementAlgorithmNotSupportedError(`kty '${encryptionKey.kty} for content encryption'`, this.backend);
|
|
251
288
|
try {
|
|
252
289
|
Kms.assertAllowedEncryptionAlgForKey(encryptionKey, encryption.algorithm);
|
|
253
290
|
Kms.assertKeyAllowsEncrypt(encryptionKey);
|
|
254
|
-
const { encrypted, iv, tag } = await performEncrypt(encryptionKey, encryption, data);
|
|
291
|
+
const { encrypted, iv, tag } = await performEncrypt(encryptionKey, encryption, data, aad);
|
|
255
292
|
return {
|
|
256
293
|
encrypted: new Uint8Array(encrypted),
|
|
257
294
|
iv: new Uint8Array(iv),
|
|
258
|
-
tag: tag ? new Uint8Array(tag) : void 0
|
|
259
|
-
encryptedKey
|
|
295
|
+
tag: tag ? new Uint8Array(tag) : void 0
|
|
260
296
|
};
|
|
261
297
|
} catch (error) {
|
|
262
298
|
if (error instanceof Kms.KeyManagementError) throw error;
|
|
@@ -292,14 +328,17 @@ var NodeKeyManagementService = class {
|
|
|
292
328
|
else if (key.privateJwk) decryptionKey = key.privateJwk;
|
|
293
329
|
else if (key.keyAgreement) {
|
|
294
330
|
Kms.assertSupportedKeyAgreementAlgorithm(key.keyAgreement, nodeSupportedKeyAgreementAlgorithms, this.backend);
|
|
295
|
-
Kms.
|
|
296
|
-
|
|
331
|
+
const publicJwks = Kms.keyAgreementPublicJwks(key.keyAgreement);
|
|
332
|
+
for (const publicJwk of publicJwks) {
|
|
333
|
+
Kms.assertAllowedKeyDerivationAlgForKey(publicJwk, key.keyAgreement.algorithm);
|
|
334
|
+
Kms.assertKeyAllowsDerive(publicJwk);
|
|
335
|
+
}
|
|
297
336
|
const privateJwk = await this.getKeyAsserted(agentContext, key.keyAgreement.keyId);
|
|
298
337
|
Kms.assertJwkAsymmetric(privateJwk, key.keyAgreement.keyId);
|
|
299
338
|
Kms.assertAllowedKeyDerivationAlgForKey(privateJwk, key.keyAgreement.algorithm);
|
|
300
339
|
Kms.assertKeyAllowsDerive(privateJwk);
|
|
301
|
-
Kms.assertAsymmetricJwkKeyTypeMatches(privateJwk,
|
|
302
|
-
const { contentEncryptionKey } =
|
|
340
|
+
for (const publicJwk of publicJwks) Kms.assertAsymmetricJwkKeyTypeMatches(privateJwk, publicJwk);
|
|
341
|
+
const { contentEncryptionKey } = deriveDecryptionKey({
|
|
303
342
|
keyAgreement: key.keyAgreement,
|
|
304
343
|
decryption,
|
|
305
344
|
privateJwk
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeKeyManagementService.mjs","names":[],"sources":["../../src/kms/NodeKeyManagementService.ts"],"sourcesContent":["import { createPrivateKey, createSecretKey, randomBytes, randomUUID } from 'node:crypto'\nimport type { AgentContext } from '@credo-ts/core'\nimport { Kms, TypedArrayEncoder } from '@credo-ts/core'\nimport {\n assertNodeSupportedEcCrv,\n assertNodeSupportedOctAlgorithm,\n assertNodeSupportedOkpCrv,\n createEcKey,\n createOctKey,\n createOkpKey,\n createRsaKey,\n} from './crypto/createKey'\nimport { performDecrypt } from './crypto/decrypt'\nimport { deriveDecryptionKey, deriveEncryptionKey, nodeSupportedKeyAgreementAlgorithms } from './crypto/deriveKey'\nimport { nodeSupportedEncryptionAlgorithms, performEncrypt } from './crypto/encrypt'\nimport { hpkeOpen, hpkeSeal, nodeSupportedHpkeAlgorithms } from './crypto/hpke'\nimport { nodeSupportedJwaAlgorithm, performSign } from './crypto/sign'\nimport { performVerify } from './crypto/verify'\nimport type { NodeKeyManagementStorage } from './NodeKeyManagementStorage'\n\nexport class NodeKeyManagementService implements Kms.KeyManagementService {\n public readonly backend = 'node'\n\n #storage: NodeKeyManagementStorage\n\n public constructor(storage: NodeKeyManagementStorage) {\n this.#storage = storage\n }\n\n public isOperationSupported(_agentContext: AgentContext, operation: Kms.KmsOperation): boolean {\n if (operation.operation === 'deleteKey') return true\n if (operation.operation === 'randomBytes') return true\n\n if (operation.operation === 'createKey') {\n // TODO: probably clean to split the assert methods so we don't need try/catch here\n try {\n if (operation.type.kty === 'RSA') {\n return true\n }\n\n if (operation.type.kty === 'EC') {\n assertNodeSupportedEcCrv(operation.type)\n return true\n }\n\n if (operation.type.kty === 'OKP') {\n assertNodeSupportedOkpCrv(operation.type)\n return true\n }\n\n if (operation.type.kty === 'oct') {\n assertNodeSupportedOctAlgorithm(operation.type)\n return true\n }\n } catch {\n return false\n }\n\n return false\n }\n\n if (operation.operation === 'importKey') {\n try {\n if (operation.privateJwk.kty === 'RSA' || operation.privateJwk.kty === 'oct') {\n return true\n }\n\n if (operation.privateJwk.kty === 'EC') {\n assertNodeSupportedEcCrv({ kty: operation.privateJwk.kty, crv: operation.privateJwk.crv })\n return true\n }\n\n if (operation.privateJwk.kty === 'OKP') {\n assertNodeSupportedOkpCrv({ kty: operation.privateJwk.kty, crv: operation.privateJwk.crv })\n return true\n }\n } catch {\n return false\n }\n }\n\n if (operation.operation === 'sign' || operation.operation === 'verify') {\n return nodeSupportedJwaAlgorithm.includes(operation.algorithm)\n }\n\n if (operation.operation === 'encrypt' || operation.operation === 'decrypt') {\n const encryption = operation.operation === 'encrypt' ? operation.encryption : operation.decryption\n\n // We can only perform key agreement with curves we support. We also can't create the\n // ephemeral key for e.g. ECDH-ES if the curve is not supported.\n if (\n operation.keyAgreement &&\n 'externalPublicJwk' in operation.keyAgreement &&\n operation.keyAgreement.externalPublicJwk\n ) {\n const externalPublicJwk = operation.keyAgreement.externalPublicJwk\n try {\n if (externalPublicJwk.kty === 'EC') assertNodeSupportedEcCrv(externalPublicJwk)\n else assertNodeSupportedOkpCrv(externalPublicJwk)\n } catch {\n return false\n }\n }\n\n // HPKE is an integrated encryption mode: the suite fixes the AEAD, so the HPKE key agreement\n // algorithm is all there is to check.\n if (encryption.algorithm === 'HPKE') {\n if (!operation.keyAgreement || !Kms.isJwaHpkeAlgorithm(operation.keyAgreement.algorithm)) return false\n\n return nodeSupportedHpkeAlgorithms.includes(\n operation.keyAgreement.algorithm as (typeof nodeSupportedHpkeAlgorithms)[number]\n )\n }\n\n const isSupportedEncryptionAlgorithm = nodeSupportedEncryptionAlgorithms.includes(\n encryption.algorithm as (typeof nodeSupportedEncryptionAlgorithms)[number]\n )\n if (!isSupportedEncryptionAlgorithm) return false\n if (!operation.keyAgreement) return true\n\n return nodeSupportedKeyAgreementAlgorithms.includes(\n operation.keyAgreement.algorithm as (typeof nodeSupportedKeyAgreementAlgorithms)[number]\n )\n }\n\n return false\n }\n\n public randomBytes(_agentContext: AgentContext, options: Kms.KmsRandomBytesOptions): Kms.KmsRandomBytesReturn {\n return new Uint8Array(randomBytes(options.length))\n }\n\n public async getPublicKey(agentContext: AgentContext, keyId: string): Promise<Kms.KmsJwkPublic | null> {\n const privateJwk = await this.#storage.get(agentContext, keyId)\n if (!privateJwk) return null\n\n return Kms.publicJwkFromPrivateJwk(privateJwk)\n }\n\n public async importKey<Jwk extends Kms.KmsJwkPrivate>(\n agentContext: AgentContext,\n options: Kms.KmsImportKeyOptions<Jwk>\n ): Promise<Kms.KmsImportKeyReturn<Jwk>> {\n const { kid } = options.privateJwk\n\n if (kid) await this.assertKeyNotExists(agentContext, kid)\n\n const privateJwk = {\n ...options.privateJwk,\n kid: kid ?? randomUUID(),\n }\n\n try {\n if (privateJwk.kty === 'oct') {\n // Just check if we can create a secret key instance\n createSecretKey(TypedArrayEncoder.fromBase64Url(privateJwk.k)).export({ format: 'jwk' })\n } else if (privateJwk.kty === 'EC') {\n assertNodeSupportedEcCrv({ kty: privateJwk.kty, crv: privateJwk.crv })\n // This validates the JWK\n createPrivateKey({\n format: 'jwk',\n key: privateJwk,\n })\n } else if (privateJwk.kty === 'OKP') {\n assertNodeSupportedOkpCrv({ kty: privateJwk.kty, crv: privateJwk.crv })\n // This validates the JWK\n createPrivateKey({\n format: 'jwk',\n key: privateJwk,\n })\n } else if (privateJwk.kty === 'RSA') {\n // This validates the JWK\n createPrivateKey({\n format: 'jwk',\n key: privateJwk,\n })\n } else {\n // All kty values supported for now, but can change in the future\n // @ts-expect-error\n throw new Kms.KeyManagementAlgorithmNotSupportedError(`kty '${privateJwk.kty}'`, this.backend)\n }\n\n await this.#storage.set(agentContext, privateJwk.kid, privateJwk)\n const publicJwk = Kms.publicJwkFromPrivateJwk(privateJwk)\n\n return {\n keyId: privateJwk.kid,\n publicJwk: {\n ...publicJwk,\n kid: privateJwk.kid,\n },\n } as Kms.KmsImportKeyReturn<Jwk>\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n\n throw new Kms.KeyManagementError('Error importing key', { cause: error })\n }\n }\n\n public async deleteKey(agentContext: AgentContext, options: Kms.KmsDeleteKeyOptions): Promise<boolean> {\n return await this.#storage.delete(agentContext, options.keyId)\n }\n\n public async createKey<Type extends Kms.KmsCreateKeyType>(\n agentContext: AgentContext,\n options: Kms.KmsCreateKeyOptions<Type>\n ): Promise<Kms.KmsCreateKeyReturn<Type>> {\n const { type, keyId } = options\n\n if (keyId) await this.assertKeyNotExists(agentContext, keyId)\n\n try {\n let jwks: { publicJwk: Kms.KmsJwkPublic; privateJwk: Kms.KmsJwkPrivate }\n if (type.kty === 'EC') {\n assertNodeSupportedEcCrv(type)\n jwks = await createEcKey(type)\n } else if (type.kty === 'OKP') {\n assertNodeSupportedOkpCrv(type)\n jwks = await createOkpKey(type)\n } else if (type.kty === 'RSA') {\n jwks = await createRsaKey(type)\n } else if (type.kty === 'oct') {\n assertNodeSupportedOctAlgorithm(type)\n jwks = await createOctKey(type)\n } else {\n // @ts-expect-error\n throw new Kms.KeyManagementAlgorithmNotSupportedError(`kty '${type.kty}'`, this.backend)\n }\n\n jwks.privateJwk.kid = keyId ?? randomUUID()\n jwks.publicJwk.kid = jwks.privateJwk.kid\n\n await this.#storage.set(agentContext, jwks.privateJwk.kid, jwks.privateJwk)\n\n return {\n publicJwk: jwks.publicJwk as Kms.KmsCreateKeyReturn<Type>['publicJwk'],\n keyId: jwks.publicJwk.kid,\n }\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n\n throw new Kms.KeyManagementError('Error creating key', { cause: error })\n }\n }\n\n public async sign(agentContext: AgentContext, options: Kms.KmsSignOptions): Promise<Kms.KmsSignReturn> {\n const { keyId, algorithm, data } = options\n\n // 1. Retrieve the key\n const key = await this.getKeyAsserted(agentContext, keyId)\n\n try {\n // 2. Validate alg and use for key\n Kms.assertAllowedSigningAlgForKey(key, algorithm)\n Kms.assertKeyAllowsSign(key)\n\n // 3. Perform the signing operation\n const signature = await performSign(key, algorithm, data)\n\n return {\n signature: new Uint8Array(signature),\n }\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n\n throw new Kms.KeyManagementError('Error signing with key', { cause: error })\n }\n }\n\n public async verify(agentContext: AgentContext, options: Kms.KmsVerifyOptions): Promise<Kms.KmsVerifyReturn> {\n const { algorithm, data, signature } = options\n\n try {\n let key: Exclude<Kms.KmsJwkPublic, Kms.KmsJwkPublicOct> | Kms.KmsJwkPrivate\n if (options.key.keyId) {\n key = await this.getKeyAsserted(agentContext, options.key.keyId)\n } else if (options.key.publicJwk?.kty === 'EC') {\n assertNodeSupportedEcCrv(options.key.publicJwk)\n key = options.key.publicJwk\n } else if (options.key.publicJwk?.kty === 'OKP') {\n assertNodeSupportedOkpCrv(options.key.publicJwk)\n key = options.key.publicJwk\n } else if (options.key.publicJwk?.kty === 'RSA') {\n key = options.key.publicJwk\n } else {\n // @ts-expect-error\n throw new Kms.KeyManagementAlgorithmNotSupportedError(`kty ${options.key.kty}`, this.backend)\n }\n\n // 2. Validate alg and use for key\n Kms.assertAllowedSigningAlgForKey(key, algorithm)\n Kms.assertKeyAllowsVerify(key)\n\n // 3. Perform the verify operation\n const verified = await performVerify(key, algorithm, data, signature)\n if (verified) {\n return {\n verified: true,\n publicJwk: Kms.publicJwkFromPrivateJwk(key),\n }\n }\n\n return {\n verified: false,\n }\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n\n throw new Kms.KeyManagementError('Error verifying with key', { cause: error })\n }\n }\n\n public async encrypt(agentContext: AgentContext, options: Kms.KmsEncryptOptions): Promise<Kms.KmsEncryptReturn> {\n const { data, encryption, key } = options\n\n if (encryption.algorithm === 'HPKE') {\n if (!key.keyAgreement || !Kms.isKmsKeyAgreementEncryptHpke(key.keyAgreement)) {\n throw new Kms.KeyManagementError(\n `Encryption algorithm 'HPKE' can only be used with an integrated-encryption HPKE key agreement algorithm`\n )\n }\n\n const { keyAgreement } = key\n Kms.assertAllowedKeyDerivationAlgForKey(keyAgreement.externalPublicJwk, keyAgreement.algorithm)\n Kms.assertKeyAllowsDerive(keyAgreement.externalPublicJwk)\n\n try {\n return await hpkeSeal({\n algorithm: keyAgreement.algorithm,\n recipientPublicJwk: keyAgreement.externalPublicJwk,\n data,\n info: keyAgreement.info,\n aad: encryption.aad,\n })\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n throw new Kms.KeyManagementError('Error encrypting', { cause: error })\n }\n }\n\n Kms.assertSupportedEncryptionAlgorithm(encryption, nodeSupportedEncryptionAlgorithms, this.backend)\n\n let encryptionKey: Kms.KmsJwkPrivate\n let encryptedKey: Kms.KmsEncryptedKey | undefined\n\n if (key.keyId) {\n encryptionKey = await this.getKeyAsserted(agentContext, key.keyId)\n } else if (key.privateJwk) {\n encryptionKey = key.privateJwk\n } else if (key.keyAgreement) {\n Kms.assertAllowedKeyDerivationAlgForKey(key.keyAgreement.externalPublicJwk, key.keyAgreement.algorithm)\n Kms.assertKeyAllowsDerive(key.keyAgreement.externalPublicJwk)\n Kms.assertSupportedKeyAgreementAlgorithm(key.keyAgreement, nodeSupportedKeyAgreementAlgorithms, this.backend)\n\n const privateJwk = await this.getKeyAsserted(agentContext, key.keyAgreement.keyId)\n Kms.assertJwkAsymmetric(privateJwk, key.keyAgreement.keyId)\n Kms.assertAllowedKeyDerivationAlgForKey(privateJwk, key.keyAgreement.algorithm)\n Kms.assertKeyAllowsDerive(privateJwk)\n Kms.assertAsymmetricJwkKeyTypeMatches(privateJwk, key.keyAgreement.externalPublicJwk)\n\n const { contentEncryptionKey, encryptedContentEncryptionKey } = await deriveEncryptionKey({\n keyAgreement: key.keyAgreement,\n encryption,\n privateJwk,\n })\n\n encryptionKey = contentEncryptionKey\n encryptedKey = encryptedContentEncryptionKey\n } else {\n throw new Kms.KeyManagementError('Unexpected key parameter for encrypt')\n }\n\n if (encryptionKey.kty !== 'oct') {\n throw new Kms.KeyManagementAlgorithmNotSupportedError(\n `kty '${encryptionKey.kty} for content encryption'`,\n this.backend\n )\n }\n\n try {\n // 2. Validate alg and use for key\n Kms.assertAllowedEncryptionAlgForKey(encryptionKey, encryption.algorithm)\n Kms.assertKeyAllowsEncrypt(encryptionKey)\n\n // 3. Perform the encryption operation\n const { encrypted, iv, tag } = await performEncrypt(encryptionKey, encryption, data)\n return {\n encrypted: new Uint8Array(encrypted),\n iv: new Uint8Array(iv),\n tag: tag ? new Uint8Array(tag) : undefined,\n encryptedKey,\n }\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n\n throw new Kms.KeyManagementError('Error encrypting', { cause: error })\n }\n }\n\n public async decrypt(agentContext: AgentContext, options: Kms.KmsDecryptOptions): Promise<Kms.KmsDecryptReturn> {\n const { decryption, encrypted, key } = options\n\n if (decryption.algorithm === 'HPKE') {\n if (!key.keyAgreement || !Kms.isKmsKeyAgreementDecryptHpke(key.keyAgreement)) {\n throw new Kms.KeyManagementError(\n `Decryption algorithm 'HPKE' can only be used with an integrated-encryption HPKE key agreement algorithm`\n )\n }\n\n const { keyAgreement } = key\n const recipientPrivateJwk = await this.getKeyAsserted(agentContext, keyAgreement.keyId)\n\n Kms.assertJwkAsymmetric(recipientPrivateJwk, keyAgreement.keyId)\n Kms.assertAllowedKeyDerivationAlgForKey(recipientPrivateJwk, keyAgreement.algorithm)\n Kms.assertKeyAllowsDerive(recipientPrivateJwk)\n\n try {\n return {\n data: await hpkeOpen({\n algorithm: keyAgreement.algorithm,\n recipientPrivateJwk,\n encapsulatedKey: keyAgreement.encapsulatedKey,\n encrypted,\n info: keyAgreement.info,\n aad: decryption.aad,\n }),\n }\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n throw new Kms.KeyManagementError('Error decrypting', { cause: error })\n }\n }\n\n Kms.assertSupportedEncryptionAlgorithm(decryption, nodeSupportedEncryptionAlgorithms, this.backend)\n\n let decryptionKey: Kms.KmsJwkPrivate\n if (key.keyId) {\n decryptionKey = await this.getKeyAsserted(agentContext, key.keyId)\n } else if (key.privateJwk) {\n decryptionKey = key.privateJwk\n } else if (key.keyAgreement) {\n Kms.assertSupportedKeyAgreementAlgorithm(key.keyAgreement, nodeSupportedKeyAgreementAlgorithms, this.backend)\n Kms.assertAllowedKeyDerivationAlgForKey(key.keyAgreement.externalPublicJwk, key.keyAgreement.algorithm)\n Kms.assertKeyAllowsDerive(key.keyAgreement.externalPublicJwk)\n\n const privateJwk = await this.getKeyAsserted(agentContext, key.keyAgreement.keyId)\n Kms.assertJwkAsymmetric(privateJwk, key.keyAgreement.keyId)\n Kms.assertAllowedKeyDerivationAlgForKey(privateJwk, key.keyAgreement.algorithm)\n Kms.assertKeyAllowsDerive(privateJwk)\n Kms.assertAsymmetricJwkKeyTypeMatches(privateJwk, key.keyAgreement.externalPublicJwk)\n\n const { contentEncryptionKey } = await deriveDecryptionKey({\n keyAgreement: key.keyAgreement,\n decryption,\n privateJwk,\n })\n\n decryptionKey = contentEncryptionKey\n } else {\n throw new Kms.KeyManagementError('Unexpected key parameter for decrypt')\n }\n\n if (decryptionKey.kty !== 'oct') {\n throw new Kms.KeyManagementAlgorithmNotSupportedError(\n `kty '${decryptionKey.kty}' for content encryption`,\n this.backend\n )\n }\n\n try {\n // 2. Validate alg and use for key\n Kms.assertAllowedEncryptionAlgForKey(decryptionKey, decryption.algorithm)\n Kms.assertKeyAllowsEncrypt(decryptionKey)\n\n // 3. Perform the decryption operation\n const { data } = await performDecrypt(decryptionKey, decryption, encrypted)\n return { data: new Uint8Array(data) }\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n\n throw new Kms.KeyManagementError('Error decrypting', { cause: error })\n }\n }\n\n private async getKeyAsserted(agentContext: AgentContext, keyId: string) {\n const storageKey = await this.#storage.get(agentContext, keyId)\n if (!storageKey) {\n throw new Kms.KeyManagementKeyNotFoundError(keyId, [this.backend])\n }\n\n return storageKey\n }\n\n private async assertKeyNotExists(agentContext: AgentContext, keyId: string) {\n const storageKey = await this.#storage.get(agentContext, keyId)\n\n if (storageKey) {\n throw new Kms.KeyManagementKeyExistsError(keyId, this.backend)\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAoBA,IAAa,2BAAb,MAA0E;CAKxE,YAAmB,SAAmC;EAJtD,KAAgB,UAAU;;EAKxB,uBAAA,UAAA,MAAgB,OAAA;CAClB;CAEA,qBAA4B,eAA6B,WAAsC;EAC7F,IAAI,UAAU,cAAc,aAAa,OAAO;EAChD,IAAI,UAAU,cAAc,eAAe,OAAO;EAElD,IAAI,UAAU,cAAc,aAAa;GAEvC,IAAI;IACF,IAAI,UAAU,KAAK,QAAQ,OACzB,OAAO;IAGT,IAAI,UAAU,KAAK,QAAQ,MAAM;KAC/B,yBAAyB,UAAU,IAAI;KACvC,OAAO;IACT;IAEA,IAAI,UAAU,KAAK,QAAQ,OAAO;KAChC,0BAA0B,UAAU,IAAI;KACxC,OAAO;IACT;IAEA,IAAI,UAAU,KAAK,QAAQ,OAAO;KAChC,gCAAgC,UAAU,IAAI;KAC9C,OAAO;IACT;GACF,QAAQ;IACN,OAAO;GACT;GAEA,OAAO;EACT;EAEA,IAAI,UAAU,cAAc,aAC1B,IAAI;GACF,IAAI,UAAU,WAAW,QAAQ,SAAS,UAAU,WAAW,QAAQ,OACrE,OAAO;GAGT,IAAI,UAAU,WAAW,QAAQ,MAAM;IACrC,yBAAyB;KAAE,KAAK,UAAU,WAAW;KAAK,KAAK,UAAU,WAAW;IAAI,CAAC;IACzF,OAAO;GACT;GAEA,IAAI,UAAU,WAAW,QAAQ,OAAO;IACtC,0BAA0B;KAAE,KAAK,UAAU,WAAW;KAAK,KAAK,UAAU,WAAW;IAAI,CAAC;IAC1F,OAAO;GACT;EACF,QAAQ;GACN,OAAO;EACT;EAGF,IAAI,UAAU,cAAc,UAAU,UAAU,cAAc,UAC5D,OAAO,0BAA0B,SAAS,UAAU,SAAS;EAG/D,IAAI,UAAU,cAAc,aAAa,UAAU,cAAc,WAAW;GAC1E,MAAM,aAAa,UAAU,cAAc,YAAY,UAAU,aAAa,UAAU;GAIxF,IACE,UAAU,gBACV,uBAAuB,UAAU,gBACjC,UAAU,aAAa,mBACvB;IACA,MAAM,oBAAoB,UAAU,aAAa;IACjD,IAAI;KACF,IAAI,kBAAkB,QAAQ,MAAM,yBAAyB,iBAAiB;UACzE,0BAA0B,iBAAiB;IAClD,QAAQ;KACN,OAAO;IACT;GACF;GAIA,IAAI,WAAW,cAAc,QAAQ;IACnC,IAAI,CAAC,UAAU,gBAAgB,CAAC,IAAI,mBAAmB,UAAU,aAAa,SAAS,GAAG,OAAO;IAEjG,OAAO,4BAA4B,SACjC,UAAU,aAAa,SACzB;GACF;GAKA,IAAI,CAHmC,kCAAkC,SACvE,WAAW,SAEqB,GAAG,OAAO;GAC5C,IAAI,CAAC,UAAU,cAAc,OAAO;GAEpC,OAAO,oCAAoC,SACzC,UAAU,aAAa,SACzB;EACF;EAEA,OAAO;CACT;CAEA,YAAmB,eAA6B,SAA8D;EAC5G,OAAO,IAAI,WAAW,YAAY,QAAQ,MAAM,CAAC;CACnD;CAEA,MAAa,aAAa,cAA4B,OAAiD;EACrG,MAAM,aAAa,MAAA,uBAAA,UAAM,IAAA,CAAA,CAAc,IAAI,cAAc,KAAK;EAC9D,IAAI,CAAC,YAAY,OAAO;EAExB,OAAO,IAAI,wBAAwB,UAAU;CAC/C;CAEA,MAAa,UACX,cACA,SACsC;EACtC,MAAM,EAAE,QAAQ,QAAQ;EAExB,IAAI,KAAK,MAAM,KAAK,mBAAmB,cAAc,GAAG;EAExD,MAAM,aAAa;GACjB,GAAG,QAAQ;GACX,KAAK,OAAO,WAAW;EACzB;EAEA,IAAI;GACF,IAAI,WAAW,QAAQ,OAErB,gBAAgB,kBAAkB,cAAc,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,MAAM,CAAC;QAClF,IAAI,WAAW,QAAQ,MAAM;IAClC,yBAAyB;KAAE,KAAK,WAAW;KAAK,KAAK,WAAW;IAAI,CAAC;IAErE,iBAAiB;KACf,QAAQ;KACR,KAAK;IACP,CAAC;GACH,OAAO,IAAI,WAAW,QAAQ,OAAO;IACnC,0BAA0B;KAAE,KAAK,WAAW;KAAK,KAAK,WAAW;IAAI,CAAC;IAEtE,iBAAiB;KACf,QAAQ;KACR,KAAK;IACP,CAAC;GACH,OAAO,IAAI,WAAW,QAAQ,OAE5B,iBAAiB;IACf,QAAQ;IACR,KAAK;GACP,CAAC;QAID,MAAM,IAAI,IAAI,wCAAwC,QAAQ,WAAW,IAAI,IAAI,KAAK,OAAO;GAG/F,MAAA,uBAAA,UAAM,IAAA,CAAA,CAAc,IAAI,cAAc,WAAW,KAAK,UAAU;GAChE,MAAM,YAAY,IAAI,wBAAwB,UAAU;GAExD,OAAO;IACL,OAAO,WAAW;IAClB,WAAW;KACT,GAAG;KACH,KAAK,WAAW;IAClB;GACF;EACF,SAAS,OAAO;GACd,IAAI,iBAAiB,IAAI,oBAAoB,MAAM;GAEnD,MAAM,IAAI,IAAI,mBAAmB,uBAAuB,EAAE,OAAO,MAAM,CAAC;EAC1E;CACF;CAEA,MAAa,UAAU,cAA4B,SAAoD;EACrG,OAAO,MAAA,uBAAA,UAAM,IAAA,CAAA,CAAc,OAAO,cAAc,QAAQ,KAAK;CAC/D;CAEA,MAAa,UACX,cACA,SACuC;EACvC,MAAM,EAAE,MAAM,UAAU;EAExB,IAAI,OAAO,MAAM,KAAK,mBAAmB,cAAc,KAAK;EAE5D,IAAI;GACF,IAAI;GACJ,IAAI,KAAK,QAAQ,MAAM;IACrB,yBAAyB,IAAI;IAC7B,OAAO,MAAM,YAAY,IAAI;GAC/B,OAAO,IAAI,KAAK,QAAQ,OAAO;IAC7B,0BAA0B,IAAI;IAC9B,OAAO,MAAM,aAAa,IAAI;GAChC,OAAO,IAAI,KAAK,QAAQ,OACtB,OAAO,MAAM,aAAa,IAAI;QACzB,IAAI,KAAK,QAAQ,OAAO;IAC7B,gCAAgC,IAAI;IACpC,OAAO,MAAM,aAAa,IAAI;GAChC,OAEE,MAAM,IAAI,IAAI,wCAAwC,QAAQ,KAAK,IAAI,IAAI,KAAK,OAAO;GAGzF,KAAK,WAAW,MAAM,SAAS,WAAW;GAC1C,KAAK,UAAU,MAAM,KAAK,WAAW;GAErC,MAAA,uBAAA,UAAM,IAAA,CAAA,CAAc,IAAI,cAAc,KAAK,WAAW,KAAK,KAAK,UAAU;GAE1E,OAAO;IACL,WAAW,KAAK;IAChB,OAAO,KAAK,UAAU;GACxB;EACF,SAAS,OAAO;GACd,IAAI,iBAAiB,IAAI,oBAAoB,MAAM;GAEnD,MAAM,IAAI,IAAI,mBAAmB,sBAAsB,EAAE,OAAO,MAAM,CAAC;EACzE;CACF;CAEA,MAAa,KAAK,cAA4B,SAAyD;EACrG,MAAM,EAAE,OAAO,WAAW,SAAS;EAGnC,MAAM,MAAM,MAAM,KAAK,eAAe,cAAc,KAAK;EAEzD,IAAI;GAEF,IAAI,8BAA8B,KAAK,SAAS;GAChD,IAAI,oBAAoB,GAAG;GAG3B,MAAM,YAAY,MAAM,YAAY,KAAK,WAAW,IAAI;GAExD,OAAO,EACL,WAAW,IAAI,WAAW,SAAS,EACrC;EACF,SAAS,OAAO;GACd,IAAI,iBAAiB,IAAI,oBAAoB,MAAM;GAEnD,MAAM,IAAI,IAAI,mBAAmB,0BAA0B,EAAE,OAAO,MAAM,CAAC;EAC7E;CACF;CAEA,MAAa,OAAO,cAA4B,SAA6D;EAC3G,MAAM,EAAE,WAAW,MAAM,cAAc;EAEvC,IAAI;GACF,IAAI;GACJ,IAAI,QAAQ,IAAI,OACd,MAAM,MAAM,KAAK,eAAe,cAAc,QAAQ,IAAI,KAAK;QAC1D,IAAI,QAAQ,IAAI,WAAW,QAAQ,MAAM;IAC9C,yBAAyB,QAAQ,IAAI,SAAS;IAC9C,MAAM,QAAQ,IAAI;GACpB,OAAO,IAAI,QAAQ,IAAI,WAAW,QAAQ,OAAO;IAC/C,0BAA0B,QAAQ,IAAI,SAAS;IAC/C,MAAM,QAAQ,IAAI;GACpB,OAAO,IAAI,QAAQ,IAAI,WAAW,QAAQ,OACxC,MAAM,QAAQ,IAAI;QAGlB,MAAM,IAAI,IAAI,wCAAwC,OAAO,QAAQ,IAAI,OAAO,KAAK,OAAO;GAI9F,IAAI,8BAA8B,KAAK,SAAS;GAChD,IAAI,sBAAsB,GAAG;GAI7B,IAAI,MADmB,cAAc,KAAK,WAAW,MAAM,SAAS,GAElE,OAAO;IACL,UAAU;IACV,WAAW,IAAI,wBAAwB,GAAG;GAC5C;GAGF,OAAO,EACL,UAAU,MACZ;EACF,SAAS,OAAO;GACd,IAAI,iBAAiB,IAAI,oBAAoB,MAAM;GAEnD,MAAM,IAAI,IAAI,mBAAmB,4BAA4B,EAAE,OAAO,MAAM,CAAC;EAC/E;CACF;CAEA,MAAa,QAAQ,cAA4B,SAA+D;EAC9G,MAAM,EAAE,MAAM,YAAY,QAAQ;EAElC,IAAI,WAAW,cAAc,QAAQ;GACnC,IAAI,CAAC,IAAI,gBAAgB,CAAC,IAAI,6BAA6B,IAAI,YAAY,GACzE,MAAM,IAAI,IAAI,mBACZ,yGACF;GAGF,MAAM,EAAE,iBAAiB;GACzB,IAAI,oCAAoC,aAAa,mBAAmB,aAAa,SAAS;GAC9F,IAAI,sBAAsB,aAAa,iBAAiB;GAExD,IAAI;IACF,OAAO,MAAM,SAAS;KACpB,WAAW,aAAa;KACxB,oBAAoB,aAAa;KACjC;KACA,MAAM,aAAa;KACnB,KAAK,WAAW;IAClB,CAAC;GACH,SAAS,OAAO;IACd,IAAI,iBAAiB,IAAI,oBAAoB,MAAM;IACnD,MAAM,IAAI,IAAI,mBAAmB,oBAAoB,EAAE,OAAO,MAAM,CAAC;GACvE;EACF;EAEA,IAAI,mCAAmC,YAAY,mCAAmC,KAAK,OAAO;EAElG,IAAI;EACJ,IAAI;EAEJ,IAAI,IAAI,OACN,gBAAgB,MAAM,KAAK,eAAe,cAAc,IAAI,KAAK;OAC5D,IAAI,IAAI,YACb,gBAAgB,IAAI;OACf,IAAI,IAAI,cAAc;GAC3B,IAAI,oCAAoC,IAAI,aAAa,mBAAmB,IAAI,aAAa,SAAS;GACtG,IAAI,sBAAsB,IAAI,aAAa,iBAAiB;GAC5D,IAAI,qCAAqC,IAAI,cAAc,qCAAqC,KAAK,OAAO;GAE5G,MAAM,aAAa,MAAM,KAAK,eAAe,cAAc,IAAI,aAAa,KAAK;GACjF,IAAI,oBAAoB,YAAY,IAAI,aAAa,KAAK;GAC1D,IAAI,oCAAoC,YAAY,IAAI,aAAa,SAAS;GAC9E,IAAI,sBAAsB,UAAU;GACpC,IAAI,kCAAkC,YAAY,IAAI,aAAa,iBAAiB;GAEpF,MAAM,EAAE,sBAAsB,kCAAkC,MAAM,oBAAoB;IACxF,cAAc,IAAI;IAClB;IACA;GACF,CAAC;GAED,gBAAgB;GAChB,eAAe;EACjB,OACE,MAAM,IAAI,IAAI,mBAAmB,sCAAsC;EAGzE,IAAI,cAAc,QAAQ,OACxB,MAAM,IAAI,IAAI,wCACZ,QAAQ,cAAc,IAAI,2BAC1B,KAAK,OACP;EAGF,IAAI;GAEF,IAAI,iCAAiC,eAAe,WAAW,SAAS;GACxE,IAAI,uBAAuB,aAAa;GAGxC,MAAM,EAAE,WAAW,IAAI,QAAQ,MAAM,eAAe,eAAe,YAAY,IAAI;GACnF,OAAO;IACL,WAAW,IAAI,WAAW,SAAS;IACnC,IAAI,IAAI,WAAW,EAAE;IACrB,KAAK,MAAM,IAAI,WAAW,GAAG,IAAI,KAAA;IACjC;GACF;EACF,SAAS,OAAO;GACd,IAAI,iBAAiB,IAAI,oBAAoB,MAAM;GAEnD,MAAM,IAAI,IAAI,mBAAmB,oBAAoB,EAAE,OAAO,MAAM,CAAC;EACvE;CACF;CAEA,MAAa,QAAQ,cAA4B,SAA+D;EAC9G,MAAM,EAAE,YAAY,WAAW,QAAQ;EAEvC,IAAI,WAAW,cAAc,QAAQ;GACnC,IAAI,CAAC,IAAI,gBAAgB,CAAC,IAAI,6BAA6B,IAAI,YAAY,GACzE,MAAM,IAAI,IAAI,mBACZ,yGACF;GAGF,MAAM,EAAE,iBAAiB;GACzB,MAAM,sBAAsB,MAAM,KAAK,eAAe,cAAc,aAAa,KAAK;GAEtF,IAAI,oBAAoB,qBAAqB,aAAa,KAAK;GAC/D,IAAI,oCAAoC,qBAAqB,aAAa,SAAS;GACnF,IAAI,sBAAsB,mBAAmB;GAE7C,IAAI;IACF,OAAO,EACL,MAAM,MAAM,SAAS;KACnB,WAAW,aAAa;KACxB;KACA,iBAAiB,aAAa;KAC9B;KACA,MAAM,aAAa;KACnB,KAAK,WAAW;IAClB,CAAC,EACH;GACF,SAAS,OAAO;IACd,IAAI,iBAAiB,IAAI,oBAAoB,MAAM;IACnD,MAAM,IAAI,IAAI,mBAAmB,oBAAoB,EAAE,OAAO,MAAM,CAAC;GACvE;EACF;EAEA,IAAI,mCAAmC,YAAY,mCAAmC,KAAK,OAAO;EAElG,IAAI;EACJ,IAAI,IAAI,OACN,gBAAgB,MAAM,KAAK,eAAe,cAAc,IAAI,KAAK;OAC5D,IAAI,IAAI,YACb,gBAAgB,IAAI;OACf,IAAI,IAAI,cAAc;GAC3B,IAAI,qCAAqC,IAAI,cAAc,qCAAqC,KAAK,OAAO;GAC5G,IAAI,oCAAoC,IAAI,aAAa,mBAAmB,IAAI,aAAa,SAAS;GACtG,IAAI,sBAAsB,IAAI,aAAa,iBAAiB;GAE5D,MAAM,aAAa,MAAM,KAAK,eAAe,cAAc,IAAI,aAAa,KAAK;GACjF,IAAI,oBAAoB,YAAY,IAAI,aAAa,KAAK;GAC1D,IAAI,oCAAoC,YAAY,IAAI,aAAa,SAAS;GAC9E,IAAI,sBAAsB,UAAU;GACpC,IAAI,kCAAkC,YAAY,IAAI,aAAa,iBAAiB;GAEpF,MAAM,EAAE,yBAAyB,MAAM,oBAAoB;IACzD,cAAc,IAAI;IAClB;IACA;GACF,CAAC;GAED,gBAAgB;EAClB,OACE,MAAM,IAAI,IAAI,mBAAmB,sCAAsC;EAGzE,IAAI,cAAc,QAAQ,OACxB,MAAM,IAAI,IAAI,wCACZ,QAAQ,cAAc,IAAI,2BAC1B,KAAK,OACP;EAGF,IAAI;GAEF,IAAI,iCAAiC,eAAe,WAAW,SAAS;GACxE,IAAI,uBAAuB,aAAa;GAGxC,MAAM,EAAE,SAAS,MAAM,eAAe,eAAe,YAAY,SAAS;GAC1E,OAAO,EAAE,MAAM,IAAI,WAAW,IAAI,EAAE;EACtC,SAAS,OAAO;GACd,IAAI,iBAAiB,IAAI,oBAAoB,MAAM;GAEnD,MAAM,IAAI,IAAI,mBAAmB,oBAAoB,EAAE,OAAO,MAAM,CAAC;EACvE;CACF;CAEA,MAAc,eAAe,cAA4B,OAAe;EACtE,MAAM,aAAa,MAAA,uBAAA,UAAM,IAAA,CAAA,CAAc,IAAI,cAAc,KAAK;EAC9D,IAAI,CAAC,YACH,MAAM,IAAI,IAAI,8BAA8B,OAAO,CAAC,KAAK,OAAO,CAAC;EAGnE,OAAO;CACT;CAEA,MAAc,mBAAmB,cAA4B,OAAe;EAG1E,IAAI,MAAA,uBAAA,UAFqB,IAAA,CAAA,CAAc,IAAI,cAAc,KAAK,GAG5D,MAAM,IAAI,IAAI,4BAA4B,OAAO,KAAK,OAAO;CAEjE;AACF"}
|
|
1
|
+
{"version":3,"file":"NodeKeyManagementService.mjs","names":[],"sources":["../../src/kms/NodeKeyManagementService.ts"],"sourcesContent":["import { createPrivateKey, createSecretKey, randomBytes, randomUUID } from 'node:crypto'\nimport type { AgentContext } from '@credo-ts/core'\nimport { Kms, TypedArrayEncoder } from '@credo-ts/core'\nimport {\n assertNodeSupportedEcCrv,\n assertNodeSupportedOctAlgorithm,\n assertNodeSupportedOkpCrv,\n createEcKey,\n createOctKey,\n createOkpKey,\n createRsaKey,\n} from './crypto/createKey'\nimport { performDecrypt } from './crypto/decrypt'\nimport { deriveDecryptionKey, encryptEcdh, nodeSupportedKeyAgreementAlgorithms } from './crypto/deriveKey'\nimport { nodeSupportedEncryptionAlgorithms, performEncrypt } from './crypto/encrypt'\nimport { hpkeOpen, hpkeSeal, nodeSupportedHpkeAlgorithms } from './crypto/hpke'\nimport { nodeSupportedJwaAlgorithm, performSign } from './crypto/sign'\nimport { performVerify } from './crypto/verify'\nimport type { NodeKeyManagementStorage } from './NodeKeyManagementStorage'\n\nexport class NodeKeyManagementService implements Kms.KeyManagementService {\n public readonly backend = 'node'\n\n #storage: NodeKeyManagementStorage\n\n public constructor(storage: NodeKeyManagementStorage) {\n this.#storage = storage\n }\n\n public isOperationSupported(_agentContext: AgentContext, operation: Kms.KmsOperation): boolean {\n if (operation.operation === 'deleteKey') return true\n if (operation.operation === 'randomBytes') return true\n\n if (operation.operation === 'createKey') {\n // TODO: probably clean to split the assert methods so we don't need try/catch here\n try {\n if (operation.type.kty === 'RSA') {\n return true\n }\n\n if (operation.type.kty === 'EC') {\n assertNodeSupportedEcCrv(operation.type)\n return true\n }\n\n if (operation.type.kty === 'OKP') {\n assertNodeSupportedOkpCrv(operation.type)\n return true\n }\n\n if (operation.type.kty === 'oct') {\n assertNodeSupportedOctAlgorithm(operation.type)\n return true\n }\n } catch {\n return false\n }\n\n return false\n }\n\n if (operation.operation === 'importKey') {\n try {\n if (operation.privateJwk.kty === 'RSA' || operation.privateJwk.kty === 'oct') {\n return true\n }\n\n if (operation.privateJwk.kty === 'EC') {\n assertNodeSupportedEcCrv({ kty: operation.privateJwk.kty, crv: operation.privateJwk.crv })\n return true\n }\n\n if (operation.privateJwk.kty === 'OKP') {\n assertNodeSupportedOkpCrv({ kty: operation.privateJwk.kty, crv: operation.privateJwk.crv })\n return true\n }\n } catch {\n return false\n }\n }\n\n if (operation.operation === 'sign' || operation.operation === 'verify') {\n return nodeSupportedJwaAlgorithm.includes(operation.algorithm)\n }\n\n if (operation.operation === 'encrypt' || operation.operation === 'decrypt') {\n const encryption = operation.operation === 'encrypt' ? operation.encryption : operation.decryption\n\n // We can only perform key agreement with curves we support. We also can't create the\n // ephemeral key for e.g. ECDH-ES if the curve is not supported.\n if (operation.keyAgreement) {\n const { keyAgreement } = operation\n for (const publicJwk of Kms.keyAgreementPublicJwks(keyAgreement)) {\n try {\n if (publicJwk.kty === 'EC') assertNodeSupportedEcCrv(publicJwk)\n else assertNodeSupportedOkpCrv(publicJwk)\n } catch {\n return false\n }\n\n if (!Kms.supportedKeyDerivationAlgsForKey(publicJwk).includes(keyAgreement.algorithm)) return false\n }\n }\n\n // HPKE is an integrated encryption mode: the suite fixes the AEAD, so the HPKE key agreement\n // algorithm is all there is to check.\n if (encryption.algorithm === 'HPKE') {\n if (!operation.keyAgreement || !Kms.isJwaHpkeAlgorithm(operation.keyAgreement.algorithm)) return false\n\n return nodeSupportedHpkeAlgorithms.includes(\n operation.keyAgreement.algorithm as (typeof nodeSupportedHpkeAlgorithms)[number]\n )\n }\n\n const isSupportedEncryptionAlgorithm = nodeSupportedEncryptionAlgorithms.includes(\n encryption.algorithm as (typeof nodeSupportedEncryptionAlgorithms)[number]\n )\n if (!isSupportedEncryptionAlgorithm) return false\n if (!operation.keyAgreement) return true\n\n return nodeSupportedKeyAgreementAlgorithms.includes(\n operation.keyAgreement.algorithm as (typeof nodeSupportedKeyAgreementAlgorithms)[number]\n )\n }\n\n return false\n }\n\n public randomBytes(_agentContext: AgentContext, options: Kms.KmsRandomBytesOptions): Kms.KmsRandomBytesReturn {\n return new Uint8Array(randomBytes(options.length))\n }\n\n public async getPublicKey(agentContext: AgentContext, keyId: string): Promise<Kms.KmsJwkPublic | null> {\n const privateJwk = await this.#storage.get(agentContext, keyId)\n if (!privateJwk) return null\n\n return Kms.publicJwkFromPrivateJwk(privateJwk)\n }\n\n public async importKey<Jwk extends Kms.KmsJwkPrivate>(\n agentContext: AgentContext,\n options: Kms.KmsImportKeyOptions<Jwk>\n ): Promise<Kms.KmsImportKeyReturn<Jwk>> {\n const { kid } = options.privateJwk\n\n if (kid) await this.assertKeyNotExists(agentContext, kid)\n\n const privateJwk = {\n ...options.privateJwk,\n kid: kid ?? randomUUID(),\n }\n\n try {\n if (privateJwk.kty === 'oct') {\n // Just check if we can create a secret key instance\n createSecretKey(TypedArrayEncoder.fromBase64Url(privateJwk.k)).export({ format: 'jwk' })\n } else if (privateJwk.kty === 'EC') {\n assertNodeSupportedEcCrv({ kty: privateJwk.kty, crv: privateJwk.crv })\n // This validates the JWK\n createPrivateKey({\n format: 'jwk',\n key: privateJwk,\n })\n } else if (privateJwk.kty === 'OKP') {\n assertNodeSupportedOkpCrv({ kty: privateJwk.kty, crv: privateJwk.crv })\n // This validates the JWK\n createPrivateKey({\n format: 'jwk',\n key: privateJwk,\n })\n } else if (privateJwk.kty === 'RSA') {\n // This validates the JWK\n createPrivateKey({\n format: 'jwk',\n key: privateJwk,\n })\n } else {\n // All kty values supported for now, but can change in the future\n // @ts-expect-error\n throw new Kms.KeyManagementAlgorithmNotSupportedError(`kty '${privateJwk.kty}'`, this.backend)\n }\n\n await this.#storage.set(agentContext, privateJwk.kid, privateJwk)\n const publicJwk = Kms.publicJwkFromPrivateJwk(privateJwk)\n\n return {\n keyId: privateJwk.kid,\n publicJwk: {\n ...publicJwk,\n kid: privateJwk.kid,\n },\n } as Kms.KmsImportKeyReturn<Jwk>\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n\n throw new Kms.KeyManagementError('Error importing key', { cause: error })\n }\n }\n\n public async deleteKey(agentContext: AgentContext, options: Kms.KmsDeleteKeyOptions): Promise<boolean> {\n return await this.#storage.delete(agentContext, options.keyId)\n }\n\n public async createKey<Type extends Kms.KmsCreateKeyType>(\n agentContext: AgentContext,\n options: Kms.KmsCreateKeyOptions<Type>\n ): Promise<Kms.KmsCreateKeyReturn<Type>> {\n const { type, keyId } = options\n\n if (keyId) await this.assertKeyNotExists(agentContext, keyId)\n\n try {\n let jwks: { publicJwk: Kms.KmsJwkPublic; privateJwk: Kms.KmsJwkPrivate }\n if (type.kty === 'EC') {\n assertNodeSupportedEcCrv(type)\n jwks = await createEcKey(type)\n } else if (type.kty === 'OKP') {\n assertNodeSupportedOkpCrv(type)\n jwks = await createOkpKey(type)\n } else if (type.kty === 'RSA') {\n jwks = await createRsaKey(type)\n } else if (type.kty === 'oct') {\n assertNodeSupportedOctAlgorithm(type)\n jwks = await createOctKey(type)\n } else {\n // @ts-expect-error\n throw new Kms.KeyManagementAlgorithmNotSupportedError(`kty '${type.kty}'`, this.backend)\n }\n\n jwks.privateJwk.kid = keyId ?? randomUUID()\n jwks.publicJwk.kid = jwks.privateJwk.kid\n\n await this.#storage.set(agentContext, jwks.privateJwk.kid, jwks.privateJwk)\n\n return {\n publicJwk: jwks.publicJwk as Kms.KmsCreateKeyReturn<Type>['publicJwk'],\n keyId: jwks.publicJwk.kid,\n }\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n\n throw new Kms.KeyManagementError('Error creating key', { cause: error })\n }\n }\n\n public async sign(agentContext: AgentContext, options: Kms.KmsSignOptions): Promise<Kms.KmsSignReturn> {\n const { keyId, algorithm, data } = options\n\n // 1. Retrieve the key\n const key = await this.getKeyAsserted(agentContext, keyId)\n\n try {\n // 2. Validate alg and use for key\n Kms.assertAllowedSigningAlgForKey(key, algorithm)\n Kms.assertKeyAllowsSign(key)\n\n // 3. Perform the signing operation\n const signature = await performSign(key, algorithm, data)\n\n return {\n signature: new Uint8Array(signature),\n }\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n\n throw new Kms.KeyManagementError('Error signing with key', { cause: error })\n }\n }\n\n public async verify(agentContext: AgentContext, options: Kms.KmsVerifyOptions): Promise<Kms.KmsVerifyReturn> {\n const { algorithm, data, signature } = options\n\n try {\n let key: Exclude<Kms.KmsJwkPublic, Kms.KmsJwkPublicOct> | Kms.KmsJwkPrivate\n if (options.key.keyId) {\n key = await this.getKeyAsserted(agentContext, options.key.keyId)\n } else if (options.key.publicJwk?.kty === 'EC') {\n assertNodeSupportedEcCrv(options.key.publicJwk)\n key = options.key.publicJwk\n } else if (options.key.publicJwk?.kty === 'OKP') {\n assertNodeSupportedOkpCrv(options.key.publicJwk)\n key = options.key.publicJwk\n } else if (options.key.publicJwk?.kty === 'RSA') {\n key = options.key.publicJwk\n } else {\n // @ts-expect-error\n throw new Kms.KeyManagementAlgorithmNotSupportedError(`kty ${options.key.kty}`, this.backend)\n }\n\n // 2. Validate alg and use for key\n Kms.assertAllowedSigningAlgForKey(key, algorithm)\n Kms.assertKeyAllowsVerify(key)\n\n // 3. Perform the verify operation\n const verified = await performVerify(key, algorithm, data, signature)\n if (verified) {\n return {\n verified: true,\n publicJwk: Kms.publicJwkFromPrivateJwk(key),\n }\n }\n\n return {\n verified: false,\n }\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n\n throw new Kms.KeyManagementError('Error verifying with key', { cause: error })\n }\n }\n\n public async encrypt(agentContext: AgentContext, options: Kms.KmsEncryptOptions): Promise<Kms.KmsEncryptReturn> {\n const { data, encryption, key } = options\n\n if (encryption.algorithm === 'HPKE') {\n if (!key.keyAgreement || !Kms.isKmsKeyAgreementEncryptHpke(key.keyAgreement)) {\n throw new Kms.KeyManagementError(\n `Encryption algorithm 'HPKE' can only be used with an integrated-encryption HPKE key agreement algorithm`\n )\n }\n\n const { keyAgreement } = key\n Kms.assertAllowedKeyDerivationAlgForKey(keyAgreement.externalPublicJwk, keyAgreement.algorithm)\n Kms.assertKeyAllowsDerive(keyAgreement.externalPublicJwk)\n\n try {\n return await hpkeSeal({\n algorithm: keyAgreement.algorithm,\n recipientPublicJwk: keyAgreement.externalPublicJwk,\n data,\n info: keyAgreement.info,\n aad: encryption.aad,\n })\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n throw new Kms.KeyManagementError('Error encrypting', { cause: error })\n }\n }\n\n Kms.assertSupportedEncryptionAlgorithm(encryption, nodeSupportedEncryptionAlgorithms, this.backend)\n const aad = 'aad' in encryption ? encryption.aad : undefined\n\n if (key.keyAgreement) {\n const { keyAgreement } = key\n Kms.assertSupportedKeyAgreementAlgorithm(keyAgreement, nodeSupportedKeyAgreementAlgorithms, this.backend)\n\n const recipientJwks = Kms.keyAgreementPublicJwks(keyAgreement)\n for (const recipientJwk of recipientJwks) {\n Kms.assertAllowedKeyDerivationAlgForKey(recipientJwk, keyAgreement.algorithm)\n Kms.assertKeyAllowsDerive(recipientJwk)\n }\n\n let senderPrivateJwk: Kms.KmsJwkPrivateAsymmetric | undefined\n if (keyAgreement.algorithm === 'ECDH-1PU+A256KW') {\n const privateJwk = await this.getKeyAsserted(agentContext, keyAgreement.keyId)\n Kms.assertJwkAsymmetric(privateJwk, keyAgreement.keyId)\n Kms.assertAllowedKeyDerivationAlgForKey(privateJwk, keyAgreement.algorithm)\n Kms.assertKeyAllowsDerive(privateJwk)\n Kms.assertAsymmetricJwkKeyTypeMatches(privateJwk, recipientJwks[0])\n senderPrivateJwk = privateJwk\n }\n\n const recipientPublicJwk = recipientJwks[0]\n const ephemeral =\n recipientPublicJwk.kty === 'OKP'\n ? await createOkpKey({ kty: 'OKP', crv: 'X25519' })\n : await createEcKey({ kty: 'EC', crv: recipientPublicJwk.crv })\n const ephemeralPublicJwk = ephemeral.publicJwk as Kms.KmsJwkPublicEcdh\n\n // Called outside the try below, so errors from the callback reach the caller as they are\n const contentAad = typeof aad === 'function' ? aad({ ephemeralPublicJwk }) : aad\n if (contentAad !== undefined && !(contentAad instanceof Uint8Array)) {\n throw new Kms.KeyManagementError(`'encryption.aad' callback must return a Uint8Array`)\n }\n\n try {\n const { encrypted, iv, tag, encryptedKeys } = await encryptEcdh({\n keyAgreement,\n encryption,\n aad: contentAad,\n ephemeralPrivateJwk: ephemeral.privateJwk,\n senderPrivateJwk,\n data,\n })\n\n return {\n encrypted: new Uint8Array(encrypted),\n iv: new Uint8Array(iv),\n tag: tag ? new Uint8Array(tag) : undefined,\n ephemeralPublicJwk,\n encryptedKeys,\n }\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n\n throw new Kms.KeyManagementError('Error encrypting', { cause: error })\n }\n }\n\n if (typeof aad === 'function') {\n throw new Kms.KeyManagementError(`'encryption.aad' can only be a callback with ECDH key agreement`)\n }\n\n let encryptionKey: Kms.KmsJwkPrivate\n if (key.keyId) {\n encryptionKey = await this.getKeyAsserted(agentContext, key.keyId)\n } else if (key.privateJwk) {\n encryptionKey = key.privateJwk\n } else {\n throw new Kms.KeyManagementError('Unexpected key parameter for encrypt')\n }\n\n if (encryptionKey.kty !== 'oct') {\n throw new Kms.KeyManagementAlgorithmNotSupportedError(\n `kty '${encryptionKey.kty} for content encryption'`,\n this.backend\n )\n }\n\n try {\n // 2. Validate alg and use for key\n Kms.assertAllowedEncryptionAlgForKey(encryptionKey, encryption.algorithm)\n Kms.assertKeyAllowsEncrypt(encryptionKey)\n\n // 3. Perform the encryption operation\n const { encrypted, iv, tag } = await performEncrypt(encryptionKey, encryption, data, aad)\n return {\n encrypted: new Uint8Array(encrypted),\n iv: new Uint8Array(iv),\n tag: tag ? new Uint8Array(tag) : undefined,\n }\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n\n throw new Kms.KeyManagementError('Error encrypting', { cause: error })\n }\n }\n\n public async decrypt(agentContext: AgentContext, options: Kms.KmsDecryptOptions): Promise<Kms.KmsDecryptReturn> {\n const { decryption, encrypted, key } = options\n\n if (decryption.algorithm === 'HPKE') {\n if (!key.keyAgreement || !Kms.isKmsKeyAgreementDecryptHpke(key.keyAgreement)) {\n throw new Kms.KeyManagementError(\n `Decryption algorithm 'HPKE' can only be used with an integrated-encryption HPKE key agreement algorithm`\n )\n }\n\n const { keyAgreement } = key\n const recipientPrivateJwk = await this.getKeyAsserted(agentContext, keyAgreement.keyId)\n\n Kms.assertJwkAsymmetric(recipientPrivateJwk, keyAgreement.keyId)\n Kms.assertAllowedKeyDerivationAlgForKey(recipientPrivateJwk, keyAgreement.algorithm)\n Kms.assertKeyAllowsDerive(recipientPrivateJwk)\n\n try {\n return {\n data: await hpkeOpen({\n algorithm: keyAgreement.algorithm,\n recipientPrivateJwk,\n encapsulatedKey: keyAgreement.encapsulatedKey,\n encrypted,\n info: keyAgreement.info,\n aad: decryption.aad,\n }),\n }\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n throw new Kms.KeyManagementError('Error decrypting', { cause: error })\n }\n }\n\n Kms.assertSupportedEncryptionAlgorithm(decryption, nodeSupportedEncryptionAlgorithms, this.backend)\n\n let decryptionKey: Kms.KmsJwkPrivate\n if (key.keyId) {\n decryptionKey = await this.getKeyAsserted(agentContext, key.keyId)\n } else if (key.privateJwk) {\n decryptionKey = key.privateJwk\n } else if (key.keyAgreement) {\n Kms.assertSupportedKeyAgreementAlgorithm(key.keyAgreement, nodeSupportedKeyAgreementAlgorithms, this.backend)\n const publicJwks = Kms.keyAgreementPublicJwks(key.keyAgreement)\n for (const publicJwk of publicJwks) {\n Kms.assertAllowedKeyDerivationAlgForKey(publicJwk, key.keyAgreement.algorithm)\n Kms.assertKeyAllowsDerive(publicJwk)\n }\n\n const privateJwk = await this.getKeyAsserted(agentContext, key.keyAgreement.keyId)\n Kms.assertJwkAsymmetric(privateJwk, key.keyAgreement.keyId)\n Kms.assertAllowedKeyDerivationAlgForKey(privateJwk, key.keyAgreement.algorithm)\n Kms.assertKeyAllowsDerive(privateJwk)\n for (const publicJwk of publicJwks) {\n Kms.assertAsymmetricJwkKeyTypeMatches(privateJwk, publicJwk)\n }\n\n const { contentEncryptionKey } = deriveDecryptionKey({\n keyAgreement: key.keyAgreement,\n decryption,\n privateJwk,\n })\n\n decryptionKey = contentEncryptionKey\n } else {\n throw new Kms.KeyManagementError('Unexpected key parameter for decrypt')\n }\n\n if (decryptionKey.kty !== 'oct') {\n throw new Kms.KeyManagementAlgorithmNotSupportedError(\n `kty '${decryptionKey.kty}' for content encryption`,\n this.backend\n )\n }\n\n try {\n // 2. Validate alg and use for key\n Kms.assertAllowedEncryptionAlgForKey(decryptionKey, decryption.algorithm)\n Kms.assertKeyAllowsEncrypt(decryptionKey)\n\n // 3. Perform the decryption operation\n const { data } = await performDecrypt(decryptionKey, decryption, encrypted)\n return { data: new Uint8Array(data) }\n } catch (error) {\n if (error instanceof Kms.KeyManagementError) throw error\n\n throw new Kms.KeyManagementError('Error decrypting', { cause: error })\n }\n }\n\n private async getKeyAsserted(agentContext: AgentContext, keyId: string) {\n const storageKey = await this.#storage.get(agentContext, keyId)\n if (!storageKey) {\n throw new Kms.KeyManagementKeyNotFoundError(keyId, [this.backend])\n }\n\n return storageKey\n }\n\n private async assertKeyNotExists(agentContext: AgentContext, keyId: string) {\n const storageKey = await this.#storage.get(agentContext, keyId)\n\n if (storageKey) {\n throw new Kms.KeyManagementKeyExistsError(keyId, this.backend)\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,101 +1,116 @@
|
|
|
1
|
+
import { performEncrypt } from "./encrypt.mjs";
|
|
1
2
|
import { Kms, TypedArrayEncoder } from "@credo-ts/core";
|
|
2
3
|
import { createCipheriv, createDecipheriv, createHash, createPrivateKey, createPublicKey, diffieHellman, getRandomValues } from "node:crypto";
|
|
3
4
|
import { Buffer } from "node:buffer";
|
|
4
5
|
//#region src/kms/crypto/deriveKey.ts
|
|
5
|
-
const nodeSupportedEcdhKeyDerivationEcCrv = [
|
|
6
|
-
"P-256",
|
|
7
|
-
"P-384",
|
|
8
|
-
"P-521",
|
|
9
|
-
"secp256k1"
|
|
10
|
-
];
|
|
11
6
|
const nodeSupportedKeyAgreementAlgorithms = [
|
|
12
7
|
"ECDH-ES",
|
|
13
8
|
"ECDH-ES+A128KW",
|
|
14
9
|
"ECDH-ES+A192KW",
|
|
15
|
-
"ECDH-ES+A256KW"
|
|
10
|
+
"ECDH-ES+A256KW",
|
|
11
|
+
"ECDH-1PU+A256KW"
|
|
16
12
|
];
|
|
17
|
-
function assertNodeSupportedEcdhKeyDerivationCrv(jwk) {
|
|
18
|
-
if (jwk.kty === "OKP" && jwk.crv !== "X25519" || jwk.kty === "EC" && !nodeSupportedEcdhKeyDerivationEcCrv.includes(jwk.crv)) throw new Kms.KeyManagementAlgorithmNotSupportedError(`key derivation with crv '${jwk.crv}' for kty '${jwk.kty}'`, "node");
|
|
19
|
-
}
|
|
20
13
|
const aesKeyWrapIv = Buffer.from("a6a6a6a6a6a6a6a6", "hex");
|
|
21
|
-
async function
|
|
22
|
-
const { keyAgreement, encryption,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const derivedKeyBytes = await deriveKeyEcdhEs({
|
|
27
|
-
keyLength,
|
|
28
|
-
usageAlgorithm: keyAgreement.algorithm === "ECDH-ES" ? encryption.algorithm : keyAgreement.algorithm,
|
|
29
|
-
privateJwk,
|
|
30
|
-
publicJwk: keyAgreement.externalPublicJwk,
|
|
14
|
+
async function encryptEcdh(options) {
|
|
15
|
+
const { keyAgreement, encryption, aad, ephemeralPrivateJwk, senderPrivateJwk, data } = options;
|
|
16
|
+
const kdfOptions = {
|
|
17
|
+
keyAgreementAlgorithm: keyAgreement.algorithm,
|
|
18
|
+
encryptionAlgorithm: encryption.algorithm,
|
|
31
19
|
apu: keyAgreement.apu,
|
|
32
20
|
apv: keyAgreement.apv
|
|
33
|
-
}
|
|
34
|
-
if (keyAgreement.algorithm === "ECDH-ES")
|
|
21
|
+
};
|
|
22
|
+
if (keyAgreement.algorithm === "ECDH-ES") {
|
|
23
|
+
const contentEncryptionKey = deriveEcdhKey(ecdhSharedSecret(ephemeralPrivateJwk, keyAgreement.externalPublicJwk), kdfOptions);
|
|
24
|
+
return await performEncrypt({
|
|
25
|
+
kty: "oct",
|
|
26
|
+
k: contentEncryptionKey.toString("base64url")
|
|
27
|
+
}, encryption, data, aad);
|
|
28
|
+
}
|
|
29
|
+
const contentEncryptionKey = getRandomValues(new Uint8Array(mapContentEncryptionAlgorithmToKeyLength(encryption.algorithm) >> 3));
|
|
30
|
+
const { encrypted, iv, tag } = await performEncrypt({
|
|
35
31
|
kty: "oct",
|
|
36
|
-
k:
|
|
37
|
-
}
|
|
38
|
-
const
|
|
39
|
-
|
|
32
|
+
k: TypedArrayEncoder.toBase64Url(contentEncryptionKey)
|
|
33
|
+
}, encryption, data, aad);
|
|
34
|
+
const isEcdh1Pu = keyAgreement.algorithm === "ECDH-1PU+A256KW";
|
|
35
|
+
if (isEcdh1Pu && (!senderPrivateJwk || !tag)) throw new Kms.KeyManagementError(`Expected a sender key and an authentication tag for 'ECDH-1PU+A256KW'`);
|
|
40
36
|
return {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
37
|
+
encrypted,
|
|
38
|
+
iv,
|
|
39
|
+
tag,
|
|
40
|
+
encryptedKeys: keyAgreement.recipients.map(({ externalPublicJwk }) => {
|
|
41
|
+
return { encrypted: aesKeyWrap(deriveEcdhKey(Buffer.concat([ecdhSharedSecret(ephemeralPrivateJwk, externalPublicJwk), ...isEcdh1Pu && senderPrivateJwk ? [ecdhSharedSecret(senderPrivateJwk, externalPublicJwk)] : []]), {
|
|
42
|
+
...kdfOptions,
|
|
43
|
+
ccTag: isEcdh1Pu ? tag : void 0
|
|
44
|
+
}), contentEncryptionKey) };
|
|
45
|
+
})
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
-
|
|
48
|
+
function deriveDecryptionKey(options) {
|
|
49
49
|
const { keyAgreement, decryption, privateJwk } = options;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
keyLength,
|
|
55
|
-
usageAlgorithm: keyAgreement.algorithm === "ECDH-ES" ? decryption.algorithm : keyAgreement.algorithm,
|
|
56
|
-
privateJwk,
|
|
57
|
-
publicJwk: keyAgreement.externalPublicJwk,
|
|
50
|
+
const isEcdh1Pu = keyAgreement.algorithm === "ECDH-1PU+A256KW";
|
|
51
|
+
const derivedKey = deriveEcdhKey(Buffer.concat([ecdhSharedSecret(privateJwk, keyAgreement.ephemeralPublicJwk), ...isEcdh1Pu ? [ecdhSharedSecret(privateJwk, keyAgreement.senderPublicJwk)] : []]), {
|
|
52
|
+
keyAgreementAlgorithm: keyAgreement.algorithm,
|
|
53
|
+
encryptionAlgorithm: decryption.algorithm,
|
|
58
54
|
apu: keyAgreement.apu,
|
|
59
|
-
apv: keyAgreement.apv
|
|
55
|
+
apv: keyAgreement.apv,
|
|
56
|
+
ccTag: isEcdh1Pu && "tag" in decryption ? decryption.tag : void 0
|
|
60
57
|
});
|
|
61
|
-
if (keyAgreement.algorithm === "ECDH-ES") return { contentEncryptionKey: {
|
|
62
|
-
kty: "oct",
|
|
63
|
-
k: derivedKeyBytes.toString("base64url")
|
|
64
|
-
} };
|
|
65
|
-
const decipher = createDecipheriv(`id-aes${keyLength}-wrap`, derivedKeyBytes, aesKeyWrapIv);
|
|
66
58
|
return { contentEncryptionKey: {
|
|
67
59
|
kty: "oct",
|
|
68
|
-
k:
|
|
60
|
+
k: (keyAgreement.algorithm === "ECDH-ES" ? derivedKey : aesKeyUnwrap(derivedKey, keyAgreement.encryptedKey.encrypted)).toString("base64url")
|
|
69
61
|
} };
|
|
70
62
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
*/
|
|
74
|
-
async function deriveKeyEcdhEs(options) {
|
|
75
|
-
const sharedSecret = diffieHellman({
|
|
63
|
+
function ecdhSharedSecret(privateJwk, publicJwk) {
|
|
64
|
+
return diffieHellman({
|
|
76
65
|
privateKey: createPrivateKey({
|
|
77
66
|
format: "jwk",
|
|
78
|
-
key:
|
|
67
|
+
key: privateJwk
|
|
79
68
|
}),
|
|
80
69
|
publicKey: createPublicKey({
|
|
81
70
|
format: "jwk",
|
|
82
|
-
key:
|
|
71
|
+
key: publicJwk
|
|
83
72
|
})
|
|
84
73
|
});
|
|
85
|
-
|
|
74
|
+
}
|
|
75
|
+
function aesKeyWrap(keyEncryptionKey, contentEncryptionKey) {
|
|
76
|
+
const cipher = createCipheriv(`id-aes${keyEncryptionKey.length * 8}-wrap`, keyEncryptionKey, aesKeyWrapIv);
|
|
77
|
+
return new Uint8Array(Buffer.concat([cipher.update(contentEncryptionKey), cipher.final()]));
|
|
78
|
+
}
|
|
79
|
+
function aesKeyUnwrap(keyEncryptionKey, encryptedContentEncryptionKey) {
|
|
80
|
+
try {
|
|
81
|
+
const decipher = createDecipheriv(`id-aes${keyEncryptionKey.length * 8}-wrap`, keyEncryptionKey, aesKeyWrapIv);
|
|
82
|
+
return Buffer.concat([decipher.update(encryptedContentEncryptionKey), decipher.final()]);
|
|
83
|
+
} catch (error) {
|
|
84
|
+
throw new Kms.KeyManagementError("Error unwrapping content encryption key", { cause: error });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function deriveEcdhKey(sharedSecret, options) {
|
|
88
|
+
const { keyAgreementAlgorithm, encryptionAlgorithm } = options;
|
|
89
|
+
const keyLength = keyAgreementAlgorithm === "ECDH-ES" ? mapContentEncryptionAlgorithmToKeyLength(encryptionAlgorithm) : keyAgreementAlgorithm === "ECDH-ES+A128KW" ? 128 : keyAgreementAlgorithm === "ECDH-ES+A192KW" ? 192 : 256;
|
|
90
|
+
return concatKDF(sharedSecret, keyLength, concatKdfOtherInfo({
|
|
91
|
+
algorithm: keyAgreementAlgorithm === "ECDH-ES" ? encryptionAlgorithm : keyAgreementAlgorithm,
|
|
92
|
+
keyLength,
|
|
93
|
+
apu: options.apu,
|
|
94
|
+
apv: options.apv,
|
|
95
|
+
ccTag: options.ccTag
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
function concatKdfOtherInfo(options) {
|
|
99
|
+
const algorithmData = TypedArrayEncoder.fromUtf8String(options.algorithm);
|
|
86
100
|
const algorithmID = TypedArrayEncoder.concat([numberTo4ByteUint8Array(algorithmData.length), algorithmData]);
|
|
87
101
|
const apu = options.apu || Buffer.alloc(0);
|
|
88
102
|
const partyUInfo = Buffer.concat([numberTo4ByteUint8Array(apu.length), apu]);
|
|
89
103
|
const apv = options.apv || Buffer.alloc(0);
|
|
90
104
|
const partyVInfo = Buffer.concat([numberTo4ByteUint8Array(apv.length), apv]);
|
|
91
|
-
const
|
|
105
|
+
const ccTag = options.ccTag ? [numberTo4ByteUint8Array(options.ccTag.length), options.ccTag] : [];
|
|
106
|
+
return Buffer.concat([
|
|
92
107
|
algorithmID,
|
|
93
108
|
partyUInfo,
|
|
94
109
|
partyVInfo,
|
|
95
110
|
numberTo4ByteUint8Array(options.keyLength),
|
|
111
|
+
...ccTag,
|
|
96
112
|
Buffer.alloc(0)
|
|
97
113
|
]);
|
|
98
|
-
return concatKDF(sharedSecret, options.keyLength, otherInfo);
|
|
99
114
|
}
|
|
100
115
|
function numberTo4ByteUint8Array(number) {
|
|
101
116
|
const buffer = /* @__PURE__ */ new ArrayBuffer(4);
|
|
@@ -137,6 +152,6 @@ function mapContentEncryptionAlgorithmToKeyLength(encryptionAlgorithm) {
|
|
|
137
152
|
}
|
|
138
153
|
}
|
|
139
154
|
//#endregion
|
|
140
|
-
export { deriveDecryptionKey,
|
|
155
|
+
export { deriveDecryptionKey, encryptEcdh, nodeSupportedKeyAgreementAlgorithms };
|
|
141
156
|
|
|
142
157
|
//# sourceMappingURL=deriveKey.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deriveKey.mjs","names":[],"sources":["../../../src/kms/crypto/deriveKey.ts"],"sourcesContent":["import { Buffer } from 'node:buffer'\nimport {\n createCipheriv,\n createDecipheriv,\n createHash,\n createPrivateKey,\n createPublicKey,\n diffieHellman,\n getRandomValues,\n} from 'node:crypto'\nimport { Kms, TypedArrayEncoder } from '@credo-ts/core'\nimport type { NodeKmsSupportedEcCrvs } from './createKey'\n\nconst nodeSupportedEcdhKeyDerivationEcCrv = [\n 'P-256',\n 'P-384',\n 'P-521',\n 'secp256k1',\n] as const satisfies NodeKmsSupportedEcCrvs[]\n\nexport const nodeSupportedKeyAgreementAlgorithms = [\n 'ECDH-ES',\n 'ECDH-ES+A128KW',\n 'ECDH-ES+A192KW',\n 'ECDH-ES+A256KW',\n] satisfies Kms.KnownJwaKeyAgreementAlgorithm[]\n\nfunction assertNodeSupportedEcdhKeyDerivationCrv<Jwk extends Kms.KmsJwkPrivateAsymmetric | Kms.KmsJwkPublicAsymmetric>(\n jwk: Jwk\n): asserts jwk is Jwk & { kty: 'OKP' | 'EC'; crv: (typeof nodeSupportedEcdhKeyDerivationEcCrv)[number] | 'X25519' } {\n if (\n (jwk.kty === 'OKP' && jwk.crv !== 'X25519') ||\n (jwk.kty === 'EC' && !(nodeSupportedEcdhKeyDerivationEcCrv as string[]).includes(jwk.crv))\n ) {\n throw new Kms.KeyManagementAlgorithmNotSupportedError(\n `key derivation with crv '${jwk.crv}' for kty '${jwk.kty}'`,\n 'node'\n )\n }\n}\n\ntype NodeSupportedKeyAgreementDecryptOptions = Kms.KmsKeyAgreementDecryptOptions & {\n algorithm: (typeof nodeSupportedKeyAgreementAlgorithms)[number]\n}\ntype NodeSupportedKeyAgreementEncryptOptions = Kms.KmsKeyAgreementEncryptOptions & {\n algorithm: (typeof nodeSupportedKeyAgreementAlgorithms)[number]\n}\n\n// Default IV from RFC 3394 section 2.2.3.1\nconst aesKeyWrapIv = Buffer.from('a6a6a6a6a6a6a6a6', 'hex')\n\nexport async function deriveEncryptionKey(options: {\n keyAgreement: NodeSupportedKeyAgreementEncryptOptions\n privateJwk: Kms.KmsJwkPrivateAsymmetric\n encryption: Kms.KmsEncryptDataContentEncryption\n}) {\n const { keyAgreement, encryption, privateJwk } = options\n\n assertNodeSupportedEcdhKeyDerivationCrv(keyAgreement.externalPublicJwk)\n assertNodeSupportedEcdhKeyDerivationCrv(privateJwk)\n\n const keyLength =\n keyAgreement.algorithm === 'ECDH-ES'\n ? mapContentEncryptionAlgorithmToKeyLength(encryption.algorithm)\n : keyAgreement.algorithm === 'ECDH-ES+A128KW'\n ? 128\n : keyAgreement.algorithm === 'ECDH-ES+A192KW'\n ? 192\n : 256\n\n const derivedKeyBytes = await deriveKeyEcdhEs({\n keyLength,\n usageAlgorithm: keyAgreement.algorithm === 'ECDH-ES' ? encryption.algorithm : keyAgreement.algorithm,\n privateJwk,\n publicJwk: keyAgreement.externalPublicJwk,\n apu: keyAgreement.apu,\n apv: keyAgreement.apv,\n })\n\n if (keyAgreement.algorithm === 'ECDH-ES') {\n return {\n // TODO: will be more efficient to return node key instance\n contentEncryptionKey: {\n kty: 'oct',\n k: derivedKeyBytes.toString('base64url'),\n } as const,\n }\n }\n\n // Key wrapping\n const contentEncryptionKeyBytes = getRandomValues(\n new Uint8Array(mapContentEncryptionAlgorithmToKeyLength(encryption.algorithm) >> 3)\n )\n const cipher = createCipheriv(`id-aes${keyLength}-wrap`, derivedKeyBytes, aesKeyWrapIv)\n\n return {\n encryptedContentEncryptionKey: {\n encrypted: new Uint8Array(Buffer.concat([cipher.update(contentEncryptionKeyBytes), cipher.final()])),\n } satisfies Kms.KmsEncryptedKey,\n contentEncryptionKey: {\n kty: 'oct',\n k: TypedArrayEncoder.toBase64Url(contentEncryptionKeyBytes),\n } as const,\n }\n}\n\nexport async function deriveDecryptionKey(options: {\n keyAgreement: NodeSupportedKeyAgreementDecryptOptions\n privateJwk: Kms.KmsJwkPrivateAsymmetric\n decryption: Kms.KmsDecryptDataContentDecryption\n}) {\n const { keyAgreement, decryption, privateJwk } = options\n\n assertNodeSupportedEcdhKeyDerivationCrv(keyAgreement.externalPublicJwk)\n assertNodeSupportedEcdhKeyDerivationCrv(privateJwk)\n\n const keyLength =\n keyAgreement.algorithm === 'ECDH-ES'\n ? mapContentEncryptionAlgorithmToKeyLength(decryption.algorithm)\n : keyAgreement.algorithm === 'ECDH-ES+A128KW'\n ? 128\n : keyAgreement.algorithm === 'ECDH-ES+A192KW'\n ? 192\n : 256\n\n const derivedKeyBytes = await deriveKeyEcdhEs({\n keyLength,\n usageAlgorithm: keyAgreement.algorithm === 'ECDH-ES' ? decryption.algorithm : keyAgreement.algorithm,\n privateJwk: privateJwk,\n publicJwk: keyAgreement.externalPublicJwk,\n apu: keyAgreement.apu,\n apv: keyAgreement.apv,\n })\n\n if (keyAgreement.algorithm === 'ECDH-ES') {\n return {\n // TODO: will be more efficient to return node key instance\n contentEncryptionKey: {\n kty: 'oct',\n k: derivedKeyBytes.toString('base64url'),\n } as const,\n }\n }\n\n // Key wrapping\n const decipher = createDecipheriv(`id-aes${keyLength}-wrap`, derivedKeyBytes, aesKeyWrapIv)\n const contentEncryptionKeyBytes = Buffer.concat([\n decipher.update(keyAgreement.encryptedKey.encrypted),\n decipher.final(),\n ])\n\n return {\n contentEncryptionKey: {\n kty: 'oct',\n k: contentEncryptionKeyBytes.toString('base64url'),\n } as const,\n }\n}\n\n/**\n * Derive a key using ECDH and Concat KDF\n */\nasync function deriveKeyEcdhEs(options: {\n keyLength: number\n /**\n * This is only used for the AlgorithmID in KDF\n */\n usageAlgorithm: string\n apv?: Uint8Array\n apu?: Uint8Array\n privateJwk: Kms.KmsJwkPrivateEc | Kms.KmsJwkPrivateOkp\n publicJwk: Kms.KmsJwkPublicEc | Kms.KmsJwkPublicOkp\n}): Promise<Buffer> {\n const sharedSecret = diffieHellman({\n privateKey: createPrivateKey({ format: 'jwk', key: options.privateJwk }),\n publicKey: createPublicKey({ format: 'jwk', key: options.publicJwk }),\n })\n\n // Prepare AlgorithmID for KDF (Datalen || Data)\n const algorithmData = TypedArrayEncoder.fromUtf8String(options.usageAlgorithm) // ASCII representation of alg\n const algorithmID = TypedArrayEncoder.concat([\n numberTo4ByteUint8Array(algorithmData.length), // Datalen: 32-bit big-endian counter\n algorithmData, // Data: ASCII representation of algorithm\n ])\n\n // Prepare PartyUInfo with proper length prefix\n const apu = options.apu || Buffer.alloc(0)\n const partyUInfo = Buffer.concat([\n numberTo4ByteUint8Array(apu.length), // Datalen: 32-bit big-endian counter\n apu, // Data: PartyUInfo value\n ])\n\n // Prepare PartyVInfo with proper length prefix\n const apv = options.apv || Buffer.alloc(0)\n const partyVInfo = Buffer.concat([\n numberTo4ByteUint8Array(apv.length), // Datalen: 32-bit big-endian counter\n apv, // Data: PartyVInfo value\n ])\n\n // Prepare otherInfo for KDF\n const otherInfo = Buffer.concat([\n algorithmID, // AlgorithmID: Datalen || Data\n partyUInfo, // PartyUInfo: Datalen || Data\n partyVInfo, // PartyVInfo: Datalen || Data\n numberTo4ByteUint8Array(options.keyLength), // SuppPubInfo: 32-bit big-endian rep of keydatalen\n Buffer.alloc(0), // SuppPrivInfo (empty octet sequence)\n ])\n\n // Derive final key using Concat KDF\n return concatKDF(sharedSecret, options.keyLength, otherInfo)\n}\n\nfunction numberTo4ByteUint8Array(number: number) {\n const buffer = new ArrayBuffer(4)\n const view = new DataView(buffer)\n view.setUint32(0, number)\n return new Uint8Array(buffer)\n}\n\n/**\n * Implements Concat KDF as per NIST SP 800-56A, with SHA-256 for every curve (RFC 7518 section 4.6.2)\n */\nfunction concatKDF(secret: Buffer, length: number, otherInfo: Buffer): Buffer {\n const hashLength = 256\n const reps = Math.ceil((length >> 3) / (hashLength >> 3))\n const output = Buffer.alloc(reps * (hashLength >> 3))\n\n for (let i = 0; i < reps; i++) {\n const counter = Buffer.alloc(4 + secret.length + otherInfo.length)\n counter.writeUInt32BE(i + 1)\n counter.set(secret, 4)\n counter.set(otherInfo, 4 + secret.length)\n\n createHash(`sha${hashLength}`)\n .update(counter)\n .digest()\n .copy(output, (i * hashLength) >> 3)\n }\n\n return output.subarray(0, length >> 3)\n}\n\n// TODO: might be worthwhile to add this to core?\n// TODO: we might want to have a separate definition per algorithm\n// defines things such as required key length.\nfunction mapContentEncryptionAlgorithmToKeyLength(\n encryptionAlgorithm: Kms.KnownJwaContentEncryptionAlgorithm | Kms.KnownJwaKeyEncryptionAlgorithm\n): number {\n switch (encryptionAlgorithm) {\n case 'A128CBC':\n case 'A128GCM':\n case 'A128KW':\n return 128\n case 'A192GCM':\n case 'A192KW':\n return 192\n case 'A128CBC-HS256':\n case 'A256CBC':\n case 'A256GCM':\n case 'C20P':\n case 'XC20P':\n case 'A256KW':\n return 256\n\n case 'A192CBC-HS384':\n return 384\n case 'A256CBC-HS512':\n return 512\n case 'XSALSA20-POLY1305':\n return 256\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"deriveKey.mjs","names":[],"sources":["../../../src/kms/crypto/deriveKey.ts"],"sourcesContent":["import { Buffer } from 'node:buffer'\nimport {\n createCipheriv,\n createDecipheriv,\n createHash,\n createPrivateKey,\n createPublicKey,\n diffieHellman,\n getRandomValues,\n} from 'node:crypto'\nimport { Kms, TypedArrayEncoder } from '@credo-ts/core'\nimport { performEncrypt } from './encrypt'\n\nexport const nodeSupportedKeyAgreementAlgorithms = [\n 'ECDH-ES',\n 'ECDH-ES+A128KW',\n 'ECDH-ES+A192KW',\n 'ECDH-ES+A256KW',\n 'ECDH-1PU+A256KW',\n] satisfies Kms.KnownJwaKeyAgreementAlgorithm[]\n\ntype NodeSupportedKeyAgreementDecryptOptions = Kms.KmsKeyAgreementDecryptOptions & {\n algorithm: (typeof nodeSupportedKeyAgreementAlgorithms)[number]\n}\ntype NodeSupportedKeyAgreementEncryptOptions = Kms.KmsKeyAgreementEncryptOptions & {\n algorithm: (typeof nodeSupportedKeyAgreementAlgorithms)[number]\n}\n\n// Default IV from RFC 3394 section 2.2.3.1\nconst aesKeyWrapIv = Buffer.from('a6a6a6a6a6a6a6a6', 'hex')\n\nexport async function encryptEcdh(options: {\n keyAgreement: NodeSupportedKeyAgreementEncryptOptions\n encryption: Kms.KmsEncryptDataContentEncryption\n aad?: Uint8Array\n ephemeralPrivateJwk: Kms.KmsJwkPrivateAsymmetric\n senderPrivateJwk?: Kms.KmsJwkPrivateAsymmetric\n data: Uint8Array\n}): Promise<{ encrypted: Uint8Array; iv: Uint8Array; tag?: Uint8Array; encryptedKeys?: Kms.KmsEncryptedKey[] }> {\n const { keyAgreement, encryption, aad, ephemeralPrivateJwk, senderPrivateJwk, data } = options\n const kdfOptions = {\n keyAgreementAlgorithm: keyAgreement.algorithm,\n encryptionAlgorithm: encryption.algorithm,\n apu: keyAgreement.apu,\n apv: keyAgreement.apv,\n }\n\n if (keyAgreement.algorithm === 'ECDH-ES') {\n const contentEncryptionKey = deriveEcdhKey(\n ecdhSharedSecret(ephemeralPrivateJwk, keyAgreement.externalPublicJwk),\n kdfOptions\n )\n return await performEncrypt({ kty: 'oct', k: contentEncryptionKey.toString('base64url') }, encryption, data, aad)\n }\n\n const contentEncryptionKey = getRandomValues(\n new Uint8Array(mapContentEncryptionAlgorithmToKeyLength(encryption.algorithm) >> 3)\n )\n // Encrypt before wrapping, since ECDH-1PU puts the authentication tag into the key derivation\n const { encrypted, iv, tag } = await performEncrypt(\n { kty: 'oct', k: TypedArrayEncoder.toBase64Url(contentEncryptionKey) },\n encryption,\n data,\n aad\n )\n\n const isEcdh1Pu = keyAgreement.algorithm === 'ECDH-1PU+A256KW'\n if (isEcdh1Pu && (!senderPrivateJwk || !tag)) {\n throw new Kms.KeyManagementError(`Expected a sender key and an authentication tag for 'ECDH-1PU+A256KW'`)\n }\n\n const encryptedKeys = keyAgreement.recipients.map(({ externalPublicJwk }) => {\n const sharedSecret = Buffer.concat([\n ecdhSharedSecret(ephemeralPrivateJwk, externalPublicJwk),\n ...(isEcdh1Pu && senderPrivateJwk ? [ecdhSharedSecret(senderPrivateJwk, externalPublicJwk)] : []),\n ])\n const keyEncryptionKey = deriveEcdhKey(sharedSecret, { ...kdfOptions, ccTag: isEcdh1Pu ? tag : undefined })\n\n return { encrypted: aesKeyWrap(keyEncryptionKey, contentEncryptionKey) }\n })\n\n return { encrypted, iv, tag, encryptedKeys }\n}\n\nexport function deriveDecryptionKey(options: {\n keyAgreement: NodeSupportedKeyAgreementDecryptOptions\n privateJwk: Kms.KmsJwkPrivateAsymmetric\n decryption: Kms.KmsDecryptDataContentDecryption\n}): { contentEncryptionKey: Kms.KmsJwkPrivateOct } {\n const { keyAgreement, decryption, privateJwk } = options\n\n const isEcdh1Pu = keyAgreement.algorithm === 'ECDH-1PU+A256KW'\n const sharedSecret = Buffer.concat([\n ecdhSharedSecret(privateJwk, keyAgreement.ephemeralPublicJwk),\n ...(isEcdh1Pu ? [ecdhSharedSecret(privateJwk, keyAgreement.senderPublicJwk)] : []),\n ])\n const derivedKey = deriveEcdhKey(sharedSecret, {\n keyAgreementAlgorithm: keyAgreement.algorithm,\n encryptionAlgorithm: decryption.algorithm,\n apu: keyAgreement.apu,\n apv: keyAgreement.apv,\n ccTag: isEcdh1Pu && 'tag' in decryption ? decryption.tag : undefined,\n })\n\n const contentEncryptionKey =\n keyAgreement.algorithm === 'ECDH-ES' ? derivedKey : aesKeyUnwrap(derivedKey, keyAgreement.encryptedKey.encrypted)\n\n return { contentEncryptionKey: { kty: 'oct', k: contentEncryptionKey.toString('base64url') } }\n}\n\nfunction ecdhSharedSecret(privateJwk: Kms.KmsJwkPrivateAsymmetric, publicJwk: Kms.KmsJwkPublicAsymmetric): Buffer {\n return diffieHellman({\n privateKey: createPrivateKey({ format: 'jwk', key: privateJwk }),\n publicKey: createPublicKey({ format: 'jwk', key: publicJwk }),\n })\n}\n\nfunction aesKeyWrap(keyEncryptionKey: Uint8Array, contentEncryptionKey: Uint8Array): Uint8Array {\n const cipher = createCipheriv(`id-aes${keyEncryptionKey.length * 8}-wrap`, keyEncryptionKey, aesKeyWrapIv)\n return new Uint8Array(Buffer.concat([cipher.update(contentEncryptionKey), cipher.final()]))\n}\n\nfunction aesKeyUnwrap(keyEncryptionKey: Uint8Array, encryptedContentEncryptionKey: Uint8Array): Buffer {\n try {\n const decipher = createDecipheriv(`id-aes${keyEncryptionKey.length * 8}-wrap`, keyEncryptionKey, aesKeyWrapIv)\n return Buffer.concat([decipher.update(encryptedContentEncryptionKey), decipher.final()])\n } catch (error) {\n throw new Kms.KeyManagementError('Error unwrapping content encryption key', { cause: error })\n }\n}\n\nfunction deriveEcdhKey(\n sharedSecret: Buffer,\n options: {\n keyAgreementAlgorithm: (typeof nodeSupportedKeyAgreementAlgorithms)[number]\n encryptionAlgorithm: Kms.KnownJwaContentEncryptionAlgorithm\n apu?: Uint8Array\n apv?: Uint8Array\n ccTag?: Uint8Array\n }\n): Buffer {\n const { keyAgreementAlgorithm, encryptionAlgorithm } = options\n const keyLength =\n keyAgreementAlgorithm === 'ECDH-ES'\n ? mapContentEncryptionAlgorithmToKeyLength(encryptionAlgorithm)\n : keyAgreementAlgorithm === 'ECDH-ES+A128KW'\n ? 128\n : keyAgreementAlgorithm === 'ECDH-ES+A192KW'\n ? 192\n : 256\n\n return concatKDF(\n sharedSecret,\n keyLength,\n concatKdfOtherInfo({\n algorithm: keyAgreementAlgorithm === 'ECDH-ES' ? encryptionAlgorithm : keyAgreementAlgorithm,\n keyLength,\n apu: options.apu,\n apv: options.apv,\n ccTag: options.ccTag,\n })\n )\n}\n\nfunction concatKdfOtherInfo(options: {\n algorithm: string\n keyLength: number\n apu?: Uint8Array\n apv?: Uint8Array\n ccTag?: Uint8Array\n}): Buffer {\n // Prepare AlgorithmID for KDF (Datalen || Data)\n const algorithmData = TypedArrayEncoder.fromUtf8String(options.algorithm) // ASCII representation of alg\n const algorithmID = TypedArrayEncoder.concat([\n numberTo4ByteUint8Array(algorithmData.length), // Datalen: 32-bit big-endian counter\n algorithmData, // Data: ASCII representation of algorithm\n ])\n\n // Prepare PartyUInfo with proper length prefix\n const apu = options.apu || Buffer.alloc(0)\n const partyUInfo = Buffer.concat([\n numberTo4ByteUint8Array(apu.length), // Datalen: 32-bit big-endian counter\n apu, // Data: PartyUInfo value\n ])\n\n // Prepare PartyVInfo with proper length prefix\n const apv = options.apv || Buffer.alloc(0)\n const partyVInfo = Buffer.concat([\n numberTo4ByteUint8Array(apv.length), // Datalen: 32-bit big-endian counter\n apv, // Data: PartyVInfo value\n ])\n\n // ECDH-1PU key wrapping appends Datalen || tag to SuppPubInfo (draft-madden-jose-ecdh-1pu-04 section 2.3)\n const ccTag = options.ccTag ? [numberTo4ByteUint8Array(options.ccTag.length), options.ccTag] : []\n\n return Buffer.concat([\n algorithmID, // AlgorithmID: Datalen || Data\n partyUInfo, // PartyUInfo: Datalen || Data\n partyVInfo, // PartyVInfo: Datalen || Data\n numberTo4ByteUint8Array(options.keyLength), // SuppPubInfo: 32-bit big-endian rep of keydatalen\n ...ccTag,\n Buffer.alloc(0), // SuppPrivInfo (empty octet sequence)\n ])\n}\n\nfunction numberTo4ByteUint8Array(number: number) {\n const buffer = new ArrayBuffer(4)\n const view = new DataView(buffer)\n view.setUint32(0, number)\n return new Uint8Array(buffer)\n}\n\n/**\n * Implements Concat KDF as per NIST SP 800-56A, with SHA-256 for every curve (RFC 7518 section 4.6.2)\n */\nfunction concatKDF(secret: Buffer, length: number, otherInfo: Buffer): Buffer {\n const hashLength = 256\n const reps = Math.ceil((length >> 3) / (hashLength >> 3))\n const output = Buffer.alloc(reps * (hashLength >> 3))\n\n for (let i = 0; i < reps; i++) {\n const counter = Buffer.alloc(4 + secret.length + otherInfo.length)\n counter.writeUInt32BE(i + 1)\n counter.set(secret, 4)\n counter.set(otherInfo, 4 + secret.length)\n\n createHash(`sha${hashLength}`)\n .update(counter)\n .digest()\n .copy(output, (i * hashLength) >> 3)\n }\n\n return output.subarray(0, length >> 3)\n}\n\n// TODO: might be worthwhile to add this to core?\n// TODO: we might want to have a separate definition per algorithm\n// defines things such as required key length.\nfunction mapContentEncryptionAlgorithmToKeyLength(\n encryptionAlgorithm: Kms.KnownJwaContentEncryptionAlgorithm | Kms.KnownJwaKeyEncryptionAlgorithm\n): number {\n switch (encryptionAlgorithm) {\n case 'A128CBC':\n case 'A128GCM':\n case 'A128KW':\n return 128\n case 'A192GCM':\n case 'A192KW':\n return 192\n case 'A128CBC-HS256':\n case 'A256CBC':\n case 'A256GCM':\n case 'C20P':\n case 'XC20P':\n case 'A256KW':\n return 256\n\n case 'A192CBC-HS384':\n return 384\n case 'A256CBC-HS512':\n return 512\n case 'XSALSA20-POLY1305':\n return 256\n }\n}\n"],"mappings":"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"}
|
|
@@ -14,7 +14,7 @@ const nodeSupportedEncryptionAlgorithms = [
|
|
|
14
14
|
"A256GCM",
|
|
15
15
|
"C20P"
|
|
16
16
|
];
|
|
17
|
-
async function performEncrypt(key, dataEncryption, data) {
|
|
17
|
+
async function performEncrypt(key, dataEncryption, data, aad) {
|
|
18
18
|
const secretKeyBytes = TypedArrayEncoder.fromBase64Url(key.k);
|
|
19
19
|
const nodeKey = createSecretKey(secretKeyBytes);
|
|
20
20
|
if (dataEncryption.algorithm === "A128CBC" || dataEncryption.algorithm === "A256CBC") {
|
|
@@ -50,10 +50,10 @@ async function performEncrypt(key, dataEncryption, data) {
|
|
|
50
50
|
const cipher = createCipheriv(algSettings.cbcAlg, encKey, iv);
|
|
51
51
|
const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
|
|
52
52
|
const al = Buffer.alloc(8);
|
|
53
|
-
const aadLength =
|
|
53
|
+
const aadLength = aad ? aad.length * 8 : 0;
|
|
54
54
|
al.writeBigUInt64BE(BigInt(aadLength));
|
|
55
55
|
const macData = Buffer.concat([
|
|
56
|
-
|
|
56
|
+
aad ?? Buffer.alloc(0),
|
|
57
57
|
iv,
|
|
58
58
|
encrypted,
|
|
59
59
|
al
|
|
@@ -71,7 +71,7 @@ async function performEncrypt(key, dataEncryption, data) {
|
|
|
71
71
|
const nodeAlgorithm = dataEncryption.algorithm === "A128GCM" ? "aes-128-gcm" : dataEncryption.algorithm === "A192GCM" ? "aes-192-gcm" : "aes-256-gcm";
|
|
72
72
|
const iv = dataEncryption.iv ?? randomBytes(12);
|
|
73
73
|
const cipher = createCipheriv(nodeAlgorithm, nodeKey, iv);
|
|
74
|
-
if (
|
|
74
|
+
if (aad) cipher.setAAD(aad);
|
|
75
75
|
return {
|
|
76
76
|
encrypted: Buffer.concat([cipher.update(data), cipher.final()]),
|
|
77
77
|
tag: cipher.getAuthTag(),
|
|
@@ -81,7 +81,7 @@ async function performEncrypt(key, dataEncryption, data) {
|
|
|
81
81
|
if (dataEncryption.algorithm === "C20P") {
|
|
82
82
|
const iv = dataEncryption.iv ?? randomBytes(12);
|
|
83
83
|
const cipher = createCipheriv("chacha20-poly1305", nodeKey, iv, { authTagLength: 16 });
|
|
84
|
-
if (
|
|
84
|
+
if (aad) cipher.setAAD(aad);
|
|
85
85
|
return {
|
|
86
86
|
encrypted: Buffer.concat([cipher.update(data), cipher.final()]),
|
|
87
87
|
tag: cipher.getAuthTag(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encrypt.mjs","names":[],"sources":["../../../src/kms/crypto/encrypt.ts"],"sourcesContent":["import { Buffer } from 'node:buffer'\nimport type { CipherGCM } from 'node:crypto'\nimport { createCipheriv, createSecretKey, randomBytes } from 'node:crypto'\nimport { Kms, TypedArrayEncoder } from '@credo-ts/core'\nimport { performSign } from './sign'\n\nexport const nodeSupportedEncryptionAlgorithms = [\n 'A128CBC',\n 'A256CBC',\n 'A128CBC-HS256',\n 'A192CBC-HS384',\n 'A256CBC-HS512',\n 'A128GCM',\n 'A192GCM',\n 'A256GCM',\n 'C20P',\n] as const satisfies Kms.KnownJwaContentEncryptionAlgorithm[]\n\nexport async function performEncrypt(\n key: Kms.KmsJwkPrivateOct,\n dataEncryption: Kms.KmsEncryptDataContentEncryption,\n data: Uint8Array\n): Promise<{ encrypted: Uint8Array; tag?: Uint8Array; iv: Uint8Array }> {\n const secretKeyBytes = TypedArrayEncoder.fromBase64Url(key.k)\n const nodeKey = createSecretKey(secretKeyBytes)\n\n // Create cipher with key and IV\n if (dataEncryption.algorithm === 'A128CBC' || dataEncryption.algorithm === 'A256CBC') {\n const nodeAlgorithm = dataEncryption.algorithm === 'A128CBC' ? 'aes-128-cbc' : 'aes-256-cbc'\n\n // IV should be exactly 16 bytes (128 bits) for CBC mode\n const iv = dataEncryption.iv ?? randomBytes(16)\n\n const cipher = createCipheriv(nodeAlgorithm, nodeKey, iv)\n\n // Get encrypted data\n const encrypted = Buffer.concat([cipher.update(data), cipher.final()])\n\n return { encrypted, iv }\n }\n if (\n dataEncryption.algorithm === 'A128CBC-HS256' ||\n dataEncryption.algorithm === 'A192CBC-HS384' ||\n dataEncryption.algorithm === 'A256CBC-HS512'\n ) {\n // Map algorithms to their corresponding CBC and HMAC settings\n const algSettings = {\n 'A128CBC-HS256': { cbcAlg: 'aes-128-cbc', hmacAlg: 'HS256', keySize: 16 } as const,\n 'A192CBC-HS384': { cbcAlg: 'aes-192-cbc', hmacAlg: 'HS384', keySize: 24 } as const,\n 'A256CBC-HS512': { cbcAlg: 'aes-256-cbc', hmacAlg: 'HS512', keySize: 32 } as const,\n }[dataEncryption.algorithm]\n\n // IV should be exactly 16 bytes (128 bits) for CBC mode\n const iv = dataEncryption.iv ?? randomBytes(16)\n\n // Split the input key into MAC and ENC keys (MAC key is first half, ENC key is second half)\n const macKey = secretKeyBytes.subarray(0, algSettings.keySize)\n const encKey = createSecretKey(secretKeyBytes.subarray(algSettings.keySize))\n\n // Perform encryption\n const cipher = createCipheriv(algSettings.cbcAlg, encKey, iv)\n const encrypted = Buffer.concat([cipher.update(data), cipher.final()])\n\n // Calculate authentication tag\n // AL (Associated Length) is 64-bit big-endian length of AAD in bits\n const al = Buffer.alloc(8)\n const aadLength =
|
|
1
|
+
{"version":3,"file":"encrypt.mjs","names":[],"sources":["../../../src/kms/crypto/encrypt.ts"],"sourcesContent":["import { Buffer } from 'node:buffer'\nimport type { CipherGCM } from 'node:crypto'\nimport { createCipheriv, createSecretKey, randomBytes } from 'node:crypto'\nimport { Kms, TypedArrayEncoder } from '@credo-ts/core'\nimport { performSign } from './sign'\n\nexport const nodeSupportedEncryptionAlgorithms = [\n 'A128CBC',\n 'A256CBC',\n 'A128CBC-HS256',\n 'A192CBC-HS384',\n 'A256CBC-HS512',\n 'A128GCM',\n 'A192GCM',\n 'A256GCM',\n 'C20P',\n] as const satisfies Kms.KnownJwaContentEncryptionAlgorithm[]\n\nexport async function performEncrypt(\n key: Kms.KmsJwkPrivateOct,\n dataEncryption: Kms.KmsEncryptDataContentEncryption,\n data: Uint8Array,\n aad?: Uint8Array\n): Promise<{ encrypted: Uint8Array; tag?: Uint8Array; iv: Uint8Array }> {\n const secretKeyBytes = TypedArrayEncoder.fromBase64Url(key.k)\n const nodeKey = createSecretKey(secretKeyBytes)\n\n // Create cipher with key and IV\n if (dataEncryption.algorithm === 'A128CBC' || dataEncryption.algorithm === 'A256CBC') {\n const nodeAlgorithm = dataEncryption.algorithm === 'A128CBC' ? 'aes-128-cbc' : 'aes-256-cbc'\n\n // IV should be exactly 16 bytes (128 bits) for CBC mode\n const iv = dataEncryption.iv ?? randomBytes(16)\n\n const cipher = createCipheriv(nodeAlgorithm, nodeKey, iv)\n\n // Get encrypted data\n const encrypted = Buffer.concat([cipher.update(data), cipher.final()])\n\n return { encrypted, iv }\n }\n if (\n dataEncryption.algorithm === 'A128CBC-HS256' ||\n dataEncryption.algorithm === 'A192CBC-HS384' ||\n dataEncryption.algorithm === 'A256CBC-HS512'\n ) {\n // Map algorithms to their corresponding CBC and HMAC settings\n const algSettings = {\n 'A128CBC-HS256': { cbcAlg: 'aes-128-cbc', hmacAlg: 'HS256', keySize: 16 } as const,\n 'A192CBC-HS384': { cbcAlg: 'aes-192-cbc', hmacAlg: 'HS384', keySize: 24 } as const,\n 'A256CBC-HS512': { cbcAlg: 'aes-256-cbc', hmacAlg: 'HS512', keySize: 32 } as const,\n }[dataEncryption.algorithm]\n\n // IV should be exactly 16 bytes (128 bits) for CBC mode\n const iv = dataEncryption.iv ?? randomBytes(16)\n\n // Split the input key into MAC and ENC keys (MAC key is first half, ENC key is second half)\n const macKey = secretKeyBytes.subarray(0, algSettings.keySize)\n const encKey = createSecretKey(secretKeyBytes.subarray(algSettings.keySize))\n\n // Perform encryption\n const cipher = createCipheriv(algSettings.cbcAlg, encKey, iv)\n const encrypted = Buffer.concat([cipher.update(data), cipher.final()])\n\n // Calculate authentication tag\n // AL (Associated Length) is 64-bit big-endian length of AAD in bits\n const al = Buffer.alloc(8)\n const aadLength = aad ? aad.length * 8 : 0\n al.writeBigUInt64BE(BigInt(aadLength))\n\n // Create concatenated buffer for MAC calculation\n const macData = Buffer.concat([\n // If AAD exists, include it first, otherwise empty buffer\n aad ?? Buffer.alloc(0),\n iv, // Initial Vector\n encrypted, // Ciphertext\n al, // Associated Length (AL)\n ])\n\n const hmac = await performSign(\n { kty: 'oct', k: TypedArrayEncoder.toBase64Url(macKey) },\n algSettings.hmacAlg,\n macData\n )\n const tag = hmac.subarray(0, algSettings.keySize) // Truncate to appropriate size\n\n return { encrypted, tag, iv }\n }\n if (\n dataEncryption.algorithm === 'A128GCM' ||\n dataEncryption.algorithm === 'A192GCM' ||\n dataEncryption.algorithm === 'A256GCM'\n ) {\n const nodeAlgorithm =\n dataEncryption.algorithm === 'A128GCM'\n ? 'aes-128-gcm'\n : dataEncryption.algorithm === 'A192GCM'\n ? 'aes-192-gcm'\n : 'aes-256-gcm'\n\n // IV should be exactly 12 bytes (96 bits) for GCM\n const iv = dataEncryption.iv ?? randomBytes(12)\n\n const cipher = createCipheriv(nodeAlgorithm, nodeKey, iv)\n\n // If AAD is provided, update the cipher with it before encryption\n if (aad) {\n cipher.setAAD(aad)\n }\n\n // Get encrypted data\n const encrypted = Buffer.concat([cipher.update(data), cipher.final()])\n\n // Get auth tag - must be saved to verify decryption\n const tag = cipher.getAuthTag() as Uint8Array\n\n return {\n encrypted,\n tag,\n iv,\n }\n }\n if (dataEncryption.algorithm === 'C20P') {\n // IV should be exactly 12 bytes (96 bits) for C20P\n const iv = dataEncryption.iv ?? randomBytes(12)\n\n const cipher: CipherGCM = createCipheriv('chacha20-poly1305', nodeKey, iv, {\n authTagLength: 16,\n })\n\n // If AAD is provided, update the cipher with it before encryption\n if (aad) {\n cipher.setAAD(aad)\n }\n\n // Get encrypted data\n const encrypted = Buffer.concat([cipher.update(data), cipher.final()])\n\n // Get auth tag - must be saved to verify decryption\n const tag = cipher.getAuthTag() as Uint8Array\n\n return {\n encrypted,\n tag,\n iv,\n }\n }\n\n throw new Kms.KeyManagementAlgorithmNotSupportedError(\n `JWA content encryption algorithm '${dataEncryption.algorithm}'`,\n 'node'\n )\n}\n"],"mappings":";;;;;AAMA,MAAa,oCAAoC;CAC/C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,eAAsB,eACpB,KACA,gBACA,MACA,KACsE;CACtE,MAAM,iBAAiB,kBAAkB,cAAc,IAAI,CAAC;CAC5D,MAAM,UAAU,gBAAgB,cAAc;CAG9C,IAAI,eAAe,cAAc,aAAa,eAAe,cAAc,WAAW;EACpF,MAAM,gBAAgB,eAAe,cAAc,YAAY,gBAAgB;EAG/E,MAAM,KAAK,eAAe,MAAM,YAAY,EAAE;EAE9C,MAAM,SAAS,eAAe,eAAe,SAAS,EAAE;EAKxD,OAAO;GAAE,WAFS,OAAO,OAAO,CAAC,OAAO,OAAO,IAAI,GAAG,OAAO,MAAM,CAAC,CAEnD;GAAG;EAAG;CACzB;CACA,IACE,eAAe,cAAc,mBAC7B,eAAe,cAAc,mBAC7B,eAAe,cAAc,iBAC7B;EAEA,MAAM,cAAc;GAClB,iBAAiB;IAAE,QAAQ;IAAe,SAAS;IAAS,SAAS;GAAG;GACxE,iBAAiB;IAAE,QAAQ;IAAe,SAAS;IAAS,SAAS;GAAG;GACxE,iBAAiB;IAAE,QAAQ;IAAe,SAAS;IAAS,SAAS;GAAG;EAC1E,EAAE,eAAe;EAGjB,MAAM,KAAK,eAAe,MAAM,YAAY,EAAE;EAG9C,MAAM,SAAS,eAAe,SAAS,GAAG,YAAY,OAAO;EAC7D,MAAM,SAAS,gBAAgB,eAAe,SAAS,YAAY,OAAO,CAAC;EAG3E,MAAM,SAAS,eAAe,YAAY,QAAQ,QAAQ,EAAE;EAC5D,MAAM,YAAY,OAAO,OAAO,CAAC,OAAO,OAAO,IAAI,GAAG,OAAO,MAAM,CAAC,CAAC;EAIrE,MAAM,KAAK,OAAO,MAAM,CAAC;EACzB,MAAM,YAAY,MAAM,IAAI,SAAS,IAAI;EACzC,GAAG,iBAAiB,OAAO,SAAS,CAAC;EAGrC,MAAM,UAAU,OAAO,OAAO;GAE5B,OAAO,OAAO,MAAM,CAAC;GACrB;GACA;GACA;EACF,CAAC;EASD,OAAO;GAAE;GAAW,MAFR,MALO,YACjB;IAAE,KAAK;IAAO,GAAG,kBAAkB,YAAY,MAAM;GAAE,GACvD,YAAY,SACZ,OACF,EAAA,CACiB,SAAS,GAAG,YAAY,OAEnB;GAAG;EAAG;CAC9B;CACA,IACE,eAAe,cAAc,aAC7B,eAAe,cAAc,aAC7B,eAAe,cAAc,WAC7B;EACA,MAAM,gBACJ,eAAe,cAAc,YACzB,gBACA,eAAe,cAAc,YAC3B,gBACA;EAGR,MAAM,KAAK,eAAe,MAAM,YAAY,EAAE;EAE9C,MAAM,SAAS,eAAe,eAAe,SAAS,EAAE;EAGxD,IAAI,KACF,OAAO,OAAO,GAAG;EASnB,OAAO;GACL,WANgB,OAAO,OAAO,CAAC,OAAO,OAAO,IAAI,GAAG,OAAO,MAAM,CAAC,CAM1D;GACR,KAJU,OAAO,WAIf;GACF;EACF;CACF;CACA,IAAI,eAAe,cAAc,QAAQ;EAEvC,MAAM,KAAK,eAAe,MAAM,YAAY,EAAE;EAE9C,MAAM,SAAoB,eAAe,qBAAqB,SAAS,IAAI,EACzE,eAAe,GACjB,CAAC;EAGD,IAAI,KACF,OAAO,OAAO,GAAG;EASnB,OAAO;GACL,WANgB,OAAO,OAAO,CAAC,OAAO,OAAO,IAAI,GAAG,OAAO,MAAM,CAAC,CAM1D;GACR,KAJU,OAAO,WAIf;GACF;EACF;CACF;CAEA,MAAM,IAAI,IAAI,wCACZ,qCAAqC,eAAe,UAAU,IAC9D,MACF;AACF"}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
".": "./build/index.mjs",
|
|
5
5
|
"./package.json": "./package.json"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.8.0-alpha-
|
|
7
|
+
"version": "0.8.0-alpha-20261021192900",
|
|
8
8
|
"files": [
|
|
9
9
|
"build"
|
|
10
10
|
],
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"directory": "packages/node"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@credo-ts/core": "0.8.0-alpha-
|
|
26
|
-
"@credo-ts/didcomm": "0.8.0-alpha-
|
|
25
|
+
"@credo-ts/core": "0.8.0-alpha-20261021192900",
|
|
26
|
+
"@credo-ts/didcomm": "0.8.0-alpha-20261021192900",
|
|
27
27
|
"@types/node": "^22.19.0",
|
|
28
28
|
"@types/express": "^5.0.6",
|
|
29
29
|
"@types/ws": "^8.18.2",
|