Is binary hashing possible with CryptoJS? - javascript

I want to create an HOTP client using javascript similar to SpeakEasy
The above library is intended for server side javascript usage and it uses NodeJS.
I want to do the same thing on front end javascript in a browser but I haven't been able to use CryptoJS to achieve this behavior.
var key = "abc";
var counter = "123";
// create an octet array from the counter
var octet_array = new Array(8);
var counter_temp = counter;
for (var i = 0; i < 8; i++) {
var i_from_right = 7 - i;
// mask 255 over number to get last 8
octet_array[i_from_right] = counter_temp & 255;
// shift 8 and get ready to loop over the next batch of 8
counter_temp = counter_temp >> 8;
}
// There is no such class called as Buffer on Browsers (its node js)
var counter_buffer = new Buffer(octet_array);
var hash = CryptoJS.HmacSHA1(key,counter_buffer);
document.write("hex value "+ hash);
document.write("hash value "+ CryptoJS.enc.Hex.stringify(hash));
I know this is possible on a native platform like java (android) or objective c (ios)
Here is the corresponding implementation HOTP in Objective C but I doubt if it's possible to do on a web based front end.
Also, I highly doubt if such a thing is secure in browser because javascript is viewable from any browser. Any inputs suggestions would be useful. I am doing this for a POC. I am curious if anyone has used Hotp on web based platform.

There is no such language that supports binary data strings in the code. You need to encode the binary data into some format such as Hex or Base64 and let CryptoJS decode it into it's own internal binary format which you then can pass to the various CryptoJS functions:
var wordArrayFromUtf = CryptoJS.enc.Utf8.parse("test");
var wordArrayFromHex = CryptoJS.enc.Hex.parse("74657374"); // "test"
var wordArrayFromB64 = CryptoJS.enc.Base64.parse("dGVzdA=="); // "test"
Other functions are:
wordArrayFromHex.toString(CryptoJS.enc.Utf8) // "test"
CryptoJS.enc.Utf8.stringify(wordArrayFromB64) // "test"
If you pass a string into a CrypoJS function (not these here), it will be assumed to be a Utf8-encoded string. If you don't want that, you need to decode it yourself.

The code at http://caligatio.github.io/jsSHA/ works fine for SHA-512.
Drop the .js files, look in their test/test.html at line 515. It might look like a string to you but it is binary hex.
So their input is binary which is unmistaken. Don't get hung up on the fact it is sitting in a big string.

Related

How to parseInt or ParseInt embedded data with TypeScript in Qualtrics?

Even when I save an integer to embedded data earlier in the survey flow (in previous blocks on different screens), I am not able in Javascript to get the embedded data value, ensure it is parsed as a number/integer, then use it in a loop. Is this something about TypeScript? I didn't see anything about parseInt or ParseInt in the TypeScript documentation.
For example, suppose I do the following:
// Draw a random number
var x = Math.floor(Math.random() * 5);
// Save it in embedded data
Qualtrics.SurveyEngine.setEmbeddedData("foo", x);
// In a later block on a different screen, get the embedded data as an integer
var x_new = "${e://Field/foo}"; // not an int
var x_new = parseInt("${e://Field/foo}"); // doesn't work
var x_new = ParseInt("${e://Field/foo}"); // doesn't work
// Loop using x_new:
for(i = 0; i < x_new; i++) {
console.log(i)
}
Any idea why this isn't working? Perhaps I just don't know how to parseint().
In "normal" JS runtime system, we have parseInt function, the function gets a string (like number string) as a parameter. In this env, we don't support your syntax - "${e://Field/foo}", because it is not a "number string".
In Qualtrics system environment they have parseInt too, but they support their custom syntax "${e://Field/foo}" to get EmbeddedData.
Make sure that your code is running on Qualtrics system environment.
ParseInt is just turning your string into an integer.
Look at the demo below.
let myVar = "${e://Field/foo}"; // This is a string
console.log(myVar); // This prints a string
console.log(parseInt(myVar)); // This prints "NaN", i.e. Not a Number, because the string isn't a representation of a number.

node.js change in concatenation?

