@hpke/common
Version:
A Hybrid Public Key Encryption (HPKE) internal-use common module for @hpke family modules.
177 lines (176 loc) • 4.86 kB
JavaScript
import * as dntShim from "../../_dnt.shims.js";
import { KemId } from "../identifiers.js";
export const isDenoV1 = () =>
// deno-lint-ignore no-explicit-any
dntShim.dntGlobalThis.process === undefined;
/**
* Checks whether the runtime is Deno or not (Node.js).
* @returns boolean - true if the runtime is Deno, false Node.js.
*/
export function isDeno() {
// deno-lint-ignore no-explicit-any
if (dntShim.dntGlobalThis.process === undefined) {
return true;
}
// deno-lint-ignore no-explicit-any
return dntShim.dntGlobalThis.process?.versions?.deno !== undefined;
}
/**
* Checks whetehr the type of input is CryptoKeyPair or not.
*/
export const isCryptoKeyPair = (x) => typeof x === "object" &&
x !== null &&
typeof x.privateKey === "object" &&
typeof x.publicKey === "object";
/**
* Converts integer to octet string. I2OSP implementation.
*/
export function i2Osp(n, w) {
if (w <= 0) {
throw new Error("i2Osp: too small size");
}
if (n >= 256 ** w) {
throw new Error("i2Osp: too large integer");
}
const ret = new Uint8Array(w);
for (let i = 0; i < w && n; i++) {
ret[w - (i + 1)] = n % 256;
n = Math.floor(n / 256);
}
return ret;
}
/**
* Concatenates two Uint8Arrays.
* @param a Uint8Array
* @param b Uint8Array
* @returns Concatenated Uint8Array
*/
export function concat(a, b) {
const ret = new Uint8Array(a.length + b.length);
ret.set(a, 0);
ret.set(b, a.length);
return ret;
}
/**
* Decodes Base64Url-encoded data.
* @param v Base64Url-encoded string
* @returns Uint8Array
*/
export function base64UrlToBytes(v) {
const base64 = v.replace(/-/g, "+").replace(/_/g, "/");
const byteString = atob(base64);
const ret = new Uint8Array(byteString.length);
for (let i = 0; i < byteString.length; i++) {
ret[i] = byteString.charCodeAt(i);
}
return ret;
}
/**
* Encodes Uint8Array to Base64Url.
* @param v Uint8Array
* @returns Base64Url-encoded string
*/
export function bytesToBase64Url(v) {
return btoa(String.fromCharCode(...v))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=*$/g, "");
}
/**
* Decodes hex string to Uint8Array.
* @param v Hex string
* @returns Uint8Array
* @throws Error if the input is not a hex string.
*/
export function hexToBytes(v) {
if (v.length === 0) {
return new Uint8Array([]);
}
const res = v.match(/[\da-f]{2}/gi);
if (res == null) {
throw new Error("Not hex string.");
}
return new Uint8Array(res.map(function (h) {
return parseInt(h, 16);
}));
}
/**
* Encodes Uint8Array to hex string.
* @param v Uint8Array
* @returns Hex string
*/
export function bytesToHex(v) {
return [...v].map((x) => x.toString(16).padStart(2, "0")).join("");
}
/**
* Converts KemId to KeyAlgorithm.
* @param kem KemId
* @returns KeyAlgorithm
*/
export function kemToKeyGenAlgorithm(kem) {
switch (kem) {
case KemId.DhkemP256HkdfSha256:
return {
name: "ECDH",
namedCurve: "P-256",
};
case KemId.DhkemP384HkdfSha384:
return {
name: "ECDH",
namedCurve: "P-384",
};
case KemId.DhkemP521HkdfSha512:
return {
name: "ECDH",
namedCurve: "P-521",
};
default:
// case KemId.DhkemX25519HkdfSha256
return {
name: "X25519",
};
}
}
export async function loadSubtleCrypto() {
if (dntShim.dntGlobalThis !== undefined && globalThis.crypto !== undefined) {
// Browsers, Node.js >= v19, Cloudflare Workers, Bun, etc.
return globalThis.crypto.subtle;
}
// Node.js <= v18
try {
// @ts-ignore: to ignore "crypto"
const { webcrypto } = await import("crypto"); // node:crypto
return webcrypto.subtle;
}
catch (_e) {
throw new Error("Failed to load SubtleCrypto");
}
}
export async function loadCrypto() {
if (typeof dntShim.dntGlobalThis !== "undefined" && globalThis.crypto !== undefined) {
// Browsers, Node.js >= v19, Cloudflare Workers, Bun, etc.
return globalThis.crypto;
}
// Node.js <= v18
try {
// @ts-ignore: to ignore "crypto"
const { webcrypto } = await import("crypto"); // node:crypto
return webcrypto;
}
catch (_e) {
throw new Error("failed to load Crypto");
}
}
/**
* XOR for Uint8Array.
*/
export function xor(a, b) {
if (a.byteLength !== b.byteLength) {
throw new Error("xor: different length inputs");
}
const buf = new Uint8Array(a.byteLength);
for (let i = 0; i < a.byteLength; i++) {
buf[i] = a[i] ^ b[i];
}
return buf;
}