Last active
March 20, 2020 23:47
-
-
Save liath/7fa52509b7f754b65d6525bd5096d8c2 to your computer and use it in GitHub Desktop.
Emulating C-style integer maths in javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint no-console:0, func-names:0 */ | |
// JS ints are signed, which isn't useful here. Unfortunately, | |
// this means << can flip the sign bit and give a negative | |
// number which throws everything off. Luckily, we know how to | |
// handle this. The below is an unsigned leftshift implementation. | |
const ls = (input, shift) => ((input << shift) >>> 1) * 2; | |
// Integer casts that drop overflowing data (Just like grandma used to make) | |
const u8 = i => (i << 24) >>> 24; | |
const u16 = i => (i << 16) >>> 16; | |
const u32 = i => i >>> 0; | |
// JS is kind enough to convert into 32bit ints for us when we use any bitwise operations | |
const compress = function compress(input, rounds) { | |
const lu = ['0', '1', '2', '3', '4', '5', '6', '7', | |
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', | |
'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', | |
'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; | |
let num = input; | |
const builder = (new Array(rounds)).fill(' '); | |
let index; | |
for (let i = 0; i < rounds; i += 1) { | |
index = u32(num % 0x23); | |
num = Math.floor(num / 0x23); | |
builder[i] = lu[index]; | |
} | |
return builder.join(''); | |
}; | |
const getHashCode = function getHashCode(host) { | |
let num = u32(0x1505); | |
let num2 = u32(0x1505); | |
for (let i = 0; i < host.length; i += 1) { | |
num = u32((ls(num, 5) + num) ^ host[i++].charCodeAt(0)); | |
if (i < host.length) { | |
num2 = u32((ls(num2, 5) + num2) ^ host[i].charCodeAt(0)); | |
} | |
} | |
return u32(num + u32(num2 * 0x5d588b65)); | |
}; | |
const getAuth = function getAuth(hostname) { | |
let loSID = getHashCode(hostname); | |
let hiSID = u16(getHashCode(`${hostname}|`)); | |
const num1 = u32(loSID % 2); | |
const num2 = u32(hiSID % 2); | |
loSID = u32(ls(num2, 31) + (loSID >>> 1)); | |
hiSID = u32(ls(num1, 15) + (hiSID >>> 1)); | |
hiSID = u32(0x30000172 + ls(hiSID, 10)); | |
const a = u32(hiSID % 1024); | |
const b = u16(hiSID >>> 26); | |
const d = u32((ls(hiSID, 6) >>> 16)); | |
// Set this to fixed value for debugging purpoises. (sic) | |
// const first = u16(0x1337); | |
const first = u16(Math.floor((Math.random() * 65535))); | |
const fourth = u16(loSID); | |
const fifth = u16(loSID >>> 16); | |
const second = u16(ls(b, 27) + ls(d, 10) + a); | |
const third = u16((ls(b, 27) + ls(d, 10) + a) >>> 16); | |
const buffer = new Array(12); | |
buffer[1] = u8(first >>> 8); | |
buffer[0] = u8(ls(buffer[1], 8) ^ first); | |
buffer[3] = u8(second >>> 8); | |
buffer[2] = u8(ls(buffer[3], 8) ^ second); | |
buffer[5] = u8(third >>> 8); | |
buffer[4] = u8(ls(buffer[5], 8) ^ third); | |
buffer[7] = u8(fourth >>> 8); | |
buffer[6] = u8(ls(buffer[7], 8) ^ fourth); | |
buffer[9] = u8(fifth >>> 8); | |
buffer[8] = u8(ls(buffer[9], 8) ^ fifth); | |
buffer[10] = u8((first >>> 4) ^ 65535); | |
buffer[11] = 0; | |
let index; | |
for (index = 0; index < 11; index += 1) { | |
buffer[11] = u8(buffer[11] + buffer[index]); | |
} | |
for (index = 1; index < 6; index += 1) { | |
const int = index * 2; | |
buffer[int] = u8(buffer[int] ^ buffer[0]); | |
buffer[int + 1] = u8(buffer[int + 1] ^ buffer[1]); | |
} | |
const buffera = (new Array(12)).fill(0); | |
for (index = 0; index < 12; index += 1) { | |
buffera[index] = u8(buffer[index] >>> 3); | |
buffer[index] = u8(ls(buffer[index], 5)); | |
} | |
buffer[0] = u8(buffer[0] + buffera[7]); | |
buffer[1] = u8(buffer[1] + buffera[0]); | |
buffer[2] = u8(buffer[2] + buffera[1]); | |
buffer[3] = u8(buffer[3] + buffera[2]); | |
buffer[4] = u8(buffer[4] + buffera[11]); | |
buffer[5] = u8(buffer[5] + buffera[4]); | |
buffer[6] = u8(buffer[6] + buffera[5]); | |
buffer[7] = u8(buffer[7] + buffera[6]); | |
buffer[8] = u8(buffer[8] + buffera[3]); | |
buffer[9] = u8(buffer[9] + buffera[8]); | |
buffer[10] = u8(buffer[10] + buffera[9]); | |
buffer[11] = u8(buffer[11] + buffera[10]); | |
const auth = `${ | |
compress(u32( | |
ls(buffer[3], 24) + | |
ls(buffer[2], 16) + | |
ls(buffer[1], 8) + | |
buffer[0]), 7) | |
}-${ | |
compress(u32( | |
ls(buffer[7], 24) + | |
ls(buffer[6], 16) + | |
ls(buffer[5], 8) + | |
buffer[4]), 7) | |
}-${ | |
compress(u32( | |
ls(buffer[11], 24) + | |
ls(buffer[10], 16) + | |
ls(buffer[9], 8) + | |
buffer[8]), 7) | |
}`; | |
const sid = `${compress(hiSID, 7)}-${compress(loSID, 7)}`; | |
return {auth, sid}; | |
}; | |
const keygen = function keygen(hostname) { | |
const major = [ | |
1048335, 1048334, 1048333, 1048332, 1048331, 1048330, 1048329, 1048328, | |
1048327, 1048326, 1048325, 1048324, 1048323, 1048322, 1048321, 1048320 | |
][Math.floor(Math.random() * 16)]; | |
return `Serial:${ | |
(ls(major, 1) ^ major) | |
}\nProduct Code: ${ | |
compress(major, 5) | |
}-XA${ | |
compress(major << 1, 5) | |
}\nMachine Name: ${ | |
hostname | |
}\nAuth Code: ${ | |
getAuth(hostname).auth | |
}\n`; | |
}; | |
const hostname = 'Tilt'.toUpperCase(); | |
console.log(keygen(hostname)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment