UNPKG

@hpke/common

Version:

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

309 lines (308 loc) 12.1 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", "../../algorithm.js", "../../consts.js", "../../errors.js", "../../identifiers.js", "../../interfaces/dhkemPrimitives.js", "../../utils/bignum.js", "../../utils/misc.js"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Ec = void 0; const algorithm_js_1 = require("../../algorithm.js"); 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 bignum_js_1 = require("../../utils/bignum.js"); const misc_js_1 = require("../../utils/misc.js"); // b"candidate" // deno-fmt-ignore const LABEL_CANDIDATE = new Uint8Array([ 99, 97, 110, 100, 105, 100, 97, 116, 101, ]); // the order of the curve being used. // deno-fmt-ignore 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, ]); // deno-fmt-ignore 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, ]); // deno-fmt-ignore 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, ]); // deno-fmt-ignore const PKCS8_ALG_ID_P_256 = new Uint8Array([ 48, 65, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 39, 48, 37, 2, 1, 1, 4, 32, ]); // deno-fmt-ignore const PKCS8_ALG_ID_P_384 = new Uint8Array([ 48, 78, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 55, 48, 53, 2, 1, 1, 4, 48, ]); // deno-fmt-ignore const PKCS8_ALG_ID_P_521 = new Uint8Array([ 48, 96, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 73, 48, 71, 2, 1, 1, 4, 66, ]); class Ec extends algorithm_js_1.NativeAlgorithm { constructor(kem, hkdf) { super(); Object.defineProperty(this, "_hkdf", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_alg", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_nPk", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_nSk", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_nDh", { enumerable: true, configurable: true, writable: true, value: void 0 }); // EC specific arguments for deriving key pair. Object.defineProperty(this, "_order", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_bitmask", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_pkcs8AlgId", { enumerable: true, configurable: true, writable: true, value: void 0 }); this._hkdf = hkdf; switch (kem) { case identifiers_js_1.KemId.DhkemP256HkdfSha256: this._alg = { name: "ECDH", namedCurve: "P-256" }; this._nPk = 65; this._nSk = 32; this._nDh = 32; this._order = ORDER_P_256; this._bitmask = 0xFF; this._pkcs8AlgId = PKCS8_ALG_ID_P_256; break; case identifiers_js_1.KemId.DhkemP384HkdfSha384: this._alg = { name: "ECDH", namedCurve: "P-384" }; this._nPk = 97; this._nSk = 48; this._nDh = 48; this._order = ORDER_P_384; this._bitmask = 0xFF; this._pkcs8AlgId = PKCS8_ALG_ID_P_384; break; default: // case KemId.DhkemP521HkdfSha512: this._alg = { name: "ECDH", namedCurve: "P-521" }; this._nPk = 133; this._nSk = 66; this._nDh = 66; this._order = ORDER_P_521; this._bitmask = 0x01; this._pkcs8AlgId = PKCS8_ALG_ID_P_521; break; } } async serializePublicKey(key) { await this._setup(); try { return await this._api.exportKey("raw", key); } catch (e) { throw new errors_js_1.SerializeError(e); } } async deserializePublicKey(key) { await this._setup(); try { return await this._importRawKey(key, true); } catch (e) { throw new errors_js_1.DeserializeError(e); } } async serializePrivateKey(key) { await this._setup(); try { const jwk = await this._api.exportKey("jwk", key); if (!("d" in jwk)) { throw new Error("Not private key"); } return (0, misc_js_1.base64UrlToBytes)(jwk["d"]).buffer; } catch (e) { throw new errors_js_1.SerializeError(e); } } async deserializePrivateKey(key) { await this._setup(); try { return await this._importRawKey(key, false); } catch (e) { throw new errors_js_1.DeserializeError(e); } } async importKey(format, key, isPublic) { await this._setup(); try { if (format === "raw") { return await this._importRawKey(key, isPublic); } // jwk if (key instanceof ArrayBuffer) { throw new Error("Invalid jwk key format"); } return await this._importJWK(key, isPublic); } catch (e) { throw new errors_js_1.DeserializeError(e); } } async generateKeyPair() { await this._setup(); try { return await this._api.generateKey(this._alg, true, dhkemPrimitives_js_1.KEM_USAGES); } catch (e) { throw new errors_js_1.NotSupportedError(e); } } async deriveKeyPair(ikm) { await this._setup(); try { const dkpPrk = await this._hkdf.labeledExtract(consts_js_1.EMPTY.buffer, dhkemPrimitives_js_1.LABEL_DKP_PRK, new Uint8Array(ikm)); const bn = new bignum_js_1.Bignum(this._nSk); for (let counter = 0; bn.isZero() || !bn.lessThan(this._order); counter++) { if (counter > 255) { throw new Error("Faild to derive a key pair"); } const bytes = new Uint8Array(await this._hkdf.labeledExpand(dkpPrk, LABEL_CANDIDATE, (0, misc_js_1.i2Osp)(counter, 1), this._nSk)); bytes[0] = bytes[0] & this._bitmask; bn.set(bytes); } const sk = await this._deserializePkcs8Key(bn.val()); bn.reset(); return { privateKey: sk, publicKey: await this.derivePublicKey(sk), }; } catch (e) { throw new errors_js_1.DeriveKeyPairError(e); } } async derivePublicKey(key) { await this._setup(); try { const jwk = await this._api.exportKey("jwk", key); delete jwk["d"]; delete jwk["key_ops"]; return await this._api.importKey("jwk", jwk, this._alg, true, []); } catch (e) { throw new errors_js_1.DeserializeError(e); } } async dh(sk, pk) { try { await this._setup(); const bits = await this._api.deriveBits({ name: "ECDH", public: pk, }, sk, this._nDh * 8); return bits; } catch (e) { throw new errors_js_1.SerializeError(e); } } async _importRawKey(key, isPublic) { if (isPublic && key.byteLength !== this._nPk) { throw new Error("Invalid public key for the ciphersuite"); } if (!isPublic && key.byteLength !== this._nSk) { throw new Error("Invalid private key for the ciphersuite"); } if (isPublic) { return await this._api.importKey("raw", key, this._alg, true, []); } return await this._deserializePkcs8Key(new Uint8Array(key)); } async _importJWK(key, isPublic) { if (typeof key.crv === "undefined" || key.crv !== this._alg.namedCurve) { throw new Error(`Invalid crv: ${key.crv}`); } if (isPublic) { 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, []); } if (typeof key.d === "undefined") { throw new Error("Invalid key: `d` not found"); } return await this._api.importKey("jwk", key, this._alg, true, dhkemPrimitives_js_1.KEM_USAGES); } async _deserializePkcs8Key(k) { 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("pkcs8", pkcs8Key, this._alg, true, dhkemPrimitives_js_1.KEM_USAGES); } } exports.Ec = Ec; });