@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.
@@ -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;EAuFjF,QAAQ,cAAc,cAAc,SAAS,IAAI,oBAAoB,QAAQ,IAAI;UAqFhF;UASA"}
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 && "externalPublicJwk" in operation.keyAgreement && operation.keyAgreement.externalPublicJwk) {
67
- const externalPublicJwk = operation.keyAgreement.externalPublicJwk;
68
- try {
69
- if (externalPublicJwk.kty === "EC") assertNodeSupportedEcCrv(externalPublicJwk);
70
- else assertNodeSupportedOkpCrv(externalPublicJwk);
71
- } catch {
72
- return false;
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 if (key.keyAgreement) {
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.assertAllowedKeyDerivationAlgForKey(key.keyAgreement.externalPublicJwk, key.keyAgreement.algorithm);
296
- Kms.assertKeyAllowsDerive(key.keyAgreement.externalPublicJwk);
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, key.keyAgreement.externalPublicJwk);
302
- const { contentEncryptionKey } = await deriveDecryptionKey({
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 deriveEncryptionKey(options) {
22
- const { keyAgreement, encryption, privateJwk } = options;
23
- assertNodeSupportedEcdhKeyDerivationCrv(keyAgreement.externalPublicJwk);
24
- assertNodeSupportedEcdhKeyDerivationCrv(privateJwk);
25
- const keyLength = keyAgreement.algorithm === "ECDH-ES" ? mapContentEncryptionAlgorithmToKeyLength(encryption.algorithm) : keyAgreement.algorithm === "ECDH-ES+A128KW" ? 128 : keyAgreement.algorithm === "ECDH-ES+A192KW" ? 192 : 256;
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") return { contentEncryptionKey: {
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: derivedKeyBytes.toString("base64url")
37
- } };
38
- const contentEncryptionKeyBytes = getRandomValues(new Uint8Array(mapContentEncryptionAlgorithmToKeyLength(encryption.algorithm) >> 3));
39
- const cipher = createCipheriv(`id-aes${keyLength}-wrap`, derivedKeyBytes, aesKeyWrapIv);
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
- encryptedContentEncryptionKey: { encrypted: new Uint8Array(Buffer.concat([cipher.update(contentEncryptionKeyBytes), cipher.final()])) },
42
- contentEncryptionKey: {
43
- kty: "oct",
44
- k: TypedArrayEncoder.toBase64Url(contentEncryptionKeyBytes)
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
- async function deriveDecryptionKey(options) {
48
+ function deriveDecryptionKey(options) {
49
49
  const { keyAgreement, decryption, privateJwk } = options;
50
- assertNodeSupportedEcdhKeyDerivationCrv(keyAgreement.externalPublicJwk);
51
- assertNodeSupportedEcdhKeyDerivationCrv(privateJwk);
52
- const keyLength = keyAgreement.algorithm === "ECDH-ES" ? mapContentEncryptionAlgorithmToKeyLength(decryption.algorithm) : keyAgreement.algorithm === "ECDH-ES+A128KW" ? 128 : keyAgreement.algorithm === "ECDH-ES+A192KW" ? 192 : 256;
53
- const derivedKeyBytes = await deriveKeyEcdhEs({
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: Buffer.concat([decipher.update(keyAgreement.encryptedKey.encrypted), decipher.final()]).toString("base64url")
60
+ k: (keyAgreement.algorithm === "ECDH-ES" ? derivedKey : aesKeyUnwrap(derivedKey, keyAgreement.encryptedKey.encrypted)).toString("base64url")
69
61
  } };
70
62
  }
71
- /**
72
- * Derive a key using ECDH and Concat KDF
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: options.privateJwk
67
+ key: privateJwk
79
68
  }),
80
69
  publicKey: createPublicKey({
81
70
  format: "jwk",
82
- key: options.publicJwk
71
+ key: publicJwk
83
72
  })
84
73
  });
85
- const algorithmData = TypedArrayEncoder.fromUtf8String(options.usageAlgorithm);
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 otherInfo = Buffer.concat([
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, deriveEncryptionKey, nodeSupportedKeyAgreementAlgorithms };
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 = dataEncryption.aad ? dataEncryption.aad.length * 8 : 0;
53
+ const aadLength = aad ? aad.length * 8 : 0;
54
54
  al.writeBigUInt64BE(BigInt(aadLength));
55
55
  const macData = Buffer.concat([
56
- dataEncryption.aad ?? Buffer.alloc(0),
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 (dataEncryption.aad) cipher.setAAD(dataEncryption.aad);
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 (dataEncryption.aad) cipher.setAAD(dataEncryption.aad);
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 = dataEncryption.aad ? dataEncryption.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 dataEncryption.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 (dataEncryption.aad) {\n cipher.setAAD(dataEncryption.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 (dataEncryption.aad) {\n cipher.setAAD(dataEncryption.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,MACsE;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,eAAe,MAAM,eAAe,IAAI,SAAS,IAAI;EACvE,GAAG,iBAAiB,OAAO,SAAS,CAAC;EAGrC,MAAM,UAAU,OAAO,OAAO;GAE5B,eAAe,OAAO,OAAO,MAAM,CAAC;GACpC;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,eAAe,KACjB,OAAO,OAAO,eAAe,GAAG;EASlC,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,eAAe,KACjB,OAAO,OAAO,eAAe,GAAG;EASlC,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"}
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-20261020190607",
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-20261020190607",
26
- "@credo-ts/didcomm": "0.8.0-alpha-20261020190607",
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",