UNPKG

@wault-pw/srp6a-webcrypto

Version:

Pure javascript implementation of SRP-6a (RFC-5054, RFC-2945) using web-crypto

58 lines (48 loc) 2.09 kB
import bigInt from "big-integer" import {Params} from "./rfc5054" import {BigInt2Uint8Array, BigIntFromInt, BigIntFromUint8Array, Hash} from "./util" export class Engine { readonly N: bigInt.BigInteger; readonly g: bigInt.BigInteger; readonly hash: string; public get N_SIZE(): number { return this.N.bitLength().toJSNumber() >> 3 } constructor(params: Params) { this.N = BigIntFromUint8Array(params.N) this.g = BigIntFromInt(params.g) this.hash = params.hash } async k(): Promise<bigInt.BigInteger> { return BigIntFromUint8Array(await this.HASH(BigInt2Uint8Array(this.N), this.PAD(BigInt2Uint8Array(this.g)))) } isModZero(a: bigInt.BigInteger, b: bigInt.BigInteger): boolean { return a.mod(b).isZero() } async HASH(...inputs: (Uint8Array)[]): Promise<Uint8Array> { return await Hash(this.hash, ...inputs) } // Conversion between integers and byte-strings assumes the most // significant bytes are stored first, as per [TLS] and [SRP-RFC]. In // the following text, if a conversion from integer to byte-string is // implicit, the most significant byte in the resultant byte-string MUST // be non-zero. If a conversion is explicitly specified with the // operator PAD(), the integer will first be implicitly converted, then // the resultant byte-string will be left-padded with zeros (if // necessary) until its length equals the implicitly-converted length of // N. // // In other words RFC5054 specifies that number should be // left-padded with zeros to be the same length as N. PAD(input: Uint8Array) { if (input.length >= this.N_SIZE) { return input } const diff = this.N_SIZE - input.length return new Uint8Array([...new Uint8Array(diff), ...input]) } async HASHED_CRED(username: string, password: string): Promise<Uint8Array> { const credentials = new TextEncoder().encode(username + ":" + password) return await this.HASH(credentials) } }