From 8ccf0b77ac5189092cf908c06af837b92f0a271e Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Mon, 18 Nov 2024 14:09:25 -0800 Subject: [PATCH] Include aes gcm encryption key connector will always provide the asym keys and the clients will encapsulate a key and encrypt communications with it. --- .../web-crypto-function.service.spec.ts | 41 +++++++++++++++++++ .../services/web-crypto-function.service.ts | 20 +++++++++ .../node-crypto-function.service.spec.ts | 41 +++++++++++++++++++ .../services/node-crypto-function.service.ts | 21 +++++++++- 4 files changed, 122 insertions(+), 1 deletion(-) diff --git a/libs/common/src/platform/services/web-crypto-function.service.spec.ts b/libs/common/src/platform/services/web-crypto-function.service.spec.ts index 743eca7f1f8..022684e213d 100644 --- a/libs/common/src/platform/services/web-crypto-function.service.spec.ts +++ b/libs/common/src/platform/services/web-crypto-function.service.spec.ts @@ -270,6 +270,47 @@ describe("WebCrypto Function Service", () => { }); }); + describe("aes encrypt GCM mode", () => { + it("should successfully encrypt data", async () => { + const cryptoFunctionService = getWebCryptoFunctionService(); + const iv = makeStaticByteArray(12); + const key = makeStaticByteArray(32); + const data = Utils.fromUtf8ToArray("EncryptMe!"); + const encValue = await cryptoFunctionService.aesGcmEncrypt(data, iv, key); + expect(encValue).toEqual( + new Uint8Array( + Buffer.concat([Utils.fromB64ToArray("Amy1abyVtlboYFBtLnDAzAwAgb3Qg2m4fMo="), iv]), + ), + ); + }); + + it("should successfully encrypt with aad", async () => { + const cryptoFunctionService = getWebCryptoFunctionService(); + const iv = makeStaticByteArray(12); + const key = makeStaticByteArray(32); + const data = Utils.fromUtf8ToArray("EncryptMe!"); + const aad = Utils.fromUtf8ToArray("aad"); + const encValue = await cryptoFunctionService.aesGcmEncrypt(data, iv, key, aad); + expect(encValue).toEqual( + new Uint8Array( + Buffer.concat([Utils.fromB64ToArray("Amy1abyVtlboYJTbBTRtNtA4JtxBgjhhSCE="), iv]), + ), + ); + }); + + it("should successfully encrypt and then decrypt data", async () => { + const cryptoFunctionService = getWebCryptoFunctionService(); + const iv = makeStaticByteArray(12); + const key = makeStaticByteArray(32); + const value = "EncryptMe!"; + const data = Utils.fromUtf8ToArray(value); + const encAndIv = new Uint8Array(await cryptoFunctionService.aesGcmEncrypt(data, iv, key)); + const envValue = encAndIv.slice(0, encAndIv.length - 12); + const decValue = await cryptoFunctionService.aesDecrypt(envValue, iv, key, "gcm"); + expect(Utils.fromBufferToUtf8(decValue)).toBe(value); + }); + }); + describe("aesDecryptFast CBC mode", () => { it("should successfully decrypt data", async () => { const cryptoFunctionService = getWebCryptoFunctionService(); diff --git a/libs/common/src/platform/services/web-crypto-function.service.ts b/libs/common/src/platform/services/web-crypto-function.service.ts index fb824d204fc..c760bb2b3ee 100644 --- a/libs/common/src/platform/services/web-crypto-function.service.ts +++ b/libs/common/src/platform/services/web-crypto-function.service.ts @@ -234,6 +234,26 @@ export class WebCryptoFunctionService implements CryptoFunctionService { return new Uint8Array(buffer); } + async aesGcmEncrypt( + data: Uint8Array, + iv: Uint8Array, + key: Uint8Array, + additionalData?: Uint8Array, + ): Promise { + const impKey = await this.subtle.importKey("raw", key, { name: "AES-GCM" } as any, false, [ + "encrypt", + ]); + const buffer = await this.subtle.encrypt( + { name: "AES-GCM", iv: iv, tagLength: 128, additionalData }, + impKey, + data, + ); + const result = new Uint8Array(buffer.byteLength + iv.byteLength); + result.set(new Uint8Array(buffer), 0); + result.set(iv, buffer.byteLength); + return result; + } + aesDecryptFastParameters( data: string, iv: string, diff --git a/libs/node/src/services/node-crypto-function.service.spec.ts b/libs/node/src/services/node-crypto-function.service.spec.ts index f068b13ea3e..a6feeba3a57 100644 --- a/libs/node/src/services/node-crypto-function.service.spec.ts +++ b/libs/node/src/services/node-crypto-function.service.spec.ts @@ -187,6 +187,47 @@ describe("NodeCrypto Function Service", () => { }); }); + describe("aes encrypt GCM mode", () => { + it("should successfully encrypt data", async () => { + const cryptoFunctionService = new NodeCryptoFunctionService(); + const iv = makeStaticByteArray(12); + const key = makeStaticByteArray(32); + const data = Utils.fromUtf8ToArray("EncryptMe!"); + const encValue = await cryptoFunctionService.aesGcmEncrypt(data, iv, key); + expect(encValue).toEqual( + new Uint8Array( + Buffer.concat([Utils.fromB64ToArray("Amy1abyVtlboYFBtLnDAzAwAgb3Qg2m4fMo="), iv]), + ), + ); + }); + + it("should successfully encrypt with aad", async () => { + const cryptoFunctionService = new NodeCryptoFunctionService(); + const iv = makeStaticByteArray(12); + const key = makeStaticByteArray(32); + const data = Utils.fromUtf8ToArray("EncryptMe!"); + const aad = Utils.fromUtf8ToArray("aad"); + const encValue = await cryptoFunctionService.aesGcmEncrypt(data, iv, key, aad); + expect(encValue).toEqual( + new Uint8Array( + Buffer.concat([Utils.fromB64ToArray("Amy1abyVtlboYJTbBTRtNtA4JtxBgjhhSCE="), iv]), + ), + ); + }); + + it("should successfully encrypt and then decrypt data", async () => { + const cryptoFunctionService = new NodeCryptoFunctionService(); + const iv = makeStaticByteArray(12); + const key = makeStaticByteArray(32); + const value = "EncryptMe!"; + const data = Utils.fromUtf8ToArray(value); + const encAndIv = new Uint8Array(await cryptoFunctionService.aesGcmEncrypt(data, iv, key)); + const envValue = encAndIv.slice(0, encAndIv.length - 12); + const decValue = await cryptoFunctionService.aesDecrypt(envValue, iv, key, "gcm"); + expect(Utils.fromBufferToUtf8(decValue)).toBe(value); + }); + }); + describe("aesDecryptFast CBC mode", () => { it("should successfully decrypt data", async () => { const nodeCryptoFunctionService = new NodeCryptoFunctionService(); diff --git a/libs/node/src/services/node-crypto-function.service.ts b/libs/node/src/services/node-crypto-function.service.ts index 7fc8bf3c4b6..3225d1d2808 100644 --- a/libs/node/src/services/node-crypto-function.service.ts +++ b/libs/node/src/services/node-crypto-function.service.ts @@ -163,6 +163,25 @@ export class NodeCryptoFunctionService implements CryptoFunctionService { return Promise.resolve(this.toUint8Buffer(encBuf)); } + async aesGcmEncrypt( + data: Uint8Array, + iv: Uint8Array, + key: Uint8Array, + additionalData?: Uint8Array, + ): Promise { + const nodeData = this.toNodeBuffer(data); + const nodeIv = this.toNodeBuffer(iv); + const nodeKey = this.toNodeBuffer(key); + const cipher = crypto.createCipheriv("aes-256-gcm", nodeKey, nodeIv, { authTagLength: 16 }); + if (additionalData != null) { + const nodeAdditionalData = this.toNodeBuffer(additionalData); + cipher.setAAD(nodeAdditionalData); + } + const encBuf = Buffer.concat([cipher.update(nodeData), cipher.final()]); + const tag = cipher.getAuthTag(); + return Promise.resolve(this.toUint8Buffer(Buffer.concat([encBuf, tag, nodeIv]))); + } + aesDecryptFastParameters( data: string, iv: string, @@ -318,7 +337,7 @@ export class NodeCryptoFunctionService implements CryptoFunctionService { if (typeof value === "string") { buf = Utils.fromUtf8ToArray(value); } else { - buf = value; + buf = new Uint8Array(value); } return buf; }