UNPKG

@am92/kms

Version:
191 lines (190 loc) 7.79 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.NodeKms = void 0; const crypto_1 = __importDefault(require("crypto")); const NodeKmsError_1 = require("./NodeKmsError"); const CONSTANTS_1 = require("./CONSTANTS"); const ERRORS_1 = require("./ERRORS"); /** * Class to execute KMS methods using Node Crypto * * @class */ class NodeKms { /** * Configurations used for Node Crypto */ CONFIG; /** * Creates an instance of NodeKms. * * @constructor * @param config */ constructor(config) { this.CONFIG = validateConfigAndExtend(config); this.generateDataKey = this.generateDataKey.bind(this); this.generateDataKeyPair = this.generateDataKeyPair.bind(this); this.encrypt = this.encrypt.bind(this); this.decrypt = this.decrypt.bind(this); } /** * Generates encryption keys for symmetric encryption algorithm * * @async * @returns */ async generateDataKey() { try { const { KEY_ALGO, KEY_LENGTH, KEY_FORMAT } = this.CONFIG; const options = { length: KEY_LENGTH }; const keyObject = crypto_1.default.generateKeySync(KEY_ALGO, options); const dataKey = keyObject.export().toString(KEY_FORMAT); const encryptOptions = { cipherTextFormat: KEY_FORMAT, plainTextFormat: KEY_FORMAT }; const encryptedDataKey = await this.encrypt(dataKey, encryptOptions); const dataKeyObject = { dataKey, encryptedDataKey }; return dataKeyObject; } catch (error) { const errorCode = `NodeKms::${error.code}`; throw new NodeKmsError_1.NodeKmsError(error, { errorCode }); } } /** * Generates encryption keys for asymmetric encryption algorithm * * @async * @returns */ async generateDataKeyPair() { try { const { KEY_PAIR_ALGO, KEY_PAIR_LENGTH, KEY_FORMAT } = this.CONFIG; const options = { modulusLength: KEY_PAIR_LENGTH }; const keyObjects = crypto_1.default.generateKeyPairSync(KEY_PAIR_ALGO, options); const privateKey = keyObjects.privateKey .export(CONSTANTS_1.PRIVATE_KEY_EXPORT_OPTIONS) .toString(KEY_FORMAT); const publicKey = keyObjects.publicKey .export(CONSTANTS_1.PUBLIC_KEY_EXPORT_OPTIONS) .toString(KEY_FORMAT); const encryptOptions = { cipherTextFormat: KEY_FORMAT, plainTextFormat: KEY_FORMAT }; const encryptedPrivateKey = await this.encrypt(privateKey, encryptOptions); const dataKeyPairObject = { privateKey, publicKey, encryptedPrivateKey }; return dataKeyPairObject; } catch (error) { const errorCode = `NodeKms::${error.code}`; throw new NodeKmsError_1.NodeKmsError(error, { errorCode }); } } /** * Encrypts a given string using AES-256-CBC. The key and IV are as defined in `CONFIG.MASTER_KEY_HEX` and `CONFIG.MASTER_IV_HEX` respectively. * * @async * @param [plainText=''] * @param [options] * @returns */ async encrypt(plainText = '', options) { const { MASTER_KEY_UINT8, MASTER_IV_UINT8, CIPHER_TEXT_FORMAT, PLAIN_TEXT_FORMAT } = this.CONFIG; const { cipherTextFormat = CIPHER_TEXT_FORMAT, plainTextFormat = PLAIN_TEXT_FORMAT } = options || {}; try { const plainTextUint8 = new Uint8Array(Buffer.from(plainText, plainTextFormat)); const encryptor = crypto_1.default.createCipheriv(CONSTANTS_1.ENCRYPTION_ALGO, MASTER_KEY_UINT8, MASTER_IV_UINT8); const encryptedUint8 = new Uint8Array(encryptor.update(plainTextUint8)); const finalEncryptedUint8 = new Uint8Array(encryptor.final()); const cipherTextBuffer = Buffer.concat([ encryptedUint8, finalEncryptedUint8 ]); const cipherText = cipherTextBuffer.toString(cipherTextFormat); return cipherText; } catch (error) { const errorCode = `NodeKms::${error.code}`; throw new NodeKmsError_1.NodeKmsError(error, { errorCode }); } } /** * Decrypts a given string using AES-256-CBC. The key and IV are as defined in `CONFIG.MASTER_KEY_HEX` and `CONFIG.MASTER_IV_HEX` respectively. * * @async * @param [ciphertext=''] * @param [options] * @returns */ async decrypt(ciphertext = '', options) { const { MASTER_KEY_UINT8, MASTER_IV_UINT8, CIPHER_TEXT_FORMAT, PLAIN_TEXT_FORMAT } = this.CONFIG; const { cipherTextFormat = CIPHER_TEXT_FORMAT, plainTextFormat = PLAIN_TEXT_FORMAT } = options || {}; const cipherTextUint8 = new Uint8Array(Buffer.from(ciphertext, cipherTextFormat)); try { const decryptor = crypto_1.default.createDecipheriv(CONSTANTS_1.ENCRYPTION_ALGO, MASTER_KEY_UINT8, MASTER_IV_UINT8); const decryptedUint8 = new Uint8Array(decryptor.update(cipherTextUint8)); const finalDecryptedUint8 = new Uint8Array(decryptor.final()); const plainTextBuffer = Buffer.concat([ decryptedUint8, finalDecryptedUint8 ]); const plainText = plainTextBuffer.toString(plainTextFormat); return plainText; } catch (error) { const errorCode = `NodeKms::${error.code}`; throw new NodeKmsError_1.NodeKmsError(error, { errorCode }); } } } exports.NodeKms = NodeKms; /** @ignore */ function validateConfigAndExtend(config) { const { KEY_SPEC = '', KEY_PAIR_SPEC = '', MASTER_KEY_HEX, MASTER_IV_HEX } = config; if (!MASTER_KEY_HEX) { throw new NodeKmsError_1.NodeKmsError(config, ERRORS_1.INVALID_CONFIG_ERROR); } if (!MASTER_IV_HEX) { throw new NodeKmsError_1.NodeKmsError(config, ERRORS_1.INVALID_CONFIG_ERROR); } if (!CONSTANTS_1.VALID_KEY_SPECS.includes(KEY_SPEC)) { throw new NodeKmsError_1.NodeKmsError({ KEY_SPEC, VALID_KEY_SPECS: CONSTANTS_1.VALID_KEY_SPECS }, ERRORS_1.INVALID_KEY_SPEC_ERROR); } if (!CONSTANTS_1.VALID_KEY_PAIR_SPECS.includes(KEY_PAIR_SPEC)) { throw new NodeKmsError_1.NodeKmsError({ KEY_PAIR_SPEC, VALID_KEY_PAIR_SPECS: CONSTANTS_1.VALID_KEY_PAIR_SPECS }, ERRORS_1.INVALID_KEY_PAIR_SPEC_ERROR); } const keySpecArray = KEY_SPEC.split('_'); const KEY_ALGO = 'aes'; const KEY_LENGTH = parseInt(keySpecArray[1], 10); const keyPairSpecArray = KEY_PAIR_SPEC.split('_'); const KEY_PAIR_ALGO = 'rsa'; const KEY_PAIR_LENGTH = parseInt(keyPairSpecArray[1], 10); const MASTER_KEY_UINT8 = new Uint8Array(Buffer.from(MASTER_KEY_HEX, 'hex')); const MASTER_IV_UINT8 = new Uint8Array(Buffer.from(MASTER_IV_HEX, 'hex')); if (MASTER_KEY_UINT8.length !== CONSTANTS_1.MASTER_KEY_LENGTH) { throw new NodeKmsError_1.NodeKmsError({ MASTER_KEY_HEX }, ERRORS_1.INVALD_MASTER_KEY_HEX_ERROR); } if (MASTER_IV_UINT8.length !== CONSTANTS_1.MASTER_IV_LENGTH) { throw new NodeKmsError_1.NodeKmsError({ MASTER_IV_HEX }, ERRORS_1.INVALID_MASTER_IV_HEX_ERROR); } const extendedConfig = { ...config, KEY_ALGO, KEY_LENGTH, KEY_PAIR_ALGO, KEY_PAIR_LENGTH, MASTER_KEY_UINT8, MASTER_IV_UINT8 }; return extendedConfig; }