teradatasql
Version:
Teradata SQL Driver for Node.js
260 lines • 11.5 kB
JavaScript
"use strict";
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 });
const teradatasql = __importStar(require("teradatasql"));
const fs = __importStar(require("fs"));
const crypto_ = __importStar(require("crypto"));
function convertJavaNames(sName, nKeySizeInBits = 0, sMode = "") {
if (sName === "AES") {
sName = "aes-" + nKeySizeInBits.toString() + "-" + sMode.toLowerCase();
}
return sName;
}
function createPasswordEncryptionKeyFile(sTransformation, sAlgorithm, sMatch, sMac, nKeySizeInBits, sPassKeyFileName) {
const nKeySizeInBytes = nKeySizeInBits / 8;
const abyKey = crypto_.randomBytes(nKeySizeInBytes);
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" });
return [abyKey, abyMacKey];
}
function createEncryptedPasswordFile(sTransformation, sAlgorithm, sMatch, sMac, sMode, nKeySizeInBits, abyKey, abyMacKey, sEncPassFileName, nCipherBlockSizeInBytes, sPassword) {
let abyPassword = Buffer.from(sPassword, "utf8");
const abyIV = crypto_.randomBytes(nCipherBlockSizeInBytes);
const octetStringTag = 0x04;
let abyASN1EncodedIV = Buffer.allocUnsafe(2);
abyASN1EncodedIV[0] = octetStringTag;
abyASN1EncodedIV[1] = abyIV.length;
abyASN1EncodedIV = Buffer.concat([abyASN1EncodedIV, abyIV], abyASN1EncodedIV.length + abyIV.length);
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);
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);
const sEncryptedPasswordHexDigits = abyEncryptedPassword.toString("hex");
const sASN1EncodedIVHexDigits = abyASN1EncodedIV.toString("hex");
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();
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" });
}
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;
}
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];
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");
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);
}
const abyContentLength = abyEncryptedPassword.length + abyTransformation.length + abyASN1EncodedIV.length;
const abyContent = Buffer.concat([abyEncryptedPassword, abyTransformation, abyASN1EncodedIV], abyContentLength);
const sMac = sMACAlgorithm.slice(4).toLowerCase();
const hmac = crypto_.createHmac(sMac, abyMacKey);
hmac.update(abyContent);
const hashHexDigits = hmac.digest("hex");
const sHashHexDigits = mapEncPass[hashString];
if (hashHexDigits !== sHashHexDigits) {
console.log("Hash mismatch indicates possible tampering with file %s or %s", sPassKeyFileName, sEncPassFileName);
process.exit(1);
}
const nKeySizeInBytes = abyKey.length;
const nKeySizeInBits = nKeySizeInBytes * 8;
const nodeAlgorithmName = convertJavaNames(sAlgorithm, nKeySizeInBits, sMode);
const abyIV = abyASN1EncodedIV.slice(2, 2 + abyASN1EncodedIV[1]);
const decipher = crypto_.createDecipheriv(nodeAlgorithmName, abyKey, abyIV);
const decrypted = decipher.update(abyEncryptedPassword);
const finalCipher = decipher.final();
const abyPassword = Buffer.concat([decrypted, finalCipher], decrypted.length + finalCipher.length);
const sPassword = abyPassword.slice(0, abyPassword.indexOf("\x00")).toString("utf8");
console.log("Decrypted password: %s", sPassword);
}
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