diff --git a/src/aeadKeys/aesGcmKey.ts b/src/aeadKeys/aesGcmKey.ts index b7f2587b4..14c13cb1c 100644 --- a/src/aeadKeys/aesGcmKey.ts +++ b/src/aeadKeys/aesGcmKey.ts @@ -1,20 +1,21 @@ import type { AeadKey } from "../interfaces/aeadKey.ts"; +import { Algorithm } from "../algorithm.ts"; import { Aead } from "../identifiers.ts"; import * as consts from "../consts.ts"; -export class AesGcmKey implements AeadKey { +export class AesGcmKey extends Algorithm implements AeadKey { public readonly id: Aead = Aead.Aes128Gcm; public readonly keySize: number = 0; public readonly nonceSize: number = 0; public readonly tagSize: number = 0; private _rawKey: ArrayBuffer; private _key: CryptoKey | undefined = undefined; - private _api: SubtleCrypto; + // private _api: SubtleCrypto; - public constructor(key: ArrayBuffer, api: SubtleCrypto) { + public constructor(key: ArrayBuffer) { + super(); this._rawKey = key; - this._api = api; } public async seal( @@ -22,6 +23,7 @@ export class AesGcmKey implements AeadKey { data: ArrayBuffer, aad: ArrayBuffer, ): Promise { + this.checkInit(); if (this._key === undefined) { this._key = await this.importKey(this._rawKey); (new Uint8Array(this._rawKey)).fill(0); @@ -31,7 +33,11 @@ export class AesGcmKey implements AeadKey { iv: iv, additionalData: aad, }; - const ct: ArrayBuffer = await this._api.encrypt(alg, this._key, data); + const ct: ArrayBuffer = await (this._api as SubtleCrypto).encrypt( + alg, + this._key, + data, + ); return ct; } @@ -40,6 +46,7 @@ export class AesGcmKey implements AeadKey { data: ArrayBuffer, aad: ArrayBuffer, ): Promise { + this.checkInit(); if (this._key === undefined) { this._key = await this.importKey(this._rawKey); (new Uint8Array(this._rawKey)).fill(0); @@ -49,12 +56,16 @@ export class AesGcmKey implements AeadKey { iv: iv, additionalData: aad, }; - const pt: ArrayBuffer = await this._api.decrypt(alg, this._key, data); + const pt: ArrayBuffer = await (this._api as SubtleCrypto).decrypt( + alg, + this._key, + data, + ); return pt; } private async importKey(key: ArrayBuffer): Promise { - return await this._api.importKey( + return await (this._api as SubtleCrypto).importKey( "raw", key, { name: "AES-GCM" }, diff --git a/src/aeadKeys/chacha20Poly1305Key.ts b/src/aeadKeys/chacha20Poly1305Key.ts index a4cab0451..f3d6aab34 100644 --- a/src/aeadKeys/chacha20Poly1305Key.ts +++ b/src/aeadKeys/chacha20Poly1305Key.ts @@ -1,10 +1,10 @@ import { chacha20_poly1305 } from "npm:@noble/ciphers@0.1.4/chacha"; +import { Algorithm } from "../algorithm.ts"; import type { AeadKey } from "../interfaces/aeadKey.ts"; - import { Aead } from "../identifiers.ts"; -export class Chacha20Poly1305Key implements AeadKey { +export class Chacha20Poly1305Key extends Algorithm implements AeadKey { public readonly id: Aead = Aead.Chacha20Poly1305; public readonly keySize: number = 32; public readonly nonceSize: number = 12; @@ -12,6 +12,7 @@ export class Chacha20Poly1305Key implements AeadKey { private _key: Uint8Array; public constructor(key: ArrayBuffer) { + super(); this._key = new Uint8Array(key); } diff --git a/src/algorithm.ts b/src/algorithm.ts new file mode 100644 index 000000000..536d7a900 --- /dev/null +++ b/src/algorithm.ts @@ -0,0 +1,36 @@ +import * as consts from "./consts.ts"; + +export class AlgorithmBase { + protected _api: SubtleCrypto | undefined = undefined; + + constructor() {} + + protected checkInit(): void { + if (typeof this._api === "undefined") { + throw new Error("Not initialized. Call init()"); + } + } +} + +export class Algorithm extends AlgorithmBase { + constructor() { + super(); + } + + public init(api: SubtleCrypto): void { + this._api = api; + } +} + +export class KdfAlgorithm extends AlgorithmBase { + protected _suiteId: Uint8Array = consts.EMPTY; + + constructor() { + super(); + } + + public init(api: SubtleCrypto, suiteId: Uint8Array): void { + this._api = api; + this._suiteId = suiteId; + } +} diff --git a/src/cipherSuite.ts b/src/cipherSuite.ts index 3a1665973..60d3904b4 100644 --- a/src/cipherSuite.ts +++ b/src/cipherSuite.ts @@ -194,7 +194,9 @@ export class CipherSuite { */ public async createAeadKey(key: ArrayBuffer): Promise { await this.setup(); - return createAeadKey(this.aead, key, this._api as SubtleCrypto); + const ret = createAeadKey(this.aead, key); + ret.init(this._api as SubtleCrypto); + return ret; } /** @@ -534,31 +536,46 @@ export class CipherSuite { } private createKemContext(): KemInterface { + let ret: KemInterface; switch (this.kem) { case Kem.DhkemP256HkdfSha256: - return new DhkemP256HkdfSha256(this._api as SubtleCrypto); + ret = new DhkemP256HkdfSha256(); + break; case Kem.DhkemP384HkdfSha384: - return new DhkemP384HkdfSha384(this._api as SubtleCrypto); + ret = new DhkemP384HkdfSha384(); + break; case Kem.DhkemP521HkdfSha512: - return new DhkemP521HkdfSha512(this._api as SubtleCrypto); + ret = new DhkemP521HkdfSha512(); + break; case Kem.DhkemX25519HkdfSha256: - return new DhkemX25519HkdfSha256(this._api as SubtleCrypto); + ret = new DhkemX25519HkdfSha256(); + break; case Kem.DhkemX448HkdfSha512: - return new DhkemX448HkdfSha512(this._api as SubtleCrypto); + ret = new DhkemX448HkdfSha512(); + break; default: - return new DhkemSecp256K1HkdfSha256(this._api as SubtleCrypto); + ret = new DhkemSecp256K1HkdfSha256(); + break; } + ret.init(this._api as SubtleCrypto); + return ret; } private createKdfContext(): KdfInterface { + let ret: KdfInterface; switch (this.kdf) { case Kdf.HkdfSha256: - return new HkdfSha256(this._api as SubtleCrypto, this._suiteId); + ret = new HkdfSha256(); + break; case Kdf.HkdfSha384: - return new HkdfSha384(this._api as SubtleCrypto, this._suiteId); + ret = new HkdfSha384(); + break; default: // case Kdf.HkdfSha512: - return new HkdfSha512(this._api as SubtleCrypto, this._suiteId); + ret = new HkdfSha512(); + break; } + ret.init(this._api as SubtleCrypto, this._suiteId); + return ret; } } diff --git a/src/encryptionContext.ts b/src/encryptionContext.ts index 03be88348..49b52d778 100644 --- a/src/encryptionContext.ts +++ b/src/encryptionContext.ts @@ -60,7 +60,8 @@ export class EncryptionContext extends ExporterContext { break; } - const key = createAeadKey(this._aead, params.key, this._api); + const key = createAeadKey(this._aead, params.key); + key.init(this._api); this._f = { key: key, @@ -97,7 +98,8 @@ export class EncryptionContext extends ExporterContext { await this.export(nonceSeed, this._nN), ); const key = await this.export(keySeed, this._nK); - this._r.key = createAeadKey(this._aead, key, this._api); + this._r.key = createAeadKey(this._aead, key); + this._r.key.init(this._api); this._r.seq = 0; } catch (e: unknown) { this._r.baseNonce = consts.EMPTY; @@ -109,13 +111,12 @@ export class EncryptionContext extends ExporterContext { export function createAeadKey( aead: Aead, key: ArrayBuffer, - api: SubtleCrypto, ): AeadKey { switch (aead) { case Aead.Aes128Gcm: - return new Aes128GcmKey(key, api); + return new Aes128GcmKey(key); case Aead.Aes256Gcm: - return new Aes256GcmKey(key, api); + return new Aes256GcmKey(key); case Aead.Chacha20Poly1305: return new Chacha20Poly1305Key(key); default: diff --git a/src/exporterContext.ts b/src/exporterContext.ts index 5dece7f4a..1b31f425a 100644 --- a/src/exporterContext.ts +++ b/src/exporterContext.ts @@ -2,13 +2,11 @@ import type { Encapsulator } from "./interfaces/encapsulator.ts"; import type { EncryptionContextInterface } from "./interfaces/encryptionContextInterface.ts"; import type { KdfInterface } from "./interfaces/kdfInterface.ts"; -import { WebCrypto } from "./webCrypto.ts"; - import * as consts from "./consts.ts"; import * as errors from "./errors.ts"; -export class ExporterContext extends WebCrypto - implements EncryptionContextInterface { +export class ExporterContext implements EncryptionContextInterface { + protected _api: SubtleCrypto; protected readonly exporterSecret: ArrayBuffer; private _kdf: KdfInterface; @@ -17,7 +15,7 @@ export class ExporterContext extends WebCrypto kdf: KdfInterface, exporterSecret: ArrayBuffer, ) { - super(api); + this._api = api; this._kdf = kdf; this.exporterSecret = exporterSecret; } diff --git a/src/interfaces/aeadKey.ts b/src/interfaces/aeadKey.ts index e22c49b9e..8df0119bd 100644 --- a/src/interfaces/aeadKey.ts +++ b/src/interfaces/aeadKey.ts @@ -13,6 +13,11 @@ export interface AeadKey { /** The length in bytes of an AEAD authentication tag (Nt). */ readonly tagSize: number; + /** + * Initializes the key by setting the SubtleCrypto. + */ + init(api: SubtleCrypto): void; + /** * Encrypts data with initial vector and additional authenticated data. */ diff --git a/src/interfaces/kdfInterface.ts b/src/interfaces/kdfInterface.ts index d89209541..81f866234 100644 --- a/src/interfaces/kdfInterface.ts +++ b/src/interfaces/kdfInterface.ts @@ -16,6 +16,8 @@ export interface KdfInterface { len: number, ): Uint8Array; + init(api: SubtleCrypto, suiteId: Uint8Array): void; + extract( salt: ArrayBuffer, ikm: ArrayBuffer, diff --git a/src/interfaces/kemInterface.ts b/src/interfaces/kemInterface.ts index 722692e5c..98f2d0845 100644 --- a/src/interfaces/kemInterface.ts +++ b/src/interfaces/kemInterface.ts @@ -18,6 +18,8 @@ export interface KemInterface { /** The length in bytes of an encoded private key for this KEM (Nsk). */ readonly privateKeySize: number; + init(api: SubtleCrypto): void; + /** * Generates a key pair. */ diff --git a/src/interfaces/kemPrimitives.ts b/src/interfaces/kemPrimitives.ts index bec11e940..c0bd3b231 100644 --- a/src/interfaces/kemPrimitives.ts +++ b/src/interfaces/kemPrimitives.ts @@ -1,4 +1,6 @@ export interface KemPrimitives { + init(api: SubtleCrypto): void; + serializePublicKey(key: CryptoKey): Promise; deserializePublicKey(key: ArrayBuffer): Promise; diff --git a/src/kdfs/hkdf.ts b/src/kdfs/hkdf.ts index 1521e005a..390be55fc 100644 --- a/src/kdfs/hkdf.ts +++ b/src/kdfs/hkdf.ts @@ -5,33 +5,36 @@ import { sha384, sha512 } from "npm:@noble/hashes@1.3.1/sha512"; import type { KdfInterface } from "../interfaces/kdfInterface.ts"; import { Kdf } from "../identifiers.ts"; -import { WebCrypto } from "../webCrypto.ts"; +import { KdfAlgorithm } from "../algorithm.ts"; import * as consts from "../consts.ts"; -export class Hkdf extends WebCrypto implements KdfInterface { +export class Hkdf extends KdfAlgorithm implements KdfInterface { public readonly id: Kdf = Kdf.HkdfSha256; public readonly hashSize: number = 0; - protected readonly suiteId: Uint8Array; + // protected readonly suiteId: Uint8Array; protected readonly algHash: HmacKeyGenParams = { name: "HMAC", hash: "SHA-256", length: 256, }; - constructor(api: SubtleCrypto, suiteId: Uint8Array) { - super(api); - this.suiteId = suiteId; + // constructor(api: SubtleCrypto, suiteId: Uint8Array) { + // super(api); + // this._suiteId = _suiteId; + // } + constructor() { + super(); } public buildLabeledIkm(label: Uint8Array, ikm: Uint8Array): Uint8Array { const ret = new Uint8Array( - 7 + this.suiteId.byteLength + label.byteLength + ikm.byteLength, + 7 + this._suiteId.byteLength + label.byteLength + ikm.byteLength, ); ret.set(consts.HPKE_VERSION, 0); - ret.set(this.suiteId, 7); - ret.set(label, 7 + this.suiteId.byteLength); - ret.set(ikm, 7 + this.suiteId.byteLength + label.byteLength); + ret.set(this._suiteId, 7); + ret.set(label, 7 + this._suiteId.byteLength); + ret.set(ikm, 7 + this._suiteId.byteLength + label.byteLength); return ret; } @@ -41,13 +44,13 @@ export class Hkdf extends WebCrypto implements KdfInterface { len: number, ): Uint8Array { const ret = new Uint8Array( - 9 + this.suiteId.byteLength + label.byteLength + info.byteLength, + 9 + this._suiteId.byteLength + label.byteLength + info.byteLength, ); ret.set(new Uint8Array([0, len]), 0); ret.set(consts.HPKE_VERSION, 2); - ret.set(this.suiteId, 9); - ret.set(label, 9 + this.suiteId.byteLength); - ret.set(info, 9 + this.suiteId.byteLength + label.byteLength); + ret.set(this._suiteId, 9); + ret.set(label, 9 + this._suiteId.byteLength); + ret.set(info, 9 + this._suiteId.byteLength + label.byteLength); return ret; } @@ -55,6 +58,7 @@ export class Hkdf extends WebCrypto implements KdfInterface { salt: ArrayBuffer, ikm: ArrayBuffer, ): Promise { + this.checkInit(); if (salt.byteLength === 0) { salt = new ArrayBuffer(this.hashSize); } @@ -83,10 +87,16 @@ export class Hkdf extends WebCrypto implements KdfInterface { ); } } - const key = await this._api.importKey("raw", salt, this.algHash, false, [ - "sign", - ]); - return await this._api.sign("HMAC", key, ikm); + const key = await (this._api as SubtleCrypto).importKey( + "raw", + salt, + this.algHash, + false, + [ + "sign", + ], + ); + return await (this._api as SubtleCrypto).sign("HMAC", key, ikm); } public async expand( @@ -94,9 +104,16 @@ export class Hkdf extends WebCrypto implements KdfInterface { info: ArrayBuffer, len: number, ): Promise { - const key = await this._api.importKey("raw", prk, this.algHash, false, [ - "sign", - ]); + this.checkInit(); + const key = await (this._api as SubtleCrypto).importKey( + "raw", + prk, + this.algHash, + false, + [ + "sign", + ], + ); const okm = new ArrayBuffer(len); const p = new Uint8Array(okm); @@ -115,7 +132,7 @@ export class Hkdf extends WebCrypto implements KdfInterface { tmp.set(mid, prev.length); tmp.set(tail, prev.length + mid.length); prev = new Uint8Array( - await this._api.sign( + await (this._api as SubtleCrypto).sign( "HMAC", key, tmp.slice(0, prev.length + mid.length + 1), @@ -138,14 +155,15 @@ export class Hkdf extends WebCrypto implements KdfInterface { info: ArrayBuffer, len: number, ): Promise { - const baseKey = await this._api.importKey( + this.checkInit(); + const baseKey = await (this._api as SubtleCrypto).importKey( "raw", ikm, "HKDF", false, consts.KEM_USAGES, ); - return await this._api.deriveBits( + return await (this._api as SubtleCrypto).deriveBits( { name: "HKDF", hash: this.algHash.hash, diff --git a/src/kems/dhkem.ts b/src/kems/dhkem.ts index 0502af1cf..4a5133973 100644 --- a/src/kems/dhkem.ts +++ b/src/kems/dhkem.ts @@ -4,6 +4,7 @@ import type { KemPrimitives } from "../interfaces/kemPrimitives.ts"; import type { SenderContextParams } from "../interfaces/senderContextParams.ts"; import type { RecipientContextParams } from "../interfaces/recipientContextParams.ts"; +import { Algorithm } from "../algorithm.ts"; import { Ec } from "./dhkemPrimitives/ec.ts"; import { Secp256K1 } from "./dhkemPrimitives/secp256k1.ts"; import { X25519 } from "./dhkemPrimitives/x25519.ts"; @@ -11,26 +12,34 @@ import { X448 } from "./dhkemPrimitives/x448.ts"; import { Kem } from "../identifiers.ts"; import { HkdfSha256, HkdfSha384, HkdfSha512 } from "../kdfs/hkdf.ts"; import { concat, concat3, i2Osp, isCryptoKeyPair } from "../utils/misc.ts"; -import { WebCrypto } from "../webCrypto.ts"; import * as consts from "../consts.ts"; import * as errors from "../errors.ts"; -export class Dhkem extends WebCrypto implements KemInterface { +export class Dhkem extends Algorithm implements KemInterface { public readonly id: Kem = Kem.DhkemP256HkdfSha256; public readonly secretSize: number = 0; public readonly encSize: number = 0; public readonly publicKeySize: number = 0; public readonly privateKeySize: number = 0; - private _prim: KemPrimitives; - private _kdf: KdfInterface; + protected _prim: KemPrimitives; + protected _kdf: KdfInterface; - constructor(api: SubtleCrypto, prim: KemPrimitives, kdf: KdfInterface) { - super(api); + constructor(prim: KemPrimitives, kdf: KdfInterface) { + super(); this._prim = prim; this._kdf = kdf; } + public init(api: SubtleCrypto): void { + super.init(api); + const suiteId = new Uint8Array(consts.SUITE_ID_HEADER_KEM); + suiteId.set(i2Osp(this.id, 2), 3); + this._prim.init(api); + this._kdf.init(api, suiteId); + super.init(api); + } + public async generateKeyPair(): Promise { try { return await this._prim.generateKeyPair(); @@ -206,12 +215,10 @@ export class DhkemP256HkdfSha256 extends Dhkem implements KemInterface { public readonly publicKeySize: number = 65; public readonly privateKeySize: number = 32; - constructor(api: SubtleCrypto) { - const suiteId = new Uint8Array(consts.SUITE_ID_HEADER_KEM); - suiteId.set(i2Osp(Kem.DhkemP256HkdfSha256, 2), 3); - const kdf = new HkdfSha256(api, suiteId); - const prim = new Ec(Kem.DhkemP256HkdfSha256, kdf, api); - super(api, prim, kdf); + constructor() { + const kdf = new HkdfSha256(); + const prim = new Ec(Kem.DhkemP256HkdfSha256, kdf); + super(prim, kdf); } } @@ -222,12 +229,10 @@ export class DhkemP384HkdfSha384 extends Dhkem implements KemInterface { public readonly publicKeySize: number = 97; public readonly privateKeySize: number = 48; - constructor(api: SubtleCrypto) { - const suiteId = new Uint8Array(consts.SUITE_ID_HEADER_KEM); - suiteId.set(i2Osp(Kem.DhkemP384HkdfSha384, 2), 3); - const kdf = new HkdfSha384(api, suiteId); - const prim = new Ec(Kem.DhkemP384HkdfSha384, kdf, api); - super(api, prim, kdf); + constructor() { + const kdf = new HkdfSha384(); + const prim = new Ec(Kem.DhkemP384HkdfSha384, kdf); + super(prim, kdf); } } @@ -238,12 +243,10 @@ export class DhkemP521HkdfSha512 extends Dhkem implements KemInterface { public readonly publicKeySize: number = 133; public readonly privateKeySize: number = 64; - constructor(api: SubtleCrypto) { - const suiteId = new Uint8Array(consts.SUITE_ID_HEADER_KEM); - suiteId.set(i2Osp(Kem.DhkemP521HkdfSha512, 2), 3); - const kdf = new HkdfSha512(api, suiteId); - const prim = new Ec(Kem.DhkemP521HkdfSha512, kdf, api); - super(api, prim, kdf); + constructor() { + const kdf = new HkdfSha512(); + const prim = new Ec(Kem.DhkemP521HkdfSha512, kdf); + super(prim, kdf); } } @@ -254,28 +257,24 @@ export class DhkemSecp256K1HkdfSha256 extends Dhkem implements KemInterface { public readonly publicKeySize: number = 65; public readonly privateKeySize: number = 32; - constructor(api: SubtleCrypto) { - const suiteId = new Uint8Array(consts.SUITE_ID_HEADER_KEM); - suiteId.set(i2Osp(Kem.DhkemSecp256K1HkdfSha256, 2), 3); - const kdf = new HkdfSha256(api, suiteId); + constructor() { + const kdf = new HkdfSha256(); const prim = new Secp256K1(kdf); - super(api, prim, kdf); + super(prim, kdf); } } -export class DhkemX25519HkdfSha256 extends Dhkem implements KemInterface { +export class DhkemX25519HkdfSha256 extends Dhkem { public readonly id: Kem = Kem.DhkemX25519HkdfSha256; public readonly secretSize: number = 32; public readonly encSize: number = 32; public readonly publicKeySize: number = 32; public readonly privateKeySize: number = 32; - constructor(api: SubtleCrypto) { - const suiteId = new Uint8Array(consts.SUITE_ID_HEADER_KEM); - suiteId.set(i2Osp(Kem.DhkemX25519HkdfSha256, 2), 3); - const kdf = new HkdfSha256(api, suiteId); + constructor() { + const kdf = new HkdfSha256(); const prim = new X25519(kdf); - super(api, prim, kdf); + super(prim, kdf); } } @@ -286,11 +285,9 @@ export class DhkemX448HkdfSha512 extends Dhkem implements KemInterface { public readonly publicKeySize: number = 56; public readonly privateKeySize: number = 56; - constructor(api: SubtleCrypto) { - const suiteId = new Uint8Array(consts.SUITE_ID_HEADER_KEM); - suiteId.set(i2Osp(Kem.DhkemX448HkdfSha512, 2), 3); - const kdf = new HkdfSha512(api, suiteId); + constructor() { + const kdf = new HkdfSha512(); const prim = new X448(kdf); - super(api, prim, kdf); + super(prim, kdf); } } diff --git a/src/kems/dhkemPrimitives/ec.ts b/src/kems/dhkemPrimitives/ec.ts index 3659e781c..fdf3b4c83 100644 --- a/src/kems/dhkemPrimitives/ec.ts +++ b/src/kems/dhkemPrimitives/ec.ts @@ -1,6 +1,7 @@ import type { KemPrimitives } from "../../interfaces/kemPrimitives.ts"; import type { KdfInterface } from "../../interfaces/kdfInterface.ts"; +import { Algorithm } from "../../algorithm.ts"; import { Kem } from "../../identifiers.ts"; import { Bignum } from "../../utils/bignum.ts"; @@ -116,9 +117,8 @@ const PKCS8_ALG_ID_P_521 = new Uint8Array([ 66, ]); -export class Ec implements KemPrimitives { +export class Ec extends Algorithm implements KemPrimitives { private _hkdf: KdfInterface; - private _api: SubtleCrypto; private _alg: EcKeyGenParams; private _nPk: number; private _nSk: number; @@ -129,9 +129,9 @@ export class Ec implements KemPrimitives { private _bitmask: number; private _pkcs8AlgId: Uint8Array; - constructor(kem: Kem, hkdf: KdfInterface, api: SubtleCrypto) { + constructor(kem: Kem, hkdf: KdfInterface) { + super(); this._hkdf = hkdf; - this._api = api; switch (kem) { case Kem.DhkemP256HkdfSha256: this._alg = { name: "ECDH", namedCurve: "P-256" }; @@ -165,7 +165,8 @@ export class Ec implements KemPrimitives { } public async serializePublicKey(key: CryptoKey): Promise { - const ret = await this._api.exportKey("raw", key); + this.checkInit(); + const ret = await (this._api as SubtleCrypto).exportKey("raw", key); // const ret = (await this._api.exportKey('spki', key)).slice(24); if (ret.byteLength !== this._nPk) { throw new Error("Invalid public key for the ciphersuite"); @@ -174,11 +175,18 @@ export class Ec implements KemPrimitives { } public async deserializePublicKey(key: ArrayBuffer): Promise { + this.checkInit(); if (key.byteLength !== this._nPk) { throw new Error("Invalid public key for the ciphersuite"); } try { - return await this._api.importKey("raw", key, this._alg, true, []); + return await (this._api as SubtleCrypto).importKey( + "raw", + key, + this._alg, + true, + [], + ); } catch (_e: unknown) { throw new Error("Invalid public key for the ciphersuite"); } @@ -189,6 +197,7 @@ export class Ec implements KemPrimitives { key: ArrayBuffer | JsonWebKey, isPublic: boolean, ): Promise { + this.checkInit(); if (format === "raw") { return await this._importRawKey(key as ArrayBuffer, isPublic); } @@ -212,13 +221,19 @@ export class Ec implements KemPrimitives { try { if (isPublic) { // return await this._api.importKey(format, key, this._alg, true, consts.KEM_USAGES); - return await this._api.importKey("raw", key, this._alg, true, []); + return await (this._api as SubtleCrypto).importKey( + "raw", + key, + this._alg, + true, + [], + ); } const k = new Uint8Array(key); const pkcs8Key = new Uint8Array(this._pkcs8AlgId.length + k.length); pkcs8Key.set(this._pkcs8AlgId, 0); pkcs8Key.set(k, this._pkcs8AlgId.length); - return await this._api.importKey( + return await (this._api as SubtleCrypto).importKey( "pkcs8", pkcs8Key, this._alg, @@ -241,12 +256,18 @@ export class Ec implements KemPrimitives { if (typeof key.d !== "undefined") { throw new Error("Invalid key: `d` should not be set"); } - return await this._api.importKey("jwk", key, this._alg, true, []); + return await (this._api as SubtleCrypto).importKey( + "jwk", + key, + this._alg, + true, + [], + ); } if (typeof key.d === "undefined") { throw new Error("Invalid key: `d` not found"); } - return await this._api.importKey( + return await (this._api as SubtleCrypto).importKey( "jwk", key, this._alg, @@ -256,18 +277,31 @@ export class Ec implements KemPrimitives { } public async derivePublicKey(key: CryptoKey): Promise { - const jwk = await this._api.exportKey("jwk", key); + this.checkInit(); + const jwk = await (this._api as SubtleCrypto).exportKey("jwk", key); delete jwk["d"]; delete jwk["key_ops"]; // return await this._api.importKey('jwk', jwk, this._alg, true, consts.KEM_USAGES); - return await this._api.importKey("jwk", jwk, this._alg, true, []); + return await (this._api as SubtleCrypto).importKey( + "jwk", + jwk, + this._alg, + true, + [], + ); } public async generateKeyPair(): Promise { - return await this._api.generateKey(this._alg, true, consts.KEM_USAGES); + this.checkInit(); + return await (this._api as SubtleCrypto).generateKey( + this._alg, + true, + consts.KEM_USAGES, + ); } public async deriveKeyPair(ikm: ArrayBuffer): Promise { + this.checkInit(); const dkpPrk = await this._hkdf.labeledExtract( consts.EMPTY, consts.LABEL_DKP_PRK, @@ -292,7 +326,7 @@ export class Ec implements KemPrimitives { const pkcs8Key = new Uint8Array(this._pkcs8AlgId.length + bn.val().length); pkcs8Key.set(this._pkcs8AlgId, 0); pkcs8Key.set(bn.val(), this._pkcs8AlgId.length); - const sk = await this._api.importKey( + const sk = await (this._api as SubtleCrypto).importKey( "pkcs8", pkcs8Key, this._alg, @@ -307,7 +341,8 @@ export class Ec implements KemPrimitives { } public async dh(sk: CryptoKey, pk: CryptoKey): Promise { - const bits = await this._api.deriveBits( + this.checkInit(); + const bits = await (this._api as SubtleCrypto).deriveBits( { name: "ECDH", public: pk, diff --git a/src/kems/dhkemPrimitives/secp256k1.ts b/src/kems/dhkemPrimitives/secp256k1.ts index e2ffaeb3e..503cd8520 100644 --- a/src/kems/dhkemPrimitives/secp256k1.ts +++ b/src/kems/dhkemPrimitives/secp256k1.ts @@ -3,18 +3,20 @@ import * as secp from "npm:@noble/secp256k1@1.7.1"; import type { KemPrimitives } from "../../interfaces/kemPrimitives.ts"; import type { KdfInterface } from "../../interfaces/kdfInterface.ts"; +import { Algorithm } from "../../algorithm.ts"; import { XCryptoKey } from "../../xCryptoKey.ts"; import * as consts from "../../consts.ts"; const ALG_NAME = "ECDH"; -export class Secp256K1 implements KemPrimitives { +export class Secp256K1 extends Algorithm implements KemPrimitives { private _hkdf: KdfInterface; private _nPk: number; private _nSk: number; constructor(hkdf: KdfInterface) { + super(); this._hkdf = hkdf; this._nPk = 65; this._nSk = 32; diff --git a/src/kems/dhkemPrimitives/x25519.ts b/src/kems/dhkemPrimitives/x25519.ts index c6662a97f..e3ca8e18e 100644 --- a/src/kems/dhkemPrimitives/x25519.ts +++ b/src/kems/dhkemPrimitives/x25519.ts @@ -3,6 +3,7 @@ import { ed25519, x25519 } from "npm:@noble/curves@1.1.0/ed25519"; import type { KemPrimitives } from "../../interfaces/kemPrimitives.ts"; import type { KdfInterface } from "../../interfaces/kdfInterface.ts"; +import { Algorithm } from "../../algorithm.ts"; import { XCryptoKey } from "../../xCryptoKey.ts"; import * as consts from "../../consts.ts"; @@ -10,12 +11,13 @@ import { base64UrlToBytes } from "../../utils/misc.ts"; const ALG_NAME = "X25519"; -export class X25519 implements KemPrimitives { +export class X25519 extends Algorithm implements KemPrimitives { private _hkdf: KdfInterface; private _nPk: number; private _nSk: number; constructor(hkdf: KdfInterface) { + super(); this._hkdf = hkdf; this._nPk = 32; this._nSk = 32; diff --git a/src/kems/dhkemPrimitives/x448.ts b/src/kems/dhkemPrimitives/x448.ts index b6113009c..8e5d08d4e 100644 --- a/src/kems/dhkemPrimitives/x448.ts +++ b/src/kems/dhkemPrimitives/x448.ts @@ -3,6 +3,7 @@ import { ed448, x448 } from "npm:@noble/curves@1.1.0/ed448"; import type { KemPrimitives } from "../../interfaces/kemPrimitives.ts"; import type { KdfInterface } from "../../interfaces/kdfInterface.ts"; +import { Algorithm } from "../../algorithm.ts"; import { XCryptoKey } from "../../xCryptoKey.ts"; import * as consts from "../../consts.ts"; @@ -10,12 +11,13 @@ import { base64UrlToBytes } from "../../utils/misc.ts"; const ALG_NAME = "X448"; -export class X448 implements KemPrimitives { +export class X448 extends Algorithm implements KemPrimitives { private _hkdf: KdfInterface; private _nPk: number; private _nSk: number; constructor(hkdf: KdfInterface) { + super(); this._hkdf = hkdf; this._nPk = 56; this._nSk = 56; diff --git a/src/webCrypto.ts b/src/webCrypto.ts index d4991538e..ad5dbdf8a 100644 --- a/src/webCrypto.ts +++ b/src/webCrypto.ts @@ -2,13 +2,6 @@ import { isBrowser, isCloudflareWorkers } from "./utils/misc.ts"; import * as errors from "./errors.ts"; -export class WebCrypto { - protected _api: SubtleCrypto; - constructor(api: SubtleCrypto) { - this._api = api; - } -} - export async function loadCrypto(): Promise { if (isBrowser() || isCloudflareWorkers()) { if (globalThis.crypto !== undefined) { diff --git a/test/conformanceTester.ts b/test/conformanceTester.ts index 506a0e15d..99dbe167b 100644 --- a/test/conformanceTester.ts +++ b/test/conformanceTester.ts @@ -6,16 +6,20 @@ import type { TestVector } from "./testVector.ts"; import { CipherSuite } from "../src/cipherSuite.ts"; import { Aead, Kdf, Kem } from "../src/identifiers.ts"; -import { WebCrypto } from "../src/webCrypto.ts"; import { loadSubtleCrypto } from "../src/webCrypto.ts"; import * as errors from "../src/errors.ts"; import { hexStringToBytes, kemToKeyGenAlgorithm } from "./utils.ts"; -export class ConformanceTester extends WebCrypto { +export class ConformanceTester { + protected _api: SubtleCrypto; private _count = 0; + constructor(api: SubtleCrypto) { + this._api = api; + } + public count(): number { return this._count; } diff --git a/test/encryptionContext.test.ts b/test/encryptionContext.test.ts index 88f1748e0..017bec07d 100644 --- a/test/encryptionContext.test.ts +++ b/test/encryptionContext.test.ts @@ -25,7 +25,8 @@ describe("constructor", () => { suiteId.set(i2Osp(Kem.DhkemP256HkdfSha256, 2), 4); suiteId.set(i2Osp(Kdf.HkdfSha256, 2), 6); suiteId.set(i2Osp(Aead.Aes128Gcm, 2), 8); - const kdf = new HkdfSha256(api, suiteId); + const kdf = new HkdfSha256(); + kdf.init(api, suiteId); const key = DUMMY_BYTES_16.buffer; const baseNonce = DUMMY_BYTES_12; @@ -54,7 +55,8 @@ describe("constructor", () => { suiteId.set(i2Osp(Kem.DhkemP256HkdfSha256, 2), 4); suiteId.set(i2Osp(Kdf.HkdfSha256, 2), 6); suiteId.set(i2Osp(Aead.Aes128Gcm, 2), 8); - const kdf = new HkdfSha256(api, suiteId); + const kdf = new HkdfSha256(); + kdf.init(api, suiteId); const key = DUMMY_BYTES_16.buffer; const baseNonce = DUMMY_BYTES_12; @@ -446,7 +448,8 @@ describe("createRecipientContext", () => { suiteId.set(i2Osp(Kem.DhkemP256HkdfSha256, 2), 4); suiteId.set(i2Osp(Kdf.HkdfSha256, 2), 6); suiteId.set(i2Osp(Aead.Aes128Gcm, 2), 8); - const kdf = new HkdfSha256(api, suiteId); + const kdf = new HkdfSha256(); + kdf.init(api, suiteId); const params = { aead: Aead.Aes128Gcm, nK: 16, @@ -522,7 +525,8 @@ describe("setupBidirectional", () => { suiteId.set(i2Osp(Kem.DhkemP256HkdfSha256, 2), 4); suiteId.set(i2Osp(Kdf.HkdfSha256, 2), 6); suiteId.set(i2Osp(Aead.Aes128Gcm, 2), 8); - const kdf = new HkdfSha256(api, suiteId); + const kdf = new HkdfSha256(); + kdf.init(api, suiteId); const key = DUMMY_BYTES_16.buffer; const baseNonce = DUMMY_BYTES_12; @@ -557,7 +561,8 @@ describe("setupBidirectional", () => { suiteId.set(i2Osp(Kem.DhkemP256HkdfSha256, 2), 4); suiteId.set(i2Osp(Kdf.HkdfSha256, 2), 6); suiteId.set(i2Osp(Aead.Aes128Gcm, 2), 8); - const kdf = new HkdfSha256(api, suiteId); + const kdf = new HkdfSha256(); + kdf.init(api, suiteId); const key = DUMMY_BYTES_16.buffer; const baseNonce = DUMMY_BYTES_12; diff --git a/test/kdfContext.test.ts b/test/kdfContext.test.ts index d75e6de82..825a1a4fa 100644 --- a/test/kdfContext.test.ts +++ b/test/kdfContext.test.ts @@ -20,7 +20,8 @@ describe("extract/expand", () => { suiteId.set(i2Osp(Kem.DhkemP256HkdfSha256, 2), 4); suiteId.set(i2Osp(Kdf.HkdfSha256, 2), 6); suiteId.set(i2Osp(Aead.Aes128Gcm, 2), 8); - const kdf = new HkdfSha256(api, suiteId); + const kdf = new HkdfSha256(); + kdf.init(api, suiteId); const salt = new Uint8Array(32); cryptoApi.getRandomValues(salt); @@ -46,7 +47,8 @@ describe("extract/expand", () => { suiteId.set(i2Osp(Kem.DhkemP384HkdfSha384, 2), 4); suiteId.set(i2Osp(Kdf.HkdfSha384, 2), 6); suiteId.set(i2Osp(Aead.Aes128Gcm, 2), 8); - const kdf = new HkdfSha384(api, suiteId); + const kdf = new HkdfSha384(); + kdf.init(api, suiteId); const salt = new Uint8Array(48); cryptoApi.getRandomValues(salt); @@ -72,7 +74,8 @@ describe("extract/expand", () => { suiteId.set(i2Osp(Kem.DhkemP521HkdfSha512, 2), 4); suiteId.set(i2Osp(Kdf.HkdfSha512, 2), 6); suiteId.set(i2Osp(Aead.Aes128Gcm, 2), 8); - const kdf = new HkdfSha512(api, suiteId); + const kdf = new HkdfSha512(); + kdf.init(api, suiteId); const salt = new Uint8Array(64); cryptoApi.getRandomValues(salt); @@ -97,7 +100,8 @@ describe("extract/expand", () => { suiteId.set(i2Osp(Kem.DhkemP521HkdfSha512, 2), 4); suiteId.set(i2Osp(Kdf.HkdfSha512, 2), 6); suiteId.set(i2Osp(Aead.Aes128Gcm, 2), 8); - const kdf = new HkdfSha512(api, suiteId); + const kdf = new HkdfSha512(); + kdf.init(api, suiteId); const salt = new Uint8Array(64 + 32); cryptoApi.getRandomValues(salt); @@ -123,7 +127,8 @@ describe("extract/expand", () => { suiteId.set(i2Osp(Kem.DhkemP384HkdfSha384, 2), 4); suiteId.set(i2Osp(Kdf.HkdfSha384, 2), 6); suiteId.set(i2Osp(Aead.Aes128Gcm, 2), 8); - const kdf = new HkdfSha384(api, suiteId); + const kdf = new HkdfSha384(); + kdf.init(api, suiteId); const salt = new Uint8Array(48 + 32); cryptoApi.getRandomValues(salt); diff --git a/test/kemContext.test.ts b/test/kemContext.test.ts index 07b298e6c..65bdb0db3 100644 --- a/test/kemContext.test.ts +++ b/test/kemContext.test.ts @@ -24,7 +24,12 @@ describe("constructor", () => { const api = await loadSubtleCrypto(); // assert - const dhkemP256 = new DhkemP256HkdfSha256(api); + const dhkemP256 = new DhkemP256HkdfSha256(); + await assertRejects( + () => dhkemP256.generateKeyPair(), + errors.NotSupportedError, + ); + dhkemP256.init(api); assertEquals(typeof dhkemP256, "object"); assertEquals(dhkemP256.id, Kem.DhkemP256HkdfSha256); assertEquals(dhkemP256.secretSize, 32); @@ -32,7 +37,8 @@ describe("constructor", () => { assertEquals(dhkemP256.publicKeySize, 65); assertEquals(dhkemP256.privateKeySize, 32); - const dhkemP384 = new DhkemP384HkdfSha384(api); + const dhkemP384 = new DhkemP384HkdfSha384(); + dhkemP384.init(api); assertEquals(typeof dhkemP384, "object"); assertEquals(dhkemP384.id, Kem.DhkemP384HkdfSha384); assertEquals(dhkemP384.secretSize, 48); @@ -40,7 +46,8 @@ describe("constructor", () => { assertEquals(dhkemP384.publicKeySize, 97); assertEquals(dhkemP384.privateKeySize, 48); - const dhkemP521 = new DhkemP521HkdfSha512(api); + const dhkemP521 = new DhkemP521HkdfSha512(); + dhkemP521.init(api); assertEquals(typeof dhkemP521, "object"); assertEquals(dhkemP521.id, Kem.DhkemP521HkdfSha512); assertEquals(dhkemP521.secretSize, 64); @@ -48,7 +55,8 @@ describe("constructor", () => { assertEquals(dhkemP521.publicKeySize, 133); assertEquals(dhkemP521.privateKeySize, 64); - const dhkemSecp256K1 = new DhkemSecp256K1HkdfSha256(api); + const dhkemSecp256K1 = new DhkemSecp256K1HkdfSha256(); + dhkemSecp256K1.init(api); assertEquals(typeof dhkemP256, "object"); assertEquals(dhkemSecp256K1.id, Kem.DhkemSecp256K1HkdfSha256); assertEquals(dhkemSecp256K1.secretSize, 32); @@ -56,7 +64,8 @@ describe("constructor", () => { assertEquals(dhkemSecp256K1.publicKeySize, 65); assertEquals(dhkemSecp256K1.privateKeySize, 32); - const dhkemX25519 = new DhkemX25519HkdfSha256(api); + const dhkemX25519 = new DhkemX25519HkdfSha256(); + dhkemX25519.init(api); assertEquals(typeof dhkemX25519, "object"); assertEquals(dhkemX25519.id, Kem.DhkemX25519HkdfSha256); assertEquals(dhkemX25519.secretSize, 32); @@ -64,7 +73,8 @@ describe("constructor", () => { assertEquals(dhkemX25519.publicKeySize, 32); assertEquals(dhkemX25519.privateKeySize, 32); - const dhkemX448 = new DhkemX448HkdfSha512(api); + const dhkemX448 = new DhkemX448HkdfSha512(); + dhkemX448.init(api); assertEquals(typeof dhkemX448, "object"); assertEquals(dhkemX448.id, Kem.DhkemX448HkdfSha512); assertEquals(dhkemX448.secretSize, 64); @@ -81,7 +91,8 @@ describe("generateKeyPair", () => { const api = await loadSubtleCrypto(); // assert - const kemContext = new DhkemP256HkdfSha256(api); + const kemContext = new DhkemP256HkdfSha256(); + kemContext.init(api); const kp = await kemContext.generateKeyPair(); assertEquals(kp.publicKey.type, "public"); assertEquals(kp.publicKey.extractable, true); @@ -100,7 +111,8 @@ describe("generateKeyPair", () => { const api = await loadSubtleCrypto(); // assert - const kemContext = new DhkemP384HkdfSha384(api); + const kemContext = new DhkemP384HkdfSha384(); + kemContext.init(api); const kp = await kemContext.generateKeyPair(); assertEquals(kp.publicKey.type, "public"); assertEquals(kp.publicKey.extractable, true); @@ -122,7 +134,8 @@ describe("generateKeyPair", () => { const api = await loadSubtleCrypto(); // assert - const kemContext = new DhkemP521HkdfSha512(api); + const kemContext = new DhkemP521HkdfSha512(); + kemContext.init(api); const kp = await kemContext.generateKeyPair(); assertEquals(kp.publicKey.type, "public"); assertEquals(kp.publicKey.extractable, true); @@ -141,7 +154,8 @@ describe("generateKeyPair", () => { const api = await loadSubtleCrypto(); // assert - const kemContext = new DhkemSecp256K1HkdfSha256(api); + const kemContext = new DhkemSecp256K1HkdfSha256(); + kemContext.init(api); const kp = await kemContext.generateKeyPair(); assertEquals(kp.publicKey.type, "public"); assertEquals(kp.publicKey.extractable, true); @@ -161,7 +175,8 @@ describe("generateKeyPair", () => { const api = await loadSubtleCrypto(); // assert - const kemContext = new DhkemX25519HkdfSha256(api); + const kemContext = new DhkemX25519HkdfSha256(); + kemContext.init(api); const kp = await kemContext.generateKeyPair(); assertEquals(kp.publicKey.type, "public"); assertEquals(kp.publicKey.extractable, true); @@ -179,7 +194,8 @@ describe("generateKeyPair", () => { const api = await loadSubtleCrypto(); // assert - const kemContext = new DhkemX448HkdfSha512(api); + const kemContext = new DhkemX448HkdfSha512(); + kemContext.init(api); const kp = await kemContext.generateKeyPair(); assertEquals(kp.publicKey.type, "public"); assertEquals(kp.publicKey.extractable, true); @@ -202,7 +218,8 @@ describe("generateKeyPair", () => { const api = await loadSubtleCrypto(); // assert - const kemContext = new DhkemP521HkdfSha512(api); + const kemContext = new DhkemP521HkdfSha512(); + kemContext.init(api); await assertRejects( () => kemContext.generateKeyPair(), errors.NotSupportedError, @@ -221,7 +238,8 @@ describe("deriveKeyPair", () => { const cryptoApi = await loadCrypto(); // assert - const kemContext = new DhkemP256HkdfSha256(api); + const kemContext = new DhkemP256HkdfSha256(); + kemContext.init(api); const ikm = new Uint8Array(32); cryptoApi.getRandomValues(ikm); const kp = await kemContext.deriveKeyPair(ikm.buffer); @@ -246,7 +264,8 @@ describe("deriveKeyPair", () => { const cryptoApi = await loadCrypto(); // assert - const kemContext = new DhkemP384HkdfSha384(api); + const kemContext = new DhkemP384HkdfSha384(); + kemContext.init(api); const ikm = new Uint8Array(32); cryptoApi.getRandomValues(ikm); const kp = await kemContext.deriveKeyPair(ikm.buffer); @@ -271,7 +290,8 @@ describe("deriveKeyPair", () => { const cryptoApi = await loadCrypto(); // assert - const kemContext = new DhkemP521HkdfSha512(api); + const kemContext = new DhkemP521HkdfSha512(); + kemContext.init(api); const ikm = new Uint8Array(32); cryptoApi.getRandomValues(ikm); const kp = await kemContext.deriveKeyPair(ikm.buffer); @@ -293,7 +313,8 @@ describe("deriveKeyPair", () => { const cryptoApi = await loadCrypto(); // assert - const kemContext = new DhkemSecp256K1HkdfSha256(api); + const kemContext = new DhkemSecp256K1HkdfSha256(); + kemContext.init(api); const ikm = new Uint8Array(32); cryptoApi.getRandomValues(ikm); const kp = await kemContext.deriveKeyPair(ikm.buffer); @@ -315,7 +336,8 @@ describe("deriveKeyPair", () => { const cryptoApi = await loadCrypto(); // assert - const kemContext = new DhkemX25519HkdfSha256(api); + const kemContext = new DhkemX25519HkdfSha256(); + kemContext.init(api); const ikm = new Uint8Array(32); cryptoApi.getRandomValues(ikm); const kp = await kemContext.deriveKeyPair(ikm.buffer); @@ -336,7 +358,8 @@ describe("deriveKeyPair", () => { const cryptoApi = await loadCrypto(); // assert - const kemContext = new DhkemX448HkdfSha512(api); + const kemContext = new DhkemX448HkdfSha512(); + kemContext.init(api); const ikm = new Uint8Array(32); cryptoApi.getRandomValues(ikm); const kp = await kemContext.deriveKeyPair(ikm.buffer); @@ -364,7 +387,8 @@ describe("deriveKeyPair", () => { cryptoApi.getRandomValues(ikm); // assert - const kemContext = new DhkemP256HkdfSha256(api); + const kemContext = new DhkemP256HkdfSha256(); + kemContext.init(api); await assertRejects( () => kemContext.deriveKeyPair(ikm.buffer), errors.DeriveKeyPairError, @@ -379,7 +403,8 @@ describe("serialize/deserializePublicKey", () => { const api = await loadSubtleCrypto(); // assert - const kemContext = new DhkemP256HkdfSha256(api); + const kemContext = new DhkemP256HkdfSha256(); + kemContext.init(api); const kp = await kemContext.generateKeyPair(); const bPubKey = await kemContext.serializePublicKey(kp.publicKey); const pubKey = await kemContext.deserializePublicKey(bPubKey); @@ -394,7 +419,8 @@ describe("serialize/deserializePublicKey", () => { const api = await loadSubtleCrypto(); // assert - const kemContext = new DhkemP384HkdfSha384(api); + const kemContext = new DhkemP384HkdfSha384(); + kemContext.init(api); const kp = await kemContext.generateKeyPair(); const bPubKey = await kemContext.serializePublicKey(kp.publicKey); const pubKey = await kemContext.deserializePublicKey(bPubKey); @@ -412,7 +438,8 @@ describe("serialize/deserializePublicKey", () => { const api = await loadSubtleCrypto(); // assert - const kemContext = new DhkemP521HkdfSha512(api); + const kemContext = new DhkemP521HkdfSha512(); + kemContext.init(api); const kp = await kemContext.generateKeyPair(); const bPubKey = await kemContext.serializePublicKey(kp.publicKey); const pubKey = await kemContext.deserializePublicKey(bPubKey); @@ -427,7 +454,8 @@ describe("serialize/deserializePublicKey", () => { const api = await loadSubtleCrypto(); // assert - const kemContext = new DhkemSecp256K1HkdfSha256(api); + const kemContext = new DhkemSecp256K1HkdfSha256(); + kemContext.init(api); const kp = await kemContext.generateKeyPair(); const bPubKey = await kemContext.serializePublicKey(kp.publicKey); const pubKey = await kemContext.deserializePublicKey(bPubKey); @@ -443,7 +471,8 @@ describe("serialize/deserializePublicKey", () => { const api = await loadSubtleCrypto(); // assert - const kemContext = new DhkemX25519HkdfSha256(api); + const kemContext = new DhkemX25519HkdfSha256(); + kemContext.init(api); const kp = await kemContext.generateKeyPair(); const bPubKey = await kemContext.serializePublicKey(kp.publicKey); const pubKey = await kemContext.deserializePublicKey(bPubKey); @@ -458,7 +487,8 @@ describe("serialize/deserializePublicKey", () => { const api = await loadSubtleCrypto(); // assert - const kemContext = new DhkemX448HkdfSha512(api); + const kemContext = new DhkemX448HkdfSha512(); + kemContext.init(api); const kp = await kemContext.generateKeyPair(); const bPubKey = await kemContext.serializePublicKey(kp.publicKey); const pubKey = await kemContext.deserializePublicKey(bPubKey); @@ -478,9 +508,10 @@ describe("serialize/deserializePublicKey", () => { const api = await loadSubtleCrypto(); // assert - const ctx = new DhkemX25519HkdfSha256(api); + const ctx = new DhkemX25519HkdfSha256(); + ctx.init(api); const kp = await ctx.generateKeyPair(); - const kemContext = new DhkemP256HkdfSha256(api); + const kemContext = new DhkemP256HkdfSha256(); await assertRejects( () => kemContext.serializePublicKey(kp.publicKey), errors.SerializeError, @@ -494,7 +525,8 @@ describe("serialize/deserializePublicKey", () => { const api = await loadSubtleCrypto(); // assert - const kemContext = new DhkemP256HkdfSha256(api); + const kemContext = new DhkemP256HkdfSha256(); + kemContext.init(api); const cryptoApi = await loadCrypto(); const rawKey = new Uint8Array(32); cryptoApi.getRandomValues(rawKey); @@ -510,7 +542,8 @@ describe("importKey", () => { describe("with valid parameters", () => { it("should return a valid private key for DhkemP256HkdfSha256 from JWK", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemP256HkdfSha256(api); + const kemContext = new DhkemP256HkdfSha256(); + kemContext.init(api); const jwk = { kty: "EC", @@ -530,7 +563,8 @@ describe("importKey", () => { it("should return a valid public key for DhkemP256HkdfSha256 from JWK", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemP256HkdfSha256(api); + const kemContext = new DhkemP256HkdfSha256(); + kemContext.init(api); const jwk = { kty: "EC", @@ -548,7 +582,8 @@ describe("importKey", () => { it("should return a valid private key for DhkemP384HkdfSha384 from JWK", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemP384HkdfSha384(api); + const kemContext = new DhkemP384HkdfSha384(); + kemContext.init(api); const jwk = { kty: "EC", @@ -568,7 +603,8 @@ describe("importKey", () => { it("should return a valid public key for DhkemP384HkdfSha384 from JWK", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemP384HkdfSha384(api); + const kemContext = new DhkemP384HkdfSha384(); + kemContext.init(api); const jwk = { kty: "EC", @@ -589,7 +625,8 @@ describe("importKey", () => { return; } const api = await loadSubtleCrypto(); - const kemContext = new DhkemP521HkdfSha512(api); + const kemContext = new DhkemP521HkdfSha512(); + kemContext.init(api); const jwk = { kty: "EC", @@ -612,7 +649,8 @@ describe("importKey", () => { return; } const api = await loadSubtleCrypto(); - const kemContext = new DhkemP521HkdfSha512(api); + const kemContext = new DhkemP521HkdfSha512(); + kemContext.init(api); const jwk = { kty: "EC", @@ -630,7 +668,8 @@ describe("importKey", () => { it("should return a valid private key for DhkemX25519HkdfSha256 from JWK", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX25519HkdfSha256(api); + const kemContext = new DhkemX25519HkdfSha256(); + kemContext.init(api); const jwk = { kty: "OKP", @@ -649,7 +688,8 @@ describe("importKey", () => { it("should return a valid public key for DhkemX25519HkdfSha256 from JWK", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX25519HkdfSha256(api); + const kemContext = new DhkemX25519HkdfSha256(); + kemContext.init(api); const jwk = { kty: "OKP", @@ -666,7 +706,8 @@ describe("importKey", () => { it("should return a valid private key for DhkemX448HkdfSha512 from JWK", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX448HkdfSha512(api); + const kemContext = new DhkemX448HkdfSha512(); + kemContext.init(api); const jwk = { kty: "OKP", @@ -685,7 +726,8 @@ describe("importKey", () => { it("should return a valid public key for DhkemX448HkdfSha512 from JWK", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX448HkdfSha512(api); + const kemContext = new DhkemX448HkdfSha512(); + kemContext.init(api); const jwk = { kty: "OKP", @@ -702,7 +744,8 @@ describe("importKey", () => { it("should return a valid private key for DhkemSecp256K1HkdfSha256 from raw key", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemSecp256K1HkdfSha256(api); + const kemContext = new DhkemSecp256K1HkdfSha256(); + kemContext.init(api); const cryptoApi = await loadCrypto(); const rawKey = new Uint8Array(32); @@ -716,7 +759,8 @@ describe("importKey", () => { it("should return a valid public key for DhkemSecp256K1HkdfSha256 from raw key", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemSecp256K1HkdfSha256(api); + const kemContext = new DhkemSecp256K1HkdfSha256(); + kemContext.init(api); const cryptoApi = await loadCrypto(); const rawKey = new Uint8Array(65); @@ -733,7 +777,8 @@ describe("importKey", () => { describe("with invalid parameters", () => { it("should throw DeserializeError with private raw key(EC/P-256) with 'jwk'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemP256HkdfSha256(api); + const kemContext = new DhkemP256HkdfSha256(); + kemContext.init(api); const cryptoApi = await loadCrypto(); const rawKey = new Uint8Array(32); @@ -748,7 +793,8 @@ describe("importKey", () => { it("should throw DeserializeError with private JWK(EC/P-256) with 'raw'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemP256HkdfSha256(api); + const kemContext = new DhkemP256HkdfSha256(); + kemContext.init(api); const jwk = { kty: "EC", @@ -769,7 +815,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid private JWK(EC/P-256) without 'kty'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemP256HkdfSha256(api); + const kemContext = new DhkemP256HkdfSha256(); + kemContext.init(api); const jwk = { // kty: "EC", @@ -790,7 +837,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid private JWK(EC/P-256) without 'crv'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemP256HkdfSha256(api); + const kemContext = new DhkemP256HkdfSha256(); + kemContext.init(api); const jwk = { kty: "EC", @@ -811,7 +859,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid private JWK(EC/P-256) without 'd'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemP256HkdfSha256(api); + const kemContext = new DhkemP256HkdfSha256(); + kemContext.init(api); const jwk = { kty: "EC", @@ -832,7 +881,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid public JWK(EC/P-256) without 'x'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemP256HkdfSha256(api); + const kemContext = new DhkemP256HkdfSha256(); + kemContext.init(api); const jwk = { kty: "EC", @@ -853,7 +903,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid public JWK(EC/P-256) with 'd'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemP256HkdfSha256(api); + const kemContext = new DhkemP256HkdfSha256(); + kemContext.init(api); const jwk = { kty: "EC", @@ -874,7 +925,8 @@ describe("importKey", () => { it("should throw DeserializeError with private raw key(OKP/X25519) with 'jwk'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX25519HkdfSha256(api); + const kemContext = new DhkemX25519HkdfSha256(); + kemContext.init(api); const cryptoApi = await loadCrypto(); const rawKey = new Uint8Array(32); @@ -889,7 +941,8 @@ describe("importKey", () => { it("should throw DeserializeError with private JWK(OKP/X25519) with 'raw'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX25519HkdfSha256(api); + const kemContext = new DhkemX25519HkdfSha256(); + kemContext.init(api); const jwk = { kty: "OKP", @@ -909,7 +962,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid private JWK(OKP/X25519) without 'kty'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX25519HkdfSha256(api); + const kemContext = new DhkemX25519HkdfSha256(); + kemContext.init(api); const jwk = { // kty: "OKP", @@ -929,7 +983,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid private JWK(OKP/X25519) without 'crv'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX25519HkdfSha256(api); + const kemContext = new DhkemX25519HkdfSha256(); + kemContext.init(api); const jwk = { kty: "OKP", @@ -949,7 +1004,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid private JWK(OKP/X25519) without 'd'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX25519HkdfSha256(api); + const kemContext = new DhkemX25519HkdfSha256(); + kemContext.init(api); const jwk = { kty: "OKP", @@ -969,7 +1025,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid public JWK(OKP/X25519) without 'x'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX25519HkdfSha256(api); + const kemContext = new DhkemX25519HkdfSha256(); + kemContext.init(api); const jwk = { kty: "OKP", @@ -989,7 +1046,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid public JWK(OKP/X25519) with 'd'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX25519HkdfSha256(api); + const kemContext = new DhkemX25519HkdfSha256(); + kemContext.init(api); const jwk = { kty: "OKP", @@ -1009,7 +1067,8 @@ describe("importKey", () => { it("should throw DeserializeError with private raw key(OKP/448) with 'jwk'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX448HkdfSha512(api); + const kemContext = new DhkemX448HkdfSha512(); + kemContext.init(api); const cryptoApi = await loadCrypto(); const rawKey = new Uint8Array(56); @@ -1024,7 +1083,8 @@ describe("importKey", () => { it("should throw DeserializeError with private JWK(OKP/448) with 'raw'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX448HkdfSha512(api); + const kemContext = new DhkemX448HkdfSha512(); + kemContext.init(api); const jwk = { kty: "OKP", @@ -1044,7 +1104,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid private JWK(OKP/X448) without 'kty'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX448HkdfSha512(api); + const kemContext = new DhkemX448HkdfSha512(); + kemContext.init(api); const jwk = { // kty: "OKP", @@ -1064,7 +1125,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid private JWK(OKP/X448) without 'crv'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX448HkdfSha512(api); + const kemContext = new DhkemX448HkdfSha512(); + kemContext.init(api); const jwk = { kty: "OKP", @@ -1084,7 +1146,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid private JWK(OKP/X448) without 'd'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX448HkdfSha512(api); + const kemContext = new DhkemX448HkdfSha512(); + kemContext.init(api); const jwk = { kty: "OKP", @@ -1104,7 +1167,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid public JWK(OKP/X448) without 'x'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX448HkdfSha512(api); + const kemContext = new DhkemX448HkdfSha512(); + kemContext.init(api); const jwk = { kty: "OKP", @@ -1124,7 +1188,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid public JWK(X448) with 'd'", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemX448HkdfSha512(api); + const kemContext = new DhkemX448HkdfSha512(); + kemContext.init(api); const jwk = { kty: "OKP", @@ -1144,7 +1209,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid DhkemSecp256K1HkdfSha256 private key", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemSecp256K1HkdfSha256(api); + const kemContext = new DhkemSecp256K1HkdfSha256(); + kemContext.init(api); const cryptoApi = await loadCrypto(); const rawKey = new Uint8Array(33); @@ -1159,7 +1225,8 @@ describe("importKey", () => { it("should throw DeserializeError with invalid DhkemSecp256K1HkdfSha256 public key", async () => { const api = await loadSubtleCrypto(); - const kemContext = new DhkemSecp256K1HkdfSha256(api); + const kemContext = new DhkemSecp256K1HkdfSha256(); + kemContext.init(api); const cryptoApi = await loadCrypto(); const rawKey = new Uint8Array(32);