UNPKG

@hpke/common

Version:

A Hybrid Public Key Encryption (HPKE) internal-use common module for @hpke family modules.

242 lines (241 loc) 10.7 kB
(function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "../consts.js", "../errors.js", "../identifiers.js", "../interfaces/dhkemPrimitives.js", "../interfaces/kemInterface.js", "../utils/misc.js", "../xCryptoKey.js"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Hybridkem = void 0; const consts_js_1 = require("../consts.js"); const errors_js_1 = require("../errors.js"); const identifiers_js_1 = require("../identifiers.js"); const dhkemPrimitives_js_1 = require("../interfaces/dhkemPrimitives.js"); const kemInterface_js_1 = require("../interfaces/kemInterface.js"); const misc_js_1 = require("../utils/misc.js"); const xCryptoKey_js_1 = require("../xCryptoKey.js"); class Hybridkem { constructor(id, a, b, kdf) { Object.defineProperty(this, "id", { enumerable: true, configurable: true, writable: true, value: identifiers_js_1.KemId.NotAssigned }); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: "" }); Object.defineProperty(this, "secretSize", { enumerable: true, configurable: true, writable: true, value: 0 }); Object.defineProperty(this, "encSize", { enumerable: true, configurable: true, writable: true, value: 0 }); Object.defineProperty(this, "publicKeySize", { enumerable: true, configurable: true, writable: true, value: 0 }); Object.defineProperty(this, "privateKeySize", { enumerable: true, configurable: true, writable: true, value: 0 }); Object.defineProperty(this, "_a", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_b", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_kdf", { enumerable: true, configurable: true, writable: true, value: void 0 }); this.id = id; this._a = a; this._b = b; this._kdf = kdf; const suiteId = new Uint8Array(kemInterface_js_1.SUITE_ID_HEADER_KEM); suiteId.set((0, misc_js_1.i2Osp)(this.id, 2), 3); this._kdf.init(suiteId); } async serializePublicKey(key) { try { return await this._serializePublicKey(key); } catch (e) { throw new errors_js_1.SerializeError(e); } } async deserializePublicKey(key) { try { return await this._deserializePublicKey(key); } catch (e) { throw new errors_js_1.DeserializeError(e); } } async serializePrivateKey(key) { try { return await this._serializePrivateKey(key); } catch (e) { throw new errors_js_1.SerializeError(e); } } async deserializePrivateKey(key) { try { return await this._deserializePrivateKey(key); } catch (e) { throw new errors_js_1.DeserializeError(e); } } async generateKeyPair() { const kpA = await this._a.generateKeyPair(); const kpB = await this._b.generateKeyPair(); const pkA = await this._a.serializePublicKey(kpA.publicKey); const skA = await this._a.serializePrivateKey(kpA.privateKey); const pkB = await this._b.serializePublicKey(kpB.publicKey); const skB = await this._b.serializePrivateKey(kpB.privateKey); return { publicKey: await this.deserializePublicKey((0, misc_js_1.concat)(new Uint8Array(pkA), new Uint8Array(pkB)).buffer), privateKey: await this.deserializePrivateKey((0, misc_js_1.concat)(new Uint8Array(skA), new Uint8Array(skB)).buffer), }; } async deriveKeyPair(ikm) { const dkpPrk = await this._kdf.labeledExtract(consts_js_1.EMPTY.buffer, dhkemPrimitives_js_1.LABEL_DKP_PRK, new Uint8Array(ikm)); const seed = new Uint8Array(await this._kdf.labeledExpand(dkpPrk, dhkemPrimitives_js_1.LABEL_SK, consts_js_1.EMPTY, 32 + 64)); const seed1 = seed.slice(0, 32); const seed2 = seed.slice(32, 96); const kpA = await this._a.deriveKeyPair(seed1.buffer); const kpB = await this._b.deriveKeyPair(seed2.buffer); const pkA = await this._a.serializePublicKey(kpA.publicKey); const skA = await this._a.serializePrivateKey(kpA.privateKey); const pkB = await this._b.serializePublicKey(kpB.publicKey); const skB = await this._b.serializePrivateKey(kpB.privateKey); return { publicKey: await this.deserializePublicKey((0, misc_js_1.concat)(new Uint8Array(pkA), new Uint8Array(pkB)).buffer), privateKey: await this.deserializePrivateKey((0, misc_js_1.concat)(new Uint8Array(skA), new Uint8Array(skB)).buffer), }; } async importKey(format, key, isPublic = true) { if (format !== "raw") { throw new errors_js_1.NotSupportedError("'jwk' is not supported"); } if (!(key instanceof ArrayBuffer)) { throw new errors_js_1.InvalidParamError("Invalid type of key"); } if (isPublic) { return await this.deserializePublicKey(key); } return await this.deserializePrivateKey(key); } async encap(params) { let ekmA = undefined; let ekmB = undefined; if (params.ekm !== undefined && !(0, misc_js_1.isCryptoKeyPair)(params.ekm)) { if (params.ekm.byteLength !== 64) { throw new errors_js_1.InvalidParamError("ekm must be 64 bytes in length"); } ekmA = params.ekm.slice(0, 32); ekmB = params.ekm.slice(32); } const pkR = new Uint8Array(await this.serializePublicKey(params.recipientPublicKey)); const pkRA = await this._a.deserializePublicKey(pkR.slice(0, this._a.publicKeySize).buffer); const pkRB = await this._b.deserializePublicKey(pkR.slice(this._a.publicKeySize).buffer); const resA = await this._a.encap({ recipientPublicKey: pkRA, ekm: ekmA }); const resB = await this._b.encap({ recipientPublicKey: pkRB, ekm: ekmB }); return { sharedSecret: (0, misc_js_1.concat)(new Uint8Array(resA.sharedSecret), new Uint8Array(resB.sharedSecret)).buffer, enc: (0, misc_js_1.concat)(new Uint8Array(resA.enc), new Uint8Array(resB.enc)) .buffer, }; } async decap(params) { const sk = (0, misc_js_1.isCryptoKeyPair)(params.recipientKey) ? params.recipientKey.privateKey : params.recipientKey; const skR = new Uint8Array(await this.serializePrivateKey(sk)); const skRA = await this._a.deserializePrivateKey(skR.slice(0, this._a.privateKeySize).buffer); const skRB = await this._b.deserializePrivateKey(skR.slice(this._a.privateKeySize).buffer); const ssA = await this._a.decap({ recipientKey: skRA, enc: params.enc.slice(0, this._a.encSize), }); const ssB = await this._b.decap({ recipientKey: skRB, enc: params.enc.slice(this._a.encSize), }); return (0, misc_js_1.concat)(new Uint8Array(ssA), new Uint8Array(ssB)) .buffer; } _serializePublicKey(k) { return new Promise((resolve, reject) => { if (k.type !== "public") { reject(new Error("Not public key")); } if (k.algorithm.name !== this.name) { reject(new Error(`Invalid algorithm name: ${k.algorithm.name}`)); } if (k.key.byteLength !== this.publicKeySize) { reject(new Error(`Invalid key length: ${k.key.byteLength}`)); } resolve(k.key.buffer); }); } _deserializePublicKey(k) { return new Promise((resolve, reject) => { if (k.byteLength !== this.publicKeySize) { reject(new Error(`Invalid key length: ${k.byteLength}`)); } resolve(new xCryptoKey_js_1.XCryptoKey(this.name, new Uint8Array(k), "public")); }); } _serializePrivateKey(k) { return new Promise((resolve, reject) => { if (k.type !== "private") { reject(new Error("Not private key")); } if (k.algorithm.name !== this.name) { reject(new Error(`Invalid algorithm name: ${k.algorithm.name}`)); } if (k.key.byteLength !== this.privateKeySize) { reject(new Error(`Invalid key length: ${k.key.byteLength}`)); } resolve(k.key.buffer); }); } _deserializePrivateKey(k) { return new Promise((resolve, reject) => { if (k.byteLength !== this.privateKeySize) { reject(new Error(`Invalid key length: ${k.byteLength}`)); } resolve(new xCryptoKey_js_1.XCryptoKey(this.name, new Uint8Array(k), "private", ["deriveBits"])); }); } } exports.Hybridkem = Hybridkem; });