54 lines
1.4 KiB
TypeScript
54 lines
1.4 KiB
TypeScript
import { Solitaire } from "./crypto";
|
|
import { createHash } from "crypto";
|
|
import type { integer } from "types/misc";
|
|
|
|
function reverseString(data: string) {
|
|
return Array.from(data).reverse().join("");
|
|
}
|
|
|
|
function CalculateCardKey(serial: integer, key: string) {
|
|
const paddedSerial = serial.toString().padStart(8, "0");
|
|
const realDigest = createHash("md5").update(paddedSerial).digest();
|
|
|
|
const digest = new Array(16);
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
const idx = Number(`0x${key[i]}`);
|
|
const nib = realDigest[idx];
|
|
|
|
if (nib === undefined) {
|
|
throw new Error(
|
|
"crypto.createHash returned an undefined value in a Buffer. this should not happen."
|
|
);
|
|
}
|
|
|
|
digest[i] = nib;
|
|
}
|
|
|
|
// nasty ass bit string hacks that i am not good enough at math to replace
|
|
let bitstring = reverseString(
|
|
digest.map((n) => reverseString(n.toString(2).padStart(8, "0"))).join("")
|
|
).padStart(6 * 23, "0");
|
|
let computed = 0;
|
|
|
|
while (bitstring) {
|
|
const work = Number(`0b${bitstring.slice(0, 23)}`);
|
|
|
|
// eslint-disable-next-line no-bitwise
|
|
computed = computed ^ work;
|
|
|
|
bitstring = bitstring.slice(23);
|
|
}
|
|
|
|
return computed.toString().padStart(7, "0");
|
|
}
|
|
|
|
export function CalculateAccessCode(serial: integer, prefix: string, key: string): string {
|
|
const digest = CalculateCardKey(serial, key);
|
|
|
|
const paddedSerial = serial.toString().padStart(8, "0");
|
|
const hashedId = Solitaire.encrypt(paddedSerial, digest);
|
|
|
|
return `${prefix}${hashedId}${digest}`;
|
|
}
|