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

63 lines
1.8 KiB
TypeScript

import { Solitaire } from "./crypto";
import { createHash } from "crypto";
import type { integer } from "types/misc";
/* eslint-disable no-bitwise */
export function CalculateCardKey(serial: integer, key: string) {
const keyBuffer = Buffer.from(key, "hex");
const paddedSerial = serial.toString().padStart(8, "0");
const digest = createHash("md5").update(paddedSerial).digest();
let hash = 0;
let num = 0;
let storedBits = 0;
for (let i = 0; i < 16; i++) {
// Extract the i-th hexadecimal digit of the key...
const byte = keyBuffer[Math.trunc(i / 2)];
if (byte === undefined) {
throw new Error("Buffer.from returned an undefined value in a Buffer?");
}
// Extract the upper byte and lower byte respectively...
const idx = i % 2 === 0 ? byte >>> 4 : byte & 0xf;
// Using it as the index to shuffle the serial MD5...
const nib = digest[idx];
if (nib === undefined) {
throw new Error(
"crypto.createHash returned an undefined value in a Buffer. this should not happen."
);
}
// Store the byte into a temporary little-endian number...
num = num | (nib << storedBits);
storedBits = storedBits + 8;
// XOR every 23 bits or if it's the final iteration
if (storedBits > 23 || i === 15) {
// 0x7fffff is mask to extract the last 23 bits of num.
hash = hash ^ (num & 0x7fffff);
// Removed the bits we worked on
num = num >>> 23;
storedBits = storedBits - 23;
}
}
return hash.toString().padStart(7, "0");
}
/* eslint-enable no-bitwise */
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}`;
}