Say I need to get the SHA-256 hash of 0xF0FD93 as a hex value not a string.
var SHA256 = require('crypto-js/sha256');
hash = SHA256(0xF0FD93);
console.log(hash.toString()); //4ea5c508a6566e76240543f8feb06fd457777be39549c4016436afda65d2330e
I should get a2ad9b3ba41abb6e4e4cafa6467efe65f58f0fb9a01b0f96c6548188ded27356 according to this http://extranet.cryptomathic.com/hashcalc/index.
edit I solved it:
var CryptoJS = require('crypto-js')
var message = CryptoJS.enc.Hex.parse('F0FD93');
var hash = CryptoJS.SHA256(message);
console.log(hash.toString()); // a2ad9b3ba41abb6e4e4cafa6467efe65f58f0fb9a01b0f96c6548188ded27356
var wrongMessage = ('F0FD93');
var wrongHash = CryptoJS.SHA256(wrongMessage);
console.log(wrongHash.toString()); //c55b21323979adf4f963998e272827739a86ddeb8afc85b4e5dea3cdef7274be
Related
I use some remote api, they use such C# code:
SHA256Managed sha256Managed = new SHA256Managed();
byte[] passwordSaltBytes = Encoding.Unicode.GetBytes("zda");
byte[] hash = sha256Managed.ComputeHash(passwordSaltBytes);
string result = Convert.ToBase64String(hash);
Console.WriteLine("result = " + result); // result = NUbWRkT8QfzmDt/2kWaikNOZUXIDt7KKRghv0rTGIp4=
I need to get the same result in my javascript frontend code. Does somebody can help with such problem?
The answer is:
var utf8arr = CryptoJS.enc.Utf16LE.parse("zda");
var hash = CryptoJS.SHA256(utf8arr);
var base64 = CryptoJS.enc.Base64.stringify(hash);
console.log(base64);
Not quite obvious, but Unicode in C# is using UTF-16LE enconding.
So you can use CryptoJS to achieve the same result:
var utf16 = CryptoJS.enc.Utf16LE.parse("zda");
var hash = CryptoJS.SHA256(utf16);
var base64 = CryptoJS.enc.Base64.stringify(hash);
console.log(base64);
So I have a piece of code which encrypts a string with a passphrase. It uses the CryptoJS AES encrypt function (CryptoJS.AES.encrypt) and looks like this...
CryptoJS.AES.encrypt(data, password).toString();
Going forward, I don't want to be using CryptoJS, as it's officially deprecated/not maintained, and I would instead like to use Forge.js. I've attempted to read through the Forge.js docs on GitHub to find a solution, but haven't been able to find anything which uses passphrases instead of manually creating the key & IV.
I've taken a look at the CryptoJS archive at https://code.google.com/archive/p/crypto-js/ and it seems that if the encrypt function is passed a string as the second argument (key) it's used as a passphrase to derive a key and IV. But it doesn't detail how it does this.
It seems that base64 decoding the result gives a string that starts with Salted__ then a comma and then the encrypted blob of binary text, and I'm unsure even how I would pass the "salt" through to Forge.
How would I go about decrypting this blob of data using Forge.js only?
CryptoJS supports OpenSSL's EVP_BytesToKey function, which derives a key and IV from a freshly generated salt and password with one round of MD5. There is an example on the forge documentation page:
Using forge in node.js to match openssl's "enc" command line tool
(Note: OpenSSL "enc" uses a non-standard file format with a custom key
derivation function and a fixed iteration count of 1, which some
consider less secure than alternatives such as OpenPGP/GnuPG):
var forge = require('node-forge');
var fs = require('fs');
// openssl enc -des3 -in input.txt -out input.enc
function encrypt(password) {
var input = fs.readFileSync('input.txt', {encoding: 'binary'});
// 3DES key and IV sizes
var keySize = 24;
var ivSize = 8;
// get derived bytes
// Notes:
// 1. If using an alternative hash (eg: "-md sha1") pass
// "forge.md.sha1.create()" as the final parameter.
// 2. If using "-nosalt", set salt to null.
var salt = forge.random.getBytesSync(8);
// var md = forge.md.sha1.create(); // "-md sha1"
var derivedBytes = forge.pbe.opensslDeriveBytes(
password, salt, keySize + ivSize/*, md*/);
var buffer = forge.util.createBuffer(derivedBytes);
var key = buffer.getBytes(keySize);
var iv = buffer.getBytes(ivSize);
var cipher = forge.cipher.createCipher('3DES-CBC', key);
cipher.start({iv: iv});
cipher.update(forge.util.createBuffer(input, 'binary'));
cipher.finish();
var output = forge.util.createBuffer();
// if using a salt, prepend this to the output:
if(salt !== null) {
output.putBytes('Salted__'); // (add to match openssl tool output)
output.putBytes(salt);
}
output.putBuffer(cipher.output);
fs.writeFileSync('input.enc', output.getBytes(), {encoding: 'binary'});
}
// openssl enc -d -des3 -in input.enc -out input.dec.txt
function decrypt(password) {
var input = fs.readFileSync('input.enc', {encoding: 'binary'});
// parse salt from input
input = forge.util.createBuffer(input, 'binary');
// skip "Salted__" (if known to be present)
input.getBytes('Salted__'.length);
// read 8-byte salt
var salt = input.getBytes(8);
// Note: if using "-nosalt", skip above parsing and use
// var salt = null;
// 3DES key and IV sizes
var keySize = 24;
var ivSize = 8;
var derivedBytes = forge.pbe.opensslDeriveBytes(
password, salt, keySize + ivSize);
var buffer = forge.util.createBuffer(derivedBytes);
var key = buffer.getBytes(keySize);
var iv = buffer.getBytes(ivSize);
var decipher = forge.cipher.createDecipher('3DES-CBC', key);
decipher.start({iv: iv});
decipher.update(input);
var result = decipher.finish(); // check 'result' for true/false
fs.writeFileSync(
'input.dec.txt', decipher.output.getBytes(), {encoding: 'binary'});
}
This example is shown for Triple DES, but it works in the same way for AES. You just have to change the ivSize to 16.
My code
I'm encrypting a string with two different keys with CryptoJS:
var password = "testpassword";
var serverkey = "randomkey";
var text = document.getElementById("new_note").value;
var encrypted1 = CryptoJS.AES.encrypt(text, password);
encrypted1 = encrypted1.toString();
var encrypted = CryptoJS.AES.encrypt(encrypted1,serverkey);
And trying to decrypt it with this code:
var password = "testpassword";
var serverkey = "randomkey";
var encrypted_text = localStorage.getItem("encrypted");
var decrypted1 = CryptoJS.AES.decrypt(encrypted_text,serverkey);
decrypted1 = decrypted.toString();
var decrypted = CryptoJS.AES.decrypt(decrypted1,password);
decrypted = decrypted.toString(CryptoJS.enc.Utf8);
document.getElementById("decrypted").innerHTML = decrypted;
What isn't working
While the encryption seems to work fine, when I try to convert decrypted1 to a string in order to decrypt it the second time, I get Cannot read property 'toString' of undefined on the chrome console. This should mean that the first decryption process returns an empty string.
My question
How can I fix this problem?
There is a typo in your variable names. Check where you define decrypted and where you use it. You meant to use decrypted1.
Additionally, you have a problem with the encoding. The first decrypted1.toString(); will encode the string into Hex, but earlier you called encrypted1.toString(); which does not encode to Hex, but a special Base64 encoding (OpenSSL compatible). You will need to encode to UTF-8 in order to get to the same encoding that you had before during encryption.
Here is the working code:
document.getElementById("enc_button").onclick = function(){
var password = "testpassword";
var serverkey = "randomkey";
var text = document.getElementById("new_note").value;
var encrypted1 = CryptoJS.AES.encrypt(text, password);
encrypted1 = encrypted1.toString();
var encrypted = CryptoJS.AES.encrypt(encrypted1, serverkey);
var decrypted1 = CryptoJS.AES.decrypt(encrypted,serverkey);
decrypted1 = decrypted1.toString(CryptoJS.enc.Utf8);
var decrypted = CryptoJS.AES.decrypt(decrypted1,password);
decrypted = decrypted.toString(CryptoJS.enc.Utf8);
document.getElementById("decrypted").innerHTML = decrypted;
}
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
<div id="decrypted">Please wait...</div>
<div>
Insert new note:
<input type="text" id="new_note">
<input type="button" id="enc_button" value="Encrypt & Decrypt">
</div>
It looks like decripted IS empty.
you have initialized decripted1
var decrypted1 = CryptoJS.AES.decrypt(encrypted_text,serverkey);
and then tryed to "toString()" the uninitialized decrypted var
decrypted1 = decrypted.toString();
Although I think you don't need this line... (?).
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);
I have some troubles with a simple crypto-challenge.
I want to do following:
getting a url-encoded and base64-encoded value
do url-decoding
do base64-decoding
hash with Sha512
When working with CryptoJS, i use following code:
var parameter = "Akuwnm2318kwioasdjlnmn";
var urlDecoded = decodeURIComponent(parameter);
var base64Decoded = CryptoJS.enc.Base64.parse(urlDecoded);
var hashed = CryptoJS.SHA512(base64Decoded).toString(CryptoJS.enc.Base64);
//hashed = "UxupkI5+dkhUorQ+K3+Tqct1WNUkj3I6N76g82CbNQ0EAH/nWjqi9CW5Qec1vq/qakNIYeXeqiAPOVAVkzf9mA=="/eWTS2lUgCEe6NJDXhNfYvXMRQDvH6k2PHVmy6LJS7RloVvcQcpVjRNVU5lJpAg=="
When working with Closure, i use following code:
var parameter = "Akuwnm2318kwioasdjlnmn";
var urlDecoded = decodeURIComponent(parameter);
var byteArray = goog.crypt.base64.decodeStringToByteArray(urlDecoded);
var base64Decoded = goog.crypt.byteArrayToHex(byteArray);
var sha512 = new goog.crypt.Sha512();
sha512.update(base64Decoded);
var hashed = sha512.digest();
hashed = goog.crypt.byteArrayToHex(hashed);
//hashed = "bc2a878edfffb0937fbc6c0f9dbc9566edc59b74080d68d4c8bdfeb4027f17c4316a02285baaf446872d2df37b1144ac3ce18d62ab9c786b1f1fb18a53acea1d"
So, why are the hashes different?
I would be very happy if someone could tell me how to adapt the Closure-Code, to get the same hash as the CryptoJS code provides.
Thanks a lot!
PS:
I also tried:
var parameter = "Akuwnm2318kwioasdjlnmn";
var urlDecoded = decodeURIComponent(parameter);
var base64DecodedByteArray = goog.crypt.base64.decodeStringToByteArray(urlDecoded);
var sha512 = new goog.crypt.Sha512();
sha512.update(base64DecodedByteArray);
var hashed = sha512.digest();
hashed = goog.crypt.byteArrayToHex(hashed);
//hashed = "531ba9908e7e764854a2b43e2b7f93a9cb7558d5248f723a37bea0f3609b350d04007fe75a3aa2f425b941e735beafea6a434861e5deaa200f3950159337fd98"
but then, as you see, i get another hash. why??
The first hash value is identical to the third, except it is base64-encoded rather than hex-encoded. You can change to hex encoding and get the same value:
var hashed = CryptoJS.SHA512(base64Decoded).toString(CryptoJS.enc.Hex);
//hashed = "531ba9908e7e764854a2b43e2b7f93a9cb7558d5248f723a37bea0f3609b350d04007fe75a3aa2f425b941e735beafea6a434861e5deaa200f3950159337fd98"
The second approach you show has a different value because you are not hashing the same data; you are instead converting the byteArray to a hex string and then hashing that string representation, not the underlying values.