/**
* Module for some common utility functions that needs to be separated from {@link module:api/utils/common} either due to circular references or other reasons
* @module api/utils/utils
*/
var crypto = require('crypto'),
countlyConfig = require('./../config', 'dont-enclose');
if (!countlyConfig.encryption) {
countlyConfig.encryption = {};
}
/**
* Encrypt provided value
* @param {string} text - value to encrypt
* @param {string=} key - key used for encryption and decryption
* @param {string=} iv - initialization vector to make encryption more secure
* @param {string=} algorithm - name of the algorithm to use for encryption. The algorithm is dependent on OpenSSL, examples are 'aes192', etc. On recent OpenSSL releases, openssl list-cipher-algorithms will display the available cipher algorithms. Default value is aes-256-cbc
* @param {string=} input_encoding - how encryption input is encoded. Used as output for decrypting. Default utf-8.
* @param {string=} output_encoding - how encryption output is encoded. Used as input for decrypting. Default hex.
* @returns {string} encrypted value
*/
exports.encrypt = function(text, key, iv, algorithm, input_encoding, output_encoding) {
var cipher, crypted;
if (typeof key === "undefined") {
key = countlyConfig.encryption.key || "dpYheF85";
}
//pad or shrink to 32 bytes
key = Buffer.concat([Buffer.from(key), Buffer.alloc(32)], 32);
if (typeof iv === "undefined") {
iv = crypto.randomBytes(16);
}
if (typeof algorithm === "undefined") {
//The algorithm is dependent on OpenSSL, examples are 'aes192', etc.
//On recent OpenSSL releases, openssl list-cipher-algorithms will display the available cipher algorithms.
algorithm = countlyConfig.encryption.algorithm || "aes-256-cbc";
}
if (typeof input_encoding === "undefined") {
input_encoding = countlyConfig.encryption.input_encoding || "utf-8";
}
if (typeof output_encoding === "undefined") {
output_encoding = countlyConfig.encryption.output_encoding || "hex";
}
cipher = crypto.createCipheriv(algorithm, key, iv);
crypted = cipher.update(text, input_encoding, output_encoding);
crypted += cipher.final(output_encoding);
return iv.toString('hex') + ':' + crypted + "[CLY]_true";
};
/**
* Decrypt provided value
* @param {string} crypted - value to decrypt
* @param {string=} key - key used for encryption and decryption
* @param {string=} iv - initialization vector used in encryption
* @param {string=} algorithm - name of the algorithm used in encryption. The algorithm is dependent on OpenSSL, examples are 'aes192', etc. On recent OpenSSL releases, openssl list-cipher-algorithms will display the available cipher algorithms. Default value is aes-256-cbc
* @param {string=} input_encoding - how decryption input is encoded. Default hex.
* @param {string=} output_encoding - how decryption output is encoded. Default utf-8.
* @returns {string} decrypted value
*/
exports.decrypt = function(crypted, key, iv, algorithm, input_encoding, output_encoding) {
if (!crypted || !crypted.length || typeof crypted !== "string") {
return crypted;
}
if (crypted.indexOf(":") === -1) {
return this.decrypt_old(crypted, key, iv, algorithm, input_encoding, output_encoding);
}
if (crypted.lastIndexOf("[CLY]_true") === -1 || crypted.lastIndexOf("[CLY]_true") !== crypted.length - 10) {
return crypted;
}
else {
crypted = crypted.substring(0, crypted.length - 10);
}
var parts = crypted.split(':');
var ivPart = Buffer.from(parts.shift(), 'hex');
var encryptedText = Buffer.from(parts.join(':'), 'hex');
var decipher, decrypted;
if (typeof key === "undefined") {
key = countlyConfig.encryption.key || "dpYheF85";
}
//pad or shrink to 32 bytes
key = Buffer.concat([Buffer.from(key), Buffer.alloc(32)], 32);
if (typeof iv === "undefined") {
iv = countlyConfig.encryption.iv || ivPart;
}
if (typeof algorithm === "undefined") {
//The algorithm is dependent on OpenSSL, examples are 'aes192', etc.
//On recent OpenSSL releases, openssl list-cipher-algorithms will display the available cipher algorithms.
algorithm = countlyConfig.encryption.algorithm || "aes-256-cbc";
}
if (typeof input_encoding === "undefined") {
input_encoding = countlyConfig.encryption.output_encoding || "hex";
}
if (typeof output_encoding === "undefined") {
output_encoding = countlyConfig.encryption.input_encoding || "utf-8";
}
decipher = crypto.createDecipheriv(algorithm, key, iv);
decrypted = decipher.update(encryptedText, input_encoding, output_encoding);
decrypted += decipher.final(output_encoding);
return decrypted;
};
/**
* Old deprecated decrypt function, needed for old stored values
* @param {string} crypted - value to decrypt
* @param {string=} key - key used for encryption and decryption
* @param {string=} iv - initialization vector used in encryption
* @param {string=} algorithm - name of the algorithm used in encryption. The algorithm is dependent on OpenSSL, examples are 'aes192', etc. On recent OpenSSL releases, openssl list-cipher-algorithms will display the available cipher algorithms. Default value is aes-256-cbc
* @param {string=} input_encoding - how decryption input is encoded. Default hex.
* @param {string=} output_encoding - how decryption output is encoded. Default utf-8.
* @returns {string} decrypted value
*/
exports.decrypt_old = function(crypted, key, iv, algorithm, input_encoding, output_encoding) {
if (!crypted || !crypted.length || typeof crypted !== "string") {
return crypted;
}
if (crypted.lastIndexOf("[CLY]_true") === -1 || crypted.lastIndexOf("[CLY]_true") !== crypted.length - 10) {
return crypted;
}
else {
crypted = crypted.substring(0, crypted.length - 10);
}
var decipher, decrypted;
if (typeof key === "undefined") {
key = countlyConfig.encryption.key || "dpYheF85";
}
if (typeof iv === "undefined") {
iv = countlyConfig.encryption.iv;
}
if (typeof algorithm === "undefined") {
//The algorithm is dependent on OpenSSL, examples are 'aes192', etc.
//On recent OpenSSL releases, openssl list-cipher-algorithms will display the available cipher algorithms.
algorithm = countlyConfig.encryption.algorithm || "aes-256-cbc";
}
if (typeof input_encoding === "undefined") {
input_encoding = countlyConfig.encryption.output_encoding || "hex";
}
if (typeof output_encoding === "undefined") {
output_encoding = countlyConfig.encryption.input_encoding || "utf-8";
}
if (iv) {
decipher = crypto.createDecipheriv(algorithm, key, iv);
}
else {
decipher = crypto.createDecipher(algorithm, key);
}
decrypted = decipher.update(crypted, input_encoding, output_encoding);
decrypted += decipher.final(output_encoding);
return decrypted;
};