UNPKG

@hpke/common

Version:

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

200 lines (199 loc) 8.56 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", "../interfaces/kemInterface.js", "../utils/misc.js"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Dhkem = void 0; const consts_js_1 = require("../consts.js"); const errors_js_1 = require("../errors.js"); const kemInterface_js_1 = require("../interfaces/kemInterface.js"); const misc_js_1 = require("../utils/misc.js"); // b"eae_prk" const LABEL_EAE_PRK = new Uint8Array([101, 97, 101, 95, 112, 114, 107]); // b"shared_secret" // deno-fmt-ignore const LABEL_SHARED_SECRET = new Uint8Array([ 115, 104, 97, 114, 101, 100, 95, 115, 101, 99, 114, 101, 116, ]); function concat3(a, b, c) { const ret = new Uint8Array(a.length + b.length + c.length); ret.set(a, 0); ret.set(b, a.length); ret.set(c, a.length + b.length); return ret; } class Dhkem { constructor(id, prim, kdf) { Object.defineProperty(this, "id", { enumerable: true, configurable: true, writable: true, value: void 0 }); 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, "_prim", { 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._prim = prim; 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) { return await this._prim.serializePublicKey(key); } async deserializePublicKey(key) { return await this._prim.deserializePublicKey(key); } async serializePrivateKey(key) { return await this._prim.serializePrivateKey(key); } async deserializePrivateKey(key) { return await this._prim.deserializePrivateKey(key); } async importKey(format, key, isPublic = true) { return await this._prim.importKey(format, key, isPublic); } async generateKeyPair() { return await this._prim.generateKeyPair(); } async deriveKeyPair(ikm) { if (ikm.byteLength > consts_js_1.INPUT_LENGTH_LIMIT) { throw new errors_js_1.InvalidParamError("Too long ikm"); } return await this._prim.deriveKeyPair(ikm); } async encap(params) { let ke; if (params.ekm === undefined) { ke = await this.generateKeyPair(); } else if ((0, misc_js_1.isCryptoKeyPair)(params.ekm)) { // params.ekm is only used for testing. ke = params.ekm; } else { // params.ekm is only used for testing. ke = await this.deriveKeyPair(params.ekm); } const enc = await this._prim.serializePublicKey(ke.publicKey); const pkrm = await this._prim.serializePublicKey(params.recipientPublicKey); try { let dh; if (params.senderKey === undefined) { dh = new Uint8Array(await this._prim.dh(ke.privateKey, params.recipientPublicKey)); } else { const sks = (0, misc_js_1.isCryptoKeyPair)(params.senderKey) ? params.senderKey.privateKey : params.senderKey; const dh1 = new Uint8Array(await this._prim.dh(ke.privateKey, params.recipientPublicKey)); const dh2 = new Uint8Array(await this._prim.dh(sks, params.recipientPublicKey)); dh = (0, misc_js_1.concat)(dh1, dh2); } let kemContext; if (params.senderKey === undefined) { kemContext = (0, misc_js_1.concat)(new Uint8Array(enc), new Uint8Array(pkrm)); } else { const pks = (0, misc_js_1.isCryptoKeyPair)(params.senderKey) ? params.senderKey.publicKey : await this._prim.derivePublicKey(params.senderKey); const pksm = await this._prim.serializePublicKey(pks); kemContext = concat3(new Uint8Array(enc), new Uint8Array(pkrm), new Uint8Array(pksm)); } const sharedSecret = await this._generateSharedSecret(dh, kemContext); return { enc: enc, sharedSecret: sharedSecret, }; } catch (e) { throw new errors_js_1.EncapError(e); } } async decap(params) { const pke = await this._prim.deserializePublicKey(params.enc); const skr = (0, misc_js_1.isCryptoKeyPair)(params.recipientKey) ? params.recipientKey.privateKey : params.recipientKey; const pkr = (0, misc_js_1.isCryptoKeyPair)(params.recipientKey) ? params.recipientKey.publicKey : await this._prim.derivePublicKey(params.recipientKey); const pkrm = await this._prim.serializePublicKey(pkr); try { let dh; if (params.senderPublicKey === undefined) { dh = new Uint8Array(await this._prim.dh(skr, pke)); } else { const dh1 = new Uint8Array(await this._prim.dh(skr, pke)); const dh2 = new Uint8Array(await this._prim.dh(skr, params.senderPublicKey)); dh = (0, misc_js_1.concat)(dh1, dh2); } let kemContext; if (params.senderPublicKey === undefined) { kemContext = (0, misc_js_1.concat)(new Uint8Array(params.enc), new Uint8Array(pkrm)); } else { const pksm = await this._prim.serializePublicKey(params.senderPublicKey); kemContext = new Uint8Array(params.enc.byteLength + pkrm.byteLength + pksm.byteLength); kemContext.set(new Uint8Array(params.enc), 0); kemContext.set(new Uint8Array(pkrm), params.enc.byteLength); kemContext.set(new Uint8Array(pksm), params.enc.byteLength + pkrm.byteLength); } return await this._generateSharedSecret(dh, kemContext); } catch (e) { throw new errors_js_1.DecapError(e); } } async _generateSharedSecret(dh, kemContext) { const labeledIkm = this._kdf.buildLabeledIkm(LABEL_EAE_PRK, dh); const labeledInfo = this._kdf.buildLabeledInfo(LABEL_SHARED_SECRET, kemContext, this.secretSize); return await this._kdf.extractAndExpand(consts_js_1.EMPTY.buffer, labeledIkm.buffer, labeledInfo.buffer, this.secretSize); } } exports.Dhkem = Dhkem; });