Skip to content

Instantly share code, notes, and snippets.

@gpotter2
Last active March 6, 2021 18:38
Show Gist options
  • Save gpotter2/2eb1eae1ad18ab51186a71c0c7900ade to your computer and use it in GitHub Desktop.
Save gpotter2/2eb1eae1ad18ab51186a71c0c7900ade to your computer and use it in GitHub Desktop.
Laravel 4 encrypt and decrypt using NodeJS
/*
* A duplicate of Laravel's Crypt::
*
* This is copy/pasted from https://gist.github.com/Agoreddah/511864e2c00da064586523b3087c30e2#file-encrypter-js
* but fixed to work with Laravel == 4
*/
// load dependencies
const Rijndael = require('rijndael-js');
const crypto = require('crypto');
const SETTINGS = {
key : 'fancy key',
sha : 'sha256',
mode : 'cbc'
}
/**
* Caclulate MAC.
* Paylod needs to be decoded to JSON with getJsonPayload(payload)
* @param {Object} payload with iv & value
* @param {String} key
*/
function calculateMac(payload, key){
let hashedData = hash(payload['iv'], payload['value'])
return hashHmac(hashedData, key);
}
/**
* Decrypts payload with master key
* @param {String} Payload - base64 encoded json with iv, value, mac information
*/
function decrypt(payload){
let _payload = getJsonPayload(payload);
let _iv = Buffer.from(_payload['iv'], 'base64');
let _value = Buffer.from(_payload['value'], 'base64');
let decipher = new Rijndael(SETTINGS.key, SETTINGS.mode);
let decrypted = Buffer.from(decipher.decrypt(_value, 256, _iv));
return hashDeserialize(decrypted);
}
/**
* Create payload encrypted with master key.
* Payload contains: iv, value, mac
* @param {String} data to be encrypted
* @return {String} Base64 encdoded payload
*/
function encrypt(data){
let serializedValue = hashSerialize(data);
console.log(serializedValue);
try{
let _iv = crypto.randomBytes(32);
let base64_iv = _iv.toString('base64');
const cipher = new Rijndael(SETTINGS.key, SETTINGS.mode);
let encrypted = Buffer.from(cipher.encrypt(serializedValue, 256, _iv)).toString('base64');
let _mac = hash(base64_iv, encrypted.toString('base64'));
let payloadObject = {
'iv' : base64_iv,
'value' : encrypted,
'mac' : _mac
}
let _payload = JSON.stringify(payloadObject);
base64_payload = Buffer.from(_payload).toString('base64');
return base64_payload;
}
catch(e){
console.log(e);
throw new Error('Cannot encrypt data provided !');
}
}
/**
* Get JSON object from payload.
* Payload needs to be base64 encoded and must contains iv, value, mac attributes.
* MAC is validated
* @param {String} payload
* @return {Object} Data with iv, value, mac
*/
function getJsonPayload(payload){
if(payload === undefined || payload === ''){
throw new Error('Payload MUST NOT be empty !');
}
if(typeof payload !== 'string'){
throw new Error('Payload MUST be string !');
}
try{
var _payload = JSON.parse(Buffer.from(payload, 'base64'));
}
catch(e){
throw new Error('Payload cannot be parsed !');
}
if(!isValidPayload(_payload)){
throw new Error('Payload is not valid !');
}
if(!isValidMac(_payload)){
throw new Error('Mac is not valid !');
}
return _payload;
}
/**
* Hash function.
* Combines initialization vector (iv) with data to be hashed (value).
* Uses master key to hash results
* @param {String} iv Initialization vector
* @param {String} value Data
*/
function hash(iv, value){
if(iv === undefined || iv === ''){
throw new Error('Iv is not defined !');
}
if(value === undefined || value === ''){
throw new Error('Value is not defined !');
}
let data = String(iv) + String(value);
return hashHmac(data, SETTINGS.key);
}
/**
* Crypto function to hash data with given key
* @param {String} data
* @param {String} key
*/
function hashHmac(data, key){
let hmac = crypto.createHmac(SETTINGS.sha, key);
hmac.update(data);
return hmac.digest('hex');
}
/**
* MAC validation function.
* Payload must be decoded to JSON
* @param {Object} payload
*/
function isValidMac(payload){
let bytes = crypto.randomBytes(16),
calculatedMac = calculateMac(payload, bytes);
let originalMac = hashHmac(payload['mac'], bytes);
return originalMac === calculatedMac;
}
/**
* Payload validation function.
* Payload must be decoded to JSON
* @param {Object} payload
*/
function isValidPayload(payload){
return (payload.hasOwnProperty('iv') && payload.hasOwnProperty('value') && payload.hasOwnProperty('mac'));
}
function hashDeserialize(data){
let str = String(data);
return str.substring( str.lastIndexOf(':') + 1, str.lastIndexOf(';') ).replace(/"/g,'');
}
function hashSerialize(data){
if(typeof data !== 'string'){
throw new Error('Data to be serialized must be type of string !');
}
let str = String(data);
return 's:'+str.length+':"'+str+'";';
}
module.exports = {
encrypt,
decrypt,
getJsonPayload,
hash
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment