Encrypting Data with Ruby Decrypting with Node

Encrypting data with ruby decrypting with node

OK. I want to thank everyone for helping me out. Basically this thread here answers my question: https://github.com/joyent/node/issues/1395. I am going to go ahead and post the two programs in case anyone else has to go through this rigamarole. Keep in mind this isn't mean to be hardcore secure, this is a stepping stone for ruby encrypting data and node decrypting it. You will have to take more steps to make sure higher security measures are taken.

The code is located at this gist: https://gist.github.com/799d6021890f34734470

These were run on ruby 1.9.2p290 and node 0.4.10

Reading Ruby Active Record Encryption from a Node Script

The NodeJS code returns the same results as the Ruby code if

  • no key derivation (SHA256) is used
  • for the ciphertext a Base64 encoding is applied instead of a hex encoding

Full NodeJS code:

var crypto = require('crypto');

const algorithm = 'aes-256-gcm';

function encrypt(secret, originalData) {
console.log('encrypting with ', {
secret,
originalData
});
const iv = Buffer.from('377YrtFzBASSjvol', 'base64'); // crypto.randomBytes(16); // disabled for testing (in the final solution a random nonce MUST be applied for security reasons)
var crypt = crypto.createCipheriv(algorithm, Buffer.from(secret, 'base64'), iv);

var encoded = crypt.update(originalData, 'utf8', 'base64'); // Fix: Base64 encoding
encoded += crypt.final('base64'); // Fix: Base64 encoding
const at = crypt.getAuthTag();
return { encrypted: encoded, iv: iv.toString('base64'), at: at.toString('base64') };
};
function decrypt(secret, encryptedData, iv, at) {
console.log('decrypting with ', {
secret,
encryptedData,
iv,
at
});
var crypt = crypto.createDecipheriv(algorithm, Buffer.from(secret, 'base64'), Buffer.from(iv, 'base64'));
crypt.setAuthTag(Buffer.from(at, 'base64'));
var decoded = crypt.update(encryptedData, 'base64', 'utf8'); // Fix: Base64 encoding
decoded += crypt.final('utf8');
return decoded;
};

var originalData = 'This is some debug text';
var secret = 'eKAyTQoTH0apq8+fsQYHSYelUy3mL34gl2M+rnvpXhs='; // Fix: No key derivation
const encryptionResult = encrypt(
secret,
originalData,
);

console.log(encryptionResult);
var secret = 'eKAyTQoTH0apq8+fsQYHSYelUy3mL34gl2M+rnvpXhs='; // Fix: No key derivation
var encryptedData = 'LtbIG7tnBVtbMUlnvG+qtmoK2NgL+18=';
var iv = '377YrtFzBASSjvol';
var at = 'QqQcyOhGKPP0sPFOANToFw==';
const decryptionResult = decrypt(
secret,
encryptedData,
iv,
at
);
console.log(decryptionResult);

Output:

encrypting with  {
secret: 'eKAyTQoTH0apq8+fsQYHSYelUy3mL34gl2M+rnvpXhs=',
originalData: 'This is some debug text'
}
{
encrypted: 'LtbIG7tnBVtbMUlnvG+qtmoK2NgL+18=',
iv: '377YrtFzBASSjvol',
at: 'QqQcyOhGKPP0sPFOANToFw=='
}
decrypting with {
secret: 'eKAyTQoTH0apq8+fsQYHSYelUy3mL34gl2M+rnvpXhs=',
encryptedData: 'LtbIG7tnBVtbMUlnvG+qtmoK2NgL+18=',
iv: '377YrtFzBASSjvol',
at: 'QqQcyOhGKPP0sPFOANToFw=='
}
This is some debug text

how to encode and decode a json array to base64 in ruby

So the following should work for you: (I used the structure from the comment rather than the Post)

JS:

var obj = [{"edmc":"78787041","house_no":"987654234","type":"0","abc_type":"AABB","bbcname":"Unknown","abc_nick_name":"notKnown", "allot":"1.00", "hhic":"BAC1235","address1":"abcdw","city":"abcde", "state":"UU", "pincode":"123456", "email":"anccss@gmail.com","phone":"1234567898"}]; 
btoa(JSON.stringify(obj));

Results in:

W3siZWRtYyI6Ijc4Nzg3MDQxIiwiaG91c2Vfbm8iOiI5ODc2NTQyMzQiLCJ0eXBlIjoiMCIsImFiY190eXBlIjoiQUFCQiIsImJiY25hbWUiOiJVbmtub3duIiwiYWJjX25pY2tfbmFtZSI6Im5vdEtub3duIiwiYWxsb3QiOiIxLjAwIiwiaGhpYyI6IkJBQzEyMzUiLCJhZGRyZXNzMSI6ImFiY2R3IiwiY2l0eSI6ImFiY2RlIiwic3RhdGUiOiJVVSIsInBpbmNvZGUiOiIxMjM0NTYiLCJlbWFpbCI6ImFuY2Nzc0BnbWFpbC5jb20iLCJwaG9uZSI6IjEyMzQ1Njc4OTgifV0=

