UNPKG

tink-crypto

Version:

A multi-language, cross-platform library that provides cryptographic APIs that are secure, easy to use correctly, and hard(er) to misuse.

185 lines 18.7 kB
/** * @license * Copyright 2020 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import { InvalidArgumentsException } from '../exception/invalid_arguments_exception'; /** * Does near constant time byte array comparison. * @param ba1 The first bytearray to check. * @param ba2 The second bytearray to check. * @return If the array are equal. */ export function isEqual(ba1, ba2) { if (ba1.length !== ba2.length) { return false; } let result = 0; for (let i = 0; i < ba1.length; i++) { result |= ba1[i] ^ ba2[i]; } return result == 0; } /** * Returns a new array that is the result of joining the arguments. */ export function concat(...var_args) { let length = 0; for (let i = 0; i < arguments.length; i++) { length += arguments[i].length; } const result = new Uint8Array(length); let curOffset = 0; for (let i = 0; i < arguments.length; i++) { result.set(arguments[i], curOffset); curOffset += arguments[i].length; } return result; } /** * Converts a non-negative integer number to a 64-bit big-endian byte array. * @param value The number to convert. * @return The number as a big-endian byte array. * @throws {InvalidArgumentsException} * @static */ export function fromNumber(value) { if (Number.isNaN(value) || value % 1 !== 0) { throw new InvalidArgumentsException('cannot convert non-integer value'); } if (value < 0) { throw new InvalidArgumentsException('cannot convert negative number'); } if (value > Number.MAX_SAFE_INTEGER) { throw new InvalidArgumentsException('cannot convert number larger than ' + Number.MAX_SAFE_INTEGER); } const twoPower32 = Math.pow(2, 32); let low = value % twoPower32; let high = value / twoPower32; const result = new Uint8Array(8); for (let i = 7; i >= 4; i--) { result[i] = low & 255; low >>>= 8; } for (let i = 3; i >= 0; i--) { result[i] = high & 255; high >>>= 8; } return result; } /** * Converts the hex string to a byte array. * * @param hex the input * @return the byte array output * @throws {!InvalidArgumentsException} * @static */ export function fromHex(hex) { if (hex.length % 2 != 0) { throw new InvalidArgumentsException('Hex string length must be multiple of 2'); } const arr = new Uint8Array(hex.length / 2); for (let i = 0; i < hex.length; i += 2) { arr[i / 2] = parseInt(hex.substring(i, i + 2), 16); } return arr; } /** * Converts a byte array to hex. * * @param bytes the byte array input * @return hex the output * @static */ export function toHex(bytes) { let result = ''; for (let i = 0; i < bytes.length; i++) { const hexByte = bytes[i].toString(16); result += hexByte.length > 1 ? hexByte : '0' + hexByte; } return result; } /** * Converts the Base64 string to a byte array. * * @param encoded the base64 string * @param opt_webSafe True indicates we should use the alternative * alphabet, which does not require escaping for use in URLs. * @return the byte array output * @static */ export function fromBase64(encoded, opt_webSafe) { if (opt_webSafe) { const normalBase64 = encoded.replace(/-/g, '+').replace(/_/g, '/'); return fromByteString(window.atob(normalBase64)); } return fromByteString(window.atob(encoded)); } /** * Base64 encode a byte array. * * @param bytes the byte array input * @param opt_webSafe True indicates we should use the alternative * alphabet, which does not require escaping for use in URLs. * @return base64 output * @static */ export function toBase64(bytes, opt_webSafe) { const encoded = window .btoa( /* padding */ toByteString(bytes)) .replace(/=/g, ''); if (opt_webSafe) { return encoded.replace(/\+/g, '-').replace(/\//g, '_'); } return encoded; } /** * Converts a byte string to a byte array. Only support ASCII and Latin-1 * strings, does not support multi-byte characters. * * @param str the input * @return the byte array output * @static */ export function fromByteString(str) { const output = []; let p = 0; for (let i = 0; i < str.length; i++) { const c = str.charCodeAt(i); output[p++] = c; } return new Uint8Array(output); } /** * Turns a byte array into the string given by the concatenation of the * characters to which the numbers correspond. Each byte is corresponding to a * character. Does not support multi-byte characters. * * @param bytes Array of numbers representing * characters. * @return Stringification of the array. */ export function toByteString(bytes) { let str = ''; for (let i = 0; i < bytes.length; i += 1) { str += String.fromCharCode(bytes[i]); } return str; } /** * Returns the element-wise XOR of two byte arrays of the same length */ export function xor(x, y) { if (x.length !== y.length) { throw new InvalidArgumentsException('Both byte arrays should be of the same length'); } const arr = new Uint8Array(x.length); for (let i = 0; i < arr.length; i++) { arr[i] = x[i] ^ y[i]; } return arr; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnl0ZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zdWJ0bGUvYnl0ZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUVILE9BQU8sRUFBQyx5QkFBeUIsRUFBQyxNQUFNLDBDQUEwQyxDQUFDO0FBRW5GOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLE9BQU8sQ0FBQyxHQUFlLEVBQUUsR0FBZTtJQUN0RCxJQUFJLEdBQUcsQ0FBQyxNQUFNLEtBQUssR0FBRyxDQUFDLE1BQU0sRUFBRTtRQUM3QixPQUFPLEtBQUssQ0FBQztLQUNkO0lBQ0QsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFDO0lBQ2YsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDbkMsTUFBTSxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7S0FDM0I7SUFDRCxPQUFPLE1BQU0sSUFBSSxDQUFDLENBQUM7QUFDckIsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLE1BQU0sQ0FBQyxHQUFHLFFBQXNCO0lBQzlDLElBQUksTUFBTSxHQUFHLENBQUMsQ0FBQztJQUNmLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ3pDLE1BQU0sSUFBSSxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO0tBQy9CO0lBQ0QsTUFBTSxNQUFNLEdBQUcsSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDdEMsSUFBSSxTQUFTLEdBQUcsQ0FBQyxDQUFDO0lBQ2xCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFF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ICogU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcbiAqL1xuXG5pbXBvcnQge0ludmFsaWRBcmd1bWVudHNFeGNlcHRpb259IGZyb20gJy4uL2V4Y2VwdGlvbi9pbnZhbGlkX2FyZ3VtZW50c19leGNlcHRpb24nO1xuXG4vKipcbiAqIERvZXMgbmVhciBjb25zdGFudCB0aW1lIGJ5dGUgYXJyYXkgY29tcGFyaXNvbi5cbiAqIEBwYXJhbSBiYTEgVGhlIGZpcnN0IGJ5dGVhcnJheSB0byBjaGVjay5cbiAqIEBwYXJhbSBiYTIgVGhlIHNlY29uZCBieXRlYXJyYXkgdG8gY2hlY2suXG4gKiBAcmV0dXJuIElmIHRoZSBhcnJheSBhcmUgZXF1YWwuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0VxdWFsKGJhMTogVWludDhBcnJheSwgYmEyOiBVaW50OEFycmF5KTogYm9vbGVhbiB7XG4gIGlmIChiYTEubGVuZ3RoICE9PSBiYTIubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGxldCByZXN1bHQgPSAwO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGJhMS5sZW5ndGg7IGkrKykge1xuICAgIHJlc3VsdCB8PSBiYTFbaV0gXiBiYTJbaV07XG4gIH1cbiAgcmV0dXJuIHJlc3VsdCA9PSAwO1xufVxuXG4vKipcbiAqIFJldHVybnMgYSBuZXcgYXJyYXkgdGhhdCBpcyB0aGUgcmVzdWx0IG9mIGpvaW5pbmcgdGhlIGFyZ3VtZW50cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbmNhdCguLi52YXJfYXJnczogVWludDhBcnJheVtdKTogVWludDhBcnJheSB7XG4gIGxldCBsZW5ndGggPSAwO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgIGxlbmd0aCArPSBhcmd1bWVudHNbaV0ubGVuZ3RoO1xuICB9XG4gIGNvbnN0IHJlc3VsdCA9IG5ldyBVaW50OEFycmF5KGxlbmd0aCk7XG4gIGxldCBjdXJPZmZzZXQgPSAwO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgIHJlc3VsdC5zZXQoYXJndW1lbnRzW2ldLCBjdXJPZmZzZXQpO1xuICAgIGN1ck9mZnNldCArPSBhcmd1bWVudHNbaV0ubGVuZ3RoO1xuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKlxuICogQ29udmVydHMgYSBub24tbmVnYXRpdmUgaW50ZWdlciBudW1iZXIgdG8gYSA2NC1iaXQgYmlnLWVuZGlhbiBieXRlIGFycmF5LlxuICogQHBhcmFtIHZhbHVlIFRoZSBudW1iZXIgdG8gY29udmVydC5cbiAqIEByZXR1cm4gVGhlIG51bWJlciBhcyBhIGJpZy1lbmRpYW4gYnl0ZSBhcnJheS5cbiAqIEB0aHJvd3Mge0ludmFsaWRBcmd1bWVudHNFeGNlcHRpb259XG4gKiBAc3RhdGljXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmcm9tTnVtYmVyKHZhbHVlOiBudW1iZXIpOiBVaW50OEFycmF5IHtcbiAgaWYgKE51bWJlci5pc05hTih2YWx1ZSkgfHwgdmFsdWUgJSAxICE9PSAwKSB7XG4gICAgdGhyb3cgbmV3IEludmFsaWRBcmd1bWVudHNFeGNlcHRpb24oJ2Nhbm5vdCBjb252ZXJ0IG5vbi1pbnRlZ2VyIHZhbHVlJyk7XG4gIH1cbiAgaWYgKHZhbHVlIDwgMCkge1xuICAgIHRocm93IG5ldyBJbnZhbGlkQXJndW1lbnRzRXhjZXB0aW9uKCdjYW5ub3QgY29udmVydCBuZWdhdGl2ZSBudW1iZXInKTtcbiAgfVxuICBpZiAodmFsdWUgPiBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUikge1xuICAgIHRocm93IG5ldyBJbnZhbGlkQXJndW1lbnRzRXhjZXB0aW9uKFxuICAgICAgICAnY2Fubm90IGNvbnZlcnQgbnVtYmVyIGxhcmdlciB0aGFuICcgKyBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUik7XG4gIH1cbiAgY29uc3QgdHdvUG93ZXIzMiA9IDIgKiogMzI7XG4gIGxldCBsb3cgPSB2YWx1ZSAlIHR3b1Bvd2VyMzI7XG4gIGxldCBoaWdoID0gdmFsdWUgLyB0d29Qb3dlcjMyO1xuICBjb25zdCByZXN1bHQgPSBuZXcgVWludDhBcnJheSg4KTtcbiAgZm9yIChsZXQgaSA9IDc7IGkgPj0gNDsgaS0tKSB7XG4gICAgcmVzdWx0W2ldID0gbG93ICYgMjU1O1xuICAgIGxvdyA+Pj49IDg7XG4gIH1cbiAgZm9yIChsZXQgaSA9IDM7IGkgPj0gMDsgaS0tKSB7XG4gICAgcmVzdWx0W2ldID0gaGlnaCAmIDI1NTtcbiAgICBoaWdoID4+Pj0gODtcbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKipcbiAqIENvbnZlcnRzIHRoZSBoZXggc3RyaW5nIHRvIGEgYnl0ZSBhcnJheS5cbiAqXG4gKiBAcGFyYW0gaGV4IHRoZSBpbnB1dFxuICogQHJldHVybiB0aGUgYnl0ZSBhcnJheSBvdXRwdXRcbiAqIEB0aHJvd3MgeyFJbnZhbGlkQXJndW1lbnRzRXhjZXB0aW9ufVxuICogQHN0YXRpY1xuICovXG5leHBvcnQgZnVuY3Rpb24gZnJvbUhleChoZXg6IHN0cmluZyk6IFVpbnQ4QXJyYXkge1xuICBpZiAoaGV4Lmxlbmd0aCAlIDIgIT0gMCkge1xuICAgIHRocm93IG5ldyBJbnZhbGlkQXJndW1lbnRzRXhjZXB0aW9uKFxuICAgICAgICAnSGV4IHN0cmluZyBsZW5ndGggbXVzdCBiZSBtdWx0aXBsZSBvZiAyJyk7XG4gIH1cbiAgY29uc3QgYXJyID0gbmV3IFVpbnQ4QXJyYXkoaGV4Lmxlbmd0aCAvIDIpO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGhleC5sZW5ndGg7IGkgKz0gMikge1xuICAgIGFycltpIC8gMl0gPSBwYXJzZUludChoZXguc3Vic3RyaW5nKGksIGkgKyAyKSwgMTYpO1xuICB9XG4gIHJldHVybiBhcnI7XG59XG5cbi8qKlxuICogQ29udmVydHMgYSBieXRlIGFycmF5IHRvIGhleC5cbiAqXG4gKiBAcGFyYW0gYnl0ZXMgdGhlIGJ5dGUgYXJyYXkgaW5wdXRcbiAqIEByZXR1cm4gaGV4IHRoZSBvdXRwdXRcbiAqIEBzdGF0aWNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvSGV4KGJ5dGVzOiBVaW50OEFycmF5KTogc3RyaW5nIHtcbiAgbGV0IHJlc3VsdCA9ICcnO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGJ5dGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3QgaGV4Qnl0ZSA9IGJ5dGVzW2ldLnRvU3RyaW5nKDE2KTtcbiAgICByZXN1bHQgKz0gaGV4Qnl0ZS5sZW5ndGggPiAxID8gaGV4Qnl0ZSA6ICcwJyArIGhleEJ5dGU7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyB0aGUgQmFzZTY0IHN0cmluZyB0byBhIGJ5dGUgYXJyYXkuXG4gKlxuICogQHBhcmFtIGVuY29kZWQgdGhlIGJhc2U2NCBzdHJpbmdcbiAqIEBwYXJhbSBvcHRfd2ViU2FmZSBUcnVlIGluZGljYXRlcyB3ZSBzaG91bGQgdXNlIHRoZSBhbHRlcm5hdGl2ZVxuICogICAgIGFscGhhYmV0LCB3aGljaCBkb2VzIG5vdCByZXF1aXJlIGVzY2FwaW5nIGZvciB1c2UgaW4gVVJMcy5cbiAqIEByZXR1cm4gdGhlIGJ5dGUgYXJyYXkgb3V0cHV0XG4gKiBAc3RhdGljXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmcm9tQmFzZTY0KGVuY29kZWQ6IHN0cmluZywgb3B0X3dlYlNhZmU/OiBib29sZWFuKTogVWludDhBcnJheSB7XG4gIGlmIChvcHRfd2ViU2FmZSkge1xuICAgIGNvbnN0IG5vcm1hbEJhc2U2NCA9IGVuY29kZWQucmVwbGFjZSgvLS9nLCAnKycpLnJlcGxhY2UoL18vZywgJy8nKTtcbiAgICByZXR1cm4gZnJvbUJ5dGVTdHJpbmcod2luZG93LmF0b2Iobm9ybWFsQmFzZTY0KSk7XG4gIH1cbiAgcmV0dXJuIGZyb21CeXRlU3RyaW5nKHdpbmRvdy5hdG9iKGVuY29kZWQpKTtcbn1cblxuLyoqXG4gKiBCYXNlNjQgZW5jb2RlIGEgYnl0ZSBhcnJheS5cbiAqXG4gKiBAcGFyYW0gYnl0ZXMgdGhlIGJ5dGUgYXJyYXkgaW5wdXRcbiAqIEBwYXJhbSBvcHRfd2ViU2FmZSBUcnVlIGluZGljYXRlcyB3ZSBzaG91bGQgdXNlIHRoZSBhbHRlcm5hdGl2ZVxuICogICAgIGFscGhhYmV0LCB3aGljaCBkb2VzIG5vdCByZXF1aXJlIGVzY2FwaW5nIGZvciB1c2UgaW4gVVJMcy5cbiAqIEByZXR1cm4gYmFzZTY0IG91dHB1dFxuICogQHN0YXRpY1xuICovXG5leHBvcnQgZnVuY3Rpb24gdG9CYXNlNjQoYnl0ZXM6IFVpbnQ4QXJyYXksIG9wdF93ZWJTYWZlPzogYm9vbGVhbik6IHN0cmluZyB7XG4gIGNvbnN0IGVuY29kZWQgPSB3aW5kb3dcbiAgICAgICAgICAgICAgICAgICAgICAuYnRvYShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLyogcGFkZGluZyAqL1xuICAgICAgICAgICAgICAgICAgICAgICAgICB0b0J5dGVTdHJpbmcoYnl0ZXMpKVxuICAgICAgICAgICAgICAgICAgICAgIC5yZXBsYWNlKC89L2csICcnKTtcbiAgaWYgKG9wdF93ZWJTYWZlKSB7XG4gICAgcmV0dXJuIGVuY29kZWQucmVwbGFjZSgvXFwrL2csICctJykucmVwbGFjZSgvXFwvL2csICdfJyk7XG4gIH1cbiAgcmV0dXJuIGVuY29kZWQ7XG59XG5cbi8qKlxuICogQ29udmVydHMgYSBieXRlIHN0cmluZyB0byBhIGJ5dGUgYXJyYXkuIE9ubHkgc3VwcG9ydCBBU0NJSSBhbmQgTGF0aW4tMVxuICogc3RyaW5ncywgZG9lcyBub3Qgc3VwcG9ydCBtdWx0aS1ieXRlIGNoYXJhY3RlcnMuXG4gKlxuICogQHBhcmFtIHN0ciB0aGUgaW5wdXRcbiAqIEByZXR1cm4gdGhlIGJ5dGUgYXJyYXkgb3V0cHV0XG4gKiBAc3RhdGljXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmcm9tQnl0ZVN0cmluZyhzdHI6IHN0cmluZyk6IFVpbnQ4QXJyYXkge1xuICBjb25zdCBvdXRwdXQgPSBbXTtcbiAgbGV0IHAgPSAwO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IHN0ci5sZW5ndGg7IGkrKykge1xuICAgIGNvbnN0IGMgPSBzdHIuY2hhckNvZGVBdChpKTtcbiAgICBvdXRwdXRbcCsrXSA9IGM7XG4gIH1cbiAgcmV0dXJuIG5ldyBVaW50OEFycmF5KG91dHB1dCk7XG59XG5cbi8qKlxuICogVHVybnMgYSBieXRlIGFycmF5IGludG8gdGhlIHN0cmluZyBnaXZlbiBieSB0aGUgY29uY2F0ZW5hdGlvbiBvZiB0aGVcbiAqIGNoYXJhY3RlcnMgdG8gd2hpY2ggdGhlIG51bWJlcnMgY29ycmVzcG9uZC4gRWFjaCBieXRlIGlzIGNvcnJlc3BvbmRpbmcgdG8gYVxuICogY2hhcmFjdGVyLiBEb2VzIG5vdCBzdXBwb3J0IG11bHRpLWJ5dGUgY2hhcmFjdGVycy5cbiAqXG4gKiBAcGFyYW0gYnl0ZXMgQXJyYXkgb2YgbnVtYmVycyByZXByZXNlbnRpbmdcbiAqICAgICBjaGFyYWN0ZXJzLlxuICogQHJldHVybiBTdHJpbmdpZmljYXRpb24gb2YgdGhlIGFycmF5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gdG9CeXRlU3RyaW5nKGJ5dGVzOiBVaW50OEFycmF5KTogc3RyaW5nIHtcbiAgbGV0IHN0ciA9ICcnO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGJ5dGVzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgc3RyICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnl0ZXNbaV0pO1xuICB9XG4gIHJldHVybiBzdHI7XG59XG5cbi8qKlxuICogUmV0dXJucyB0aGUgZWxlbWVudC13aXNlIFhPUiBvZiB0d28gYnl0ZSBhcnJheXMgb2YgdGhlIHNhbWUgbGVuZ3RoXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB4b3IoeDogVWludDhBcnJheSwgeTogVWludDhBcnJheSk6IFVpbnQ4QXJyYXkge1xuICBpZiAoeC5sZW5ndGggIT09IHkubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IEludmFsaWRBcmd1bWVudHNFeGNlcHRpb24oXG4gICAgICAgICdCb3RoIGJ5dGUgYXJyYXlzIHNob3VsZCBiZSBvZiB0aGUgc2FtZSBsZW5ndGgnKTtcbiAgfVxuXG4gIGNvbnN0IGFyciA9IG5ldyBVaW50OEFycmF5KHgubGVuZ3RoKTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyci5sZW5ndGg7IGkrKykge1xuICAgIGFycltpXSA9IHhbaV0gXiB5W2ldO1xuICB9XG5cbiAgcmV0dXJuIGFycjtcbn1cbiJdfQ==