teradatasql
Version:
Teradata SQL Driver for Node.js
558 lines • 30.7 kB
JavaScript
"use strict";
// Copyright 2023 by Teradata Corporation. All rights reserved.
//
// Purpose: Encrypts a password, saves the encryption key in one file, and saves the encrypted password in a second file
//
// This program accepts eight command-line arguments:
//
// 1. Transformation - Specifies the transformation in the form Algorithm/Mode/Padding.
// Example: AES/CBC/NoPadding
//
// 2. KeySizeInBits - Specifies the algorithm key size, which governs the encryption strength.
// Example: 256
//
// 3. MAC - Specifies the message authentication code (MAC) algorithm HmacSHA1 or HmacSHA256.
// Example: HmacSHA256
//
// 4. PasswordEncryptionKeyFileName - Specifies a filename in the current directory, a relative pathname, or an absolute pathname.
// The file is created by this program. If the file already exists, it will be overwritten by the new file.
// Example: PassKey.properties
//
// 5. EncryptedPasswordFileName - Specifies a filename in the current directory, a relative pathname, or an absolute pathname.
// The filename or pathname that must differ from the PasswordEncryptionKeyFileName.
// The file is created by this program. If the file already exists, it will be overwritten by the new file.
// Example: EncPass.properties
//
// 6. Hostname - Specifies the Teradata Database hostname.
// Example: whomooz
//
// 7. Username - Specifies the Teradata Database username.
// Example: guest
//
// 8. Password - Specifies the Teradata Database password to be encrypted.
// Example: please
//
// Overview
// --------
//
// Stored Password Protection enables an application to provide a connection password in encrypted form to
// the Teradata SQL Driver for Node.js.
//
// An encrypted password may be specified in the following contexts:
// * A login password specified as the "password" connection parameter.
// * A login password specified within the "logdata" connection parameter.
//
// If the password, however specified, begins with the prefix "ENCRYPTED_PASSWORD(" then the specified password must follow this format:
//
// ENCRYPTED_PASSWORD(file:PasswordEncryptionKeyFileName,file:EncryptedPasswordFileName)
//
// Each filename must be preceded by the "file:"" prefix.
// The PasswordEncryptionKeyFileName must be separated from the EncryptedPasswordFileName by a single comma.
// The PasswordEncryptionKeyFileName specifies the name of a properties file that contains the password
// encryption key and associated information.
// The EncryptedPasswordFileName specifies the name of a properties file that contains the encrypted password and associated information.
// The two files are described below.
//
// Stored Password Protection is offered by the Teradata JDBC Driver and the Teradata SQL Driver for Node.js.
// The same file format is used by both drivers.
//
// This program works in conjunction with Stored Password Protection offered by the Teradata JDBC Driver and the
// Teradata SQL Driver for Node.js. This program creates the files containing the password encryption key and encrypted password,
// which can be subsequently specified via the "ENCRYPTED_PASSWORD(" syntax.
//
// You are not required to use this program to create the files containing the password encryption key and encrypted password.
// You can develop your own software to create the necessary files.
// The only requirement is that the files must match the format expected by the Teradata SQL Driver for Node.js, which is
// documented below.
//
// This program encrypts the password and then immediately decrypts the password, in order to verify that the password can be
// successfully decrypted. This program mimics the password decryption of the Teradata SQL Driver for Node.js, and is intended
// to openly illustrate its operation and enable scrutiny by the community.
//
// The encrypted password is only as safe as the two files. You are responsible for restricting access to the files containing
// the password encryption key and encrypted password. If an attacker obtains both files, the password can be decrypted.
// The operating system file permissions for the two files should be as limited and restrictive as possible, to ensure that
// only the intended operating system userid has access to the files.
//
// The two files can be kept on separate physical volumes, to reduce the risk that both files might be lost at the same time.
// If either or both of the files are located on a network volume, then an encrypted wire protocol can be used to access the
// network volume, such as sshfs, encrypted NFSv4, or encrypted SMB 3.0.
//
// Example Commands
// ----------------
//
// This program uses the Teradata SQL Driver for Node.js to log on to the specified Teradata Database using the encrypted
// password, so the Teradata SQL Driver for Node.js must have been installed.
//
// The following example commands illustrate using a 256-bit AES key, and using the HmacSHA256 algorithm.
//
// node TJEncryptPassword.js AES/CBC/NoPadding 256 HmacSHA256 PassKey.properties EncPass.properties whomooz guest please
//
// Password Encryption Key File Format
// -----------------------------------
//
// You are not required to use the TJEncryptPassword program to create the files containing the password encryption key and
// encrypted password. You can develop your own software to create the necessary files, but the files must match the format
// expected by the Teradata SQL Driver for Node.js.
//
// The password encryption key file is a text file in Java Properties file format, using the ISO 8859-1 character encoding.
//
// The file must contain the following string properties:
//
// version=1
//
// The version number must be 1.
// This property is required.
//
// transformation=TransformationName
//
// Specifies the transformation in the form Algorithm/Mode/Padding.
// This property is required.
// Example: AES/CBC/NoPadding
//
// algorithm=AlgorithmName
//
// This value must correspond to the Algorithm portion of the transformation.
// This property is required.
// Example: AES
//
// match=MatchValue
//
// The password encryption key and encrypted password files must contain the same match value.
// The match values are compared to ensure that the two specified files are related to each other,
// serving as a "sanity check" to help avoid configuration errors.
// This property is required. Any shared string can serve as a match value.
//
// key=HexDigits
//
// This value is the password encryption key, encoded as hex digits.
// This property is required.
//
// mac=MACAlgorithmName
//
// Specifies the message authentication code (MAC) algorithm HmacSHA1 or HmacSHA256.
// Stored Password Protection performs Encrypt-then-MAC for protection from a padding oracle attack.
// This property is required.
//
// mackey=HexDigits
//
// This value is the MAC key, encoded as hex digits.
// This property is required.
//
// Encrypted Password File Format
// ------------------------------
//
// The encrypted password file is a text file in Java Properties file format, using the ISO 8859-1 character encoding.
//
// The file must contain the following string properties:
//
// version=1
//
// The version number must be 1.
// This property is required.
//
// match=MatchValue
//
// The password encryption key and encrypted password files must contain the same match value.
// The match values are compared to ensure that the two specified files are related to each other,
// serving as a "sanity check" to help avoid configuration errors.
// This property is required. Any shared string can serve as a match value.
//
// password=HexDigits
//
// This value is the encrypted password, encoded as hex digits.
// This property is required.
//
// params=HexDigits
//
// This value contains the cipher algorithm parameters, if any, encoded as hex digits.
// Some ciphers need algorithm parameters that cannot be derived from the key, such as an initialization vector.
// This property is optional, depending on whether the cipher algorithm has associated parameters.
//
// While this value is technically optional, an initialization vector is required by all three
// block cipher modes CBC, CFB, and OFB that are supported by the Teradata SQL Driver for Node.js.
// ECB (Electronic Codebook) does not require params, but ECB is not supported by the Teradata SQL Driver for Node.js.
//
// hash=HexDigits
//
// This value is the expected message authentication code (MAC), encoded as hex digits.
// After encryption, the expected MAC is calculated using the ciphertext, transformation name, and algorithm parameters if any.
// Before decryption, the Teradata SQL Driver for Node.js calculates the MAC using the ciphertext, transformation name,
// and algorithm parameters, if any, and verifies that the calculated MAC matches the expected MAC.
// If the calculated MAC differs from the expected MAC, then either or both of the files may have been tampered with.
// This property is required.
//
// Transformation, Key Size, and MAC
// ---------------------------------
//
// A transformation is a string that describes the set of operations to be performed on the given input, to produce transformed output.
// A transformation specifies the name of a cryptographic algorithm such as AES, followed by a feedback mode and padding scheme.
//
// The Teradata SQL Driver for Node.js supports the following transformations and key sizes.
//
// AES/CBC/NoPadding 128
// AES/CBC/NoPadding 192
// AES/CBC/NoPadding 256
// AES/CBC/PKCS5Padding 128
// AES/CBC/PKCS5Padding 192
// AES/CBC/PKCS5Padding 256
// AES/CFB/NoPadding 128
// AES/CFB/NoPadding 192
// AES/CFB/NoPadding 256
// AES/CFB/PKCS5Padding 128
// AES/CFB/PKCS5Padding 192
// AES/CFB/PKCS5Padding 256
// AES/OFB/NoPadding 128
// AES/OFB/NoPadding 192
// AES/OFB/NoPadding 256
// AES/OFB/PKCS5Padding 128
// AES/OFB/PKCS5Padding 192
// AES/OFB/PKCS5Padding 256
//
// Stored Password Protection uses a symmetric encryption algorithm such as AES, in which the same secret key is used for
// encryption and decryption of the password. Stored Password Protection does not use an asymmetric encryption algorithm such as RSA,
// with separate public and private keys.
//
// CBC (Cipher Block Chaining) is a block cipher encryption mode. With CBC, each ciphertext block is dependent on all plaintext blocks
// processed up to that point. CBC is suitable for encrypting data whose total byte count exceeds the algorithm's block size, and is
// therefore suitable for use with Stored Password Protection.
//
// Stored Password Protection hides the password length in the encrypted password file by extending the length of the UTF8-encoded
// password with trailing null bytes. The length is extended to the next 512-byte boundary.
//
// A block cipher with no padding, such as AES/CBC/NoPadding, may only be used to encrypt data whose byte count after extension is
// a multiple of the algorithm's block size. The 512-byte boundary is compatible with many block ciphers. AES, for example, has a
// block size of 128 bits (16 bytes), and is therefore compatible with the 512-byte boundary.
//
// A block cipher with padding, such as AES/CBC/PKCS5Padding, can be used to encrypt data of any length. However, CBC with padding
// is vulnerable to a "padding oracle attack", so Stored Password Protection performs Encrypt-then-MAC for protection from a padding
// oracle attack. MAC algorithms HmacSHA1 and HmacSHA256 are supported.
//
// The Teradata SQL Driver for Node.js does not support block ciphers used as byte-oriented ciphers via modes such as CFB8 or OFB8.
//
// The strength of the encryption depends on your choice of cipher algorithm and key size.
//
// AES uses a 128-bit (16 byte), 192-bit (24 byte), or 256-bit (32 byte) key.
//
// Sharing Files with the Teradata JDBC Driver
// -------------------------------------------
//
// The Teradata SQL Driver for Node.js and the Teradata JDBC Driver can share the files containing the password encryption key and
// encrypted password, if you use a transformation, key size, and MAC algorithm that is supported by both drivers.
//
// Recommended choices for compatibility are AES/CBC/NoPadding and HmacSHA256.
// Use a 256-bit key if your Java environment has the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files
// from Oracle.
// Use a 128-bit key if your Java environment does not have the Unlimited Strength Jurisdiction Policy Files.
// Use HmacSHA1 for compatibility with JDK 1.4.2.
//
// File Locations
// --------------
//
// For the "ENCRYPTED_PASSWORD(" syntax of the Teradata SQL Driver for Node.js, each filename must be preceded by the file: prefix.
// The PasswordEncryptionKeyFileName must be separated from the EncryptedPasswordFileName by a single comma.
// The files can be located in the current directory, specified with a relative path, or specified with an absolute path.
//
// Example for files in the current directory:
//
// ENCRYPTED_PASSWORD(file:JohnDoeKey.properties,file:JohnDoePass.properties)
//
// Example with relative paths:
//
// ENCRYPTED_PASSWORD(file:../dir1/JohnDoeKey.properties,file:../dir2/JohnDoePass.properties)
//
// Example with absolute paths on Windows:
//
// ENCRYPTED_PASSWORD(file:c:/dir1/JohnDoeKey.properties,file:c:/dir2/JohnDoePass.properties)
//
// Example with absolute paths on Linux:
//
// ENCRYPTED_PASSWORD(file:/dir1/JohnDoeKey.properties,file:/dir2/JohnDoePass.properties)
//
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-ignore
const teradatasql = __importStar(require("teradatasql"));
const fs = __importStar(require("fs"));
const crypto_ = __importStar(require("crypto"));
function convertJavaNames(sName, nKeySizeInBits = 0, sMode = "") {
// for list of available cypher names in node.js run command: openssl list -cipher-algorithms
if (sName === "AES") {
sName = "aes-" + nKeySizeInBits.toString() + "-" + sMode.toLowerCase(); // e.g., 'aes-128-ofb'
}
return sName;
} // convertJavaNames
function createPasswordEncryptionKeyFile(sTransformation, sAlgorithm, sMatch, sMac, nKeySizeInBits, sPassKeyFileName) {
// Create encryption key
const nKeySizeInBytes = nKeySizeInBits / 8;
const abyKey = crypto_.randomBytes(nKeySizeInBytes);
// Create MAC key
const nMacBlockSizeBytes = 64;
const abyMacKey = crypto_.randomBytes(nMacBlockSizeBytes);
const sKeyHexDigits = abyKey.toString("hex");
const sMacKeyHexDigits = abyMacKey.toString("hex");
const fileData = "# Teradata SQL Driver password encryption key file\n" +
"version=1\n" +
"transformation=" +
sTransformation +
"\n" +
"algorithm=" +
sAlgorithm +
"\n" +
"match=" +
sMatch +
"\n" +
"key=" +
sKeyHexDigits +
"\n" +
"mac=" +
sMac +
"\n" +
"mackey=" +
sMacKeyHexDigits +
"\n";
const asTransformationParts = sTransformation.split("/");
if (asTransformationParts.length !== 3) {
console.log(">>> Invalid transformation: " + sTransformation);
process.exit(1);
}
fs.writeFileSync(sPassKeyFileName, fileData, { encoding: "latin1" }); // Latin-1 stands for ISO-8859-1
return [abyKey, abyMacKey];
} // createPasswordEncryptionKeyFile
function createEncryptedPasswordFile(sTransformation, sAlgorithm, sMatch, sMac, sMode, nKeySizeInBits, abyKey, abyMacKey, sEncPassFileName, nCipherBlockSizeInBytes, sPassword) {
let abyPassword = Buffer.from(sPassword, "utf8");
// Create an initialization vector for the cipher
const abyIV = crypto_.randomBytes(nCipherBlockSizeInBytes);
// Encode the initialization vector as an octet string in der-format
const octetStringTag = 0x04; // The tag value for an octet string in der-format is 0x04
let abyASN1EncodedIV = Buffer.allocUnsafe(2);
abyASN1EncodedIV[0] = octetStringTag;
abyASN1EncodedIV[1] = abyIV.length;
abyASN1EncodedIV = Buffer.concat([abyASN1EncodedIV, abyIV], abyASN1EncodedIV.length + abyIV.length);
// Zero-pad the password to the next 512-byte boundary and append null bytes to next 512 boundary
const nPlaintextByteCount = (Math.floor(abyPassword.length / 512) + 1) * 512;
const nTrailerByteCount = nPlaintextByteCount - abyPassword.length;
const emptyBuffer = Buffer.alloc(nTrailerByteCount);
abyPassword = Buffer.concat([abyPassword, emptyBuffer], abyPassword.length + emptyBuffer.length);
// Create cipher and encrypt password
const nodeAlgorithmName = convertJavaNames(sAlgorithm, nKeySizeInBits, sMode);
const cipher = crypto_.createCipheriv(nodeAlgorithmName, abyKey, abyIV);
let abyEncryptedPassword = cipher.update(abyPassword);
const finalCipher = cipher.final();
abyEncryptedPassword = Buffer.concat([abyEncryptedPassword, finalCipher], abyEncryptedPassword.length + finalCipher.length);
// Create hex for encrypted password
const sEncryptedPasswordHexDigits = abyEncryptedPassword.toString("hex");
// Create hex for parameters
const sASN1EncodedIVHexDigits = abyASN1EncodedIV.toString("hex");
// Create hex for 'hash' (using MAC key)
// The purpose of 'hash' is to be used to verify the integrity of encrypted password/parameters
const abyTransformation = Buffer.from(sTransformation, "utf8");
const abyContentLength = abyEncryptedPassword.length + abyTransformation.length + abyASN1EncodedIV.length;
const abyContent = Buffer.concat([abyEncryptedPassword, abyTransformation, abyASN1EncodedIV], abyContentLength);
sMac = sMac.slice(4).toLowerCase(); // e.g., slice 'HmacSHA256' to 'SHA256'
const hmac = crypto_.createHmac(sMac, abyMacKey);
hmac.update(abyContent);
const sHashHexDigits = hmac.digest("hex");
const fileData = "# Teradata SQL Driver encrypted password file\n" +
"version=1\n" +
"match=" +
sMatch +
"\n" +
"password=" +
sEncryptedPasswordHexDigits +
"\n" +
"params=" +
sASN1EncodedIVHexDigits +
"\n" +
"hash=" +
sHashHexDigits +
"\n";
fs.writeFileSync(sEncPassFileName, fileData, { encoding: "latin1" });
} // createEncryptedPasswordFile
function loadPropertiesFile(sFileName) {
const properties = {};
const content = fs.readFileSync(sFileName, { encoding: "latin1" });
const lines = content.split("\n");
lines.forEach((line) => {
line = line.trim();
if (line.indexOf("#") !== 0) {
const asTokens = line.split("=", 2);
if (asTokens.length === 2) {
const sKey = asTokens[0];
const sValue = asTokens[1];
properties[sKey] = sValue;
}
}
});
return properties;
} // loadPropertiesFile
function decryptPassword(sPassKeyFileName, sEncPassFileName) {
const mapPassKey = loadPropertiesFile(sPassKeyFileName);
const mapEncPass = loadPropertiesFile(sEncPassFileName);
const algorithmString = "algorithm";
const hashString = "hash";
const keyString = "key";
const macString = "mac";
const mackeyString = "mackey";
const matchString = "match";
const paramsString = "params";
const passwordString = "password";
const transformationString = "transformation";
const versionString = "version";
if (mapPassKey[versionString] !== "1") {
console.log("Unrecognized version %s in file %s", mapPassKey[versionString], sPassKeyFileName);
process.exit(1);
}
if (mapEncPass[versionString] !== "1") {
console.log("Unrecognized version %s in file %s", mapPassKey[versionString], sEncPassFileName);
process.exit(1);
}
if (mapPassKey[matchString] !== mapEncPass[matchString]) {
console.log("Match value differs between files %s and %s", sPassKeyFileName, sEncPassFileName);
process.exit(1);
}
const sTransformation = mapPassKey[transformationString];
const sAlgorithm = mapPassKey[algorithmString];
const sKeyHexDigits = mapPassKey[keyString];
const sMACAlgorithm = mapPassKey[macString];
const sMacKeyHexDigits = mapPassKey[mackeyString];
// While params is technically optional, an initialization vector is required by all three block
// cipher modes CBC, CFB, and OFB that are supported by the Teradata SQL Driver for Node.js.
// ECB does not require params, but ECB is not supported by the Teradata SQL Driver for Node.js.
const abyTransformation = Buffer.from(sTransformation, "utf8");
const abyKey = Buffer.from(sKeyHexDigits, "hex");
const abyMacKey = Buffer.from(sMacKeyHexDigits, "hex");
const abyEncryptedPassword = Buffer.from(mapEncPass[passwordString], "hex");
const abyASN1EncodedIV = Buffer.from(mapEncPass[paramsString], "hex"); // required for CBC, CFB, and OFB
// Verify algorithm is part of transformation
const asTransformationParts = sTransformation.split("/");
const sMode = asTransformationParts[1];
if (sAlgorithm !== asTransformationParts[0]) {
console.log("Algorithm differs from transformation in file %s", sPassKeyFileName);
process.exit(1);
}
// Verify the hash value produced from encrypted password/params having the same value as the recorded one.
const abyContentLength = abyEncryptedPassword.length + abyTransformation.length + abyASN1EncodedIV.length;
const abyContent = Buffer.concat([abyEncryptedPassword, abyTransformation, abyASN1EncodedIV], abyContentLength);
const sMac = sMACAlgorithm.slice(4).toLowerCase(); // e.g., slice 'HmacSHA256' to 'SHA256'
const hmac = crypto_.createHmac(sMac, abyMacKey); // Use MAC key
hmac.update(abyContent);
const hashHexDigits = hmac.digest("hex"); // Produce hash value
const sHashHexDigits = mapEncPass[hashString]; // Read the recorded hash value
if (hashHexDigits !== sHashHexDigits) {
console.log("Hash mismatch indicates possible tampering with file %s or %s", sPassKeyFileName, sEncPassFileName);
process.exit(1);
}
// Create decipher and decrypt the encrypted password
// 1. Lookup the Node.js algorithm name
const nKeySizeInBytes = abyKey.length;
const nKeySizeInBits = nKeySizeInBytes * 8;
const nodeAlgorithmName = convertJavaNames(sAlgorithm, nKeySizeInBits, sMode);
// 2. Retrieve the initialization vector value from 'params'
// The params is encoded as octet string in der-format:
// - The first byte is the id tag of the octet string (i.e., 0x04).
// - The second byte is the length of payload (iv).
// - The payload starts at the third byte of the octect string.
const abyIV = abyASN1EncodedIV.slice(2, 2 + abyASN1EncodedIV[1]);
// 3. Create the decipher
const decipher = crypto_.createDecipheriv(nodeAlgorithmName, abyKey, abyIV);
// 4. Decrypt the password
const decrypted = decipher.update(abyEncryptedPassword);
const finalCipher = decipher.final();
const abyPassword = Buffer.concat([decrypted, finalCipher], decrypted.length + finalCipher.length);
// 5. The password was zero-padded before it was encrypted.
// Trim trailing zero byptes to obtain the original password.
const sPassword = abyPassword.slice(0, abyPassword.indexOf("\x00")).toString("utf8");
console.log("Decrypted password: %s", sPassword);
} // decryptPassword
if (process.argv.length !== 10) {
console.log("Parameters: Transformation KeySizeInBits MAC PasswordEncryptionKeyFileName EncryptedPasswordFileName" + " Hostname Username Password");
process.exit(1);
}
const sTransformation = process.argv[2];
const sKeySizeInBits = process.argv[3];
const sMac = process.argv[4];
const sPassKeyFileName = process.argv[5];
const sEncPassFileName = process.argv[6];
const sHostname = process.argv[7];
const sUsername = process.argv[8];
let sPassword = process.argv[9];
const asTransformationParts = sTransformation.split("/");
if (asTransformationParts.length !== 3) {
console.log("Invalid transformation: " + sTransformation);
process.exit(1);
}
const sAlgorithm = asTransformationParts[0];
const sMode = asTransformationParts[1];
const sPadding = asTransformationParts[2];
if ("AES".indexOf(sAlgorithm) < 0) {
console.log("Unknown algorithm " + sAlgorithm);
process.exit(1);
}
if (["CBC", "CFB", "OFB"].indexOf(sMode) < 0) {
console.log("Unknown mode " + sMode);
process.exit(1);
}
if (["PKCS5Padding", "NoPadding"].indexOf(sPadding) < 0) {
console.log("Unknown padding " + sPadding);
process.exit(1);
}
if (["HmacSHA1", "HmacSHA256"].indexOf(sMac) < 0) {
console.log("Unknown MAC algorithm " + sMac);
process.exit(1);
}
if (!sPassword) {
console.log("Password cannot be zero length");
process.exit(1);
}
const nKeySizeInBits = parseInt(sKeySizeInBits, 10);
const match = Date.now().toString();
let nCipherBlockSizeInBytes = 0;
if (sAlgorithm === "AES") {
nCipherBlockSizeInBytes = 16;
}
else {
nCipherBlockSizeInBytes = 8;
}
const encryptKeys = createPasswordEncryptionKeyFile(sTransformation, sAlgorithm, match, sMac, nKeySizeInBits, sPassKeyFileName);
createEncryptedPasswordFile(sTransformation, sAlgorithm, match, sMac, sMode, nKeySizeInBits, encryptKeys[0], encryptKeys[1], sEncPassFileName, nCipherBlockSizeInBytes, sPassword);
decryptPassword(sPassKeyFileName, sEncPassFileName);
sPassword = "ENCRYPTED_PASSWORD(file:" + sPassKeyFileName + ",file:" + sEncPassFileName + ")";
const con = teradatasql.connect({ host: sHostname, user: sUsername, password: sPassword });
try {
const cur = con.cursor();
try {
cur.execute("select user, session");
const row = cur.fetchone();
console.log(row);
}
finally {
cur.close();
}
}
finally {
con.close();
}
//# sourceMappingURL=TJEncryptPassword.js.map