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.

162 lines 21.8 kB
/** * @license * Copyright 2022 Google LLC * SPDX-License-Identifier: Apache-2.0 */ 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 { InvalidArgumentsException } from '../../../exception/invalid_arguments_exception'; import { SecurityException } from '../../../exception/security_exception'; import { PbHpkeKem } from '../../../internal/proto'; import * as bytes from '../../../subtle/bytes'; import * as ellipticCurves from '../../../subtle/elliptic_curves'; /** HPKE mode identifiers. */ export const BASE_MODE = numberToByteArray(1, 0x00); /** HPKE KEM algorithm identifier for P256 HKDF SHA256 KEM */ export const P256_HKDF_SHA256_KEM_ID = numberToByteArray(2, 0x0010); /** HPKE KEM algorithm identifier for P521 HKDF SHA512 KEM */ export const P521_HKDF_SHA512_KEM_ID = numberToByteArray(2, 0x0012); /** HPKE KDF algorithm identifier for HKDF SHA256 KDF */ export const HKDF_SHA256_KDF_ID = numberToByteArray(2, 0x0001); /** HPKE KDF algorithm identifier for HKDF SHA512 KDF */ export const HKDF_SHA512_KDF_ID = numberToByteArray(2, 0x0003); /** HPKE AEAD algorithm identifier for AES128 GCM */ export const AES_128_GCM_AEAD_ID = numberToByteArray(2, 0x0001); /** HPKE AEAD algorithm identifier for AES256 GCM */ export const AES_256_GCM_AEAD_ID = numberToByteArray(2, 0x0002); /** HPKE byte array representation for KEM */ export const KEM = bytes.fromByteString('KEM'); /** HPKE byte array representation for KPKE */ export const HPKE = bytes.fromByteString('HPKE'); /** HPKE byte array representation for HPKE-v1 */ export const HPKE_V1 = bytes.fromByteString('HPKE-v1'); /** * Transforms a passed value to an MSB first byte array with the size of the * specified capacity. * * The HPKE standard defines this function as I2OSP(n, w) where w = * capacity and n = value. * * @see https://www.rfc-editor.org/rfc/rfc9180.html#name-notation */ export function numberToByteArray(capacity, value) { const result = new Uint8Array(capacity); for (let i = 0; i < capacity; i++) { result[i] = (value >> (8 * (capacity - i - 1))) & 0xFF; } return result; } /** * Transforms `value` to a MSB-first byte array of size `capacity`. * * The HPKE standard defines this function as I2OSP(n, w) where w = * capacity and n = value. * * @see https://www.rfc-editor.org/rfc/rfc9180.html#name-notation * */ export function bigIntToByteArray(capacity, value) { const result = new Uint8Array(capacity); for (let i = 0; i < capacity; i++) { result[i] = Number((value >> BigInt((8 * (capacity - i - 1))))) & 0xFF; } return result; } /** * Generates KEM suite id from `kemId` according to the definition in * @see https://www.rfc-editor.org/rfc/rfc9180.html#section-4.1-5. Only used for * KEM suite id. * @throws SecurityException if byte concatenation fails. */ export function kemSuiteId(kemId) { return bytes.concat(KEM, kemId); } /** * Generates HPKE suite id from `kemId`, `kdfId`, and `aeadId` according to the * definition in @see https://www.rfc-editor.org/rfc/rfc9180.html#section-5.1-8. * Used for any non-KEM suite id. * @throws a SecurityException if byte concatenation fails. */ export function hpkeSuiteId({ kemId, kdfId, aeadId }) { return bytes.concat(HPKE, kemId, kdfId, aeadId); } /** * Transforms `ikm` into labeled ikm using `label` and `suiteId` according to * `LabeledExtract()` defined in * @see https://www.rfc-editor.org/rfc/rfc9180.html#section-4. * @throws an SecurityException if byte concatenation fails. */ export function labelIkm({ ikmLabel, ikm, suiteId }) { return bytes.concat(HPKE_V1, suiteId, bytes.fromByteString(ikmLabel), ikm); } /** * Transforms `info` into labeled info using `label`, `suiteId`, and `length` * according to `LabeledExpand()` defined in * @see https://www.rfc-editor.org/rfc/rfc9180.html#section-4. * @throws a SecurityException if byte concatenation fails. */ export function labelInfo({ infoLabel, info, suiteId, length }) { return bytes.concat(numberToByteArray(2, length), HPKE_V1, suiteId, bytes.fromByteString(infoLabel), info); } /** Translates the NIST HPKE KEM identifier to the corresponding curve type */ export function nistHpkeKemToCurve(kem) { switch (kem) { case PbHpkeKem.DHKEM_P256_HKDF_SHA256: return ellipticCurves.CurveType.P256; case PbHpkeKem.DHKEM_P521_HKDF_SHA512: return ellipticCurves.CurveType.P521; default: throw new InvalidArgumentsException('Unrecognized NIST HPKE KEM identifier'); } } /** * Performs the uncompressed string (given as `key` in the form of a byte array) * to elliptic curve (given via (string) `curveType`) point conversion according * to Section 2.3.3 of https://secg.org/sec1-v2.pdf and returns the result as a * CryptoKey. */ export function getPublicKeyFromByteArray(curveType, key) { return __awaiter(this, void 0, void 0, function* () { const jsonWebKey = ellipticCurves.pointDecode(curveType, ellipticCurves.PointFormatType.UNCOMPRESSED, key); return yield ellipticCurves.importPublicKey('ECDH', jsonWebKey); }); } /** * Converts `{curveType, publicKey, privateKey}`, into a private `CryptoKey`. * * The `publicKey` is an uncompressed point encoded according to * Section 2.3.3 of @see https://secg.org/sec1-v2.pdf. The `privateKey` is a * large integer encoded according to Section 2.3.5 of * @see https://secg.org/sec1-v2.pdf. `curveType` is the the string * representation of the elliptic curve on which to perform the conversion. */ export function getPrivateKeyFromByteArray({ curveType, publicKey, privateKey }) { return __awaiter(this, void 0, void 0, function* () { const jsonWebKey = ellipticCurves.pointDecode(curveType, ellipticCurves.PointFormatType.UNCOMPRESSED, publicKey); jsonWebKey.d = bytes.toBase64(privateKey, true); return yield ellipticCurves.importPrivateKey('ECDH', jsonWebKey); }); } /** * Converts a public `key` into a `Uint8Array` containing an * uncompressed point encoded according to Section 2.3.3 of * @see https://secg.org/sec1-v2.pdf. */ export function getByteArrayFromPublicKey(key) { return __awaiter(this, void 0, void 0, function* () { const alg = key.algorithm; const jsonWebKey = yield ellipticCurves.exportCryptoKey(key); if (!jsonWebKey.crv) { throw new SecurityException('Curve has to be defined.'); } return ellipticCurves.pointEncode(alg.namedCurve, ellipticCurves.PointFormatType.UNCOMPRESSED, jsonWebKey); }); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHBrZV91dGlsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vaHlicmlkL2ludGVybmFsL2hwa2UvaHBrZV91dGlsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7O0dBSUc7Ozs7Ozs7Ozs7QUFFSCxPQUFPLEVBQUMseUJBQXlCLEVBQUMsTUFBTSxnREFBZ0QsQ0FBQztBQUN6RixPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSx1Q0FBdUMsQ0FBQztBQUN4RSxPQUFPLEVBQUMsU0FBUyxFQUFDLE1BQU0seUJBQXlCLENBQUM7QUFDbEQsT0FBTyxLQUFLLEtBQUssTUFBTSx1QkFBdUIsQ0FBQztBQUMvQyxPQUFPLEtBQUssY0FBYyxNQUFNLGlDQUFpQyxDQUFDO0FBRWxFLDZCQUE2QjtBQUM3QixNQUFNLENBQUMsTUFBTSxTQUFTLEdBQUcsaUJBQWlCLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDO0FBRXBELDZEQUE2RDtBQUM3RCxNQUFNLENBQUMsTUFBTSx1QkFBdUIsR0FBRyxpQkFBaUIsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUM7QUFFcEUsNkRBQTZEO0FBQzdELE1BQU0sQ0FBQyxNQUFNLHVCQUF1QixHQUFHLGlCQUFpQixDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQztBQUVwRSx3REFBd0Q7QUFDeEQsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQUcsaUJBQWlCLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0FBRS9ELHdEQUF3RDtBQUN4RCxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRyxpQkFBaUIsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUM7QUFFL0Qsb0RBQW9EO0FBQ3BELE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFHLGlCQUFpQixDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQztBQUNoRSxvREFBb0Q7QUFDcEQsTUFBTSxDQUFDLE1BQU0s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Q0FBQyxHQUFHLEVBQUU7WUFDbkIsTUFBTSxJQUFJLGlCQUFpQixDQUFDLDBCQUEwQixDQUFDLENBQUM7U0FDekQ7UUFFRCxPQUFPLGNBQWMsQ0FBQyxXQUFXLENBQzdCLEdBQUcsQ0FBQyxVQUFVLEVBQUUsY0FBYyxDQUFDLGVBQWUsQ0FBQyxZQUFZLEVBQUUsVUFBVSxDQUFDLENBQUM7SUFDL0UsQ0FBQztDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMjIgR29vZ2xlIExMQ1xuICogU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcbiAqL1xuXG5pbXBvcnQge0ludmFsaWRBcmd1bWVudHNFeGNlcHRpb259IGZyb20gJy4uLy4uLy4uL2V4Y2VwdGlvbi9pbnZhbGlkX2FyZ3VtZW50c19leGNlcHRpb24nO1xuaW1wb3J0IHtTZWN1cml0eUV4Y2VwdGlvbn0gZnJvbSAnLi4vLi4vLi4vZXhjZXB0aW9uL3NlY3VyaXR5X2V4Y2VwdGlvbic7XG5pbXBvcnQge1BiSHBrZUtlbX0gZnJvbSAnLi4vLi4vLi4vaW50ZXJuYWwvcHJvdG8nO1xuaW1wb3J0ICogYXMgYnl0ZXMgZnJvbSAnLi4vLi4vLi4vc3VidGxlL2J5dGVzJztcbmltcG9ydCAqIGFzIGVsbGlwdGljQ3VydmVzIGZyb20gJy4uLy4uLy4uL3N1YnRsZS9lbGxpcHRpY19jdXJ2ZXMnO1xuXG4vKiogSFBLRSBtb2RlIGlkZW50aWZpZXJzLiAqL1xuZXhwb3J0IGNvbnN0IEJBU0VfTU9ERSA9IG51bWJlclRvQnl0ZUFycmF5KDEsIDB4MDApO1xuXG4vKiogSFBLRSBLRU0gYWxnb3JpdGhtIGlkZW50aWZpZXIgZm9yIFAyNTYgSEtERiBTSEEyNTYgS0VNICovXG5leHBvcnQgY29uc3QgUDI1Nl9IS0RGX1NIQTI1Nl9LRU1fSUQgPSBudW1iZXJUb0J5dGVBcnJheSgyLCAweDAwMTApO1xuXG4vKiogSFBLRSBLRU0gYWxnb3JpdGhtIGlkZW50aWZpZXIgZm9yIFA1MjEgSEtERiBTSEE1MTIgS0VNICovXG5leHBvcnQgY29uc3QgUDUyMV9IS0RGX1NIQTUxMl9LRU1fSUQgPSBudW1iZXJUb0J5dGVBcnJheSgyLCAweDAwMTIpO1xuXG4vKiogSFBLRSBLREYgYWxnb3JpdGhtIGlkZW50aWZpZXIgZm9yIEhLREYgU0hBMjU2IEtERiAqL1xuZXhwb3J0IGNvbnN0IEhLREZfU0hBMjU2X0tERl9JRCA9IG51bWJlclRvQnl0ZUFycmF5KDIsIDB4MDAwMSk7XG5cbi8qKiBIUEtFIEtERiBhbGdvcml0aG0gaWRlbnRpZmllciBmb3IgSEtERiBTSEE1MTIgS0RGICovXG5leHBvcnQgY29uc3QgSEtERl9TSEE1MTJfS0RGX0lEID0gbnVtYmVyVG9CeXRlQXJyYXkoMiwgMHgwMDAzKTtcblxuLyoqIEhQS0UgQUVBRCBhbGdvcml0aG0gaWRlbnRpZmllciBmb3IgQUVTMTI4IEdDTSAqL1xuZXhwb3J0IGNvbnN0IEFFU18xMjhfR0NNX0FFQURfSUQgPSBudW1iZXJUb0J5dGVBcnJheSgyLCAweDAwMDEpO1xuLyoqIEhQS0UgQUVBRCBhbGdvcml0aG0gaWRlbnRpZmllciBmb3IgQUVTMjU2IEdDTSAqL1xuZXhwb3J0IGNvbnN0IEFFU18yNTZfR0NNX0FFQURfSUQgPSBudW1iZXJUb0J5dGVBcnJheSgyLCAweDAwMDIpO1xuXG4vKiogSFBLRSBieXRlIGFycmF5IHJlcHJlc2VudGF0aW9uIGZvciBLRU0gKi9cbmV4cG9ydCBjb25zdCBLRU0gPSBieXRlcy5mcm9tQnl0ZVN0cmluZygnS0VNJyk7XG4vKiogSFBLRSBieXRlIGFycmF5IHJlcHJlc2VudGF0aW9uIGZvciBLUEtFICovXG5leHBvcnQgY29uc3QgSFBLRSA9IGJ5dGVzLmZyb21CeXRlU3RyaW5nKCdIUEtFJyk7XG4vKiogSFBLRSBieXRlIGFycmF5IHJlcHJlc2VudGF0aW9uIGZvciBIUEtFLXYxICovXG5leHBvcnQgY29uc3QgSFBLRV9WMSA9IGJ5dGVzLmZyb21CeXRlU3RyaW5nKCdIUEtFLXYxJyk7XG5cbi8qKlxuICogVHJhbnNmb3JtcyBhIHBhc3NlZCB2YWx1ZSB0byBhbiBNU0IgZmlyc3QgYnl0ZSBhcnJheSB3aXRoIHRoZSBzaXplIG9mIHRoZVxuICogc3BlY2lmaWVkIGNhcGFjaXR5LlxuICpcbiAqIFRoZSBIUEtFIHN0YW5kYXJkIGRlZmluZXMgdGhpcyBmdW5jdGlvbiBhcyBJMk9TUChuLCB3KSB3aGVyZSB3ID1cbiAqIGNhcGFjaXR5IGFuZCBuID0gdmFsdWUuXG4gKlxuICogQHNlZSBodHRwczovL3d3dy5yZmMtZWRpdG9yLm9yZy9yZmMvcmZjOTE4MC5odG1sI25hbWUtbm90YXRpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG51bWJlclRvQnl0ZUFycmF5KGNhcGFjaXR5OiBudW1iZXIsIHZhbHVlOiBudW1iZXIpOiBVaW50OEFycmF5IHtcbiAgY29uc3QgcmVzdWx0ID0gbmV3IFVpbnQ4QXJyYXkoY2FwYWNpdHkpO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGNhcGFjaXR5OyBpKyspIHtcbiAgICByZXN1bHRbaV0gPSAodmFsdWUgPj4gKDggKiAoY2FwYWNpdHkgLSBpIC0gMSkpKSAmIDB4RkY7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuXG4vKipcbiAqIFRyYW5zZm9ybXMgYHZhbHVlYCB0byBhIE1TQi1maXJzdCBieXRlIGFycmF5IG9mIHNpemUgYGNhcGFjaXR5YC5cbiAqXG4gKiBUaGUgSFBLRSBzdGFuZGFyZCBkZWZpbmVzIHRoaXMgZnVuY3Rpb24gYXMgSTJPU1Aobiwgdykgd2hlcmUgdyA9XG4gKiBjYXBhY2l0eSBhbmQgbiA9IHZhbHVlLlxuICpcbiAqIEBzZWUgaHR0cHM6Ly93d3cucmZjLWVkaXRvci5vcmcvcmZjL3JmYzkxODAuaHRtbCNuYW1lLW5vdGF0aW9uXG4gKlxuICovXG5leHBvcnQgZnVuY3Rpb24gYmlnSW50VG9CeXRlQXJyYXkoY2FwYWNpdHk6IG51bWJlciwgdmFsdWU6IGJpZ2ludCk6IFVpbnQ4QXJyYXkge1xuICBjb25zdCByZXN1bHQgPSBuZXcgVWludDhBcnJheShjYXBhY2l0eSk7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgY2FwYWNpdHk7IGkrKykge1xuICAgIHJlc3VsdFtpXSA9IE51bWJlcigodmFsdWUgPj4gQmlnSW50KCg4ICogKGNhcGFjaXR5IC0gaSAtIDEpKSkpKSAmIDB4RkY7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuLyoqXG4gKiBHZW5lcmF0ZXMgS0VNIHN1aXRlIGlkIGZyb20gYGtlbUlkYCBhY2NvcmRpbmcgdG8gdGhlIGRlZmluaXRpb24gaW5cbiAqIEBzZWUgaHR0cHM6Ly93d3cucmZjLWVkaXRvci5vcmcvcmZjL3JmYzkxODAuaHRtbCNzZWN0aW9uLTQuMS01LiBPbmx5IHVzZWQgZm9yXG4gKiBLRU0gc3VpdGUgaWQuXG4gKiBAdGhyb3dzIFNlY3VyaXR5RXhjZXB0aW9uIGlmIGJ5dGUgY29uY2F0ZW5hdGlvbiBmYWlscy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGtlbVN1aXRlSWQoa2VtSWQ6IFVpbnQ4QXJyYXkpOiBVaW50OEFycmF5IHtcbiAgcmV0dXJuIGJ5dGVzLmNvbmNhdChLRU0sIGtlbUlkKTtcbn1cblxuLyoqXG4gKiBHZW5lcmF0ZXMgSFBLRSBzdWl0ZSBpZCBmcm9tIGBrZW1JZGAsIGBrZGZJZGAsIGFuZCBgYWVhZElkYCBhY2NvcmRpbmcgdG8gdGhlXG4gKiBkZWZpbml0aW9uIGluIEBzZWUgaHR0cHM6Ly93d3cucmZjLWVkaXRvci5vcmcvcmZjL3JmYzkxODAuaHRtbCNzZWN0aW9uLTUuMS04LlxuICogVXNlZCBmb3IgYW55IG5vbi1LRU0gc3VpdGUgaWQuXG4gKiBAdGhyb3dzIGEgU2VjdXJpdHlFeGNlcHRpb24gaWYgYnl0ZSBjb25jYXRlbmF0aW9uIGZhaWxzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaHBrZVN1aXRlSWQoXG4gICAge2tlbUlkLCBrZGZJZCwgYWVhZElkfTpcbiAgICAgICAge2tlbUlkOiBVaW50OEFycmF5LCBrZGZJZDogVWludDhBcnJheSwgYWVhZElkOiBVaW50OEFycmF5fSk6XG4gICAgVWludDhBcnJheSB7XG4gIHJldHVybiBieXRlcy5jb25jYXQoSFBLRSwga2VtSWQsIGtkZklkLCBhZWFkSWQpO1xufVxuXG4vKipcbiAqIFRyYW5zZm9ybXMgYGlrbWAgaW50byBsYWJlbGVkIGlrbSB1c2luZyBgbGFiZWxgIGFuZCBgc3VpdGVJZGAgYWNjb3JkaW5nIHRvXG4gKiBgTGFiZWxlZEV4dHJhY3QoKWAgZGVmaW5lZCBpblxuICogQHNlZSBodHRwczovL3d3dy5yZmMtZWRpdG9yLm9yZy9yZmMvcmZjOTE4MC5odG1sI3NlY3Rpb24tNC5cbiAqIEB0aHJvd3MgYW4gU2VjdXJpdHlFeGNlcHRpb24gaWYgYnl0ZSBjb25jYXRlbmF0aW9uIGZhaWxzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbGFiZWxJa20oXG4gICAge2lrbUxhYmVsLCBpa20sIHN1aXRlSWR9OlxuICAgICAgICB7aWttTGFiZWw6IHN0cmluZywgaWttOiBVaW50OEFycmF5LCBzdWl0ZUlkOiBVaW50OEFycmF5fSk6IFVpbnQ4QXJyYXkge1xuICByZXR1cm4gYnl0ZXMuY29uY2F0KEhQS0VfVjEsIHN1aXRlSWQsIGJ5dGVzLmZyb21CeXRlU3RyaW5nKGlrbUxhYmVsKSwgaWttKTtcbn1cblxuLyoqXG4gKiBUcmFuc2Zvcm1zIGBpbmZvYCBpbnRvIGxhYmVsZWQgaW5mbyB1c2luZyBgbGFiZWxgLCBgc3VpdGVJZGAsIGFuZCBgbGVuZ3RoYFxuICogYWNjb3JkaW5nIHRvIGBMYWJlbGVkRXhwYW5kKClgIGRlZmluZWQgaW5cbiAqIEBzZWUgaHR0cHM6Ly93d3cucmZjLWVkaXRvci5vcmcvcmZjL3JmYzkxODAuaHRtbCNzZWN0aW9uLTQuXG4gKiBAdGhyb3dzIGEgU2VjdXJpdHlFeGNlcHRpb24gaWYgYnl0ZSBjb25jYXRlbmF0aW9uIGZhaWxzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbGFiZWxJbmZvKHtpbmZvTGFiZWwsIGluZm8sIHN1aXRlSWQsIGxlbmd0aH06IHtcbiAgaW5mb0xhYmVsOiBzdHJpbmcsXG4gIGluZm86IFVpbnQ4QXJyYXksXG4gIHN1aXRlSWQ6IFVpbnQ4QXJyYXksXG4gIGxlbmd0aDogbnVtYmVyXG59KTogVWludDhBcnJheSB7XG4gIHJldHVybiBieXRlcy5jb25jYXQoXG4gICAgICBudW1iZXJUb0J5dGVBcnJheSgyLCBsZW5ndGgpLCBIUEtFX1YxLCBzdWl0ZUlkLFxuICAgICAgYnl0ZXMuZnJvbUJ5dGVTdHJpbmcoaW5mb0xhYmVsKSwgaW5mbyk7XG59XG5cbi8qKiBUcmFuc2xhdGVzIHRoZSBOSVNUIEhQS0UgS0VNIGlkZW50aWZpZXIgdG8gdGhlIGNvcnJlc3BvbmRpbmcgY3VydmUgdHlwZSAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5pc3RIcGtlS2VtVG9DdXJ2ZShrZW06IFBiSHBrZUtlbSk6XG4gICAgZWxsaXB0aWNDdXJ2ZXMuQ3VydmVUeXBlLlAyNTZ8ZWxsaXB0aWNDdXJ2ZXMuQ3VydmVUeXBlLlA1MjEge1xuICBzd2l0Y2ggKGtlbSkge1xuICAgIGNhc2UgUGJIcGtlS2VtLkRIS0VNX1AyNTZfSEtERl9TSEEyNTY6XG4gICAgICByZXR1cm4gZWxsaXB0aWNDdXJ2ZXMuQ3VydmVUeXBlLlAyNTY7XG4gICAgY2FzZSBQYkhwa2VLZW0uREhLRU1fUDUyMV9IS0RGX1NIQTUxMjpcbiAgICAgIHJldHVybiBlbGxpcHRpY0N1cnZlcy5DdXJ2ZVR5cGUuUDUyMTtcbiAgICBkZWZhdWx0OlxuICAgICAgdGhyb3cgbmV3IEludmFsaWRBcmd1bWVudHNFeGNlcHRpb24oXG4gICAgICAgICAgJ1VucmVjb2duaXplZCBOSVNUIEhQS0UgS0VNIGlkZW50aWZpZXInKTtcbiAgfVxufVxuXG4vKipcbiAqIFBlcmZvcm1zIHRoZSB1bmNvbXByZXNzZWQgc3RyaW5nIChnaXZlbiBhcyBga2V5YCBpbiB0aGUgZm9ybSBvZiBhIGJ5dGUgYXJyYXkpXG4gKiB0byBlbGxpcHRpYyBjdXJ2ZSAoZ2l2ZW4gdmlhIChzdHJpbmcpIGBjdXJ2ZVR5cGVgKSBwb2ludCBjb252ZXJzaW9uIGFjY29yZGluZ1xuICogdG8gU2VjdGlvbiAyLjMuMyBvZiBodHRwczovL3NlY2cub3JnL3NlYzEtdjIucGRmIGFuZCByZXR1cm5zIHRoZSByZXN1bHQgYXMgYVxuICogQ3J5cHRvS2V5LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0UHVibGljS2V5RnJvbUJ5dGVBcnJheShcbiAgICBjdXJ2ZVR5cGU6IHN0cmluZywga2V5OiBVaW50OEFycmF5KTogUHJvbWlzZTxDcnlwdG9LZXk+IHtcbiAgY29uc3QganNvbldlYktleSA9IGVsbGlwdGljQ3VydmVzLnBvaW50RGVjb2RlKFxuICAgICAgY3VydmVUeXBlLCBlbGxpcHRpY0N1cnZlcy5Qb2ludEZvcm1hdFR5cGUuVU5DT01QUkVTU0VELCBrZXkpO1xuICByZXR1cm4gYXdhaXQgZWxsaXB0aWNDdXJ2ZXMuaW1wb3J0UHVibGljS2V5KCdFQ0RIJywganNvbldlYktleSk7XG59XG5cbi8qKlxuICogQ29udmVydHMgYHtjdXJ2ZVR5cGUsIHB1YmxpY0tleSwgcHJpdmF0ZUtleX1gLCBpbnRvIGEgcHJpdmF0ZSBgQ3J5cHRvS2V5YC5cbiAqXG4gKiBUaGUgYHB1YmxpY0tleWAgaXMgYW4gdW5jb21wcmVzc2VkIHBvaW50IGVuY29kZWQgYWNjb3JkaW5nIHRvXG4gKiBTZWN0aW9uIDIuMy4zIG9mIEBzZWUgaHR0cHM6Ly9zZWNnLm9yZy9zZWMxLXYyLnBkZi4gVGhlIGBwcml2YXRlS2V5YCBpcyBhXG4gKiBsYXJnZSBpbnRlZ2VyIGVuY29kZWQgYWNjb3JkaW5nIHRvIFNlY3Rpb24gMi4zLjUgb2ZcbiAqIEBzZWUgaHR0cHM6Ly9zZWNnLm9yZy9zZWMxLXYyLnBkZi4gYGN1cnZlVHlwZWAgaXMgdGhlIHRoZSBzdHJpbmdcbiAqIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBlbGxpcHRpYyBjdXJ2ZSBvbiB3aGljaCB0byBwZXJmb3JtIHRoZSBjb252ZXJzaW9uLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0UHJpdmF0ZUtleUZyb21CeXRlQXJyYXkoXG4gICAge2N1cnZlVHlwZSwgcHVibGljS2V5LCBwcml2YXRlS2V5fTpcbiAgICAgICAge2N1cnZlVHlwZTogc3RyaW5nLCBwdWJsaWNLZXk6IFVpbnQ4QXJyYXksIHByaXZhdGVLZXk6IFVpbnQ4QXJyYXl9KTpcbiAgICBQcm9taXNlPENyeXB0b0tleT4ge1xuICBjb25zdCBqc29uV2ViS2V5ID0gZWxsaXB0aWNDdXJ2ZXMucG9pbnREZWNvZGUoXG4gICAgICBjdXJ2ZVR5cGUsIGVsbGlwdGljQ3VydmVzLlBvaW50Rm9ybWF0VHlwZS5VTkNPTVBSRVNTRUQsIHB1YmxpY0tleSk7XG5cbiAganNvbldlYktleS5kID0gYnl0ZXMudG9CYXNlNjQocHJpdmF0ZUtleSwgdHJ1ZSk7XG5cbiAgcmV0dXJuIGF3YWl0IGVsbGlwdGljQ3VydmVzLmltcG9ydFByaXZhdGVLZXkoJ0VDREgnLCBqc29uV2ViS2V5KTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBhIHB1YmxpYyBga2V5YCBpbnRvIGEgYFVpbnQ4QXJyYXlgIGNvbnRhaW5pbmcgYW5cbiAqIHVuY29tcHJlc3NlZCBwb2ludCBlbmNvZGVkIGFjY29yZGluZyB0byBTZWN0aW9uIDIuMy4zIG9mXG4gKiBAc2VlIGh0dHBzOi8vc2VjZy5vcmcvc2VjMS12Mi5wZGYuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRCeXRlQXJyYXlGcm9tUHVibGljS2V5KGtleTogQ3J5cHRvS2V5KTpcbiAgICBQcm9taXNlPFVpbnQ4QXJyYXk+IHtcbiAgY29uc3QgYWxnOiBFY0tleUdlblBhcmFtcyA9IGtleS5hbGdvcml0aG0gYXMgRWNLZXlHZW5QYXJhbXM7XG4gIGNvbnN0IGpzb25XZWJLZXkgPSBhd2FpdCBlbGxpcHRpY0N1cnZlcy5leHBvcnRDcnlwdG9LZXkoa2V5KTtcblxuICBpZiAoIWpzb25XZWJLZXkuY3J2KSB7XG4gICAgdGhyb3cgbmV3IFNlY3VyaXR5RXhjZXB0aW9uKCdDdXJ2ZSBoYXMgdG8gYmUgZGVmaW5lZC4nKTtcbiAgfVxuXG4gIHJldHVybiBlbGxpcHRpY0N1cnZlcy5wb2ludEVuY29kZShcbiAgICAgIGFsZy5uYW1lZEN1cnZlLCBlbGxpcHRpY0N1cnZlcy5Qb2ludEZvcm1hdFR5cGUuVU5DT01QUkVTU0VELCBqc29uV2ViS2V5KTtcbn1cbiJdfQ==