Reorganize file structure
This commit is contained in:
1 parent
f6888b8872
commit
b8a8d37e36
24 files changed
+3
-2
No files matched your search
@@ -0,0 +1,43 @@
|
||||
import { asusKeygen, asusSolver } from "./asus";
|
||||
|
||||
// https://pastebin.com/L3c3rySj
|
||||
|
||||
describe("Test Asus keygen", () => {
|
||||
it("Asus password for 2007-02-01 is AA19BALA", () => {
|
||||
expect(asusKeygen(2007, 2, 1)).toEqual("AA19BALA");
|
||||
});
|
||||
|
||||
it("Asus password for 2017-10-12 is AABABLAL", () => {
|
||||
expect(asusKeygen(2017, 10, 12)).toEqual("AABABLAL");
|
||||
});
|
||||
|
||||
it("Asus password for 2020-09-15 is LBD9DBA1", () => {
|
||||
expect(asusKeygen(2020, 9, 15)).toEqual("LBD9DBA1");
|
||||
});
|
||||
|
||||
it("Asus password for 2012-03-29 is AOBOBL2B", () => {
|
||||
expect(asusKeygen(2012, 3, 29)).toEqual("AOBOBL2B");
|
||||
});
|
||||
|
||||
it("Asus password for 2002-01-02 is ALAA4ABA", () => {
|
||||
expect(asusKeygen(2002, 1, 2)).toEqual("ALAA4ABA");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test Asus solver", () => {
|
||||
it("Asus password for 2007-02-01 is AA19BALA", () => {
|
||||
expect(asusSolver("2007-02-01")).toEqual(["AA19BALA"]);
|
||||
});
|
||||
|
||||
it("Asus password for 01-02-2007 is AA19BALA (dmy format)", () => {
|
||||
expect(asusSolver("01-02-2007")).toEqual(["AA19BALA"]);
|
||||
});
|
||||
|
||||
it("Asus password for 01022007 is AA19BALA (dmy format)", () => {
|
||||
expect(asusSolver("01022007")).toEqual(["AA19BALA"]);
|
||||
});
|
||||
|
||||
it("41022007 is bad date", () => {
|
||||
expect(asusSolver("41022007")).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,137 @@
|
||||
// based on dogbert's pwgen-asus.py
|
||||
/* tslint:disable:no-bitwise */
|
||||
import { makeSolver } from "./utils";
|
||||
|
||||
function initTable(a1: number = 11, a2: number = 19, a3: number = 6): number[] {
|
||||
let table: number[] = [];
|
||||
const zeroCode = "0".charCodeAt(0);
|
||||
table[0] = a1 + zeroCode;
|
||||
table[1] = a2 + zeroCode;
|
||||
table[2] = a3 + zeroCode;
|
||||
table[3] = "6".charCodeAt(0);
|
||||
table[4] = "7".charCodeAt(0);
|
||||
table[5] = "8".charCodeAt(0);
|
||||
table[6] = "9".charCodeAt(0);
|
||||
|
||||
let chksum: number = table.reduce((acc, val) => acc + val, 0);
|
||||
for (let i = 7; i < 32; i++) {
|
||||
chksum = (33676 * chksum + 12345) >>> 0;
|
||||
table[i] = ((chksum >> 16) & 0x7FFF) % 43 + zeroCode;
|
||||
}
|
||||
|
||||
let v3 = a1 * a2;
|
||||
let v4 = shuffle1((a1 - 1) * (a2 - 1), a3);
|
||||
|
||||
return table.map((value) => shuffle2(value - zeroCode, v4, v3));
|
||||
}
|
||||
|
||||
function shuffle1(a1: number, a2: number): number {
|
||||
let v3 = 2;
|
||||
for (let i = 0; i < a2; i++) {
|
||||
let v4 = v3;
|
||||
let v5 = a1;
|
||||
while (v5 > 0) {
|
||||
if (v5 < v4) {
|
||||
[v5, v4] = [v4, v5];
|
||||
}
|
||||
v5 %= v4;
|
||||
}
|
||||
if (v4 !== 1) {
|
||||
v3++;
|
||||
}
|
||||
}
|
||||
return v3;
|
||||
}
|
||||
|
||||
function shuffle2(a1: number, a2: number, a3: number): number {
|
||||
if (a1 >= a3) {
|
||||
a1 %= a3;
|
||||
}
|
||||
let result = a1;
|
||||
if (a2 !== 1) {
|
||||
for (let i = 0; i < a2 - 1; i++) {
|
||||
result = a1 * result % a3;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function leftPad(base: string, len: number, fill: string = " ") {
|
||||
const padding = len - base.length;
|
||||
for (let i = 0; i < padding; i++) {
|
||||
base = fill + base;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
function makeDateRegexp(): [RegExp, RegExp] {
|
||||
let years: string[] = [];
|
||||
let months: string[] = [];
|
||||
let days: string[] = [];
|
||||
|
||||
for (let year = 1990; year <= 2100; year++) {
|
||||
years.push(leftPad(year.toString(), 4, "0"));
|
||||
}
|
||||
|
||||
for (let month = 1; month <= 12; month++) {
|
||||
months.push(leftPad(month.toString(), 2, "0"));
|
||||
}
|
||||
|
||||
for (let day = 1; day <= 31; day++) {
|
||||
days.push(leftPad(day.toString(), 2, "0"));
|
||||
}
|
||||
let ymdre = new RegExp(`(${years.join("|")})(${months.join("|")})(${days.join("|")})`);
|
||||
let dmyre = new RegExp(`(${days.join("|")})(${months.join("|")})(${years.join("|")})`);
|
||||
return [ymdre, dmyre];
|
||||
}
|
||||
|
||||
const asusTable = initTable();
|
||||
const [ymdRegex, dmyRegex] = makeDateRegexp();
|
||||
|
||||
export function asusKeygen(year: number, month: number, day: number): string {
|
||||
const date = leftPad(year.toString(), 4, "0") +
|
||||
leftPad(month.toString(), 2, "0") +
|
||||
leftPad(day.toString(), 2, "0");
|
||||
|
||||
let chksum = parseInt(date, 16);
|
||||
let password: string = "";
|
||||
|
||||
for (let i = 0; i < 8; i++) {
|
||||
chksum = (33676 * chksum + 12345) >>> 0;
|
||||
let index = (chksum >> 16) & 31;
|
||||
let pwdChar = asusTable[index] % 36;
|
||||
if (pwdChar > 9) {
|
||||
password += String.fromCharCode(pwdChar + "7".charCodeAt(0));
|
||||
} else {
|
||||
password += String.fromCharCode(pwdChar + "0".charCodeAt(0));
|
||||
}
|
||||
}
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
export let asusSolver = makeSolver({
|
||||
name: "asusDate",
|
||||
description: "ASUS (Using date)",
|
||||
examples: ["2010-02-03"],
|
||||
inputValidator: (s) => s.length === 8,
|
||||
fun: (code) => {
|
||||
let result: string[] = [];
|
||||
|
||||
if (ymdRegex.test(code)) {
|
||||
let year = parseInt(code.slice(0, 4), 10);
|
||||
let month = parseInt(code.slice(4, 6), 10);
|
||||
let day = parseInt(code.slice(6, 8), 10);
|
||||
result.push(asusKeygen(year, month, day));
|
||||
}
|
||||
|
||||
if (dmyRegex.test(code)) {
|
||||
let day = parseInt(code.slice(0, 2), 10);
|
||||
let month = parseInt(code.slice(2, 4), 10);
|
||||
let year = parseInt(code.slice(4, 8), 10);
|
||||
result.push(asusKeygen(year, month, day));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,198 @@
|
||||
// OPENSRC-1D3B = S3yJ91q0Gar3O72I
|
||||
// ABCDEFG-1D3B xvn0qEeftqyrkG52
|
||||
// NOSOUP4-3A5B zvd97y9h
|
||||
// 7G9C0G2-6FF1 35c0b0tVb32Z6ivD
|
||||
//
|
||||
//
|
||||
// HDD SN WXH109A14712 ?
|
||||
import {
|
||||
calculateSuffix, dellHddSolver, dellSolver, DellTag, hddOldSolver, keygenDell, SuffixType
|
||||
} from "./dell";
|
||||
|
||||
// shortcut for simpler testing
|
||||
function checkSuffix(serial: string, tag: DellTag, type: SuffixType): number[] {
|
||||
serial = serial.concat(tag);
|
||||
let serialArr: number[] = serial.split("").map((c) => c.charCodeAt(0));
|
||||
return calculateSuffix(serialArr, tag, type);
|
||||
}
|
||||
|
||||
describe("Test calculateSuffix", () => {
|
||||
it("Check tag suffix for: 1234567-595B", () => {
|
||||
let suffix = checkSuffix("1234567", DellTag.Tag595B, SuffixType.ServiceTag);
|
||||
expect(suffix).toEqual([25, 34, 38, 8, 32, 48, 23, 8]);
|
||||
});
|
||||
|
||||
it("Check tag suffix for: 1234567-D35B", () => {
|
||||
let suffix = checkSuffix("1234567", DellTag.TagD35B, SuffixType.ServiceTag);
|
||||
expect(suffix).toEqual([25, 34, 38, 8, 32, 48, 23, 8]);
|
||||
});
|
||||
|
||||
it("Check tag suffix for: 1234567-2A7B", () => {
|
||||
let suffix = checkSuffix("1234567", DellTag.Tag2A7B, SuffixType.ServiceTag);
|
||||
expect(suffix).toEqual([101, 103, 102, 117, 115, 100, 97, 117]);
|
||||
});
|
||||
|
||||
it("Check tag suffix for: 1234567-A95B", () => {
|
||||
let suffix = checkSuffix("1234567", DellTag.TagA95B, SuffixType.ServiceTag);
|
||||
expect(suffix).toEqual([25, 34, 38, 8, 32, 48, 23, 8]);
|
||||
});
|
||||
|
||||
it("Check tag suffix for: 1234567-1D3B", () => {
|
||||
let suffix = checkSuffix("1234567", DellTag.Tag1D3B, SuffixType.ServiceTag);
|
||||
expect(suffix).toEqual([65, 78, 57, 72, 97, 56, 80, 72]);
|
||||
});
|
||||
|
||||
it("Check tag suffix for: 1234567-6FF1", () => {
|
||||
let suffix = checkSuffix("1234567", DellTag.Tag6FF1, SuffixType.ServiceTag);
|
||||
expect(suffix).toEqual([51, 73, 56, 52, 76, 122, 71, 52]);
|
||||
});
|
||||
|
||||
it("Check tag suffix for: 1234567-1F66", () => {
|
||||
let suffix = checkSuffix("1234567", DellTag.Tag1F66, SuffixType.ServiceTag);
|
||||
expect(suffix).toEqual([117, 66, 48, 111, 83, 107, 85, 111]);
|
||||
});
|
||||
|
||||
// HDD
|
||||
it("Check hdd suffix for: 12345678901-595B", () => {
|
||||
let suffix = checkSuffix("12345678901", DellTag.Tag595B, SuffixType.HDD);
|
||||
expect(suffix).toEqual([5, 9, 35, 6, 47, 5, 21, 32]);
|
||||
});
|
||||
|
||||
it("Check hdd suffix for: 12345678901-D35B", () => {
|
||||
let suffix = checkSuffix("12345678901", DellTag.TagD35B, SuffixType.HDD);
|
||||
expect(suffix).toEqual([5, 9, 35, 6, 47, 5, 21, 32]);
|
||||
});
|
||||
|
||||
it("Check hdd suffix for: 12345678901-2A7B", () => {
|
||||
let suffix = checkSuffix("12345678901", DellTag.Tag2A7B, SuffixType.HDD);
|
||||
expect(suffix).toEqual([48, 51, 113, 98, 107, 48, 99, 115]);
|
||||
});
|
||||
|
||||
it("Check hdd suffix for: 12345678901-A95B", () => {
|
||||
let suffix = checkSuffix("12345678901", DellTag.TagA95B, SuffixType.HDD);
|
||||
expect(suffix).toEqual([5, 9, 35, 6, 47, 5, 21, 32]);
|
||||
});
|
||||
|
||||
it("Check hdd suffix for: 12345678901-1D3B", () => {
|
||||
let suffix = checkSuffix("12345678901", DellTag.Tag1D3B, SuffixType.HDD);
|
||||
expect(suffix).toEqual([48, 73, 55, 118, 76, 48, 99, 97]);
|
||||
});
|
||||
|
||||
it("Check hdd suffix for: 12345678901-6FF1", () => {
|
||||
let suffix = checkSuffix("12345678901", DellTag.Tag6FF1, SuffixType.HDD);
|
||||
expect(suffix).toEqual([48, 112, 75, 86, 101, 48, 77, 76]);
|
||||
});
|
||||
|
||||
it("Check hdd suffix for: 12345678901-1F66", () => {
|
||||
let suffix = checkSuffix("12345678901", DellTag.Tag1F66, SuffixType.HDD);
|
||||
expect(suffix).toEqual([48, 114, 79, 71, 55, 48, 49, 83]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test keygenDell", () => {
|
||||
it("Dell password for: 1234567-595B", () => {
|
||||
expect(keygenDell("1234567", DellTag.Tag595B, SuffixType.ServiceTag))
|
||||
.toEqual("46rg65ky");
|
||||
});
|
||||
it("Dell password for: 1234567-D35B", () => {
|
||||
expect(keygenDell("1234567", DellTag.TagD35B, SuffixType.ServiceTag))
|
||||
.toEqual("5tc8q9re");
|
||||
});
|
||||
it("Dell password for: 1234567-2A7B", () => {
|
||||
expect(keygenDell("1234567", DellTag.Tag2A7B, SuffixType.ServiceTag))
|
||||
.toEqual("J1KuwWpSUgnDarfi");
|
||||
});
|
||||
it("Dell password for: 1234567-A95B", () => {
|
||||
expect(keygenDell("1234567", DellTag.TagA95B, SuffixType.ServiceTag))
|
||||
.toEqual("46rg65ky");
|
||||
});
|
||||
it("Dell password for: 1234567-1D3B", () => {
|
||||
expect(keygenDell("1234567", DellTag.Tag1D3B, SuffixType.ServiceTag))
|
||||
.toEqual("Sn4fkF8bS57NymZl");
|
||||
});
|
||||
it("Dell password for: 1234567-1F66", () => {
|
||||
expect(keygenDell("1234567", DellTag.Tag1F66, SuffixType.ServiceTag))
|
||||
.toEqual("kIpTBzx0m3s10JDR");
|
||||
});
|
||||
it("Dell password for: 1234567-6FF1", () => {
|
||||
expect(keygenDell("1234567", DellTag.Tag6FF1, SuffixType.ServiceTag))
|
||||
.toEqual("Rzn1wGe555H5bM2r");
|
||||
});
|
||||
it("Dell password for: OPENSRC-1D3B", () => {
|
||||
expect(keygenDell("OPENSRC", DellTag.Tag1D3B, SuffixType.ServiceTag))
|
||||
.toEqual("S3yJ91q0Gar3O72I");
|
||||
});
|
||||
it("Dell password for: ABCDEFG-1D3B", () => {
|
||||
expect(keygenDell("ABCDEFG", DellTag.Tag1D3B, SuffixType.ServiceTag))
|
||||
.toEqual("xvn0qEeftqyrkG52");
|
||||
});
|
||||
it("Dell password for: 7G9C0G2-6FF1", () => {
|
||||
expect(keygenDell("7G9C0G2", DellTag.Tag6FF1, SuffixType.ServiceTag))
|
||||
.toEqual("35c0b0tVb32Z6ivD");
|
||||
});
|
||||
it("Dell password for: DELLSUX-1F66", () => {
|
||||
expect(keygenDell("DELLSUX", DellTag.Tag1F66, SuffixType.ServiceTag))
|
||||
.toEqual("qHXaL0ntli6Gu4c0");
|
||||
});
|
||||
it("Dell password for: CRPP562-1F66", () => {
|
||||
expect(keygenDell("CRPP562", DellTag.Tag1F66, SuffixType.ServiceTag))
|
||||
.toEqual("8i5qLGa9woA919Ys");
|
||||
});
|
||||
it("Dell password for: CDG8T32-1F66", () => {
|
||||
expect(keygenDell("CDG8T32", DellTag.Tag1F66, SuffixType.ServiceTag))
|
||||
.toEqual("4Ke3y2L3kTP2f6Vo");
|
||||
});
|
||||
it("Dell password for: 8M5RQ32-1F66", () => {
|
||||
expect(keygenDell("8M5RQ32", DellTag.Tag1F66, SuffixType.ServiceTag))
|
||||
.toEqual("3rlrbaSj46Iw221g");
|
||||
});
|
||||
// HDD
|
||||
it("Dell HDD password for: 1234567890A-595B", () => {
|
||||
expect(keygenDell("1234567890A", DellTag.Tag595B, SuffixType.HDD))
|
||||
.toEqual("nyoap4lq");
|
||||
});
|
||||
it("Dell HDD password for: 1234567890A-D35B", () => {
|
||||
expect(keygenDell("1234567890A", DellTag.TagD35B, SuffixType.HDD))
|
||||
.toEqual("dc14blrd");
|
||||
});
|
||||
it("Dell HDD password for: 1234567890A-2A7B", () => {
|
||||
expect(keygenDell("1234567890A", DellTag.Tag2A7B, SuffixType.HDD))
|
||||
.toEqual("h6lwdi91qluUyt3u");
|
||||
});
|
||||
it("Dell HDD password for: 1234567890A-A95B", () => {
|
||||
expect(keygenDell("1234567890A", DellTag.TagA95B, SuffixType.HDD))
|
||||
.toEqual("qr0s6x4n");
|
||||
});
|
||||
it("Dell HDD password for: 1234567890A-1D3B", () => {
|
||||
expect(keygenDell("1234567890A", DellTag.Tag1D3B, SuffixType.HDD))
|
||||
.toEqual("6JQ1WacHNNR0Taia");
|
||||
});
|
||||
it("Dell HDD password for: 1234567890A-1F66", () => {
|
||||
expect(keygenDell("1234567890A", DellTag.Tag1F66, SuffixType.HDD))
|
||||
.toEqual("vP0M31x066Z7Rq9p");
|
||||
});
|
||||
it("Dell HDD password for: 1234567890A-6FF1", () => {
|
||||
expect(keygenDell("1234567890A", DellTag.Tag6FF1, SuffixType.HDD))
|
||||
.toEqual("5enLLpM3Immfb8CK");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test Dell BIOS", () => {
|
||||
it("Dell for 12345678901 is yyyyyhnn", () => {
|
||||
expect(hddOldSolver("12345678901")).toEqual(["yyyyyhnn"]);
|
||||
});
|
||||
it("Dell for 1234567-595B", () => {
|
||||
expect(dellSolver("1234567-595B")).toEqual(["46rg65ky"]);
|
||||
});
|
||||
it("Dell for: 1234567-1F66", () => {
|
||||
expect(dellSolver("1234567-1f66")).toEqual(["kIpTBzx0m3s10JDR"]);
|
||||
});
|
||||
it("Dell HDD for: 1234567890A-595B", () => {
|
||||
expect(dellHddSolver("1234567890A-595b")).toEqual(["nyoap4lq"]);
|
||||
});
|
||||
it("Check bad dell tag", () => {
|
||||
expect(dellSolver("1234567-BAD1")).toEqual([]);
|
||||
expect(dellSolver("1234567-TOLONG")).toEqual([]);
|
||||
expect(dellHddSolver("1234567-SHORT")).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,370 @@
|
||||
/* tslint:disable:no-bitwise */
|
||||
import { DellTag } from "./types";
|
||||
|
||||
const md5magic = [
|
||||
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
|
||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
|
||||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
|
||||
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
|
||||
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
|
||||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
|
||||
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
|
||||
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
|
||||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
|
||||
].map((v) => v | 0);
|
||||
|
||||
const md5magic2 = [
|
||||
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
|
||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
|
||||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
|
||||
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
|
||||
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
|
||||
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
|
||||
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
|
||||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039
|
||||
].map((v) => v | 0);
|
||||
|
||||
const rotationTable = [
|
||||
[7, 12, 17, 22],
|
||||
[5, 9, 14, 20],
|
||||
[4, 11, 16, 23],
|
||||
[6, 10, 15, 21]
|
||||
];
|
||||
|
||||
const initialData = [
|
||||
0x67452301 | 0,
|
||||
0xEFCDAB89 | 0,
|
||||
0x98BADCFE | 0,
|
||||
0x10325476 | 0
|
||||
];
|
||||
|
||||
type SumFunction = (a: number, b: number) => number;
|
||||
type EncFunction = (a: number, b: number, c: number) => number;
|
||||
interface Encoder {
|
||||
encode(data: number[]): number[];
|
||||
}
|
||||
|
||||
function rol(x: number, bitsrot: number): number {
|
||||
// n >>> 0 used to convert signed number to unsigned
|
||||
// (unsigned(x) >> (32 - bitsrot)) | (unsigned(x) << bitsrot);
|
||||
return ((x >>> 0) / Math.pow(2, 32 - bitsrot)) | (((x >>> 0) << bitsrot) | 0 );
|
||||
}
|
||||
|
||||
function encF2(num1: number, num2: number, num3: number): number {
|
||||
return ((num3 ^ num2) & num1) ^ num3;
|
||||
}
|
||||
|
||||
function encF3(num1: number, num2: number, num3: number): number {
|
||||
return ((num1 ^ num2) & num3) ^ num2;
|
||||
}
|
||||
|
||||
function encF4(num1: number, num2: number, num3: number): number {
|
||||
return (num2 ^ num1) ^ num3;
|
||||
}
|
||||
|
||||
function encF5(num1: number, num2: number, num3: number): number {
|
||||
return (num1 | ~num3) ^ num2;
|
||||
}
|
||||
|
||||
function encF1(num1: number, num2: number): number {
|
||||
return (num1 + num2) | 0;
|
||||
}
|
||||
|
||||
// Negative functions
|
||||
function encF1N(num1: number, num2: number): number {
|
||||
return (num1 - num2) | 0;
|
||||
}
|
||||
|
||||
function encF2N(num1: number, num2: number, num3: number): number {
|
||||
return encF2(num1, num2, ~num3);
|
||||
}
|
||||
|
||||
function encF4N(num1: number, num2: number, num3: number): number {
|
||||
return encF4(num1, ~num2, num3);
|
||||
}
|
||||
|
||||
function encF5N(num1: number, num2: number, num3: number): number {
|
||||
return encF5(~num1, num2, num3);
|
||||
}
|
||||
|
||||
class Tag595BEncoder {
|
||||
protected encBlock: number[];
|
||||
protected encData: number[];
|
||||
protected A: number;
|
||||
protected B: number;
|
||||
protected C: number;
|
||||
protected D: number;
|
||||
protected f1: SumFunction = encF1N;
|
||||
protected f2: EncFunction = encF2N;
|
||||
protected f3: EncFunction = encF3;
|
||||
protected f4: EncFunction = encF4N;
|
||||
protected f5: EncFunction = encF5N;
|
||||
protected md5table: number[] = md5magic;
|
||||
|
||||
constructor(encBlock: number[]) {
|
||||
this.encBlock = encBlock;
|
||||
this.encData = initialData.slice();
|
||||
this.A = this.encData[0];
|
||||
this.B = this.encData[1];
|
||||
this.C = this.encData[2];
|
||||
this.D = this.encData[3];
|
||||
}
|
||||
|
||||
protected calculate(func: EncFunction, key1: number, key2: number): number {
|
||||
let temp = func(this.B, this.C, this.D);
|
||||
return this.A + this.f1(temp, this.md5table[key2] + this.encBlock[key1]) | 0;
|
||||
}
|
||||
|
||||
protected incrementData() {
|
||||
this.encData[0] += this.A;
|
||||
this.encData[1] += this.B;
|
||||
this.encData[2] += this.C;
|
||||
this.encData[3] += this.D;
|
||||
|
||||
this.encData.forEach((val, index) => {
|
||||
this.encData[index] = val | 0;
|
||||
});
|
||||
}
|
||||
|
||||
public makeEncode(): void {
|
||||
let t: number = 0;
|
||||
for (let i = 0; i < 64; i++) {
|
||||
switch (i >> 4) {
|
||||
case 0:
|
||||
t = this.calculate(this.f2, i & 15, i); // Use half byte
|
||||
break;
|
||||
case 1:
|
||||
t = this.calculate(this.f3, (i * 5 + 1) & 15, i);
|
||||
break;
|
||||
case 2:
|
||||
t = this.calculate(this.f4, (i * 3 + 5) & 15, i);
|
||||
break;
|
||||
case 3:
|
||||
t = this.calculate(this.f5, (i * 7) & 15, i);
|
||||
break;
|
||||
}
|
||||
this.A = this.D;
|
||||
this.D = this.C;
|
||||
this.C = this.B;
|
||||
this.B = rol(t, rotationTable[i >> 4][i & 3]) + this.B | 0;
|
||||
}
|
||||
|
||||
this.incrementData();
|
||||
}
|
||||
|
||||
public result(): number[] {
|
||||
return this.encData.map((v) => v | 0);
|
||||
}
|
||||
|
||||
public static encode(encBlock: number[]): number[] {
|
||||
let obj = new this(encBlock);
|
||||
obj.makeEncode();
|
||||
return obj.result();
|
||||
}
|
||||
}
|
||||
|
||||
class TagD35BEncoder extends Tag595BEncoder {
|
||||
protected f1 = encF1;
|
||||
protected f2 = encF2;
|
||||
protected f3 = encF3;
|
||||
protected f4 = encF4;
|
||||
protected f5 = encF5;
|
||||
}
|
||||
|
||||
class Tag1D3BEncoder extends Tag595BEncoder {
|
||||
protected f1 = encF1N;
|
||||
protected f2 = encF2N;
|
||||
protected f3 = encF3;
|
||||
protected f4 = encF4N;
|
||||
protected f5 = encF5N;
|
||||
|
||||
public makeEncode(): void {
|
||||
for (let j = 0; j < 21; j++) {
|
||||
this.A |= 0x97;
|
||||
this.B ^= 0x8;
|
||||
this.C |= 0x60606161 - j;
|
||||
this.D ^= 0x50501010 + j;
|
||||
super.makeEncode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Tag1F66Encoder extends Tag595BEncoder {
|
||||
protected f1 = encF1N;
|
||||
protected f2 = encF2N;
|
||||
protected f3 = encF3;
|
||||
protected f4 = encF4N;
|
||||
protected f5 = encF5N;
|
||||
protected md5table = md5magic2;
|
||||
|
||||
public makeEncode(): void {
|
||||
let t: number = 0;
|
||||
|
||||
for (let j = 0; j < 17; j++) {
|
||||
this.A |= 0x100097;
|
||||
this.B ^= 0xA0008;
|
||||
this.C |= 0x60606161 - j;
|
||||
this.D ^= 0x50501010 + j;
|
||||
|
||||
for (let i = 0; i < 64; i++) {
|
||||
switch (i >> 4) {
|
||||
case 0:
|
||||
t = this.calculate(this.f2, i & 15, i + 16 | 0);
|
||||
break;
|
||||
case 1:
|
||||
t = this.calculate(this.f3, (i * 5 + 1) & 15, i + 32 | 0);
|
||||
break;
|
||||
case 2:
|
||||
t = this.calculate(this.f4, (i * 3 + 5) & 15, i - 2 * (i & 12) + 12);
|
||||
break;
|
||||
case 3:
|
||||
t = this.calculate(this.f5, (i * 7) & 15, 2 * (i & 3) - (i & 15) + 12);
|
||||
break;
|
||||
}
|
||||
this.A = this.D;
|
||||
this.D = this.C;
|
||||
this.C = this.B;
|
||||
this.B = rol(t, rotationTable[i >> 4][i & 3]) + this.B | 0;
|
||||
}
|
||||
|
||||
this.incrementData();
|
||||
}
|
||||
|
||||
for (let j = 0; j < 21; j++) {
|
||||
|
||||
this.A |= 0x97;
|
||||
this.B ^= 0x8;
|
||||
this.C |= 0x50501010 - j;
|
||||
this.D ^= 0x60606161 + j;
|
||||
|
||||
for (let i = 0; i < 64; i++) {
|
||||
switch (i >> 4) {
|
||||
case 0:
|
||||
t = this.calculate(this.f4, (i * 3 + 5) & 15, 2 * (i & 3) - i + 44);
|
||||
break;
|
||||
case 1:
|
||||
t = this.calculate(this.f5, (i * 7) & 15, 2 * (i & 3) - i + 76);
|
||||
break;
|
||||
case 2:
|
||||
t = this.calculate(this.f2, i & 15, (i & 15) | 0);
|
||||
break;
|
||||
case 3:
|
||||
t = this.calculate(this.f3, (i * 5 + 1) & 15, i - 32 | 0);
|
||||
break;
|
||||
}
|
||||
let g = (i >> 4) + 2;
|
||||
this.A = this.D;
|
||||
this.D = this.C;
|
||||
this.C = this.B;
|
||||
this.B = rol(t, rotationTable[g & 3][i & 3]) + this.B | 0;
|
||||
}
|
||||
|
||||
this.incrementData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Tag6FF1Encoder extends Tag595BEncoder {
|
||||
protected f1 = encF1N;
|
||||
protected f2 = encF2N;
|
||||
protected f3 = encF3;
|
||||
protected f4 = encF4N;
|
||||
protected f5 = encF5N;
|
||||
protected md5table = md5magic2;
|
||||
|
||||
public makeEncode(): void {
|
||||
let t: number = 0;
|
||||
|
||||
for (let j = 0; j < 23; j++) {
|
||||
this.A |= 0xA08097;
|
||||
this.B ^= 0xA010908;
|
||||
this.C |= 0x60606161 - j;
|
||||
this.D ^= 0x50501010 + j;
|
||||
|
||||
for (let i = 0; i < 64; i++) {
|
||||
let k = (i & 15) - ((i & 12) << 1) + 12;
|
||||
switch (i >> 4) {
|
||||
case 0:
|
||||
t = this.calculate(this.f2, i & 15, i + 32 | 0);
|
||||
break;
|
||||
case 1:
|
||||
t = this.calculate(this.f3, (i * 5 + 1) & 15, (i & 15) | 0);
|
||||
break;
|
||||
case 2:
|
||||
t = this.calculate(this.f4, (i * 3 + 5) & 15, k + 16 | 0);
|
||||
break;
|
||||
case 3:
|
||||
t = this.calculate(this.f5, (i * 7) & 15, k + 48 | 0);
|
||||
break;
|
||||
}
|
||||
this.A = this.D;
|
||||
this.D = this.C;
|
||||
this.C = this.B;
|
||||
this.B = rol(t, rotationTable[i >> 4][i & 3]) + this.B | 0;
|
||||
}
|
||||
|
||||
this.incrementData();
|
||||
}
|
||||
|
||||
for (let j = 0; j < 17; j++) {
|
||||
this.A |= 0x100097;
|
||||
this.B ^= 0xA0008;
|
||||
this.C |= 0x50501010 - j;
|
||||
this.D ^= 0x60606161 + j;
|
||||
|
||||
for (let i = 0; i < 64; i++) {
|
||||
let k = (i & 15) - ((i & 12) << 1) + 12;
|
||||
switch (i >> 4) {
|
||||
case 0:
|
||||
t = this.calculate(this.f4, ((i & 15) * 3 + 5) & 15, k + 16);
|
||||
break;
|
||||
case 1:
|
||||
t = this.calculate(this.f5, ((i & 3) * 7 + (i & 12) + 4) & 15, (i & 15) + 32);
|
||||
break;
|
||||
case 2:
|
||||
t = this.calculate(this.f2, k & 15, k);
|
||||
break;
|
||||
case 3:
|
||||
t = this.calculate(this.f3, ((i & 15) * 5 + 1) & 15, (i & 15) + 48);
|
||||
break;
|
||||
}
|
||||
let g = (i >> 4) + 2;
|
||||
this.A = this.D;
|
||||
this.D = this.C;
|
||||
this.C = this.B;
|
||||
this.B = rol(t, rotationTable[g & 3][i & 3]) + this.B | 0;
|
||||
}
|
||||
|
||||
this.incrementData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const encoders: {readonly [P in DellTag]: Encoder} = {
|
||||
"595B": Tag595BEncoder,
|
||||
"2A7B": Tag595BEncoder, // same as 595B
|
||||
"A95B": Tag595BEncoder, // same as 595B
|
||||
"1D3B": Tag1D3BEncoder,
|
||||
"D35B": TagD35BEncoder,
|
||||
"1F66": Tag1F66Encoder,
|
||||
"6FF1": Tag6FF1Encoder
|
||||
};
|
||||
|
||||
export function blockEncode(encBlock: number[], tag: DellTag): number[] {
|
||||
return encoders[tag].encode(encBlock);
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
/* tslint:disable:no-bitwise */
|
||||
import { makeSolver } from "../utils";
|
||||
import { blockEncode } from "./encode";
|
||||
import { DellTag, SuffixType } from "./types";
|
||||
export { DellTag, SuffixType};
|
||||
|
||||
const scanCodes: string =
|
||||
"\0\x1B1234567890-=\x08\x09qwertyuiop[]\x0D\xFFasdfghjkl;'`\xFF\\zxcvbnm,./";
|
||||
|
||||
const encscans: number[] = [
|
||||
0x05, 0x10, 0x13, 0x09, 0x32, 0x03, 0x25, 0x11, 0x1F, 0x17, 0x06, 0x15,
|
||||
0x30, 0x19, 0x26, 0x22, 0x0A, 0x02, 0x2C, 0x2F, 0x16, 0x14, 0x07, 0x18,
|
||||
0x24, 0x23, 0x31, 0x20, 0x1E, 0x08, 0x2D, 0x21, 0x04, 0x0B, 0x12, 0x2E
|
||||
];
|
||||
|
||||
const extraCharacters: {readonly [P in DellTag]?: string} = {
|
||||
"2A7B": "012345679abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0",
|
||||
"1D3B": "0BfIUG1kuPvc8A9Nl5DLZYSno7Ka6HMgqsJWm65yCQR94b21OTp7VFX2z0jihE33d4xtrew0",
|
||||
"1F66": "0ewr3d4xtUG1ku0BfIp7VFb21OTSno7KDLZYqsJWa6HMgCQR94m65y9Nl5Pvc8AjihE3X2z0",
|
||||
"6FF1": "08rptBxfbGVMz38IiSoeb360MKcLf4QtBCbWVzmH5wmZUcRR5DZG2xNCEv1nFtzsZB2bw1X0"
|
||||
};
|
||||
|
||||
/*
|
||||
* Does this really work somewhere ?
|
||||
* Depends only in first two chars
|
||||
* Input: 11 symbols
|
||||
*/
|
||||
function keygenHddOld(serial: string): string {
|
||||
let serialArr: number[] = serial.split("").map((c) => c.charCodeAt(0));
|
||||
// encscans[26], encscans[0xAA % encscans.length]
|
||||
let ret: number[] = [49, 49, 49, 49, 49];
|
||||
ret.push(serialArr[1] >> 1);
|
||||
ret.push((serialArr[1] >> 6) | (serialArr[0] << 2));
|
||||
ret.push(serialArr[0] >> 3);
|
||||
// lower bits then 5 are never change
|
||||
for (let i = 0; i < 8; i++) {
|
||||
let r = 0xAA;
|
||||
if (ret[i] & 8) {
|
||||
r ^= serialArr[1];
|
||||
}
|
||||
if (ret[i] & 16) {
|
||||
r ^= serialArr[0];
|
||||
}
|
||||
ret[i] = encscans[r % encscans.length];
|
||||
}
|
||||
return ret.map((c) => scanCodes.charAt(c)).join("");
|
||||
}
|
||||
|
||||
export function calculateSuffix(serial: number[], tag: DellTag, type: SuffixType): number[] {
|
||||
let suffix: number[] = [];
|
||||
let codesTable: number[];
|
||||
let arr1: number[];
|
||||
let arr2: number[];
|
||||
|
||||
if (type === SuffixType.ServiceTag) {
|
||||
arr1 = [1, 2, 3, 4];
|
||||
arr2 = [4, 3, 2];
|
||||
} else {
|
||||
// SuffixType.HDD
|
||||
arr1 = [1, 10, 9, 8];
|
||||
arr2 = [8, 9, 10];
|
||||
}
|
||||
|
||||
suffix[0] = serial[arr1[3]];
|
||||
suffix[1] = (serial[arr1[3]] >> 5) |
|
||||
(((serial[arr1[2]] >> 5) | (serial[arr1[2]] << 3)) & 0xF1);
|
||||
suffix[2] = serial[arr1[2]] >> 2;
|
||||
suffix[3] = (serial[arr1[2]] >> 7) | (serial[arr1[1]] << 1);
|
||||
suffix[4] = (serial[arr1[1]] >> 4) | (serial[arr1[0]] << 4);
|
||||
suffix[5] = serial[1] >> 1;
|
||||
suffix[6] = (serial[1] >> 6) | (serial[0] << 2);
|
||||
suffix[7] = serial[0] >> 3;
|
||||
|
||||
// normalize bytes
|
||||
suffix.forEach((v, i) => {
|
||||
suffix[i] = v & 0xFF;
|
||||
});
|
||||
|
||||
let table = extraCharacters[tag];
|
||||
if (table !== undefined) {
|
||||
codesTable = table.split("").map((s) => s.charCodeAt(0));
|
||||
} else {
|
||||
codesTable = encscans;
|
||||
}
|
||||
|
||||
for (let i = 0; i < 8; i++) {
|
||||
let r = 0xAA;
|
||||
if (suffix[i] & 1) {
|
||||
r ^= serial[arr2[0] ];
|
||||
}
|
||||
if (suffix[i] & 2) {
|
||||
r ^= serial[arr2[1]];
|
||||
}
|
||||
if (suffix[i] & 4) {
|
||||
r ^= serial[arr2[2]];
|
||||
}
|
||||
if (suffix[i] & 8) {
|
||||
r ^= serial[1];
|
||||
}
|
||||
if (suffix[i] & 16) {
|
||||
r ^= serial[0];
|
||||
}
|
||||
|
||||
suffix[i] = codesTable[r % codesTable.length];
|
||||
}
|
||||
|
||||
return suffix;
|
||||
}
|
||||
|
||||
function resultToString(arr: number[], tag: DellTag): string {
|
||||
let r = arr[0] % 9;
|
||||
let result = "";
|
||||
let table = extraCharacters[tag];
|
||||
for (let i = 0; i < 16; i++) {
|
||||
if (table !== undefined) {
|
||||
result += table.charAt(arr[i] % table.length);
|
||||
} else if (r <= i && result.length < 8) { // 595B, D35B, A95B
|
||||
result += scanCodes.charAt(encscans[arr[i] % encscans.length]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/*
|
||||
* 7 symbols + 4 symbols ( 595B, D35B, 2A7B, A95B, 1D3B etc...)
|
||||
* serial -- serial number without tag, 7 symbols for ServiceTag, 11 symbols for HDD
|
||||
* tag -- tag string
|
||||
*/
|
||||
export function keygenDell(serial: string, tag: DellTag, type: SuffixType): string {
|
||||
let fullSerial: string;
|
||||
|
||||
function byteArrayToInt(arr: number[]): number[] {
|
||||
// convert byte array to 32-bit little-endian int array
|
||||
// also will convert undefined values to 0
|
||||
let resultLength = arr.length >> 2; // divide length to 4
|
||||
let result: number[] = [];
|
||||
for (let i = 0; i <= resultLength; i++) {
|
||||
result[i] = arr[i * 4] | (arr[i * 4 + 1] << 8) |
|
||||
(arr[i * 4 + 2] << 16) | (arr[i * 4 + 3] << 24) | 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function intArrayToByte(arr: number[]): number[] {
|
||||
// convert 32-bit little-endian array to byte array
|
||||
let result: number[] = [];
|
||||
arr.forEach((num) => {
|
||||
result.push(num & 0xFF);
|
||||
result.push((num >> 8) & 0xFF);
|
||||
result.push((num >> 16) & 0xFF);
|
||||
result.push((num >> 24) & 0xFF);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
if (tag === DellTag.TagA95B) {
|
||||
|
||||
if (type === SuffixType.ServiceTag) {
|
||||
fullSerial = serial + DellTag.Tag595B as string;
|
||||
} else { // HDD
|
||||
fullSerial = serial.slice(3) + "\0\0\0" + DellTag.Tag595B as string;
|
||||
}
|
||||
|
||||
} else {
|
||||
fullSerial = serial + tag as string;
|
||||
}
|
||||
|
||||
let fullSerialArray: number[] = [];
|
||||
// convert string to byte array
|
||||
for (let i = 0; i < fullSerial.length; i++) {
|
||||
// Maybe protect against unicode symbols with: charCode & 0xFF ?
|
||||
fullSerialArray.push(fullSerial.charCodeAt(i));
|
||||
}
|
||||
|
||||
fullSerialArray = fullSerialArray.concat(calculateSuffix(fullSerialArray, tag, type));
|
||||
const cnt = 23;
|
||||
// NOTE: after this array might contain undefined values
|
||||
fullSerialArray[cnt] = 0x80;
|
||||
let encBlock = byteArrayToInt(fullSerialArray);
|
||||
// fill empty values with zeros
|
||||
for (let i = 0; i < 16; i++) {
|
||||
if (encBlock[i] === undefined) {
|
||||
encBlock[i] = 0;
|
||||
}
|
||||
}
|
||||
encBlock[14] = cnt << 3;
|
||||
let decodedBytes = intArrayToByte(blockEncode(encBlock, tag));
|
||||
return resultToString(decodedBytes, tag);
|
||||
}
|
||||
|
||||
function checkDellTag(tag: string): boolean {
|
||||
tag = tag.toUpperCase();
|
||||
for (let tagItem in DellTag) {
|
||||
if (tag === DellTag[tagItem]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export let hddOldSolver = makeSolver({
|
||||
name: "dellHDDOld",
|
||||
description: "Dell HDD Serial Number (old)",
|
||||
examples: ["12345678901"],
|
||||
inputValidator: (s) => s.length === 11,
|
||||
fun: (s) => [keygenHddOld(s)]
|
||||
});
|
||||
|
||||
export let dellSolver = makeSolver({
|
||||
name: "dellTag",
|
||||
description: "Dell from serial number",
|
||||
examples: ["1234567-595B", "1234567-1D3B"],
|
||||
inputValidator: (password: string) => {
|
||||
if (password.length !== 11) {
|
||||
return false;
|
||||
} else {
|
||||
return checkDellTag(password.slice(7, 11));
|
||||
}
|
||||
},
|
||||
fun: (password: string) => {
|
||||
let suffix = password.slice(7, 11).toUpperCase();
|
||||
return [keygenDell(password.slice(0, 7), suffix as DellTag, SuffixType.ServiceTag)];
|
||||
}
|
||||
});
|
||||
|
||||
export let dellHddSolver = makeSolver({
|
||||
name: "dellHddNew",
|
||||
description: "Dell from hdd serial number",
|
||||
examples: ["1234567890A-595B"],
|
||||
inputValidator: (password: string) => {
|
||||
if (password.length !== 15) {
|
||||
return false;
|
||||
} else {
|
||||
return checkDellTag(password.slice(11, 15));
|
||||
}
|
||||
},
|
||||
fun: (password: string) => {
|
||||
let suffix = password.slice(11, 15).toUpperCase();
|
||||
return [keygenDell(password.slice(0, 11), suffix as DellTag, SuffixType.HDD)];
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
export enum DellTag {
|
||||
Tag595B = "595B",
|
||||
TagD35B = "D35B",
|
||||
Tag2A7B = "2A7B",
|
||||
TagA95B = "A95B",
|
||||
Tag1D3B = "1D3B",
|
||||
Tag6FF1 = "6FF1",
|
||||
Tag1F66 = "1F66"
|
||||
}
|
||||
|
||||
export const enum SuffixType {
|
||||
ServiceTag,
|
||||
HDD
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { fsi20DecNewSolver, fsi20DecOldSolver, fsiHexSolver } from "./fsi";
|
||||
|
||||
describe("Test Fujitsu-Siemens 5x4 hexadecimal BIOS", () => {
|
||||
it("FSI key for 1234-4321-1234-4321-1234 is 35682708", () => {
|
||||
expect(fsiHexSolver("1234-4321-1234-4321-1234")).toEqual(["35683789"]);
|
||||
});
|
||||
it("FSI key for AAAA-BBBB-CCCC-DEAD-BEEF is 64830592", () => {
|
||||
expect(fsiHexSolver("AAAA-BBBB-CCCC-DEAD-BEEF")).toEqual(["64830592"]);
|
||||
expect(fsiHexSolver("AAAABBBBCCCCDEADBEEF")).toEqual(["64830592"]);
|
||||
});
|
||||
it("FSI key for DEADBEEF is 64830592", () => {
|
||||
expect(fsiHexSolver("DEADBEEF")).toEqual(["64830592"]);
|
||||
});
|
||||
it("test invalid keys", () => {
|
||||
expect(fsiHexSolver("AAAA-BBBB-CCCC-DEAD-CODE")).toEqual([]);
|
||||
expect(fsiHexSolver("AAAA-BBBB-CCCC-DEAD-BEEF-12")).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test Fujitsu-Siemens 5x4 decimal new", () => {
|
||||
it("FSI key for 1234-4321-1234-4321-1234 is 7122790", () => {
|
||||
expect(fsi20DecNewSolver("1234-4321-1234-4321-1234")).toEqual(["7122790"]);
|
||||
});
|
||||
|
||||
it("FSI key for 7234-4321-1234-4321-1234 is 3122790", () => {
|
||||
expect(fsi20DecNewSolver("7234-4321-1234-4321-1234")).toEqual(["3122790"]);
|
||||
});
|
||||
|
||||
it("test invalid keys", () => {
|
||||
expect(fsi20DecNewSolver("1234-4321-1234-4321-1234-1")).toEqual([]);
|
||||
expect(fsi20DecNewSolver("1234-4321-1234-4321-BEEF")).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test Fujitsu-Siemens 5x4 decimal old", () => {
|
||||
it("FSI key for 1234-4321-1234-4321-1234 is 10cphf0b", () => {
|
||||
expect(fsi20DecOldSolver("1234-4321-1234-4321-1234")).toEqual(["10cphf0b"]);
|
||||
});
|
||||
|
||||
it("FSI key for 7234-4321-1234-4321-1234 is 10cphf0b", () => {
|
||||
expect(fsi20DecOldSolver("7234-4321-1234-4321-1234")).toEqual(["90ldhf0b"]);
|
||||
});
|
||||
|
||||
it("test invalid keys", () => {
|
||||
expect(fsi20DecOldSolver("1234-4321-1234-4321-1234-1")).toEqual([]);
|
||||
expect(fsi20DecOldSolver("1234-4321-1234-4321-BEEF")).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,147 @@
|
||||
import { makeSolver } from "./utils";
|
||||
/* tslint:disable:no-bitwise */
|
||||
|
||||
function generateCRC16Table(): number[] {
|
||||
let table: number[] = [];
|
||||
for (let i = 0, crc = 0; i < 256; i++) {
|
||||
crc = (i << 8);
|
||||
for (let j = 0; j < 8; j++) {
|
||||
crc = (crc << 1);
|
||||
if (crc & 0x10000) {
|
||||
crc = crc ^ 0x1021;
|
||||
}
|
||||
}
|
||||
table.push(crc & 0xFFFF);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
const crc16Table = generateCRC16Table();
|
||||
|
||||
/* For Fujinsu-Siemens. 8 or 5x4 hexadecimal digits. */
|
||||
function fsiHexKeygen(serial: string): string {
|
||||
|
||||
function hashToString(hash: number) {
|
||||
const zero = "0".charCodeAt(0);
|
||||
return [12, 8, 4, 0].reduce((acc, num) => {
|
||||
let temp = String.fromCharCode(zero + ((hash >> num) % 16) % 10);
|
||||
return acc + temp;
|
||||
}, "");
|
||||
}
|
||||
|
||||
function calculateHash(word: string, table: number[]) {
|
||||
let hash = 0;
|
||||
for (let i = 0, d = 0; i < word.length; i++) {
|
||||
d = table[(word.charCodeAt(i) ^ (hash >> 8)) % 256];
|
||||
hash = ((hash << 8) ^ d) & 0xFFFF ;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
if (serial.length === 20) {
|
||||
serial = serial.slice(12, 20);
|
||||
}
|
||||
|
||||
return hashToString(calculateHash(serial.slice(0, 4), crc16Table)) +
|
||||
hashToString(calculateHash(serial.slice(4, 8), crc16Table));
|
||||
}
|
||||
|
||||
/* For Fujinsu-Siemens. 5x4 dicimal digits */
|
||||
function fsi20DecOldKeygen(serial: string): string {
|
||||
|
||||
function swap<T>(arr: T[], i1: number, i2: number): void {
|
||||
const temp = arr[i1];
|
||||
arr[i1] = arr[i2];
|
||||
arr[i2] = temp;
|
||||
}
|
||||
// opArr - array with that operations do, ar1,ar2 - numbers */
|
||||
function interleave(opArr: number[], ar1: number[], ar2: number[]) {
|
||||
let arr = opArr.slice(0); // copy array
|
||||
arr[ar1[0]] = ((opArr[ar2[0]] >> 4) | (opArr[ar2[3]] << 4)) & 0xFF;
|
||||
arr[ar1[1]] = ((opArr[ar2[0]] & 0x0F) | (opArr[ar2[3]] & 0xF0));
|
||||
arr[ar1[2]] = ((opArr[ar2[1]] >> 4) | (opArr[ar2[2]] << 4) & 0xFF);
|
||||
arr[ar1[3]] = (opArr[ar2[1]] & 0x0F) | (opArr[ar2[2]] & 0xF0);
|
||||
return arr;
|
||||
}
|
||||
|
||||
function codeToBytes(code: string): number[] {
|
||||
const numbers = [
|
||||
parseInt(code.slice(0, 5), 10),
|
||||
parseInt(code.slice(5, 10), 10),
|
||||
parseInt(code.slice(10, 15), 10),
|
||||
parseInt(code.slice(15, 20), 10)
|
||||
];
|
||||
let acc = [];
|
||||
for (let val of numbers) {
|
||||
acc.push(val % 256);
|
||||
acc.push(Math.floor(val / 256));
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
function decryptCode_old(bytes: number[]) {
|
||||
const xorKey = ":3-v@e4i";
|
||||
// apply XOR key
|
||||
bytes.forEach((val, i, arr) => {
|
||||
arr[i] = val ^ xorKey.charCodeAt(i);
|
||||
});
|
||||
// swap two bytes
|
||||
swap(bytes, 2, 6);
|
||||
swap(bytes, 3, 7);
|
||||
bytes = interleave(bytes, [0, 1, 2, 3], [0, 1, 2, 3]);
|
||||
bytes = interleave(bytes, [4, 5, 6, 7], [6, 7, 4, 5]);
|
||||
// final rotations
|
||||
bytes[0] = ((bytes[0] << 3) & 0xFF) | (bytes[0] >> 5);
|
||||
bytes[1] = ((bytes[1] << 5) & 0xFF) | (bytes[1] >> 3);
|
||||
bytes[2] = ((bytes[2] << 7) & 0xFF) | (bytes[2] >> 1);
|
||||
bytes[3] = ((bytes[3] << 4) & 0xFF) | (bytes[3] >> 4);
|
||||
bytes[5] = ((bytes[5] << 6) & 0xFF) | (bytes[5] >> 2);
|
||||
bytes[6] = ((bytes[6] << 1) & 0xFF) | (bytes[6] >> 7);
|
||||
bytes[7] = ((bytes[7] << 2) & 0xFF) | (bytes[7] >> 6);
|
||||
// len(solution space) = 10 + 26
|
||||
bytes = bytes.map((b) => b % 36);
|
||||
return bytes.map((sbyte) => (sbyte > 9 )
|
||||
? String.fromCharCode("a".charCodeAt(0) + sbyte - 10)
|
||||
: String.fromCharCode("0".charCodeAt(0) + sbyte)
|
||||
).join("");
|
||||
}
|
||||
|
||||
return decryptCode_old(codeToBytes(serial));
|
||||
}
|
||||
|
||||
/* For Fujinsu-Siemens. 5x4 dicimal digits. new */
|
||||
function fsi20DecNewKeygen(serial: string): string {
|
||||
const fKeys = [
|
||||
"4798156302", "7201593846", "5412367098", "6587249310",
|
||||
"9137605284", "3974018625", "8052974163"
|
||||
];
|
||||
|
||||
return [0, 2, 5, 11, 13, 15, 16].map((val, i) => {
|
||||
let temp = parseInt(serial.charAt(val), 10);
|
||||
return fKeys[i].charAt(temp);
|
||||
}).join("");
|
||||
}
|
||||
|
||||
export let fsiHexSolver = makeSolver({
|
||||
name: "fsiHex",
|
||||
description: "Fujitsu-Siemens hexdigits",
|
||||
examples: ["DEADBEEF", "AAAA-BBBB-CCCC-DEAD-BEEF"],
|
||||
inputValidator: (s) => /^([0-9ABCDEF]{20}|[0-9ABCDEF]{8})$/i.test(s),
|
||||
fun: (code: string) => [fsiHexKeygen(code)]
|
||||
});
|
||||
|
||||
export let fsi20DecNewSolver = makeSolver({
|
||||
name: "fsiDecNew",
|
||||
description: "Fujitsu-Siemens decimal new",
|
||||
examples: ["1234-4321-1234-4321-1234"],
|
||||
inputValidator: (s) => /^\d{20}$/i.test(s),
|
||||
fun: (code: string) => [fsi20DecNewKeygen(code)]
|
||||
});
|
||||
|
||||
export let fsi20DecOldSolver = makeSolver({
|
||||
name: "fsiDecOld",
|
||||
description: "Fujitsu-Siemens decimal old",
|
||||
examples: ["1234-4321-1234-4321-1234"],
|
||||
inputValidator: (s) => /^\d{20}$/i.test(s),
|
||||
fun: (code: string) => [fsi20DecOldKeygen(code)]
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
import { hpMiniSolver } from "./hpmini";
|
||||
|
||||
describe("Test HP Mini BIOS", () => {
|
||||
it("HPMini key for CNU1234ABC is e9l37fvcpe", () => {
|
||||
expect(hpMiniSolver("CNU1234ABC")).toEqual(["e9l37fvcpe"]);
|
||||
});
|
||||
it("HPMini key for CNU1234567 is e9l37fvqgx", () => {
|
||||
expect(hpMiniSolver("CNU1234567")).toEqual(["e9l37fvqgx"]);
|
||||
});
|
||||
|
||||
it("HPMini key for CNU1234ABX is e9l37fvcp4 or e9l37fvcpr", () => {
|
||||
expect(hpMiniSolver("CNU1234ABX").sort()).toEqual(["e9l37fvcp4", "e9l37fvcpr"].sort());
|
||||
});
|
||||
|
||||
it("test invalid keys", () => {
|
||||
expect(hpMiniSolver("CNU12345678")).toEqual([]);
|
||||
expect(hpMiniSolver("CNU1234")).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
/* For HP/Compaq Netbooks. 10 chars */
|
||||
import { makeSolver } from "./utils";
|
||||
|
||||
const table1: {[key: string]: string} = {
|
||||
"1": "3", "0": "1", "3": "F", "2": "7", "5": "Q", "4": "V",
|
||||
"7": "X", "6": "G", "9": "O", "8": "U", "a": "C", "c": "E",
|
||||
"b": "P", "e": "M", "d": "T", "g": "H", "f": "8", "i": "Y",
|
||||
"h": "Z", "k": "S", "j": "W", "m": "4", "l": "K", "o": "J",
|
||||
"n": "9", "q": "5", "p": "2", "s": "N", "r": "B", "u": "L",
|
||||
"t": "A", "w": "D", "v": "6", "y": "I", "x": "4", "z": "0"
|
||||
};
|
||||
|
||||
const table2: {[key: string]: string} = {
|
||||
"1": "3", "0": "1", "3": "F", "2": "7", "5": "Q", "4": "V",
|
||||
"7": "X", "6": "G", "9": "O", "8": "U", "a": "C", "c": "E",
|
||||
"b": "P", "e": "M", "d": "T", "g": "H", "f": "8", "i": "Y",
|
||||
"h": "Z", "k": "S", "j": "W", "m": "4", "l": "K", "o": "J",
|
||||
"n": "9", "q": "5", "p": "2", "s": "N", "r": "B", "u": "L",
|
||||
"t": "A", "w": "D", "v": "6", "y": "I", "x": "R", "z": "0"
|
||||
};
|
||||
|
||||
function hpMiniKeygen(serial: string): string[] {
|
||||
|
||||
let password1 = "";
|
||||
let password2 = "";
|
||||
serial = serial.toLowerCase();
|
||||
for (let i = 0; i < serial.length; i++) {
|
||||
password1 += table1[serial.charAt(i)];
|
||||
password2 += table2[serial.charAt(i)];
|
||||
}
|
||||
if (password1 === password2) {
|
||||
return [password1.toLowerCase()];
|
||||
} else {
|
||||
return [password1.toLowerCase(), password2.toLowerCase()];
|
||||
}
|
||||
}
|
||||
|
||||
export let hpMiniSolver = makeSolver({
|
||||
name: "hpMini",
|
||||
description: "HP/Compaq Mini Netbooks",
|
||||
examples: ["CNU1234ABC"],
|
||||
inputValidator: (s) => /^[0-9A-Z]{10}$/i.test(s),
|
||||
fun: hpMiniKeygen
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { keygen, solvers } from "./";
|
||||
|
||||
describe("BIOS keygen", () => {
|
||||
it("Sony key for 1234567 is 9648669", () => {
|
||||
let keysList = keygen("1234567");
|
||||
expect(keysList[0][1]).toEqual(["9648669"]);
|
||||
});
|
||||
it("Solvers names should be unique", () => {
|
||||
let names: {[key: string]: boolean} = {};
|
||||
solvers.forEach((solver) => {
|
||||
if (solver.biosName in names) {
|
||||
throw Error(`${solver.biosName} isn't unique name`);
|
||||
} else {
|
||||
names[solver.biosName] = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
import { asusSolver } from "./asus";
|
||||
import { dellHddSolver, dellSolver, hddOldSolver } from "./dell";
|
||||
import { fsi20DecNewSolver, fsi20DecOldSolver, fsiHexSolver } from "./fsi";
|
||||
import { hpMiniSolver } from "./hpmini";
|
||||
import { insydeSolver } from "./insyde";
|
||||
import { monotonicTime } from "../polyfills/performancePolyfill";
|
||||
import {
|
||||
phoenixFsiLSolver, phoenixFsiPSolver, phoenixFsiSolver,
|
||||
phoenixFsiSSolver, phoenixFsiXSolver, phoenixHPCompaqSolver, phoenixSolver
|
||||
} from "./phoenix";
|
||||
import { samsungSolver } from "./samsung";
|
||||
import { sonySolver } from "./sony";
|
||||
import { Solver } from "./utils";
|
||||
|
||||
export type KeygenResult = [Solver, string[], number];
|
||||
|
||||
export const solvers: Solver[] = [
|
||||
asusSolver,
|
||||
sonySolver,
|
||||
samsungSolver,
|
||||
hddOldSolver,
|
||||
dellSolver,
|
||||
dellHddSolver,
|
||||
fsiHexSolver,
|
||||
fsi20DecNewSolver,
|
||||
fsi20DecOldSolver,
|
||||
hpMiniSolver,
|
||||
insydeSolver,
|
||||
phoenixSolver,
|
||||
phoenixHPCompaqSolver,
|
||||
phoenixFsiSolver,
|
||||
phoenixFsiLSolver,
|
||||
phoenixFsiPSolver,
|
||||
phoenixFsiSSolver,
|
||||
phoenixFsiXSolver
|
||||
];
|
||||
|
||||
// NOTE: In future this function can change or even be removed
|
||||
export function keygen(serial: string): KeygenResult[] {
|
||||
return solvers
|
||||
.map((solver): KeygenResult => {
|
||||
let startTime = monotonicTime();
|
||||
let passwords = solver(serial);
|
||||
let calcTime = monotonicTime() - startTime;
|
||||
return [solver, passwords, calcTime];
|
||||
}).filter(([_, passwords]) => passwords !== undefined && passwords.length >= 1);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { insydeSolver } from "./insyde";
|
||||
|
||||
describe("Insyde BIOS", () => {
|
||||
it("Insyde key for 03133610 is 12891236", () => {
|
||||
expect(insydeSolver("03133610")).toEqual(["12891236"]);
|
||||
});
|
||||
it("Insyde key for 12345678 is 03023278", () => {
|
||||
expect(insydeSolver("12345678")).toEqual(["03023278"]);
|
||||
});
|
||||
|
||||
it("test invalid keys", () => {
|
||||
expect(insydeSolver("123456789")).toEqual([]);
|
||||
expect(insydeSolver("1234567")).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
/* Maybe need fixing for browsers where numbers is 32-bits */
|
||||
/* Some Acer, HP laptops. 8 digit */
|
||||
import { makeSolver } from "./utils";
|
||||
|
||||
/* tslint:disable:no-bitwise */
|
||||
function insydeKeygen(serial: string): string[] {
|
||||
const salt = "Iou|hj&Z";
|
||||
let password = "";
|
||||
let b = 0;
|
||||
let a = 0;
|
||||
for (let i = 0; i < 8; i++) {
|
||||
b = salt.charCodeAt(i) ^ serial.charCodeAt(i);
|
||||
a = b;
|
||||
// a = (a * 0x66666667) >> 32;
|
||||
a = (a * 0x66666667);
|
||||
a = Math.floor(a / Math.pow(2, 32));
|
||||
a = (a >> 2) | (a & 0xC0);
|
||||
if (a & 0x80000000) {
|
||||
a++;
|
||||
}
|
||||
a *= 10;
|
||||
password += (b - a).toString();
|
||||
}
|
||||
return [password];
|
||||
}
|
||||
|
||||
export let insydeSolver = makeSolver({
|
||||
name: "insydeH2O",
|
||||
description: "Insyde H2O BIOS (Acer, HP)",
|
||||
examples: ["03133610"],
|
||||
inputValidator: (s) => /^\d{8}$/i.test(s),
|
||||
fun: insydeKeygen
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import * as bios from "./phoenix";
|
||||
|
||||
describe("Test Phoenix BIOS", () => {
|
||||
it("check correct passwords", () => {
|
||||
expect(bios.phoenixSolver.calculateHash("abstoou")).toEqual(12345);
|
||||
expect(bios.phoenixHPCompaqSolver.calculateHash("vnflm")).toEqual(12345);
|
||||
expect(bios.phoenixFsiSolver.calculateHash("411113")).toEqual(12345);
|
||||
expect(bios.phoenixFsiLSolver.calculateHash("362153")).toEqual(12345);
|
||||
expect(bios.phoenixFsiPSolver.calculateHash("4465237")).toEqual(12345);
|
||||
expect(bios.phoenixFsiSSolver.calculateHash("71669")).toEqual(12345);
|
||||
expect(bios.phoenixFsiXSolver.calculateHash("739979")).toEqual(12345);
|
||||
});
|
||||
|
||||
it("find password for hash 12345", () => {
|
||||
function phoenixValidate(solver: bios.PhoenixSolver, hash: string): number {
|
||||
let newPassword = solver(hash)[0];
|
||||
expect(newPassword).not.toBeUndefined();
|
||||
return solver.calculateHash(newPassword);
|
||||
}
|
||||
|
||||
expect(phoenixValidate(bios.phoenixSolver, "12345")).toEqual(12345);
|
||||
expect(phoenixValidate(bios.phoenixHPCompaqSolver, "12345")).toEqual(12345);
|
||||
expect(phoenixValidate(bios.phoenixFsiSolver, "12345")).toEqual(12345);
|
||||
expect(phoenixValidate(bios.phoenixFsiLSolver, "12345")).toEqual(12345);
|
||||
expect(phoenixValidate(bios.phoenixFsiPSolver, "12345")).toEqual(12345);
|
||||
expect(phoenixValidate(bios.phoenixFsiSSolver, "12345")).toEqual(12345);
|
||||
expect(phoenixValidate(bios.phoenixFsiXSolver, "12345")).toEqual(12345);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,244 @@
|
||||
/* tslint:disable:no-bitwise */
|
||||
import {
|
||||
asciiToKeyboardEnc, keyboardEncToAscii, reversedScanCodes, Solver
|
||||
} from "./utils";
|
||||
|
||||
export const enum PhoenixErrors {
|
||||
BadHash,
|
||||
NotFound
|
||||
}
|
||||
|
||||
export interface PhoenixInfo {
|
||||
shift: number;
|
||||
salt: number;
|
||||
dictionary: string[];
|
||||
minLen: number;
|
||||
maxLen: number;
|
||||
}
|
||||
|
||||
export interface PhoenixBios {
|
||||
name: string;
|
||||
description?: string;
|
||||
shift?: number;
|
||||
salt?: number;
|
||||
dictionary?: string[];
|
||||
minLen?: number;
|
||||
maxLen?: number;
|
||||
}
|
||||
|
||||
export interface PhoenixSolver extends Solver {
|
||||
readonly info: PhoenixInfo;
|
||||
calculateHash(password: string): number;
|
||||
}
|
||||
|
||||
// Without zero
|
||||
const digitsOnly: string[] = "123456789".split("");
|
||||
|
||||
const lettersOnly: string[] = "abcdefghijklmnopqrstuvwxyz".split("");
|
||||
|
||||
// const alphaNumeric: string[] = lettersOnly.concat(digitsOnly);
|
||||
|
||||
const defaultPhoenix: PhoenixInfo = {
|
||||
shift: 0,
|
||||
salt: 0,
|
||||
dictionary: lettersOnly,
|
||||
minLen: 3,
|
||||
maxLen: 7
|
||||
};
|
||||
|
||||
/* The phoenix implementation of the CRC-16 contains a rather severe bug
|
||||
* quartering the image space of the function: both the first and second MSB
|
||||
* are always zero regardless of the input.
|
||||
* For a working implementation, you'd have to change the polynom from 0x2001
|
||||
* to e.g. 0xA001.
|
||||
*/
|
||||
|
||||
function badCRC16(pwd: number[], salt: number = 0): number {
|
||||
|
||||
let hash = salt;
|
||||
// tslint:disable-next-line:prefer-for-of
|
||||
for (let c = 0; c < pwd.length; c++) {
|
||||
hash ^= pwd[c];
|
||||
for (let i = 8; i--;) {
|
||||
if (hash & 1) {
|
||||
hash = (hash >> 1) ^ 0x2001;
|
||||
} else {
|
||||
hash = (hash >> 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/*
|
||||
* Modified version of badCRC16 to speedup bruteForce.
|
||||
* Returns pasword length if it matches required hash
|
||||
* or -1 if it isn't matches requiredHash.
|
||||
*/
|
||||
function searchBadCRC16(pwd: number[], salt: number, requiredHash: number, minLen: number): number {
|
||||
|
||||
minLen--;
|
||||
let hash = salt;
|
||||
// tslint:disable-next-line:prefer-for-of
|
||||
for (let c = 0; c < pwd.length; c++) {
|
||||
hash ^= pwd[c];
|
||||
for (let i = 8; i--;) {
|
||||
if (hash & 1) {
|
||||
hash = (hash >> 1) ^ 0x2001;
|
||||
} else {
|
||||
hash = (hash >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (c >= minLen && hash === requiredHash) {
|
||||
return c + 1;
|
||||
}
|
||||
}
|
||||
return -1; // not found
|
||||
}
|
||||
|
||||
function generatePhoenixPassword(encodedPwd: number[], characters: string[] = lettersOnly): void {
|
||||
let rnd = Math.random() * characters.length;
|
||||
for (let i = 0; i < encodedPwd.length; i++) {
|
||||
let index = Math.floor(rnd % characters.length);
|
||||
encodedPwd[i] = reversedScanCodes[characters[index]];
|
||||
rnd *= encodedPwd.length;
|
||||
}
|
||||
}
|
||||
|
||||
function bruteForce(hash: number, salt: number = 0, characters: string[] = lettersOnly,
|
||||
minLen: number = 3, maxLen: number = 7): string | PhoenixErrors {
|
||||
|
||||
let encodedPwd: number[] = [];
|
||||
for (let i = 0; i < maxLen; i++) {
|
||||
encodedPwd.push(0);
|
||||
}
|
||||
|
||||
if (hash > 0x3FFF) {
|
||||
return PhoenixErrors.BadHash;
|
||||
}
|
||||
|
||||
let kk = 0;
|
||||
while (true) {
|
||||
kk++;
|
||||
if (kk > 7000000) {
|
||||
return PhoenixErrors.NotFound;
|
||||
}
|
||||
|
||||
generatePhoenixPassword(encodedPwd, characters);
|
||||
|
||||
let found = searchBadCRC16(encodedPwd, salt, hash, minLen);
|
||||
if (found !== -1) {
|
||||
return keyboardEncToAscii(encodedPwd.slice(0, found));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function makePhoenixSolver(description?: PhoenixBios): PhoenixSolver {
|
||||
if (description === void 0) {
|
||||
description = {} as PhoenixBios;
|
||||
}
|
||||
|
||||
for (let key in defaultPhoenix) {
|
||||
if ((description as any)[key] === void 0) {
|
||||
(description as any)[key] = (defaultPhoenix as any)[key];
|
||||
}
|
||||
}
|
||||
|
||||
const info: PhoenixInfo = {
|
||||
shift: description.shift as number,
|
||||
salt: description.salt as number,
|
||||
dictionary: description.dictionary as string[],
|
||||
minLen: description.minLen as number,
|
||||
maxLen: description.maxLen as number
|
||||
};
|
||||
|
||||
let keygen = (code: string) => {
|
||||
let password = bruteForce(parseInt(code, 10) + info.shift, info.salt,
|
||||
info.dictionary, info.minLen, info.maxLen);
|
||||
|
||||
if (typeof password === "string") {
|
||||
return [password];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
let cleaner = (code: string): string => code.trim().replace(/[-\s]/gi, "");
|
||||
let validator = (s: string): boolean => /^[0-9]{5}$/i.test(s);
|
||||
let calculateHash = (password: string): number => {
|
||||
let pwd = asciiToKeyboardEnc(password);
|
||||
return badCRC16(pwd, info.salt) - info.shift;
|
||||
};
|
||||
let solver: any = (code: string): string[] => {
|
||||
let cleanCode = cleaner(code);
|
||||
if (validator(cleanCode)) {
|
||||
return keygen(cleanCode);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
solver.biosName = description.name;
|
||||
solver.validator = validator;
|
||||
solver.cleaner = cleaner;
|
||||
solver.keygen = keygen;
|
||||
solver.examples = ["12345"];
|
||||
solver.info = info;
|
||||
solver.calculateHash = calculateHash;
|
||||
|
||||
if (description.description) {
|
||||
solver.description = description.description;
|
||||
}
|
||||
return solver as PhoenixSolver;
|
||||
}
|
||||
|
||||
export let phoenixSolver = makePhoenixSolver({
|
||||
name: "phoenix",
|
||||
description: "Generic Phoenix"
|
||||
});
|
||||
|
||||
export let phoenixHPCompaqSolver = makePhoenixSolver({
|
||||
name: "phoenixHP",
|
||||
description: "HP/Compaq Phoenix BIOS",
|
||||
salt: 17232
|
||||
});
|
||||
|
||||
export let phoenixFsiSolver = makePhoenixSolver({
|
||||
name: "phoenixFSI",
|
||||
description: "Fujitsu-Siemens Phoenix",
|
||||
salt: 65,
|
||||
dictionary: digitsOnly
|
||||
});
|
||||
|
||||
export let phoenixFsiLSolver = makePhoenixSolver({
|
||||
name: "phoenixFSIModelL",
|
||||
description: "Fujitsu-Siemens (model L) Phoenix",
|
||||
shift: 1,
|
||||
salt: "L".charCodeAt(0),
|
||||
dictionary: digitsOnly
|
||||
});
|
||||
|
||||
export let phoenixFsiPSolver = makePhoenixSolver({
|
||||
name: "phoenixFSIModelP",
|
||||
description: "Fujitsu-Siemens (model P) Phoenix",
|
||||
shift: 1,
|
||||
salt: "P".charCodeAt(0),
|
||||
dictionary: digitsOnly
|
||||
});
|
||||
|
||||
export let phoenixFsiSSolver = makePhoenixSolver({
|
||||
name: "phoenixFSIModelS",
|
||||
description: "Fujitsu-Siemens (model S) Phoenix",
|
||||
shift: 1,
|
||||
salt: "S".charCodeAt(0),
|
||||
dictionary: digitsOnly
|
||||
});
|
||||
|
||||
export let phoenixFsiXSolver = makePhoenixSolver({
|
||||
name: "phoenixFSIModelX",
|
||||
description: "Fujitsu-Siemens (model X) Phoenix",
|
||||
shift: 1,
|
||||
salt: "X".charCodeAt(0),
|
||||
dictionary: digitsOnly
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import { samsungSolver } from "./samsung";
|
||||
|
||||
describe("Test Samsung BIOS", () => {
|
||||
it("Samsung key for 07088120410C0000 is 12345", () => {
|
||||
expect(samsungSolver("07088120410C0000")).toEqual(["12345"]);
|
||||
});
|
||||
it("Samsung key for 07088120410C is 12345", () => {
|
||||
expect(samsungSolver("07088120410C")).toEqual(["12345"]);
|
||||
});
|
||||
|
||||
it("Samsung key for 1AA9CD4638C0186000 is 5728000", () => {
|
||||
expect(samsungSolver("1AA9CD4638C0186000")).toEqual(["5728000"]);
|
||||
});
|
||||
|
||||
it("Samsung key for 1AA9CD4638C0186001 is 5728000@", () => {
|
||||
expect(samsungSolver("1AA9CD4638C0186001")).toEqual(["5728000@"]);
|
||||
});
|
||||
it("test invalid keys", () => {
|
||||
expect(samsungSolver("1AA9CD4638C01860Z0")).toEqual([]);
|
||||
expect(samsungSolver("1AA9CD4638C01860000")).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,79 @@
|
||||
/* tslint:disable:no-bitwise */
|
||||
/* Return password for samsung laptops
|
||||
* 12 or 18 hexhecimal digits like 07088120410C0000
|
||||
*/
|
||||
|
||||
import { makeSolver } from "./utils";
|
||||
import { keyboardEncToAscii } from "./utils";
|
||||
|
||||
const rotationMatrix1 = [
|
||||
7, 1, 5, 3, 0, 6, 2, 5, 2, 3, 0, 6, 1, 7, 6, 1, 5, 2, 7, 1, 0, 3, 7,
|
||||
6, 1, 0, 5, 2, 1, 5, 7, 3, 2, 0, 6
|
||||
];
|
||||
const rotationMatrix2 = [
|
||||
1, 6, 2, 5, 7, 3, 0, 7, 1, 6, 2, 5, 0, 3, 0, 6, 5, 1, 1, 7, 2, 5, 2,
|
||||
3, 7, 6, 2, 1, 3, 7, 6, 5, 0, 1, 7
|
||||
];
|
||||
|
||||
function keyToAscii(intKeys: number[]): string | undefined {
|
||||
let out = "";
|
||||
|
||||
for (let intKey of intKeys) {
|
||||
if (intKey === 0) {
|
||||
return out;
|
||||
}
|
||||
if (intKey < 32 || intKey > 127) {
|
||||
return undefined;
|
||||
}
|
||||
out += String.fromCharCode(intKey);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
function decryptHash(hash: number[], key: number, rotationMatrix: number[]): number[] {
|
||||
let outhash: number[] = [];
|
||||
|
||||
for (let i = 0; i < hash.length; i++) {
|
||||
const val = ((hash[i] << (rotationMatrix[7 * key + i])) & 0xFF) |
|
||||
(hash[i] >> (8 - rotationMatrix[7 * key + i]));
|
||||
outhash.push(val);
|
||||
}
|
||||
|
||||
return outhash;
|
||||
}
|
||||
|
||||
function samsungKeygen(serial: string): string[] {
|
||||
let hash: number[] = [];
|
||||
|
||||
for (let i = 1; i < Math.floor(serial.length / 2); i++) {
|
||||
let val = parseInt(serial.charAt(2 * i) + serial.charAt(2 * i + 1), 16);
|
||||
hash.push(val);
|
||||
}
|
||||
let key = parseInt(serial.substring(0, 2), 16) % 5;
|
||||
|
||||
let calcScanCodePwd = (matrix: number[]) =>
|
||||
keyboardEncToAscii(decryptHash(hash, key, matrix));
|
||||
|
||||
let scanCodePassword = calcScanCodePwd(rotationMatrix1);
|
||||
if (scanCodePassword === "") {
|
||||
scanCodePassword = calcScanCodePwd(rotationMatrix2);
|
||||
}
|
||||
|
||||
const asciiPassword1 = keyToAscii(decryptHash(hash, key, rotationMatrix1));
|
||||
const asciiPassword2 = keyToAscii(decryptHash(hash, key, rotationMatrix2));
|
||||
|
||||
// TODO: This might require polyfil
|
||||
return [scanCodePassword, asciiPassword1, asciiPassword2].
|
||||
filter((code) => code ? true : false) as string[];
|
||||
}
|
||||
|
||||
export let samsungSolver = makeSolver({
|
||||
name: "samsung",
|
||||
description: "Samsung",
|
||||
examples: ["07088120410C0000"],
|
||||
inputValidator: (s) => /^[0-9ABCDEF]+$/i.test(s) && (
|
||||
s.length === 12 || s.length === 14 || s.length === 16 || s.length === 18
|
||||
),
|
||||
fun: samsungKeygen
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import { sonySolver } from "./sony";
|
||||
|
||||
describe("Sony BIOS", () => {
|
||||
it("Sony key for 1234567 is 9648669", () => {
|
||||
expect(sonySolver("1234567")).toEqual(["9648669"]);
|
||||
});
|
||||
it("test invalid keys", () => {
|
||||
expect(sonySolver("123456789")).toEqual([]);
|
||||
expect(sonySolver("123")).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { makeSolver } from "./utils";
|
||||
/* Return password for old sony laptops
|
||||
* password 7 digit number like 1234567
|
||||
*/
|
||||
function sonyKeygen(serial: string): string {
|
||||
const table = "0987654321876543210976543210982109876543109876543221098765436543210987";
|
||||
let code: string = "";
|
||||
for (let i = 0; i < serial.length; i++) {
|
||||
code += table.charAt(parseInt(serial.charAt(i), 10) + 10 * i);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
export let sonySolver = makeSolver({
|
||||
name: "sony",
|
||||
description: "Old Sony",
|
||||
examples: ["1234567"],
|
||||
inputValidator: (s) => /^\d{7}$/i.test(s),
|
||||
fun: (code: string) => {
|
||||
let res = sonyKeygen(code);
|
||||
return res ? [res] : [];
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,100 @@
|
||||
export type Predicate<T> = (val: T) => boolean;
|
||||
export type SolverFunction = (val: string) => string[];
|
||||
|
||||
export interface SolverDescription {
|
||||
readonly name: string;
|
||||
readonly description?: string;
|
||||
readonly examples?: string[];
|
||||
fun: SolverFunction;
|
||||
inputValidator: Predicate<string>;
|
||||
}
|
||||
|
||||
export interface Solver {
|
||||
(code: string): string[];
|
||||
readonly biosName: string;
|
||||
readonly examples?: string[];
|
||||
readonly description: string;
|
||||
validator(code: string): boolean;
|
||||
cleaner(code: string): string;
|
||||
keygen(code: string): string[];
|
||||
}
|
||||
|
||||
export const keyboardDict: {[key: number]: string} = {
|
||||
2: "1", 3: "2", 4: "3", 5: "4", 6: "5", 7: "6", 8: "7", 9: "8",
|
||||
10: "9", 11: "0", 16: "q", 17: "w", 18: "e", 19: "r", 20: "t", 21: "y",
|
||||
22: "u", 23: "i", 24: "o", 25: "p", 30: "a", 31: "s", 32: "d", 33: "f",
|
||||
34: "g", 35: "h", 36: "j", 37: "k", 38: "l", 44: "z", 45: "x", 46: "c",
|
||||
47: "v", 48: "b", 49: "n", 50: "m"
|
||||
};
|
||||
|
||||
// reverse scan code table
|
||||
function generateReverseKeyDict(): {[key: string]: number} {
|
||||
let result: {[key: string]: number} = {};
|
||||
for (let key in keyboardDict) {
|
||||
if (keyboardDict.hasOwnProperty(key)) {
|
||||
result[keyboardDict[key]] = parseInt(key, 10);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export const reversedScanCodes = generateReverseKeyDict();
|
||||
|
||||
/* Decode Keyboard code to Ascii symbol */
|
||||
export function keyboardEncToAscii(inKey: number[]): string {
|
||||
let out = "";
|
||||
for (let key of inKey) {
|
||||
if (key === 0) {
|
||||
return out;
|
||||
}
|
||||
|
||||
if (key in keyboardDict) {
|
||||
out += keyboardDict[key];
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
export function asciiToKeyboardEnc(password: string): number[] {
|
||||
return password.split("").map((c) => {
|
||||
let code = reversedScanCodes[c];
|
||||
if (code === void 0) {
|
||||
throw new Error("Undefined scan code");
|
||||
} else {
|
||||
return code;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cleanSerial(serial: string): string {
|
||||
return serial.trim().replace(/-/gi, "");
|
||||
}
|
||||
|
||||
export function makeSolver(description: SolverDescription): Solver {
|
||||
|
||||
let solver: any = (code: string) => {
|
||||
let cleanCode = cleanSerial(code);
|
||||
if (description.inputValidator(cleanCode)) {
|
||||
return description.fun(cleanCode);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
solver.biosName = description.name;
|
||||
solver.validator = description.inputValidator;
|
||||
solver.cleaner = cleanSerial;
|
||||
solver.keygen = description.fun;
|
||||
|
||||
if (description.examples) {
|
||||
solver.examples = description.examples;
|
||||
}
|
||||
|
||||
if (description.description) {
|
||||
solver.description = description.description;
|
||||
}
|
||||
|
||||
return solver as Solver;
|
||||
}
|
||||
Reference in new issue
Block a user