kozukata-toa/src/servers/aimedb/utils/access-code.ts

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}`;
}