I'm trying to debug some code that another programmer has left for me to maintain. I've just attempted to upgrade from node.js 5 to node.js 8 and my database queries are for some requests coming back with key not found errors
We're using couchbase for the database and our document keys are "encrypted" for security. So we may have a key that starts like this "User_myemail#gmail.com" but we encrypt it using the following method:
function _GetScrambledKey(dbKey)
{
//select encryption key based on db key content
var eKeyIndex = CalculateEncryptionKeyIndex(dbKey, eKeys.length);
var sha = CalculateSHA512(dbKey + eKeyIndex);
return sha;
}
function CalculateEncryptionKeyIndex(str, max)
{
var hashBuf = CalculateSHA1(str);
var count = 0;
for (var i = 0; i < hashBuf.length; i++)
{
count += hashBuf[i];
count = count % max;
}
return count;
}
We then query couchbase for the document with
cb.get("ECB_"+encryptedKey, opts, callback);
In node5 this worked but in node8 we're getting some documents return fine and others return as missing. I outputted the "ECB_"+encryptedKey as an int array and the results have only confused me more. They are different on node5 to node8 but only by one character right in the middle of the array.
Outputting the encryptedKey as an int array on both versions shows this
188,106,14,227,211,70,94,97,63,130,78,246,155,65,6,148,62,215,47,230,211,109,35,99,21,60,178,74,195,13,233,253,187,142,213,213,104,58,168,60,225,148,25,101,155,91,122,77,2,99,102,235,26,71,157,99,6,47,162,152,58,181,21,175
Then outputting the concatenated string, in the same way, shows slightly different results
This is the node8 output
Node8 key: 69,67,66,95,65533,106,14,65533,65533,70,94,97,63,65533,78,65533,65533,65,6,65533,62,65533,47,65533,65533,109,35,99,21,60,65533,74,65533,13,65533,65533,65533,65533,65533,65533,104,58,65533,60,65533,25,101,65533,91,122,77,2,99,102,65533,26,71,65533,99,6,47,65533,65533,58,65533,21,65533
And this is the node5 output
Node5 key: 69,67,66,95,65533,106,14,65533,65533,70,94,97,63,65533,78,65533,65533,65,6,65533,62,65533,47,65533,65533,109,35,99,21,60,65533,74,65533,13,65533,65533,65533,65533,65533,65533,104,58,65533,60,65533,65533,25,101,65533,91,122,77,2,99,102,65533,26,71,65533,99,6,47,65533,65533,58,65533,21,65533
I had to run it through a diff tool to see the difference
Comparing that to the original pre-append array it looks like the 225 has just been dropped in node8. Is 225 significant? I can't understand how that would be possible otherwise unless it's a bug. Does anyone have any ideas?
Looks like this was a change in v8 5.5 https://github.com/nodejs/node/issues/21278
A lot of the issues you are facing, including the concatenation can be cleaned up using newer features from ES6 that are available in node 8.
In general, you should avoid doing string concatenations with the + operator and should use string literals instead. In your case, you should replace the "ECB_"+encryptedKey with `ECB_${encryptedKey}`.
Additionally, if you want to output the contents of the integers values from this concatenated string, then you are better off using .join, the spread operator (...) and the Buffer class from Node as follows:
let encKey = `ECB_${encryptedKey}`;
let tmpBuff = Buffer.from(encKey);
let buffArrVals = [...tmpBuff];
console.log(buffArrVals.join(','));
Also, if you can help it, you really should avoid using var inside of function blocks like it exists in your sample code. var performs something called variable hoisting and causes the variable to become available outside the scope it was declared, which is seldom intended. From node 6+ onward the recommendation is to use let or const for variable declarations to ensure they stay scoped to the block they are declared.

Google Apps script equivalent of PHP's hash_hmac() with RAW BINARY output?

