@hpke/common
Version:
A Hybrid Public Key Encryption (HPKE) internal-use common module for @hpke family modules.
234 lines (233 loc) • 8.82 kB
JavaScript
(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", "../algorithm.js"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.HkdfSha512Native = exports.HkdfSha384Native = exports.HkdfSha256Native = exports.HkdfNative = void 0;
const consts_js_1 = require("../consts.js");
const errors_js_1 = require("../errors.js");
const identifiers_js_1 = require("../identifiers.js");
const algorithm_js_1 = require("../algorithm.js");
// b"HPKE-v1"
const HPKE_VERSION = new Uint8Array([72, 80, 75, 69, 45, 118, 49]);
class HkdfNative extends algorithm_js_1.NativeAlgorithm {
constructor() {
super();
Object.defineProperty(this, "id", {
enumerable: true,
configurable: true,
writable: true,
value: identifiers_js_1.KdfId.HkdfSha256
});
Object.defineProperty(this, "hashSize", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "_suiteId", {
enumerable: true,
configurable: true,
writable: true,
value: consts_js_1.EMPTY
});
Object.defineProperty(this, "algHash", {
enumerable: true,
configurable: true,
writable: true,
value: {
name: "HMAC",
hash: "SHA-256",
length: 256,
}
});
}
init(suiteId) {
this._suiteId = suiteId;
}
buildLabeledIkm(label, ikm) {
this._checkInit();
const ret = new Uint8Array(7 + this._suiteId.byteLength + label.byteLength + ikm.byteLength);
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);
return ret;
}
buildLabeledInfo(label, info, len) {
this._checkInit();
const ret = new Uint8Array(9 + this._suiteId.byteLength + label.byteLength + info.byteLength);
ret.set(new Uint8Array([0, len]), 0);
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);
return ret;
}
async extract(salt, ikm) {
await this._setup();
if (salt.byteLength === 0) {
salt = new ArrayBuffer(this.hashSize);
}
if (salt.byteLength !== this.hashSize) {
throw new errors_js_1.InvalidParamError("The salt length must be the same as the hashSize");
}
const key = await this._api.importKey("raw", salt, this.algHash, false, [
"sign",
]);
return await this._api.sign("HMAC", key, ikm);
}
async expand(prk, info, len) {
await this._setup();
const key = await this._api.importKey("raw", prk, this.algHash, false, [
"sign",
]);
const okm = new ArrayBuffer(len);
const p = new Uint8Array(okm);
let prev = consts_js_1.EMPTY;
const mid = new Uint8Array(info);
const tail = new Uint8Array(1);
if (len > 255 * this.hashSize) {
throw new Error("Entropy limit reached");
}
const tmp = new Uint8Array(this.hashSize + mid.length + 1);
for (let i = 1, cur = 0; cur < p.length; i++) {
tail[0] = i;
tmp.set(prev, 0);
tmp.set(mid, prev.length);
tmp.set(tail, prev.length + mid.length);
prev = new Uint8Array(await this._api.sign("HMAC", key, tmp.slice(0, prev.length + mid.length + 1)));
if (p.length - cur >= prev.length) {
p.set(prev, cur);
cur += prev.length;
}
else {
p.set(prev.slice(0, p.length - cur), cur);
cur += p.length - cur;
}
}
return okm;
}
async extractAndExpand(salt, ikm, info, len) {
await this._setup();
const baseKey = await this._api.importKey("raw", ikm, "HKDF", false, ["deriveBits"]);
return await this._api.deriveBits({
name: "HKDF",
hash: this.algHash.hash,
salt: salt,
info: info,
}, baseKey, len * 8);
}
async labeledExtract(salt, label, ikm) {
return await this.extract(salt, this.buildLabeledIkm(label, ikm).buffer);
}
async labeledExpand(prk, label, info, len) {
return await this.expand(prk, this.buildLabeledInfo(label, info, len).buffer, len);
}
_checkInit() {
if (this._suiteId === consts_js_1.EMPTY) {
throw new Error("Not initialized. Call init()");
}
}
}
exports.HkdfNative = HkdfNative;
class HkdfSha256Native extends HkdfNative {
constructor() {
super(...arguments);
/** KdfId.HkdfSha256 (0x0001) */
Object.defineProperty(this, "id", {
enumerable: true,
configurable: true,
writable: true,
value: identifiers_js_1.KdfId.HkdfSha256
});
/** 32 */
Object.defineProperty(this, "hashSize", {
enumerable: true,
configurable: true,
writable: true,
value: 32
});
/** The parameters for Web Cryptography API */
Object.defineProperty(this, "algHash", {
enumerable: true,
configurable: true,
writable: true,
value: {
name: "HMAC",
hash: "SHA-256",
length: 256,
}
});
}
}
exports.HkdfSha256Native = HkdfSha256Native;
class HkdfSha384Native extends HkdfNative {
constructor() {
super(...arguments);
/** KdfId.HkdfSha384 (0x0002) */
Object.defineProperty(this, "id", {
enumerable: true,
configurable: true,
writable: true,
value: identifiers_js_1.KdfId.HkdfSha384
});
/** 48 */
Object.defineProperty(this, "hashSize", {
enumerable: true,
configurable: true,
writable: true,
value: 48
});
/** The parameters for Web Cryptography API */
Object.defineProperty(this, "algHash", {
enumerable: true,
configurable: true,
writable: true,
value: {
name: "HMAC",
hash: "SHA-384",
length: 384,
}
});
}
}
exports.HkdfSha384Native = HkdfSha384Native;
class HkdfSha512Native extends HkdfNative {
constructor() {
super(...arguments);
/** KdfId.HkdfSha512 (0x0003) */
Object.defineProperty(this, "id", {
enumerable: true,
configurable: true,
writable: true,
value: identifiers_js_1.KdfId.HkdfSha512
});
/** 64 */
Object.defineProperty(this, "hashSize", {
enumerable: true,
configurable: true,
writable: true,
value: 64
});
/** The parameters for Web Cryptography API */
Object.defineProperty(this, "algHash", {
enumerable: true,
configurable: true,
writable: true,
value: {
name: "HMAC",
hash: "SHA-512",
length: 512,
}
});
}
}
exports.HkdfSha512Native = HkdfSha512Native;
});