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.
215 lines • 28.1 kB
JavaScript
/**
* @license
* Copyright 2020 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 { SecurityException } from '../exception/security_exception';
import { PbEcdsaKeyFormat, PbEcdsaPrivateKey, PbEcdsaPublicKey, PbKeyData } from '../internal/proto';
import * as Util from '../internal/util';
import * as Bytes from '../subtle/bytes';
import * as ecdsaSign from '../subtle/ecdsa_sign';
import * as EllipticCurves from '../subtle/elliptic_curves';
import { EcdsaPublicKeyManager } from './ecdsa_public_key_manager';
import * as EcdsaUtil from './ecdsa_util';
import { PublicKeySign } from './internal/public_key_sign';
const VERSION = 0;
/**
* @final
*/
class EcdsaPrivateKeyFactory {
/**
*/
newKey(keyFormat) {
return __awaiter(this, void 0, void 0, function* () {
if (!keyFormat) {
throw new SecurityException('Key format has to be non-null.');
}
const keyFormatProto = EcdsaPrivateKeyFactory.getKeyFormatProto(keyFormat);
EcdsaUtil.validateKeyFormat(keyFormatProto);
const params = keyFormatProto.getParams();
if (!params) {
throw new SecurityException('Params not set');
}
const curveTypeProto = params.getCurve();
const curveTypeSubtle = Util.curveTypeProtoToSubtle(curveTypeProto);
const curveName = EllipticCurves.curveToString(curveTypeSubtle);
const keyPair = yield EllipticCurves.generateKeyPair('ECDSA', curveName);
const jsonPublicKey = yield EllipticCurves.exportCryptoKey(keyPair.publicKey);
const jsonPrivateKey = yield EllipticCurves.exportCryptoKey(keyPair.privateKey);
return EcdsaPrivateKeyFactory.jsonToProtoKey(jsonPrivateKey, jsonPublicKey, params);
});
}
/**
*/
newKeyData(serializedKeyFormat) {
return __awaiter(this, void 0, void 0, function* () {
const key = yield this.newKey(serializedKeyFormat);
const keyData = (new PbKeyData())
.setTypeUrl(EcdsaPrivateKeyManager.KEY_TYPE)
.setValue(key.serializeBinary())
.setKeyMaterialType(PbKeyData.KeyMaterialType.ASYMMETRIC_PRIVATE);
return keyData;
});
}
getPublicKeyData(serializedPrivateKey) {
const privateKey = deserializePrivateKey(serializedPrivateKey);
const publicKey = privateKey.getPublicKey();
if (!publicKey) {
throw new SecurityException('Public key not set');
}
const publicKeyData = (new PbKeyData())
.setValue(publicKey.serializeBinary())
.setTypeUrl(EcdsaPublicKeyManager.KEY_TYPE)
.setKeyMaterialType(PbKeyData.KeyMaterialType.ASYMMETRIC_PUBLIC);
return publicKeyData;
}
/**
* Creates a private key proto corresponding to given JSON key pair and with
* the given params.
*
*/
static jsonToProtoKey(jsonPrivateKey, jsonPublicKey, params) {
const { x, y } = jsonPublicKey;
if (x === undefined) {
throw new SecurityException('x must be set');
}
if (y === undefined) {
throw new SecurityException('y must be set');
}
const publicKeyProto = (new PbEcdsaPublicKey())
.setVersion(EcdsaPublicKeyManager.VERSION)
.setParams(params)
.setX(Bytes.fromBase64(x, true))
.setY(Bytes.fromBase64(y, true));
const { d } = jsonPrivateKey;
if (d === undefined) {
throw new SecurityException('d must be set');
}
const privateKeyProto = (new PbEcdsaPrivateKey())
.setVersion(VERSION)
.setPublicKey(publicKeyProto)
.setKeyValue(Bytes.fromBase64(d, true));
return privateKeyProto;
}
/**
* The input keyFormat is either deserialized (in case that the input is
* Uint8Array) or checked to be an EcdsaKeyFormat-proto (otherwise).
*
*/
static getKeyFormatProto(keyFormat) {
if (keyFormat instanceof Uint8Array) {
return EcdsaPrivateKeyFactory.deserializeKeyFormat(keyFormat);
}
else if (keyFormat instanceof PbEcdsaKeyFormat) {
return keyFormat;
}
else {
throw new SecurityException('Expected ' + EcdsaPrivateKeyManager.KEY_TYPE + ' key format proto.');
}
}
static deserializeKeyFormat(keyFormat) {
let keyFormatProto;
try {
keyFormatProto = PbEcdsaKeyFormat.deserializeBinary(keyFormat);
}
catch (e) {
throw new SecurityException('Input cannot be parsed as ' + EcdsaPrivateKeyManager.KEY_TYPE +
' key format proto.');
}
if (!keyFormatProto.getParams()) {
throw new SecurityException('Input cannot be parsed as ' + EcdsaPrivateKeyManager.KEY_TYPE +
' key format proto.');
}
return keyFormatProto;
}
}
/**
* @final
*/
export class EcdsaPrivateKeyManager {
constructor() {
this.keyFactory = new EcdsaPrivateKeyFactory();
}
getPrimitive(primitiveType, key) {
return __awaiter(this, void 0, void 0, function* () {
if (primitiveType !== this.getPrimitiveType()) {
throw new SecurityException('Requested primitive type which is not ' +
'supported by this key manager.');
}
const keyProto = EcdsaPrivateKeyManager.getKeyProto(key);
EcdsaUtil.validatePrivateKey(keyProto, VERSION, EcdsaPublicKeyManager.VERSION);
const recepientPrivateKey = EcdsaUtil.getJsonWebKeyFromProto(keyProto);
const publicKey = keyProto.getPublicKey();
if (!publicKey) {
throw new SecurityException('Public key not set');
}
const params = publicKey.getParams();
if (!params) {
throw new SecurityException('Params not set');
}
const hash = Util.hashTypeProtoToString(params.getHashType());
const encoding = EcdsaUtil.encodingTypeProtoToEnum(params.getEncoding());
return ecdsaSign.fromJsonWebKey(recepientPrivateKey, hash, encoding);
});
}
doesSupport(keyType) {
return keyType === this.getKeyType();
}
getKeyType() {
return EcdsaPrivateKeyManager.KEY_TYPE;
}
getPrimitiveType() {
return EcdsaPrivateKeyManager.SUPPORTED_PRIMITIVE;
}
getVersion() {
return VERSION;
}
getKeyFactory() {
return this.keyFactory;
}
static getKeyProto(keyMaterial) {
if (keyMaterial instanceof PbKeyData) {
return EcdsaPrivateKeyManager.getKeyProtoFromKeyData(keyMaterial);
}
if (keyMaterial instanceof PbEcdsaPrivateKey) {
return keyMaterial;
}
throw new SecurityException('Key type is not supported. This key ' +
'manager supports ' + EcdsaPrivateKeyManager.KEY_TYPE + '.');
}
static getKeyProtoFromKeyData(keyData) {
if (keyData.getTypeUrl() !== EcdsaPrivateKeyManager.KEY_TYPE) {
throw new SecurityException('Key type ' + keyData.getTypeUrl() +
' is not supported. This key manager supports ' +
EcdsaPrivateKeyManager.KEY_TYPE + '.');
}
return deserializePrivateKey(keyData.getValue());
}
}
EcdsaPrivateKeyManager.SUPPORTED_PRIMITIVE = PublicKeySign;
EcdsaPrivateKeyManager.KEY_TYPE = 'type.googleapis.com/google.crypto.tink.EcdsaPrivateKey';
function deserializePrivateKey(serializedPrivateKey) {
let key;
try {
key = PbEcdsaPrivateKey.deserializeBinary(serializedPrivateKey);
}
catch (e) {
throw new SecurityException('Input cannot be parsed as ' + EcdsaPrivateKeyManager.KEY_TYPE +
' key-proto.');
}
if (!key.getPublicKey() || !key.getKeyValue()) {
throw new SecurityException('Input cannot be parsed as ' + EcdsaPrivateKeyManager.KEY_TYPE +
' key-proto.');
}
return key;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWNkc2FfcHJpdmF0ZV9rZXlfbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NpZ25hdHVyZS9lY2RzYV9wcml2YXRlX2tleV9tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7O0dBSUc7Ozs7Ozs7Ozs7QUFFSCxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSxpQ0FBaUMsQ0FBQztBQUVsRSxPQUFPLEVBQUMsZ0JBQWdCLEVBQWlCLGlCQUFpQixFQUFFLGdCQUFnQixFQUFFLFNBQVMsRUFBWSxNQUFNLG1CQUFtQixDQUFDO0FBRTdILE9BQU8sS0FBSyxJQUFJLE1BQU0sa0JBQWtCLENBQUM7QUFFekMsT0FBTyxLQUFLLEtBQUssTUFBTSxpQkFBaUIsQ0FBQztBQUN6QyxPQUFPLEtBQUssU0FBUyxNQUFNLHNCQUFzQixDQUFDO0FBQ2xELE9BQU8sS0FBSyxjQUFjLE1BQU0sMkJBQTJCLENBQUM7QUFFNUQsT0FBTyxFQUFDLHFCQUFxQixFQUFDLE1BQU0sNEJBQTRCLENBQUM7QUFDakUsT0FBTyxLQUFLLFNBQVMsTUFBTSxjQUFjLENBQUM7QUFDMUMsT0FBTyxFQUFDLGFBQWEsRUFBQyxNQUFNLDRCQUE0QixDQUFDO0FBRXpELE1BQU0sT0FBTyxHQUFHLENBQUMsQ0FBQztBQUVsQjs7R0FFRztBQUNILE1BQU0sc0JBQXNCO0lBQzFCO09BQ0c7SUFDRyxNQUFNLENBQUMsU0FBK0I7O1lBQzFDLElBQUksQ0FBQyxTQUFTLEVBQUU7Z0JBQ2QsTUFBTSxJQUFJLGlCQUFpQixDQUFDLGdDQUFnQyxDQUFDLENBQUM7YUFDL0Q7WUFDRCxNQUFNLGNBQWMsR0FBRyxzQkFBc0IsQ0FBQyxpQkFBaUIsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUMzRSxTQUFTLENBQUMsaUJBQWlCLENBQUMsY0FBYyxDQUFDLENBQUM7WUFDNUMsTUFBTSxNQUFNLEdBQUcsY0FBYyxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQzFD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bkQsQ0FBQzs7QUF0RXVCLDBDQUFtQixHQUFHLGFBQWEsQ0FBQztBQUNyRCwrQkFBUSxHQUNYLHdEQUF3RCxDQUFDO0FBdUUvRCxTQUFTLHFCQUFxQixDQUFDLG9CQUFnQztJQUU3RCxJQUFJLEdBQXNCLENBQUM7SUFDM0IsSUFBSTtRQUNGLEdBQUcsR0FBRyxpQkFBaUIsQ0FBQyxpQkFBaUIsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO0tBQ2pFO0lBQUMsT0FBTyxDQUFDLEVBQUU7UUFDVixNQUFNLElBQUksaUJBQWlCLENBQ3ZCLDRCQUE0QixHQUFHLHNCQUFzQixDQUFDLFFBQVE7WUFDOUQsYUFBYSxDQUFDLENBQUM7S0FDcEI7SUFDRCxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxFQUFFO1FBQzdDLE1BQU0sSUFBSSxpQkFBaUIsQ0FDdkIsNEJBQTRCLEdBQUcsc0JBQXNCLENBQUMsUUFBUTtZQUM5RCxhQUFhLENBQUMsQ0FBQztLQUNwQjtJQUNELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCAyMDIwIEdvb2dsZSBMTENcbiAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG4gKi9cblxuaW1wb3J0IHtTZWN1cml0eUV4Y2VwdGlvbn0gZnJvbSAnLi4vZXhjZXB0aW9uL3NlY3VyaXR5X2V4Y2VwdGlvbic7XG5pbXBvcnQgKiBhcyBLZXlNYW5hZ2VyIGZyb20gJy4uL2ludGVybmFsL2tleV9tYW5hZ2VyJztcbmltcG9ydCB7UGJFY2RzYUtleUZvcm1hdCwgUGJFY2RzYVBhcmFtcywgUGJFY2RzYVByaXZhdGVLZXksIFBiRWNkc2FQdWJsaWNLZXksIFBiS2V5RGF0YSwgUGJNZXNzYWdlfSBmcm9tICcuLi9pbnRlcm5hbC9wcm90byc7XG5pbXBvcnQge1Byb3RvQnl0ZXN9IGZyb20gJy4uL2ludGVybmFsL3Byb3RvX3NoaW1zJztcbmltcG9ydCAqIGFzIFV0aWwgZnJvbSAnLi4vaW50ZXJuYWwvdXRpbCc7XG5pbXBvcnQge0NvbnN0cnVjdG9yfSBmcm9tICcuLi9pbnRlcm5hbC91dGlsJztcbmltcG9ydCAqIGFzIEJ5dGVzIGZyb20gJy4uL3N1YnRsZS9ieXRlcyc7XG5pbXBvcnQgKiBhcyBlY2RzYVNpZ24gZnJvbSAnLi4vc3VidGxlL2VjZHNhX3NpZ24nO1xuaW1wb3J0ICogYXMgRWxsaXB0aWNDdXJ2ZXMgZnJvbSAnLi4vc3VidGxlL2VsbGlwdGljX2N1cnZlcyc7XG5cbmltcG9ydCB7RWNkc2FQdWJsaWNLZXlNYW5hZ2VyfSBmcm9tICcuL2VjZHNhX3B1YmxpY19rZXlfbWFuYWdlcic7XG5pbXBvcnQgKiBhcyBFY2RzYVV0aWwgZnJvbSAnLi9lY2RzYV91dGlsJztcbmltcG9ydCB7UHVibGljS2V5U2lnbn0gZnJvbSAnLi9pbnRlcm5hbC9wdWJsaWNfa2V5X3NpZ24nO1xuXG5jb25zdCBWRVJTSU9OID0gMDtcblxuLyoqXG4gKiBAZmluYWxcbiAqL1xuY2xhc3MgRWNkc2FQcml2YXRlS2V5RmFjdG9yeSBpbXBsZW1lbnRzIEtleU1hbmFnZXIuUHJpdmF0ZUtleUZhY3Rvcnkge1xuICAvKipcbiAgICovXG4gIGFzeW5jIG5ld0tleShrZXlGb3JtYXQ6IFBiTWVzc2FnZXxVaW50OEFycmF5KTogUHJvbWlzZTxQYkVjZHNhUHJpdmF0ZUtleT4ge1xuICAgIGlmICgha2V5Rm9ybWF0KSB7XG4gICAgICB0aHJvdyBuZXcgU2VjdXJpdHlFeGNlcHRpb24oJ0tleSBmb3JtYXQgaGFzIHRvIGJlIG5vbi1udWxsLicpO1xuICAgIH1cbiAgICBjb25zdCBrZXlGb3JtYXRQcm90byA9IEVjZHNhUHJpdmF0ZUtleUZhY3RvcnkuZ2V0S2V5Rm9ybWF0UHJvdG8oa2V5Rm9ybWF0KTtcbiAgICBFY2RzYVV0aWwudmFsaWRhdGVLZXlGb3JtYXQoa2V5Rm9ybWF0UHJvdG8pO1xuICAgIGNvbnN0IHBhcmFtcyA9IGtleUZvcm1hdFByb3RvLmdldFBhcmFtcygpO1xuICAgIGlmICghcGFyYW1zKSB7XG4gICAgICB0aHJvdyBuZXcgU2VjdXJpdHlFeGNlcHRpb24oJ1BhcmFtcyBub3Qgc2V0Jyk7XG4gICAgfVxuICAgIGNvbnN0IGN1cnZlVHlwZVByb3RvID0gcGFyYW1zLmdldEN1cnZlKCk7XG4gICAgY29uc3QgY3VydmVUeXBlU3VidGxlID0gVXRpbC5jdXJ2ZVR5cGVQcm90b1RvU3VidGxlKGN1cnZlVHlwZVByb3RvKTtcbiAgICBjb25zdCBjdXJ2ZU5hbWUgPSBFbGxpcHRpY0N1cnZlcy5jdXJ2ZVRvU3RyaW5nKGN1cnZlVHlwZVN1YnRsZSk7XG4gICAgY29uc3Qga2V5UGFpciA9IGF3YWl0IEVsbGlwdGljQ3VydmVzLmdlbmVyYXRlS2V5UGFpcignRUNEU0EnLCBjdXJ2ZU5hbWUpO1xuICAgIGNvbnN0IGpzb25QdWJsaWNLZXkgPVxuICAgICAgICBhd2FpdCBFbGxpcHRpY0N1cnZlcy5leHBvcnRDcnlwdG9LZXkoa2V5UGFpci5wdWJsaWNLZXkhKTtcbiAgICBjb25zdCBqc29uUHJpdmF0ZUtleSA9XG4gICAgICAgIGF3YWl0IEVsbGlwdGljQ3VydmVzLmV4cG9ydENyeXB0b0tleShrZXlQYWlyLnByaXZhdGVLZXkhKTtcbiAgICByZXR1cm4gRWNkc2FQcml2YXRlS2V5RmFjdG9yeS5qc29uVG9Qcm90b0tleShcbiAgICAgICAganNvblByaXZhdGVLZXksIGpzb25QdWJsaWNLZXksIHBhcmFtcyk7XG4gIH1cblxuICAvKipcbiAgICovXG4gIGFzeW5jIG5ld0tleURhdGEoc2VyaWFsaXplZEtleUZvcm1hdDogVWludDhBcnJheSk6IFByb21pc2U8UGJLZXlEYXRhPiB7XG4gICAgY29uc3Qga2V5ID0gYXdhaXQgdGhpcy5uZXdLZXkoc2VyaWFsaXplZEtleUZvcm1hdCk7XG4gICAgY29uc3Qga2V5RGF0YSA9XG4gICAgICAgIChuZXcgUGJLZXlEYXRhKCkpXG4gICAgICAgICAgICAuc2V0VHlwZVVybChFY2RzYVByaXZhdGVLZXlNYW5hZ2VyLktFWV9UWVBFKVxuICAgICAgICAgICAgLnNldFZhbHVlKGtleS5zZXJpYWxpemVCaW5hcnkoKSlcbiAgICAgICAgICAgIC5zZXRLZXlNYXRlcmlhbFR5cGUoUGJLZXlEYXRhLktleU1hdGVyaWFsVHlwZS5BU1lNTUVUUklDX1BSSVZBVEUpO1xuICAgIHJldHVybiBrZXlEYXRhO1xuICB9XG5cbiAgZ2V0UHVibGljS2V5RGF0YShzZXJpYWxpemVkUHJpdmF0ZUtleTogVWludDhBcnJheSkge1xuICAgIGNvbnN0IHByaXZhdGVLZXkgPSBkZXNlcmlhbGl6ZVByaXZhdGVLZXkoc2VyaWFsaXplZFByaXZhdGVLZXkpO1xuICAgIGNvbnN0IHB1YmxpY0tleSA9IHByaXZhdGVLZXkuZ2V0UHVibGljS2V5KCk7XG4gICAgaWYgKCFwdWJsaWNLZXkpIHtcbiAgICAgIHRocm93IG5ldyBTZWN1cml0eUV4Y2VwdGlvbignUHVibGljIGtleSBub3Qgc2V0Jyk7XG4gICAgfVxuICAgIGNvbnN0IHB1YmxpY0tleURhdGEgPVxuICAgICAgICAobmV3IFBiS2V5RGF0YSgpKVxuICAgICAgICAgICAgLnNldFZhbHVlKHB1YmxpY0tleS5zZXJpYWxpemVCaW5hcnkoKSlcbiAgICAgICAgICAgIC5zZXRUeXBlVXJsKEVjZHNhUHVibGljS2V5TWFuYWdlci5LRVlfVFlQRSlcbiAgICAgICAgICAgIC5zZXRLZXlNYXRlcmlhbFR5cGUoUGJLZXlEYXRhLktleU1hdGVyaWFsVHlwZS5BU1lNTUVUUklDX1BVQkxJQyk7XG4gICAgcmV0dXJuIHB1YmxpY0tleURhdGE7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIHByaXZhdGUga2V5IHByb3RvIGNvcnJlc3BvbmRpbmcgdG8gZ2l2ZW4gSlNPTiBrZXkgcGFpciBhbmQgd2l0aFxuICAgKiB0aGUgZ2l2ZW4gcGFyYW1zLlxuICAgKlxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMganNvblRvUHJvdG9LZXkoXG4gICAgICBqc29uUHJpdmF0ZUtleTogSnNvbldlYktleSwganNvblB1YmxpY0tleTogSnNvbldlYktleSxcbiAgICAgIHBhcmFtczogUGJFY2RzYVBhcmFtcyk6IFBiRWNkc2FQcml2YXRlS2V5IHtcbiAgICBjb25zdCB7eCwgeX0gPSBqc29uUHVibGljS2V5O1xuICAgIGlmICh4ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBTZWN1cml0eUV4Y2VwdGlvbigneCBtdXN0IGJlIHNldCcpO1xuICAgIH1cbiAgICBpZiAoeSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgU2VjdXJpdHlFeGNlcHRpb24oJ3kgbXVzdCBiZSBzZXQnKTtcbiAgICB9XG4gICAgY29uc3QgcHVibGljS2V5UHJvdG8gPSAobmV3IFBiRWNkc2FQdWJsaWNLZXkoKSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuc2V0VmVyc2lvbihFY2RzYVB1YmxpY0tleU1hbmFnZXIuVkVSU0lPTilcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuc2V0UGFyYW1zKHBhcmFtcylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuc2V0WChCeXRlcy5mcm9tQmFzZTY0KHgsIHRydWUpKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5zZXRZKEJ5dGVzLmZyb21CYXNlNjQoeSwgdHJ1ZSkpO1xuICAgIGNvbnN0IHtkfSA9IGpzb25Qcml2YXRlS2V5O1xuICAgIGlmIChkID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBTZWN1cml0eUV4Y2VwdGlvbignZCBtdXN0IGJlIHNldCcpO1xuICAgIH1cbiAgICBjb25zdCBwcml2YXRlS2V5UHJvdG8gPSAobmV3IFBiRWNkc2FQcml2YXRlS2V5KCkpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5zZXRWZXJzaW9uKFZFUlNJT04pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5zZXRQdWJsaWNLZXkocHVibGljS2V5UHJvdG8pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5zZXRLZXlWYWx1ZShCeXRlcy5mcm9tQmFzZTY0KGQsIHRydWUpKTtcbiAgICByZXR1cm4gcHJpdmF0ZUtleVByb3RvO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBpbnB1dCBrZXlGb3JtYXQgaXMgZWl0aGVyIGRlc2VyaWFsaXplZCAoaW4gY2FzZSB0aGF0IHRoZSBpbnB1dCBpc1xuICAgKiBVaW50OEFycmF5KSBvciBjaGVja2VkIHRvIGJlIGFuIEVjZHNhS2V5Rm9ybWF0LXByb3RvIChvdGhlcndpc2UpLlxuICAgKlxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgZ2V0S2V5Rm9ybWF0UHJvdG8oa2V5Rm9ybWF0OiBQYk1lc3NhZ2V8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFVpbnQ4QXJyYXkpOiBQYkVjZHNhS2V5Rm9ybWF0IHtcbiAgICBpZiAoa2V5Rm9ybWF0IGluc3RhbmNlb2YgVWludDhBcnJheSkge1xuICAgICAgcmV0dXJuIEVjZHNhUHJpdmF0ZUtleUZhY3RvcnkuZGVzZXJpYWxpemVLZXlGb3JtYXQoa2V5Rm9ybWF0KTtcbiAgICB9IGVsc2UgaWYgKGtleUZvcm1hdCBpbnN0YW5jZW9mIFBiRWNkc2FLZXlGb3JtYXQpIHtcbiAgICAgIHJldHVybiBrZXlGb3JtYXQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBTZWN1cml0eUV4Y2VwdGlvbihcbiAgICAgICAgICAnRXhwZWN0ZWQgJyArIEVjZHNhUHJpdmF0ZUtleU1hbmFnZXIuS0VZX1RZUEUgKyAnIGtleSBmb3JtYXQgcHJvdG8uJyk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgZGVzZXJpYWxpemVLZXlGb3JtYXQoa2V5Rm9ybWF0OiBVaW50OEFycmF5KTogUGJFY2RzYUtleUZvcm1hdCB7XG4gICAgbGV0IGtleUZvcm1hdFByb3RvOiBQYkVjZHNhS2V5Rm9ybWF0O1xuICAgIHRyeSB7XG4gICAgICBrZXlGb3JtYXRQcm90byA9IFBiRWNkc2FLZXlGb3JtYXQuZGVzZXJpYWxpemVCaW5hcnkoa2V5Rm9ybWF0KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aHJvdyBuZXcgU2VjdXJpdHlFeGNlcHRpb24oXG4gICAgICAgICAgJ0lucHV0IGNhbm5vdCBiZSBwYXJzZWQgYXMgJyArIEVjZHNhUHJpdmF0ZUtleU1hbmFnZXIuS0VZX1RZUEUgK1xuICAgICAgICAgICcga2V5IGZvcm1hdCBwcm90by4nKTtcbiAgICB9XG4gICAgaWYgKCFrZXlGb3JtYXRQcm90by5nZXRQYXJhbXMoKSkge1xuICAgICAgdGhyb3cgbmV3IFNlY3VyaXR5RXhjZXB0aW9uKFxuICAgICAgICAgICdJbnB1dCBjYW5ub3QgYmUgcGFyc2VkIGFzICcgKyBFY2RzYVByaXZhdGVLZXlNYW5hZ2VyLktFWV9UWVBFICtcbiAgICAgICAgICAnIGtleSBmb3JtYXQgcHJvdG8uJyk7XG4gICAgfVxuICAgIHJldHVybiBrZXlGb3JtYXRQcm90bztcbiAgfVxufVxuXG4vKipcbiAqIEBmaW5hbFxuICovXG5leHBvcnQgY2xhc3MgRWNkc2FQcml2YXRlS2V5TWFuYWdlciBpbXBsZW1lbnRzXG4gICAgS2V5TWFuYWdlci5LZXlNYW5hZ2VyPFB1YmxpY0tleVNpZ24+IHtcbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgU1VQUE9SVEVEX1BSSU1JVElWRSA9IFB1YmxpY0tleVNpZ247XG4gIHN0YXRpYyBLRVlfVFlQRTogc3RyaW5nID1cbiAgICAgICd0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5FY2RzYVByaXZhdGVLZXknO1xuICBrZXlGYWN0b3J5ID0gbmV3IEVjZHNhUHJpdmF0ZUtleUZhY3RvcnkoKTtcblxuICBhc3luYyBnZXRQcmltaXRpdmUoXG4gICAgICBwcmltaXRpdmVUeXBlOiBDb25zdHJ1Y3RvcjxQdWJsaWNLZXlTaWduPiwga2V5OiBQYktleURhdGF8UGJNZXNzYWdlKSB7XG4gICAgaWYgKHByaW1pdGl2ZVR5cGUgIT09IHRoaXMuZ2V0UHJpbWl0aXZlVHlwZSgpKSB7XG4gICAgICB0aHJvdyBuZXcgU2VjdXJpdHlFeGNlcHRpb24oXG4gICAgICAgICAgJ1JlcXVlc3RlZCBwcmltaXRpdmUgdHlwZSB3aGljaCBpcyBub3QgJyArXG4gICAgICAgICAgJ3N1cHBvcnRlZCBieSB0aGlzIGtleSBtYW5hZ2VyLicpO1xuICAgIH1cbiAgICBjb25zdCBrZXlQcm90byA9IEVjZHNhUHJpdmF0ZUtleU1hbmFnZXIuZ2V0S2V5UHJvdG8oa2V5KTtcbiAgICBFY2RzYVV0aWwudmFsaWRhdGVQcml2YXRlS2V5KFxuICAgICAgICBrZXlQcm90bywgVkVSU0lPTiwgRWNkc2FQdWJsaWNLZXlNYW5hZ2VyLlZFUlNJT04pO1xuICAgIGNvbnN0IHJlY2VwaWVudFByaXZhdGVLZXkgPSBFY2RzYVV0aWwuZ2V0SnNvbldlYktleUZyb21Qcm90byhrZXlQcm90byk7XG4gICAgY29uc3QgcHVibGljS2V5ID0ga2V5UHJvdG8uZ2V0UHVibGljS2V5KCk7XG4gICAgaWYgKCFwdWJsaWNLZXkpIHtcbiAgICAgIHRocm93IG5ldyBTZWN1cml0eUV4Y2VwdGlvbignUHVibGljIGtleSBub3Qgc2V0Jyk7XG4gICAgfVxuICAgIGNvbnN0IHBhcmFtcyA9IHB1YmxpY0tleS5nZXRQYXJhbXMoKTtcbiAgICBpZiAoIXBhcmFtcykge1xuICAgICAgdGhyb3cgbmV3IFNlY3VyaXR5RXhjZXB0aW9uKCdQYXJhbXMgbm90IHNldCcpO1xuICAgIH1cbiAgICBjb25zdCBoYXNoID0gVXRpbC5oYXNoVHlwZVByb3RvVG9TdHJpbmcocGFyYW1zLmdldEhhc2hUeXBlKCkpO1xuICAgIGNvbnN0IGVuY29kaW5nID0gRWNkc2FVdGlsLmVuY29kaW5nVHlwZVByb3RvVG9FbnVtKHBhcmFtcy5nZXRFbmNvZGluZygpKTtcbiAgICByZXR1cm4gZWNkc2FTaWduLmZyb21Kc29uV2ViS2V5KHJlY2VwaWVudFByaXZhdGVLZXksIGhhc2gsIGVuY29kaW5nKTtcbiAgfVxuXG4gIGRvZXNTdXBwb3J0KGtleVR5cGU6IHN0cmluZykge1xuICAgIHJldHVybiBrZXlUeXBlID09PSB0aGlzLmdldEtleVR5cGUoKTtcbiAgfVxuXG4gIGdldEtleVR5cGUoKSB7XG4gICAgcmV0dXJuIEVjZHNhUHJpdmF0ZUtleU1hbmFnZXIuS0VZX1RZUEU7XG4gIH1cblxuICBnZXRQcmltaXRpdmVUeXBlKCkge1xuICAgIHJldHVybiBFY2RzYVByaXZhdGVLZXlNYW5hZ2VyLlNVUFBPUlRFRF9QUklNSVRJVkU7XG4gIH1cblxuICBnZXRWZXJzaW9uKCkge1xuICAgIHJldHVybiBWRVJTSU9OO1xuICB9XG5cbiAgZ2V0S2V5RmFjdG9yeSgpIHtcbiAgICByZXR1cm4gdGhpcy5rZXlGYWN0b3J5O1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgZ2V0S2V5UHJvdG8oa2V5TWF0ZXJpYWw6IFBiS2V5RGF0YXxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUGJNZXNzYWdlKTogUGJFY2RzYVByaXZhdGVLZXkge1xuICAgIGlmIChrZXlNYXRlcmlhbCBpbnN0YW5jZW9mIFBiS2V5RGF0YSkge1xuICAgICAgcmV0dXJuIEVjZHNhUHJpdmF0ZUtleU1hbmFnZXIuZ2V0S2V5UHJvdG9Gcm9tS2V5RGF0YShrZXlNYXRlcmlhbCk7XG4gICAgfVxuICAgIGlmIChrZXlNYXRlcmlhbCBpbnN0YW5jZW9mIFBiRWNkc2FQcml2YXRlS2V5KSB7XG4gICAgICByZXR1cm4ga2V5TWF0ZXJpYWw7XG4gICAgfVxuICAgIHRocm93IG5ldyBTZWN1cml0eUV4Y2VwdGlvbihcbiAgICAgICAgJ0tleSB0eXBlIGlzIG5vdCBzdXBwb3J0ZWQuIFRoaXMga2V5ICcgK1xuICAgICAgICAnbWFuYWdlciBzdXBwb3J0cyAnICsgRWNkc2FQcml2YXRlS2V5TWFuYWdlci5LRVlfVFlQRSArICcuJyk7XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBnZXRLZXlQcm90b0Zyb21LZXlEYXRhKGtleURhdGE6IFBiS2V5RGF0YSk6IFBiRWNkc2FQcml2YXRlS2V5IHtcbiAgICBpZiAoa2V5RGF0YS5nZXRUeXBlVXJsKCkgIT09IEVjZHNhUHJpdmF0ZUtleU1hbmFnZXIuS0VZX1RZUEUpIHtcbiAgICAgIHRocm93IG5ldyBTZWN1cml0eUV4Y2VwdGlvbihcbiAgICAgICAgICAnS2V5IHR5cGUgJyArIGtleURhdGEuZ2V0VHlwZVVybCgpICtcbiAgICAgICAgICAnIGlzIG5vdCBzdXBwb3J0ZWQuIFRoaXMga2V5IG1hbmFnZXIgc3VwcG9ydHMgJyArXG4gICAgICAgICAgRWNkc2FQcml2YXRlS2V5TWFuYWdlci5LRVlfVFlQRSArICcuJyk7XG4gICAgfVxuICAgIHJldHVybiBkZXNlcmlhbGl6ZVByaXZhdGVLZXkoa2V5RGF0YS5nZXRWYWx1ZSgpKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBkZXNlcmlhbGl6ZVByaXZhdGVLZXkoc2VyaWFsaXplZFByaXZhdGVLZXk6IFByb3RvQnl0ZXMpOlxuICAgIFBiRWNkc2FQcml2YXRlS2V5IHtcbiAgbGV0IGtleTogUGJFY2RzYVByaXZhdGVLZXk7XG4gIHRyeSB7XG4gICAga2V5ID0gUGJFY2RzYVByaXZhdGVLZXkuZGVzZXJpYWxpemVCaW5hcnkoc2VyaWFsaXplZFByaXZhdGVLZXkpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgdGhyb3cgbmV3IFNlY3VyaXR5RXhjZXB0aW9uKFxuICAgICAgICAnSW5wdXQgY2Fubm90IGJlIHBhcnNlZCBhcyAnICsgRWNkc2FQcml2YXRlS2V5TWFuYWdlci5LRVlfVFlQRSArXG4gICAgICAgICcga2V5LXByb3RvLicpO1xuICB9XG4gIGlmICgha2V5LmdldFB1YmxpY0tleSgpIHx8ICFrZXkuZ2V0S2V5VmFsdWUoKSkge1xuICAgIHRocm93IG5ldyBTZWN1cml0eUV4Y2VwdGlvbihcbiAgICAgICAgJ0lucHV0IGNhbm5vdCBiZSBwYXJzZWQgYXMgJyArIEVjZHNhUHJpdmF0ZUtleU1hbmFnZXIuS0VZX1RZUEUgK1xuICAgICAgICAnIGtleS1wcm90by4nKTtcbiAgfVxuICByZXR1cm4ga2V5O1xufVxuIl19