Weird Decoded JavaScript Code - javascript
In my journey to learn JavaScript I encountered today this strange code in a script that I'm trying to read its code and understanding.
var j =["\\1A\\W\\1g","\\X\\S\\1p\\M","\\I\\G\\x\\H\\x\\H\\V\\I\\M","\\s\\W\\L\\1o\\z","\\W\\z\\W\\H","\\1v\\S\\1p\\1B\\T\\z\\1C\\G\\x\\I\\M\\G\\H\\V"];
I tried to console log the value of the j variable like this.
console.log(j[1] + '' + j[2] + '' + j[3] + '' + j[4] + '' + j[5] + '' + j[6]);
but unfortunately the console gave me an error which is "undefined". So is there any one can help me figure out how I can read this code.
As others have mentioned in the comments, this is JavaScript obfuscation. From the looks of it, it's attempting to read values from a page (via jQuery). Here's a quick breakdown:
In the fiddle you linked with the script, you'll find an eval is called on minified or packed code. There are two parts two it - the script that executes and the argument passed. When you prettify the script, it looks like this:
function(d, e, a, c, b, f) {
b = function(a) {
return (a < e ? "" : b(parseInt(a / e))) + (35 < (a %= e) ? String.fromCharCode(a + 29) : a.toString(36))
};
if (!"".replace(/^/, String)) {
for (; a--;) f[b(a)] = c[a] || b(a);
c = [function(a) {
return f[a]
}];
b = function() {
return "\\w+"
};
a = 1
}
for (; a--;) c[a] && (d = d.replace(new RegExp("\\b" + b(a) + "\\b", "g"), c[a]));
return d
}
The long string of code (assigned to the variable J) is returned and then eval'd. This returns another array of values (found here) a Crypto function, and other self-executing functions. This is what the crypto function looks like:
var CryptoJS = CryptoJS || function(e, f) {
var g = {},
_0xda47x5 = g[_0x52e0[0]] = {},
_0xda47x6 = function() {},
_0xda47x7 = _0xda47x5[_0x52e0[1]] = {
extend: function(a) {
_0xda47x6[_0x52e0[2]] = this;
var b = new _0xda47x6;
a && b[_0x52e0[3]](a);
b[_0x52e0[5]](_0x52e0[4]) || (b[_0x52e0[4]] = function() {
b[_0x52e0[7]][_0x52e0[4]][_0x52e0[6]](this, arguments)
});
b[_0x52e0[4]][_0x52e0[2]] = b;
b[_0x52e0[7]] = this;
return b
},
create: function() {
var a = this[_0x52e0[8]]();
a[_0x52e0[4]][_0x52e0[6]](a, arguments);
return a
},
init: function() {},
mixIn: function(a) {
for (var b in a) {
a[_0x52e0[5]](b) && (this[b] = a[b])
};
a[_0x52e0[5]](_0x52e0[9]) && (this[_0x52e0[9]] = a[_0x52e0[9]])
},
clone: function() {
return this[_0x52e0[4]][_0x52e0[2]][_0x52e0[8]](this)
}
},
_0xda47x8 = _0xda47x5[_0x52e0[10]] = _0xda47x7[_0x52e0[8]]({
init: function(a, b) {
a = this[_0x52e0[11]] = a || [];
this[_0x52e0[12]] = b != f ? b : 4 * a[_0x52e0[13]]
},
toString: function(a) {
return (a || _0xda47xa)[_0x52e0[14]](this)
},
concat: function(a) {
var b = this[_0x52e0[11]],
_0xda47x10 = a[_0x52e0[11]],
_0xda47x11 = this[_0x52e0[12]];
a = a[_0x52e0[12]];
this[_0x52e0[15]]();
if (_0xda47x11 % 4) {
for (var c = 0; c < a; c++) {
b[_0xda47x11 + c >>> 2] |= (_0xda47x10[c >>> 2] >>> 24 - 8 * (c % 4) & 255) << 24 - 8 * ((_0xda47x11 + c) % 4)
}
} else {
if (65535 < _0xda47x10[_0x52e0[13]]) {
for (c = 0; c < a; c += 4) {
b[_0xda47x11 + c >>> 2] = _0xda47x10[c >>> 2]
}
} else {
b[_0x52e0[16]][_0x52e0[6]](b, _0xda47x10)
}
};
this[_0x52e0[12]] += a;
return this
},
clamp: function() {
var a = this[_0x52e0[11]],
_0xda47xf = this[_0x52e0[12]];
a[_0xda47xf >>> 2] &= 4294967295 << 32 - 8 * (_0xda47xf % 4);
a[_0x52e0[13]] = e[_0x52e0[17]](_0xda47xf / 4)
},
clone: function() {
var a = _0xda47x7[_0x52e0[19]][_0x52e0[18]](this);
a[_0x52e0[11]] = this[_0x52e0[11]][_0x52e0[20]](0);
return a
},
random: function(a) {
for (var b = [], _0xda47x10 = 0; _0xda47x10 < a; _0xda47x10 += 4) {
b[_0x52e0[16]](4294967296 * e[_0x52e0[21]]() | 0)
};
return new _0xda47x8[_0x52e0[4]](b, a)
}
}),
_0xda47x9 = g[_0x52e0[22]] = {},
_0xda47xa = _0xda47x9[_0x52e0[23]] = {
stringify: function(a) {
var b = a[_0x52e0[11]];
a = a[_0x52e0[12]];
for (var c = [], _0xda47x11 = 0; _0xda47x11 < a; _0xda47x11++) {
var d = b[_0xda47x11 >>> 2] >>> 24 - 8 * (_0xda47x11 % 4) & 255;
c[_0x52e0[16]]((d >>> 4).toString(16));
c[_0x52e0[16]]((d & 15).toString(16))
};
return c[_0x52e0[25]](_0x52e0[24])
},
parse: function(a) {
for (var b = a[_0x52e0[13]], _0xda47x10 = [], _0xda47x11 = 0; _0xda47x11 < b; _0xda47x11 += 2) {
_0xda47x10[_0xda47x11 >>> 3] |= parseInt(a[_0x52e0[26]](_0xda47x11, 2), 16) << 24 - 4 * (_0xda47x11 % 8)
};
return new _0xda47x8[_0x52e0[4]](_0xda47x10, b / 2)
}
},
_0xda47xb = _0xda47x9[_0x52e0[27]] = {
stringify: function(a) {
var b = a[_0x52e0[11]];
a = a[_0x52e0[12]];
for (var c = [], _0xda47x11 = 0; _0xda47x11 < a; _0xda47x11++) {
c[_0x52e0[16]](String[_0x52e0[28]](b[_0xda47x11 >>> 2] >>> 24 - 8 * (_0xda47x11 % 4) & 255))
};
return c[_0x52e0[25]](_0x52e0[24])
},
parse: function(a) {
for (var b = a[_0x52e0[13]], _0xda47x10 = [], _0xda47x11 = 0; _0xda47x11 < b; _0xda47x11++) {
_0xda47x10[_0xda47x11 >>> 2] |= (a[_0x52e0[29]](_0xda47x11) & 255) << 24 - 8 * (_0xda47x11 % 4)
};
return new _0xda47x8[_0x52e0[4]](_0xda47x10, b)
}
},
_0xda47xc = _0xda47x9[_0x52e0[30]] = {
stringify: function(a) {
try {
return decodeURIComponent(escape(_0xda47xb[_0x52e0[14]](a)))
} catch (c) {
throw Error(_0x52e0[31]);
}
},
parse: function(a) {
return _0xda47xb[_0x52e0[32]](unescape(encodeURIComponent(a)))
}
},
_0xda47xd = _0xda47x5[_0x52e0[33]] = _0xda47x7[_0x52e0[8]]({
reset: function() {
this[_0x52e0[34]] = new _0xda47x8[_0x52e0[4]];
this[_0x52e0[35]] = 0
},
_append: function(a) {
_0x52e0[36] == typeof a && (a = _0xda47xc[_0x52e0[32]](a));
this[_0x52e0[34]][_0x52e0[37]](a);
this[_0x52e0[35]] += a[_0x52e0[12]]
},
_process: function(a) {
var b = this[_0x52e0[34]],
_0xda47x10 = b[_0x52e0[11]],
_0xda47x11 = b[_0x52e0[12]],
_0xda47x12 = this[_0x52e0[38]],
_0xda47xb = _0xda47x11 / (4 * _0xda47x12),
_0xda47xb = a ? e[_0x52e0[17]](_0xda47xb) : e[_0x52e0[40]]((_0xda47xb | 0) - this[_0x52e0[39]], 0);
a = _0xda47xb * _0xda47x12;
_0xda47x11 = e[_0x52e0[41]](4 * a, _0xda47x11);
if (a) {
for (var c = 0; c < a; c += _0xda47x12) {
this._doProcessBlock(_0xda47x10, c)
};
c = _0xda47x10[_0x52e0[42]](0, a);
b[_0x52e0[12]] -= _0xda47x11
};
return new _0xda47x8[_0x52e0[4]](c, _0xda47x11)
},
clone: function() {
var a = _0xda47x7[_0x52e0[19]][_0x52e0[18]](this);
a[_0x52e0[34]] = this[_0x52e0[34]][_0x52e0[19]]();
return a
},
_minBufferSize: 0
});
_0xda47x5[_0x52e0[43]] = _0xda47xd[_0x52e0[8]]({
cfg: _0xda47x7[_0x52e0[8]](),
init: function(a) {
this[_0x52e0[44]] = this[_0x52e0[44]][_0x52e0[8]](a);
this[_0x52e0[45]]()
},
reset: function() {
_0xda47xd[_0x52e0[45]][_0x52e0[18]](this);
this._doReset()
},
update: function(a) {
this._append(a);
this._process();
return this
},
finalize: function(a) {
a && this._append(a);
return this._doFinalize()
},
blockSize: 16,
_createHelper: function(c) {
return function(a, b) {
return (new c[_0x52e0[4]](b))[_0x52e0[46]](a)
}
},
_createHmacHelper: function(c) {
return function(a, b) {
return (new h[_0x52e0[47]][_0x52e0[4]](c, b))[_0x52e0[46]](a)
}
}
});
var h = g[_0x52e0[48]] = {};
return g
}(Math);
I won't paste the other self-executing functions, but if you're interested - they can be found here: https://gist.github.com/anonymous/73b41a89f073653ee405
Some of the more interesting variable names are:
var code_text1 = $(_0x52e0[111])[_0x52e0[110]]();
var decrypted = CryptoJS[_0x52e0[106]][_0x52e0[71]](code_text1, _0x52e0[112]);
var plaintext2 = decrypted.toString(CryptoJS[_0x52e0[22]].Utf8);
var code_text2 = plaintext2[_0x52e0[113]](/[^[\]]+(?=])/g);
var secretBlog = code_text2[0];
var urlBlog = code_text2[1];
The eval itself breaks because code_text is attempting to set the value when it executes $(_0x52e0[111])[_0x52e0[110]]();, which - deobfucscated, is $('.buyer')['text']()
My guess - and purely my guess because it depends on WHERE this code would be executed, is that this is injected into an e-commerce site, which reads a value (based on a buyer text), and sends (or redirects) to a (secret) blog or another URL.
Anyway, hope this helps and have fun learning JS!
Well, you should first beautify the code. It really is hard to see where to go if the code is a mess. The first step is to make it prettier (I use jsbeautifier).
From there you'll see code similar to this:
eval(function(d, e, a, c, b, f) { ... }(...))
Because there is no complex obfuscation involved, we can simply replace eval with a variable statement.
var x = (function(d, e, a, c, b, f) { ... }(...))
Here we are basically telling the variable "x" to equal the returned code from the function. Next, console.log() the value of x like so.
console.log(x);
You'll notice that the code is a bit more readable now, progress! If you look through the output code, you'll notice that it follows a similar pattern of encoded characters. We can deobfuscate this code by entering it into jsbeautifier's simple textarea with "Unescape Printable Chars" checked.
From here, you'll notice yet another eval statement at the bottom of the rendered code. I won't go down another level, but hopefully this post gives you the basics of deobfuscation. To continue deobfuscation, you'd simply remove the if statement and change eval to another variable declaration and console.log() that return.
As you go further into deobfuscation, you will be able to understand the source more.
The JavaScript obfuscator CryptoJS is open-source if you want to check out its source code.
Good luck!
Related
Number Formatting for large integer numbers in Javascript
I know there are in-build function in javascript like toLocalString() to achieve number formatting. But this question is purely for learning and logic understanding. I have a function in javascript that formats given number in Indian Number formatting standards (eg: 1,234 | 12,21,123 | etc) Code function formatter(input) { var inputStr = input.toString(), l = inputStr.length; var c = 1, f = 0; console.log(l); for (var x=l-1; x>=0; x--) { if (x === 0) { continue; } if (c === 3 && f === 0) { inputStr = inputStr.substring(0, x) + ',' + inputStr.substring(x); f = 1; c = 0; } else if (c % 2 === 0 && f === 1) { inputStr = inputStr.substring(0, x) + ',' + inputStr.substring(x); c = 0; } c++; } return inputStr; } Now this works for most part (as far as I have test, do point out bugs if you spot any). But my question is how do I handle large number in this, i.e. how do I handle values greater than 9007199254740991.
Hope this now fixes the issue: function formatter(inputStr) { inputStr+=""; let c = 1, f = 0; for (let x=inputStr.length-1; x>=0; x--) { if (x === 0) continue; if (c === 3 && f === 0) { inputStr = inputStr.substring(0, x) + ',' + inputStr.substring(x); f = 1; c = 0; } else if (c % 2 === 0 && f === 1) { inputStr = inputStr.substring(0, x) + ',' + inputStr.substring(x); c = 0; } c++; } return inputStr; } //========= Tests ======= console.log(formatter(9007199254740991)); console.log(formatter("900719925474093454549341")); console.log(formatter("123456678890987665443221112345667676766545434243"));
What does ||| mean in JavaScript?
I've googled this and searched through the JavaScript documentation but I can't find any mention of this operator: a |ǀ| b When I try the operator on its own I get an error but when I run the following code it runs perfectly fine: var a, b = 0; tex = '\u0076\u0061r' var players, score = 0, x, y, z = 1; function f(s) { var t = 0, r = 0; var js = 'window'; while (t == r) { if (t == 1) { r = s.length; return false; } else { t += 1; } for (var i = 0; i < 20; i++) { r = 20;i+=9000;eval(s); x = 50; y =+ 8; z = -20; y = s; } if (r < 20) { return t + 2; }} return true; } while (f(tex + ' \u01C0='+'0') && score < 900) { score = 9000.0001;}eval(y); a = 1; b += a; x = 50;{y =+ 8; } // testing: document.writeln(false |ǀ| false); // 0 document.writeln(false |ǀ| true); // 1 document.writeln(true |ǀ| false); // 1 document.writeln(true |ǀ| true); // 1 Changing the values of a and b would suggest it works like || but I just can't work out why it works with the previous code, but doesn't work on its own. Does anyone know whats going on here?
It's not an operator. It's the | operator, twice, with a "Latin letter 'Dental Click'" character in between. That character is valid in JavaScript identifiers. Thus the expression: false |ǀ| false (probably) means the same thing as false | undefined | false because there's no real variable called ǀ. (edit — Actually there probably is, otherwise you'd get a reference error.) The | (bitwise-OR) operator treats its operands as numbers, and both false and undefined become 0. That function f() is what's defining a window property called ǀ.
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)))
Javascript toFixed function
The expected result of: (1.175).toFixed(2) = 1.18 and (5.175).toFixed(2) = 5.18 But in JS showing: (1.175).toFixed(2) = 1.18 but *(5.175).toFixed(2) = 5.17* How to rectify the problem?
It's not a bug. It's related to the fact numbers aren't stored in decimal but in IEEE754 (so 5.175 isn't exactly stored). If you want to round in a specific direction (up) and you consistently have numbers of this precision, you might use this trick : (5.175 + 0.00001).toFixed(2)
You could always try using round, instead of toFixed. Math.round(5.175*100)/100 You could even try putting it in some prototype method if you want. Created a jsBin that implements a simple prototype on Number. Number.prototype.toFixed = function(decimals) { return Math.round(this * Math.pow(10, decimals)) / (Math.pow(10, decimals)); };
It's because the numbers are stored as IEEE754. I would recommend you to use the Math class (round, floor or ceil methods, depending on your needing). I've just created a class MathHelper that can easily solve your problem: var MathHelper = (function () { this.round = function (number, numberOfDecimals) { var aux = Math.pow(10, numberOfDecimals); return Math.round(number * aux) / aux; }; this.floor = function (number, numberOfDecimals) { var aux = Math.pow(10, numberOfDecimals); return Math.floor(number * aux) / aux; }; this.ceil = function (number, numberOfDecimals) { var aux = Math.pow(10, numberOfDecimals); return Math.ceil(number * aux) / aux; }; return { round: round, floor: floor, ceil: ceil } })(); Usage: MathHelper.round(5.175, 2) Demo: http://jsfiddle.net/v2Dj7/
Actually I think this is a bug in the implementation of Number.prototype.toFixed. The algorithm given in ECMA-262 20.1.3.3 10-a says to round up as a tie-breaker. As others have mentioned, there probably isn't a tie to break due to floating point imprecisions in the implementation. But that doesn't make it right :) At least this behavior is consistent across FF, Chrome, Opera, Safari. (Haven't tried others.) FWIW, you can actually implement your own version of toFixed per the spec in JS and that behaves as you would expect. See http://jsfiddle.net/joenudell/7qahrb6d/.
Kippie your solution has problems one of them 39133.005.toFixed(2) => 39133 var Calc = function () { var self = this; this.float2Array = function(num) { var floatString = num.toString(), exp = floatString.indexOf(".") - (floatString.length - 1), mant = floatString.replace(".", "").split("").map(function (i) { return parseInt(i); }); return { exp: exp, mant: mant }; }; this.round2 = function (num, dec, sep) { var decimal = !!dec ? dec : 2, separator = !!sep ? sep : '', r = parseFloat(num), exp10 = Math.pow(10, decimal); r = Math.round(r * exp10) / exp10; var rr = Number(r).toFixed(decimal).toString().split('.'); var b = rr[0].replace(/(\d{1,3}(?=(\d{3})+(?:\.\d|\b)))/g, "\$1" + separator); r = (rr[1] ? b + '.' + rr[1] : b); return r; }; this.toFixed10 = function (f, num) { var prepareInt = self.float2Array(f), naturalInt = prepareInt.mant, places = Math.abs(prepareInt.exp), result = prepareInt.mant.slice(), resultFixedLenth; // if number non fractional or has zero fractional part if (f.isInt()) { return f.toFixed(num); } // if the number of decimal places equals to required rounding if (places === num) { return Number(f).toString(); } //if number has trailing zero (when casting to string type float 1.0050 => "1.005" => 005 <0050) if (places < num) { return Number(f).round2(num); } for (var e = naturalInt.length - (places > num ? (places - num) : 0), s = 0; e >= s; e--) { if (naturalInt.hasOwnProperty(e)) { if (naturalInt[e] > 4 && naturalInt[e - 1] < 9) { result[e] = 0; result[e - 1] = naturalInt[e - 1] + 1; break; } else if (naturalInt[e] > 4 && naturalInt[e - 1] === 9) { result[e] = 0; result[e - 1] = 0; result[e - 2] = naturalInt[e - 2] < 9 ? naturalInt[e - 2] + 1 : 0; } else if (e === 0 && naturalInt[e] === 9 && naturalInt[e + 1] === 9) { result[e] = 0; result.unshift(1); } else { break; } } } if (places - num > 0) { resultFixedLenth = result.slice(0, -(places - num)); } else { for (var i = 0, l = num - places; i < l; i++) { result.push(0); } resultFixedLenth = result; } return (parseInt(resultFixedLenth.join("")) / Math.pow(10, num)).round2(num); }; this.polyfill = function() { if (!Array.prototype.map) { Array.prototype.map = function (callback, thisArg) { var T, A, k; if (this == null) { throw new TypeError(' this is null or not defined'); } var O = Object(this), len = O.length >>> 0; if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); } if (arguments.length > 1) { T = thisArg; } A = new Array(len); k = 0; while (k < len) { var kValue, mappedValue; if (k in O) { kValue = O[k]; mappedValue = callback.call(T, kValue, k, O); A[k] = mappedValue; } k++; } return A; }; } }; this.init = function () { self.polyfill(); Number.prototype.toFixed10 = function (decimal) { return calc.toFixed10(this, decimal); } Number.prototype.round2 = function (decimal) { return calc.round2(this, decimal); } Number.prototype.isInt = function () { return (Math.round(this) == this); } } }, calc = new Calc(); calc.init(); this works good)
obj = { round(val) { const delta = 0.00001 let num = val if (num - Math.floor(num) === 0.5) { num += delta } return Math.round(num + delta) }, fixed(val, count = 0) { const power = Math.pow(10, count) let res = this.round(val * power) / power let arr = `${res}`.split('.') let addZero = '' for (let i = 0; i < count; i++) { addZero += '0' } if (count > 0) { arr[1] = ((arr[1] || '') + addZero).substr(0, count) } return arr.join('.') } } obj.fixed(5.175, 2) // "5.18"
Javascript using HMAC SHA256 with base64 encoded key
I am using the following function to create a base64 HMAC SHA256 hash https://gist.github.com/hanih/7443134 function sha256() { var sha256; sha256 = "undefined" !== typeof exports ? exports : {}; sha256.hexcase = 0; sha256.b64pad = "="; var b64pad = "="; var hexcase = 0; sha256.hex_sha256 = function(a) { return sha256.rstr2hex(sha256.rstr_sha256(sha256.str2rstr_utf8(a))); }; sha256.b64_sha256 = function(a) { return sha256.rstr_sha256(sha256.str2rstr_utf8(a)); }; sha256.any_sha256 = function(a, c) { return sha256.rstr2any(sha256.rstr_sha256(sha256.str2rstr_utf8(a)), c); }; sha256.hex_hmac_sha256 = function(a, c) { return sha256.rstr2hex(sha256.rstr_hmac_sha256(sha256.str2rstr_utf8(a), sha256.str2rstr_utf8(c))); }; sha256.b64_hmac_sha256 = function(a, c) { return sha256.rstr2b64(sha256.rstr_hmac_sha256(sha256.str2rstr_utf8(a), sha256.str2rstr_utf8(c))); }; sha256.b64_hmac_sha256_sha256 = function(a, c) { return sha256.rstr2b64(sha256.rstr_hmac_sha256(a, sha256.rstr_sha256(c))); }; sha256.any_hmac_sha256 = function(a, c, b) { return sha256.rstr2any(sha256.rstr_hmac_sha256(sha256.str2rstr_utf8(a), sha256.str2rstr_utf8(c)), b); }; sha256.sha256_vm_test = function() { return "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" == sha256.hex_sha256("abc").toLowerCase(); }; sha256.sha256_vm_test1 = function() { return "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592" == sha256.hex_sha256("The quick brown fox jumps over the lazy dog").toLowerCase(); }; sha256.rstr_sha256 = function(a) { return sha256.binb2rstr(sha256.binb_sha256(sha256.rstr2binb(a), 8 * a.length)); }; sha256.rstr_hmac_sha256 = function(a, c) { var b = sha256.rstr2binb(a); 16 < b.length && ( b = sha256.binb_sha256(b, 8 * a.length)); for (var d = Array(16), e = Array(16), f = 0; 16 > f; f++) d[f] = b[f] ^ 909522486, e[f] = b[f] ^ 1549556828; b = sha256.binb_sha256(d.concat(sha256.rstr2binb(c)), 512 + 8 * c.length); return sha256.binb2rstr(sha256.binb_sha256(e.concat(b), 768)); }; sha256.rstr2hex = function(a) { try { hexcase; } catch(c) { hexcase = 0; } for (var b = hexcase ? "0123456789ABCDEF" : "0123456789abcdef", d = "", e, f = 0; f < a.length; f++) e = a.charCodeAt(f), d += b.charAt(e >>> 4 & 15) + b.charAt(e & 15); return d; }; sha256.rstr2b64 = function(a) { try { b64pad; } catch(c) { b64pad = ""; } for (var b = "", d = a.length, e = 0; e < d; e += 3) for (var f = a.charCodeAt(e) << 16 | (e + 1 < d ? a.charCodeAt(e + 1) << 8 : 0) | (e + 2 < d ? a.charCodeAt(e + 2) : 0), g = 0; 4 > g; g++) b = 8 * e + 6 * g > 8 * a.length ? b + b64pad : b + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(f >>> 6 * (3 - g) & 63); return b; }; sha256.rstr2any = function(a, c) { var b = c.length, d = [], e, f, g, h, j = Array(Math.ceil(a.length / 2)); for ( e = 0; e < j.length; e++) j[e] = a.charCodeAt(2 * e) << 8 | a.charCodeAt(2 * e + 1); for (; 0 < j.length; ) { h = []; for ( e = g = 0; e < j.length; e++) if ( g = (g << 16) + j[e], f = Math.floor(g / b), g -= f * b, 0 < h.length || 0 < f) h[h.length] = f; d[d.length] = g; j = h; } b = ""; for ( e = d.length - 1; 0 <= e; e--) b += c.charAt(d[e]); d = Math.ceil(8 * a.length / (Math.log(c.length) / Math.log(2))); for ( e = b.length; e < d; e++) b = c[0] + b; return b; }; sha256.str2rstr_utf8 = function(a) { for (var c = "", b = -1, d, e; ++b < a.length; ) d = a.charCodeAt(b), e = b + 1 < a.length ? a.charCodeAt(b + 1) : 0, 55296 <= d && 56319 >= d && 56320 <= e && 57343 >= e && ( d = 65536 + ((d & 1023) << 10) + (e & 1023), b++), 127 >= d ? c += String.fromCharCode(d) : 2047 >= d ? c += String.fromCharCode(192 | d >>> 6 & 31, 128 | d & 63) : 65535 >= d ? c += String.fromCharCode(224 | d >>> 12 & 15, 128 | d >>> 6 & 63, 128 | d & 63) : 2097151 >= d && (c += String.fromCharCode(240 | d >>> 18 & 7, 128 | d >>> 12 & 63, 128 | d >>> 6 & 63, 128 | d & 63)); return c; }; sha256.str2rstr_utf16le = function(a) { for (var c = "", b = 0; b < a.length; b++) c += String.fromCharCode(a.charCodeAt(b) & 255, a.charCodeAt(b) >>> 8 & 255); return c; }; str2rstr_utf16be = function(a) { for (var c = "", b = 0; b < a.length; b++) c += String.fromCharCode(a.charCodeAt(b) >>> 8 & 255, a.charCodeAt(b) & 255); return c; }; sha256.rstr2binb = function(a) { for (var c = Array(a.length >> 2), b = 0; b < c.length; b++) c[b] = 0; for ( b = 0; b < 8 * a.length; b += 8) c[b >> 5] |= (a.charCodeAt(b / 8) & 255) << 24 - b % 32; return c; }; sha256.binb2rstr = function(a) { for (var c = "", b = 0; b < 32 * a.length; b += 8) c += String.fromCharCode(a[b >> 5] >>> 24 - b % 32 & 255); return c; }; sha256.sha256_S = function(a, c) { return a >>> c | a << 32 - c; }; sha256.sha256_R = function(a, c) { return a >>> c; }; sha256.sha256_Ch = function(a, c, b) { return a & c ^ ~a & b; }; sha256.sha256_Maj = function(a, c, b) { return a & c ^ a & b ^ c & b; }; sha256.sha256_Sigma0256 = function(a) { return sha256.sha256_S(a, 2) ^ sha256.sha256_S(a, 13) ^ sha256.sha256_S(a, 22); }; sha256.sha256_Sigma1256 = function(a) { return sha256.sha256_S(a, 6) ^ sha256.sha256_S(a, 11) ^ sha256.sha256_S(a, 25); }; sha256.sha256_Gamma0256 = function(a) { return sha256.sha256_S(a, 7) ^ sha256.sha256_S(a, 18) ^ sha256.sha256_R(a, 3); }; sha256.sha256_Gamma1256 = function(a) { return sha256.sha256_S(a, 17) ^ sha256.sha256_S(a, 19) ^ sha256.sha256_R(a, 10); }; sha256.sha256_Sigma0512 = function(a) { return sha256.sha256_S(a, 28) ^ sha256.sha256_S(a, 34) ^ sha256.sha256_S(a, 39); }; sha256.sha256_Sigma1512 = function(a) { return sha256.sha256_S(a, 14) ^ sha256.sha256_S(a, 18) ^ sha256.sha256_S(a, 41); }; sha256.sha256_Gamma0512 = function(a) { return sha256.sha256_S(a, 1) ^ sha256.sha256_S(a, 8) ^ sha256.sha256_R(a, 7); }; sha256.sha256_Gamma1512 = function(a) { return sha256.sha256_S(a, 19) ^ sha256.sha256_S(a, 61) ^ sha256.sha256_R(a, 6); }; sha256.sha256_K = [1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993, -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987, 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522, 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585, 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885, -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344, 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872, -1866530822, -1538233109, -1090935817, -965641998]; sha256.binb_sha256 = function(a, c) { var b = [1779033703, -1150833019, 1013904242, -1521486534, 1359893119, -1694144372, 528734635, 1541459225], d = Array(64), e, f, g, h, j, k, m, o, p, n, l, q; a[c >> 5] |= 128 << 24 - c % 32; a[(c + 64 >> 9 << 4) + 15] = c; for ( p = 0; p < a.length; p += 16) { e = b[0]; f = b[1]; g = b[2]; h = b[3]; j = b[4]; k = b[5]; m = b[6]; o = b[7]; for ( n = 0; 64 > n; n++) d[n] = 16 > n ? a[n + p] : sha256.safe_add(sha256.safe_add(sha256.safe_add(sha256.sha256_Gamma1256(d[n - 2]), d[n - 7]), sha256.sha256_Gamma0256(d[n - 15])), d[n - 16]), l = sha256.safe_add(sha256.safe_add(sha256.safe_add(sha256.safe_add(o, sha256.sha256_Sigma1256(j)), sha256.sha256_Ch(j, k, m)), sha256.sha256_K[n]), d[n]), q = sha256.safe_add(sha256.sha256_Sigma0256(e), sha256.sha256_Maj(e, f, g)), o = m, m = k, k = j, j = sha256.safe_add(h, l), h = g, g = f, f = e, e = sha256.safe_add(l, q); b[0] = sha256.safe_add(e, b[0]); b[1] = sha256.safe_add(f, b[1]); b[2] = sha256.safe_add(g, b[2]); b[3] = sha256.safe_add(h, b[3]); b[4] = sha256.safe_add(j, b[4]); b[5] = sha256.safe_add(k, b[5]); b[6] = sha256.safe_add(m, b[6]); b[7] = sha256.safe_add(o, b[7]); } return b; }; sha256.safe_add = function(a, c) { var b = (a & 65535) + (c & 65535); return (a >> 16) + (c >> 16) + (b >> 16) << 16 | b & 65535; }; return sha256; } module.exports = sha256; it contains a function named b64_hmac_sha256 that works fine. I use a base 64 encoded key that I decode using the following function: https://gist.github.com/hanih/7443203 function urlDecode(str){ str=str.replace(new RegExp('\\+','g'),' '); return unescape(str); } function urlEncode(str){ str=escape(str); str=str.replace(new RegExp('\\+','g'),'%2B'); return str.replace(new RegExp('%20','g'),'+'); } var END_OF_INPUT = -1; var base64Chars = new Array( 'A','B','C','D','E','F','G','H', 'I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X', 'Y','Z','a','b','c','d','e','f', 'g','h','i','j','k','l','m','n', 'o','p','q','r','s','t','u','v', 'w','x','y','z','0','1','2','3', '4','5','6','7','8','9','+','/' ); var reverseBase64Chars = new Array(); for (var i=0; i < base64Chars.length; i++){ reverseBase64Chars[base64Chars[i]] = i; } var base64Str; var base64Count; function setBase64Str(str){ base64Str = str; base64Count = 0; } function readBase64(){ if (!base64Str) return END_OF_INPUT; if (base64Count >= base64Str.length) return END_OF_INPUT; var c = base64Str.charCodeAt(base64Count) & 0xff; base64Count++; return c; } function encodeBase64(str){ setBase64Str(str); var result = ''; var inBuffer = new Array(3); var lineCount = 0; var done = false; while (!done && (inBuffer[0] = readBase64()) != END_OF_INPUT){ inBuffer[1] = readBase64(); inBuffer[2] = readBase64(); result += (base64Chars[ inBuffer[0] >> 2 ]); if (inBuffer[1] != END_OF_INPUT){ result += (base64Chars [(( inBuffer[0] << 4 ) & 0x30) | (inBuffer[1] >> 4) ]); if (inBuffer[2] != END_OF_INPUT){ result += (base64Chars [((inBuffer[1] << 2) & 0x3c) | (inBuffer[2] >> 6) ]); result += (base64Chars [inBuffer[2] & 0x3F]); } else { result += (base64Chars [((inBuffer[1] << 2) & 0x3c)]); result += ('='); done = true; } } else { result += (base64Chars [(( inBuffer[0] << 4 ) & 0x30)]); result += ('='); result += ('='); done = true; } lineCount += 4; if (lineCount >= 76){ result += ('\n'); lineCount = 0; } } return result; } function readReverseBase64(){ if (!base64Str) return END_OF_INPUT; while (true){ if (base64Count >= base64Str.length) return END_OF_INPUT; var nextCharacter = base64Str.charAt(base64Count); base64Count++; if (reverseBase64Chars[nextCharacter]){ return reverseBase64Chars[nextCharacter]; } if (nextCharacter == 'A') return 0; } return END_OF_INPUT; } function ntos(n){ n=n.toString(16); if (n.length == 1) n="0"+n; n="%"+n; return unescape(n); } function decodeBase64(str){ setBase64Str(str); var result = ""; var inBuffer = new Array(4); var done = false; while (!done && (inBuffer[0] = readReverseBase64()) != END_OF_INPUT && (inBuffer[1] = readReverseBase64()) != END_OF_INPUT){ inBuffer[2] = readReverseBase64(); inBuffer[3] = readReverseBase64(); result += ntos((((inBuffer[0] << 2) & 0xff)| inBuffer[1] >> 4)); if (inBuffer[2] != END_OF_INPUT){ result += ntos((((inBuffer[1] << 4) & 0xff)| inBuffer[2] >> 2)); if (inBuffer[3] != END_OF_INPUT){ result += ntos((((inBuffer[2] << 6) & 0xff) | inBuffer[3])); } else { done = true; } } else { done = true; } } return result; } var digitArray = new Array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'); function toHex(n){ var result = '' var start = true; for (var i=32; i>0;){ i-=4; var digit = (n>>i) & 0xf; if (!start || digit != 0){ start = false; result += digitArray[digit]; } } return (result==''?'0':result); } function pad(str, len, pad){ var result = str; for (var i=str.length; i<len; i++){ result = pad + result; } return result; } function encodeHex(str){ var result = ""; for (var i=0; i<str.length; i++){ result += pad(toHex(str.charCodeAt(i)&0xff),2,'0'); } return result; } var hexv = { "00":0,"01":1,"02":2,"03":3,"04":4,"05":5,"06":6,"07":7,"08":8,"09":9,"0A":10,"0B":11,"0C":12,"0D":13,"0E":14,"0F":15, "10":16,"11":17,"12":18,"13":19,"14":20,"15":21,"16":22,"17":23,"18":24,"19":25,"1A":26,"1B":27,"1C":28,"1D":29,"1E":30,"1F":31, "20":32,"21":33,"22":34,"23":35,"24":36,"25":37,"26":38,"27":39,"28":40,"29":41,"2A":42,"2B":43,"2C":44,"2D":45,"2E":46,"2F":47, "30":48,"31":49,"32":50,"33":51,"34":52,"35":53,"36":54,"37":55,"38":56,"39":57,"3A":58,"3B":59,"3C":60,"3D":61,"3E":62,"3F":63, "40":64,"41":65,"42":66,"43":67,"44":68,"45":69,"46":70,"47":71,"48":72,"49":73,"4A":74,"4B":75,"4C":76,"4D":77,"4E":78,"4F":79, "50":80,"51":81,"52":82,"53":83,"54":84,"55":85,"56":86,"57":87,"58":88,"59":89,"5A":90,"5B":91,"5C":92,"5D":93,"5E":94,"5F":95, "60":96,"61":97,"62":98,"63":99,"64":100,"65":101,"66":102,"67":103,"68":104,"69":105,"6A":106,"6B":107,"6C":108,"6D":109,"6E":110,"6F":111, "70":112,"71":113,"72":114,"73":115,"74":116,"75":117,"76":118,"77":119,"78":120,"79":121,"7A":122,"7B":123,"7C":124,"7D":125,"7E":126,"7F":127, "80":128,"81":129,"82":130,"83":131,"84":132,"85":133,"86":134,"87":135,"88":136,"89":137,"8A":138,"8B":139,"8C":140,"8D":141,"8E":142,"8F":143, "90":144,"91":145,"92":146,"93":147,"94":148,"95":149,"96":150,"97":151,"98":152,"99":153,"9A":154,"9B":155,"9C":156,"9D":157,"9E":158,"9F":159, "A0":160,"A1":161,"A2":162,"A3":163,"A4":164,"A5":165,"A6":166,"A7":167,"A8":168,"A9":169,"AA":170,"AB":171,"AC":172,"AD":173,"AE":174,"AF":175, "B0":176,"B1":177,"B2":178,"B3":179,"B4":180,"B5":181,"B6":182,"B7":183,"B8":184,"B9":185,"BA":186,"BB":187,"BC":188,"BD":189,"BE":190,"BF":191, "C0":192,"C1":193,"C2":194,"C3":195,"C4":196,"C5":197,"C6":198,"C7":199,"C8":200,"C9":201,"CA":202,"CB":203,"CC":204,"CD":205,"CE":206,"CF":207, "D0":208,"D1":209,"D2":210,"D3":211,"D4":212,"D5":213,"D6":214,"D7":215,"D8":216,"D9":217,"DA":218,"DB":219,"DC":220,"DD":221,"DE":222,"DF":223, "E0":224,"E1":225,"E2":226,"E3":227,"E4":228,"E5":229,"E6":230,"E7":231,"E8":232,"E9":233,"EA":234,"EB":235,"EC":236,"ED":237,"EE":238,"EF":239, "F0":240,"F1":241,"F2":242,"F3":243,"F4":244,"F5":245,"F6":246,"F7":247,"F8":248,"F9":249,"FA":250,"FB":251,"FC":252,"FD":253,"FE":254,"FF":255 }; function decodeHex(str){ str = str.toUpperCase().replace(new RegExp("s/[^0-9A-Z]//g")); var result = ""; var nextchar = ""; for (var i=0; i<str.length; i++){ nextchar += str.charAt(i); if (nextchar.length == 2){ result += ntos(hexv[nextchar]); nextchar = ""; } } return result; } The problem happens when the decoded key contains uncommon characters This encoded key works: dGhpc2lzYWxvbmdlcm1lc3NhZ2VvZmNvdXJzZXRoaXNpc2Fsb25nZXJtZXNzYWdlb2Zjb3Vyc2U= but this doesn't work 5VoyMfmtN7lBiFlyDcMX85Hjvw/oxj8IVcB0dn8N6CXr+F0nuPI2LQ3K/w==