Porting SHA512 Javascript implemention to Actionscript - javascript
I am wondering if anyone can help me in porting a SHA-512 implemention in Javascript to Actionscript. Since both Javascript and Actionscript share the same origin, I think porting it will be easy for people who are used to Actionscript.
The code for sha512 in javascript can be found here:
http://pajhome.org.uk/crypt/md5/sha512.html
Thank you.
Here is the code ported by me. The code is separated between two files Int64.as and Sha512.as, both of them belong to the com.crypto package.
com/crypto/Int64.as
/*
* Int64 for ActionScript
* Ported by: AAA
* Ported from: See below
*/
/*
* A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined
* in FIPS 180-2
* Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for details.
*/
package com.crypto {
public class Int64 {
public var h;
public var l;
public function Int64(h, l) {
this.h = h;
this.l = l;
}
public function copy(src) {
this.h = src.h;
this.l = src.l;
}
public function rrot(x, shift) {
this.l = (x.l >>> shift) | (x.h << (32-shift));
this.h = (x.h >>> shift) | (x.l << (32-shift));
}
public function revrrot(x, shift) {
this.l = (x.h >>> shift) | (x.l << (32-shift));
this.h = (x.l >>> shift) | (x.h << (32-shift));
}
public function shr(x, shift) {
this.l = (x.l >>> shift) | (x.h << (32-shift));
this.h = (x.h >>> shift);
}
public function add(x, y) {
var w0 = (x.l & 0xffff) + (y.l & 0xffff);
var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
this.l = (w0 & 0xffff) | (w1 << 16);
this.h = (w2 & 0xffff) | (w3 << 16);
}
public function add4(a, b, c, d) {
var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
this.l = (w0 & 0xffff) | (w1 << 16);
this.h = (w2 & 0xffff) | (w3 << 16);
}
public function add5(a, b, c, d, e) {
var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff);
var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16);
var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16);
var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
this.l = (w0 & 0xffff) | (w1 << 16);
this.h = (w2 & 0xffff) | (w3 << 16);
}
}
}
com/crypto/Sha512.as
/*
* SHA-512 for ActionScript
* Ported by: AAA
* Ported from: See below
*/
/*
* A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined
* in FIPS 180-2
* Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for details.
*/
package com.crypto {
public class Sha512 {
public var hexcase = 0;
public var b64pad = "";
public function Sha512() {
}
public function hex_sha512(s) { return rstr2hex(rstr_sha512(str2rstr_utf8(s))); }
public function b64_sha512(s) { return rstr2b64(rstr_sha512(str2rstr_utf8(s))); }
public function any_sha512(s, e) { return rstr2any(rstr_sha512(str2rstr_utf8(s)), e);}
public function hex_hmac_sha512(k, d) { return rstr2hex(rstr_hmac_sha512(str2rstr_utf8(k), str2rstr_utf8(d))); }
public function b64_hmac_sha512(k, d) { return rstr2b64(rstr_hmac_sha512(str2rstr_utf8(k), str2rstr_utf8(d))); }
public function any_hmac_sha512(k, d, e) { return rstr2any(rstr_hmac_sha512(str2rstr_utf8(k), str2rstr_utf8(d)), e);}
public function sha512_vm_test() {
return hex_sha512("abc").toLowerCase() == "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a"
+ "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
}
private function rstr_sha512(s) {
return binb2rstr(binb_sha512(rstr2binb(s), s.length * 8));
}
private function rstr_hmac_sha512(key, data) {
var bkey = rstr2binb(key);
if(bkey.length > 32) bkey = binb_sha512(bkey, key.length * 8);
var ipad = new Array(32)
var opad = new Array(32);
for(var i = 0; i < 32; i++) {
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5C5C5C5C;
}
var hash = binb_sha512(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
return binb2rstr(binb_sha512(opad.concat(hash), 1024 + 512));
}
private function rstr2hex(input) {
try { hexcase } catch(e) { hexcase=0; }
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var output = "";
var x;
for(var i = 0; i < input.length; i++) {
x = input.charCodeAt(i);
output += hex_tab.charAt((x >>> 4) & 0x0F) + hex_tab.charAt(x & 0x0F);
}
return output;
}
private function rstr2b64(input)
{
try { b64pad } catch(e) { b64pad=''; }
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var output = "";
var len = input.length;
for(var i = 0; i < len; i += 3) {
var triplet = (input.charCodeAt(i) << 16)
| (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
| (i + 2 < len ? input.charCodeAt(i+2) : 0);
for(var j = 0; j < 4; j++) {
if(i * 8 + j * 6 > input.length * 8) output += b64pad;
else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
}
}
return output;
}
private function rstr2any(input, encoding) {
var divisor = encoding.length;
var i, j, q, x, quotient;
var dividend = new Array(Math.ceil(input.length / 2));
for(i = 0; i < dividend.length; i++) {
dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
}
var full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
var remainders = new Array(full_length);
for(j = 0; j < full_length; j++) {
quotient = new Array();
x = 0;
for(i = 0; i < dividend.length; i++) {
x = (x << 16) + dividend[i];
q = Math.floor(x / divisor);
x -= q * divisor;
if(quotient.length > 0 || q > 0)
quotient[quotient.length] = q;
}
remainders[j] = x;
dividend = quotient;
}
var output = "";
for(i = remainders.length - 1; i >= 0; i--)
output += encoding.charAt(remainders[i]);
return output;
}
private function str2rstr_utf8(input) {
var output = "";
var i = -1;
var x, y;
while(++i < input.length) {
x = input.charCodeAt(i);
y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
i++;
}
if(x <= 0x7F)
output += String.fromCharCode(x);
else if(x <= 0x7FF)
output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F), 0x80 | ( x & 0x3F));
else if(x <= 0xFFFF)
output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
0x80 | ((x >>> 6 ) & 0x3F),
0x80 | ( x & 0x3F));
else if(x <= 0x1FFFFF)
output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
0x80 | ((x >>> 12) & 0x3F),
0x80 | ((x >>> 6 ) & 0x3F),
0x80 | ( x & 0x3F));
}
return output;
}
private function str2rstr_utf16le(input) {
var output = "";
for(var i = 0; i < input.length; i++)
output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
(input.charCodeAt(i) >>> 8) & 0xFF);
return output;
}
private function str2rstr_utf16be(input) {
var output = "";
for(var i = 0; i < input.length; i++)
output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
input.charCodeAt(i) & 0xFF);
return output;
}
private function rstr2binb(input) {
var output = new Array(input.length >> 2);
for(var i = 0; i < output.length; i++)
output[i] = 0;
for(var i = 0; i < input.length * 8; i += 8)
output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
return output;
}
private function binb2rstr(input) {
var output = "";
for(var i = 0; i < input.length * 32; i += 8)
output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
return output;
}
var sha512_k;
private function binb_sha512(x, len) {
if(sha512_k == undefined) {
sha512_k = new Array(
new Int64(0x428a2f98, -685199838), new Int64(0x71374491, 0x23ef65cd),
new Int64(-1245643825, -330482897), new Int64(-373957723, -2121671748),
new Int64(0x3956c25b, -213338824), new Int64(0x59f111f1, -1241133031),
new Int64(-1841331548, -1357295717), new Int64(-1424204075, -630357736),
new Int64(-670586216, -1560083902), new Int64(0x12835b01, 0x45706fbe),
new Int64(0x243185be, 0x4ee4b28c), new Int64(0x550c7dc3, -704662302),
new Int64(0x72be5d74, -226784913), new Int64(-2132889090, 0x3b1696b1),
new Int64(-1680079193, 0x25c71235), new Int64(-1046744716, -815192428),
new Int64(-459576895, -1628353838), new Int64(-272742522, 0x384f25e3),
new Int64(0xfc19dc6, -1953704523), new Int64(0x240ca1cc, 0x77ac9c65),
new Int64(0x2de92c6f, 0x592b0275), new Int64(0x4a7484aa, 0x6ea6e483),
new Int64(0x5cb0a9dc, -1119749164), new Int64(0x76f988da, -2096016459),
new Int64(-1740746414, -295247957), new Int64(-1473132947, 0x2db43210),
new Int64(-1341970488, -1728372417), new Int64(-1084653625, -1091629340),
new Int64(-958395405, 0x3da88fc2), new Int64(-710438585, -1828018395),
new Int64(0x6ca6351, -536640913), new Int64(0x14292967, 0xa0e6e70),
new Int64(0x27b70a85, 0x46d22ffc), new Int64(0x2e1b2138, 0x5c26c926),
new Int64(0x4d2c6dfc, 0x5ac42aed), new Int64(0x53380d13, -1651133473),
new Int64(0x650a7354, -1951439906), new Int64(0x766a0abb, 0x3c77b2a8),
new Int64(-2117940946, 0x47edaee6), new Int64(-1838011259, 0x1482353b),
new Int64(-1564481375, 0x4cf10364), new Int64(-1474664885, -1136513023),
new Int64(-1035236496, -789014639), new Int64(-949202525, 0x654be30),
new Int64(-778901479, -688958952), new Int64(-694614492, 0x5565a910),
new Int64(-200395387, 0x5771202a), new Int64(0x106aa070, 0x32bbd1b8),
new Int64(0x19a4c116, -1194143544), new Int64(0x1e376c08, 0x5141ab53),
new Int64(0x2748774c, -544281703), new Int64(0x34b0bcb5, -509917016),
new Int64(0x391c0cb3, -976659869), new Int64(0x4ed8aa4a, -482243893),
new Int64(0x5b9cca4f, 0x7763e373), new Int64(0x682e6ff3, -692930397),
new Int64(0x748f82ee, 0x5defb2fc), new Int64(0x78a5636f, 0x43172f60),
new Int64(-2067236844, -1578062990), new Int64(-1933114872, 0x1a6439ec),
new Int64(-1866530822, 0x23631e28), new Int64(-1538233109, -561857047),
new Int64(-1090935817, -1295615723), new Int64(-965641998, -479046869),
new Int64(-903397682, -366583396), new Int64(-779700025, 0x21c0c207),
new Int64(-354779690, -840897762), new Int64(-176337025, -294727304),
new Int64(0x6f067aa, 0x72176fba), new Int64(0xa637dc5, -1563912026),
new Int64(0x113f9804, -1090974290), new Int64(0x1b710b35, 0x131c471b),
new Int64(0x28db77f5, 0x23047d84), new Int64(0x32caab7b, 0x40c72493),
new Int64(0x3c9ebe0a, 0x15c9bebc), new Int64(0x431d67c4, -1676669620),
new Int64(0x4cc5d4be, -885112138), new Int64(0x597f299c, -60457430),
new Int64(0x5fcb6fab, 0x3ad6faec), new Int64(0x6c44198c, 0x4a475817));
}
var H = new Array(
new Int64(0x6a09e667, -205731576),
new Int64(-1150833019, -2067093701),
new Int64(0x3c6ef372, -23791573),
new Int64(-1521486534, 0x5f1d36f1),
new Int64(0x510e527f, -1377402159),
new Int64(-1694144372, 0x2b3e6c1f),
new Int64(0x1f83d9ab, -79577749),
new Int64(0x5be0cd19, 0x137e2179));
var T1 = new Int64(0, 0),
T2 = new Int64(0, 0),
a = new Int64(0,0),
b = new Int64(0,0),
c = new Int64(0,0),
d = new Int64(0,0),
e = new Int64(0,0),
f = new Int64(0,0),
g = new Int64(0,0),
h = new Int64(0,0),
s0 = new Int64(0, 0),
s1 = new Int64(0, 0),
Ch = new Int64(0, 0),
Maj = new Int64(0, 0),
r1 = new Int64(0, 0),
r2 = new Int64(0, 0),
r3 = new Int64(0, 0);
var j, i;
var W = new Array(80);
for(i=0; i<80; i++)
W[i] = new Int64(0, 0);
x[len >> 5] |= 0x80 << (24 - (len & 0x1f));
x[((len + 128 >> 10)<< 5) + 31] = len;
for(i = 0; i<x.length; i+=32) {
a.copy(H[0]);
b.copy(H[1]);
c.copy(H[2]);
d.copy(H[3]);
e.copy(H[4]);
f.copy(H[5]);
g.copy(H[6]);
h.copy(H[7]);
for(j=0; j<16; j++) {
W[j].h = x[i + 2*j];
W[j].l = x[i + 2*j + 1];
}
for(j=16; j<80; j++) {
r1.rrot(W[j-2], 19);
r2.revrrot(W[j-2], 29);
r3.shr(W[j-2], 6);
s1.l = r1.l ^ r2.l ^ r3.l;
s1.h = r1.h ^ r2.h ^ r3.h;
r1.rrot(W[j-15], 1);
r2.rrot(W[j-15], 8);
r3.shr(W[j-15], 7);
s0.l = r1.l ^ r2.l ^ r3.l;
s0.h = r1.h ^ r2.h ^ r3.h;
W[j].add4(s1, W[j-7], s0, W[j-16]);
}
for(j = 0; j < 80; j++) {
Ch.l = (e.l & f.l) ^ (~e.l & g.l);
Ch.h = (e.h & f.h) ^ (~e.h & g.h);
r1.rrot(e, 14);
r2.rrot(e, 18);
r3.revrrot(e, 9);
s1.l = r1.l ^ r2.l ^ r3.l;
s1.h = r1.h ^ r2.h ^ r3.h;
r1.rrot(a, 28);
r2.revrrot(a, 2);
r3.revrrot(a, 7);
s0.l = r1.l ^ r2.l ^ r3.l;
s0.h = r1.h ^ r2.h ^ r3.h;
Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l);
Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h);
T1.add5(h, s1, Ch, sha512_k[j], W[j]);
T2.add(s0, Maj);
h.copy(g);
g.copy(f);
f.copy(e);
e.add(d, T1);
d.copy(c);
c.copy(b);
b.copy(a);
a.add(T1, T2);
}
H[0].add(H[0], a);
H[1].add(H[1], b);
H[2].add(H[2], c);
H[3].add(H[3], d);
H[4].add(H[4], e);
H[5].add(H[5], f);
H[6].add(H[6], g);
H[7].add(H[7], h);
}
var hash = new Array(16);
for(i=0; i<8; i++) {
hash[2*i] = H[i].h;
hash[2*i + 1] = H[i].l;
}
return hash;
}
}
}
Sorry, I could not find a proper place to upload them.
I am not able to post a comment on the above (where this should be), but there is an error with some signatures using this code due to Actionscript's imaginative behaviour when appending the null character to a string (it doesn't).
For a quick and dirty fix to the hex encoded hmac which is what I am using, I changed the hex_hmac_sha512 function (just for the encoding it calls) and added a binb2hex function as follows:
private function hex_hmac_sha512(key, data) {
key = str2rstr_utf8(key);
data = str2rstr_utf8(data);
var bkey = rstr2binb(key);
if(bkey.length > 32) bkey = binb_sha512(bkey, key.length * 8);
var ipad = new Array(32)
var opad = new Array(32);
for(var i = 0; i < 32; i++) {
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5C5C5C5C;
}
var hash = binb_sha512(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
return binb2hex(binb_sha512(opad.concat(hash), 1024 + 512));
}
private function binb2hex(input) {
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var output = "";
for(var i = 0; i < input.length * 32; i += 8){
var schar = (input[i>>5] >>> (24 - i % 32)) & 0xFF;
output += hex_tab.charAt((schar >>> 4) & 0x0F) + hex_tab.charAt(schar & 0x0F);
}
return output;
}
Related
how to generate SHA256 with 32 bytes for a given string?
I am looking for javascript code for generating a SHA256 with 32 bytes for a given string this code is suppose to work inside a browser so it should work without any dependencies so far I found the following function that gives 64 bytes SHA256: /** * Secure Hash Algorithm (SHA256) * http://www.webtoolkit.info/ * Original code by Angel Marin, Paul Johnston **/ function SHA256(s){ var chrsz = 8; var hexcase = 0; function safe_add (x, y) { var lsw = (x & 0xFFFF) + (y & 0xFFFF); var msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xFFFF); } function S (X, n) { return ( X >>> n ) | (X << (32 - n)); } function R (X, n) { return ( X >>> n ); } function Ch(x, y, z) { return ((x & y) ^ ((~x) & z)); } function Maj(x, y, z) { return ((x & y) ^ (x & z) ^ (y & z)); } function Sigma0256(x) { return (S(x, 2) ^ S(x, 13) ^ S(x, 22)); } function Sigma1256(x) { return (S(x, 6) ^ S(x, 11) ^ S(x, 25)); } function Gamma0256(x) { return (S(x, 7) ^ S(x, 18) ^ R(x, 3)); } function Gamma1256(x) { return (S(x, 17) ^ S(x, 19) ^ R(x, 10)); } function core_sha256 (m, l) { var K = new Array(0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 0xE49B69C1, 0xEFBE4786, 0xFC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x6CA6351, 0x14292967, 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2); var HASH = new Array(0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19); var W = new Array(64); var a, b, c, d, e, f, g, h, i, j; var T1, T2; m[l >> 5] |= 0x80 << (24 - l % 32); m[((l + 64 >> 9) << 4) + 15] = l; for ( var i = 0; i<m.length; i+=16 ) { a = HASH[0]; b = HASH[1]; c = HASH[2]; d = HASH[3]; e = HASH[4]; f = HASH[5]; g = HASH[6]; h = HASH[7]; for ( var j = 0; j<64; j++) { if (j < 16) W[j] = m[j + i]; else W[j] = safe_add(safe_add(safe_add(Gamma1256(W[j - 2]), W[j - 7]), Gamma0256(W[j - 15])), W[j - 16]); T1 = safe_add(safe_add(safe_add(safe_add(h, Sigma1256(e)), Ch(e, f, g)), K[j]), W[j]); T2 = safe_add(Sigma0256(a), Maj(a, b, c)); h = g; g = f; f = e; e = safe_add(d, T1); d = c; c = b; b = a; a = safe_add(T1, T2); } HASH[0] = safe_add(a, HASH[0]); HASH[1] = safe_add(b, HASH[1]); HASH[2] = safe_add(c, HASH[2]); HASH[3] = safe_add(d, HASH[3]); HASH[4] = safe_add(e, HASH[4]); HASH[5] = safe_add(f, HASH[5]); HASH[6] = safe_add(g, HASH[6]); HASH[7] = safe_add(h, HASH[7]); } return HASH; } function str2binb (str) { var bin = Array(); var mask = (1 << chrsz) - 1; for(var i = 0; i < str.length * chrsz; i += chrsz) { bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i % 32); } return bin; } function Utf8Encode(string) { string = string.replace(/\r\n/g,'\n'); var utftext = ''; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { utftext += String.fromCharCode(c); } else if((c > 127) && (c < 2048)) { utftext += String.fromCharCode((c >> 6) | 192); utftext += String.fromCharCode((c & 63) | 128); } else { utftext += String.fromCharCode((c >> 12) | 224); utftext += String.fromCharCode(((c >> 6) & 63) | 128); utftext += String.fromCharCode((c & 63) | 128); } } return utftext; } function binb2hex (binarray) { var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef'; var str = ''; for(var i = 0; i < binarray.length * 4; i++) { str += hex_tab.charAt((binarray[i>>2] >> ((3 - i % 4)*8+4)) & 0xF) + hex_tab.charAt((binarray[i>>2] >> ((3 - i % 4)*8 )) & 0xF); } return str; } s = Utf8Encode(s); return binb2hex(core_sha256(str2binb(s), s.length * chrsz)); }
The result you're receiving actually are 32 bytes. Let's have a look at an example: console.log(SHA256("test")); returns: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 What we see is a string representation of 32 bytes which results in 64 bytes of individual chars. However a group of two chars is actually one byte, ranging from 0 up to 255 in decimal. 9f (hex) -> 10011111 (binary) -> 159 (decimal) 86 (hex) -> 10000110 (binary) -> 134 (decimal) and so on. If you want to store the 64 character sequence as 'real' 32 bytes, you need to convert pairs of two characters to an 8-bit unsigned integer value (0-255) and put those in a JavaScript typed array. For example ... let hexString = "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"; let unsignedIntegers = hexString.match(/[\dA-F]{2}/gi).map(function(s) { return parseInt(s, 16); }); let typedArray = new Uint8Array(unsignedIntegers); console.log(typedArray); ... gives a 32 bytes Uint8Array.
SHA1 Generated Hashes Do Not Match (JS and C#)
I am trying to create the .NET equivalent of Javascript code below. I've tried what I've shared in the ".NET SHA1" section but it generated different hash outputs. I tried translating javascript code into C# (which I've shared as well) which doesn't work either. What am I doing wrong, how can I get the same hash value generated by javascript function in C# ? .NET SHA1 Hash: public string CreateHash(string a, string b, string c) { string concatenation = string.Concat(a, b, c); SHA1 sha = new SHA1CryptoServiceProvider(); byte[] byt = Encoding.GetEncoding(0).GetBytes(concatenation); byte[] hash = sha.ComputeHash(byt); return Convert.ToBase64String(hash); } Javascript Code: function createHash() { var hashdata = somestringconcat; m.digest.value = encode64(sha1Hash(hashdata)); return 0; } var keyStr = "ABCDEFGHIJKLMNOP" + "QRSTUVWXYZabcdef" + "ghijklmnopqrstuv" + "wxyz0123456789+/" + "="; function encode64(input) { var output = ""; var chr1, chr2, chr3 = ""; var enc1, enc2, enc3, enc4 = ""; var i = 0; do { chr1 = eval('0x' + input.charAt(i++) + input.charAt(i++)); if (i<input.length) chr2 = eval('0x' + input.charAt(i++) + input.charAt(i++)); else i=i+2; if (i<input.length) chr3 = eval('0x' + input.charAt(i++) + input.charAt(i++)); else i=i+2; enc1 = chr1 >> 2; enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); enc4 = chr3 & 63; if (i == input.length + 4) { enc3 = enc4 = 64; } else if (i == input.length + 2) { enc4 = 64; } output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4); chr1 = chr2 = chr3 = ""; enc1 = enc2 = enc3 = enc4 = ""; } while (i < input.length); return output; } function sha1Hash(msg) { // constants [4.2.1] var K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6]; // PREPROCESSING msg += String.fromCharCode(0x80); // add trailing '1' bit to string [5.1.1] // convert string msg into 512-bit/16-integer blocks arrays of ints [5.2.1] var l = Math.ceil(msg.length/4) + 2; // long enough to contain msg plus 2-word length var N = Math.ceil(l/16); // in N 16-int blocks var M = new Array(N); for (var i=0; i<N; i++) { M[i] = new Array(16); for (var j=0; j<16; j++) { // encode 4 chars per integer, big-endian encoding M[i][j] = (msg.charCodeAt(i*64+j*4)<<24) | (msg.charCodeAt(i*64+j*4+1)<<16) | (msg.charCodeAt(i*64+j*4+2)<<8) | (msg.charCodeAt(i*64+j*4+3)); } } // add length (in bits) into final pair of 32-bit integers (big-endian) [5.1.1] // note: most significant word would be ((len-1)*8 >>> 32, but since JS converts // bitwise-op args to 32 bits, we need to simulate this by arithmetic operators M[N-1][14] = ((msg.length-1)*8) / Math.pow(2, 32); M[N-1][14] = Math.floor(M[N-1][14]) M[N-1][15] = ((msg.length-1)*8) & 0xffffffff; // set initial hash value [5.3.1] var H0 = 0x67452301; var H1 = 0xefcdab89; var H2 = 0x98badcfe; var H3 = 0x10325476; var H4 = 0xc3d2e1f0; // HASH COMPUTATION [6.1.2] var W = new Array(80); var a, b, c, d, e; for (var i=0; i<N; i++) { // 1 - prepare message schedule 'W' for (var t=0; t<16; t++) W[t] = M[i][t]; for (var t=16; t<80; t++) W[t] = ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1); // 2 - initialise five working variables a, b, c, d, e with previous hash value a = H0; b = H1; c = H2; d = H3; e = H4; // 3 - main loop for (var t=0; t<80; t++) { var s = Math.floor(t/20); // seq for blocks of 'f' functions and 'K' constants var T = (ROTL(a,5) + f(s,b,c,d) + e + K[s] + W[t]) & 0xffffffff; e = d; d = c; c = ROTL(b, 30); b = a; a = T; } // 4 - compute the new intermediate hash value H0 = (H0+a) & 0xffffffff; // note 'addition modulo 2^32' H1 = (H1+b) & 0xffffffff; H2 = (H2+c) & 0xffffffff; H3 = (H3+d) & 0xffffffff; H4 = (H4+e) & 0xffffffff; } return H0.toHexStr() + H1.toHexStr() + H2.toHexStr() + H3.toHexStr() + H4.toHexStr(); } // // function 'f' [4.1.1] // function f(s, x, y, z) { switch (s) { case 0: return (x & y) ^ (~x & z); case 1: return x ^ y ^ z; case 2: return (x & y) ^ (x & z) ^ (y & z); case 3: return x ^ y ^ z; } } // // rotate left (circular left shift) value x by n positions [3.2.5] // function ROTL(x, n) { return (x<<n) | (x>>>(32-n)); } // // extend Number class with a tailored hex-string method // (note toString(16) is implementation-dependant, and // in IE returns signed numbers when used on full words) // Number.prototype.toHexStr = function() { var s="", v; for (var i=7; i>=0; i--) { v = (this>>>(i*4)) & 0xf; s += v.toString(16); } return s; } C# Translation Attempt: string Sha1Hash(string msg) { // constants [4.2.1] uint[] K = new uint[] { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 }; // PREPROCESSING msg += Convert.ToChar(0x80); // add trailing '1' bit to string [5.1.1] // convert string msg into 512-bit/16-integer blocks arrays of ints [5.2.1] uint l = (uint)Math.Ceiling(msg.Length / 4d) + 2; // long enough to contain msg plus 2-word length uint N = (uint)Math.Ceiling(l / 16d); // in N 16-int blocks uint[][] M = new uint[N][]; for (int i = 0; i < N; i++) { M[i] = new uint[16]; for (int j = 0; j < 16; j++) { // encode 4 chars per integer, big-endian encoding M[i][j] = (uint)((Convert.ToChar(i * 64 + j * 4) << 24) | (Convert.ToChar(i * 64 + j * 4 + 1) << 16) | (Convert.ToChar(i * 64 + j * 4 + 2) << 8) | (Convert.ToChar(i * 64 + j * 4 + 3))); } } // add length (in bits) into final pair of 32-bit integers (big-endian) [5.1.1] // note: most significant word would be ((len-1)*8 >>> 32, but since JS converts // bitwise-op args to 32 bits, we need to simulate this by arithmetic operators M[N - 1][14] = (uint)Math.Floor(((msg.Length - 1) * 8) / Math.Pow(2, 32)); M[N - 1][15] = (uint)((msg.Length - 1) * 8) & 0xffffffff; // set initial hash value [5.3.1] ulong H0 = 0x67452301; ulong H1 = 0xefcdab89; ulong H2 = 0x98badcfe; ulong H3 = 0x10325476; ulong H4 = 0xc3d2e1f0; // HASH COMPUTATION [6.1.2] ulong[] W = new ulong[80]; ulong a, b, c, d, e; for (int i = 0; i < N; i++) { // 1 - prepare message schedule 'W' for (int t = 0; t < 16; t++) W[t] = M[i][t]; for (int t = 16; t < 80; t++) W[t] = ROTL(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); // 2 - initialise five working variables a, b, c, d, e with previous hash value a = H0; b = H1; c = H2; d = H3; e = H4; // 3 - main loop for (int t = 0; t < 80; t++) { ulong s = (ulong)Math.Floor(t / 20d); // seq for blocks of 'f' functions and 'K' constants var T = (ROTL(a, 5) + F(s, b, c, d) + e + K[s] + W[t]) & 0xffffffff; e = d; d = c; c = ROTL(b, 30); b = a; a = T; } // 4 - compute the new intermediate hash value H0 = (H0 + a) & 0xffffffff; // note 'addition modulo 2^32' H1 = (H1 + b) & 0xffffffff; H2 = (H2 + c) & 0xffffffff; H3 = (H3 + d) & 0xffffffff; H4 = (H4 + e) & 0xffffffff; } return string.Concat(ToHexStr(H0), ToHexStr(H1), ToHexStr(H2), ToHexStr(H3), ToHexStr(H4)); } ulong ROTL(ulong x, int n) { return ((x << n) | (x >> (32 - n))); } string ToHexStr(ulong param) { return ""; // } ulong F(ulong s, ulong x, ulong y, ulong z) { switch (s) { case 0: return (x & y) ^ (~x & z); case 1: return x ^ y ^ z; case 2: return (x & y) ^ (x & z) ^ (y & z); case 3: return x ^ y ^ z; } return 0; } const string keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; string Encode64(string input) { string output = ""; int chr1 = 0; int chr2 = 0; int chr3 = 0; int enc1, enc2, enc3, enc4 = 0; var i = 0; do { chr1 = Convert.ToInt32(("0x" + input[i++] + input[i++]), 16); if (i < input.Length) chr2 = Convert.ToInt32(("0x" + input[i++] + input[i++]), 16); else i = i + 2; if (i < input.Length) chr3 = Convert.ToInt32(("0x" + input[i++] + input[i++]), 16); else i = i + 2; enc1 = chr1 >> 2; enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); enc4 = chr3 & 63; if (i == input.Length + 4) { enc3 = enc4 = 64; } else if (i == input.Length + 2) { enc4 = 64; } output = output + keyStr[enc1] + keyStr[enc2] + keyStr[enc3] + keyStr[enc4]; chr1 = chr2 = chr3 = 0; enc1 = enc2 = enc3 = enc4 = 0; } while (i < input.Length); return output; }
TEA Encryption in Javascript
I am trying to convert Objective C TEA encryption to Javascript but inside one of the inner loops, numbers doesn't match against Objective C version Here is the Objective C version #define TIMES 32 #implementation NSData (NSData_extend) // Encrypt NSData with pwdKey -(NSData*)addTEA:(const unsigned int *)pwdkey { unsigned char * ch = (unsigned char*)[self bytes]; int n = 8-self.length%8; char byte[self.length+n]; char cc = n; for (int i=0; i<n; i++) { if (i==0) { byte[i] = cc; } else{ byte[i] = 0; } } for (int i=0; i<self.length; i++) { byte[n+i] = ch[i]; } int delta = 0x9e3779b9; int a = pwdkey[0]; int b = pwdkey[1]; int c = pwdkey[2]; int d = pwdkey[3]; unsigned char newbyte[self.length+n]; for (int offset=0; offset<self.length+n; offset += 8) { int y = [self ByteTounint:byte[offset+3]] | [self ByteTounint:byte[offset+2]]<<8 | [self ByteTounint:byte[offset+1]]<<16 | [self ByteTounint:byte[offset+0]]<<24; int z = [self ByteTounint:byte[offset+7]] | [self ByteTounint:byte[offset+6]]<<8 | [self ByteTounint:byte[offset+5]]<<16 | [self ByteTounint:byte[offset+4]]<<24; int sum = 0; for (int i=0; i<TIMES; i++) { sum += delta; y += ((z<<4) + a) ^ (z + sum) ^ ((z>>5) + b); z += ((y<<4) + c) ^ (y + sum) ^ ((y>>5) + d); } newbyte[offset+7] = z & 0x000000ff; newbyte[offset+6] = (z & 0x0000ff00) >> 8; newbyte[offset+5] = (z & 0x00ff0000) >> 16; newbyte[offset+4] = (z & 0xff000000) >> 24; newbyte[offset+3] = y & 0x000000ff; newbyte[offset+2] = (y & 0x0000ff00) >> 8; newbyte[offset+1] = (y & 0x00ff0000) >> 16; newbyte[offset+0] = (y & 0xff000000) >> 24; } NSData * resultData = [NSData dataWithBytes:newbyte length:self.length+n]; return resultData; } // Decrypt NSData with pwdKey -(NSData*)subtractTEA:(const unsigned int *)pwdkey { unsigned char * byte = (unsigned char*)[self bytes]; int delta = 0x9e3779b9; int a = pwdkey[0]; int b = pwdkey[1]; int c = pwdkey[2]; int d = pwdkey[3]; unsigned char newbyte[self.length]; for (int offset=0; offset<self.length; offset += 8) { int y = [self ByteTounint:byte[offset+3]] | [self ByteTounint:byte[offset+2]]<<8 | [self ByteTounint:byte[offset+1]]<<16 | [self ByteTounint:byte[offset+0]]<<24; int z = [self ByteTounint:byte[offset+7]] | [self ByteTounint:byte[offset+6]]<<8 | [self ByteTounint:byte[offset+5]]<<16 | [self ByteTounint:byte[offset+4]]<<24; int sum = 0; if (TIMES == 32) { sum = 0xC6EF3720; } else if (TIMES == 16){ sum = 0xE3779B90; } else{ sum = delta * TIMES; } for (int i=0; i<TIMES; i++) { z -= ((y<<4) + c) ^ (y + sum) ^ ((y>>5) + d); y -= ((z<<4) + a) ^ (z + sum) ^ ((z>>5) + b); sum -= delta; } newbyte[offset+7] = z & 0x000000ff; newbyte[offset+6] = (z & 0x0000ff00) >> 8; newbyte[offset+5] = (z & 0x00ff0000) >> 16; newbyte[offset+4] = (z & 0xff000000) >> 24; newbyte[offset+3] = y & 0x000000ff; newbyte[offset+2] = (y & 0x0000ff00) >> 8; newbyte[offset+1] = (y & 0x00ff0000) >> 16; newbyte[offset+0] = (y & 0xff000000) >> 24; } int n = newbyte[0]; unsigned char ch[self.length-n]; for (int i=0; i<self.length-n; i++) { ch[i] = newbyte[i+n]; } NSData * resultData = [NSData dataWithBytes:ch length:self.length-n]; return resultData; } - (int)ByteTounint:(int)byte { if (byte<0) { return (byte+256); } return byte; } My JavaScript version TEA.prototype.encrypt = function(src,pwdkey) { var TIMES = 32; var n = 8 - (src.length % 8); var byte = Buffer.alloc(src.length + n); var cc = n; for (var i = 0; i < n; i++) { if (i == 0) { byte[i] = cc; } else { byte[i] = 0; } } for (var j = 0; j < src.length; j++) { byte.write( src[j],(n+j)); } var delta = 0x9e3779b9; var a = pwdkey.readInt32LE(0); var b = pwdkey.readInt32LE(1); var c = pwdkey.readInt32LE(2); var d = pwdkey.readInt32LE(3); var newbyte = Buffer.alloc(src.length + n); for (var offset = 0; offset < src.length + n; offset += 8) { var y = ByteTounint(byte[offset + 3]) | ByteTounint(byte[offset + 2] << 8) | ByteTounint(byte[offset + 1] << 16) | ByteTounint(byte[offset + 0]) << 24; var z = ByteTounint(byte[offset + 7]) | ByteTounint(byte[offset + 6]) << 8 | ByteTounint(byte[offset + 5]) << 16 | ByteTounint(byte[offset + 4]) << 24; var sum = 0; for(var i=0;i<TIMES;i++) { sum += delta; sum >>>= 0; y += (((z<<4)+a) ^ (z+sum) ^ ((z>>>5)+b)) >>> 0; z += (((y<<4)+c) ^ (y+sum) ^ ((y>>>5)+d)) >>> 0; } newbyte.writeInt8((z & 0x000000ff),(offset + 7)); newbyte.writeInt8(((z & 0x0000ff00) >> 8),(offset + 6)); newbyte.writeInt8(((z & 0x00ff0000) >> 16),(offset + 5)); newbyte.writeInt8(((z & 0xff000000) >> 24),(offset + 4)); newbyte.writeInt8((y & 0x000000ff),(offset + 3)); newbyte.writeInt8(((y & 0x0000ff00) >> 8),(offset + 2)); newbyte.writeInt8(((y & 0x00ff0000) >> 16),(offset + 1)); newbyte.writeInt8(((y & 0xff000000) >> 24),(offset + 0)); } return newbyte }; function ByteTounint(byte) { if (byte<0) { return (byte+256); } return byte; } Usage for JavaScript Version var pwdkey = new Buffer("4523F10F214365873248738902EFCDAB","hex"); var dene = tea.encrypt("params={\"method\":\"waybill.querywaybill\",\"requstParams\":{\"memNo\":\"\",\"waybillNo\":\"606447740110\"}}",pwdkey); Usage and Sample Result from Objective version NSString *keyString = #"4523F10F214365873248738902EFCDAB"; NSData *keyData = [NSData dataWithHexString:keyString]; const unsigned char *src = (const unsigned char *)[key bytes]; NSString *str = #"params={\"method\":\"waybill.querywaybill\",\"requstParams\":{\"memNo\":\"\",\"waybillNo\":\"606447740110\"}}"; NSData *data = [NSData dataWithBytes:str.UTF8String length:str.length]; NSData * result2 = [data addTEA:src]; NSLog(#"%#",result2); // prints 167da396 9b183f2e d12ac3f5 5083a581..... My version starts to give wrong values inside for(var i=0;i<TIMES;i++) loop. Then it crashes during newbyte.writeInt8 part.
Finally, I made it work. Here is a working version which correctly encrypts and decrypts any size of text. function ByteTounint(byte) { if (byte<0) { return (byte+256); } return byte; } TEA.prototype.decrypt = function(src,pwdkey) { var TIMES = 32; var delta = 0x9e3779b9; var a = pwdkey.readUInt32LE(0); var b = pwdkey.readUInt32LE(4); var c = pwdkey.readUInt32LE(8); var d = pwdkey.readUInt32LE(12); var newbyte = Buffer.alloc(src.length); for (var offset=0; offset<src.length; offset += 8) { var y = ByteTounint(src[offset + 3]) | ByteTounint(src[offset + 2]) << 8 | ByteTounint(src[offset + 1]) << 16 | ByteTounint(src[offset + 0]) << 24; var z = ByteTounint(src[offset + 7]) | ByteTounint(src[offset + 6]) << 8 | ByteTounint(src[offset + 5]) << 16 | ByteTounint(src[offset + 4]) << 24; var sum = 0; if (TIMES == 32) { sum = 0xC6EF3720; } else if (TIMES == 16) { sum = 0xE3779B90; } else { sum = delta * TIMES; } for (var i = 0; i < TIMES; i++) { z = (z - (( ( (y<<4) + c) & 0xFFFFFFFF) ^ ( (y + sum) & 0xFFFFFFFF ) ^ ( ((y >> 5) + d ) & 0xFFFFFFFF))) & 0xFFFFFFFF y = (y - (( ( (z<<4) + a) & 0xFFFFFFFF) ^ ( (z + sum) & 0xFFFFFFFF ) ^ ( ((z >> 5) + b ) & 0xFFFFFFFF))) & 0xFFFFFFFF sum = (sum - delta) & 0xFFFFFFFF; } newbyte.writeInt32BE((y & 0xFFFFFFFF),offset); newbyte.writeInt32BE((z & 0xFFFFFFFF),(offset+4)); } var n = newbyte[0]; var ch = Buffer.alloc(src.length - n); for (var i=0; i<src.length-n; i++) { ch[i] = newbyte[i+n]; } return ch; }; TEA.prototype.encrypt = function(src,pwdkey) { var TIMES = 32; var n = 8 - (src.length % 8); var byte = Buffer.alloc(src.length + n); var cc = n; for (var i = 0; i < n; i++) { if (i == 0) { byte[i] = cc; } else { byte[i] = 0; } } for (var j = 0; j < src.length; j++) { byte.write( src[j],(n+j)); } var delta = 0x9e3779b9; var a = pwdkey.readUInt32LE(0); var b = pwdkey.readUInt32LE(4); var c = pwdkey.readUInt32LE(8); var d = pwdkey.readUInt32LE(12); var newbyte = Buffer.alloc(src.length + n); for (var offset = 0; offset < src.length + n; offset += 8) { var y = ByteTounint(byte[offset + 3]) | ByteTounint(byte[offset + 2]) << 8 | ByteTounint(byte[offset + 1]) << 16 | ByteTounint(byte[offset + 0]) << 24; var z = ByteTounint(byte[offset + 7]) | ByteTounint(byte[offset + 6]) << 8 | ByteTounint(byte[offset + 5]) << 16 | ByteTounint(byte[offset + 4]) << 24; var sum = 0; for(var i=0;i<TIMES;i++) { sum = (sum + delta) & 0xFFFFFFFF; y = (y + (( ( (z<<4) + a) & 0xFFFFFFFF) ^ ( (z + sum) & 0xFFFFFFFF ) ^ ( ((z >> 5) + b ) & 0xFFFFFFFF))) & 0xFFFFFFFF; z = (z + (( ( (y<<4) + c) & 0xFFFFFFFF) ^ ( (y + sum) & 0xFFFFFFFF ) ^ ( ((y >> 5) + d ) & 0xFFFFFFFF))) & 0xFFFFFFFF } newbyte.writeInt32BE((y & 0xFFFFFFFF),offset); newbyte.writeInt32BE((z & 0xFFFFFFFF),(offset+4)); } return newbyte }; ```
Generating the same SHA1 UUID in golang and Javascript
I have what I thought was a pretty simply question. I'm using this code to generate a SHA1 uuid in Golang: namespace := uuid.Parse("b9cfdb9d-f741-4e1f-89ae-fac6b2a5d740") sha := uuid.NewSHA1(namespace, []byte("something")) fmt.Println(sha.String()) Now I want to generate the same UUID in javascript, and I thought it would be as easy as something like this: var hash = CryptoJS.SHA1("b9cfdb9d-f741-4e1f-89ae-fac6b2a5d740" + "something") // chomp the hash into a UUID string However, I'm running into serious issues. It seems that the uuid.Parse function in Golang is running this parsing function that converts the namespace to a 16-byte array, so even though I use the same SHA1 algorithm in Javascript, I'm not getting the same output. I'v been messing around with doing the same in JS, but I'm stumped. Any smart crypto people in here that can help me?
Well, that only took me a month. var SHA1Generator = { hex_chr: "0123456789abcdef", hex: function (num) { var str = ""; for (var j = 7; j >= 0; j--) str += this.hex_chr.charAt((num >> (j * 4)) & 0x0F); return str; }, str2blks_SHA1: function (str) { var nblk = ((str.length + 8) >> 6) + 1; var blks = new Array(nblk * 16); for (var i = 0; i < nblk * 16; i++) blks[i] = 0; for (i = 0; i < str.length; i++) blks[i >> 2] |= str.charCodeAt(i) << (24 - (i % 4) * 8); blks[i >> 2] |= 0x80 << (24 - (i % 4) * 8); blks[nblk * 16 - 1] = str.length * 8; return blks; }, add: function (x, y) { var lsw = (x & 0xFFFF) + (y & 0xFFFF); var msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xFFFF); }, rol: function (num, cnt) { return (num << cnt) | (num >>> (32 - cnt)); }, ft: function (t, b, c, d) { if (t < 20) return (b & c) | ((~b) & d); if (t < 40) return b ^ c ^ d; if (t < 60) return (b & c) | (b & d) | (c & d); return b ^ c ^ d; }, kt: function (t) { return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : (t < 60) ? -1894007588 : -899497514; }, calcSHA1FromByte: function(byteArr) { var str = ''; for(var i=0; i<byteArr.length; i++) str += String.fromCharCode(byteArr[i]); return this.calcSHA1(str); }, calcSHA1: function (str) { if (str != '') { var x = this.str2blks_SHA1(str); var w = new Array(80); var a = 1732584193; var b = -271733879; var c = -1732584194; var d = 271733878; var e = -1009589776; for (var i = 0; i < x.length; i += 16) { var olda = a; var oldb = b; var oldc = c; var oldd = d; var olde = e; for (var j = 0; j < 80; j++) { if (j < 16) w[j] = x[i + j]; else w[j] = this.rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); t = this.add(this.add(this.rol(a, 5), this.ft(j, b, c, d)), this.add(this.add(e, w[j]), this.kt(j))); e = d; d = c; c = this.rol(b, 30); b = a; a = t; } a = this.add(a, olda); b = this.add(b, oldb); c = this.add(c, oldc); d = this.add(d, oldd); e = this.add(e, olde); } return this.hex(a) + this.hex(b) + this.hex(c) + this.hex(d) + this.hex(e); } else { return ''; } } }; function stringToByteArray(str) { var bytes = []; for (var i = 0; i < str.length; ++i) { bytes.push(str.charCodeAt(i)); } return bytes; } function uuidToByteArray(hex) { // If this is a uuid, remove the dashes hex = hex.replace(/-/g, ""); // convert each hex number into a string representation // of the byte integer. var bytes = []; for(var i = 0; i < hex.length; i += 2) { bytes.push(parseInt(hex.substring(i, i+2),16)); } return bytes; } function sha1ToUUID5(hash) { var uuid = hash.substring(0, 8) + '-' + hash.substring(8, 12) + // four most significant bits holds version number 5 '-' + ((parseInt(hash.substring(12, 16), 16) & 0x0fff) | 0x5000).toString(16) + // two most significant bits holds zero and one for variant DCE1.1 '-' + ((parseInt(hash.substring(16, 20), 16) & 0x3fff) | 0x8000).toString(16) + '-' + hash.substring(20, 32); //12 digits return uuid; } var namespace = "e75a36a9-3323-40dd-a7d1-1c57ad2aa3cd" var id = "event154" var namespaceBytes = uuidToByteArray(namespace); var idBytes = stringToByteArray(id); var allBytes = namespaceBytes.concat(idBytes); console.log("ORG 4505612c-c323-5d6f-b5cc-b7f362b9ba55") console.log("NEW " + sha1ToUUID5(SHA1Generator.calcSHA1FromByte(allBytes)))
Get SHA1 checksum of byte array in JavaScript?
So I need to get a SHA1 hash of a byte array in javascript (Will be array of integer values 0-255), I can't seem to figure out how to achive this. I need to be able to get the same result as the C# SHA1.ComputeHash function, meaning I input a byte array and get a 20 byte array back representing the resulting checksum. Does anyone have a way to achieve this? Thanks!
Use the calcSHA1FromByte function to get the sha1 of a byte array var SHA1Generator = { hex_chr: "0123456789abcdef", hex: function (num) { var str = ""; for (var j = 7; j >= 0; j--) str += this.hex_chr.charAt((num >> (j * 4)) & 0x0F); return str; }, str2blks_SHA1: function (str) { var nblk = ((str.length + 8) >> 6) + 1; var blks = new Array(nblk * 16); for (var i = 0; i < nblk * 16; i++) blks[i] = 0; for (i = 0; i < str.length; i++) blks[i >> 2] |= str.charCodeAt(i) << (24 - (i % 4) * 8); blks[i >> 2] |= 0x80 << (24 - (i % 4) * 8); blks[nblk * 16 - 1] = str.length * 8; return blks; }, add: function (x, y) { var lsw = (x & 0xFFFF) + (y & 0xFFFF); var msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xFFFF); }, rol: function (num, cnt) { return (num << cnt) | (num >>> (32 - cnt)); }, ft: function (t, b, c, d) { if (t < 20) return (b & c) | ((~b) & d); if (t < 40) return b ^ c ^ d; if (t < 60) return (b & c) | (b & d) | (c & d); return b ^ c ^ d; }, kt: function (t) { return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : (t < 60) ? -1894007588 : -899497514; }, calcSHA1FromByte: function(byteArr) { var str = ''; for(var i=0; i<byteArr.length; i++) str += String.fromCharCode(byteArr[i]); return this.calcSHA1(str); }, calcSHA1: function (str) { if (str != '') { var x = this.str2blks_SHA1(str); var w = new Array(80); var a = 1732584193; var b = -271733879; var c = -1732584194; var d = 271733878; var e = -1009589776; for (var i = 0; i < x.length; i += 16) { var olda = a; var oldb = b; var oldc = c; var oldd = d; var olde = e; for (var j = 0; j < 80; j++) { if (j < 16) w[j] = x[i + j]; else w[j] = this.rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); t = this.add(this.add(this.rol(a, 5), this.ft(j, b, c, d)), this.add(this.add(e, w[j]), this.kt(j))); e = d; d = c; c = this.rol(b, 30); b = a; a = t; } a = this.add(a, olda); b = this.add(b, oldb); c = this.add(c, oldc); d = this.add(d, oldd); e = this.add(e, olde); } return this.hex(a) + this.hex(b) + this.hex(c) + this.hex(d) + this.hex(e); } else { return ''; } } }; // your byte array var byteArr = ['100','101','114']; var sha1 = SHA1Generator.calcSHA1FromByte(byteArr);