I have to connect to an API using hash_hmac. In the PHP documentation for hash_hmac, the fourth parameter bool $raw_output controls whether the output is raw binary data (true) or lowercase hexits (false). My program works in PHP by simply setting that parameter to true.
This is what works in PHP:
$signature = base64_encode(hash_hmac('SHA256', $signature_string, $private_key, true))
In Google Apps I can't use any javascript libraries (or can I?) but there is this function: Utilities.computeHmacSha256Signature https://developers.google.com/apps-script/reference/utilities/utilities#computehmacsha256signaturevalue-key
However this doesn't have the "true" option that PHP has, so it doesn't output the raw binary data.
How can I get the same value using Google Apps as I get in PHP?
This is what I have in Google Apps, but obviously it doesn't output the raw binary data:
var signature = Utilities.computeHmacSha256Signature(signature_string, private_key);
I did find a way to convert the response to hex (PHP equivalent of FALSE instead of TRUE, but that's not bringing me any closer to the solution.
// convert to hex
var signature_in_hex = signature.reduce(function(str,chr) {
chr = (chr < 0 ? chr + 256 : chr).toString(16);
return str + (chr.length==1?'0':'') + chr;
},'');
What worked for me is just copying these scripts straight into Google Apps:
https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/hmac-sha256.js
https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/enc-base64-min.js
And then use:
var hash = CryptoJS.HmacSHA256(signature, private_key);
var base64 = hash.toString(CryptoJS.enc.Base64);
Fiddle:
http://jsfiddle.net/c5r78fzm/

make a javascript HMAC token

I am trying to emulate the following .NET code in javascript using the Crypto.js library.
var hashInput = "public=ID1000000001::routetype=POST::route=personsearch::key1=ID1000000001::key2=1043"
byte[] inputBytes = new byte[hashInput.Length * sizeof(char)];
System.Buffer.BlockCopy(hashInput.ToCharArray(), 0, inputBytes,0,inputBytes.Length);
byte[] keyBytes = HexadecimalStringToByteArray("A_HEX_STRING_GOES_HERE");
var hmac = HMACSHA256.Create();
hmac.Key = keyBytes;
var clientHash = hmac.ComputeHash(inputBytes);
This gives me a ByteArray which is used as part of POST to a WebAPI in the form of
[41,197,254,91,244,87.....] etc.
I want to make the same exact byte array in a javascript client but i am having diffculty getting this. I have tried the following:
var stringToHash = 'public=ID1000000001::routetype=POST::route=personsearch::key1=ID1000000001::key2=1043';
var privateKey = 'A_HEX_STRING_GOES_HERE';
var hash = CryptoJS.HmacSHA256(stringToHash, privateKey);
//this results in a WordArray, which can be converted to many types
//however i cannot get the byte array as in the .net example
//i.e. i just want to get [41,197,254,91,244,87....] etc.
I can see on the documentation for Crypto.js how to convert to base64, and other formats, but not to the ByteArray which i need.
Any ideas?
--UPDATE
Thanks for the advice on not using BlockCopy, and also for pointing me in the direction of the encoding issues which i had completely neglected.
This was part of the issue. The other part was that i had managed to misuse the HMACSHA256 class. I found (after several, several hours) that the .NET code was not producing the correct hash value.
It turns out this code DID produce the correct Hash:
var hashInput = "a::string::to::hash";
var privateKey = "C0B615950F9D577A4EAF64C9B4F2E50F3DA2C6BB6F790FA346E9732788B29A08AC5444F1B82984DB190A75D3861CC4802D598EBF0025FD1C327928F43EB1C80E";
byte[] inputBytes = Encoding.UTF8.GetBytes(hashInput);
byte[] keyBytes = Encoding.UTF8.GetBytes(privateKey);
HMACSHA256 hmac = new HMACSHA256(keyBytes);
hmac.Initialize();
var clientHash = hmac.ComputeHash(inputBytes);
var base64 = Convert.ToBase64String(clientHash);
Lucky for me my WebAPI is not live yet!
The problem is probably the character encoding. You should use for instance the method encode_utf8(stringValue) in JavaScript and new UTF8Encoding.getBytes(String value) in .NET, to make sure that the character encodings match. Note that modern cryptography is based on bytes, not on strings or characters. Using System.Buffer.BlockCopy() to encode characters is really bad practice.

Is there a way to read binary data in JavaScript?

I would like to inject binary data into an object in JavaScript. Is there a way to do this?
i.e.
var binObj = new BinaryObject('101010100101011');
Something to that effect. Any help would be great.
You can use parseInt:
var bin = parseInt('10101010', 2);
The second argument (the radix) is the base of the input.
There's this binary ajax library that is explained here and there's also another binary parser library that can handle more data types.
You could also look at Google Gears which has a binary Blob object or take a look at making a javascript wrapper for Flash which provides a native ByteArray implementation.
Or... you can sit and wait and hope that all these things become standard :)
On all recent browsers you can do:
xhr.overrideMimeType('text/plain; charset=x-user-defined');
And retrieve a string. To get the binary result you will have to do
data.charCodeAt(pos) & 0xff;
On the nightly builds of Firefox and Chrome you can retrieve the value as an ArrayBuffer
xhr.responseType = "arraybuffer";
The result is then accessible there
xhr.mozResponseArrayBuffer // Firefox
xhr.response // Chrome
Then you can apply a TypedArray (eg: Int32Array) or a DataView on the buffer to read the result.
In order to make this process easier, I made a jQuery Patch to support the binary type and a DataView Wrapper that uses the latest available reading feature of the browser.
JavaScript has very little support for raw binary data. In general, it's best to live within this restriction. However, there's a trick I'm considering trying for a project of mine that involves manipulating huge bitmaps to do set operations in an OLAP database. This won't work in IE.
The basic idea is this: coerce the binary data into a PNG to send it to JavaScript, For example, a bitmap might be a black and white PNG, with black being 100% transparent. Then use Canvas operations to do bitwise data manipulation.
The HTML5 Canvas includes a pixel array type, which allows access to bytes in an image. Canvas also supports compositing operations, such as XOR. Lighten and darken should be able to do AND and OR. These operations are likely to be well optimized in any browser that supports them-- probably using the GPU.
If anyone tries this, please let me know how well it works.
That would be the other way around... pow and squareroot might be calculated by the Math-Class... I don't know if it is the fastest way, but it's as fast as the Windows Calculator in the "Programmer View".
AlertFormatedBin();
function AlertFormatedBin()
{
var vals = decToBinArr(31,8);
var i;
var s = "";
var mod = vals.length % 4;
for(i= 0; i <mod;i++)
{
s+=vals[i];
}
if(i>0)
s+=" ";
var j = i;
for(i;i<vals.length;i++)
{
s+=vals[i];
if(i-j != 0 && (i+1-j)%4 == 0)
{
s+=" ";
}
}
alert(s);
}
function decToBinArr(dec, minSize)
{
var mod = dec%2;
var r = new Array();
if(dec > 1)
{
dec-=mod;
var bd = squareRootRoundedDown(dec);
if(minSize && minSize-1 > bd)
bd = minSize-1;
else
var i;
for(i = bd; i>0;i--)
{
var nxt = pow(2,i);
if(dec >= nxt)
{
r[i] = 1;
dec-=nxt;
}
else
{
r[i] = 0;
}
}
}
r[0]= mod;
r.reverse();
return r;
}
function squareRootRoundedDown(dec)
{
if(dec<2)
return 0;
var x = 2;
var i;
for(i= 1;true;i++)
{
if(x>=dec)
{
i = x == dec ? i : i-1;
break;
}
x= x*2;
}
return i;
}
function pow(b,exp)
{
if(exp == 0)
return 0;
var i = 1;
var r= b;
for(i = 1; i < exp;i++)
r=r*b;
return r;
}
In the near future you will be able to use ArrayBuffers and File API Blobs.
As #Zippy pointed out in a comment, the more recent (late 2016) solutions include:
DataView (Standard)
jDataView (polyfill/extension of DataView)
jBinary (built on jDataView)
Javascript doesn't provide a mechanism to load an object in any form other than simple strings.
Closest you can do is serializing the object to a string, optionally encrypting/compressing it, sending it to the browser, and decrypting/decompressing if necessary, checking for sanity, eval() and pray().
Instead of using eval (which is not quite safe), you can use your own format (alternatively, xml or json for which there are plenty of libs) and parse it yourself.
As a side note, if you want this for obfuscation after the browser gets the usable data (after decrypting/decompressing), it is too easy to circumvent.
Percent encoding can unescape strings into a direct 1<->1 representaion of any binary blob and is also portable across browsers;
unescape("%uFFFF%uFFFF%uFFFF");
Most browser exploit's use this technique for embedding shellcode into HTML pages, it works very well for creating arbitrary binary streams.
jBinary "makes it easy to create, load, parse, modify and save complex binary files and data structures in both browser and Node.js."
I haven't used it, but it's what I found when asking the same question asked here...
Welcome to everyone who found this older post on Google. I figured out a solution that works in Chrome as of 2019, so hopefully this is just some added feature or something most people missed.
You can use a 0b prefix to your number. It won't quite get the binary representation, but you can easily convert it to an integer for storage. For example, you could store the binary number 1010 as such:
var binNum = 0b1010 //Stores as an integer, which would be 10
If you're curious, it also works for hexadecimal with the 0x prefix:
var binNum = 0x1010 //Stores as an integer, which would be 4112

Categories