UNPKG

tssrp6a

Version:

SRP6a client and server lib

145 lines 5.43 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { crossEnvCrypto } from "./crossEnvCrypto.js"; const ZERO = BigInt(0); const ONE = BigInt(1); const TWO = BigInt(2); export const bigIntToArrayBuffer = (n) => { const hex = n.toString(16); const arrayBuffer = new ArrayBuffer(Math.ceil(hex.length / 2)); const u8 = new Uint8Array(arrayBuffer); let offset = 0; // handle toString(16) not padding if (hex.length % 2 !== 0) { u8[0] = parseInt(hex[0], 16); offset = 1; } for (let i = 0; i < arrayBuffer.byteLength; i++) { u8[i + offset] = parseInt(hex.slice(2 * i + offset, 2 * i + 2 + offset), 16); } return arrayBuffer; }; export const arrayBufferToBigInt = (arrayBuffer) => { const hex = []; // we can't use map here because map will return Uint8Array which will screw up the parsing below new Uint8Array(arrayBuffer).forEach((i) => { hex.push(("0" + i.toString(16)).slice(-2)); // i.toString(16) will transform 01 to 1, so we add it back on and slice takes the last two chars }); return BigInt(`0x${hex.join("")}`); }; /** * Convert some string into ArrayBuffer. * @param str Any UTF8 string, like a username, email, or password */ export function stringToArrayBuffer(str) { return new TextEncoder().encode(str).buffer; } /** * Left pad ArrayBuffer with zeroes. * @param arrayBuffer - ArrayBuffer to pad * @param targetLength Length of the target array in bytes. * @returns Padded array or original array if targetLength is less than original * array length. */ export const padStartArrayBuffer = (arrayBuffer, targetLength) => { const u8 = new Uint8Array(arrayBuffer); if (u8.length < targetLength) { const tmp = new Uint8Array(targetLength); tmp.fill(0, 0, targetLength - u8.length); tmp.set(u8, targetLength - u8.length); return tmp; } return u8; }; export function hash(parameters, ...arrays) { const length = arrays.reduce((p, c) => p + c.byteLength, 0); const target = new Uint8Array(length); for (let offset = 0, i = 0; i < arrays.length; i++) { target.set(new Uint8Array(arrays[i]), offset); offset += arrays[i].byteLength; } return parameters.H(target); } export function hashPadded(parameters, targetLen, ...arrays) { const arraysPadded = arrays.map((arrayBuffer) => padStartArrayBuffer(arrayBuffer, targetLen)); return hash(parameters, ...arraysPadded); } /** * Generates random string of ASCII characters using crypto secure random generator. * @param characterCount The length of the result string. * @return The string. */ export function generateRandomString(characterCount = 10) { const u8 = new Uint8Array(Math.ceil(Math.ceil(characterCount / 2))); // each byte has 2 hex digits crossEnvCrypto.randomBytes(u8); return u8 .reduce((str, i) => { const hex = i.toString(16).toString(); if (hex.length === 1) { return str + "0" + hex; } return str + hex; }, "") .slice(0, characterCount); // so we don't go over when characterCount is odd } export function generateRandomBigInt(numBytes = 16) { return arrayBufferToBigInt(generateRandom(numBytes)); } export function createVerifier(routines, I, s, P) { return __awaiter(this, void 0, void 0, function* () { if (!I || !I.trim()) { throw new Error("Identity (I) must not be null or empty."); } if (!s) { throw new Error("Salt (s) must not be null."); } if (!P) { throw new Error("Password (P) must not be null"); } const x = yield routines.computeX(I, s, P); return routines.computeVerifier(x); }); } export function createVerifierAndSalt(routines, I, P, sBytes) { return __awaiter(this, void 0, void 0, function* () { const s = yield routines.generateRandomSalt(sBytes); return { s, v: yield createVerifier(routines, I, s, P), }; }); } export const hashBitCount = (parameters) => __awaiter(void 0, void 0, void 0, function* () { return (yield hash(parameters, bigIntToArrayBuffer(BigInt(1)))).byteLength * 8; }); /** * Calculates (x**pow) % mod * @param x base * @param pow power * @param mod modulo */ export function modPow(x, pow, mod) { let result = ONE; while (pow > ZERO) { if (pow % TWO == ONE) { result = (x * result) % mod; pow -= ONE; } else { x = (x * x) % mod; pow /= TWO; } } return result; } const generateRandom = (numBytes) => { const u8 = new Uint8Array(numBytes); crossEnvCrypto.randomBytes(u8); return u8.buffer; }; //# sourceMappingURL=utils.js.map