I am coding in node.js where i want to use AES/ECB/Pkcs5 for encrypting my string with a particular key. Now i have java code which is given below but as i tried to code the same thing in javascript things became really messy, Firstly i saw a simple solution of using crypto whose code is given below and i tried it but the output i got was different from the one i got from java, then i switched from crypto to Crypto-js which is another library for encryption now i gain tried the same but i again got different output and then finally when i saw plethora of posts where one said to declare iv and the other one to use key and input_string as a buffer and the other one to use chunks to encrypt the data.
Now as you can imagine i have tried for two days straight to code all these possibilities but none of them worked out, now can anyone please enlighten me and tell me which is the right approach or where i am missing something.
Thanks
JAVA CODE
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(1, secretKeySpec);
byte[] aBytes = cipher.doFinal(inputString.getBytes());
BASE64Encoder encoder = new BASE64Encoder();
String base64 = encoder.encode(aBytes).toString();
base64 = URLEncoder.encode(base64, "UTF-8");
return base64;
CRYPTO-JS CODE
var encrypted = CryptoJS.DES.encrypt(input_string, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
var base64 = CryptoJS.enc.Base64.toString(encrypted.ciphertext);
// var base64 = CryptoJS.enc.Base64.stringify(encrypted);
var parsedStr = base64.toString(CryptoJS.enc.Utf8);
console.log('parsedStr: ', parsedStr);
Crypto CODE
var cipher = crypto.createCipher('aes-128-ecb', key);
var crypted = cipher.update(input_string,'utf8','base64')
crypted += cipher.final('base64');
Chunks Implementation
var crypto = require('crypto'),
iv = new Buffer(''),
key = new Buffer('abcgthdbgfhyjhuy', 'hex'),
cipher = cypto.createCipheriv('aes-128-ecb', key, iv),
chunks = [];
chunks.push(cipher.update(
new Buffer(JSON.stringify({key: "abcgthdbgfhyjhuy"}), 'utf8'),
'buffer', 'base64'));
chunks.push(cipher.final('base64'));
var encryptedString = chunks.join('');
console.log('encryptedString: ', encryptedString);
ONE WHERE I USED input_string AND key AS BUFFER
var key = new Buffer(key, "utf8");
var input_string = new Buffer(input_string, "utf8");
IV USAGE
var key = new Buffer(key, "utf8");
var input_string = new Buffer(input_string, "utf8");
var iv = new Buffer(16); // 16 byte buffer with random data
iv.fill(0); // fill with zeros
var cipher = crypto.createCipher('aes-128-ecb', key, iv);
var crypted = cipher.update(input_string,'utf8','base64')
crypted += cipher.final('base64');
Related
I'm a Noob to Java and Javascript. I'm trying to decrypt a Java encrypted text using Javascript, tried with both CryptoJS and node-forge, but the decrypted text I'm getting is gibberish.
Java cipher creation (this works in JAVA where we pass in the ciphermode as Cipher.DECRYPT_MODE and is able to decrypt the line encrypted using the same cipher algo/spec)
Cipher c;
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
SecretKey key = factory.generateSecret(new PBEKeySpec(password.toCharArray(), salt, iterationsCount, bitStrength));
SecretKeySpec keyspec = new SecretKeySpec(key.getEncoded(), "AES");
c = Cipher.getInstance("AES/ECB/PKCS5Padding");
c.init(cipherMode, keyspec);
return c;
Anyone know of a good Js library that I can use or provide some sample of how to decrypt the encrypted line using this Cipher and KeySpec?
Javascript Code
const bufferStr = Buffer.from(encryptedStr, "base64"); //encryptedStr is the encrypted string in base64 format
//generate key using node forge
//password is a String, salt is a hex, numIterations is an int
const AESkey = forge.pkcs5.pbkdf2(password, salt, numIterations, 32);
var decipher = forge.cipher.createDecipher("AES-ECB", AESkey);
decipher.start({});
//console.log(decipher);
decipher.update(forge.util.createBuffer(bufferStr));
var result = decipher.finish(); // check 'result' for true/false
// outputs decrypted hex
console.log(decipher.output);
Output
ByteStringBuffer {
data:
'ÏWʃÓYqŽé\u0017\u0000†\u0018ŸHª3•—²Ì[iòjóÑ8⌂\u0002k\rÒ\r\u0018EvX!ØçQâ!1zåDÉ-<\u0012s)‰²\u001aò=k6<å`r’Ã×lCê)Xq×mÊ¥ ‚Ø\u0000D°l붳È\b>‘`eó¾Î<å\u001c•g|K\\Ù\u0014\u0010#œó\u0019±žk¯þM“‹¾tüzØçBïõîi¸\u0006ÙZ9Jsæ!kµ¸Ã.à-É‹Ï69',
read: 0,
_constructedStringLength: 208 }
Additional Details
On the Java Side
String password = <Password String>;
byte[] salt = { bytes array|| String };
int iterationCount = 65536;
int bitStrength = 256;
encryptedText = <base64 encoded string>'; //this is what I'm trying to decrypt
Node JS Code I'm using to decrypt this (and I'm doing something really wrong :( )
const forge = require('node-forge');
const password = <password as String>;
const salt = new Int8Array(new Buffer(<array of bytes>)); //converting from Java byte[] array
const numIterations = 65536;
const keyPhrase = forge.pkcs5.pbkdf2(password, salt, numIterations, 32, "SHA512");
const encryptedText =
"<base64 encoded String>";
let decipher = forge.cipher.createDecipher("AES-ECB", keyPhrase);
decipher.start({});
decipher.update(forge.util.createBuffer(encryptedText));
let result = decipher.finish(); // check 'result' for true/false
console.log(decipher.output);
//Outputs a ByteStringBuffer
/*ByteStringBuffer {
data:
'ÜB\rÌ9pÞ[\u000e²&øV$²ÝªüÚf\u0000ÀÅmè·èjÉû¤Á|ê¹õIpð\u0012ì\u001cª\f\u000f¦¹ñøÄ\u001b!ëáÕXô\u0007½¦{±\u0012\u001a®}#U6òöÞÊ\u0016n§#gf h£xû\u0016jyÕ5Õ3ÍJ&\n^Eå2õÉ\u000eÑßü!ªÎâÉ\u0010!eÑ.&·à\u0011¬\u0005\u0015/#&\u0019&WàÃK\u000eç8|\'Êb°¸ó¹Ñ\bS\u0004lÑ´<\u0011O½\u0014q?uu$\u001c\b^»',
read: 0,
_constructedStringLength: 192 }*/
I have following code in Java.
String secretString = 'AAABBBCCC'
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom securerandom = SecureRandom.getInstance("SHA1PRNG");
securerandom.setSeed(secretString.getBytes());
kgen.init(256, securerandom);
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Security.addProvider(new BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] byteContent = content.getBytes("utf-8");
byte[] cryptograph = cipher.doFinal(byteContent);
String enc1 = Base64.getEncoder().encodeToString(cryptograph);
return enc1;
I need to implement it in JavaScript/Node.js, however I can only figure out the last half in js like below
'use strict';
const crypto = require('crypto');
const ALGORITHM = 'AES-256-ECB';
const secretString = 'AAABBBCCC'
// missing part in JS (how to convert secretString to key)
function encrypt(plaintext, key) {
const cipher = crypto.createCipheriv(ALGORITHM, key, Buffer.alloc(0));
return cipher.update(plaintext, 'utf8', 'base64') + cipher.final('base64');
}
For the previous Java part( from secretString to key generated by KeyGenerator), I don't know how to implement it in JavaScript, neither do I know whether there is a thing like KeyGenerator in JavaScript world could help me to do the heavy lifting work.
I think this is what you're after:
const crypto = require("crypto-js");
// Encrypt
const ciphertext = crypto.AES.encrypt('SOMETHING SECRET', 'secret key 123');
// Decrypt
const bytes = crypto.AES.decrypt(ciphertext.toString(), 'secret key 123');
const decryptedData = bytes.toString(crypto.enc.Utf8);
console.log(decryptedData);
https://runkit.com/mswilson4040/5b74f914d4998d0012cccdc0
UPDATE
JavaScript does not have a native equivalent for key generation. The answer is to create your own or use a third party module. I would recommend something like uuid for starters.
You can use crypto.randomBytes().
As per its documentation:
Generates cryptographically strong pseudo-random data. The size argument is a number indicating the number of bytes to generate.
Also, it uses openssl's RAND_bytes API behind scenes
I use following code in JS to encrypt my data:
const crypto = require('crypto');
const IV_LENGTH = 16; // For AES, this is always 16
export function encrypt(text, key) {
let iv = crypto.randomBytes(IV_LENGTH);
let cipher = crypto.createCipheriv('aes-256-cbc', new Buffer(key), iv);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return iv.toString('hex') + ':' + encrypted.toString('hex');
}
I have tried to decrypt it in PHP (with pack('H*',.) etc but I can't find a solution to decode it in PHP. All the time I get the error that the IV is to long because I am not able to transform it back in PHP.
Do you have an idea how I can decrypt it in PHP?
Thank you very much and I wish a nice weekend!
I am trying to use RNCryptor-JS which uses SJCL but for some reason, SJCL bit array concatenation does not seem to work.
var SALT_SIZE = 64/8;
var plaintext = "Hello, World!";
var password = "myPassword";
function keyForPassword(password, salt){
// Using CryptoJS for pbkdf2, aes, sha256, and random word arrays
var pbkdf2_key = CryptoJS.PBKDF2(
password,
salt,
{
keySize: 256/32,
iterations: 1000,
hasher: CryptoJS.algo.SHA256
}
);
return pbkdf2_key;
}
var encryption_salt = CryptoJS.lib.WordArray.random(SALT_SIZE);
var encryption_key = keyForPassword(password, encryption_salt);
var hmac_salt = CryptoJS.lib.WordArray.random(SALT_SIZE);
var hmac_key = keyForPassword(password, hmac_salt);
var iv = CryptoJS.lib.WordArray.random(128/8);
var version = sjcl.codec.hex.toBits("03");
var options = sjcl.codec.hex.toBits("01");
var message = sjcl.bitArray.concat(version, iv);
message = sjcl.bitArray.concat(message, encryption_salt);
message = sjcl.bitArray.concat(message, hmac_salt);
message = sjcl.bitArray.concat(message, iv);
// Progressive cipher
var aesEncryptor = CryptoJS.algo.AES.createEncryptor(encryption_key, {iv: iv});
var ciphertext = aesEncryptor.process(plaintext);
message = sjcl.bitArray.concat(message, ciphertext);
var hmac = new sjcl.misc.hmac(hmac_key).encrypt(message);
var encrypted_data = sjcl.bitArray.concat(message, hmac);
var output = sjcl.codec.hex.fromBits(encrypted_data);
console.log(output);
When I log the output of message after the first set of sjcl.bitArray.concat is done, all that returns is the first concatenation of version and iv. The final hex output is just that first concatenation and hmac concatenated. This reinforces my suspicion that it might be CryptoJS's fault because the output concatenation works and is between two sjcl variables.
I tried using SJCL random bit arrays but had some trouble. SJCL's generator, prng, did not work when using
new sjcl.prng.randomWords(32/4);
or
new sjcl.prng(32/4);
And sjcl.random.randomWords does not seem to work anymore.
CryptoJS (WordArray) and SJCL (bitArray) have different internal representations of data. You can't simply concatenate them.
The easiest way would be probably to encode it into an intermediate format such as Hex and let the other side decode into its internal format:
message = sjcl.bitArray.concat(version, sjcl.codec.hex.toBits(iv.toString()));
WordArray#toString() automatically uses Hex encoding. You would have to do this for all lines, but this is a little overkill, since you can concatenate Hex strings as strings:
message = sjcl.codec.hex.toBits("03" + iv + encryption_salt + hmac_salt + iv);
This should work as expected, because adding a WordArray such as iv to a string automatically calls its toString() function which in turn produces a big-endian hex-encoded string.
I wonder why you're using iv twice. Perhaps you meant options on one of them.
What needs to change:
function convert(wordArray){
return sjcl.codec.hex.toBits(wordArray.toString());
}
var message = "0301" + encryption_salt + hmac_salt + iv;
var ciphertext = CryptoJS.AES.encrypt(plaintext, encryption_key, {iv: iv}).ciphertext;
message += ciphertext;
message = sjcl.codec.hex.toBits(message);
var hmac = new sjcl.misc.hmac(convert(hmac_key)).encrypt(message);
var encrypted_data = sjcl.bitArray.concat(message, hmac);
var output = sjcl.codec.hex.fromBits(encrypted_data);
console.log(output);
NOTE: Yes, I understand there is a lot of code in this message, but you do encourage us to show prior research and how we've been trying.
Let me preface this by saying, I am not interested in the security of this function. All I want is to encrypt and decrypt arbitrarily long messages using RSA. Usually to do this, the message is encrypted using a block cipher (such as AES) and encrypting the key with the RSA cipher. However, I am just trying to find the easiest way to encrypt/decrypt long messages, irregardless of security. Hence why I am using RC4 in place of the block cipher.
Now, I can encrypt properly using the following code:
function encryptLong(signedCert, msg) {
var key256Bits = CryptoJS.SHA256("password");
var ciphertext = CryptoJS.RC4.encrypt(msg, key256Bits);
key = new RSAKey();
var m = CryptoJS.SHA256("password").toString(CryptoJS.enc.Hex);
m = new BigInteger(m, 16);
key.setPublic(signedCert.msg.subject.pk.n, signedCert.msg.subject.pk.e);
var ctxt = key.doPublic(m).toString(16);
var cipherstring = ciphertext + ":" + ctxt;
var obj = { "type": "CTXT-LONG", "encrypted": cipherstring };
return JSON.stringify(obj);
}
The message and the key are encrypted properly. I tested them individually using these functions.
function encryptRSA(signedCert, msg) {
//create a new RSA key object
var key = new RSAKey();
//convert ASCII message to hex
var m = asciiToHex(msg);
// create new BigInterger from m
m = new BigInteger(m, 16);
// set the values for the public key
key.setPublic(signedCert.msg.subject.pk.n, signedCert.msg.subject.pk.e);
// compute the RSA public key operation, and convert to a hex value
var ctxt = key.doPublic(m).toString(16);
//enter ctxt into the JSON obj
var obj = { "type": "CTXT-SHORT", "c": ctxt };
return JSON.stringify(obj);
}
And...
function encryptRSA(password, message) {
var key256Bits = CryptoJS.SHA256(password);
var ciphertext = CryptoJS.RC4.encrypt(CryptoJS.enc.Utf8.parse(message), key256Bits);
return ciphertext;
}
Now, here is our decryption code:
function decryptLong(sk, ctxt) {
key = new RSAKey();
encryptedStuff = JSON.stringify(ctxt.encrypted);
log(encryptedStuff);
splitEncryptedstuff = encryptedStuff.split(":");
rsaencryption = splitEncryptedstuff[1];
log(rsaencryption);
rc4encryption = splitEncryptedstuff[0];
log(rc4encryption);
c = new BigInteger(rsaencryption, 16);
key.setPrivate(sk.n, sk.e, sk.d);
var key256Bits = key.doPrivate(c).toString(16);
log(key256Bits);
// RC4 decryption
var message = CryptoJS.RC4.decrypt(rc4encryption, key224Bits);
// var ptxt = CryptoJS.enc.Utf8.stringify(message);
// log(ptxt);
return CryptoJS.enc.Utf8.stringify(message);
}
This code doesn't decrypt properly, but I know parts of it work. For example, where I have
log(key356Bits);
it returns the key exactly. So I know that at least the RSA decryption works. What I don't understand is, I followed the decryption function that I have exactly. Which is as follows.
function decryptRC4(password, ciphertext) {
var key256Bits = CryptoJS.SHA256(password);
var message = CryptoJS.RC4.decrypt(ciphertext, key256Bits);
return CryptoJS.enc.Utf8.stringify(message);
}
Well not exactly, I don't have to take the Hash of the password to get the key, as I already have the key. But, I still don't understand what is not working. When we decrypt our ciphertext using this individual function, the plaintext is correct.
Any assistance in this matter would be greatly appreciated.
Knowing my luck, it's probably just something annoying like it's in the wrong encoding type thing.