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.
Related
Try to genegarate HMAC on JS with CryptoJS lib from UTF8 string with UTF8 secret. Like PHP hash_hmac('sha1','...','...',true);
PHP :
$buf = ' accept';
$bufferedSecret = '��xDx�����4�J�?)#';
hash_hmac('sha1', $buf, $bufferedSecret, false);
/* d301cae776ed8c5d46ac93bd7441b01af4d1b888 */
hash_hmac('sha1', $buf, $bufferedSecret, true);
/* ���v�]F���tA��Ѹ� */
JavaScript :
var buf = ' accept';
var bufferedSecret = '��xDx�����4�J�?)#';
CryptoJS.HmacSHA1(buf, bufferedSecret).toString();
/* d301cae776ed8c5d46ac93bd7441b01af4d1b888 */
var forBase64 = CryptoJS.HmacSHA1(buf, bufferedSecret);
CryptoJS.enc.Base64.stringify(forBase64);
/* 0wHK53btjF1GrJO9dEGwGvTRuIg= */
How get same HMAC(SHA1) UTF8 value on JS?
I was found a way for get UTF-8 RAW.
Used "convertWordArrayToUint8Array()" from here:
https://gist.github.com/getify/7325764
and just decode it.
var wordArr = CryptoJS.HmacSHA1(buf, bufferedSecret);
var utf8Arr = convertWordArrayToUint8Array(wordArr);
var string = new TextDecoder('utf-8').decode(utf8Arr);
Buffer to UTF8
You can take your Buffer and convert it to UTF-8 in JavaScript using the toString method; make sure you specify which format in the parameters, suitable values are hex and utf8, read more here.
var buf = ' accept';
var bufferedSecret = '��xDx�����4�J�?)#';
CryptoJS.HmacSHA1(buf, bufferedSecret).toString('utf8');
I'm working on this Encryption Cipher using CryptoJS for people who want to encrypt their messages. Unfortunately, I've run into a problem decrypting any messages that is encrypted using "NoPadding" padding. After hours and hours of testing the program for bugs, I finally found out what the problem was. I turns out that, when I append the encrypted javascript string into the HTML textarea, it changed the value of the string. Therefore, when I tried to decrypt the value from the textarea, it didn't work.
<textarea id="textarea"></textarea>
<button onclick="encrypting_without_textarea()">encrypting without textarea</button>
<button onclick="encrypting_with_textarea()">encrypting with textarea</button>
HTML
function encrypting_without_textarea(){
var textarea_element = document.getElementById("textarea");
var encryptionKey = "fkjasdlfkdsanfknlasknflsjkanflnasjkfnjknskjnfnlsnf";
var key = CryptoJS.enc.Hex.stringify(encryptionKey);
var value = "Multi-stability is the tendency of ambiguous perceptual experiences to move unstably back and forth between alternative interpretations. Some objects can be perceived in more than one way. An example from below in the section of figure/ground.";
var paddingObject = CryptoJS.pad.NoPadding;
var encrypted = CryptoJS.AES.encrypt(value, key, {mode:CryptoJS.mode.ECB, padding:paddingObject});
var decrypted = CryptoJS.AES.decrypt(encrypted, key, {mode:CryptoJS.mode.ECB, padding:paddingObject});
var msg = decrypted.toString(CryptoJS.enc.Utf8);
alert(msg);
}
The one above is decrypted straight from the encrypted message and it works, and the one below is decrypted with the value from from the textarea but it returns an error.
function encrypting_with_textarea(){
var textarea_element = document.getElementById("textarea");
var encryptionKey = "fkjasdlfkdsanfknlasknflsjkanflnasjkfnjknskjnfnlsnf";
var key = CryptoJS.enc.Hex.stringify(encryptionKey);
var value = "Multi-stability is the tendency of ambiguous perceptual experiences to move unstably back and forth between alternative interpretations. Some objects can be perceived in more than one way. An example from below in the section of figure/ground.";
var paddingObject = CryptoJS.pad.NoPadding;
var encrypted = CryptoJS.AES.encrypt(value, key, {mode:CryptoJS.mode.ECB, padding:paddingObject});
textarea_element.value = encrypted;
var decrypted = CryptoJS.AES.decrypt(textarea_element.value, key, {mode:CryptoJS.mode.ECB, padding:paddingObject});
var msg = decrypted.toString(CryptoJS.enc.Utf8);
alert(msg);
//Error: Malformed UTF-8 data
}
Here is the plnkr link. I understand that the value append to the textarea has change, but how? And, how do I change/encode the string so that the code can be display in the textarea and copy so that the message can be paste/decode with out it being corrupted. I'm open to any solutions, simpler the better?
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.
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.
I can get a hmac sing using Python as following:
import hmac, base64, hashlib
def make_sign():
hash_data = "data"
secret = "this is secret"
sha512 = hashlib.sha512
hmac_obj = hmac.new(secret, hash_data, sha512)
str_hash = hmac_obj.digest()
sign = base64.b64encode(str_hash)
hex_hash = hmac_obj.hexdigest()
hex_sign = base64.b64encode(hex_hash)
print "correct_sign:",sign
print "hex_digest_sign:",hex_sign
make_sign()
output:
correct_sign: Lg4pXNCIpitNQt2DLU19qWb+FxdsYZlK4LLncfkTzSidrYoFJLNolUziRqh09B5HyRdCTEP7enZp6/Te34FK1g==
hex_digest_sign: MmUwZTI5NWNkMDg4YTYyYjRkNDJkZDgzMmQ0ZDdkYTk2NmZlMTcxNzZjNjE5OTRhZTBiMmU3NzFmOTEzY2QyODlkYWQ4YTA1MjRiMzY4OTU0Y2UyNDZhODc0ZjQxZTQ3YzkxNzQyNGM0M2ZiN2E3NjY5ZWJmNGRlZGY4MTRhZDY=
but with js, I can get hex_digest_sign, but I need to get correct_sign for web request.
function make_request() {
hash_data = "data"
secret = "this is secret"
hmac = hmac_512(hash_data, secret)
var sign = $.base64.encode(hmac),
console.log("js_sign="+sign);
}
function hmac_512(message, secret) {
var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA512, secret);
hmac.update(message);
var hash = hmac.finalize();
return hash;
}
js output:
js_sign="MmUwZTI5NWNkMDg4YTYyYjRkNDJkZDgzMmQ0ZDdkYTk2NmZlMTcxNzZjNjE5OTRhZTBiMmU3NzFmOTEzY2QyODlkYWQ4YTA1MjRiMzY4OTU0Y2UyNDZhODc0ZjQxZTQ3YzkxNzQyNGM0M2ZiN2E3NjY5ZWJmNGRlZGY4MTRhZDY="
the correct sign is correct_sign: Lg4pXNCIpitNQt2DLU19qWb+FxdsYZlK4LLncfkTzSidrYoFJLNolUziRqh09B5HyRdCTEP7enZp6/Te34FK1g==
how to get it in js?
I suspect that you are running into trouble with types and encoding. According to the CryptoJS source, the iterative hashing style that you are using returns a WordArray once you call finalize().
With that, once you go to print the results, you are printing the contents of the WordArray.
The purpose for itterative hashing is typically if you have a large input, you can break it into chunks to work on one piece at a time. Try the below edit I made that removes this as it does not look like you need to iterate.
function hmac_512(message, secret) {
var newHMAC = CryptoJS.HmacSHA256(message, secret);
return newHMAC;
}
The above will simply return the HMAC in string form which, once Base64 encoded, should match the result you see in Python.
Hope this helps!