UNPKG

tedious

Version:

A TDS driver, for connecting to MS SQLServer databases.

315 lines (250 loc) 47.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ColumnEncryptionAzureKeyVaultProvider = void 0; var _identity = require("@azure/identity"); var _keyvaultKeys = require("@azure/keyvault-keys"); var _crypto = require("crypto"); var _url = require("url"); // This code is based on the `mssql-jdbc` library published under the conditions of MIT license. // Copyright (c) 2019 Microsoft Corporation class ColumnEncryptionAzureKeyVaultProvider { constructor(clientId, clientKey, tenantId) { this.name = void 0; this.url = void 0; this.rsaEncryptionAlgorithmWithOAEPForAKV = void 0; this.firstVersion = void 0; this.credentials = void 0; this.azureKeyVaultDomainName = void 0; this.keyClient = void 0; this.name = 'AZURE_KEY_VAULT'; this.azureKeyVaultDomainName = 'vault.azure.net'; this.rsaEncryptionAlgorithmWithOAEPForAKV = 'RSA-OAEP'; this.firstVersion = Buffer.from([0x01]); this.credentials = new _identity.ClientSecretCredential(tenantId, clientId, clientKey); } async decryptColumnEncryptionKey(masterKeyPath, encryptionAlgorithm, encryptedColumnEncryptionKey) { if (!encryptedColumnEncryptionKey) { throw new Error('Internal error. Encrypted column encryption key cannot be null.'); } if (encryptedColumnEncryptionKey.length === 0) { throw new Error('Internal error. Empty encrypted column encryption key specified.'); } encryptionAlgorithm = this.validateEncryptionAlgorithm(encryptionAlgorithm); const masterKey = await this.getMasterKey(masterKeyPath); const keySizeInBytes = this.getAKVKeySize(masterKey); const cryptoClient = this.createCryptoClient(masterKey); if (encryptedColumnEncryptionKey[0] !== this.firstVersion[0]) { throw new Error(`Specified encrypted column encryption key contains an invalid encryption algorithm version ${Buffer.from([encryptedColumnEncryptionKey[0]]).toString('hex')}. Expected version is ${Buffer.from([this.firstVersion[0]]).toString('hex')}.`); } let currentIndex = this.firstVersion.length; const keyPathLength = encryptedColumnEncryptionKey.readInt16LE(currentIndex); currentIndex += 2; const cipherTextLength = encryptedColumnEncryptionKey.readInt16LE(currentIndex); currentIndex += 2; currentIndex += keyPathLength; if (cipherTextLength !== keySizeInBytes) { throw new Error(`The specified encrypted column encryption key's ciphertext length: ${cipherTextLength} does not match the ciphertext length: ${keySizeInBytes} when using column master key (Azure Key Vault key) in ${masterKeyPath}. The encrypted column encryption key may be corrupt, or the specified Azure Key Vault key path may be incorrect.`); } const signatureLength = encryptedColumnEncryptionKey.length - currentIndex - cipherTextLength; if (signatureLength !== keySizeInBytes) { throw new Error(`The specified encrypted column encryption key's signature length: ${signatureLength} does not match the signature length: ${keySizeInBytes} when using column master key (Azure Key Vault key) in ${masterKeyPath}. The encrypted column encryption key may be corrupt, or the specified Azure Key Vault key path may be incorrect.`); } const cipherText = Buffer.alloc(cipherTextLength); encryptedColumnEncryptionKey.copy(cipherText, 0, currentIndex, currentIndex + cipherTextLength); currentIndex += cipherTextLength; const signature = Buffer.alloc(signatureLength); encryptedColumnEncryptionKey.copy(signature, 0, currentIndex, currentIndex + signatureLength); const hash = Buffer.alloc(encryptedColumnEncryptionKey.length - signature.length); encryptedColumnEncryptionKey.copy(hash, 0, 0, encryptedColumnEncryptionKey.length - signature.length); const messageDigest = (0, _crypto.createHash)('sha256'); messageDigest.update(hash); const dataToVerify = messageDigest.digest(); if (!dataToVerify) { throw new Error('Hash should not be null while decrypting encrypted column encryption key.'); } const verifyKey = await cryptoClient.verify('RS256', dataToVerify, signature); if (!verifyKey.result) { throw new Error(`The specified encrypted column encryption key signature does not match the signature computed with the column master key (Asymmetric key in Azure Key Vault) in ${masterKeyPath}. The encrypted column encryption key may be corrupt, or the specified path may be incorrect.`); } const decryptedCEK = await this.azureKeyVaultUnWrap(cryptoClient, encryptionAlgorithm, cipherText); return decryptedCEK; } async encryptColumnEncryptionKey(masterKeyPath, encryptionAlgorithm, columnEncryptionKey) { if (!columnEncryptionKey) { throw new Error('Column encryption key cannot be null.'); } if (columnEncryptionKey.length === 0) { throw new Error('Empty column encryption key specified.'); } encryptionAlgorithm = this.validateEncryptionAlgorithm(encryptionAlgorithm); const masterKey = await this.getMasterKey(masterKeyPath); const keySizeInBytes = this.getAKVKeySize(masterKey); const cryptoClient = this.createCryptoClient(masterKey); const version = Buffer.from([this.firstVersion[0]]); const masterKeyPathBytes = Buffer.from(masterKeyPath.toLowerCase(), 'utf8'); const keyPathLength = Buffer.alloc(2); keyPathLength[0] = masterKeyPathBytes.length & 0xff; keyPathLength[1] = masterKeyPathBytes.length >> 8 & 0xff; const cipherText = await this.azureKeyVaultWrap(cryptoClient, encryptionAlgorithm, columnEncryptionKey); const cipherTextLength = Buffer.alloc(2); cipherTextLength[0] = cipherText.length & 0xff; cipherTextLength[1] = cipherText.length >> 8 & 0xff; if (cipherText.length !== keySizeInBytes) { throw new Error('CipherText length does not match the RSA key size.'); } const dataToHash = Buffer.alloc(version.length + keyPathLength.length + cipherTextLength.length + masterKeyPathBytes.length + cipherText.length); let destinationPosition = version.length; version.copy(dataToHash, 0, 0, version.length); keyPathLength.copy(dataToHash, destinationPosition, 0, keyPathLength.length); destinationPosition += keyPathLength.length; cipherTextLength.copy(dataToHash, destinationPosition, 0, cipherTextLength.length); destinationPosition += cipherTextLength.length; masterKeyPathBytes.copy(dataToHash, destinationPosition, 0, masterKeyPathBytes.length); destinationPosition += masterKeyPathBytes.length; cipherText.copy(dataToHash, destinationPosition, 0, cipherText.length); const messageDigest = (0, _crypto.createHash)('sha256'); messageDigest.update(dataToHash); const dataToSign = messageDigest.digest(); const signedHash = await this.azureKeyVaultSignedHashedData(cryptoClient, dataToSign); if (signedHash.length !== keySizeInBytes) { throw new Error('Signed hash length does not match the RSA key size.'); } const verifyKey = await cryptoClient.verify('RS256', dataToSign, signedHash); if (!verifyKey.result) { throw new Error('Invalid signature of the encrypted column encryption key computed.'); } const encryptedColumnEncryptionKeyLength = version.length + cipherTextLength.length + keyPathLength.length + cipherText.length + masterKeyPathBytes.length + signedHash.length; const encryptedColumnEncryptionKey = Buffer.alloc(encryptedColumnEncryptionKeyLength); let currentIndex = 0; version.copy(encryptedColumnEncryptionKey, currentIndex, 0, version.length); currentIndex += version.length; keyPathLength.copy(encryptedColumnEncryptionKey, currentIndex, 0, keyPathLength.length); currentIndex += keyPathLength.length; cipherTextLength.copy(encryptedColumnEncryptionKey, currentIndex, 0, cipherTextLength.length); currentIndex += cipherTextLength.length; masterKeyPathBytes.copy(encryptedColumnEncryptionKey, currentIndex, 0, masterKeyPathBytes.length); currentIndex += masterKeyPathBytes.length; cipherText.copy(encryptedColumnEncryptionKey, currentIndex, 0, cipherText.length); currentIndex += cipherText.length; signedHash.copy(encryptedColumnEncryptionKey, currentIndex, 0, signedHash.length); return encryptedColumnEncryptionKey; } async getMasterKey(masterKeyPath) { if (!masterKeyPath) { throw new Error('Master key path cannot be null or undefined'); } const keyParts = this.parsePath(masterKeyPath); this.createKeyClient(keyParts.vaultUrl); return await this.keyClient.getKey(keyParts.name, keyParts.version ? { version: keyParts.version } : {}); } createKeyClient(keyVaultUrl) { if (!keyVaultUrl) { throw new Error('Cannot create key client with null or undefined keyVaultUrl'); } if (!this.keyClient) { this.url = keyVaultUrl; this.keyClient = new _keyvaultKeys.KeyClient(keyVaultUrl, this.credentials); } } createCryptoClient(masterKey) { if (!masterKey) { throw new Error('Cannot create CryptographyClient with null or undefined masterKey'); } return new _keyvaultKeys.CryptographyClient(masterKey, this.credentials); } parsePath(masterKeyPath) { if (!masterKeyPath || masterKeyPath.trim() === '') { throw new Error('Azure Key Vault key path cannot be null.'); } let baseUri; try { baseUri = (0, _url.parse)(masterKeyPath, true, true); } catch { throw new Error(`Invalid keys identifier: ${masterKeyPath}. Not a valid URI`); } if (!baseUri.hostname || !baseUri.hostname.toLowerCase().endsWith(this.azureKeyVaultDomainName)) { throw new Error(`Invalid Azure Key Vault key path specified: ${masterKeyPath}.`); } // Path is of the form '/collection/name[/version]' const segments = (baseUri.pathname || '').split('/'); if (segments.length !== 3 && segments.length !== 4) { throw new Error(`Invalid keys identifier: ${masterKeyPath}. Bad number of segments: ${segments.length}`); } if ('keys' !== segments[1]) { throw new Error(`Invalid keys identifier: ${masterKeyPath}. segment [1] should be "keys", found "${segments[1]}"`); } const vaultUrl = `${baseUri.protocol}//${baseUri.host}`; const name = segments[2]; const version = segments.length === 4 ? segments[3] : undefined; return { vaultUrl, name, version }; } async azureKeyVaultSignedHashedData(cryptoClient, dataToSign) { if (!cryptoClient) { throw new Error('Azure KVS Crypto Client is not defined.'); } const signedData = await cryptoClient.sign('RS256', dataToSign); return Buffer.from(signedData.result); } async azureKeyVaultWrap(cryptoClient, encryptionAlgorithm, columnEncryptionKey) { if (!cryptoClient) { throw new Error('Azure KVS Crypto Client is not defined.'); } if (!columnEncryptionKey) { throw new Error('Column encryption key cannot be null.'); } const wrappedKey = await cryptoClient.wrapKey(encryptionAlgorithm, columnEncryptionKey); return Buffer.from(wrappedKey.result); } async azureKeyVaultUnWrap(cryptoClient, encryptionAlgorithm, encryptedColumnEncryptionKey) { if (!cryptoClient) { throw new Error('Azure KVS Crypto Client is not defined.'); } if (!encryptionAlgorithm) { throw new Error('Encryption Algorithm cannot be null or undefined'); } if (!encryptedColumnEncryptionKey) { throw new Error('Encrypted column encryption key cannot be null.'); } if (encryptedColumnEncryptionKey.length === 0) { throw new Error('Encrypted Column Encryption Key length should not be zero.'); } const unwrappedKey = await cryptoClient.unwrapKey(encryptionAlgorithm, encryptedColumnEncryptionKey); return Buffer.from(unwrappedKey.result); } getAKVKeySize(retrievedKey) { if (!retrievedKey) { throw new Error('Retrieved key cannot be null or undefined'); } const key = retrievedKey.key; if (!key) { throw new Error(`Key does not exist ${retrievedKey.name}`); } const kty = key && key.kty && key.kty.toString().toUpperCase(); if (!kty || 'RSA'.localeCompare(kty, 'en') !== 0) { throw new Error(`Cannot use a non-RSA key: ${kty}.`); } const keyLength = key && key.n && key.n.length; return keyLength || 0; } validateEncryptionAlgorithm(encryptionAlgorithm) { if (!encryptionAlgorithm) { throw new Error('Key encryption algorithm cannot be null.'); } if ('RSA_OAEP'.localeCompare(encryptionAlgorithm.toUpperCase(), 'en') === 0) { encryptionAlgorithm = 'RSA-OAEP'; } if (this.rsaEncryptionAlgorithmWithOAEPForAKV.localeCompare(encryptionAlgorithm.trim().toUpperCase(), 'en') !== 0) { throw new Error(`Invalid key encryption algorithm specified: ${encryptionAlgorithm}. Expected value: ${this.rsaEncryptionAlgorithmWithOAEPForAKV}.`); } return encryptionAlgorithm; } } exports.ColumnEncryptionAzureKeyVaultProvider = ColumnEncryptionAzureKeyVaultProvider; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJDb2x1bW5FbmNyeXB0aW9uQXp1cmVLZXlWYXVsdFByb3ZpZGVyIiwiY29uc3RydWN0b3IiLCJjbGllbnRJZCIsImNsaWVudEtleSIsInRlbmFudElkIiwibmFtZSIsInVybCIsInJzYUVuY3J5cHRpb25BbGdvcml0aG1XaXRoT0FFUEZvckFLViIsImZpcnN0VmVyc2lvbiIsImNyZWRlbnRpYWxzIiwiYXp1cmVLZXlWYXVsdERvbWFpbk5hbWUiLCJrZXlDbGllbnQiLCJCdWZmZXIiLCJmcm9tIiwiQ2xpZW50U2VjcmV0Q3JlZGVudGlhbCIsImRlY3J5cHRDb2x1bW5FbmNyeXB0aW9uS2V5IiwibWFzdGVyS2V5UGF0aCIsImVuY3J5cHRpb25BbGdvcml0aG0iLCJlbmNyeXB0ZWRDb2x1bW5FbmNyeXB0aW9uS2V5IiwiRXJyb3IiLCJsZW5ndGgiLCJ2YWxpZGF0ZUVuY3J5cHRpb25BbGdvcml0aG0iLCJtYXN0ZXJLZXkiLCJnZXRNYXN0ZXJLZXkiLCJrZXlTaXplSW5CeXRlcyIsImdldEFLVktleVNpemUiLCJjcnlwdG9DbGllbnQiLCJjcmVhdGVDcnlwdG9DbGllbnQiLCJ0b1N0cmluZyIsImN1cnJlbnRJbmRleCIsImtleVBhdGhMZW5ndGgiLCJyZWFkSW50MTZMRSIsImNpcGhlclRleHRMZW5ndGgiLCJzaWduYXR1cmVMZW5ndGgiLCJjaXBoZXJUZXh0IiwiYWxsb2MiLCJjb3B5Iiwic2lnbmF0dXJlIiwiaGFzaCIsIm1lc3NhZ2VEaWdlc3QiLCJ1cGRhdGUiLCJkYXRhVG9WZXJpZnkiLCJkaWdlc3QiLCJ2ZXJpZnlLZXkiLCJ2ZXJpZnkiLCJyZXN1bHQiLCJkZWNyeXB0ZWRDRUsiLCJhenVyZUtleVZhdWx0VW5XcmFwIiwiZW5jcnlwdENvbHVtbkVuY3J5cHRpb25LZXkiLCJjb2x1bW5FbmNyeXB0aW9uS2V5IiwidmVyc2lvbiIsIm1hc3RlcktleVBhdGhCeXRlcyIsInRvTG93ZXJDYXNlIiwiYXp1cmVLZXlWYXVsdFdyYXAiLCJkYXRhVG9IYXNoIiwiZGVzdGluYXRpb25Qb3NpdGlvbiIsImRhdGFUb1NpZ24iLCJzaWduZWRIYXNoIiwiYXp1cmVLZXlWYXVsdFNpZ25lZEhhc2hlZERhdGEiLCJlbmNyeXB0ZWRDb2x1bW5FbmNyeXB0aW9uS2V5TGVuZ3RoIiwia2V5UGFydHMiLCJwYXJzZVBhdGgiLCJjcmVhdGVLZXlDbGllbnQiLCJ2YXVsdFVybCIsImdldEtleSIsImtleVZhdWx0VXJsIiwiS2V5Q2xpZW50IiwiQ3J5cHRvZ3JhcGh5Q2xpZW50IiwidHJpbSIsImJhc2VVcmkiLCJob3N0bmFtZSIsImVuZHNXaXRoIiwic2VnbWVudHMiLCJwYXRobmFtZSIsInNwbGl0IiwicHJvdG9jb2wiLCJob3N0IiwidW5kZWZpbmVkIiwic2lnbmVkRGF0YSIsInNpZ24iLCJ3cmFwcGVkS2V5Iiwid3JhcEtleSIsInVud3JhcHBlZEtleSIsInVud3JhcEtleSIsInJldHJpZXZlZEtleSIsImtleSIsImt0eSIsInRvVXBwZXJDYXNlIiwibG9jYWxlQ29tcGFyZSIsImtleUxlbmd0aCIsIm4iXSwic291cmNlcyI6WyIuLi8uLi9zcmMvYWx3YXlzLWVuY3J5cHRlZC9rZXlzdG9yZS1wcm92aWRlci1henVyZS1rZXktdmF1bHQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gVGhpcyBjb2RlIGlzIGJhc2VkIG9uIHRoZSBgbXNzcWwtamRiY2AgbGlicmFyeSBwdWJsaXNoZWQgdW5kZXIgdGhlIGNvbmRpdGlvbnMgb2YgTUlUIGxpY2Vuc2UuXG4vLyBDb3B5cmlnaHQgKGMpIDIwMTkgTWljcm9zb2Z0IENvcnBvcmF0aW9uXG5cbmltcG9ydCB7IENsaWVudFNlY3JldENyZWRlbnRpYWwgfSBmcm9tICdAYXp1cmUvaWRlbnRpdHknO1xuaW1wb3J0IHsgQ3J5cHRvZ3JhcGh5Q2xpZW50LCBLZXlXcmFwQWxnb3JpdGhtLCBLZXlDbGllbnQsIEtleVZhdWx0S2V5IH0gZnJvbSAnQGF6dXJlL2tleXZhdWx0LWtleXMnO1xuaW1wb3J0IHsgY3JlYXRlSGFzaCB9IGZyb20gJ2NyeXB0byc7XG5pbXBvcnQgeyBwYXJzZSB9IGZyb20gJ3VybCc7XG5cbmludGVyZmFjZSBQYXJzZWRLZXlQYXRoIHtcbiAgdmF1bHRVcmw6IHN0cmluZztcbiAgbmFtZTogc3RyaW5nO1xuICB2ZXJzaW9uPzogc3RyaW5nIHwgdW5kZWZpbmVkO1xufVxuXG5leHBvcnQgY2xhc3MgQ29sdW1uRW5jcnlwdGlvbkF6dXJlS2V5VmF1bHRQcm92aWRlciB7XG4gIHB1YmxpYyByZWFkb25seSBuYW1lOiBzdHJpbmc7XG4gIHByaXZhdGUgdXJsOiB1bmRlZmluZWQgfCBzdHJpbmc7XG4gIHByaXZhdGUgcmVhZG9ubHkgcnNhRW5jcnlwdGlvbkFsZ29yaXRobVdpdGhPQUVQRm9yQUtWOiBzdHJpbmc7XG4gIHByaXZhdGUgcmVhZG9ubHkgZmlyc3RWZXJzaW9uOiBCdWZmZXI7XG4gIHByaXZhdGUgY3JlZGVudGlhbHM6IENsaWVudFNlY3JldENyZWRlbnRpYWw7XG4gIHByaXZhdGUgcmVhZG9ubHkgYXp1cmVLZXlWYXVsdERvbWFpbk5hbWU6IHN0cmluZztcbiAgcHJpdmF0ZSBrZXlDbGllbnQ6IHVuZGVmaW5lZCB8IEtleUNsaWVudDtcblxuICBjb25zdHJ1Y3RvcihjbGllbnRJZDogc3RyaW5nLCBjbGllbnRLZXk6IHN0cmluZywgdGVuYW50SWQ6IHN0cmluZykge1xuICAgIHRoaXMubmFtZSA9ICdBWlVSRV9LRVlfVkFVTFQnO1xuICAgIHRoaXMuYXp1cmVLZXlWYXVsdERvbWFpbk5hbWUgPSAndmF1bHQuYXp1cmUubmV0JztcbiAgICB0aGlzLnJzYUVuY3J5cHRpb25BbGdvcml0aG1XaXRoT0FFUEZvckFLViA9ICdSU0EtT0FFUCc7XG4gICAgdGhpcy5maXJzdFZlcnNpb24gPSBCdWZmZXIuZnJvbShbMHgwMV0pO1xuICAgIHRoaXMuY3JlZGVudGlhbHMgPSBuZXcgQ2xpZW50U2VjcmV0Q3JlZGVudGlhbCh0ZW5hbnRJZCwgY2xpZW50SWQsIGNsaWVudEtleSk7XG4gIH1cblxuICBhc3luYyBkZWNyeXB0Q29sdW1uRW5jcnlwdGlvbktleShtYXN0ZXJLZXlQYXRoOiBzdHJpbmcsIGVuY3J5cHRpb25BbGdvcml0aG06IHN0cmluZywgZW5jcnlwdGVkQ29sdW1uRW5jcnlwdGlvbktleTogQnVmZmVyKTogUHJvbWlzZTxCdWZmZXI+IHtcbiAgICBpZiAoIWVuY3J5cHRlZENvbHVtbkVuY3J5cHRpb25LZXkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW50ZXJuYWwgZXJyb3IuIEVuY3J5cHRlZCBjb2x1bW4gZW5jcnlwdGlvbiBrZXkgY2Fubm90IGJlIG51bGwuJyk7XG4gICAgfVxuXG4gICAgaWYgKGVuY3J5cHRlZENvbHVtbkVuY3J5cHRpb25LZXkubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGVycm9yLiBFbXB0eSBlbmNyeXB0ZWQgY29sdW1uIGVuY3J5cHRpb24ga2V5IHNwZWNpZmllZC4nKTtcbiAgICB9XG5cbiAgICBlbmNyeXB0aW9uQWxnb3JpdGhtID0gdGhpcy52YWxpZGF0ZUVuY3J5cHRpb25BbGdvcml0aG0oZW5jcnlwdGlvbkFsZ29yaXRobSk7XG5cbiAgICBjb25zdCBtYXN0ZXJLZXkgPSBhd2FpdCB0aGlzLmdldE1hc3RlcktleShtYXN0ZXJLZXlQYXRoKTtcblxuICAgIGNvbnN0IGtleVNpemVJbkJ5dGVzID0gdGhpcy5nZXRBS1ZLZXlTaXplKG1hc3RlcktleSk7XG5cbiAgICBjb25zdCBjcnlwdG9DbGllbnQgPSB0aGlzLmNyZWF0ZUNyeXB0b0NsaWVudChtYXN0ZXJLZXkpO1xuXG4gICAgaWYgKGVuY3J5cHRlZENvbHVtbkVuY3J5cHRpb25LZXlbMF0gIT09IHRoaXMuZmlyc3RWZXJzaW9uWzBdKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFNwZWNpZmllZCBlbmNyeXB0ZWQgY29sdW1uIGVuY3J5cHRpb24ga2V5IGNvbnRhaW5zIGFuIGludmFsaWQgZW5jcnlwdGlvbiBhbGdvcml0aG0gdmVyc2lvbiAke0J1ZmZlci5mcm9tKFtlbmNyeXB0ZWRDb2x1bW5FbmNyeXB0aW9uS2V5WzBdXSkudG9TdHJpbmcoJ2hleCcpfS4gRXhwZWN0ZWQgdmVyc2lvbiBpcyAke0J1ZmZlci5mcm9tKFt0aGlzLmZpcnN0VmVyc2lvblswXV0pLnRvU3RyaW5nKCdoZXgnKX0uYCk7XG4gICAgfVxuXG4gICAgbGV0IGN1cnJlbnRJbmRleCA9IHRoaXMuZmlyc3RWZXJzaW9uLmxlbmd0aDtcbiAgICBjb25zdCBrZXlQYXRoTGVuZ3RoOiBudW1iZXIgPSBlbmNyeXB0ZWRDb2x1bW5FbmNyeXB0aW9uS2V5LnJlYWRJbnQxNkxFKGN1cnJlbnRJbmRleCk7XG5cbiAgICBjdXJyZW50SW5kZXggKz0gMjtcblxuICAgIGNvbnN0IGNpcGhlclRleHRMZW5ndGg6IG51bWJlciA9IGVuY3J5cHRlZENvbHVtbkVuY3J5cHRpb25LZXkucmVhZEludDE2TEUoY3VycmVudEluZGV4KTtcblxuICAgIGN1cnJlbnRJbmRleCArPSAyO1xuXG4gICAgY3VycmVudEluZGV4ICs9IGtleVBhdGhMZW5ndGg7XG5cbiAgICBpZiAoY2lwaGVyVGV4dExlbmd0aCAhPT0ga2V5U2l6ZUluQnl0ZXMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgVGhlIHNwZWNpZmllZCBlbmNyeXB0ZWQgY29sdW1uIGVuY3J5cHRpb24ga2V5J3MgY2lwaGVydGV4dCBsZW5ndGg6ICR7Y2lwaGVyVGV4dExlbmd0aH0gZG9lcyBub3QgbWF0Y2ggdGhlIGNpcGhlcnRleHQgbGVuZ3RoOiAke2tleVNpemVJbkJ5dGVzfSB3aGVuIHVzaW5nIGNvbHVtbiBtYXN0ZXIga2V5IChBenVyZSBLZXkgVmF1bHQga2V5KSBpbiAke21hc3RlcktleVBhdGh9LiBUaGUgZW5jcnlwdGVkIGNvbHVtbiBlbmNyeXB0aW9uIGtleSBtYXkgYmUgY29ycnVwdCwgb3IgdGhlIHNwZWNpZmllZCBBenVyZSBLZXkgVmF1bHQga2V5IHBhdGggbWF5IGJlIGluY29ycmVjdC5gKTtcbiAgICB9XG5cbiAgICBjb25zdCBzaWduYXR1cmVMZW5ndGg6IG51bWJlciA9IGVuY3J5cHRlZENvbHVtbkVuY3J5cHRpb25LZXkubGVuZ3RoIC0gY3VycmVudEluZGV4IC0gY2lwaGVyVGV4dExlbmd0aDtcblxuICAgIGlmIChzaWduYXR1cmVMZW5ndGggIT09IGtleVNpemVJbkJ5dGVzKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFRoZSBzcGVjaWZpZWQgZW5jcnlwdGVkIGNvbHVtbiBlbmNyeXB0aW9uIGtleSdzIHNpZ25hdHVyZSBsZW5ndGg6ICR7c2lnbmF0dXJlTGVuZ3RofSBkb2VzIG5vdCBtYXRjaCB0aGUgc2lnbmF0dXJlIGxlbmd0aDogJHtrZXlTaXplSW5CeXRlc30gd2hlbiB1c2luZyBjb2x1bW4gbWFzdGVyIGtleSAoQXp1cmUgS2V5IFZhdWx0IGtleSkgaW4gJHttYXN0ZXJLZXlQYXRofS4gVGhlIGVuY3J5cHRlZCBjb2x1bW4gZW5jcnlwdGlvbiBrZXkgbWF5IGJlIGNvcnJ1cHQsIG9yIHRoZSBzcGVjaWZpZWQgQXp1cmUgS2V5IFZhdWx0IGtleSBwYXRoIG1heSBiZSBpbmNvcnJlY3QuYCk7XG4gICAgfVxuXG4gICAgY29uc3QgY2lwaGVyVGV4dCA9IEJ1ZmZlci5hbGxvYyhjaXBoZXJUZXh0TGVuZ3RoKTtcbiAgICBlbmNyeXB0ZWRDb2x1bW5FbmNyeXB0aW9uS2V5LmNvcHkoY2lwaGVyVGV4dCwgMCwgY3VycmVudEluZGV4LCBjdXJyZW50SW5kZXggKyBjaXBoZXJUZXh0TGVuZ3RoKTtcbiAgICBjdXJyZW50SW5kZXggKz0gY2lwaGVyVGV4dExlbmd0aDtcblxuICAgIGNvbnN0IHNpZ25hdHVyZSA9IEJ1ZmZlci5hbGxvYyhzaWduYXR1cmVMZW5ndGgpO1xuICAgIGVuY3J5cHRlZENvbHVtbkVuY3J5cHRpb25LZXkuY29weShzaWduYXR1cmUsIDAsIGN1cnJlbnRJbmRleCwgY3VycmVudEluZGV4ICsgc2lnbmF0dXJlTGVuZ3RoKTtcblxuICAgIGNvbnN0IGhhc2ggPSBCdWZmZXIuYWxsb2MoZW5jcnlwdGVkQ29sdW1uRW5jcnlwdGlvbktleS5sZW5ndGggLSBzaWduYXR1cmUubGVuZ3RoKTtcbiAgICBlbmNyeXB0ZWRDb2x1bW5FbmNyeXB0aW9uS2V5LmNvcHkoaGFzaCwgMCwgMCwgZW5jcnlwdGVkQ29sdW1uRW5jcnlwdGlvbktleS5sZW5ndGggLSBzaWduYXR1cmUubGVuZ3RoKTtcblxuICAgIGNvbnN0IG1lc3NhZ2VEaWdlc3QgPSBjcmVhdGVIYXNoKCdzaGEyNTYnKTtcbiAgICBtZXNzYWdlRGlnZXN0LnVwZGF0ZShoYXNoKTtcblxuICAgIGNvbnN0IGRhdGFUb1ZlcmlmeTogQnVmZmVyID0gbWVzc2FnZURpZ2VzdC5kaWdlc3QoKTtcblxuICAgIGlmICghZGF0YVRvVmVyaWZ5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0hhc2ggc2hvdWxkIG5vdCBiZSBudWxsIHdoaWxlIGRlY3J5cHRpbmcgZW5jcnlwdGVkIGNvbHVtbiBlbmNyeXB0aW9uIGtleS4nKTtcbiAgICB9XG5cbiAgICBjb25zdCB2ZXJpZnlLZXkgPSBhd2FpdCBjcnlwdG9DbGllbnQudmVyaWZ5KCdSUzI1NicsIGRhdGFUb1ZlcmlmeSwgc2lnbmF0dXJlKTtcbiAgICBpZiAoIXZlcmlmeUtleS5yZXN1bHQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgVGhlIHNwZWNpZmllZCBlbmNyeXB0ZWQgY29sdW1uIGVuY3J5cHRpb24ga2V5IHNpZ25hdHVyZSBkb2VzIG5vdCBtYXRjaCB0aGUgc2lnbmF0dXJlIGNvbXB1dGVkIHdpdGggdGhlIGNvbHVtbiBtYXN0ZXIga2V5IChBc3ltbWV0cmljIGtleSBpbiBBenVyZSBLZXkgVmF1bHQpIGluICR7bWFzdGVyS2V5UGF0aH0uIFRoZSBlbmNyeXB0ZWQgY29sdW1uIGVuY3J5cHRpb24ga2V5IG1heSBiZSBjb3JydXB0LCBvciB0aGUgc3BlY2lmaWVkIHBhdGggbWF5IGJlIGluY29ycmVjdC5gKTtcbiAgICB9XG5cbiAgICBjb25zdCBkZWNyeXB0ZWRDRUs6IEJ1ZmZlciA9IGF3YWl0IHRoaXMuYXp1cmVLZXlWYXVsdFVuV3JhcChjcnlwdG9DbGllbnQsIGVuY3J5cHRpb25BbGdvcml0aG0sIGNpcGhlclRleHQpO1xuXG4gICAgcmV0dXJuIGRlY3J5cHRlZENFSztcbiAgfVxuXG4gIGFzeW5jIGVuY3J5cHRDb2x1bW5FbmNyeXB0aW9uS2V5KG1hc3RlcktleVBhdGg6IHN0cmluZywgZW5jcnlwdGlvbkFsZ29yaXRobTogc3RyaW5nLCBjb2x1bW5FbmNyeXB0aW9uS2V5OiBCdWZmZXIpOiBQcm9taXNlPEJ1ZmZlcj4ge1xuICAgIGlmICghY29sdW1uRW5jcnlwdGlvbktleSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb2x1bW4gZW5jcnlwdGlvbiBrZXkgY2Fubm90IGJlIG51bGwuJyk7XG4gICAgfVxuXG4gICAgaWYgKGNvbHVtbkVuY3J5cHRpb25LZXkubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0VtcHR5IGNvbHVtbiBlbmNyeXB0aW9uIGtleSBzcGVjaWZpZWQuJyk7XG4gICAgfVxuXG4gICAgZW5jcnlwdGlvbkFsZ29yaXRobSA9IHRoaXMudmFsaWRhdGVFbmNyeXB0aW9uQWxnb3JpdGhtKGVuY3J5cHRpb25BbGdvcml0aG0pO1xuXG4gICAgY29uc3QgbWFzdGVyS2V5ID0gYXdhaXQgdGhpcy5nZXRNYXN0ZXJLZXkobWFzdGVyS2V5UGF0aCk7XG5cbiAgICBjb25zdCBrZXlTaXplSW5CeXRlcyA9IHRoaXMuZ2V0QUtWS2V5U2l6ZShtYXN0ZXJLZXkpO1xuXG4gICAgY29uc3QgY3J5cHRvQ2xpZW50ID0gdGhpcy5jcmVhdGVDcnlwdG9DbGllbnQobWFzdGVyS2V5KTtcblxuICAgIGNvbnN0IHZlcnNpb24gPSBCdWZmZXIuZnJvbShbdGhpcy5maXJzdFZlcnNpb25bMF1dKTtcblxuICAgIGNvbnN0IG1hc3RlcktleVBhdGhCeXRlczogQnVmZmVyID0gQnVmZmVyLmZyb20obWFzdGVyS2V5UGF0aC50b0xvd2VyQ2FzZSgpLCAndXRmOCcpO1xuXG4gICAgY29uc3Qga2V5UGF0aExlbmd0aDogQnVmZmVyID0gQnVmZmVyLmFsbG9jKDIpO1xuXG4gICAga2V5UGF0aExlbmd0aFswXSA9IG1hc3RlcktleVBhdGhCeXRlcy5sZW5ndGggJiAweGZmO1xuICAgIGtleVBhdGhMZW5ndGhbMV0gPSBtYXN0ZXJLZXlQYXRoQnl0ZXMubGVuZ3RoID4+IDggJiAweGZmO1xuXG4gICAgY29uc3QgY2lwaGVyVGV4dDogQnVmZmVyID0gYXdhaXQgdGhpcy5henVyZUtleVZhdWx0V3JhcChjcnlwdG9DbGllbnQsIGVuY3J5cHRpb25BbGdvcml0aG0sIGNvbHVtbkVuY3J5cHRpb25LZXkpO1xuXG4gICAgY29uc3QgY2lwaGVyVGV4dExlbmd0aDogQnVmZmVyID0gQnVmZmVyLmFsbG9jKDIpO1xuXG4gICAgY2lwaGVyVGV4dExlbmd0aFswXSA9IGNpcGhlclRleHQubGVuZ3RoICYgMHhmZjtcbiAgICBjaXBoZXJUZXh0TGVuZ3RoWzFdID0gY2lwaGVyVGV4dC5sZW5ndGggPj4gOCAmIDB4ZmY7XG5cbiAgICBpZiAoY2lwaGVyVGV4dC5sZW5ndGggIT09IGtleVNpemVJbkJ5dGVzKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NpcGhlclRleHQgbGVuZ3RoIGRvZXMgbm90IG1hdGNoIHRoZSBSU0Ega2V5IHNpemUuJyk7XG4gICAgfVxuXG4gICAgY29uc3QgZGF0YVRvSGFzaDogQnVmZmVyID0gQnVmZmVyLmFsbG9jKHZlcnNpb24ubGVuZ3RoICsga2V5UGF0aExlbmd0aC5sZW5ndGggKyBjaXBoZXJUZXh0TGVuZ3RoLmxlbmd0aCArIG1hc3RlcktleVBhdGhCeXRlcy5sZW5ndGggKyBjaXBoZXJUZXh0Lmxlbmd0aCk7XG4gICAgbGV0IGRlc3RpbmF0aW9uUG9zaXRpb246IG51bWJlciA9IHZlcnNpb24ubGVuZ3RoO1xuICAgIHZlcnNpb24uY29weShkYXRhVG9IYXNoLCAwLCAwLCB2ZXJzaW9uLmxlbmd0aCk7XG5cbiAgICBrZXlQYXRoTGVuZ3RoLmNvcHkoZGF0YVRvSGFzaCwgZGVzdGluYXRpb25Qb3NpdGlvbiwgMCwga2V5UGF0aExlbmd0aC5sZW5ndGgpO1xuICAgIGRlc3RpbmF0aW9uUG9zaXRpb24gKz0ga2V5UGF0aExlbmd0aC5sZW5ndGg7XG5cbiAgICBjaXBoZXJUZXh0TGVuZ3RoLmNvcHkoZGF0YVRvSGFzaCwgZGVzdGluYXRpb25Qb3NpdGlvbiwgMCwgY2lwaGVyVGV4dExlbmd0aC5sZW5ndGgpO1xuICAgIGRlc3RpbmF0aW9uUG9zaXRpb24gKz0gY2lwaGVyVGV4dExlbmd0aC5sZW5ndGg7XG5cbiAgICBtYXN0ZXJLZXlQYXRoQnl0ZXMuY29weShkYXRhVG9IYXNoLCBkZXN0aW5hdGlvblBvc2l0aW9uLCAwLCBtYXN0ZXJLZXlQYXRoQnl0ZXMubGVuZ3RoKTtcbiAgICBkZXN0aW5hdGlvblBvc2l0aW9uICs9IG1hc3RlcktleVBhdGhCeXRlcy5sZW5ndGg7XG5cbiAgICBjaXBoZXJUZXh0LmNvcHkoZGF0YVRvSGFzaCwgZGVzdGluYXRpb25Qb3NpdGlvbiwgMCwgY2lwaGVyVGV4dC5sZW5ndGgpO1xuXG4gICAgY29uc3QgbWVzc2FnZURpZ2VzdCA9IGNyZWF0ZUhhc2goJ3NoYTI1NicpO1xuXG4gICAgbWVzc2FnZURpZ2VzdC51cGRhdGUoZGF0YVRvSGFzaCk7XG5cbiAgICBjb25zdCBkYXRhVG9TaWduOiBCdWZmZXIgPSBtZXNzYWdlRGlnZXN0LmRpZ2VzdCgpO1xuXG4gICAgY29uc3Qgc2lnbmVkSGFzaDogQnVmZmVyID0gYXdhaXQgdGhpcy5henVyZUtleVZhdWx0U2lnbmVkSGFzaGVkRGF0YShjcnlwdG9DbGllbnQsIGRhdGFUb1NpZ24pO1xuICAgIGlmIChzaWduZWRIYXNoLmxlbmd0aCAhPT0ga2V5U2l6ZUluQnl0ZXMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignU2lnbmVkIGhhc2ggbGVuZ3RoIGRvZXMgbm90IG1hdGNoIHRoZSBSU0Ega2V5IHNpemUuJyk7XG4gICAgfVxuXG4gICAgY29uc3QgdmVyaWZ5S2V5ID0gYXdhaXQgY3J5cHRvQ2xpZW50LnZlcmlmeSgnUlMyNTYnLCBkYXRhVG9TaWduLCBzaWduZWRIYXNoKTtcblxuICAgIGlmICghdmVyaWZ5S2V5LnJlc3VsdCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHNpZ25hdHVyZSBvZiB0aGUgZW5jcnlwdGVkIGNvbHVtbiBlbmNyeXB0aW9uIGtleSBjb21wdXRlZC4nKTtcbiAgICB9XG5cbiAgICBjb25zdCBlbmNyeXB0ZWRDb2x1bW5FbmNyeXB0aW9uS2V5TGVuZ3RoOiBudW1iZXIgPSB2ZXJzaW9uLmxlbmd0aCArIGNpcGhlclRleHRMZW5ndGgubGVuZ3RoICsga2V5UGF0aExlbmd0aC5sZW5ndGggKyBjaXBoZXJUZXh0Lmxlbmd0aCArIG1hc3RlcktleVBhdGhCeXRlcy5sZW5ndGggKyBzaWduZWRIYXNoLmxlbmd0aDtcbiAgICBjb25zdCBlbmNyeXB0ZWRDb2x1bW5FbmNyeXB0aW9uS2V5OiBCdWZmZXIgPSBCdWZmZXIuYWxsb2MoZW5jcnlwdGVkQ29sdW1uRW5jcnlwdGlvbktleUxlbmd0aCk7XG5cbiAgICBsZXQgY3VycmVudEluZGV4ID0gMDtcbiAgICB2ZXJzaW9uLmNvcHkoZW5jcnlwdGVkQ29sdW1uRW5jcnlwdGlvbktleSwgY3VycmVudEluZGV4LCAwLCB2ZXJzaW9uLmxlbmd0aCk7XG4gICAgY3VycmVudEluZGV4ICs9IHZlcnNpb24ubGVuZ3RoO1xuXG4gICAga2V5UGF0aExlbmd0aC5jb3B5KGVuY3J5cHRlZENvbHVtbkVuY3J5cHRpb25LZXksIGN1cnJlbnRJbmRleCwgMCwga2V5UGF0aExlbmd0aC5sZW5ndGgpO1xuICAgIGN1cnJlbnRJbmRleCArPSBrZXlQYXRoTGVuZ3RoLmxlbmd0aDtcblxuICAgIGNpcGhlclRleHRMZW5ndGguY29weShlbmNyeXB0ZWRDb2x1bW5FbmNyeXB0aW9uS2V5LCBjdXJyZW50SW5kZXgsIDAsIGNpcGhlclRleHRMZW5ndGgubGVuZ3RoKTtcbiAgICBjdXJyZW50SW5kZXggKz0gY2lwaGVyVGV4dExlbmd0aC5sZW5ndGg7XG5cbiAgICBtYXN0ZXJLZXlQYXRoQnl0ZXMuY29weShlbmNyeXB0ZWRDb2x1bW5FbmNyeXB0aW9uS2V5LCBjdXJyZW50SW5kZXgsIDAsIG1hc3RlcktleVBhdGhCeXRlcy5sZW5ndGgpO1xuICAgIGN1cnJlbnRJbmRleCArPSBtYXN0ZXJLZXlQYXRoQnl0ZXMubGVuZ3RoO1xuXG4gICAgY2lwaGVyVGV4dC5jb3B5KGVuY3J5cHRlZENvbHVtbkVuY3J5cHRpb25LZXksIGN1cnJlbnRJbmRleCwgMCwgY2lwaGVyVGV4dC5sZW5ndGgpO1xuICAgIGN1cnJlbnRJbmRleCArPSBjaXBoZXJUZXh0Lmxlbmd0aDtcblxuICAgIHNpZ25lZEhhc2guY29weShlbmNyeXB0ZWRDb2x1bW5FbmNyeXB0aW9uS2V5LCBjdXJyZW50SW5kZXgsIDAsIHNpZ25lZEhhc2gubGVuZ3RoKTtcblxuICAgIHJldHVybiBlbmNyeXB0ZWRDb2x1bW5FbmNyeXB0aW9uS2V5O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBnZXRNYXN0ZXJLZXkobWFzdGVyS2V5UGF0aDogc3RyaW5nKTogUHJvbWlzZTxLZXlWYXVsdEtleT4ge1xuICAgIGlmICghbWFzdGVyS2V5UGF0aCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdNYXN0ZXIga2V5IHBhdGggY2Fubm90IGJlIG51bGwgb3IgdW5kZWZpbmVkJyk7XG4gICAgfVxuICAgIGNvbnN0IGtleVBhcnRzID0gdGhpcy5wYXJzZVBhdGgobWFzdGVyS2V5UGF0aCk7XG5cbiAgICB0aGlzLmNyZWF0ZUtleUNsaWVudChrZXlQYXJ0cy52YXVsdFVybCk7XG5cbiAgICByZXR1cm4gYXdhaXQgKHRoaXMua2V5Q2xpZW50IGFzIEtleUNsaWVudCkuZ2V0S2V5KGtleVBhcnRzLm5hbWUsIGtleVBhcnRzLnZlcnNpb24gPyB7IHZlcnNpb246IGtleVBhcnRzLnZlcnNpb24gfSA6IHt9KTtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlS2V5Q2xpZW50KGtleVZhdWx0VXJsOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAoIWtleVZhdWx0VXJsKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBjcmVhdGUga2V5IGNsaWVudCB3aXRoIG51bGwgb3IgdW5kZWZpbmVkIGtleVZhdWx0VXJsJyk7XG4gICAgfVxuICAgIGlmICghdGhpcy5rZXlDbGllbnQpIHtcbiAgICAgIHRoaXMudXJsID0ga2V5VmF1bHRVcmw7XG4gICAgICB0aGlzLmtleUNsaWVudCA9IG5ldyBLZXlDbGllbnQoa2V5VmF1bHRVcmwsIHRoaXMuY3JlZGVudGlhbHMpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlQ3J5cHRvQ2xpZW50KG1hc3RlcktleTogS2V5VmF1bHRLZXkpOiBDcnlwdG9ncmFwaHlDbGllbnQge1xuICAgIGlmICghbWFzdGVyS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBjcmVhdGUgQ3J5cHRvZ3JhcGh5Q2xpZW50IHdpdGggbnVsbCBvciB1bmRlZmluZWQgbWFzdGVyS2V5Jyk7XG4gICAgfVxuICAgIHJldHVybiBuZXcgQ3J5cHRvZ3JhcGh5Q2xpZW50KG1hc3RlcktleSwgdGhpcy5jcmVkZW50aWFscyk7XG4gIH1cblxuICBwcml2YXRlIHBhcnNlUGF0aChtYXN0ZXJLZXlQYXRoOiBzdHJpbmcpOiBQYXJzZWRLZXlQYXRoIHtcbiAgICBpZiAoIW1hc3RlcktleVBhdGggfHwgbWFzdGVyS2V5UGF0aC50cmltKCkgPT09ICcnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0F6dXJlIEtleSBWYXVsdCBrZXkgcGF0aCBjYW5ub3QgYmUgbnVsbC4nKTtcbiAgICB9XG5cbiAgICBsZXQgYmFzZVVyaTtcbiAgICB0cnkge1xuICAgICAgYmFzZVVyaSA9IHBhcnNlKG1hc3RlcktleVBhdGgsIHRydWUsIHRydWUpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGtleXMgaWRlbnRpZmllcjogJHttYXN0ZXJLZXlQYXRofS4gTm90IGEgdmFsaWQgVVJJYCk7XG4gICAgfVxuXG4gICAgaWYgKCFiYXNlVXJpLmhvc3RuYW1lIHx8ICFiYXNlVXJpLmhvc3RuYW1lLnRvTG93ZXJDYXNlKCkuZW5kc1dpdGgodGhpcy5henVyZUtleVZhdWx0RG9tYWluTmFtZSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBBenVyZSBLZXkgVmF1bHQga2V5IHBhdGggc3BlY2lmaWVkOiAke21hc3RlcktleVBhdGh9LmApO1xuICAgIH1cblxuICAgIC8vIFBhdGggaXMgb2YgdGhlIGZvcm0gJy9jb2xsZWN0aW9uL25hbWVbL3ZlcnNpb25dJ1xuICAgIGNvbnN0IHNlZ21lbnRzID0gKGJhc2VVcmkucGF0aG5hbWUgfHwgJycpLnNwbGl0KCcvJyk7XG4gICAgaWYgKHNlZ21lbnRzLmxlbmd0aCAhPT0gMyAmJiBzZWdtZW50cy5sZW5ndGggIT09IDQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEludmFsaWQga2V5cyBpZGVudGlmaWVyOiAke21hc3RlcktleVBhdGh9LiBCYWQgbnVtYmVyIG9mIHNlZ21lbnRzOiAke3NlZ21lbnRzLmxlbmd0aH1gXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmICgna2V5cycgIT09IHNlZ21lbnRzWzFdKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBJbnZhbGlkIGtleXMgaWRlbnRpZmllcjogJHttYXN0ZXJLZXlQYXRofS4gc2VnbWVudCBbMV0gc2hvdWxkIGJlIFwia2V5c1wiLCBmb3VuZCBcIiR7c2VnbWVudHNbMV19XCJgXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHZhdWx0VXJsID0gYCR7YmFzZVVyaS5wcm90b2NvbH0vLyR7YmFzZVVyaS5ob3N0fWA7XG4gICAgY29uc3QgbmFtZSA9IHNlZ21lbnRzWzJdO1xuICAgIGNvbnN0IHZlcnNpb24gPSBzZWdtZW50cy5sZW5ndGggPT09IDQgPyBzZWdtZW50c1szXSA6IHVuZGVmaW5lZDtcbiAgICByZXR1cm4ge1xuICAgICAgdmF1bHRVcmwsXG4gICAgICBuYW1lLFxuICAgICAgdmVyc2lvblxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGF6dXJlS2V5VmF1bHRTaWduZWRIYXNoZWREYXRhKGNyeXB0b0NsaWVudDogQ3J5cHRvZ3JhcGh5Q2xpZW50LCBkYXRhVG9TaWduOiBCdWZmZXIpOiBQcm9taXNlPEJ1ZmZlcj4ge1xuICAgIGlmICghY3J5cHRvQ2xpZW50KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0F6dXJlIEtWUyBDcnlwdG8gQ2xpZW50IGlzIG5vdCBkZWZpbmVkLicpO1xuICAgIH1cblxuICAgIGNvbnN0IHNpZ25lZERhdGEgPSBhd2FpdCBjcnlwdG9DbGllbnQuc2lnbignUlMyNTYnLCBkYXRhVG9TaWduKTtcblxuICAgIHJldHVybiBCdWZmZXIuZnJvbShzaWduZWREYXRhLnJlc3VsdCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGF6dXJlS2V5VmF1bHRXcmFwKGNyeXB0b0NsaWVudDogQ3J5cHRvZ3JhcGh5Q2xpZW50LCBlbmNyeXB0aW9uQWxnb3JpdGhtOiBzdHJpbmcsIGNvbHVtbkVuY3J5cHRpb25LZXk6IEJ1ZmZlcik6IFByb21pc2U8QnVmZmVyPiB7XG4gICAgaWYgKCFjcnlwdG9DbGllbnQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQXp1cmUgS1ZTIENyeXB0byBDbGllbnQgaXMgbm90IGRlZmluZWQuJyk7XG4gICAgfVxuXG4gICAgaWYgKCFjb2x1bW5FbmNyeXB0aW9uS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvbHVtbiBlbmNyeXB0aW9uIGtleSBjYW5ub3QgYmUgbnVsbC4nKTtcbiAgICB9XG5cbiAgICBjb25zdCB3cmFwcGVkS2V5ID0gYXdhaXQgY3J5cHRvQ2xpZW50LndyYXBLZXkoZW5jcnlwdGlvbkFsZ29yaXRobSBhcyBLZXlXcmFwQWxnb3JpdGhtLCBjb2x1bW5FbmNyeXB0aW9uS2V5KTtcblxuICAgIHJldHVybiBCdWZmZXIuZnJvbSh3cmFwcGVkS2V5LnJlc3VsdCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGF6dXJlS2V5VmF1bHRVbldyYXAoY3J5cHRvQ2xpZW50OiBDcnlwdG9ncmFwaHlDbGllbnQsIGVuY3J5cHRpb25BbGdvcml0aG06IHN0cmluZywgZW5jcnlwdGVkQ29sdW1uRW5jcnlwdGlvbktleTogQnVmZmVyKTogUHJvbWlzZTxCdWZmZXI+IHtcbiAgICBpZiAoIWNyeXB0b0NsaWVudCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdBenVyZSBLVlMgQ3J5cHRvIENsaWVudCBpcyBub3QgZGVmaW5lZC4nKTtcbiAgICB9XG5cbiAgICBpZiAoIWVuY3J5cHRpb25BbGdvcml0aG0pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRW5jcnlwdGlvbiBBbGdvcml0aG0gY2Fubm90IGJlIG51bGwgb3IgdW5kZWZpbmVkJyk7XG4gICAgfVxuXG4gICAgaWYgKCFlbmNyeXB0ZWRDb2x1bW5FbmNyeXB0aW9uS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0VuY3J5cHRlZCBjb2x1bW4gZW5jcnlwdGlvbiBrZXkgY2Fubm90IGJlIG51bGwuJyk7XG4gICAgfVxuXG4gICAgaWYgKGVuY3J5cHRlZENvbHVtbkVuY3J5cHRpb25LZXkubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0VuY3J5cHRlZCBDb2x1bW4gRW5jcnlwdGlvbiBLZXkgbGVuZ3RoIHNob3VsZCBub3QgYmUgemVyby4nKTtcbiAgICB9XG5cbiAgICBjb25zdCB1bndyYXBwZWRLZXkgPSBhd2FpdCBjcnlwdG9DbGllbnQudW53cmFwS2V5KGVuY3J5cHRpb25BbGdvcml0aG0gYXMgS2V5V3JhcEFsZ29yaXRobSwgZW5jcnlwdGVkQ29sdW1uRW5jcnlwdGlvbktleSk7XG5cbiAgICByZXR1cm4gQnVmZmVyLmZyb20odW53cmFwcGVkS2V5LnJlc3VsdCk7XG4gIH1cblxuICBwcml2YXRlIGdldEFLVktleVNpemUocmV0cmlldmVkS2V5OiBLZXlWYXVsdEtleSk6IG51bWJlciB7XG4gICAgaWYgKCFyZXRyaWV2ZWRLZXkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignUmV0cmlldmVkIGtleSBjYW5ub3QgYmUgbnVsbCBvciB1bmRlZmluZWQnKTtcbiAgICB9XG4gICAgY29uc3Qga2V5ID0gcmV0cmlldmVkS2V5LmtleTtcblxuICAgIGlmICgha2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEtleSBkb2VzIG5vdCBleGlzdCAke3JldHJpZXZlZEtleS5uYW1lfWApO1xuICAgIH1cblxuICAgIGNvbnN0IGt0eTogc3RyaW5nIHwgdW5kZWZpbmVkID0ga2V5ICYmIGtleS5rdHkgJiYga2V5Lmt0eS50b1N0cmluZygpLnRvVXBwZXJDYXNlKCk7XG5cbiAgICBpZiAoIWt0eSB8fCAnUlNBJy5sb2NhbGVDb21wYXJlKGt0eSwgJ2VuJykgIT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IHVzZSBhIG5vbi1SU0Ega2V5OiAke2t0eX0uYCk7XG4gICAgfVxuXG4gICAgY29uc3Qga2V5TGVuZ3RoID0ga2V5ICYmIGtleS5uICYmIGtleS5uLmxlbmd0aDtcblxuICAgIHJldHVybiBrZXlMZW5ndGggfHwgMDtcbiAgfVxuXG4gIHByaXZhdGUgdmFsaWRhdGVFbmNyeXB0aW9uQWxnb3JpdGhtKGVuY3J5cHRpb25BbGdvcml0aG06IHN0cmluZyk6IHN0cmluZyB7XG4gICAgaWYgKCFlbmNyeXB0aW9uQWxnb3JpdGhtKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0tleSBlbmNyeXB0aW9uIGFsZ29yaXRobSBjYW5ub3QgYmUgbnVsbC4nKTtcbiAgICB9XG5cbiAgICBpZiAoJ1JTQV9PQUVQJy5sb2NhbGVDb21wYXJlKGVuY3J5cHRpb25BbGdvcml0aG0udG9VcHBlckNhc2UoKSwgJ2VuJykgPT09IDApIHtcbiAgICAgIGVuY3J5cHRpb25BbGdvcml0aG0gPSAnUlNBLU9BRVAnO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnJzYUVuY3J5cHRpb25BbGdvcml0aG1XaXRoT0FFUEZvckFLVi5sb2NhbGVDb21wYXJlKGVuY3J5cHRpb25BbGdvcml0aG0udHJpbSgpLnRvVXBwZXJDYXNlKCksICdlbicpICE9PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQga2V5IGVuY3J5cHRpb24gYWxnb3JpdGhtIHNwZWNpZmllZDogJHtlbmNyeXB0aW9uQWxnb3JpdGhtfS4gRXhwZWN0ZWQgdmFsdWU6ICR7dGhpcy5yc2FFbmNyeXB0aW9uQWxnb3JpdGhtV2l0aE9BRVBGb3JBS1Z9LmApO1xuICAgIH1cblxuICAgIHJldHVybiBlbmNyeXB0aW9uQWxnb3JpdGhtO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7QUFHQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFOQTtBQUNBO0FBYU8sTUFBTUEscUNBQU4sQ0FBNEM7RUFTakRDLFdBQVcsQ0FBQ0MsUUFBRCxFQUFtQkMsU0FBbkIsRUFBc0NDLFFBQXRDLEVBQXdEO0lBQUEsS0FSbkRDLElBUW1EO0lBQUEsS0FQM0RDLEdBTzJEO0lBQUEsS0FObERDLG9DQU1rRDtJQUFBLEtBTGxEQyxZQUtrRDtJQUFBLEtBSjNEQyxXQUkyRDtJQUFBLEtBSGxEQyx1QkFHa0Q7SUFBQSxLQUYzREMsU0FFMkQ7SUFDakUsS0FBS04sSUFBTCxHQUFZLGlCQUFaO0lBQ0EsS0FBS0ssdUJBQUwsR0FBK0IsaUJBQS9CO0lBQ0EsS0FBS0gsb0NBQUwsR0FBNEMsVUFBNUM7SUFDQSxLQUFLQyxZQUFMLEdBQW9CSSxNQUFNLENBQUNDLElBQVAsQ0FBWSxDQUFDLElBQUQsQ0FBWixDQUFwQjtJQUNBLEtBQUtKLFdBQUwsR0FBbUIsSUFBSUssZ0NBQUosQ0FBMkJWLFFBQTNCLEVBQXFDRixRQUFyQyxFQUErQ0MsU0FBL0MsQ0FBbkI7RUFDRDs7RUFFK0IsTUFBMUJZLDBCQUEwQixDQUFDQyxhQUFELEVBQXdCQyxtQkFBeEIsRUFBcURDLDRCQUFyRCxFQUE0RztJQUMxSSxJQUFJLENBQUNBLDRCQUFMLEVBQW1DO01B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