From 013db2b339bc696ed2a935e09c81bc0eead837f8 Mon Sep 17 00:00:00 2001 From: Ajitomi Daisuke Date: Mon, 7 Aug 2023 21:46:37 +0900 Subject: [PATCH] Separate consts to minimize the size of submodules. --- src/aeads/aesGcm.ts | 4 +- src/algorithm.ts | 4 +- src/cipherSuiteNative.ts | 73 ++++++- src/consts.ts | 259 ----------------------- src/exporterContext.ts | 5 +- src/interfaces/aeadEncryptionContext.ts | 3 + src/interfaces/kemPrimitives.ts | 9 + src/kdfs/hkdf.ts | 9 +- src/kems/dhkem.ts | 32 ++- src/kems/dhkemPrimitives/ec.ts | 196 +++++++++++++++-- src/kems/dhkemPrimitives/x25519.ts | 20 +- src/kems/dhkemPrimitives/x448.ts | 20 +- src/xCryptoKey.ts | 12 +- test/conformanceTester.ts | 1 - test/encryptionContext.test.ts | 19 +- test/kdfContext.test.ts | 23 +- x/dhkem-secp256k1/src/dhkem-secp256k1.ts | 11 +- 17 files changed, 379 insertions(+), 321 deletions(-) diff --git a/src/aeads/aesGcm.ts b/src/aeads/aesGcm.ts index cd9d8d91d..89dc3f3c9 100644 --- a/src/aeads/aesGcm.ts +++ b/src/aeads/aesGcm.ts @@ -3,7 +3,7 @@ import type { AeadInterface } from "../interfaces/aeadInterface.ts"; import { Algorithm } from "../algorithm.ts"; import { AeadId } from "../identifiers.ts"; -import * as consts from "../consts.ts"; +import { AEAD_USAGES } from "../interfaces/aeadEncryptionContext.ts"; export class AesGcmContext implements AeadEncryptionContext { private _rawKey: ArrayBuffer; @@ -65,7 +65,7 @@ export class AesGcmContext implements AeadEncryptionContext { key, { name: "AES-GCM" }, true, - consts.AEAD_USAGES, + AEAD_USAGES, ); } } diff --git a/src/algorithm.ts b/src/algorithm.ts index 536d7a900..648881422 100644 --- a/src/algorithm.ts +++ b/src/algorithm.ts @@ -1,4 +1,4 @@ -import * as consts from "./consts.ts"; +import { EMPTY } from "./consts.ts"; export class AlgorithmBase { protected _api: SubtleCrypto | undefined = undefined; @@ -23,7 +23,7 @@ export class Algorithm extends AlgorithmBase { } export class KdfAlgorithm extends AlgorithmBase { - protected _suiteId: Uint8Array = consts.EMPTY; + protected _suiteId: Uint8Array = EMPTY; constructor() { super(); diff --git a/src/cipherSuiteNative.ts b/src/cipherSuiteNative.ts index 371dfa859..2aa0f639a 100644 --- a/src/cipherSuiteNative.ts +++ b/src/cipherSuiteNative.ts @@ -37,6 +37,65 @@ import { i2Osp } from "./utils/misc.ts"; import * as consts from "./consts.ts"; import * as errors from "./errors.ts"; +// b"base_nonce" +const LABEL_BASE_NONCE = new Uint8Array([ + 98, + 97, + 115, + 101, + 95, + 110, + 111, + 110, + 99, + 101, +]); +// b"exp" +const LABEL_EXP = new Uint8Array([101, 120, 112]); +// b"info_hash" +const LABEL_INFO_HASH = new Uint8Array([ + 105, + 110, + 102, + 111, + 95, + 104, + 97, + 115, + 104, +]); +// b"key" +const LABEL_KEY = new Uint8Array([107, 101, 121]); +// b"psk_id_hash" +const LABEL_PSK_ID_HASH = new Uint8Array([ + 112, + 115, + 107, + 95, + 105, + 100, + 95, + 104, + 97, + 115, + 104, +]); +// b"secret" +const LABEL_SECRET = new Uint8Array([115, 101, 99, 114, 101, 116]); +// b"HPKE" +const SUITE_ID_HEADER_HPKE = new Uint8Array([ + 72, + 80, + 75, + 69, + 0, + 0, + 0, + 0, + 0, + 0, +]); + /** * The Hybrid Public Key Encryption (HPKE) ciphersuite, * which is implemented using only @@ -168,7 +227,7 @@ export class CipherSuiteNative { } } - this._suiteId = new Uint8Array(consts.SUITE_ID_HEADER_HPKE); + this._suiteId = new Uint8Array(SUITE_ID_HEADER_HPKE); this._suiteId.set(i2Osp(this._kem.id, 2), 4); this._suiteId.set(i2Osp(this._kdf.id, 2), 6); this._suiteId.set(i2Osp(this._aead.id, 2), 8); @@ -399,7 +458,7 @@ export class CipherSuiteNative { : new Uint8Array(params.psk.id); const pskIdHash = await this._kdf.labeledExtract( consts.EMPTY, - consts.LABEL_PSK_ID_HASH, + LABEL_PSK_ID_HASH, pskId, ); @@ -408,7 +467,7 @@ export class CipherSuiteNative { : new Uint8Array(params.info); const infoHash = await this._kdf.labeledExtract( consts.EMPTY, - consts.LABEL_INFO_HASH, + LABEL_INFO_HASH, info, ); @@ -422,10 +481,10 @@ export class CipherSuiteNative { const psk = params.psk === undefined ? consts.EMPTY : new Uint8Array(params.psk.key); - const ikm = this._kdf.buildLabeledIkm(consts.LABEL_SECRET, psk); + const ikm = this._kdf.buildLabeledIkm(LABEL_SECRET, psk); const exporterSecretInfo = this._kdf.buildLabeledInfo( - consts.LABEL_EXP, + LABEL_EXP, keyScheduleContext, this._kdf.hashSize, ); @@ -441,7 +500,7 @@ export class CipherSuiteNative { } const keyInfo = this._kdf.buildLabeledInfo( - consts.LABEL_KEY, + LABEL_KEY, keyScheduleContext, this._aead.keySize, ); @@ -453,7 +512,7 @@ export class CipherSuiteNative { ); const baseNonceInfo = this._kdf.buildLabeledInfo( - consts.LABEL_BASE_NONCE, + LABEL_BASE_NONCE, keyScheduleContext, this._aead.nonceSize, ); diff --git a/src/consts.ts b/src/consts.ts index 494eacc23..6eb2c9325 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -1,8 +1,3 @@ -// The key usages for KEM. -export const KEM_USAGES: KeyUsage[] = ["deriveBits"]; -// The key usages for AEAD. -export const AEAD_USAGES: KeyUsage[] = ["encrypt", "decrypt"]; - // The input length limit (psk, psk_id, info, exporter_context, ikm). export const INPUT_LENGTH_LIMIT = 8192; @@ -11,257 +6,3 @@ export const MINIMUM_PSK_LENGTH = 32; // b"" export const EMPTY = new Uint8Array(0); -// b"HPKE-v1" -export const HPKE_VERSION = new Uint8Array([72, 80, 75, 69, 45, 118, 49]); -// b"HPKE" -export const SUITE_ID_HEADER_HPKE = new Uint8Array([ - 72, - 80, - 75, - 69, - 0, - 0, - 0, - 0, - 0, - 0, -]); -// b"KEM" -export const SUITE_ID_HEADER_KEM = new Uint8Array([75, 69, 77, 0, 0]); -// b"dkp_prk" -export const LABEL_DKP_PRK = new Uint8Array([100, 107, 112, 95, 112, 114, 107]); -// b"eae_prk" -export const LABEL_EAE_PRK = new Uint8Array([101, 97, 101, 95, 112, 114, 107]); -// b"info_hash" -export const LABEL_INFO_HASH = new Uint8Array([ - 105, - 110, - 102, - 111, - 95, - 104, - 97, - 115, - 104, -]); -// b"psk_id_hash" -export const LABEL_PSK_ID_HASH = new Uint8Array([ - 112, - 115, - 107, - 95, - 105, - 100, - 95, - 104, - 97, - 115, - 104, -]); -// b"secret" -export const LABEL_SECRET = new Uint8Array([115, 101, 99, 114, 101, 116]); -// b"shared_secret" -export const LABEL_SHARED_SECRET = new Uint8Array([ - 115, - 104, - 97, - 114, - 101, - 100, - 95, - 115, - 101, - 99, - 114, - 101, - 116, -]); -// b"key" -export const LABEL_KEY = new Uint8Array([107, 101, 121]); -// b"base_nonce" -export const LABEL_BASE_NONCE = new Uint8Array([ - 98, - 97, - 115, - 101, - 95, - 110, - 111, - 110, - 99, - 101, -]); -// b"exp" -export const LABEL_EXP = new Uint8Array([101, 120, 112]); -// b"sec" -export const LABEL_SEC = new Uint8Array([115, 101, 99]); -// b"candidate" -export const LABEL_CANDIDATE = new Uint8Array([ - 99, - 97, - 110, - 100, - 105, - 100, - 97, - 116, - 101, -]); -// b"sk" -export const LABEL_SK = new Uint8Array([115, 107]); - -// the order of the curve being used. -export const ORDER_P_256 = new Uint8Array([ - 0xff, - 0xff, - 0xff, - 0xff, - 0x00, - 0x00, - 0x00, - 0x00, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xbc, - 0xe6, - 0xfa, - 0xad, - 0xa7, - 0x17, - 0x9e, - 0x84, - 0xf3, - 0xb9, - 0xca, - 0xc2, - 0xfc, - 0x63, - 0x25, - 0x51, -]); - -export const ORDER_P_384 = new Uint8Array([ - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xc7, - 0x63, - 0x4d, - 0x81, - 0xf4, - 0x37, - 0x2d, - 0xdf, - 0x58, - 0x1a, - 0x0d, - 0xb2, - 0x48, - 0xb0, - 0xa7, - 0x7a, - 0xec, - 0xec, - 0x19, - 0x6a, - 0xcc, - 0xc5, - 0x29, - 0x73, -]); - -export const ORDER_P_521 = new Uint8Array([ - 0x01, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xfa, - 0x51, - 0x86, - 0x87, - 0x83, - 0xbf, - 0x2f, - 0x96, - 0x6b, - 0x7f, - 0xcc, - 0x01, - 0x48, - 0xf7, - 0x09, - 0xa5, - 0xd0, - 0x3b, - 0xb5, - 0xc9, - 0xb8, - 0x89, - 0x9c, - 0x47, - 0xae, - 0xbb, - 0x6f, - 0xb7, - 0x1e, - 0x91, - 0x38, - 0x64, - 0x09, -]); diff --git a/src/exporterContext.ts b/src/exporterContext.ts index 1a68e37bb..7ee959f6b 100644 --- a/src/exporterContext.ts +++ b/src/exporterContext.ts @@ -5,6 +5,9 @@ import type { KdfInterface } from "./interfaces/kdfInterface.ts"; import * as consts from "./consts.ts"; import * as errors from "./errors.ts"; +// b"sec" +const LABEL_SEC = new Uint8Array([115, 101, 99]); + export class ExporterContextImpl implements EncryptionContext { protected _api: SubtleCrypto; protected readonly exporterSecret: ArrayBuffer; @@ -44,7 +47,7 @@ export class ExporterContextImpl implements EncryptionContext { try { return await this._kdf.labeledExpand( this.exporterSecret, - consts.LABEL_SEC, + LABEL_SEC, new Uint8Array(exporterContext), len, ); diff --git a/src/interfaces/aeadEncryptionContext.ts b/src/interfaces/aeadEncryptionContext.ts index 7e5ddd274..3b34be697 100644 --- a/src/interfaces/aeadEncryptionContext.ts +++ b/src/interfaces/aeadEncryptionContext.ts @@ -1,3 +1,6 @@ +// The key usages for AEAD. +export const AEAD_USAGES: KeyUsage[] = ["encrypt", "decrypt"]; + /** * The AEAD encryption context interface. */ diff --git a/src/interfaces/kemPrimitives.ts b/src/interfaces/kemPrimitives.ts index c0bd3b231..4fe014a99 100644 --- a/src/interfaces/kemPrimitives.ts +++ b/src/interfaces/kemPrimitives.ts @@ -1,3 +1,12 @@ +// The key usages for KEM. +export const KEM_USAGES: KeyUsage[] = ["deriveBits"]; + +// b"dkp_prk" +export const LABEL_DKP_PRK = new Uint8Array([100, 107, 112, 95, 112, 114, 107]); + +// b"sk" +export const LABEL_SK = new Uint8Array([115, 107]); + export interface KemPrimitives { init(api: SubtleCrypto): void; diff --git a/src/kdfs/hkdf.ts b/src/kdfs/hkdf.ts index de30f0b9b..406321468 100644 --- a/src/kdfs/hkdf.ts +++ b/src/kdfs/hkdf.ts @@ -6,6 +6,9 @@ import { KdfAlgorithm } from "../algorithm.ts"; import * as consts from "../consts.ts"; import * as errors from "../errors.ts"; +// b"HPKE-v1" +const HPKE_VERSION = new Uint8Array([72, 80, 75, 69, 45, 118, 49]); + export class HkdfNative extends KdfAlgorithm implements KdfInterface { public readonly id: KdfId = KdfId.HkdfSha256; public readonly hashSize: number = 0; @@ -23,7 +26,7 @@ export class HkdfNative extends KdfAlgorithm implements KdfInterface { const ret = new Uint8Array( 7 + this._suiteId.byteLength + label.byteLength + ikm.byteLength, ); - ret.set(consts.HPKE_VERSION, 0); + ret.set(HPKE_VERSION, 0); ret.set(this._suiteId, 7); ret.set(label, 7 + this._suiteId.byteLength); ret.set(ikm, 7 + this._suiteId.byteLength + label.byteLength); @@ -39,7 +42,7 @@ export class HkdfNative extends KdfAlgorithm implements KdfInterface { 9 + this._suiteId.byteLength + label.byteLength + info.byteLength, ); ret.set(new Uint8Array([0, len]), 0); - ret.set(consts.HPKE_VERSION, 2); + ret.set(HPKE_VERSION, 2); ret.set(this._suiteId, 9); ret.set(label, 9 + this._suiteId.byteLength); ret.set(info, 9 + this._suiteId.byteLength + label.byteLength); @@ -133,7 +136,7 @@ export class HkdfNative extends KdfAlgorithm implements KdfInterface { ikm, "HKDF", false, - consts.KEM_USAGES, + ["deriveBits"], ); return await (this._api as SubtleCrypto).deriveBits( { diff --git a/src/kems/dhkem.ts b/src/kems/dhkem.ts index 248d80142..4b686fafe 100644 --- a/src/kems/dhkem.ts +++ b/src/kems/dhkem.ts @@ -8,9 +8,31 @@ import { Algorithm } from "../algorithm.ts"; import { KemId } from "../identifiers.ts"; import { concat, concat3, i2Osp, isCryptoKeyPair } from "../utils/misc.ts"; -import * as consts from "../consts.ts"; +import { EMPTY } from "../consts.ts"; import * as errors from "../errors.ts"; +// b"KEM" +const SUITE_ID_HEADER_KEM = new Uint8Array([75, 69, 77, 0, 0]); + +// b"eae_prk" +const LABEL_EAE_PRK = new Uint8Array([101, 97, 101, 95, 112, 114, 107]); +// b"shared_secret" +const LABEL_SHARED_SECRET = new Uint8Array([ + 115, + 104, + 97, + 114, + 101, + 100, + 95, + 115, + 101, + 99, + 114, + 101, + 116, +]); + export class Dhkem extends Algorithm implements KemInterface { public readonly id: KemId = KemId.DhkemP256HkdfSha256; public readonly secretSize: number = 0; @@ -28,7 +50,7 @@ export class Dhkem extends Algorithm implements KemInterface { public init(api: SubtleCrypto): void { super.init(api); - const suiteId = new Uint8Array(consts.SUITE_ID_HEADER_KEM); + const suiteId = new Uint8Array(SUITE_ID_HEADER_KEM); suiteId.set(i2Osp(this.id, 2), 3); this._prim.init(api); this._kdf.init(api, suiteId); @@ -188,14 +210,14 @@ export class Dhkem extends Algorithm implements KemInterface { dh: Uint8Array, kemContext: Uint8Array, ): Promise { - const labeledIkm = this._kdf.buildLabeledIkm(consts.LABEL_EAE_PRK, dh); + const labeledIkm = this._kdf.buildLabeledIkm(LABEL_EAE_PRK, dh); const labeledInfo = this._kdf.buildLabeledInfo( - consts.LABEL_SHARED_SECRET, + LABEL_SHARED_SECRET, kemContext, this.secretSize, ); return await this._kdf.extractAndExpand( - consts.EMPTY, + EMPTY, labeledIkm, labeledInfo, this.secretSize, diff --git a/src/kems/dhkemPrimitives/ec.ts b/src/kems/dhkemPrimitives/ec.ts index f64fa839a..c1e40b790 100644 --- a/src/kems/dhkemPrimitives/ec.ts +++ b/src/kems/dhkemPrimitives/ec.ts @@ -3,11 +3,180 @@ import type { KdfInterface } from "../../interfaces/kdfInterface.ts"; import { Algorithm } from "../../algorithm.ts"; import { KemId } from "../../identifiers.ts"; - +import { KEM_USAGES, LABEL_DKP_PRK } from "../../interfaces/kemPrimitives.ts"; import { Bignum } from "../../utils/bignum.ts"; import { i2Osp } from "../../utils/misc.ts"; -import * as consts from "../../consts.ts"; +import { EMPTY } from "../../consts.ts"; + +// b"candidate" +const LABEL_CANDIDATE = new Uint8Array([ + 99, + 97, + 110, + 100, + 105, + 100, + 97, + 116, + 101, +]); + +// the order of the curve being used. +const ORDER_P_256 = new Uint8Array([ + 0xff, + 0xff, + 0xff, + 0xff, + 0x00, + 0x00, + 0x00, + 0x00, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xbc, + 0xe6, + 0xfa, + 0xad, + 0xa7, + 0x17, + 0x9e, + 0x84, + 0xf3, + 0xb9, + 0xca, + 0xc2, + 0xfc, + 0x63, + 0x25, + 0x51, +]); + +const ORDER_P_384 = new Uint8Array([ + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xc7, + 0x63, + 0x4d, + 0x81, + 0xf4, + 0x37, + 0x2d, + 0xdf, + 0x58, + 0x1a, + 0x0d, + 0xb2, + 0x48, + 0xb0, + 0xa7, + 0x7a, + 0xec, + 0xec, + 0x19, + 0x6a, + 0xcc, + 0xc5, + 0x29, + 0x73, +]); + +const ORDER_P_521 = new Uint8Array([ + 0x01, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xfa, + 0x51, + 0x86, + 0x87, + 0x83, + 0xbf, + 0x2f, + 0x96, + 0x6b, + 0x7f, + 0xcc, + 0x01, + 0x48, + 0xf7, + 0x09, + 0xa5, + 0xd0, + 0x3b, + 0xb5, + 0xc9, + 0xb8, + 0x89, + 0x9c, + 0x47, + 0xae, + 0xbb, + 0x6f, + 0xb7, + 0x1e, + 0x91, + 0x38, + 0x64, + 0x09, +]); const PKCS8_ALG_ID_P_256 = new Uint8Array([ 48, @@ -138,7 +307,7 @@ export class Ec extends Algorithm implements KemPrimitives { this._nPk = 65; this._nSk = 32; this._nDh = 32; - this._order = consts.ORDER_P_256; + this._order = ORDER_P_256; this._bitmask = 0xFF; this._pkcs8AlgId = PKCS8_ALG_ID_P_256; break; @@ -147,7 +316,7 @@ export class Ec extends Algorithm implements KemPrimitives { this._nPk = 97; this._nSk = 48; this._nDh = 48; - this._order = consts.ORDER_P_384; + this._order = ORDER_P_384; this._bitmask = 0xFF; this._pkcs8AlgId = PKCS8_ALG_ID_P_384; break; @@ -157,7 +326,7 @@ export class Ec extends Algorithm implements KemPrimitives { this._nPk = 133; this._nSk = 66; this._nDh = 66; - this._order = consts.ORDER_P_521; + this._order = ORDER_P_521; this._bitmask = 0x01; this._pkcs8AlgId = PKCS8_ALG_ID_P_521; break; @@ -220,7 +389,6 @@ export class Ec extends Algorithm implements KemPrimitives { } try { if (isPublic) { - // return await this._api.importKey(format, key, this._alg, true, consts.KEM_USAGES); return await (this._api as SubtleCrypto).importKey( "raw", key, @@ -238,7 +406,7 @@ export class Ec extends Algorithm implements KemPrimitives { pkcs8Key, this._alg, true, - consts.KEM_USAGES, + KEM_USAGES, ); } catch (_e: unknown) { throw new Error("Invalid key for the ciphersuite"); @@ -272,7 +440,7 @@ export class Ec extends Algorithm implements KemPrimitives { key, this._alg, true, - consts.KEM_USAGES, + KEM_USAGES, ); } @@ -281,7 +449,7 @@ export class Ec extends Algorithm implements KemPrimitives { 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, KEM_USAGES); return await (this._api as SubtleCrypto).importKey( "jwk", jwk, @@ -296,15 +464,15 @@ export class Ec extends Algorithm implements KemPrimitives { return await (this._api as SubtleCrypto).generateKey( this._alg, true, - consts.KEM_USAGES, + KEM_USAGES, ); } public async deriveKeyPair(ikm: ArrayBuffer): Promise { this.checkInit(); const dkpPrk = await this._hkdf.labeledExtract( - consts.EMPTY, - consts.LABEL_DKP_PRK, + EMPTY, + LABEL_DKP_PRK, new Uint8Array(ikm), ); const bn = new Bignum(this._nSk); @@ -315,7 +483,7 @@ export class Ec extends Algorithm implements KemPrimitives { const bytes = new Uint8Array( await this._hkdf.labeledExpand( dkpPrk, - consts.LABEL_CANDIDATE, + LABEL_CANDIDATE, i2Osp(counter, 1), this._nSk, ), @@ -331,7 +499,7 @@ export class Ec extends Algorithm implements KemPrimitives { pkcs8Key, this._alg, true, - consts.KEM_USAGES, + KEM_USAGES, ); bn.reset(); return { diff --git a/src/kems/dhkemPrimitives/x25519.ts b/src/kems/dhkemPrimitives/x25519.ts index f8ac46b0a..611dcef18 100644 --- a/src/kems/dhkemPrimitives/x25519.ts +++ b/src/kems/dhkemPrimitives/x25519.ts @@ -5,6 +5,11 @@ import type { KemPrimitives } from "../../interfaces/kemPrimitives.ts"; import type { KdfInterface } from "../../interfaces/kdfInterface.ts"; import { Algorithm } from "../../algorithm.ts"; +import { + KEM_USAGES, + LABEL_DKP_PRK, + LABEL_SK, +} from "../../interfaces/kemPrimitives.ts"; import { XCryptoKey } from "../../xCryptoKey.ts"; import * as consts from "../../consts.ts"; @@ -53,7 +58,7 @@ export class X25519 extends Algorithm implements KemPrimitives { public async generateKeyPair(): Promise { const rawSk = ed25519.utils.randomPrivateKey(); - const sk = new XCryptoKey(ALG_NAME, rawSk, "private"); + const sk = new XCryptoKey(ALG_NAME, rawSk, "private", KEM_USAGES); const pk = await this.derivePublicKey(sk); return { publicKey: pk, privateKey: sk }; } @@ -61,16 +66,21 @@ export class X25519 extends Algorithm implements KemPrimitives { public async deriveKeyPair(ikm: ArrayBuffer): Promise { const dkpPrk = await this._hkdf.labeledExtract( consts.EMPTY, - consts.LABEL_DKP_PRK, + LABEL_DKP_PRK, new Uint8Array(ikm), ); const rawSk = await this._hkdf.labeledExpand( dkpPrk, - consts.LABEL_SK, + LABEL_SK, consts.EMPTY, this._nSk, ); - const sk = new XCryptoKey(ALG_NAME, new Uint8Array(rawSk), "private"); + const sk = new XCryptoKey( + ALG_NAME, + new Uint8Array(rawSk), + "private", + KEM_USAGES, + ); return { privateKey: sk, publicKey: await this.derivePublicKey(sk), @@ -113,6 +123,7 @@ export class X25519 extends Algorithm implements KemPrimitives { ALG_NAME, new Uint8Array(key), isPublic ? "public" : "private", + isPublic ? [] : KEM_USAGES, ), ); }); @@ -149,6 +160,7 @@ export class X25519 extends Algorithm implements KemPrimitives { ALG_NAME, base64UrlToBytes(key.d as string), "private", + KEM_USAGES, ), ); } diff --git a/src/kems/dhkemPrimitives/x448.ts b/src/kems/dhkemPrimitives/x448.ts index 29a26bdea..c9b040187 100644 --- a/src/kems/dhkemPrimitives/x448.ts +++ b/src/kems/dhkemPrimitives/x448.ts @@ -5,6 +5,11 @@ import type { KemPrimitives } from "../../interfaces/kemPrimitives.ts"; import type { KdfInterface } from "../../interfaces/kdfInterface.ts"; import { Algorithm } from "../../algorithm.ts"; +import { + KEM_USAGES, + LABEL_DKP_PRK, + LABEL_SK, +} from "../../interfaces/kemPrimitives.ts"; import { XCryptoKey } from "../../xCryptoKey.ts"; import * as consts from "../../consts.ts"; @@ -53,7 +58,7 @@ export class X448 extends Algorithm implements KemPrimitives { public async generateKeyPair(): Promise { const rawSk = ed448.utils.randomPrivateKey(); - const sk = new XCryptoKey(ALG_NAME, rawSk, "private"); + const sk = new XCryptoKey(ALG_NAME, rawSk, "private", KEM_USAGES); const pk = await this.derivePublicKey(sk); return { publicKey: pk, privateKey: sk }; } @@ -61,16 +66,21 @@ export class X448 extends Algorithm implements KemPrimitives { public async deriveKeyPair(ikm: ArrayBuffer): Promise { const dkpPrk = await this._hkdf.labeledExtract( consts.EMPTY, - consts.LABEL_DKP_PRK, + LABEL_DKP_PRK, new Uint8Array(ikm), ); const rawSk = await this._hkdf.labeledExpand( dkpPrk, - consts.LABEL_SK, + LABEL_SK, consts.EMPTY, this._nSk, ); - const sk = new XCryptoKey(ALG_NAME, new Uint8Array(rawSk), "private"); + const sk = new XCryptoKey( + ALG_NAME, + new Uint8Array(rawSk), + "private", + KEM_USAGES, + ); return { privateKey: sk, publicKey: await this.derivePublicKey(sk), @@ -113,6 +123,7 @@ export class X448 extends Algorithm implements KemPrimitives { ALG_NAME, new Uint8Array(key), isPublic ? "public" : "private", + isPublic ? [] : KEM_USAGES, ), ); }); @@ -149,6 +160,7 @@ export class X448 extends Algorithm implements KemPrimitives { ALG_NAME, base64UrlToBytes(key.d as string), "private", + KEM_USAGES, ), ); } diff --git a/src/xCryptoKey.ts b/src/xCryptoKey.ts index 527eb74b5..1fc17aab7 100644 --- a/src/xCryptoKey.ts +++ b/src/xCryptoKey.ts @@ -1,16 +1,20 @@ -import * as consts from "./consts.ts"; - export class XCryptoKey implements CryptoKey { public readonly key: Uint8Array; public readonly type: "public" | "private"; public readonly extractable: boolean = true; public readonly algorithm: KeyAlgorithm; - public readonly usages: KeyUsage[] = consts.KEM_USAGES; + public readonly usages: KeyUsage[]; - constructor(name: string, key: Uint8Array, type: "public" | "private") { + constructor( + name: string, + key: Uint8Array, + type: "public" | "private", + usages: KeyUsage[] = [], + ) { this.key = key; this.type = type; this.algorithm = { name: name }; + this.usages = usages; if (type === "public") { this.usages = []; } diff --git a/test/conformanceTester.ts b/test/conformanceTester.ts index a85209292..b3d337b21 100644 --- a/test/conformanceTester.ts +++ b/test/conformanceTester.ts @@ -158,7 +158,6 @@ export class ConformanceTester { const pkb = hexStringToBytes(pk); const alg = kemToKeyGenAlgorithm(kemId); - // const cpk = await this._api.importKey('raw', pkb, alg, true, consts.KEM_USAGES); const cpk = await this._api.importKey("raw", pkb, alg, true, []); const sender = await suite.createSenderContext({ recipientPublicKey: cpk, diff --git a/test/encryptionContext.test.ts b/test/encryptionContext.test.ts index 9c7e0f077..1c2c5e393 100644 --- a/test/encryptionContext.test.ts +++ b/test/encryptionContext.test.ts @@ -11,9 +11,20 @@ import { i2Osp } from "../src/utils/misc.ts"; import { ExportOnly } from "../src/aeads/exportOnly.ts"; import { Aes128Gcm } from "../src/aeads/aesGcm.ts"; -import * as consts from "../src/consts.ts"; import * as errors from "../src/errors.ts"; +const SUITE_ID_HEADER_HPKE = new Uint8Array([ + 72, + 80, + 75, + 69, + 0, + 0, + 0, + 0, + 0, + 0, +]); const DUMMY_BYTES_12 = new Uint8Array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]); const DUMMY_BYTES_16 = new Uint8Array( [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], @@ -23,7 +34,7 @@ describe("constructor", () => { describe("with valid parameters", () => { it("should return a proper instance", async () => { const api = await loadSubtleCrypto(); - const suiteId = new Uint8Array(consts.SUITE_ID_HEADER_HPKE); + const suiteId = new Uint8Array(SUITE_ID_HEADER_HPKE); suiteId.set(i2Osp(KemId.DhkemP256HkdfSha256, 2), 4); suiteId.set(i2Osp(KdfId.HkdfSha256, 2), 6); suiteId.set(i2Osp(AeadId.Aes128Gcm, 2), 8); @@ -57,7 +68,7 @@ describe("constructor", () => { describe("with invalid aead id", () => { it("should throw Error", async () => { const api = await loadSubtleCrypto(); - const suiteId = new Uint8Array(consts.SUITE_ID_HEADER_HPKE); + const suiteId = new Uint8Array(SUITE_ID_HEADER_HPKE); suiteId.set(i2Osp(KemId.DhkemP256HkdfSha256, 2), 4); suiteId.set(i2Osp(KdfId.HkdfSha256, 2), 6); suiteId.set(i2Osp(AeadId.Aes128Gcm, 2), 8); @@ -411,7 +422,7 @@ describe("createRecipientContext", () => { describe("without key info", () => { it("should throw Error", async () => { const api = await loadSubtleCrypto(); - const suiteId = new Uint8Array(consts.SUITE_ID_HEADER_HPKE); + const suiteId = new Uint8Array(SUITE_ID_HEADER_HPKE); suiteId.set(i2Osp(KemId.DhkemP256HkdfSha256, 2), 4); suiteId.set(i2Osp(KdfId.HkdfSha256, 2), 6); suiteId.set(i2Osp(AeadId.Aes128Gcm, 2), 8); diff --git a/test/kdfContext.test.ts b/test/kdfContext.test.ts index aef00adb0..a84cd712c 100644 --- a/test/kdfContext.test.ts +++ b/test/kdfContext.test.ts @@ -9,7 +9,18 @@ import { AeadId, KdfId, KemId } from "../src/identifiers.ts"; import { loadCrypto, loadSubtleCrypto } from "../src/webCrypto.ts"; import { i2Osp } from "../src/utils/misc.ts"; -import * as consts from "../src/consts.ts"; +const SUITE_ID_HEADER_HPKE = new Uint8Array([ + 72, + 80, + 75, + 69, + 0, + 0, + 0, + 0, + 0, + 0, +]); describe("extract/expand", () => { describe("HKDF-SHA256 with valid parameters", () => { @@ -18,7 +29,7 @@ describe("extract/expand", () => { const api = await loadSubtleCrypto(); const cryptoApi = await loadCrypto(); - const suiteId = new Uint8Array(consts.SUITE_ID_HEADER_HPKE); + const suiteId = new Uint8Array(SUITE_ID_HEADER_HPKE); suiteId.set(i2Osp(KemId.DhkemP256HkdfSha256, 2), 4); suiteId.set(i2Osp(KdfId.HkdfSha256, 2), 6); suiteId.set(i2Osp(AeadId.Aes128Gcm, 2), 8); @@ -45,7 +56,7 @@ describe("extract/expand", () => { const api = await loadSubtleCrypto(); const cryptoApi = await loadCrypto(); - const suiteId = new Uint8Array(consts.SUITE_ID_HEADER_HPKE); + const suiteId = new Uint8Array(SUITE_ID_HEADER_HPKE); suiteId.set(i2Osp(KemId.DhkemP384HkdfSha384, 2), 4); suiteId.set(i2Osp(KdfId.HkdfSha384, 2), 6); suiteId.set(i2Osp(AeadId.Aes128Gcm, 2), 8); @@ -72,7 +83,7 @@ describe("extract/expand", () => { const api = await loadSubtleCrypto(); const cryptoApi = await loadCrypto(); - const suiteId = new Uint8Array(consts.SUITE_ID_HEADER_HPKE); + const suiteId = new Uint8Array(SUITE_ID_HEADER_HPKE); suiteId.set(i2Osp(KemId.DhkemP521HkdfSha512, 2), 4); suiteId.set(i2Osp(KdfId.HkdfSha512, 2), 6); suiteId.set(i2Osp(AeadId.Aes128Gcm, 2), 8); @@ -98,7 +109,7 @@ describe("extract/expand", () => { const te = new TextEncoder(); const api = await loadSubtleCrypto(); const cryptoApi = await loadCrypto(); - const suiteId = new Uint8Array(consts.SUITE_ID_HEADER_HPKE); + const suiteId = new Uint8Array(SUITE_ID_HEADER_HPKE); suiteId.set(i2Osp(KemId.DhkemP521HkdfSha512, 2), 4); suiteId.set(i2Osp(KdfId.HkdfSha512, 2), 6); suiteId.set(i2Osp(AeadId.Aes128Gcm, 2), 8); @@ -125,7 +136,7 @@ describe("extract/expand", () => { const te = new TextEncoder(); const api = await loadSubtleCrypto(); const cryptoApi = await loadCrypto(); - const suiteId = new Uint8Array(consts.SUITE_ID_HEADER_HPKE); + const suiteId = new Uint8Array(SUITE_ID_HEADER_HPKE); suiteId.set(i2Osp(KemId.DhkemP384HkdfSha384, 2), 4); suiteId.set(i2Osp(KdfId.HkdfSha384, 2), 6); suiteId.set(i2Osp(AeadId.Aes128Gcm, 2), 8); diff --git a/x/dhkem-secp256k1/src/dhkem-secp256k1.ts b/x/dhkem-secp256k1/src/dhkem-secp256k1.ts index 36e381b45..d26b1f141 100644 --- a/x/dhkem-secp256k1/src/dhkem-secp256k1.ts +++ b/x/dhkem-secp256k1/src/dhkem-secp256k1.ts @@ -7,11 +7,12 @@ import type { KemInterface } from "../../../src/interfaces/kemInterface.ts"; import { Algorithm } from "../../../src/algorithm.ts"; import { KemId } from "../../../src/identifiers.ts"; +import { LABEL_DKP_PRK, LABEL_SK } from "../../../src/interfaces/kemPrimitives.ts"; import { XCryptoKey } from "../../../src/xCryptoKey.ts"; import { HkdfSha256 } from "../../../src/kdfs/hkdfSha256.ts"; import { Dhkem } from "../../../src/kems/dhkem.ts"; -import * as consts from "../../../src/consts.ts"; +import { EMPTY } from "../../../src/consts.ts"; const ALG_NAME = "ECDH"; @@ -59,14 +60,14 @@ class Secp256k1 extends Algorithm implements KemPrimitives { public async deriveKeyPair(ikm: ArrayBuffer): Promise { const dkpPrk = await this._hkdf.labeledExtract( - consts.EMPTY, - consts.LABEL_DKP_PRK, + EMPTY, + LABEL_DKP_PRK, new Uint8Array(ikm), ); const rawSk = await this._hkdf.labeledExpand( dkpPrk, - consts.LABEL_SK, - consts.EMPTY, + LABEL_SK, + EMPTY, this._nSk, ); const sk = new XCryptoKey(ALG_NAME, new Uint8Array(rawSk), "private");