Reference Source

js/utils/encrypt_decrypt.js

// NPM IMPORTS
import assert from 'assert'

// COMMON IMPORTS
import T from '../utils/types'
import {is_browser} from './is_browser'

let  forge = undefined
if ( is_browser() )
{
	forge = require('forge-browser').forge
} else {
	forge = require('node-forge')
}


const context = 'common/utils/encrypt_decrypt'



/**
 * @file EncryptDecrypt class.
 * 
 * @author Luc BORIES
 * 
 * @license Apache-2.0
 */
export default class EncryptDecrypt
{
    /**
     * Create a EncryptDecrypt instance.
	 * 
	 * 	API:
	 * 		->hash():string - 
	 * 
     * @returns {nothing}
     */
	constructor()
	{
	}



	/**
	 * Generate an encryption key from a secret.
	 * 
	 * @param {string} arg_app_secret - application cryptographic secret.
	 * @param {number} arg_num_iterations - iterations count.
	 * @param {number} arg_key_length - key length.
	 * @param {number} arg_iv_length - iv length.
	 * 
	 * @returns {string} - encrypted string.
	 */
	static key(arg_app_secret, arg_num_iterations=10, arg_key_length=32)
	{
		assert( T.isString(arg_app_secret) && arg_app_secret.length > 0, context + ':encrypt:bad secret string')
		assert( T.isNumber(arg_num_iterations) && arg_num_iterations > 3, context + ':encrypt:bad key length')
		assert( T.isNumber(arg_key_length) && arg_key_length > 15, context + ':encrypt:bad key length')

		const salt = forge.random.getBytesSync(128)

		return forge.pkcs5.pbkdf2(arg_app_secret, salt, arg_num_iterations, arg_key_length)
	}



	/**
	 * Transform to a string with encryption.
	 * 
	 * @param {string} arg_string - string to encrypt.
	 * @param {string} arg_key - encryotion key.
	 * @param {string} arg_mode - cryptographic mode AES-ECB,AES-CBC,AES-CFB,AES-OFB,AES-CTR,AES-GCM,3DES-ECB,3DES-CBC,DES-ECB,DES-CBC.
	 * @param {number} arg_iv_length - iv length.
	 * 
	 * @returns {string} - encrypted string.
	 */
	static encrypt(arg_string, arg_key, arg_mode='AES-ECB', arg_iv_length=8)
	{
		assert( T.isString(arg_string) && arg_string.length > 0, context + ':encrypt:bad input string')
		assert( T.isNumber(arg_iv_length)  && arg_iv_length > 7, context + ':encrypt:bad iv length')

		const iv = forge.random.getBytesSync(arg_iv_length)

		const buffer = forge.util.createBuffer(arg_string)
		const cipher = forge.cipher.createCipher(arg_mode, arg_key)
		cipher.start({iv: iv})
		cipher.update(buffer)
		cipher.finish()
		const encrypted = cipher.output

		return encrypted.toHex()
	}



	/**
	 * Transform to a string without encryption.
	 * 
	 * @param {string} arg_string - encrypted string.
	 * @param {string} arg_key - encryption key.
	 * @param {string} arg_mode - cryptographic mode AES-ECB,AES-CBC,AES-CFB,AES-OFB,AES-CTR,AES-GCM,3DES-ECB,3DES-CBC,DES-ECB,DES-CBC.
	 * @param {number} arg_iv_length - iv length.
	 * 
	 * @returns {string} - decrypted string.
	 */
	static decrypt(arg_string, arg_key, arg_mode='AES-ECB', arg_iv_length=8)
	{
		assert( T.isString(arg_string) && arg_string.length > 0, context + ':encrypt:bad encrypted string')
		assert( T.isString(arg_mode)   && arg_mode.length > 0, context + ':encrypt:bad mode string')
		assert( T.isString(arg_key)   && arg_mode.length > 0, context + ':encrypt:bad key string')
		assert( T.isNumber(arg_iv_length)  && arg_iv_length > 7, context + ':encrypt:bad iv length')

		const iv = forge.random.getBytesSync(arg_iv_length)

		const buffer = forge.util.createBuffer(arg_string)
		const decipher = forge.cipher.createDecipher(arg_mode, arg_key)
		decipher.start({iv: iv})
		decipher.update(buffer)
		decipher.finish()
		const decrypted = decipher.output

		return decrypted.toHex()
	}
}