From b2b432aee5e8de9731204d3519a1cdde5a1e6a69 Mon Sep 17 00:00:00 2001 From: Ajitomi Daisuke Date: Fri, 21 Jul 2023 05:00:26 +0900 Subject: [PATCH 1/3] Create kem context in constructor. --- src/cipherSuite.ts | 117 ++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 60 deletions(-) diff --git a/src/cipherSuite.ts b/src/cipherSuite.ts index cd66b1a97..970cf4957 100644 --- a/src/cipherSuite.ts +++ b/src/cipherSuite.ts @@ -57,14 +57,6 @@ export class CipherSuite { /** The AEAD id of the cipher suite. */ public readonly aead: AeadId; - /** The length in bytes of a KEM shared secret produced by this KEM (Nsecret). */ - public readonly kemSecretSize: number = 0; - /** The length in bytes of an encapsulated key produced by this KEM (Nenc). */ - public readonly kemEncSize: number = 0; - /** The length in bytes of an encoded public key for this KEM (Npk). */ - public readonly kemPublicKeySize: number = 0; - /** The length in bytes of an encoded private key for this KEM (Nsk). */ - public readonly kemPrivateKeySize: number = 0; /** The length in bytes of an AEAD key (Nk). */ public readonly aeadKeySize: number = 0; /** The length in bytes of an AEAD nonce (Nn). */ @@ -73,7 +65,7 @@ export class CipherSuite { public readonly aeadTagSize: number = 0; private _api: SubtleCrypto | undefined = undefined; - private _kem: KemInterface | undefined = undefined; + private _kem: KemInterface; private _kdf: KdfInterface | undefined = undefined; private _suiteId: Uint8Array; @@ -87,40 +79,22 @@ export class CipherSuite { constructor(params: CipherSuiteParams) { switch (params.kem) { case KemId.DhkemP256HkdfSha256: - this.kemSecretSize = 32; - this.kemEncSize = 65; - this.kemPublicKeySize = 65; - this.kemPrivateKeySize = 32; + this._kem = new DhkemP256HkdfSha256(); break; case KemId.DhkemP384HkdfSha384: - this.kemSecretSize = 48; - this.kemEncSize = 97; - this.kemPublicKeySize = 97; - this.kemPrivateKeySize = 48; + this._kem = new DhkemP384HkdfSha384(); break; case KemId.DhkemP521HkdfSha512: - this.kemSecretSize = 64; - this.kemEncSize = 133; - this.kemPublicKeySize = 133; - this.kemPrivateKeySize = 66; + this._kem = new DhkemP521HkdfSha512(); break; case KemId.DhkemSecp256K1HkdfSha256: - this.kemSecretSize = 32; - this.kemEncSize = 33; - this.kemPublicKeySize = 33; - this.kemPrivateKeySize = 32; + this._kem = new DhkemSecp256K1HkdfSha256(); break; case KemId.DhkemX25519HkdfSha256: - this.kemSecretSize = 32; - this.kemEncSize = 32; - this.kemPublicKeySize = 32; - this.kemPrivateKeySize = 32; + this._kem = new DhkemX25519HkdfSha256(); break; case KemId.DhkemX448HkdfSha512: - this.kemSecretSize = 64; - this.kemEncSize = 56; - this.kemPublicKeySize = 56; - this.kemPrivateKeySize = 56; + this._kem = new DhkemX448HkdfSha512(); break; default: throw new errors.InvalidParamError("Invalid KEM id"); @@ -165,6 +139,55 @@ export class CipherSuite { this._suiteId.set(i2Osp(this.aead, 2), 8); } + /** + * The length in bytes of a KEM shared secret produced by this KEM (Nsecret). + */ + public get kemSecretSize() { + return this._kem.secretSize; + } + + /** + * The length in bytes of an encapsulated key produced by this KEM (Nenc). + */ + public get kemEncSize() { + return this._kem.encSize; + } + + /** + * The length in bytes of an encoded public key for this KEM (Npk). + */ + public get kemPublicKeySize() { + return this._kem.publicKeySize; + } + + /** + * The length in bytes of an encoded private key for this KEM (Nsk). + */ + public get kemPrivateKeySize() { + return this._kem.privateKeySize; + } + + // /** + // * The length in bytes of an AEAD key (Nk). + // */ + // public get aeadKeySize() { + // return this._aead.keySize; + // } + + // /** + // * The length in bytes of an AEAD nonce (Nn). + // */ + // public get aeadNonceSize() { + // return this._aead.nonceSize; + // } + + // /** + // * The length in bytes of an AEAD authentication tag (Nt). + // */ + // public get aeadTagSize() { + // return this._aead.tagSize; + // } + /** * Gets a suite-specific KEM context. * @@ -352,7 +375,7 @@ export class CipherSuite { private async setup() { this._api = await loadSubtleCrypto(); if (this._kem === undefined || this._kdf === undefined) { - this._kem = this.createKemContext(); + this._kem.init(this._api as SubtleCrypto); this._kdf = this.createKdfContext(); } return; @@ -535,32 +558,6 @@ export class CipherSuite { return; } - private createKemContext(): KemInterface { - let ret: KemInterface; - switch (this.kem) { - case KemId.DhkemP256HkdfSha256: - ret = new DhkemP256HkdfSha256(); - break; - case KemId.DhkemP384HkdfSha384: - ret = new DhkemP384HkdfSha384(); - break; - case KemId.DhkemP521HkdfSha512: - ret = new DhkemP521HkdfSha512(); - break; - case KemId.DhkemX25519HkdfSha256: - ret = new DhkemX25519HkdfSha256(); - break; - case KemId.DhkemX448HkdfSha512: - ret = new DhkemX448HkdfSha512(); - break; - default: - ret = new DhkemSecp256K1HkdfSha256(); - break; - } - ret.init(this._api as SubtleCrypto); - return ret; - } - private createKdfContext(): KdfInterface { let ret: KdfInterface; switch (this.kdf) { From 79ca7ba2c199e898087c063da4fceb41661247b2 Mon Sep 17 00:00:00 2001 From: Ajitomi Daisuke Date: Fri, 21 Jul 2023 05:27:50 +0900 Subject: [PATCH 2/3] Create kdf context in constructor. --- src/cipherSuite.ts | 100 ++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 61 deletions(-) diff --git a/src/cipherSuite.ts b/src/cipherSuite.ts index 970cf4957..209c70824 100644 --- a/src/cipherSuite.ts +++ b/src/cipherSuite.ts @@ -66,7 +66,7 @@ export class CipherSuite { private _api: SubtleCrypto | undefined = undefined; private _kem: KemInterface; - private _kdf: KdfInterface | undefined = undefined; + private _kdf: KdfInterface; private _suiteId: Uint8Array; /** @@ -103,8 +103,13 @@ export class CipherSuite { switch (params.kdf) { case KdfId.HkdfSha256: + this._kdf = new HkdfSha256(); + break; case KdfId.HkdfSha384: + this._kdf = new HkdfSha384(); + break; case KdfId.HkdfSha512: + this._kdf = new HkdfSha512(); break; default: throw new errors.InvalidParamError("Invalid KDF id"); @@ -373,11 +378,13 @@ export class CipherSuite { } private async setup() { - this._api = await loadSubtleCrypto(); - if (this._kem === undefined || this._kdf === undefined) { - this._kem.init(this._api as SubtleCrypto); - this._kdf = this.createKdfContext(); + if (this._api !== undefined) { + return; } + const api = await loadSubtleCrypto(); + this._kem.init(api as SubtleCrypto); + this._kdf.init(api as SubtleCrypto, this._suiteId); + this._api = api; return; } @@ -400,18 +407,16 @@ export class CipherSuite { mode: Mode, sharedSecret: ArrayBuffer, params: KeyScheduleParams, - ): Promise<{ params: AeadParams; kdf: KdfInterface }> { + ): Promise { // Currently, there is no point in executing this function // because this hpke library does not allow users to explicitly specify the mode. // // this.verifyPskInputs(mode, params); - const kdf = this.createKdfContext(); - const pskId = params.psk === undefined ? consts.EMPTY : new Uint8Array(params.psk.id); - const pskIdHash = await kdf.labeledExtract( + const pskIdHash = await this._kdf.labeledExtract( consts.EMPTY, consts.LABEL_PSK_ID_HASH, pskId, @@ -420,7 +425,7 @@ export class CipherSuite { const info = params.info === undefined ? consts.EMPTY : new Uint8Array(params.info); - const infoHash = await kdf.labeledExtract( + const infoHash = await this._kdf.labeledExtract( consts.EMPTY, consts.LABEL_INFO_HASH, info, @@ -436,48 +441,42 @@ export class CipherSuite { const psk = params.psk === undefined ? consts.EMPTY : new Uint8Array(params.psk.key); - const ikm = kdf.buildLabeledIkm(consts.LABEL_SECRET, psk); + const ikm = this._kdf.buildLabeledIkm(consts.LABEL_SECRET, psk); - const exporterSecretInfo = kdf.buildLabeledInfo( + const exporterSecretInfo = this._kdf.buildLabeledInfo( consts.LABEL_EXP, keyScheduleContext, - kdf.hashSize, + this._kdf.hashSize, ); - const exporterSecret = await kdf.extractAndExpand( + const exporterSecret = await this._kdf.extractAndExpand( sharedSecret, ikm, exporterSecretInfo, - kdf.hashSize, + this._kdf.hashSize, ); if (this.aead === AeadId.ExportOnly) { - return { - params: { - aead: this.aead, - exporterSecret: exporterSecret, - }, - kdf: kdf, - }; + return { aead: this.aead, exporterSecret: exporterSecret }; } - const keyInfo = kdf.buildLabeledInfo( + const keyInfo = this._kdf.buildLabeledInfo( consts.LABEL_KEY, keyScheduleContext, this.aeadKeySize, ); - const key = await kdf.extractAndExpand( + const key = await this._kdf.extractAndExpand( sharedSecret, ikm, keyInfo, this.aeadKeySize, ); - const baseNonceInfo = kdf.buildLabeledInfo( + const baseNonceInfo = this._kdf.buildLabeledInfo( consts.LABEL_BASE_NONCE, keyScheduleContext, this.aeadNonceSize, ); - const baseNonce = await kdf.extractAndExpand( + const baseNonce = await this._kdf.extractAndExpand( sharedSecret, ikm, baseNonceInfo, @@ -485,14 +484,11 @@ export class CipherSuite { ); return { - params: { - aead: this.aead, - exporterSecret: exporterSecret, - key: key, - baseNonce: new Uint8Array(baseNonce), - seq: 0, - }, - kdf: kdf, + aead: this.aead, + exporterSecret: exporterSecret, + key: key, + baseNonce: new Uint8Array(baseNonce), + seq: 0, }; } @@ -503,18 +499,18 @@ export class CipherSuite { params: KeyScheduleParams, ): Promise { const res = await this.keySchedule(mode, sharedSecret, params); - if (res.params.key === undefined) { + if (res.key === undefined) { return new SenderExporterContext( this._api as SubtleCrypto, - res.kdf, - res.params.exporterSecret, + this._kdf, + res.exporterSecret, enc, ); } return new SenderContext( this._api as SubtleCrypto, - res.kdf, - res.params, + this._kdf, + res, enc, ); } @@ -525,14 +521,14 @@ export class CipherSuite { params: KeyScheduleParams, ): Promise { const res = await this.keySchedule(mode, sharedSecret, params); - if (res.params.key === undefined) { + if (res.key === undefined) { return new RecipientExporterContext( this._api as SubtleCrypto, - res.kdf, - res.params.exporterSecret, + this._kdf, + res.exporterSecret, ); } - return new RecipientContext(this._api as SubtleCrypto, res.kdf, res.params); + return new RecipientContext(this._api as SubtleCrypto, this._kdf, res); } private validateInputLength(params: KeyScheduleParams) { @@ -557,22 +553,4 @@ export class CipherSuite { } return; } - - private createKdfContext(): KdfInterface { - let ret: KdfInterface; - switch (this.kdf) { - case KdfId.HkdfSha256: - ret = new HkdfSha256(); - break; - case KdfId.HkdfSha384: - ret = new HkdfSha384(); - break; - default: - // case KdfId.HkdfSha512: - ret = new HkdfSha512(); - break; - } - ret.init(this._api as SubtleCrypto, this._suiteId); - return ret; - } } From df1a62e363996ada14575e52f48098772f74923c Mon Sep 17 00:00:00 2001 From: Ajitomi Daisuke Date: Sat, 22 Jul 2023 00:15:29 +0900 Subject: [PATCH 3/3] Allow Kem/KdfInterface to be set to CipherSuiteParameters. --- mod.ts | 12 ++ src/cipherSuite.ts | 78 ++++++------ src/interfaces/cipherSuiteParams.ts | 12 +- test/cipherSuite.test.ts | 181 +++++++++++++++++++++++++++- 4 files changed, 237 insertions(+), 46 deletions(-) diff --git a/mod.ts b/mod.ts index 146b14e0a..48f56fe33 100644 --- a/mod.ts +++ b/mod.ts @@ -16,3 +16,15 @@ export * from "./src/errors.ts"; export { Aead, AeadId, Kdf, KdfId, Kem, KemId } from "./src/identifiers.ts"; export { CipherSuite } from "./src/cipherSuite.ts"; +export { + DhkemP256HkdfSha256, + DhkemP384HkdfSha384, + DhkemP521HkdfSha512, + DhkemX25519HkdfSha256, + DhkemX448HkdfSha512, +} from "./src/kems/dhkem.ts"; +export { + HkdfSha256, + HkdfSha384, + HkdfSha512, +} from "./src/kdfs/hkdf.ts"; diff --git a/src/cipherSuite.ts b/src/cipherSuite.ts index 209c70824..6e889143e 100644 --- a/src/cipherSuite.ts +++ b/src/cipherSuite.ts @@ -77,44 +77,52 @@ export class CipherSuite { * @throws {@link InvalidParamError} */ constructor(params: CipherSuiteParams) { - switch (params.kem) { - case KemId.DhkemP256HkdfSha256: - this._kem = new DhkemP256HkdfSha256(); - break; - case KemId.DhkemP384HkdfSha384: - this._kem = new DhkemP384HkdfSha384(); - break; - case KemId.DhkemP521HkdfSha512: - this._kem = new DhkemP521HkdfSha512(); - break; - case KemId.DhkemSecp256K1HkdfSha256: - this._kem = new DhkemSecp256K1HkdfSha256(); - break; - case KemId.DhkemX25519HkdfSha256: - this._kem = new DhkemX25519HkdfSha256(); - break; - case KemId.DhkemX448HkdfSha512: - this._kem = new DhkemX448HkdfSha512(); - break; - default: - throw new errors.InvalidParamError("Invalid KEM id"); + if (typeof params.kem !== "number") { + this._kem = params.kem; + } else { + switch (params.kem) { + case KemId.DhkemP256HkdfSha256: + this._kem = new DhkemP256HkdfSha256(); + break; + case KemId.DhkemP384HkdfSha384: + this._kem = new DhkemP384HkdfSha384(); + break; + case KemId.DhkemP521HkdfSha512: + this._kem = new DhkemP521HkdfSha512(); + break; + case KemId.DhkemSecp256K1HkdfSha256: + this._kem = new DhkemSecp256K1HkdfSha256(); + break; + case KemId.DhkemX25519HkdfSha256: + this._kem = new DhkemX25519HkdfSha256(); + break; + case KemId.DhkemX448HkdfSha512: + this._kem = new DhkemX448HkdfSha512(); + break; + default: + throw new errors.InvalidParamError("Invalid KEM id"); + } } - this.kem = params.kem; + this.kem = this._kem.id; - switch (params.kdf) { - case KdfId.HkdfSha256: - this._kdf = new HkdfSha256(); - break; - case KdfId.HkdfSha384: - this._kdf = new HkdfSha384(); - break; - case KdfId.HkdfSha512: - this._kdf = new HkdfSha512(); - break; - default: - throw new errors.InvalidParamError("Invalid KDF id"); + if (typeof params.kdf !== "number") { + this._kdf = params.kdf; + } else { + switch (params.kdf) { + case KdfId.HkdfSha256: + this._kdf = new HkdfSha256(); + break; + case KdfId.HkdfSha384: + this._kdf = new HkdfSha384(); + break; + case KdfId.HkdfSha512: + this._kdf = new HkdfSha512(); + break; + default: + throw new errors.InvalidParamError("Invalid KDF id"); + } } - this.kdf = params.kdf; + this.kdf = this._kdf.id; switch (params.aead) { case AeadId.Aes128Gcm: diff --git a/src/interfaces/cipherSuiteParams.ts b/src/interfaces/cipherSuiteParams.ts index dc3f37901..43f45be1d 100644 --- a/src/interfaces/cipherSuiteParams.ts +++ b/src/interfaces/cipherSuiteParams.ts @@ -1,15 +1,17 @@ import type { AeadId, KdfId, KemId } from "../identifiers.ts"; +import type { KdfInterface } from "./kdfInterface.ts"; +import type { KemInterface } from "./kemInterface.ts"; /** * The parameters used to configure the `CipherSuite`. */ export interface CipherSuiteParams { - /** The type of KEM (Key Encapsulation Mechanism). */ - kem: KemId; + /** The KEM (Key Encapsulation Mechanism) identifier or the KEM object. */ + kem: KemId | KemInterface; - /** The type of KDF (Key Derivation Function). */ - kdf: KdfId; + /** The KDF (Key Derivation Function) identifier. */ + kdf: KdfId | KdfInterface; - /** The type of AEAD (Authenticated Encryption with Addtional Data) encryption function. */ + /** The AEAD (Authenticated Encryption with Addtional Data) identifier. */ aead: AeadId; } diff --git a/test/cipherSuite.test.ts b/test/cipherSuite.test.ts index c125e0901..4f56cadbc 100644 --- a/test/cipherSuite.test.ts +++ b/test/cipherSuite.test.ts @@ -7,6 +7,14 @@ import { CipherSuite } from "../src/cipherSuite.ts"; import { isDeno } from "../src/utils/misc.ts"; import { loadCrypto } from "../src/webCrypto.ts"; import { concat } from "../src/utils/misc.ts"; +import { + DhkemP256HkdfSha256, + DhkemP384HkdfSha384, + DhkemP521HkdfSha512, + DhkemX25519HkdfSha256, + DhkemX448HkdfSha512, +} from "../src/kems/dhkem.ts"; +import { HkdfSha256, HkdfSha384, HkdfSha512 } from "../src/kdfs/hkdf.ts"; import * as errors from "../src/errors.ts"; @@ -15,7 +23,7 @@ import { hexStringToBytes } from "./utils.ts"; describe("CipherSuite", () => { // RFC9180 A.1. describe("constructor with DhkemX25519HkdfSha256/HkdfSha256/Aes128Gcm", () => { - it("should have ciphersuites", async () => { + it("should have a correct ciphersuite", async () => { const suite: CipherSuite = new CipherSuite({ kem: KemId.DhkemX25519HkdfSha256, kdf: KdfId.HkdfSha256, @@ -182,7 +190,7 @@ describe("CipherSuite", () => { }); describe("A README example of Base mode", () => { - it("should work normally with generateKeyPair", async () => { + it("should work normally with ids", async () => { // setup const suite = new CipherSuite({ kem: KemId.DhkemP256HkdfSha256, @@ -215,6 +223,39 @@ describe("CipherSuite", () => { await assertRejects(() => sender.open(ct), errors.OpenError); }); + it("should work normally with instances", async () => { + // setup + const suite = new CipherSuite({ + kem: new DhkemP256HkdfSha256(), + kdf: new HkdfSha256(), + aead: AeadId.Aes128Gcm, + }); + + const rkp = await suite.generateKeyPair(); + + const sender = await suite.createSenderContext({ + recipientPublicKey: rkp.publicKey, + }); + + const recipient = await suite.createRecipientContext({ + recipientKey: rkp, + enc: sender.enc, + }); + + // encrypt + const ct = await sender.seal( + new TextEncoder().encode("my-secret-message"), + ); + + // decrypt + const pt = await recipient.open(ct); + + // assert + assertEquals(new TextDecoder().decode(pt), "my-secret-message"); + await assertRejects(() => recipient.seal(pt), errors.SealError); + await assertRejects(() => sender.open(ct), errors.OpenError); + }); + it("should work normally with importKey('jwk')", async () => { // setup const suite = new CipherSuite({ @@ -268,7 +309,7 @@ describe("CipherSuite", () => { }); describe("A README example of Base mode (KemId.DhkemP384HkdfSha384/KdfId.HkdfSha384)", () => { - it("should work normally with generateKeyPair", async () => { + it("should work normally with ids", async () => { // setup const suite = new CipherSuite({ kem: KemId.DhkemP384HkdfSha384, @@ -299,6 +340,37 @@ describe("CipherSuite", () => { assertEquals(new TextDecoder().decode(pt), "my-secret-message"); }); + it("should work normally with instances", async () => { + // setup + const suite = new CipherSuite({ + kem: new DhkemP384HkdfSha384(), + kdf: new HkdfSha384(), + aead: AeadId.Aes128Gcm, + }); + + const rkp = await suite.generateKeyPair(); + + const sender = await suite.createSenderContext({ + recipientPublicKey: rkp.publicKey, + }); + + const recipient = await suite.createRecipientContext({ + recipientKey: rkp, + enc: sender.enc, + }); + + // encrypt + const ct = await sender.seal( + new TextEncoder().encode("my-secret-message"), + ); + + // decrypt + const pt = await recipient.open(ct); + + // assert + assertEquals(new TextDecoder().decode(pt), "my-secret-message"); + }); + it("should work normally with importKey('jwk')", async () => { // setup const suite = new CipherSuite({ @@ -352,7 +424,7 @@ describe("CipherSuite", () => { }); describe("A README example of Base mode (KemId.DhkemP521HkdfSha512/KdfId.HkdfSha512)", () => { - it("should work normally with generateKeyPair", async () => { + it("should work normally with ids", async () => { if (isDeno()) { return; } @@ -387,6 +459,41 @@ describe("CipherSuite", () => { assertEquals(new TextDecoder().decode(pt), "my-secret-message"); }); + it("should work normally with instances", async () => { + if (isDeno()) { + return; + } + + // setup + const suite = new CipherSuite({ + kem: new DhkemP521HkdfSha512(), + kdf: new HkdfSha512(), + aead: AeadId.Aes128Gcm, + }); + + const rkp = await suite.generateKeyPair(); + + const sender = await suite.createSenderContext({ + recipientPublicKey: rkp.publicKey, + }); + + const recipient = await suite.createRecipientContext({ + recipientKey: rkp, + enc: sender.enc, + }); + + // encrypt + const ct = await sender.seal( + new TextEncoder().encode("my-secret-message"), + ); + + // decrypt + const pt = await recipient.open(ct); + + // assert + assertEquals(new TextDecoder().decode(pt), "my-secret-message"); + }); + it("should work normally with importKey('jwk')", async () => { if (isDeno()) { return; @@ -444,7 +551,7 @@ describe("CipherSuite", () => { }); describe("A README example of Base mode (KemId.DhkemX25519HkdfSha256/KdfId.HkdfSha256)", () => { - it("should work normally", async () => { + it("should work normally with ids", async () => { // setup const suite = new CipherSuite({ kem: KemId.DhkemX25519HkdfSha256, @@ -475,6 +582,37 @@ describe("CipherSuite", () => { assertEquals(new TextDecoder().decode(pt), "my-secret-message"); }); + it("should work normally with instances", async () => { + // setup + const suite = new CipherSuite({ + kem: new DhkemX25519HkdfSha256(), + kdf: new HkdfSha256(), + aead: AeadId.Aes128Gcm, + }); + + const rkp = await suite.generateKeyPair(); + + const sender = await suite.createSenderContext({ + recipientPublicKey: rkp.publicKey, + }); + + const recipient = await suite.createRecipientContext({ + recipientKey: rkp, + enc: sender.enc, + }); + + // encrypt + const ct = await sender.seal( + new TextEncoder().encode("my-secret-message"), + ); + + // decrypt + const pt = await recipient.open(ct); + + // assert + assertEquals(new TextDecoder().decode(pt), "my-secret-message"); + }); + it("should work normally with importKey('jwk')", async () => { // setup const suite = new CipherSuite({ @@ -559,7 +697,7 @@ describe("CipherSuite", () => { }); describe("A README example of Base mode (KemId.DhkemX448HkdfSha256/KdfId.HkdfSha512)", () => { - it("should work normally", async () => { + it("should work normally with ids", async () => { // setup const suite = new CipherSuite({ kem: KemId.DhkemX448HkdfSha512, @@ -590,6 +728,37 @@ describe("CipherSuite", () => { assertEquals(new TextDecoder().decode(pt), "my-secret-message"); }); + it("should work normally with instances", async () => { + // setup + const suite = new CipherSuite({ + kem: new DhkemX448HkdfSha512(), + kdf: new HkdfSha512(), + aead: AeadId.Aes256Gcm, + }); + + const rkp = await suite.generateKeyPair(); + + const sender = await suite.createSenderContext({ + recipientPublicKey: rkp.publicKey, + }); + + const recipient = await suite.createRecipientContext({ + recipientKey: rkp, + enc: sender.enc, + }); + + // encrypt + const ct = await sender.seal( + new TextEncoder().encode("my-secret-message"), + ); + + // decrypt + const pt = await recipient.open(ct); + + // assert + assertEquals(new TextDecoder().decode(pt), "my-secret-message"); + }); + it("should work normally with importKey('jwk')", async () => { // setup const suite = new CipherSuite({