Ruby

obj = [{"edmc":"78787041","house_no":"987654234","type":"0","abc_type":"AABB","bbcname":"Unknown","abc_nick_name":"notKnown", "allot":"1.00", "hhic":"BAC1235","address1":"abcdw","city":"abcde", "state":"UU", "pincode":"123456", "email":"anccss@gmail.com","phone":"1234567898"}]
Base64.strict_encode64(obj.to_json)

Results in

W3siZWRtYyI6Ijc4Nzg3MDQxIiwiaG91c2Vfbm8iOiI5ODc2NTQyMzQiLCJ0eXBlIjoiMCIsImFiY190eXBlIjoiQUFCQiIsImJiY25hbWUiOiJVbmtub3duIiwiYWJjX25pY2tfbmFtZSI6Im5vdEtub3duIiwiYWxsb3QiOiIxLjAwIiwiaGhpYyI6IkJBQzEyMzUiLCJhZGRyZXNzMSI6ImFiY2R3IiwiY2l0eSI6ImFiY2RlIiwic3RhdGUiOiJVVSIsInBpbmNvZGUiOiIxMjM0NTYiLCJlbWFpbCI6ImFuY2Nzc0BnbWFpbC5jb20iLCJwaG9uZSI6IjEyMzQ1Njc4OTgifV0=

AES-256-CBC with Digest from Ruby to NodeJS

The critical missing piece is the IV, which is required when encryption/decryption is to be made across language boundaries as apparently the encrypter will generate a random IV (or something like that - still don't understand how Ruby decrypts the string without an IV.... but then what do I know....), if one is not provided.

The following snippets show how to encrypt a string in Ruby and decrypt in NodeJS.

#!/usr/bin/env ruby

require 'openssl'
require 'base64'
require 'openssl/cipher'
require 'openssl/digest'

aes = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
aes.encrypt
aes.key = Digest::SHA256.digest('IHazSekretKey')
aes.iv = '1234567890123456'

p Base64.encode64( aes.update('text to be encrypted') << aes.final )

The above prints: "eiLbdhFSFrDqvUJmjbUgwD8REjBRoRWWwHHImmMLNZA=\n"

#!/usr/bin/env node

var crypto = require('crypto');

function decrypto(toDecryptStr) {
var result,
encoded = new Buffer(toDecryptStr, 'base64'),
decodeKey = crypto.createHash('sha256').update('IHazSekretKey', 'ascii').digest(),
decipher = crypto.createDecipheriv('aes-256-cbc', decodeKey, '1234567890123456');

result = decipher.update(encoded);
result += decipher.final();

return result;
}

console.log(decrypto('eiLbdhFSFrDqvUJmjbUgwD8REjBRoRWWwHHImmMLNZA=\n'))

The JS script now properly decrypts the string.

One unfortunate side effect is that existing encrypted data will need to be decrypted and then re-encrypted with an IV that is then used in the decrypting implementation.

A PITA but nonetheless a working solution.

How to properly encode strings so to decrypt with CryptoJs in NodeJS?

  • You are using the wrong encoders for data, key and IV. All three are Base64 encoded (and not hex or Utf8). So apply the Base64 encoder.
  • The ciphertext must be passed to CryptoJS.AES.decrypt() as a CipherParams object or alternatively Base64 encoded, which is implicitly converted to a CipherParams object.

When both are fixed, the plain text is: "[\"001\",\"001\"]".

var symmetricKey =  "bDKJVr5wFtQZaPrs4ZoMkP2RjtaYpXo5HHKbzrNELs8="
var symmetricNonce = "Z8q66bFkbEqQiVbrUrts+A=="
var dataToReceive = "hX/BFO7b+6eYV1zt3+hu3o5g61PFB4V3myyU8tI3W7I="

var decrypted = CryptoJS.AES.decrypt(
dataToReceive, // pass Base64 encoded
//{ciphertext: CryptoJS.enc.Base64.parse(dataToReceive)}, // pass as CipherParams object, works also
CryptoJS.enc.Base64.parse(symmetricKey),
{iv: CryptoJS.enc.Base64.parse(symmetricNonce)}
);

console.log(decrypted.toString(CryptoJS.enc.Utf8));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>


Related Topics



Leave a reply



Submit