How to get CryptoJS result as hash_hmac PHP (SHA1) - javascript

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

Related

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

Uncaught URIError: URI malformed error with jQuery

I'm using node forge to encrypt a form before sending it to the server using AES.
The code for the crypto part for now is
const bigInt = require("big-integer");
const forge = require('node-forge');
function generateParams() {
// Cryptographic random number generator
var array = new Uint32Array(2);
var _key = bigInt(window.crypto.getRandomValues(array)[0]).toString();
var _iv = bigInt(window.crypto.getRandomValues(array)[1]).toString();
// generate random key and IV
var key = forge.util.encode64(_key);
var iv = forge.util.encode64(_iv);
const params = {
key: key,
iv: iv
}
return params;
}
function encrypt(params) {
var cipher = forge.rc2.createEncryptionCipher(params.key);
cipher.start(params.iv);
// Encrypting "testing"
cipher.update(forge.util.createBuffer("testing"));
cipher.finish();
return cipher.output;
}
function decrypt(params, encrypted) {
var cipher = forge.rc2.createDecryptionCipher(params.key);
cipher.start(params.iv);
cipher.update(encrypted);
cipher.finish();
return cipher.output;
}
and the jQuery function is (not posting yet)
$('#recordForm').submit(function(event) {
// Stop form from submitting normally
event.preventDefault();
// Grab form data
// Crypto
const params = generateParams();
const encryptedForm = {
test: encrypt(params),
}
console.log("Encrypted: " + encryptedForm.test);
const decryptedForm = {
test: decrypt(params, encryptedForm.id).data,
}
console.log("Decrypted: " + decryptedForm.test);
});
My problem is that I keep getting back (cryptob.js is the name of my file, generated with browserify)
Uncaught URIError: URI malformed
at decodeURIComponent (<anonymous>)
at Object.util.decodeUtf8 (cryptob.js:24437)
at ByteStringBuffer.util.ByteStringBuffer.toString (cryptob.js:23490)
at HTMLFormElement.<anonymous> (cryptob.js:1282)
at HTMLFormElement.dispatch (jquery-3.1.1.slim.min.js:3)
at HTMLFormElement.q.handle (jquery-3.1.1.slim.min.js:3)
when calling encrypt().
There is this answer here which recommends including a special meta tag. I have done that but it still doesn't work. Since some resources online say it is related to UTF-8 encoding, I tried replacing
cipher.update(forge.util.createBuffer("testing"));
with
cipher.update(forge.util.createBuffer(encodeURIComponent("testing")));
or
cipher.update(forge.util.createBuffer("testing", 'utf8'));
but it didn't work either (based on encodeURIComponent(str)).
You can test forge here, and if you run this code (which is essentially what I'm doing)
var forge = require("node-forge")
// generate a random key and IV
var key = forge.util.encode64("12354523465");
var iv = forge.util.encode64("2315");
// encrypt some bytes
var cipher = forge.rc2.createEncryptionCipher(key);
cipher.start(iv);
cipher.update(forge.util.createBuffer("testing"));
cipher.finish();
var encrypted = cipher.output;
console.log(encrypted);
// decrypt some bytes
var cipher = forge.rc2.createDecryptionCipher(key);
cipher.start(iv);
cipher.update(encrypted);
cipher.finish();
console.log(cipher.output.data)
it works fine.
How can I solve this?
It looks like this error is actually happening in the toString, where you generate your _key and _iv.
Try testing with some hard-coded strings, as used in the example code you posted. Then, use a method to generate random byte strings for the key and IV.
Also, for AES-256, the key should have 32 bytes (not bits) of entropy. The IV should have 16 bytes of entropy.

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.

Issue using RSA encryption in javascript

I'm working with a project that currently is doing encryption in a salesforce apex class (using the Crypto library) and that logic needs to be moved into a javascript file. The node.js package I'm trying to use to do the encryption is node-rsa.
Here's the code that currently exists in apex:
String algName = 'RSA';
blob signature;
String signGen = '';
String pKey = 'MIIEvgIBADANBgkqhkiG<rest of key snipped>';
String payload = 'some payload';
blob privateKey = EncodingUtil.base64Decode(pKey);
blob input = Blob.valueOf(payload);
signature = Crypto.sign(algName, input, privateKey);
signGen = EncodingUtil.base64Encode(signature);
And here's the initial javascript implementation:
var tmp = forge.util.decode64(pKey);
var privateKey2 = new NodeRSA(tmp);
payload = 'some payload
var encrypted = key.encrypt(payload, 'base64');
The problem I'm having is that the line:
var privateKey2 = new NodeRSA(tmp);
is causing the following error:
Invalid PEM format
The private key that the node-rsa uses in their example has markets at the beginning and end of the key of:
---- BEGIN RSA PRIVATE KEY -----
---- END RSA PRIVATE KEY -----
So I'm not sure if I have to somehow indicate to the node-rsa library that this key is in a different format. Or maybe there's another RSA javascript library I could try using?
I left you a response for how to do this using forge here: https://github.com/digitalbazaar/forge/issues/150
var pkey = 'some base64-encoded private key';
var pkeyDer = forge.util.decode64(pkey);
var pkeyAsn1 = forge.asn1.fromDer(pkeyDer);
var privateKey = forge.pki.privateKeyFromAsn1(pkeyAsn1);
// above could be simplified if pkey is stored in standard PEM format, then just do this:
// var pkey = 'some private key in pem format';
// var privateKey = forge.pki.privateKeyFromPem(pkey);
var payload = 'some string payload';
var md = forge.md.sha1.create();
md.update(payload, 'utf8');
var signature = privateKey.sign(md);
var signature64 = forge.util.encode64(signature);
// signature64 is now a base64-encoded RSA signature on a SHA-1 digest
// using PKCS#1v1.5 padding... see the examples for other padding options if necessary

Decompress gzip and zlib string in javascript

I want to get compress layer data from tmx file . Who knows libraries for decompress gzip and zlib string in javascript ? I try zlib but it doesn't work for me . Ex , layer data in tmx file is :
<data encoding="base64" compression="zlib">
eJztwTEBAAAAwqD1T20JT6AAAHgaCWAAAQ==
</data>
My javascript code is
var base64Data = "eJztwTEBAAAAwqD1T20JT6AAAHgaCWAAAQ==";
var compressData = atob(base64Data);
var inflate = new Zlib.Inflate(compressData);
var output = inflate.decompress();
It runs with displays message error "unsupported compression method" . But I try decompress with online tool as http://i-tools.org/gzip , it returns correct string.
Pako is a full and modern Zlib port.
Here is a very simple example and you can work from there.
Get pako.js and you can decompress byteArray like so:
<html>
<head>
<title>Gunzipping binary gzipped string</title>
<script type="text/javascript" src="pako.js"></script>
<script type="text/javascript">
// Get datastream as Array, for example:
var charData = [31,139,8,0,0,0,0,0,0,3,5,193,219,13,0,16,16,4,192,86,214,151,102,52,33,110,35,66,108,226,60,218,55,147,164,238,24,173,19,143,241,18,85,27,58,203,57,46,29,25,198,34,163,193,247,106,179,134,15,50,167,173,148,48,0,0,0];
// Turn number array into byte-array
var binData = new Uint8Array(charData);
// Pako magic
var data = pako.inflate(binData);
// Convert gunzipped byteArray back to ascii string:
var strData = String.fromCharCode.apply(null, new Uint16Array(data));
// Output to console
console.log(strData);
</script>
</head>
<body>
Open up the developer console.
</body>
</html>
Running example: http://jsfiddle.net/9yH7M/
Alternatively you can base64 encode the array before you send it over as the Array takes up a lot of overhead when sending as JSON or XML. Decode likewise:
// Get some base64 encoded binary data from the server. Imagine we got this:
var b64Data = 'H4sIAAAAAAAAAwXB2w0AEBAEwFbWl2Y0IW4jQmziPNo3k6TuGK0Tj/ESVRs6yzkuHRnGIqPB92qzhg8yp62UMAAAAA==';
// Decode base64 (convert ascii to binary)
var strData = atob(b64Data);
// Convert binary string to character-number array
var charData = strData.split('').map(function(x){return x.charCodeAt(0);});
// Turn number array into byte-array
var binData = new Uint8Array(charData);
// Pako magic
var data = pako.inflate(binData);
// Convert gunzipped byteArray back to ascii string:
var strData = String.fromCharCode.apply(null, new Uint16Array(data));
// Output to console
console.log(strData);
Running example: http://jsfiddle.net/9yH7M/1/
To go more advanced, here is the pako API documentation.
I can solve my problem by zlib . I fix my code as below
var base64Data = "eJztwTEBAAAAwqD1T20JT6AAAHgaCWAAAQ==";
var compressData = atob(base64Data);
var compressData = compressData.split('').map(function(e) {
return e.charCodeAt(0);
});
var inflate = new Zlib.Inflate(compressData);
var output = inflate.decompress();
For anyone using Ruby on Rails, who wants to send compressed encoded data to the browser, then uncompress it via Javascript on the browser, I've combined both excellent answers above into the following solution. Here's the Rails server code in my application controller which compresses and encodes a string before sending it the browser via a #variable to a .html.erb file:
require 'zlib'
require 'base64'
def compressor (some_string)
Base64.encode64(Zlib::Deflate.deflate(some_string))
end
Here's the Javascript function, which uses pako.min.js:
function uncompress(input_field){
base64data = document.getElementById(input_field).innerText;
compressData = atob(base64data);
compressData = compressData.split('').map(function(e) {
return e.charCodeAt(0);
});
binData = new Uint8Array(compressData);
data = pako.inflate(binData);
return String.fromCharCode.apply(null, new Uint16Array(data));
}
Here's a javascript call to that uncompress function, which wants to unencode and uncompress data stored inside a hidden HTML field:
my_answer = uncompress('my_hidden_field');
Here's the entry in the Rails application.js file to call pako.min.js, which is in the /vendor/assets/javascripts directory:
//= require pako.min
And I got the pako.min.js file from here:
https://github.com/nodeca/pako/tree/master/dist
All works at my end, anyway! :-)
I was sending data from a Python script and trying to decode it in JS. Here's what I had to do:
Python
import base64
import json
import urllib.parse
import zlib
...
data_object = {
'_id': '_id',
...
}
compressed_details = base64.b64encode(zlib.compress(bytes(json.dumps(data_object), 'utf-8'))).decode("ascii")
urlsafe_object = urllib.parse.quote(str(compressed_details))#.replace('%', '\%') # you likely don't need this last part
final_URL = f'https://my.domain.com?data_object={urlsafe_object}'
...
JS
// npm install this
import pako from 'pako';
...
const urlParams = new URLSearchParams(window.location.search);
const data_object = urlParams.get('data_object');
if (data_object) {
const compressedData = Uint8Array.from(window.atob(data_object), (c) => c.charCodeAt(0));
originalObject = JSON.parse(pako.inflate(compressedData, { to: 'string' }));
};
...

Categories