UNPKG

teradatasql

Version:
260 lines 11.5 kB
"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