What was used to compress this code? [closed] - javascript

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I'm trying to understand what's going on in this code: http://js1k.com/2013-spring/demo/1396
This doesn't look like it's been minified or encoded in Base62 to me. When I paste it in Vim weird characters appear everywhere. Is there a way I can decode it?

This has been produced using the Data URI Scheme
https://en.wikipedia.org/wiki/Data_URI_scheme
The javascript file has been supplied as a URI which contains the file's contents. Lots of codes have been URL escaped, hence all the \s. And it may have been minified before that.
The data here is a whole HTML document. The first part is the start of the HTML file:
javascript:
'<!doctype html>\n<html>\n\t<head>\n\t\t<title>JS1k, 1k demo submission [1396]</title>\n\t\t<meta charset="utf-8" />\n\t</head>\n\t<body>\n\t\t<canvas id="c"></canvas>\n\t\t
After that an inline script:
var b = document.body;\n\t\t\tvar c = document.getElementsByTagName(\'canvas\')[0];\n\t\t\tvar a = c.getContext(\'2d\');\n\t\t\tdocument.body.clientWidth; // fix bug in webkit: http://qfox.nl/weblog/218\n\t\t
which you can easily decode as:
var b = document.body;
var c = document.getElementsByTagName('canvas')[0];
var a = c.getContext('2d');
document.body.clientWidth; // fix bug in webkit: http://qfox.nl/weblog/218
etc etc.

End of code there is script, which is used to decode code
for (Y = 0; $ = 'zxqj`_^ZWVUQONMKJIHGCA#8$ ' [Y++];)
with(_.split($)) _ = join(pop());
eval(_)
I put this firebug ... instead of eval(_) put console.log( _ )
code is
e = null;
T = function (b) {
c.width = c.height = 19 * s;
a.fillStyle = "#DB5";
a.fillRect(0, 0, c.width, c.width);
for (i = s / 2; i < c.width; i += s) a.moveTo(i, s / 2), a.lineTo(i, c.width - s / 2), a.moveTo(s / 2, i), a.lineTo(c.width - s / 2, i);
a.stroke();
b && (f = 19 * ~~(0.5 + (b.clientY - s / 2) / s) + ~~(0.5 + (b.clientX - s / 2) / s), t[f] == e && (t[f] = d, (L(f) | !(L(f + 1) & L(f - 1) & L(f + 19) & L(f - 19))) & (!m | f != n) ? "d" == b.type[5] ? (m = 0, u = f, d = !d, E(f + 1, d), E(f - 1, d), E(f + 19, d), E(f - 19, d), E(f)) : (t[f] = e, a.beginPath(), a.arc(~~(0.5 + (b.clientX - s / 2) / s) * s + s / 2, ~~ (0.5 + (b.clientY - s / 2) / s) * s + s / 2, s / 2 - 1, 0, 6.3, 1), a.strokeStyle = a.fillStyle = "rgba(0,0,0,0.3)", d && (a.fillStyle = "rgba(255,255,255,0.3)"), a.fill(), a.stroke()) : t[f] = e));
a.strokeStyle = "#000";
a.fillStyle = "#000";
for (i = s / 2 + 75; i < c.width; i += 6 * s) for (h = s / 2 + 75; h < c.width; h += 6 * s) a.beginPath(), a.arc(i, h, 2, 0, 6.3, 1), a.fill();
m && (t[n] = d, L(u) || (a.beginPath(), a.rect(n % 19 * s + s / 2 / 2, ~~ (n / 19) * s + s / 2 / 2, s / 2, s / 2), a.stroke()), t[n] = e);
for (i = t.length; i--;) t[i] != e && (a.beginPath(), a.arc(i % 19 * s + s / 2, ~~ (i / 19) * s + s / 2, s / 2 - 1, 0, 6.3, 1), a.fillStyle = "#000", t[i] && (a.fillStyle = "#FFF"), a.fill(), a.stroke())
};
E = function (b, g) {
if (!L(b, g)) {
1 == w.length && (m = 1, n = b);
for (i = w.length; i--;) t[w[i]] = e
}
};
L = function (b, g) {
w = [];
g == e && (g = t[b]);
l = function (b) {
for (i = w.length; i--;) if (w[i] == b) return;
w.push(b);
0 != (b + 1) % 19 && t[b + 1] == g && l(b + 1);
0 != b % 19 && t[b - 1] == g && l(b - 1);
t[b + 19] == g && l(b + 19);
t[b - 19] == g && l(b - 19)
};
if (g != e && g == t[b]) l(b);
else return 1;
for (i = w.length; i--;) if (0 != (w[i] + 1) % 19 && t[w[i] + 1] == e || 0 != w[i] % 19 && t[w[i] - 1] == e || 342 > w[i] && t[w[i] + 19] == e || 19 <= w[i] && t[w[i] - 19] == e) return 1;
return 0
};
s = 25;
d = m = n = 0;
c.addEventListener("mousemove", T);
c.addEventListener("mousedown", T);
t = [];
T();

Related

Submitting an OTP to Microsoft API with RSA encryption

I'm gonna keep this short and clean.
I need to submit an OTP to Microsoft's API. This OTP however, is encrypted on the client side with some JavaScript function and then submitted to the API. That's the Microsoft's script for encryption (the original script has over 2000 lines, I only left functions used by Encrypt() function. I believe it is just plain RSA encryption in JavaScript but I could be wrong):
function Encrypt(e, t, i, r) {
var n = [];
switch (i.toLowerCase()) {
case "saproof":
if (null == t) {
return null
}
n = PackageSADataForProof(t);
break;
case "newpwd":
if (null == r) {
return null
}
}
if (null == n || "undefined" == typeof n) {
return n
}
if ("undefined" != typeof Key && void 0 !== parseRSAKeyFromString) {
var o = parseRSAKeyFromString(Key)
}
var s = RSAEncrypt(n, o, randomNum);
return s
}
function PackageSADataForProof(e) {
var t, i = [], r = 0;
for (t = 0; t < e.length; t++) {
i[r++] = 127 & e.charCodeAt(t),
i[r++] = (65280 & e.charCodeAt(t)) >> 8
}
return i
}
function parseRSAKeyFromString(e) {
var t = e.indexOf(";");
if (0 > t) {
return null
}
var i = e.substr(0, t)
, r = e.substr(t + 1)
, n = i.indexOf("=");
if (0 > n) {
return null
}
var o = i.substr(n + 1);
if (n = r.indexOf("="),
0 > n) {
return null
}
var s = r.substr(n + 1)
, a = new Object;
return a.n = hexStringToMP(s),
a.e = parseInt(o, 16),
a
}
function hexStringToMP(e) {
var t, i, r = Math.ceil(e.length / 4), n = new JSMPnumber;
for (n.size = r,
t = 0; r > t; t++) {
i = e.substr(4 * t, 4),
n.data[r - 1 - t] = parseInt(i, 16)
}
return n
}
function RSAEncrypt(e, t) {
for (var i = [], r = 42, n = 2 * t.n.size - r, o = 0; o < e.length; o += n) {
if (o + n >= e.length) {
var s = RSAEncryptBlock(e.slice(o), t, randomNum);
s && (i = s.concat(i))
} else {
var s = RSAEncryptBlock(e.slice(o, o + n), t, randomNum);
s && (i = s.concat(i))
}
}
var a = byteArrayToBase64(i);
return a
}
function RSAEncryptBlock(e, t, i) {
var r = t.n
, n = t.e
, o = e.length
, s = 2 * r.size
, a = 42;
if (o + a > s) {
return null
}
applyPKCSv2Padding(e, s, i),
e = e.reverse();
var l = byteArrayToMP(e)
, d = modularExp(l, n, r);
d.size = r.size;
var h = mpToByteArray(d);
return h = h.reverse()
}
function JSMPnumber() {
this.size = 1,
this.data = [],
this.data[0] = 0
}
function byteArrayToMP(e) {
var t = new JSMPnumber
, i = 0
, r = e.length
, n = r >> 1;
for (i = 0; n > i; i++) {
t.data[i] = e[2 * i] + (e[1 + 2 * i] << 8)
}
return r % 2 && (t.data[i++] = e[r - 1]),
t.size = i,
t
}
function modularExp(e, t, i) {
for (var r = [], n = 0; t > 0; ) {
r[n] = 1 & t,
t >>>= 1,
n++
}
for (var o = duplicateMP(e), s = n - 2; s >= 0; s--) {
o = modularMultiply(o, o, i),
1 == r[s] && (o = modularMultiply(o, e, i))
}
return o
}
function modularMultiply(e, t, i) {
var r = multiplyMP(e, t)
, n = divideMP(r, i);
return n.r
}
function multiplyMP(e, t) {
var i = new JSMPnumber;
i.size = e.size + t.size;
var r, n;
for (r = 0; r < i.size; r++) {
i.data[r] = 0
}
var o = e.data
, s = t.data
, a = i.data;
if (e == t) {
for (r = 0; r < e.size; r++) {
a[2 * r] += o[r] * o[r]
}
for (r = 1; r < e.size; r++) {
for (n = 0; r > n; n++) {
a[r + n] += 2 * o[r] * o[n]
}
}
} else {
for (r = 0; r < e.size; r++) {
for (n = 0; n < t.size; n++) {
a[r + n] += o[r] * s[n]
}
}
}
return normalizeJSMP(i),
i
}
function normalizeJSMP(e) {
var t, i, r, n, o;
for (r = e.size,
i = 0,
t = 0; r > t; t++) {
n = e.data[t],
n += i,
o = n,
i = Math.floor(n / 65536),
n -= 65536 * i,
e.data[t] = n
}
}
function removeLeadingZeroes(e) {
for (var t = e.size - 1; t > 0 && 0 == e.data[t--]; ) {
e.size--
}
}
function divideMP(e, t) {
var i = e.size
, r = t.size
, n = t.data[r - 1]
, o = t.data[r - 1] + t.data[r - 2] / 65536
, s = new JSMPnumber;
s.size = i - r + 1,
e.data[i] = 0;
for (var a = i - 1; a >= r - 1; a--) {
var l = a - r + 1
, d = Math.floor((65536 * e.data[a + 1] + e.data[a]) / o);
if (d > 0) {
var h = multiplyAndSubtract(e, d, t, l);
for (0 > h && (d--,
multiplyAndSubtract(e, d, t, l)); h > 0 && e.data[a] >= n; ) {
h = multiplyAndSubtract(e, 1, t, l),
h > 0 && d++
}
}
s.data[l] = d
}
removeLeadingZeroes(e);
var u = {
"q": s,
"r": e
};
return u
}
function multiplyAndSubtract(e, t, i, r) {
var n, o = e.data.slice(0), s = 0, a = e.data;
for (n = 0; n < i.size; n++) {
var l = s + i.data[n] * t;
s = l >>> 16,
l -= 65536 * s,
l > a[n + r] ? (a[n + r] += 65536 - l,
s++) : a[n + r] -= l
}
return s > 0 && (a[n + r] -= s),
a[n + r] < 0 ? (e.data = o.slice(0),
-1) : 1
}
function applyPKCSv2Padding(e, t, i) {
var r, n = e.length, o = [218, 57, 163, 238, 94, 107, 75, 13, 50, 85, 191, 239, 149, 96, 24, 144, 175, 216, 7, 9], s = t - n - 40 - 2, a = [];
for (r = 0; s > r; r++) {
a[r] = 0
}
a[s] = 1;
var l = o.concat(a, e)
, d = [];
for (r = 0; 20 > r; r++) {
d[r] = Math.floor(256 * Math.random())
}
d = SHA1(d.concat(i));
var h = MGF(d, t - 21)
, u = XORarrays(l, h)
, c = MGF(u, 20)
, p = XORarrays(d, c)
, f = [];
for (f[0] = 0,
f = f.concat(p, u),
r = 0; r < f.length; r++) {
e[r] = f[r]
}
}
function MGF(e, t) {
if (t > 4096) {
return null
}
var i = e.slice(0)
, r = i.length;
i[r++] = 0,
i[r++] = 0,
i[r++] = 0,
i[r] = 0;
for (var n = 0, o = []; o.length < t; ) {
i[r] = n++,
o = o.concat(SHA1(i))
}
return o.slice(0, t)
}
function XORarrays(e, t) {
if (e.length != t.length) {
return null
}
for (var i = [], r = e.length, n = 0; r > n; n++) {
i[n] = e[n] ^ t[n]
}
return i
}
function SHA1(e) {
var t, i = e.slice(0);
PadSHA1Input(i);
var r = {
"A": 1732584193,
"B": 4023233417,
"C": 2562383102,
"D": 271733878,
"E": 3285377520
};
for (t = 0; t < i.length; t += 64) {
SHA1RoundFunction(r, i, t)
}
var n = [];
return wordToBytes(r.A, n, 0),
wordToBytes(r.B, n, 4),
wordToBytes(r.C, n, 8),
wordToBytes(r.D, n, 12),
wordToBytes(r.E, n, 16),
n
}
function wordToBytes(e, t, i) {
var r;
for (r = 3; r >= 0; r--) {
t[i + r] = 255 & e,
e >>>= 8
}
}
function PadSHA1Input(e) {
var t, i = e.length, r = i, n = i % 64, o = 55 > n ? 56 : 120;
for (e[r++] = 128,
t = n + 1; o > t; t++) {
e[r++] = 0
}
var s = 8 * i;
for (t = 1; 8 > t; t++) {
e[r + 8 - t] = 255 & s,
s >>>= 8
}
}
function SHA1RoundFunction(e, t, i) {
var r, n, o, s = 1518500249, a = 1859775393, l = 2400959708, d = 3395469782, h = [], u = e.A, c = e.B, p = e.C, f = e.D, m = e.E;
for (n = 0,
o = i; 16 > n; n++,
o += 4) {
h[n] = t[o] << 24 | t[o + 1] << 16 | t[o + 2] << 8 | t[o + 3] << 0
}
for (n = 16; 80 > n; n++) {
h[n] = rotateLeft(h[n - 3] ^ h[n - 8] ^ h[n - 14] ^ h[n - 16], 1)
}
var g;
for (r = 0; 20 > r; r++) {
g = rotateLeft(u, 5) + (c & p | ~c & f) + m + h[r] + s & 4294967295,
m = f,
f = p,
p = rotateLeft(c, 30),
c = u,
u = g
}
for (r = 20; 40 > r; r++) {
g = rotateLeft(u, 5) + (c ^ p ^ f) + m + h[r] + a & 4294967295,
m = f,
f = p,
p = rotateLeft(c, 30),
c = u,
u = g
}
for (r = 40; 60 > r; r++) {
g = rotateLeft(u, 5) + (c & p | c & f | p & f) + m + h[r] + l & 4294967295,
m = f,
f = p,
p = rotateLeft(c, 30),
c = u,
u = g
}
for (r = 60; 80 > r; r++) {
g = rotateLeft(u, 5) + (c ^ p ^ f) + m + h[r] + d & 4294967295,
m = f,
f = p,
p = rotateLeft(c, 30),
c = u,
u = g
}
e.A = e.A + u & 4294967295,
e.B = e.B + c & 4294967295,
e.C = e.C + p & 4294967295,
e.D = e.D + f & 4294967295,
e.E = e.E + m & 4294967295
}
function rotateLeft(e, t) {
var i = e >>> 32 - t
, r = (1 << 32 - t) - 1
, n = e & r;
return n << t | i
}
function hexStringToMP(e) {
var t, i, r = Math.ceil(e.length / 4), n = new JSMPnumber;
for (n.size = r,
t = 0; r > t; t++) {
i = e.substr(4 * t, 4),
n.data[r - 1 - t] = parseInt(i, 16)
}
return n
}
function duplicateMP(e) {
var t = new JSMPnumber;
return t.size = e.size,
t.data = e.data.slice(0),
t
}
function mpToByteArray(e) {
var t = []
, i = 0
, r = e.size;
for (i = 0; r > i; i++) {
t[2 * i] = 255 & e.data[i];
var n = e.data[i] >>> 8;
t[2 * i + 1] = n
}
return t
}
function byteArrayToBase64(e) {
var t, i, r = e.length, n = "";
for (t = r - 3; t >= 0; t -= 3) {
i = e[t] | e[t + 1] << 8 | e[t + 2] << 16,
n += base64Encode(i, 4)
}
var o = r % 3;
for (i = 0,
t += 2; t >= 0; t--) {
i = i << 8 | e[t]
}
return 1 == o ? n = n + base64Encode(i << 16, 2) + "==" : 2 == o && (n = n + base64Encode(i << 8, 3) + "="),
n
}
function base64Encode(e, t) {
var i, r = "";
for (i = t; 4 > i; i++) {
e >>= 6
}
for (i = 0; t > i; i++) {
r = mapByteToBase64(63 & e) + r,
e >>= 6
}
return r
}
function mapByteToBase64(e) {
return e >= 0 && 26 > e ? String.fromCharCode(65 + e) : e >= 26 && 52 > e ? String.fromCharCode(97 + e - 26) : e >= 52 && 62 > e ? String.fromCharCode(48 + e - 52) : 62 == e ? "+" : "/"
}
var Key = "e=10001;m=d0fa1d37fa0bb621a8cbb6669249ba1d14bbd5058592f050240d8c3b68674f0e28283018a7753f4377aaa3b3645e5f119a0032129a0a64322f74888aed3519de49e98c5b3c221460218140616f01ac5e9f2f8042e2749b8a89112f15310690dad7531f6758c0c65e525dff7859283b566a5b154352c57161cd24e59133a61432f461583e40cac749d722909dfcf0edd6af3cbc9a25e639b0caaf55e8c7b08b53c7d52038b48e1b26ad40f8bb84b3bb9c92bc9b947d2ab5ae4664a5093a4895af09659a78c9393797ea76b5b9416a45025e2ab3ea1627f08d85abd22e156d3e842efbaa1d0e1e4885028b2bc0aa7be8e444799e96fce0444f2b56bd14c0244b4d"
var randomNum = "AA278C7C00D44877AA95055BB0497A6169195B7B79C664E0AC9DFDCE1112CE28282BAA83D5CD95041CB512CD35624CCD6FD873C98579E4D3C4D25E5E6134F65628BDA9DE9C00A6E53A0194EA7483BCB1AABD8AA983282259E2953CC8705D36BB9936E57E"
console.log(Encrypt(null, "1234", "saproof"))
Example output from above code
V2loAc3ik+qXTJMVF/V/0yKdbQeKGqO7UIA82cqafWUPJ6ALYd/6Bwb9QFsJOEC+yKfwqu5YE36+J3Dpsuk14EQG4YktFVao5D2i5C/2Akm5i1WhPDMbHUFfUJtxbQ3Ldc0jgpMpOrhuEkQ/u9MUgL3l1tL08GTvl4KdnvW2delt1HpuyGFI11WNb5/xXbzmZvRsF2fc3tNpZCvHSTCEQuMOzsQSTeghttXEBFFvmqC9fwH+KjiBGwl11zyH+shv8kYi+LRaqN2LoVz4eFMmWDJ0PNNeA7Aq+mQ/9BIY+tz7Tzz51OSlCgajsPnJbxyHiURdUrc103oKdja8Vd9dnw==
The main function here is Encrypt(). My program is written in Python. I tried encrypting my OTP using Python's rsa module but to no avail. The API rejected the request and marked the encrypted OTP as invalid.
import rsa
import base64
Key = "d0fa1d37fa0bb621a8cbb6669249ba1d14bbd5058592f050240d8c3b68674f0e28283018a7753f4377aaa3b3645e5f119a0032129a0a64322f74888aed3519de49e98c5b3c221460218140616f01ac5e9f2f8042e2749b8a89112f15310690dad7531f6758c0c65e525dff7859283b566a5b154352c57161cd24e59133a61432f461583e40cac749d722909dfcf0edd6af3cbc9a25e639b0caaf55e8c7b08b53c7d52038b48e1b26ad40f8bb84b3bb9c92bc9b947d2ab5ae4664a5093a4895af09659a78c9393797ea76b5b9416a45025e2ab3ea1627f08d85abd22e156d3e842efbaa1d0e1e4885028b2bc0aa7be8e444799e96fce0444f2b56bd14c0244b4d"
encrypted = rsa.encrypt(b'1234', rsa.PublicKey(int(Key, 16), 65537))
b64encrypted = base64.b64encode(encrypted)
print(b64encrypted.decode('utf-8'))
So my question is, how can I use Microsoft's encryption function in Python? Do I need to manually translate the code myself, or maybe I am doing something wrong with rsa module?
Thanks for help.
The JavaScript code uses RSA with OAEP as padding and SHA-1 for both digests (see applyPKCSv2Padding()). In addition, the plaintext is encoded with UTF-16LE (see PackageSADataForProof()) and the ciphertext is encoded in little endian order (see byteArrayToBase64()).
The RSA library used does not support OAEP, see issue #68. A possible library that supports OAEP is PyCryptodome and a possible implementation that is functionally identical to the JavaScript code is (strictly speaking, this applies only to plaintexts up to 214 bytes, for longer ones see the next section):
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import base64
modulusHex = 'd0fa1d37fa0bb621a8cbb6669249ba1d14bbd5058592f050240d8c3b68674f0e28283018a7753f4377aaa3b3645e5f119a0032129a0a64322f74888aed3519de49e98c5b3c221460218140616f01ac5e9f2f8042e2749b8a89112f15310690dad7531f6758c0c65e525dff7859283b566a5b154352c57161cd24e59133a61432f461583e40cac749d722909dfcf0edd6af3cbc9a25e639b0caaf55e8c7b08b53c7d52038b48e1b26ad40f8bb84b3bb9c92bc9b947d2ab5ae4664a5093a4895af09659a78c9393797ea76b5b9416a45025e2ab3ea1627f08d85abd22e156d3e842efbaa1d0e1e4885028b2bc0aa7be8e444799e96fce0444f2b56bd14c0244b4d';
pubExpHex = '010001'
plaintextStr = '1234'
modulus = int(modulusHex, 16)
pubExp = int(pubExpHex, 16)
plaintext = plaintextStr.encode('utf-16le') # encode plaintext with UTF-16LE
publicKey = RSA.construct((modulus, pubExp))
cipher = PKCS1_OAEP.new(publicKey) # apply OAEP as padding
ciphertext = cipher.encrypt(plaintext)
ciphertextReversed = ciphertext[::-1] # encode ciphertext in little endian order
ciphertextReversedB64 = base64.b64encode(ciphertextReversed)
print(ciphertextReversedB64)
Note that OAEP is not deterministic, i.e. repeated encryption with the same key and plaintext gives different ciphertexts. Therefore, the implementation cannot be verified by comparing the ciphertexts, but only by a successful decryption (see the last section).
Plaintexts, larger than 214 bytes: The posted JavaScript code implements a rather unusual feature: RSA can only encrypt plaintexts whose maximum length is equal to the key length (here 2048 bits = 256 bytes) minus the space required by the padding (here for OAEP with SHA-1: 42 bytes), i.e. the maximum length here is 256 - 42 = 214 bytes, see here.
But the Java Script code posted here splits the plaintext into blocks of 214 bytes (or less in the case of the last block), encrypts each block separately and concatenates the ciphertexts. This allows encryption of arbitrarily long plaintexts.
The Python code snippet above does not take this into account, since it is not needed for the short plaintext 1234 used in the example. But for plaintexts larger than 214 bytes this has to be added.
Note that usually long plaintexts are not encrypted this way, but with hybrid encryption, in which e.g. RSA is combined with AES: The plaintext is encrypted with AES, the AES key with RSA.
Test: The JavaScript code below decrypts a ciphertext generated with the JavaScript code posted in the question and a ciphertext generated with the Python code posted in this answer.
Result: Both ciphertexts can be decrypted with the same logic, which shows that the JavaScript and Python encryption code are functionally identical.
Note that a new key pair was used for this test, since only the public key was posted in the question, and that the public key of this new key pair must be applied when generating the ciphertexts (see JavaScript code for encryption) so that the private key used in decryption matches.
(async () => {
function Encrypt(e, t, i, r) {
var n = [];
switch (i.toLowerCase()) {
case "saproof":
if (null == t) {
return null
}
n = PackageSADataForProof(t);
break;
case "newpwd":
if (null == r) {
return null
}
}
if (null == n || "undefined" == typeof n) {
return n
}
if ("undefined" != typeof Key && void 0 !== parseRSAKeyFromString) {
var o = parseRSAKeyFromString(Key)
}
var s = RSAEncrypt(n, o, randomNum);
return s
}
function PackageSADataForProof(e) {
var t, i = [], r = 0;
for (t = 0; t < e.length; t++) {
i[r++] = 127 & e.charCodeAt(t),
i[r++] = (65280 & e.charCodeAt(t)) >> 8
}
return i
}
function parseRSAKeyFromString(e) {
var t = e.indexOf(";");
if (0 > t) {
return null
}
var i = e.substr(0, t)
, r = e.substr(t + 1)
, n = i.indexOf("=");
if (0 > n) {
return null
}
var o = i.substr(n + 1);
if (n = r.indexOf("="),
0 > n) {
return null
}
var s = r.substr(n + 1)
, a = new Object;
return a.n = hexStringToMP(s),
a.e = parseInt(o, 16),
a
}
function hexStringToMP(e) {
var t, i, r = Math.ceil(e.length / 4), n = new JSMPnumber;
for (n.size = r,
t = 0; r > t; t++) {
i = e.substr(4 * t, 4),
n.data[r - 1 - t] = parseInt(i, 16)
}
return n
}
function RSAEncrypt(e, t) {
for (var i = [], r = 42, n = 2 * t.n.size - r, o = 0; o < e.length; o += n) {
if (o + n >= e.length) {
var s = RSAEncryptBlock(e.slice(o), t, randomNum);
s && (i = s.concat(i))
} else {
var s = RSAEncryptBlock(e.slice(o, o + n), t, randomNum);
s && (i = s.concat(i))
}
}
var a = byteArrayToBase64(i);
return a
}
function RSAEncryptBlock(e, t, i) {
var r = t.n
, n = t.e
, o = e.length
, s = 2 * r.size
, a = 42;
if (o + a > s) {
return null
}
applyPKCSv2Padding(e, s, i),
e = e.reverse();
var l = byteArrayToMP(e)
, d = modularExp(l, n, r);
d.size = r.size;
var h = mpToByteArray(d);
return h = h.reverse()
}
function JSMPnumber() {
this.size = 1,
this.data = [],
this.data[0] = 0
}
function byteArrayToMP(e) {
var t = new JSMPnumber
, i = 0
, r = e.length
, n = r >> 1;
for (i = 0; n > i; i++) {
t.data[i] = e[2 * i] + (e[1 + 2 * i] << 8)
}
return r % 2 && (t.data[i++] = e[r - 1]),
t.size = i,
t
}
function modularExp(e, t, i) {
for (var r = [], n = 0; t > 0; ) {
r[n] = 1 & t,
t >>>= 1,
n++
}
for (var o = duplicateMP(e), s = n - 2; s >= 0; s--) {
o = modularMultiply(o, o, i),
1 == r[s] && (o = modularMultiply(o, e, i))
}
return o
}
function modularMultiply(e, t, i) {
var r = multiplyMP(e, t)
, n = divideMP(r, i);
return n.r
}
function multiplyMP(e, t) {
var i = new JSMPnumber;
i.size = e.size + t.size;
var r, n;
for (r = 0; r < i.size; r++) {
i.data[r] = 0
}
var o = e.data
, s = t.data
, a = i.data;
if (e == t) {
for (r = 0; r < e.size; r++) {
a[2 * r] += o[r] * o[r]
}
for (r = 1; r < e.size; r++) {
for (n = 0; r > n; n++) {
a[r + n] += 2 * o[r] * o[n]
}
}
} else {
for (r = 0; r < e.size; r++) {
for (n = 0; n < t.size; n++) {
a[r + n] += o[r] * s[n]
}
}
}
return normalizeJSMP(i),
i
}
function normalizeJSMP(e) {
var t, i, r, n, o;
for (r = e.size,
i = 0,
t = 0; r > t; t++) {
n = e.data[t],
n += i,
o = n,
i = Math.floor(n / 65536),
n -= 65536 * i,
e.data[t] = n
}
}
function removeLeadingZeroes(e) {
for (var t = e.size - 1; t > 0 && 0 == e.data[t--]; ) {
e.size--
}
}
function divideMP(e, t) {
var i = e.size
, r = t.size
, n = t.data[r - 1]
, o = t.data[r - 1] + t.data[r - 2] / 65536
, s = new JSMPnumber;
s.size = i - r + 1,
e.data[i] = 0;
for (var a = i - 1; a >= r - 1; a--) {
var l = a - r + 1
, d = Math.floor((65536 * e.data[a + 1] + e.data[a]) / o);
if (d > 0) {
var h = multiplyAndSubtract(e, d, t, l);
for (0 > h && (d--,
multiplyAndSubtract(e, d, t, l)); h > 0 && e.data[a] >= n; ) {
h = multiplyAndSubtract(e, 1, t, l),
h > 0 && d++
}
}
s.data[l] = d
}
removeLeadingZeroes(e);
var u = {
"q": s,
"r": e
};
return u
}
function multiplyAndSubtract(e, t, i, r) {
var n, o = e.data.slice(0), s = 0, a = e.data;
for (n = 0; n < i.size; n++) {
var l = s + i.data[n] * t;
s = l >>> 16,
l -= 65536 * s,
l > a[n + r] ? (a[n + r] += 65536 - l,
s++) : a[n + r] -= l
}
return s > 0 && (a[n + r] -= s),
a[n + r] < 0 ? (e.data = o.slice(0),
-1) : 1
}
function applyPKCSv2Padding(e, t, i) {
var r, n = e.length, o = [218, 57, 163, 238, 94, 107, 75, 13, 50, 85, 191, 239, 149, 96, 24, 144, 175, 216, 7, 9], s = t - n - 40 - 2, a = [];
for (r = 0; s > r; r++) {
a[r] = 0
}
a[s] = 1;
var l = o.concat(a, e)
, d = [];
for (r = 0; 20 > r; r++) {
d[r] = Math.floor(256 * Math.random())
}
d = SHA1(d.concat(i));
var h = MGF(d, t - 21)
, u = XORarrays(l, h)
, c = MGF(u, 20)
, p = XORarrays(d, c)
, f = [];
for (f[0] = 0,
f = f.concat(p, u),
r = 0; r < f.length; r++) {
e[r] = f[r]
}
}
function MGF(e, t) {
if (t > 4096) {
return null
}
var i = e.slice(0)
, r = i.length;
i[r++] = 0,
i[r++] = 0,
i[r++] = 0,
i[r] = 0;
for (var n = 0, o = []; o.length < t; ) {
i[r] = n++,
o = o.concat(SHA1(i))
}
return o.slice(0, t)
}
function XORarrays(e, t) {
if (e.length != t.length) {
return null
}
for (var i = [], r = e.length, n = 0; r > n; n++) {
i[n] = e[n] ^ t[n]
}
return i
}
function SHA1(e) {
var t, i = e.slice(0);
PadSHA1Input(i);
var r = {
"A": 1732584193,
"B": 4023233417,
"C": 2562383102,
"D": 271733878,
"E": 3285377520
};
for (t = 0; t < i.length; t += 64) {
SHA1RoundFunction(r, i, t)
}
var n = [];
return wordToBytes(r.A, n, 0),
wordToBytes(r.B, n, 4),
wordToBytes(r.C, n, 8),
wordToBytes(r.D, n, 12),
wordToBytes(r.E, n, 16),
n
}
function wordToBytes(e, t, i) {
var r;
for (r = 3; r >= 0; r--) {
t[i + r] = 255 & e,
e >>>= 8
}
}
function PadSHA1Input(e) {
var t, i = e.length, r = i, n = i % 64, o = 55 > n ? 56 : 120;
for (e[r++] = 128,
t = n + 1; o > t; t++) {
e[r++] = 0
}
var s = 8 * i;
for (t = 1; 8 > t; t++) {
e[r + 8 - t] = 255 & s,
s >>>= 8
}
}
function SHA1RoundFunction(e, t, i) {
var r, n, o, s = 1518500249, a = 1859775393, l = 2400959708, d = 3395469782, h = [], u = e.A, c = e.B, p = e.C, f = e.D, m = e.E;
for (n = 0,
o = i; 16 > n; n++,
o += 4) {
h[n] = t[o] << 24 | t[o + 1] << 16 | t[o + 2] << 8 | t[o + 3] << 0
}
for (n = 16; 80 > n; n++) {
h[n] = rotateLeft(h[n - 3] ^ h[n - 8] ^ h[n - 14] ^ h[n - 16], 1)
}
var g;
for (r = 0; 20 > r; r++) {
g = rotateLeft(u, 5) + (c & p | ~c & f) + m + h[r] + s & 4294967295,
m = f,
f = p,
p = rotateLeft(c, 30),
c = u,
u = g
}
for (r = 20; 40 > r; r++) {
g = rotateLeft(u, 5) + (c ^ p ^ f) + m + h[r] + a & 4294967295,
m = f,
f = p,
p = rotateLeft(c, 30),
c = u,
u = g
}
for (r = 40; 60 > r; r++) {
g = rotateLeft(u, 5) + (c & p | c & f | p & f) + m + h[r] + l & 4294967295,
m = f,
f = p,
p = rotateLeft(c, 30),
c = u,
u = g
}
for (r = 60; 80 > r; r++) {
g = rotateLeft(u, 5) + (c ^ p ^ f) + m + h[r] + d & 4294967295,
m = f,
f = p,
p = rotateLeft(c, 30),
c = u,
u = g
}
e.A = e.A + u & 4294967295,
e.B = e.B + c & 4294967295,
e.C = e.C + p & 4294967295,
e.D = e.D + f & 4294967295,
e.E = e.E + m & 4294967295
}
function rotateLeft(e, t) {
var i = e >>> 32 - t
, r = (1 << 32 - t) - 1
, n = e & r;
return n << t | i
}
function hexStringToMP(e) {
var t, i, r = Math.ceil(e.length / 4), n = new JSMPnumber;
for (n.size = r,
t = 0; r > t; t++) {
i = e.substr(4 * t, 4),
n.data[r - 1 - t] = parseInt(i, 16)
}
return n
}
function duplicateMP(e) {
var t = new JSMPnumber;
return t.size = e.size,
t.data = e.data.slice(0),
t
}
function mpToByteArray(e) {
var t = []
, i = 0
, r = e.size;
for (i = 0; r > i; i++) {
t[2 * i] = 255 & e.data[i];
var n = e.data[i] >>> 8;
t[2 * i + 1] = n
}
return t
}
function byteArrayToBase64(e) {
var t, i, r = e.length, n = "";
for (t = r - 3; t >= 0; t -= 3) {
i = e[t] | e[t + 1] << 8 | e[t + 2] << 16,
n += base64Encode(i, 4)
}
var o = r % 3;
for (i = 0,
t += 2; t >= 0; t--) {
i = i << 8 | e[t]
}
return 1 == o ? n = n + base64Encode(i << 16, 2) + "==" : 2 == o && (n = n + base64Encode(i << 8, 3) + "="),
n
}
function base64Encode(e, t) {
var i, r = "";
for (i = t; 4 > i; i++) {
e >>= 6
}
for (i = 0; t > i; i++) {
r = mapByteToBase64(63 & e) + r,
e >>= 6
}
return r
}
function mapByteToBase64(e) {
return e >= 0 && 26 > e ? String.fromCharCode(65 + e) : e >= 26 && 52 > e ? String.fromCharCode(97 + e - 26) : e >= 52 && 62 > e ? String.fromCharCode(48 + e - 52) : 62 == e ? "+" : "/"
}
var Key = "e=10001;m=ba71796836ba1c27cb30c23f3192d3e610e4df4e0253eca914c162063a3041d50c40a60767e7e4941ec6a4bc426adc5827f859eeb8df1c7dca96adb4fd8d446d80d1a29c9349f92b4f33f3c2c5f852bfe5db90ad75095d847093320c1ffc4bff6ee04da1b7f375913e0e176fe654302ad8c8e379432af022e6411eb764c5c1f25c26b06244978470b7d58164d7191427ee09e058aca452ee6b4bcdde014d711fd14ba2341fca26bcf7f13292238eeffdd45b077e3004d9f472e34b1dbf2dfde0da3afcd5e89f12660396b8bf399a783a166efb4068d4b5e5a024defaf9884366025fb11ab543aec9032dd95c31e2e57e77f0370cfe8fb4c1812a917c4ade221b"
var randomNum = "AA278C7C00D44877AA95055BB0497A6169195B7B79C664E0AC9DFDCE1112CE28282BAA83D5CD95041CB512CD35624CCD6FD873C98579E4D3C4D25E5E6134F65628BDA9DE9C00A6E53A0194EA7483BCB1AABD8AA983282259E2953CC8705D36BB9936E57E"
var ciphertextB64FromJS = Encrypt(null, "1234", "saproof");
document.getElementById("js_enc").innerHTML = "JavaScript code (encryption): " + ciphertextB64FromJS;
// Decryption ======================================================================================================================================================
// Decryption of a ciphertext from the JavaScript Code
var decryptedCiphertextFromJS = await decrypt(ciphertextB64FromJS);
document.getElementById("js_dec").innerHTML = "JavaScript code (decryption): " + decryptedCiphertextFromJS;
// Decryption of a ciphertext from the Python code for encryption
var ciphertextB64FromPy = 'iQefWJtEXRjMpJj59NmODmDVuJJkmsSV2pNvPrAX74lDWiXHjY4H34XAEGHY5bJ/3xJ3f7pM1R0Nb8cBJSgQMpCO/0PCdDSbalw7M/cbEEOzrIVMxg8NXOsUM6tqetaroSAutyesg8+EsP4liow3ssV6I7cX/QDpunFV0vRHxTM9Am35QNrNfpvZMu4kV642dq9ocSJLdbaBfaKXUyBA6nYzUIhq3nHx8XzPxo9DnAoE6qkGeRpQzV7Mo+jeY26YOP/DyVmb0JuOXPI8Uz/4yxhQp7ygAVOF5CNojZN0XtZVqORV4+2bFEMD+Fi9YIIFFMrym169ACoy2faTfLYjlw=='; // MAKE SURE TO USE THE CORRECT PUBLIC KEY DURING ENCRYPTION!!!: modulus = 0xba717968..., public exponent = 0x10001 (s. above)
var decryptedCiphertextFromPy = await decrypt(ciphertextB64FromPy);
document.getElementById("py_dec").innerHTML = "Python code (decryption): " + decryptedCiphertextFromPy;
async function decrypt(ciphertextBase64){
var pkcs8Der = b642ab('MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6cXloNrocJ8swwj8xktPmEOTfTgJT7KkUwWIGOjBB1QxApgdn5+SUHsakvEJq3Fgn+FnuuN8cfcqWrbT9jURtgNGinJNJ+StPM/PCxfhSv+XbkK11CV2EcJMyDB/8S/9u4E2ht/N1kT4OF2/mVDAq2MjjeUMq8CLmQR63ZMXB8lwmsGJEl4Rwt9WBZNcZFCfuCeBYrKRS7mtLzd4BTXEf0UuiNB/KJrz38TKSI47v/dRbB34wBNn0cuNLHb8t/eDaOvzV6J8SZgOWuL85mng6Fm77QGjUteWgJN76+YhDZgJfsRq1Q67JAy3ZXDHi5X538DcM/o+0wYEqkXxK3iIbAgMBAAECggEASlJj0ExIomKmmBhG8q8SM1s2sWG6gdQMjs6MEeluRT/1c2v79cq2Dum5y/+UBl8x8TUKPKSLpCLs+GXkiVKgHXrFlqoN+OYQArG2EUWzuODwczdYPhhupBXwR3oX4g41k/BsYfQfZBVzBFEJdWrIDLyAUFWNlfdGIj2BTiAoySfyqmamvmW8bsvc8coiGlZ28UC85/Xqx9wOzjeGoRkCH7PcTMlc9F7SxSthwX/k1VBXmNOHa+HzGOgO/W3k1LDqJbq2wKjZTW3iVEg2VodjxgBLMm0MueSGoI6IuaZSPMyFEM3gGvC2+cDBI2SL/amhiTUa/VDlTVw/IKbSuar9uQKBgQDd76M0Po5Lqh8ZhQ3obhFqkfO5EBXy7HUL15cw51kVtwF6Gf/J2HNHjwsg9Nb0eJETTS6bbuVd9bn884JoRS986nVTFNZ4dnjEgKjjQ8GjfzdkpbUxsRLWiIxuOQSpIUZGdMi2ctTTtspvMsDsjRRYdYIQCe/SDsdHGT3vcUCybwKBgQDXDz6iVnY84Fh5iDDVrQOR4lYoxCL/ikCDJjC6y1mjR0eVFdBPQ4j1dDSPU9lahBLby0VyagQCDp/kxQOl0z2zBLRI4I8jUtz9/9KW6ze7U7dQJ7OTfumd5I97OyQOG9XZwKUkRgfyb/PAMBSUSLgosi38f+OC3IN3qlvHFzvxFQKBgQCITpUDEmSczih5qQGIvolN1cRF5j5Ey7t7gXbnXz+Umah7kJpMIvdyfMVOAXJABgi8PQwiBLM0ySXo2LpARjXLV8ilNUggBktYDNktc8DrJMgltayaj3HNd2IglD5rjfc2cKWRgOd7/GlKcHaTEnbreYhfR2sWrWLxJOyoMfuVWwKBgFalCbMV6qU0LfEo8aPlBN8ttVDPVNpntP4h0NgxPXgPK8Pg+gA1UWSy4MouGg/hzkdHaj9ifyLlCX598a5JoT4S0x/ZeVHd/LNI8mtjcRzD6cMde7gdFbpLb5NSjIAyrsIAX4hxvpnqiOYRePkVIz0iLGziiaMbfMwlkrxvm/LRAoGBALPRbtSbE2pPgvOHKHTGPr7gKbmsWVbOcQA8rG801T38W/UPe1XtynMEjzzQ29OaVeQwvUN9+DxFXJ6Yvwj6ih4Wdq109i7Oo1fDnMczOQN9DKch2eNAHrNSOMyLDCBm++wbyHAsS2T0VO8+gzLABviZm5AFCQWfke4LZo5mOS10');
var privateKey = await window.crypto.subtle.importKey("pkcs8", pkcs8Der, {name: "RSA-OAEP", hash: "SHA-1"}, true, ["decrypt"]);
var ciphertext = b642ab(ciphertextBase64);
ciphertext = ciphertext.reverse(); // reverse little endian order
var decrypted = await window.crypto.subtle.decrypt({name: "RSA-OAEP"}, privateKey, ciphertext); // apply OAEP as padding
return decodeUTF16LE(decrypted); // decode with UTF-16LE
}
// Helper
function b642ab(base64_string){
return Uint8Array.from(window.atob(base64_string), c => c.charCodeAt(0));
}
// https://stackoverflow.com/a/14601808
function decodeUTF16LE(buf) {
var cp = [];
var binaryStr = String.fromCharCode.apply(null, new Uint8Array(buf));
for( var i = 0; i < binaryStr.length; i+=2) {
cp.push(
binaryStr.charCodeAt(i) |
( binaryStr.charCodeAt(i+1) << 8 )
);
}
return String.fromCharCode.apply( String, cp );
}
})();
<p style="font-family:'Courier New', monospace;" id="js_enc"></p>
<p style="font-family:'Courier New', monospace;" id="js_dec"></p>
<p style="font-family:'Courier New', monospace;" id="py_dec"></p>

Javascript RSA implementation doesn't generate correctly

The problem is at generating either e or d. But what? The math seems good to me.
e > 1 and coprime to ϕ
d satisfies de≡1(modϕ(n))
Please help
var m = 4, //Message
p = 13
q = 7
n = p * q
T = (q - 1) * (p - 1)
d = new Number;
//Calculate e:
for (let i = 2; i < T; i++) {
if( (gcd(i,T) == 1) ) { var e = i; break; }
}
//Calculate d:
while ( e * d % T != 1 ) d++;
function gcd(k, n) {
return k ? gcd(n % k, k) : n;
}
var e_m = m ** e % n, // To encrypt
d_m = e_m ** d % n // To decrypt
console.log(`m: ${m}\np: ${p}\nq: ${q}\nn: ${n}\nT: ${T}\n\ne: ${e}\nd: ${d}\n\nencrypted: ${e_m}\ndecrypted: ${d_m}`);
//Results:
// encrypted: 23
// decrypted: 28 (not 4)

Decompression Routine In Javascript to Python

I'm trying to rewrite a javascript file decompression routine to python. But I can't seem to get it right. The function always returns None on python.
Here is the original JS:
var c = new Uint8Array(b),
d = 0,
e = new Uint32Array(4096),
f = new Uint32Array(4096),
g = 256,
h = a.length,
k = 0,
l = 1,
m = 0,
n = 1;
c[d++] = a[0];
for (var r = 1;; r++) {
n = r + (r >> 1);
if (n + 1 >= h) break;
var m = a[n + 1],
n = a[n],
p = r & 1 ? m << 4 | n >> 4 : (m & 15) << 8 | n;
if (p < g)
if (256 > p) m = d, n = 1, c[d++] = p;
else
for (var m = d, n = f[p], p = e[p], q = p + n; p < q;) c[d++] = c[p++];
else if (p == g) {
m = d;
n = l + 1;
p = k;
for (q = k + l; p < q;) c[d++] = c[p++];
c[d++] = c[k]
} else break;
e[g] = k;
f[g++] = l + 1;
k = m;
l = n;
g = 4096 <= g ? 256 : g
}
return d == b ? c : null
And here is my python implementation, what did I do wrong? (Improved with #le_m answer but still returning None.)
c = [0] * b
d = 0
e = [0] * 4096
f = [0] * 4096
g = 256
h = len(a)
k = 0
l = 1
m = 0
n = 1
c[d] = a[0]
d += 1
r = 1
while True:
n = r + (r >> 1)
if (n + 1) >= h:
break
m = a[n + 1]
n = a[n]
p = (m << 4 | n >> 4) if r & 1 else ((m & 15) << 8 | n)
if (p < g):
if (256 > p):
m = d
n = 1
c[d] = p
d += 1
else:
m = d
n = f[p]
p = e[p]
q = p + n
while p < q:
c[d] = c[p]
d += 1
p += 1
elif p == g:
m = d
n = 1 + 1
p = k
q = k + l
while p < q:
c[d] = c[p]
d += 1
p += 1
else:
break
e[g] = k
f[g] = l + 1
g += 1
k = m
l = n
g = 256 if 4096 <= g else g
r += 1
Just from glancing at the code, I spot the following differences:
new Uint8Array(b) translates to [0] * b as the typed array is initialized with zeros. Same holds for the other typed arrays.
c[d++] = a[0] translates to c[d] = a[0] followed by d += 1, not the other way round. Same holds for the other post-increments, too.
The loop counter r += 1 should go to the end of the loop body or should be initialized with 0 instead.
I recommend stepping through both implementations step by step with a debugger (your browser's developer console for JavaScript) and compare the variable values.

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

Convert a number between 1 and 16777215 to a colour value

I'm trying to convert a number between 1 and 16,777,215 to any colour format (RGB/HSL/HEX) that increments through the colour spectrum using Javascript/jQuery.
The number 16,777,215 is the total possible combinations of RGB(255,255,255) which is 32 bit colour.
I initially thought converting the value to a hex value using toString(16) would increment through the spectrum, however as the number increases it seems to work through different lightness values instead and flashes. An example of this unwanted behaviour is here http://jsfiddle.net/2z82auka/
var colour = 16777215;
window.setInterval(function(){
colour -= 1000;
$('body').css({background:'#' + colour.toString(16)});
}, 50);
How can I convert a value between 1 and 16777215 to a colour on the colour spectrum shown below?
The code below will do exactly what you want - it'll give you vibrant colors of the color spectrum exactly as the image below, and to prove it, the demo will print out the integer values beside the color. The result will look like this. Please use the rainbow function in your setInterval code.
var colours = 16777215;
function rainbow(numOfSteps, step) {
var r, g, b;
var h = 1 - (step / numOfSteps);
var i = ~~(h * 6);
var f = h * 6 - i;
var q = 1 - f;
switch(i % 6){
case 0: r = 1, g = f, b = 0; break;
case 1: r = q, g = 1, b = 0; break;
case 2: r = 0, g = 1, b = f; break;
case 3: r = 0, g = q, b = 1; break;
case 4: r = f, g = 0, b = 1; break;
case 5: r = 1, g = 0, b = q; break;
}
var c = "#" + ("00" + (~ ~(r * 235)).toString(16)).slice(-2) + ("00" + (~ ~(g * 235)).toString(16)).slice(-2) + ("00" + (~ ~(b * 235)).toString(16)).slice(-2);
return (c);
}
function render(i) {
var item = "<li style='background-color:" + rainbow(colours, i) + "'>" + i + "</li>";
$("ul").append(item);
}
function repeat(fn, times) {
for (var i = 0; i < times; i+=10000) fn(i);
}
repeat(render, colours);
li {
font-size:8px;
height:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<ul></ul>
(I can't take credit for this code, but I can take credit for not giving up and settling for jerky color changes. Ref: https://gist.github.com/ruiwen/6163115)
Convert to range the initial value from 1 > 16777216 from 0 > 360
Technique here: Convert a number range to another range, maintaining ratio
Then use the HSL colour model, and increment from H0 S100 L100 > H360 S100 L100
Sticking to RGB: Always incrementing by one will not result in a steady grade through the spectrum. For example, when you go from #0000ff (which is blue) to that +1, you end up at #000100, which is essentially black.
Instead, you will probably want to do something more like incrementing each of the three values (the R value, the G value, and the B value) by one. However, that will omit many, many colors. But if smoothness is what you value over comprehensiveness, that's a simple way to get there.
#nada points out that this will give you an awful lot of grey. If you want to avoid that, you can try variations like: increment R until it can't be incremented anymore. Leave it at max value while you increment G until it hits max, then increment B to max. Now reverse it: Decrement R to minimum, then G, then B. This will still miss a ton of colors (in fact, it will miss most colors), but it should be smooth and it should avoid being nothing but grey.
Although this will work (if you don't mind missing most colors), I'm sure there is a better solution. I hope someone weighs in with it. I'm very curious.
You have the hue value, so you need to turn that into the various color formats using fixed brightness and saturation.
To properly scale the hue from [1, 16777215] to a [0, 1] scale, you'll need to do (x - 1) / 16777215. Take this number and feed it into hsl2rgb (here's a JS implementation) with a high lum and relatively high sat.
Something like so:
// From this answer: https://stackoverflow.com/a/9493060/129032
function hslToRgb(h, s, l) {
var r, g, b;
if (s == 0) {
r = g = b = l; // achromatic
} else {
var hue2rgb = function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
function scaleHue(hue) {
return ((hue - 1) / 16777215);
}
var colour = 0;
window.setInterval(function() {
colour = (colour + 100000) % 16777215;
var hue = scaleHue(colour);
var current = hslToRgb(hue, 0.8, 0.8);
$('body').css({
background: '#' + current[0].toString(16) + current[1].toString(16) + current[2].toString(16)
});
}, 50);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I increased the step from 1000 to 100000 to make the demo more obvious.
This works for me...
export function intToHex(colorNumber)
{
function toHex(n) {
n = n.toString(16) + '';
return n.length >= 2 ? n : new Array(2 - n.length + 1).join('0') + n;
}
var r = toHex(Math.floor( Math.floor(colorNumber / 256) / 256 ) % 256),
g = toHex(Math.floor( colorNumber / 256 ) % 256),
b = toHex(colorNumber % 256);
return '#' + r + g + b;
}
Generally, this is the formula for converting an integer to rgba
r = (val)&0xFF;
g = (val>>8)&0xFF;
b = (val>>16)&0xFF;
a = (val>>24)&0xFF;
Expressed as javascript
function ToRGBA(val){
var r = (val)&0xFF;
var g = (val>>8)&0xFF;
var b = (val>>16)&0xFF;
var a = (val>>24)&0xFF;
return "rgb(" + r + "," + g + "," + b + ")";
}
Updated fiddle: http://jsfiddle.net/2z82auka/2/
Something like that ?
<script>
function intToHex(colorNumber) {
var R = (colorNumber - (colorNumber%65536)) / 65536;
var G = ((colorNumber - R*65536) - ((colorNumber - R*65536)%256)) / 256;
var B = colorNumber - R*65536 - G*256;
var RGB = R.toString(16) + G.toString(16) + B.toString(16);
return RGB;
}
</script>
Marrying this answer with Drake's:
function colorNumberToHex(colorNumber) {
function toHex(n) {
n = n.toString(16) + '';
return n.length >= 2 ? n : new Array(2 - n.length + 1).join('0') + n;
}
var r = toHex(colorNumber % 256),
g = toHex(Math.floor( colorNumber / 256 ) % 256),
b = toHex(Math.floor( Math.floor(colorNumber / 256) / 256 ) % 256);
return '#' + r + g + b;
}
The picture you've shown suggests you really just want to rotate through a set of continuous colors, not every possible rgb color (since many of them essentially look white or black). I would suggest using HSV as a base instead of RGB. Trying to increment a number that represents an RGB value will lead to the stuttering you see (like #Trott pointed out, going from 0000ff to 000100 jumps from a blue to a black).
Try something like this (Fiddle):
$(document).ready(function(){
var h = 0;
window.setInterval(function(){
h += .01;
if (h >= 1) h-=1;
var rgbColor = HSVtoRGB(h, 1, 1);
var colorString = '#' + convertComponentToHex(rgbColor.r)
+ convertComponentToHex(rgbColor.g)
+ convertComponentToHex(rgbColor.b);
$('body').css({background:colorString});
}, 50);
});
function convertComponentToHex(v) {
return ("00" + v.toString(16)).substr(-2);
}
function HSVtoRGB(h, s, v) {
var r, g, b, i, f, p, q, t;
if (h && s === undefined && v === undefined) {
s = h.s, v = h.v, h = h.h;
}
i = Math.floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
return {
r: Math.floor(r * 255),
g: Math.floor(g * 255),
b: Math.floor(b * 255)
};
}
(Thanks to this SO answer for the conversion code. I was too lazy to go figure it out for myself.)
My implementation....
var r = 255;
var g = 0;
var b = 0;
var stage = 1;
var step = 5;
var int = setInterval(function () {
if (stage == 1) {
g += step;
if (g >= 255) {
g = 255;
stage = 2;
}
} else if (stage == 2) {
r -= step;
if (r <= 0) {
r = 0;
stage = 3;
}
} else if (stage == 3) {
b += step;
if (b >= 255) {
b = 255;
stage = 4;
}
} else if (stage == 4) {
g -= step;
if (g <= 0) {
g = 0
stage = 5;
}
} else if (stage == 5) {
r += step;
if (r >= 255) {
r = 255;
stage = 6;
}
} else if (stage == 6) {
b -= step;
if (b <= 0) {
b = 0;
clearInterval(int);
}
}
//console.log(r,g,b);
$('body').css('background-color', 'RGB('+r+','+g+','+b+')');
}, 10);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Categories