Files
pwgen-for-bios/src/keygen/sony_4x4.ts
T
Slava Bacherikov ea85f539d4 Switch code linter to eslint and update deps
Tslint is outdated for quite a while and has been replaced by eslint
which now can work with TypeScript as well. This also updates
dependencies and fixes all linting errors.
2022-02-08 21:01:33 +02:00

130 lines
4.3 KiB
TypeScript

// based on dogbert's pwgen-sony-4x4.py
/* eslint-disable no-bitwise */
import JSBI from "jsbi";
import { makeSolver } from "./utils";
const otpChars: string = "9DPK7V2F3RT6HX8J";
const pwdChars: string = "47592836";
const inputRe: RegExp = new RegExp(`^[${otpChars}]{16}\$`);
function arrayToNumber(arr: number[]): number {
// same as python struct.unpack("<I", arr)
return (arr[3] << 24 | arr[2] << 16 | arr[1] << 8 | arr[0]) >>> 0;
}
function numberToArray(num: number): number[] {
return [num & 0xFF, (num >> 8) & 0xFF, (num >> 16) & 0xFF, (num >> 24) & 0xFF];
}
function decodeHash(hash: string): number[] {
let temp: number[] = [];
for (let i = 0; i < hash.length; i += 2) {
// TODO: check values
temp.unshift(otpChars.indexOf(hash[i]) * 16 + otpChars.indexOf(hash[i + 1]));
}
return temp;
}
function encodePassword(pwd: number[]): string {
let n: number = arrayToNumber(pwd);
let result: string = "";
for (let i = 0; i < 8; i++) {
result += pwdChars.charAt((n >> (21 - i * 3)) & 0x7);
}
return result;
}
// http://numericalrecipes.blogspot.com/2009/03/modular-multiplicative-inverse.html
function extEuclideanAlg(a: JSBI, b: JSBI): [JSBI, JSBI, JSBI] {
if (JSBI.EQ(b, 0)) {
return [JSBI.BigInt(1), JSBI.BigInt(0), a];
} else {
let [x, y, gcd] = extEuclideanAlg(b, JSBI.remainder(a, b));
return [y, JSBI.subtract(x, JSBI.multiply(y, JSBI.divide(a, b))), gcd];
}
}
function modInvEuclid(a: JSBI, m: JSBI): JSBI | undefined {
let [x, , gcd] = extEuclideanAlg(a, m);
if (JSBI.EQ(gcd, 1)) {
// hack for javascript modulo operation
// https://stackoverflow.com/questions/4467539/javascript-modulo-gives-a-negative-result-for-negative-numbers
const temp = JSBI.remainder(x, m);
return JSBI.GE(temp, 0) ? temp : JSBI.ADD(temp, m) as JSBI;
} else {
return undefined;
}
}
// https://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method
export function modularPow(base: JSBI, exponent: number, modulus: number | JSBI): number {
let result: JSBI = JSBI.BigInt(1);
if (!(modulus instanceof JSBI)) {
modulus = JSBI.BigInt(modulus);
}
if (JSBI.EQ(modulus, 1)) {
return 0;
}
base = JSBI.remainder(base, modulus);
while (exponent > 0) {
if ((exponent & 1) === 1) {
result = JSBI.remainder(JSBI.multiply(result, base), modulus);
}
exponent = exponent >> 1;
base = JSBI.remainder(JSBI.multiply(base, base), modulus);
}
return JSBI.toNumber(result);
}
function rsaDecrypt(code: number[]): number[] {
const low: JSBI = JSBI.BigInt(arrayToNumber(code.slice(0, 4)));
const high: JSBI = JSBI.BigInt(arrayToNumber(code.slice(4, 8)));
const c: JSBI = JSBI.bitwiseOr(JSBI.leftShift(high, JSBI.BigInt(32)), low);
const p: number = 2795287379;
const q: number = 3544934711;
const e = 41;
const phi: JSBI = JSBI.multiply(JSBI.BigInt(p - 1), JSBI.BigInt(q - 1));
const d: JSBI = modInvEuclid(JSBI.BigInt(e), phi) as JSBI;
const dp: JSBI = JSBI.remainder(d, JSBI.BigInt(p - 1));
const dq: JSBI = JSBI.remainder(d, JSBI.BigInt(q - 1));
const qinv: JSBI = modInvEuclid(JSBI.BigInt(q), JSBI.BigInt(p)) as JSBI;
const m1 = modularPow(c, JSBI.toNumber(dp), p);
const m2 = modularPow(c, JSBI.toNumber(dq), q);
let h: JSBI;
if (m1 < m2) {
h = JSBI.remainder(JSBI.multiply(JSBI.add(JSBI.BigInt(m1 - m2), JSBI.BigInt(p)), qinv), JSBI.BigInt(p));
} else {
h = JSBI.remainder(JSBI.multiply(JSBI.BigInt(m1 - m2), qinv), JSBI.BigInt(p));
}
const m: JSBI = JSBI.add(JSBI.multiply(h, JSBI.BigInt(q)), JSBI.BigInt(m2));
return numberToArray(JSBI.toNumber(JSBI.asUintN(32, m))).concat(
numberToArray(JSBI.toNumber(JSBI.signedRightShift(m, JSBI.BigInt(32))))
);
}
export function sony4x4Keygen(hash: string): string {
const numHash = decodeHash(hash);
const pwd = rsaDecrypt(numHash);
return encodePassword(pwd);
}
export let sony4x4Solver = makeSolver({
name: "sony4x4",
description: "Sony 4x4",
examples: ["73KR-3FP9-PVKH-K29R"],
cleaner: (input: string) => input.trim().replace(/[-\s]/gi, "").toUpperCase(),
inputValidator: (s) => inputRe.test(s),
fun: (code: string) => {
let res = sony4x4Keygen(code);
return res ? [res] : [];
}
});