SHA512 not the same in CryptoJS and Closure - javascript

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.

Related

Recreating a CryptoJS Hmac using python

The scenario is that I have a JS script that creates a HMAC for a user provided input and I want to compute the same HMAC for the same input using python. To make things clearer, consider the following JS and Python code snippets.
Javascript
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/hmac-sha256.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/enc-base64.min.js"></script>
<script>
var secretAccessKey = "bAvW5O18eSrxke4I7eFcrnrDJkN+wKQmx9aSHuMZQ0w=";
var stringtoSign = "Test";
// Generate HMAC SHA256 signature
var secretAccessKeyBase64 = CryptoJS.enc.Base64.parse(secretAccessKey);
var hash = CryptoJS.HmacSHA256(stringtoSign, secretAccessKeyBase64);
var signature = CryptoJS.enc.Base64.stringify(hash);
</script>
Python
stringToSign = "Test"
secretAccessKey = "bAvW5O18eSrxke4I7eFcrnrDJkN+wKQmx9aSHuMZQ0w="
secretAccessKeyBase64 = base64.b64decode(secretAccessKey).hex()
keyBytes = bytes(secretAccessKeyBase64, 'utf-8')
stringToSignBytes = bytes(stringToSign, 'utf-8')
signatureHash = hmac.new(keyBytes, stringToSignBytes, digestmod=hashlib.sha256).digest()
signature = base64.b64encode(signatureHash)
print(signature)
The Javascript code gives me b+1wRzDODA85vyDZkXByPIKO5qmnjCRNF5gZFi33/Ic=, while python gives me the value b'SsZ4bcYe3op1nGU6bySzlSc9kgg9Kgp37qzF15s2zNc='
Why is my python code generating a different HMAC for (seemingly) identical inputs that was provided to the JS script? Is there anyway to obtain the HMAC value outputted by the JS code using python?
You are using a Base64 encoded value as secret in Javascript, whereas in Python you use the plain text secret.
<script>
var secretAccessKeyBase64 = "secret";
var hash = CryptoJS.HmacSHA256("Message", secretAccessKeyBase64);
var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
document.write(hashInBase64);
</script>
This prints out the same value as the Python code:
qnR8UCqJggD55PohusaBNviGoOJ67HC6Btry4qXLVZc=
Edit:
base64 returns a byte-object there is no need to convert it to hex():
stringToSign = "Test"
secretAccessKey = "bAvW5O18eSrxke4I7eFcrnrDJkN+wKQmx9aSHuMZQ0w="
secretAccessKeyBase64 = base64.b64decode(secretAccessKey)
keyBytes = secretAccessKeyBase64
stringToSignBytes = bytes(stringToSign, 'utf-8')
signatureHash = hmac.new(keyBytes, stringToSignBytes, digestmod=hashlib.sha256).digest()
signature = base64.b64encode(signatureHash)
print(signature)
Prints correctly:
b'b+1wRzDODA85vyDZkXByPIKO5qmnjCRNF5gZFi33/Ic='

Similar Encrypt code in javascript as in C#

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);

Hashfunction of a hex value not a string in crypto-js

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

JSON.parse() - SyntaxError: Expected end of stream at char 2

In my project, I have written google spreadsheet script to decipher encrypted cell content using sjcl. But I failed.
function encryptCell() {
var masterKey = Browser.inputBox('Enter masterKey');
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var cell = spreadSheet.getActiveSheet().getActiveCell();
var input = cell.getValue();
var encJson = sjcl.encrypt(masterKey, input);
/*
{"iv":"4psT+LTIh/aT7WWv7Ye7qw==","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"PjSOiia9TCM=","ct":"3hwmBbwQ7y/fsjk="}
*/
var encStr = JSON.stringify(encJson);
/*
"{\"iv\":\"4psT+LTIh/aT7WWv7Ye7qw==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"PjSOiia9TCM=\",\"ct\":\"3hwmBbwQ7y/fsjk=\"}"
*/
var encB64 = Utilities.base64Encode(encStr);
Browser.msgBox(encB64);
var rencStr = Utilities.base64Decode(encB64);
/*
34,123,92,34,105,118,92,34,58,92,34,52,112,115,84,43,76,84,73,104,47,97,84,55,87,87,118,55,89,101,55,113,119,61,61,92,34,44,92,34,118,92,34,58,49,44,92,34,105,116,101,114,92,34,58,49,48,48,48,44,92,34,107,115,92,34,58,49,50,56,44,92,34,116,115,92,34,58,54,52,44,92,34,109,111,100,101,92,34,58,92,34,99,99,109,92,34,44,92,34,97,100,97,116,97,92,34,58,92,34,92,34,44,92,34,99,105,112,104,101,114,92,34,58,92,34,97,101,115,92,34,44,92,34,115,97,108,116,92,34,58,92,34,80,106,83,79,105,105,97,57,84,67,77,61,92,34,44,92,34,99,116,92,34,58,92,34,51,104,119,109,66,98,119,81,55,121,47,102,115,106,107,61,92,34,125,34
*/
var rencJson = JSON.parse(rencStr);
var rinput = sjcl.decrypt(masterKey, rencJson);
Browser.msgBox(rinput);
}
Encryption is fine, which I can decrypt using this tool. Something is wrong with JSON.parse().
var rencStr = Utilities.base64Decode(encB64);
/*
34,123,92,34,105,118,92,34,58,92,34,52,112,115,84,43,76,84,73,104,47,97,84,55,87,87,118,55,89,101,55,113,119,61,61,92,34,44,92,34,118,92,34,58,49,44,92,34,105,116,101,114,92,34,58,49,48,48,48,44,92,34,107,115,92,34,58,49,50,56,44,92,34,116,115,92,34,58,54,52,44,92,34,109,111,100,101,92,34,58,92,34,99,99,109,92,34,44,92,34,97,100,97,116,97,92,34,58,92,34,92,34,44,92,34,99,105,112,104,101,114,92,34,58,92,34,97,101,115,92,34,44,92,34,115,97,108,116,92,34,58,92,34,80,106,83,79,105,105,97,57,84,67,77,61,92,34,44,92,34,99,116,92,34,58,92,34,51,104,119,109,66,98,119,81,55,121,47,102,115,106,107,61,92,34,125,34
*/
If you take a look, that's not JSON. did you possibly miss the JSON.stringify(); step for that one?
You can't parse it if it's not JSON.
When decoding with Utilities.base64Decode() you have one extra step to follow if you want to get a string back. If you look at the Google Scripts reference it says that base64Decode returns a byte array and not a string. Looking at your code, your decode returns
var rencStr = Utilities.base64Decode(encB64);
/*34,123,92,34,105,118,92,34,58,92,34,52,112,115,84,43,76,84,73,104,47,97,84...*/
which is a numeric representation of your string in Unicode. If you run your return value through Utilities.newBlob(rencStr).getDataAsString() as the reference recommends, you will have your JSON that you can parse back into your encrypted string.

Encrypt/decrypt with two different keys

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... (?).

Categories