From ee5f3a8d0da2bc7fbacf4a307e811bb46da4fbf9 Mon Sep 17 00:00:00 2001 From: Slava Bacherikov Date: Wed, 15 Dec 2021 14:46:26 +0200 Subject: [PATCH] Add support for Dell E7A8 generator --- README.md | 2 +- karma.conf.js | 2 +- src/keygen/cryptoUtils.spec.ts | 43 ++++ src/keygen/cryptoUtils.ts | 405 ++++++++++++++++++++++++++++++++ src/keygen/dell.spec.ts | 102 ++++++--- src/keygen/dell/encode.ts | 118 +++++++++- src/keygen/dell/index.ts | 46 +++- src/keygen/dell/types.ts | 3 +- src/keygen/insyde.spec.ts | 44 +--- src/keygen/insyde.ts | 406 +-------------------------------- 10 files changed, 674 insertions(+), 497 deletions(-) create mode 100644 src/keygen/cryptoUtils.spec.ts create mode 100644 src/keygen/cryptoUtils.ts diff --git a/README.md b/README.md index afb2cf5..66958f6 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Latest released version available [here][bios-pw] and latest testing version (*s * Asus — current BIOS date. For example: ``01-02-2013`` * Compaq — 5 decimal digits (*e.g*. ``12345``) -* Dell — supports such series: ``595B``, ``D35B``, ``2A7B``, ``A95B``, ``1D3B``, ``6FF1``, ``1F66``, ``1F5A`` and ``BF97``. *e.g*: ``1234567-2A7B`` or ``1234567890A-D35B`` for HDD. +* Dell — supports such series: ``595B``, ``D35B``, ``2A7B``, ``A95B``, ``1D3B``, ``6FF1``, ``1F66``, ``1F5A`` and ``BF97``, ``E7A8``. *e.g*: ``1234567-2A7B`` or ``1234567890A-D35B`` for HDD. * Dell Insyde BIOS (Latitude 3540) — *e.g.* ``5F3988D5E0ACE4BF-7QH8602`` (``7QH8602`` — service tag). * Fujitsu-Siemens — 5 decimal digits, 8 hexadecimal digits, 5x4 hexadecimal digits, 5x4 decimal digits * Hewlett-Packard — 5 decimal digits, 10 characters diff --git a/karma.conf.js b/karma.conf.js index 537153e..d32177f 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -21,7 +21,7 @@ module.exports = function(config) { base: "SauceLabs", browserName: 'MicrosoftEdge', platform: 'Windows 10', - version: '13.10586' + version: '18.17763' }, ChromeHeadlessTravis: { base: "ChromeHeadless", diff --git a/src/keygen/cryptoUtils.spec.ts b/src/keygen/cryptoUtils.spec.ts new file mode 100644 index 0000000..87a387d --- /dev/null +++ b/src/keygen/cryptoUtils.spec.ts @@ -0,0 +1,43 @@ +import { AES128, Crc64, Sha256 } from "./cryptoUtils"; + +describe("Crypto utils", () => { + it("sha256", () => { + expect(new Sha256(Uint8Array.from([])).hexdigest()) + .toEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + + expect(new Sha256(Uint8Array.from([1])).hexdigest()) + .toEqual("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"); + + expect(new Sha256(Uint8Array.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])).hexdigest()) + .toEqual("c848e1013f9f04a9d63fa43ce7fd4af035152c7c669a4a404b67107cee5f2e4e"); + + expect(new Sha256(Uint8Array.from("test".split("").map((v) => v.charCodeAt(0)))).hexdigest()) + .toEqual("9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"); + + expect(new Sha256(Uint8Array.from("0".repeat(256).split("").map((v) => v.charCodeAt(0)))).hexdigest()) + .toEqual("67f022195ee405142968ca1b53ae2513a8bab0404d70577785316fa95218e8ba"); + + expect(new Sha256(Uint8Array.from("0".repeat(56).split("").map((v) => v.charCodeAt(0)))).hexdigest()) + .toEqual("bd03ac1428f0ea86f4b83a731ffc7967bb82866d8545322f888d2f6e857ffc18"); + }); + it("AES128", () => { + const numbers = Uint8Array.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); + const myaes = new AES128(numbers); + expect(myaes.encryptBlock(numbers)) + .toEqual(Uint8Array.from([52, 195, 59, 127, 20, 253, 83, 220, 234, 37, 224, 26, 2, 225, 103, 39])); + + expect(myaes.encryptBlock(Uint8Array.from("123456789abcdefg".split("").map((v) => v.charCodeAt(0))))) + .toEqual(Uint8Array.from([111, 52, 225, 193, 98, 40, 19, 168, 122, 34, 93, 3, 146, 166, 202, 100])); + }); + it("crc64", () => { + let mycrc = new Crc64(Crc64.ECMA_POLYNOMIAL); + mycrc.update([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); + expect(mycrc.hexdigest()).toEqual("335a089168033fbe"); + mycrc.reset(); + mycrc.update([0x80]); + expect(mycrc.hexdigest()).toEqual("c96c5795d7870f42"); + mycrc.reset(); + mycrc.update(Uint8Array.from([0xde, 0xad, 0xbe, 0xef])); + expect(mycrc.hexdigest()).toEqual("fc232c18806871af"); + }); +}); diff --git a/src/keygen/cryptoUtils.ts b/src/keygen/cryptoUtils.ts new file mode 100644 index 0000000..992634b --- /dev/null +++ b/src/keygen/cryptoUtils.ts @@ -0,0 +1,405 @@ +/* tslint:disable:no-bitwise */ +import JSBI from "jsbi"; + +export class Crc64 { + private static tableCache: {[key: string]: JSBI[]} = {}; + // ECMA 182 0xC96C5795D7870F42 + public static readonly ECMA_POLYNOMIAL = JSBI.BigInt("14514072000185962306"); + + private table: JSBI[]; + private crc: JSBI; + public readonly polynom: JSBI; + + constructor(poly: JSBI, table?: JSBI[]) { + this.polynom = poly; + if (table && Array.isArray(table)) { + this.table = table; + } else { + this.table = Crc64.getCRC64Table(poly); + } + this.crc = JSBI.BigInt(0); + } + + public reset() { + this.crc = JSBI.BigInt(0); + } + + public update(input: Uint8Array | number[]) { + /* tslint:disable-next-line:prefer-for-of */ + for (let i = 0; i < input.length; i++) { + const b = input[i] & 0xFF; + const index = JSBI.toNumber(JSBI.asUintN(8, JSBI.bitwiseXor(this.crc, JSBI.BigInt(b)))); + const temp = JSBI.bitwiseXor(this.table[index], JSBI.signedRightShift(this.crc, JSBI.BigInt(8))); + this.crc = JSBI.asUintN(64, temp); + } + } + + public digest(): JSBI { + return this.crc; + } + + public hexdigest(): string { + return ("0".repeat(16) + this.digest().toString(16)).slice(-16); + } + private static makeTable(poly: JSBI): JSBI[] { + let table: JSBI[] = []; + for (let i = 0; i < 256; i++) { + let crc: JSBI = JSBI.BigInt(i); + for (let j = 0; j < 8; j++) { + if (JSBI.EQ(JSBI.bitwiseAnd(crc, JSBI.BigInt(1)), 1)) { + crc = JSBI.bitwiseXor(JSBI.signedRightShift(crc, JSBI.BigInt(1)), poly); + } else { + crc = JSBI.signedRightShift(crc, JSBI.BigInt(1)); + } + } + table.push(JSBI.asUintN(64, crc)); + } + return table; + } + private static getCRC64Table(poly: JSBI) { + const key = poly.toString(10); + const val = Crc64.tableCache[key]; + if (val !== undefined && Array.isArray(val)) { + return val; + } else { + const table = Crc64.makeTable(poly); + // save only ECMA table + if (JSBI.EQ(poly, Crc64.ECMA_POLYNOMIAL)) { + Crc64.tableCache[key] = table; + } + return table; + } + } +} + +/* tslint:disable:no-shadowed-variable */ +export class Sha256 { + private static readonly SHA256_CONSTANTS: Uint32Array = Uint32Array.from([ + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 + ]); + + private static readonly SHA256_IV: Uint32Array = Uint32Array.from([ + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 + ]); + + private state: Uint32Array; + private data: Uint8Array; + private bitlen: JSBI; + private datalen: number; + + constructor(input?: Uint8Array) { + this.bitlen = JSBI.BigInt(0); + this.datalen = 0; + this.data = new Uint8Array(64); + this.state = Sha256.SHA256_IV.slice(); + + if (input && (input instanceof Uint8Array || Array.isArray(input))) { + this.update(input); + } + } + + private transform() { + let m: Uint32Array = new Uint32Array(64); + + function ROTRIGHT(a: number, b: number): number { + return (a >>> b) | (a << (32 - b)); + } + function CH(a: number, b: number, c: number): number { + return (a & b) ^ (~a & c); + } + function MAJ(a: number, b: number, c: number): number { + return (a & b) ^ (a & c) ^ (b & c); + } + function EP0(a: number) { + return ROTRIGHT(a, 2) ^ ROTRIGHT(a, 13) ^ ROTRIGHT(a, 22); + } + function EP1(a: number) { + return ROTRIGHT(a, 6) ^ ROTRIGHT(a, 11) ^ ROTRIGHT(a, 25); + } + function SIG0(a: number): number { + return ROTRIGHT(a, 7) ^ ROTRIGHT(a, 18) ^ (a >>> 3); + } + function SIG1(a: number): number { + return ROTRIGHT(a, 17) ^ ROTRIGHT(a, 19) ^ (a >>> 10); + } + for (let i = 0, j = 0; i < 16; i++, j += 4) { + m[i] = (this.data[j] << 24) | (this.data[j + 1] << 16) | (this.data[j + 2] << 8) | + (this.data[j + 3]); + } + for (let i = 16; i < 64; i++) { + m[i] = (SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]) >>> 0; + } + let [a, b, c, d, e, f, g, h] = this.state; + for (let i = 0; i < 64; i++) { + const t1 = h + EP1(e) + CH(e, f, g) + Sha256.SHA256_CONSTANTS[i] + m[i]; + const t2 = EP0(a) + MAJ(a, b, c); + h = g; + g = f; + f = e; + e = (d + t1) >>> 0; + d = c; + c = b; + b = a; + a = (t1 + t2) >>> 0; + } + this.state[0] += a; + this.state[1] += b; + this.state[2] += c; + this.state[3] += d; + this.state[4] += e; + this.state[5] += f; + this.state[6] += g; + this.state[7] += h; + } + + private final(): Uint8Array { + let i = this.datalen & 63; + if (this.datalen < 56) { + this.data[i++] = 0x80; + while (i < 56) { + this.data[i++] = 0; + } + } else { + this.data[i++] = 0x80; + while (i < 64) { + this.data[i++] = 0; + } + this.transform(); + for (let i = 0; i < 56; i++) { + this.data[i] = 0; + } + } + this.bitlen = JSBI.add(this.bitlen, JSBI.BigInt(this.datalen * 8)); + for (let i = 63, j = 0; i >= 56; i--, j += 8) { + // val = (this.bitlen >> j) & 0xFF + const val = JSBI.asUintN(8, JSBI.signedRightShift(this.bitlen, JSBI.BigInt(j))); + this.data[i] = JSBI.toNumber(val); + } + this.transform(); + let hash = new Uint8Array(32); + for (let i = 0; i < 4; i++) { + for (let j = 0; j < 8; j++) { + hash[i + j * 4] = (this.state[j] >>> (24 - i * 8)) & 0xFF; + } + } + return hash; + } + + private copy(): Sha256 { + let item = new Sha256(); + item.state = this.state.slice(); + item.data = this.data.slice(); + item.bitlen = this.bitlen; + item.datalen = this.datalen; + return item; + } + + public update(input: Uint8Array) { + /* tslint:disable-next-line:prefer-for-of */ + for (let i = 0; i < input.length; i++) { + const b = input[i]; + this.data[this.datalen] = b; + this.datalen++; + + if (this.datalen >= 64) { + this.transform(); + this.bitlen = JSBI.add(this.bitlen, JSBI.BigInt(512)); + this.datalen = 0; + } + } + } + + public digest(): Uint8Array { + let item = this.copy(); + return item.final(); + } + + public hexdigest() { + return Array.from(this.digest()).map((x) => { + x = x & 0xFF; + return (x < 0xf) ? "0" + x.toString(16) : x.toString(16); + }).join(""); + } +} + +export class AES128 { + // AES128 ECB mode + private static readonly NB = 4; + private static readonly NK = 4; + private static readonly NR = 10; + + private static readonly sbox: Uint8Array = Uint8Array.from([ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 + ]); + + private static readonly rcon: Uint8Array = Uint8Array.from([ + 0x8D, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A + ]); + + private roundKey: Uint8Array; + + constructor(key: Uint8Array) { + this.roundKey = AES128.keyExpansion(key); + } + + public encryptBlock(input: Uint8Array): Uint8Array { + if (input.length !== 16) { + throw new Error("Invalid block length"); + } + let state = input.slice(); + AES128.addRoundKey(0, state, this.roundKey); + for (let round = 1; ; round++) { + AES128.subBytes(state); + AES128.shiftRows(state); + if (round === 10) { + break; + } + AES128.mixColumns(state); + AES128.addRoundKey(round, state, this.roundKey); + } + AES128.addRoundKey(AES128.NR, state, this.roundKey); + return state; + } + + private static keyExpansion(key: Uint8Array): Uint8Array { + if (key.length !== 16) { + throw new Error("Key should be 16 bytes"); + } + + let roundKey = new Uint8Array(176); + // first round key is the key itself + for (let i = 0; i < AES128.NK * 4; i++) { + roundKey[i] = key[i]; + } + let temp = new Uint8Array(4); + // all other round keys generated from previous ones + for (let i = AES128.NK; i < AES128.NB * (AES128.NR + 1); i++) { + const k = (i - 1) * 4; + temp[0] = roundKey[k + 0]; + temp[1] = roundKey[k + 1]; + temp[2] = roundKey[k + 2]; + temp[3] = roundKey[k + 3]; + + if (i % AES128.NK === 0) { + // AES RotWord() + { + const first = temp[0]; + temp[0] = temp[1]; + temp[1] = temp[2]; + temp[2] = temp[3]; + temp[3] = first; + } + // AES SubWord() + { + temp[0] = AES128.sbox[temp[0]]; + temp[1] = AES128.sbox[temp[1]]; + temp[2] = AES128.sbox[temp[2]]; + temp[3] = AES128.sbox[temp[3]]; + } + + temp[0] ^= AES128.rcon[i / AES128.NK]; + } + { + const j = i * 4; + const k = (i - AES128.NK) * 4; + roundKey[j + 0] = roundKey[k + 0] ^ temp[0]; + roundKey[j + 1] = roundKey[k + 1] ^ temp[1]; + roundKey[j + 2] = roundKey[k + 2] ^ temp[2]; + roundKey[j + 3] = roundKey[k + 3] ^ temp[3]; + } + } + return roundKey; + } + + private static addRoundKey(round: number, state: Uint8Array, roundKey: Uint8Array) { + for (let i = 0; i < 4; i++) { + for (let j = 0; j < 4; j++) { + state[i * 4 + j] ^= roundKey[(round * AES128.NB * 4) + (i * AES128.NB) + j]; + state[i * 4 + j] &= 0xFF; + } + } + } + + private static subBytes(state: Uint8Array) { + for (let i = 0; i < 4; i++) { + for (let j = 0; j < 4; j++) { + state[j * 4 + i] = AES128.sbox[state[j * 4 + i]]; + } + } + } + + private static shiftRows(state: Uint8Array) { + // rotate first row 1 columns to left + let temp: number = state[0 * 4 + 1]; + state[0 * 4 + 1] = state[1 * 4 + 1]; + state[1 * 4 + 1] = state[2 * 4 + 1]; + state[2 * 4 + 1] = state[3 * 4 + 1]; + state[3 * 4 + 1] = temp; + // rotate second row 2 columns to left + temp = state[0 * 4 + 2]; + state[0 * 4 + 2] = state[2 * 4 + 2]; + state[2 * 4 + 2] = temp; + temp = state[1 * 4 + 2]; + state[1 * 4 + 2] = state[3 * 4 + 2]; + state[3 * 4 + 2] = temp; + // rotate thirdd row 3 columns to left + temp = state[0 * 4 + 3]; + state[0 * 4 + 3] = state[3 * 4 + 3]; + state[3 * 4 + 3] = state[2 * 4 + 3]; + state[2 * 4 + 3] = state[1 * 4 + 3]; + state[1 * 4 + 3] = temp; + } + + private static mixColumns(state: Uint8Array) { + let tmp1: number; + let tmp2: number; + + function xtime(x: number): number { + return (x << 1) ^ (((x >>> 7) & 1) * 0x1B); + } + + for (let i = 0; i < 4; i++) { + const t = state[i * 4 + 0]; + tmp1 = state[i * 4 + 0] ^ state[i * 4 + 1] ^ state[i * 4 + 2] ^ state[i * 4 + 3]; + tmp2 = xtime(state[i * 4 + 0] ^ state[i * 4 + 1]); + state[i * 4 + 0] ^= tmp2 ^ tmp1; + tmp2 = xtime(state[i * 4 + 1] ^ state[i * 4 + 2]); + state[i * 4 + 1] ^= tmp2 ^ tmp1; + tmp2 = xtime(state[i * 4 + 2] ^ state[i * 4 + 3]); + state[i * 4 + 2] ^= tmp2 ^ tmp1; + tmp2 = xtime(state[i * 4 + 3] ^ t); + state[i * 4 + 3] ^= tmp2 ^ tmp1; + } + } +} diff --git a/src/keygen/dell.spec.ts b/src/keygen/dell.spec.ts index b0b9ca6..7f9734c 100644 --- a/src/keygen/dell.spec.ts +++ b/src/keygen/dell.spec.ts @@ -123,143 +123,179 @@ describe("Test calculateSuffix", () => { describe("Test keygenDell", () => { it("Dell password for: 1234567-595B", () => { expect(keygenDell("1234567", DellTag.Tag595B, SuffixType.ServiceTag)) - .toEqual("46rg65ky"); + .toEqual(["46rg65ky"]); }); it("Dell password for: 1234567-D35B", () => { expect(keygenDell("1234567", DellTag.TagD35B, SuffixType.ServiceTag)) - .toEqual("5tc8q9re"); + .toEqual(["5tc8q9re"]); }); it("Dell password for: 1234567-2A7B", () => { expect(keygenDell("1234567", DellTag.Tag2A7B, SuffixType.ServiceTag)) - .toEqual("J1KuwWpSUgnDarfi"); + .toEqual(["J1KuwWpSUgnDarfi"]); }); it("Dell password for: 1234567-A95B", () => { expect(keygenDell("1234567", DellTag.TagA95B, SuffixType.ServiceTag)) - .toEqual("46rg65ky"); + .toEqual(["46rg65ky"]); }); it("Dell password for: 1234567-1D3B", () => { expect(keygenDell("1234567", DellTag.Tag1D3B, SuffixType.ServiceTag)) - .toEqual("Sn4fkF8bS57NymZl"); + .toEqual(["Sn4fkF8bS57NymZl"]); }); it("Dell password for: 1234567-1F66", () => { expect(keygenDell("1234567", DellTag.Tag1F66, SuffixType.ServiceTag)) - .toEqual("kIpTBzx0m3s10JDR"); + .toEqual(["kIpTBzx0m3s10JDR"]); }); it("Dell password for: 1234567-6FF1", () => { expect(keygenDell("1234567", DellTag.Tag6FF1, SuffixType.ServiceTag)) - .toEqual("Rzn1wGe555H5bM2r"); + .toEqual(["Rzn1wGe555H5bM2r"]); }); it("Dell password for: OPENSRC-1D3B", () => { expect(keygenDell("OPENSRC", DellTag.Tag1D3B, SuffixType.ServiceTag)) - .toEqual("S3yJ91q0Gar3O72I"); + .toEqual(["S3yJ91q0Gar3O72I"]); }); it("Dell password for: ABCDEFG-1D3B", () => { expect(keygenDell("ABCDEFG", DellTag.Tag1D3B, SuffixType.ServiceTag)) - .toEqual("xvn0qEeftqyrkG52"); + .toEqual(["xvn0qEeftqyrkG52"]); }); it("Dell password for: 7G9C0G2-6FF1", () => { expect(keygenDell("7G9C0G2", DellTag.Tag6FF1, SuffixType.ServiceTag)) - .toEqual("35c0b0tVb32Z6ivD"); + .toEqual(["35c0b0tVb32Z6ivD"]); }); it("Dell password for: DELLSUX-1F66", () => { expect(keygenDell("DELLSUX", DellTag.Tag1F66, SuffixType.ServiceTag)) - .toEqual("qHXaL0ntli6Gu4c0"); + .toEqual(["qHXaL0ntli6Gu4c0"]); }); it("Dell password for: CRPP562-1F66", () => { expect(keygenDell("CRPP562", DellTag.Tag1F66, SuffixType.ServiceTag)) - .toEqual("8i5qLGa9woA919Ys"); + .toEqual(["8i5qLGa9woA919Ys"]); }); it("Dell password for: CDG8T32-1F66", () => { expect(keygenDell("CDG8T32", DellTag.Tag1F66, SuffixType.ServiceTag)) - .toEqual("4Ke3y2L3kTP2f6Vo"); + .toEqual(["4Ke3y2L3kTP2f6Vo"]); }); it("Dell password for: 8M5RQ32-1F66", () => { expect(keygenDell("8M5RQ32", DellTag.Tag1F66, SuffixType.ServiceTag)) - .toEqual("3rlrbaSj46Iw221g"); }); + .toEqual(["3rlrbaSj46Iw221g"]); }); it("Dell password for: 1234567-1F5A", () => { expect(keygenDell("1234567", DellTag.Tag1F5A, SuffixType.ServiceTag)) - .toEqual("2ls2b8GiP9H032kx"); + .toEqual(["2ls2b8GiP9H032kx"]); }); it("Dell password for: OPENSRC-1F5A", () => { expect(keygenDell("OPENSRC", DellTag.Tag1F5A, SuffixType.ServiceTag)) - .toEqual("ZC3j2t56eIe4Thgi"); + .toEqual(["ZC3j2t56eIe4Thgi"]); }); it("Dell password for: ABCDEFG-1F5A", () => { expect(keygenDell("ABCDEFG", DellTag.Tag1F5A, SuffixType.ServiceTag)) - .toEqual("x2zL5n7jj2Gl2TIh"); + .toEqual(["x2zL5n7jj2Gl2TIh"]); }); it("Dell password for: 1234567-BF97", () => { expect(keygenDell("1234567", DellTag.TagBF97, SuffixType.ServiceTag)) - .toEqual("2r09GZhU[r0kW2zr"); + .toEqual(["2r09GZhU[r0kW2zr"]); }); it("Dell password for: OPENSRC-BF97", () => { expect(keygenDell("OPENSRC", DellTag.TagBF97, SuffixType.ServiceTag)) - .toEqual("Dp29XkbyMrkBrp6Z"); + .toEqual(["Dp29XkbyMrkBrp6Z"]); }); it("Dell password for: ABCDEFG-BF97", () => { expect(keygenDell("ABCDEFG", DellTag.TagBF97, SuffixType.ServiceTag)) - .toEqual("kr9Z1cmPpahGzsQ["); + .toEqual(["kr9Z1cmPpahGzsQ["]); }); it("Dell password for: DELLSUX-BF97", () => { expect(keygenDell("DELLSUX", DellTag.TagBF97, SuffixType.ServiceTag)) - .toEqual("rrNM2LrbD8nGsd2P"); + .toEqual(["rrNM2LrbD8nGsd2P"]); + }); + it("Dell password for: 1234567-E7A8", () => { + expect(keygenDell("1234567", DellTag.TagE7A8, SuffixType.ServiceTag).sort()) + .toEqual(["Qk3LkU22kPeyq2jd", "rLIqjUy59IG2JU2R"].sort()); + }); + it("Dell password for: D875TG2-E7A8", () => { + expect(keygenDell("D875TG2", DellTag.TagE7A8, SuffixType.ServiceTag).sort()) + .toEqual(["rLZc96rMZyGQ2GMG", "1Q6rxIWMGUznXZNy"].sort()); + }); + it("Dell password for: 2XSX273-E7A8", () => { + expect(keygenDell("2XSX273", DellTag.TagE7A8, SuffixType.ServiceTag).sort()) + .toEqual(["rPQ0DGLdqckG2kUZ", "0ZaP6RzW9qk73rmq"].sort()); + }); + it("Dell password for: CZXKYX2-E7A8", () => { + expect(keygenDell("CZXKYX2", DellTag.TagE7A8, SuffixType.ServiceTag).sort()) + .toEqual(["RGWD2BIR9UB9ZdIy", "38Gr7brmRGBPPIkz"].sort()); + }); + it("Dell password for: 6651WZ2-E7A8", () => { + expect(keygenDell("6651WZ2", DellTag.TagE7A8, SuffixType.ServiceTag).sort()) + .toEqual(["PBjMMMsZUQR2MhmR", "Q1N6k2sLRkGGGrEN"].sort()); + }); + it("Dell password for: 9M2JTG2-E7A8", () => { + expect(keygenDell("9M2JTG2", DellTag.TagE7A8, SuffixType.ServiceTag)) + .toContain("J2yR66N1kdn2N17m"); + }); + it("Dell password for: 1219P73-E7A8", () => { + expect(keygenDell("1219P73", DellTag.TagE7A8, SuffixType.ServiceTag)) + .toContain("ksM02GskJ341hnDx"); }); // HDD it("Dell HDD password for: 1234567890A-595B", () => { expect(keygenDell("1234567890A", DellTag.Tag595B, SuffixType.HDD)) - .toEqual("nyoap4lq"); + .toEqual(["nyoap4lq"]); }); it("Dell HDD password for: 1234567890A-D35B", () => { expect(keygenDell("1234567890A", DellTag.TagD35B, SuffixType.HDD)) - .toEqual("dc14blrd"); + .toEqual(["dc14blrd"]); }); it("Dell HDD password for: 1234567890A-2A7B", () => { expect(keygenDell("1234567890A", DellTag.Tag2A7B, SuffixType.HDD)) - .toEqual("h6lwdi91qluUyt3u"); + .toEqual(["h6lwdi91qluUyt3u"]); }); it("Dell HDD password for: 1234567890A-A95B", () => { expect(keygenDell("1234567890A", DellTag.TagA95B, SuffixType.HDD)) - .toEqual("qr0s6x4n"); + .toEqual(["qr0s6x4n"]); }); it("Dell HDD password for: 1234567890A-1D3B", () => { expect(keygenDell("1234567890A", DellTag.Tag1D3B, SuffixType.HDD)) - .toEqual("6JQ1WacHNNR0Taia"); + .toEqual(["6JQ1WacHNNR0Taia"]); }); it("Dell HDD password for: 1234567890A-1F66", () => { expect(keygenDell("1234567890A", DellTag.Tag1F66, SuffixType.HDD)) - .toEqual("vP0M31x066Z7Rq9p"); + .toEqual(["vP0M31x066Z7Rq9p"]); }); it("Dell HDD password for: 1234567890A-6FF1", () => { expect(keygenDell("1234567890A", DellTag.Tag6FF1, SuffixType.HDD)) - .toEqual("5enLLpM3Immfb8CK"); + .toEqual(["5enLLpM3Immfb8CK"]); }); it("Dell HDD password for: 1234567890A-1F5A", () => { expect(keygenDell("1234567890A", DellTag.Tag1F5A, SuffixType.HDD)) - .toEqual("L9IJjYoUIXeY5wOy"); + .toEqual(["L9IJjYoUIXeY5wOy"]); }); it("Dell HDD password for: 12345678901-1F5A", () => { expect(keygenDell("12345678901", DellTag.Tag1F5A, SuffixType.HDD)) - .toEqual("QwO5Dki1zeR1n1t2"); + .toEqual(["QwO5Dki1zeR1n1t2"]); }); it("Dell HDD password for: 12345678901-BF97", () => { expect(keygenDell("12345678901", DellTag.TagBF97, SuffixType.HDD)) - .toEqual("nDrmUU6U5DI9ZLMI"); + .toEqual(["nDrmUU6U5DI9ZLMI"]); }); it("Dell HDD password for: 1234567890A-BF97", () => { expect(keygenDell("1234567890A", DellTag.TagBF97, SuffixType.HDD)) - .toEqual("pRrky3r9ryEPNNJz"); + .toEqual(["pRrky3r9ryEPNNJz"]); }); it("Dell HDD password for: 234567890AB-BF97", () => { expect(keygenDell("234567890AB", DellTag.TagBF97, SuffixType.HDD)) - .toEqual("h2RDrReN37I1NLmr"); + .toEqual(["h2RDrReN37I1NLmr"]); + }); + it("Dell HDD password for: 1234567890A-E7A8", () => { + expect(keygenDell("1234567890A", DellTag.TagE7A8, SuffixType.HDD).sort()) + .toEqual(["rN2rE2RBQh[X00yr", "G1bFzRGzjXIGzr22"].sort()); + }); + it("Dell HDD password for: 1234567890B-E7A8", () => { + expect(keygenDell("1234567890B", DellTag.TagE7A8, SuffixType.HDD).sort()) + .toEqual(["Ic18yqyXXZI5Qj22", "kzzMazZrz53sRZJm"].sort()); }); }); diff --git a/src/keygen/dell/encode.ts b/src/keygen/dell/encode.ts index 2277a2b..7f7dbc1 100644 --- a/src/keygen/dell/encode.ts +++ b/src/keygen/dell/encode.ts @@ -1,7 +1,7 @@ /* tslint:disable:no-bitwise */ import { DellTag } from "./types"; -const md5magic = [ +const md5magic = Uint32Array.from([ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, @@ -18,9 +18,9 @@ const md5magic = [ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 -].map((v) => v | 0); +]); -const md5magic2 = [ +const md5magic2 = Uint32Array.from([ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, @@ -37,7 +37,7 @@ const md5magic2 = [ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039 -].map((v) => v | 0); +]); const rotationTable = [ [7, 12, 17, 22], @@ -115,17 +115,21 @@ class Tag595BEncoder { protected f3: EncFunction = encF3; protected f4: EncFunction = encF4N; protected f5: EncFunction = encF5N; - protected md5table: number[] = md5magic; + protected readonly md5table: Uint32Array = md5magic; constructor(encBlock: number[]) { this.encBlock = encBlock; - this.encData = initialData.slice(); + this.encData = this.initialData(); this.A = this.encData[0]; this.B = this.encData[1]; this.C = this.encData[2]; this.D = this.encData[3]; } + protected initialData(): number[] { + return initialData.slice(); + } + 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; @@ -344,7 +348,7 @@ class Tag6FF1Encoder extends Tag595BEncoder { } class Tag1F5AEncoder extends Tag595BEncoder { - protected md5table = md5magic2; + protected readonly md5table = md5magic2; protected incrementData() { this.encData[0] += this.B; @@ -396,6 +400,103 @@ class TagBF97Encoder extends Tag6FF1Encoder { protected counter1 = 31; } +export class TagE7A8Encoder extends Tag595BEncoder { + protected readonly md5table = md5magic2; + + protected readonly loopParams = [17, 13, 12, 8]; + + protected readonly encodeParams = Uint32Array.from([ + 0x50501010, 0xA010908, 0xA08097, 0x60606161, + 0x60606161, 0xA0008, 0x100097, 0x50501010 + ]); + + protected initialData(): number[] { + return [0, 0, 0, 0]; + } + + private shortcut(fun: EncFunction, j: number, md5_index: number, rot_index: number, indexes: number[]): void { + + for (let i = 0; i < 4; i++) { + const t = this.calculate(fun, (j + indexes[i]) & 7, i + md5_index); + this.A = this.D; + this.D = this.C; + this.C = this.B; + this.B = rol(t, rotationTable[rot_index][i]) + this.B | 0; + } + } + + public makeEncode(): void { + + for (let p = 0; p < this.loopParams[0]; p++) { + this.A |= this.encodeParams[0]; + this.B ^= this.encodeParams[1]; + this.C |= this.encodeParams[2] - p; + this.D ^= this.encodeParams[3] + p; + + for (let j = 0; j < this.loopParams[2]; j += 4) { + this.shortcut(this.f2, j, j + 32, 0, [0, 1, 2, 3]); + } + + for (let j = 0; j < this.loopParams[2]; j += 4) { + this.shortcut(this.f3, j, j, 1, [1, -2, -1, 0]); + } + + for (let j = this.loopParams[3]; j > 3; j -= 4) { + this.shortcut(this.f4, j, j + 16, 2, [-3, -4, -1, 2]); + } + + for (let j = this.loopParams[3]; j > 3 ; j -= 4) { + this.shortcut(this.f5, j, j + 48, 3, [2, 3, 2, -3]); + } + + this.incrementData(); + } + + for (let p = 0; p < this.loopParams[1]; p++) { + this.A |= this.encodeParams[4]; + this.B ^= this.encodeParams[5]; + this.C |= this.encodeParams[6] - p; + this.D ^= this.encodeParams[7] + p; + + for (let j = this.loopParams[3]; j > 3 ; j -= 4) { + this.shortcut(this.f4, j, j + 16, 2, [-3, -4, -1, 2]); + } + + for (let j = 0; j < this.loopParams[2]; j += 4) { + this.shortcut(this.f5, j, j + 32, 3, [2, 3, 2, -3]); + } + + for (let j = this.loopParams[3]; j > 0 ; j -= 4) { + + this.shortcut(this.f2, j, j, 0, [0, 1, 2, 3]); + + } + + for (let j = 0; j < this.loopParams[2]; j += 4) { + this.shortcut(this.f3, j, j + 48, 1, [1, -2, 3, 0]); + } + + this.incrementData(); + } + } +} + +export class TagE7A8EncoderSecond extends TagE7A8Encoder { + + // this model has bug and it goes over the array limit + protected readonly md5table = (() => { + const overfillArr = [ + 0xa0008 ^ 0x6d2f93a5, 0xa08097 ^ 0x6d2f93a5, 0xa010908 ^ 0x6d2f93a5, 0x60606161 ^ 0x6d2f93a5 + ]; + let arr = new Uint32Array(md5magic2.length + overfillArr.length); + arr.set(md5magic2); + arr.set(overfillArr, md5magic2.length); + return arr; + })() + + protected readonly loopParams = [17, 13, 12, 16]; +} + const encoders: {readonly [P in DellTag]: Encoder} = { "595B": Tag595BEncoder, "2A7B": Tag595BEncoder, // same as 595B @@ -405,7 +506,8 @@ const encoders: {readonly [P in DellTag]: Encoder} = { "1F66": Tag1F66Encoder, "6FF1": Tag6FF1Encoder, "1F5A": Tag1F5AEncoder, - "BF97": TagBF97Encoder + "BF97": TagBF97Encoder, + "E7A8": TagE7A8Encoder }; export function blockEncode(encBlock: number[], tag: DellTag): number[] { diff --git a/src/keygen/dell/index.ts b/src/keygen/dell/index.ts index a6b4447..2312b82 100644 --- a/src/keygen/dell/index.ts +++ b/src/keygen/dell/index.ts @@ -1,9 +1,10 @@ /* tslint:disable:no-bitwise */ import { makeSolver } from "../utils"; -import { blockEncode } from "./encode"; +import { blockEncode, TagE7A8Encoder, TagE7A8EncoderSecond } from "./encode"; import { DES, latitude3540Keygen } from "./latitude"; import { DellTag, SuffixType } from "./types"; export { DellTag, SuffixType, DES, latitude3540Keygen }; +import { Sha256 } from "../cryptoUtils"; const scanCodes: string = "\0\x1B1234567890-=\x08\x09qwertyuiop[]\x0D\xFFasdfghjkl;'`\xFF\\zxcvbnm,./"; @@ -112,7 +113,7 @@ export function calculateSuffix(serial: number[], tag: DellTag, type: SuffixType return suffix; } -function resultToString(arr: number[], tag: DellTag): string { +function resultToString(arr: number[] | Uint8Array, tag: DellTag): string { let r = arr[0] % 9; let result = ""; let table = extraCharacters[tag]; @@ -130,7 +131,7 @@ function resultToString(arr: number[], tag: DellTag): string { * 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 { +export function keygenDell(serial: string, tag: DellTag, type: SuffixType): string[] { let fullSerial: string; function byteArrayToInt(arr: number[]): number[] { @@ -157,6 +158,19 @@ export function keygenDell(serial: string, tag: DellTag, type: SuffixType): stri return result; } + function calculate_e7a8(block: number[], klass: any): string { + // TODO: refactor this + const table = "Q92G0drk9y63r5DG1hLqJGW1EnRk[QxrFMNZ328I6myLr4MsPNeZR2z72czpzUJBGXbaIjkZ"; + const res = intArrayToByte(klass.encode(block)); + const digest = new Sha256(Uint8Array.from(res)); + const out = digest.digest(); + let out_str = ""; + for (let i = 0; i < 16; i++) { + out_str += table[(out[i + 16] + out[i]) % table.length]; + } + return out_str; + } + if (tag === DellTag.TagA95B) { if (type === SuffixType.ServiceTag) { @@ -175,6 +189,25 @@ export function keygenDell(serial: string, tag: DellTag, type: SuffixType): stri // Maybe protect against unicode symbols with: charCode & 0xFF ? fullSerialArray.push(fullSerial.charCodeAt(i)); } + if (tag == DellTag.TagE7A8) { + // TODO: refactor all this + let encBlock = byteArrayToInt(fullSerialArray); + for (let i = 0; i < 16; i++) { + if (encBlock[i] === undefined) { + encBlock[i] = 0; + } + } + const out_str1 = calculate_e7a8(encBlock, TagE7A8Encoder); + const out_str2 = calculate_e7a8(encBlock, TagE7A8EncoderSecond); + let result = []; + if (out_str1) { + result.push(out_str1); + } + if (out_str2) { + result.push(out_str2); + } + return result; + } fullSerialArray = fullSerialArray.concat(calculateSuffix(fullSerialArray, tag, type)); const cnt = 23; @@ -189,7 +222,8 @@ export function keygenDell(serial: string, tag: DellTag, type: SuffixType): stri } encBlock[14] = cnt << 3; let decodedBytes = intArrayToByte(blockEncode(encBlock, tag)); - return resultToString(decodedBytes, tag); + const result = resultToString(decodedBytes, tag); + return (result) ? [result] : []; } function checkDellTag(tag: string): boolean { @@ -223,7 +257,7 @@ export let dellSolver = makeSolver({ }, fun: (password: string) => { let suffix = password.slice(7, 11).toUpperCase(); - return [keygenDell(password.slice(0, 7), suffix as DellTag, SuffixType.ServiceTag)]; + return keygenDell(password.slice(0, 7), suffix as DellTag, SuffixType.ServiceTag); } }); @@ -240,7 +274,7 @@ export let dellHddSolver = makeSolver({ }, fun: (password: string) => { let suffix = password.slice(11, 15).toUpperCase(); - return [keygenDell(password.slice(0, 11), suffix as DellTag, SuffixType.HDD)]; + return keygenDell(password.slice(0, 11), suffix as DellTag, SuffixType.HDD); } }); diff --git a/src/keygen/dell/types.ts b/src/keygen/dell/types.ts index 03e75d2..1bf0655 100644 --- a/src/keygen/dell/types.ts +++ b/src/keygen/dell/types.ts @@ -8,7 +8,8 @@ export enum DellTag { Tag6FF1 = "6FF1", Tag1F66 = "1F66", Tag1F5A = "1F5A", - TagBF97 = "BF97" + TagBF97 = "BF97", + TagE7A8 = "E7A8" } export const enum SuffixType { diff --git a/src/keygen/insyde.spec.ts b/src/keygen/insyde.spec.ts index a7eb0c7..4eae0da 100644 --- a/src/keygen/insyde.spec.ts +++ b/src/keygen/insyde.spec.ts @@ -1,4 +1,4 @@ -import { acerInsyde10Solver, AES128, Crc64, hpInsydeSolver, insydeSolver, Sha256} from "./insyde"; +import { acerInsyde10Solver, hpInsydeSolver, insydeSolver } from "./insyde"; describe("Insyde BIOS", () => { it("Insyde key for 03133610 is 12891236", () => { @@ -75,45 +75,3 @@ describe("HP Insyde [i \d{8}] codes", () => { expect(hpInsydeSolver("i 511")).toEqual([]); }); }); - -describe("Utils", () => { - it("sha256", () => { - expect(new Sha256(Uint8Array.from([])).hexdigest()) - .toEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); - - expect(new Sha256([1]).hexdigest()) - .toEqual("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"); - - expect(new Sha256([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).hexdigest()) - .toEqual("c848e1013f9f04a9d63fa43ce7fd4af035152c7c669a4a404b67107cee5f2e4e"); - - expect(new Sha256("test".split("").map((v) => v.charCodeAt(0))).hexdigest()) - .toEqual("9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"); - - expect(new Sha256("0".repeat(256).split("").map((v) => v.charCodeAt(0))).hexdigest()) - .toEqual("67f022195ee405142968ca1b53ae2513a8bab0404d70577785316fa95218e8ba"); - - expect(new Sha256("0".repeat(56).split("").map((v) => v.charCodeAt(0))).hexdigest()) - .toEqual("bd03ac1428f0ea86f4b83a731ffc7967bb82866d8545322f888d2f6e857ffc18"); - }); - it("AES128", () => { - const numbers = Uint8Array.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); - const myaes = new AES128(numbers); - expect(myaes.encryptBlock(numbers)) - .toEqual(Uint8Array.from([52, 195, 59, 127, 20, 253, 83, 220, 234, 37, 224, 26, 2, 225, 103, 39])); - - expect(myaes.encryptBlock(Uint8Array.from("123456789abcdefg".split("").map((v) => v.charCodeAt(0))))) - .toEqual(Uint8Array.from([111, 52, 225, 193, 98, 40, 19, 168, 122, 34, 93, 3, 146, 166, 202, 100])); - }); - it("crc64", () => { - let mycrc = new Crc64(Crc64.ECMA_POLYNOMIAL); - mycrc.update([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); - expect(mycrc.hexdigest()).toEqual("335a089168033fbe"); - mycrc.reset(); - mycrc.update([0x80]); - expect(mycrc.hexdigest()).toEqual("c96c5795d7870f42"); - mycrc.reset(); - mycrc.update(Uint8Array.from([0xde, 0xad, 0xbe, 0xef])); - expect(mycrc.hexdigest()).toEqual("fc232c18806871af"); - }); -}); diff --git a/src/keygen/insyde.ts b/src/keygen/insyde.ts index 46bfe17..df2f60d 100644 --- a/src/keygen/insyde.ts +++ b/src/keygen/insyde.ts @@ -1,415 +1,13 @@ /* tslint:disable:no-bitwise */ /* tslint:disable:no-var-requires */ +/* tslint:disable:no-shadowed-variable */ /* Maybe need fixing for browsers where numbers is 32-bits */ /* Some Acer, HP laptops. 8 digit */ -import JSBI from "jsbi"; import { makeSolver } from "./utils"; +import { Crc64, Sha256, AES128 } from "./cryptoUtils"; const INSYDE_SALT = "Insyde Software Corp."; -export class Crc64 { - private static tableCache: {[key: string]: JSBI[]} = {}; - // ECMA 182 0xC96C5795D7870F42 - public static readonly ECMA_POLYNOMIAL = JSBI.BigInt("14514072000185962306"); - - private table: JSBI[]; - private crc: JSBI; - public readonly polynom: JSBI; - - constructor(poly: JSBI, table?: JSBI[]) { - this.polynom = poly; - if (table && Array.isArray(table)) { - this.table = table; - } else { - this.table = Crc64.getCRC64Table(poly); - } - this.crc = JSBI.BigInt(0); - } - - public reset() { - this.crc = JSBI.BigInt(0); - } - - public update(input: Uint8Array | number[]) { - /* tslint:disable-next-line:prefer-for-of */ - for (let i = 0; i < input.length; i++) { - const b = input[i] & 0xFF; - const index = JSBI.toNumber(JSBI.asUintN(8, JSBI.bitwiseXor(this.crc, JSBI.BigInt(b)))); - const temp = JSBI.bitwiseXor(this.table[index], JSBI.signedRightShift(this.crc, JSBI.BigInt(8))); - this.crc = JSBI.asUintN(64, temp); - } - } - - public digest(): JSBI { - return this.crc; - } - - public hexdigest(): string { - return ("0".repeat(16) + this.digest().toString(16)).slice(-16); - } - private static makeTable(poly: JSBI): JSBI[] { - let table: JSBI[] = []; - for (let i = 0; i < 256; i++) { - let crc: JSBI = JSBI.BigInt(i); - for (let j = 0; j < 8; j++) { - if (JSBI.EQ(JSBI.bitwiseAnd(crc, JSBI.BigInt(1)), 1)) { - crc = JSBI.bitwiseXor(JSBI.signedRightShift(crc, JSBI.BigInt(1)), poly); - } else { - crc = JSBI.signedRightShift(crc, JSBI.BigInt(1)); - } - } - table.push(JSBI.asUintN(64, crc)); - } - return table; - } - private static getCRC64Table(poly: JSBI) { - const key = poly.toString(10); - const val = Crc64.tableCache[key]; - if (val !== undefined && Array.isArray(val)) { - return val; - } else { - const table = Crc64.makeTable(poly); - // save only ECMA table - if (JSBI.EQ(poly, Crc64.ECMA_POLYNOMIAL)) { - Crc64.tableCache[key] = table; - } - return table; - } - } -} - -/* tslint:disable:no-shadowed-variable */ -export class Sha256 { - private static readonly SHA256_CONSTANTS: Uint32Array = Uint32Array.from([ - 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, - 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, - 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, - 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, - 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, - 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, - 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, - 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, - 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, - 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, - 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, - 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, - 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, - 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, - 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, - 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 - ]); - - private static readonly SHA256_IV: Uint32Array = Uint32Array.from([ - 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, - 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 - ]); - - private state: Uint32Array; - private data: Uint8Array; - private bitlen: JSBI; - private datalen: number; - - constructor(input?: Uint8Array | number[]) { - this.bitlen = JSBI.BigInt(0); - this.datalen = 0; - this.data = new Uint8Array(64); - this.state = Sha256.SHA256_IV.slice(); - - if (input && (input instanceof Uint8Array || Array.isArray(input))) { - this.update(input); - } - } - - private transform() { - let m: Uint32Array = new Uint32Array(64); - - function ROTRIGHT(a: number, b: number): number { - return (a >>> b) | (a << (32 - b)); - } - function CH(a: number, b: number, c: number): number { - return (a & b) ^ (~a & c); - } - function MAJ(a: number, b: number, c: number): number { - return (a & b) ^ (a & c) ^ (b & c); - } - function EP0(a: number) { - return ROTRIGHT(a, 2) ^ ROTRIGHT(a, 13) ^ ROTRIGHT(a, 22); - } - function EP1(a: number) { - return ROTRIGHT(a, 6) ^ ROTRIGHT(a, 11) ^ ROTRIGHT(a, 25); - } - function SIG0(a: number): number { - return ROTRIGHT(a, 7) ^ ROTRIGHT(a, 18) ^ (a >>> 3); - } - function SIG1(a: number): number { - return ROTRIGHT(a, 17) ^ ROTRIGHT(a, 19) ^ (a >>> 10); - } - for (let i = 0, j = 0; i < 16; i++, j += 4) { - m[i] = (this.data[j] << 24) | (this.data[j + 1] << 16) | (this.data[j + 2] << 8) | - (this.data[j + 3]); - } - for (let i = 16; i < 64; i++) { - m[i] = (SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]) >>> 0; - } - let [a, b, c, d, e, f, g, h] = this.state; - for (let i = 0; i < 64; i++) { - const t1 = h + EP1(e) + CH(e, f, g) + Sha256.SHA256_CONSTANTS[i] + m[i]; - const t2 = EP0(a) + MAJ(a, b, c); - h = g; - g = f; - f = e; - e = (d + t1) >>> 0; - d = c; - c = b; - b = a; - a = (t1 + t2) >>> 0; - } - this.state[0] += a; - this.state[1] += b; - this.state[2] += c; - this.state[3] += d; - this.state[4] += e; - this.state[5] += f; - this.state[6] += g; - this.state[7] += h; - } - - private final(): Uint8Array { - let i = this.datalen & 63; - if (this.datalen < 56) { - this.data[i++] = 0x80; - while (i < 56) { - this.data[i++] = 0; - } - } else { - this.data[i++] = 0x80; - while (i < 64) { - this.data[i++] = 0; - } - this.transform(); - for (let i = 0; i < 56; i++) { - this.data[i] = 0; - } - } - this.bitlen = JSBI.add(this.bitlen, JSBI.BigInt(this.datalen * 8)); - for (let i = 63, j = 0; i >= 56; i--, j += 8) { - // val = (this.bitlen >> j) & 0xFF - const val = JSBI.asUintN(8, JSBI.signedRightShift(this.bitlen, JSBI.BigInt(j))); - this.data[i] = JSBI.toNumber(val); - } - this.transform(); - let hash = new Uint8Array(32); - for (let i = 0; i < 4; i++) { - for (let j = 0; j < 8; j++) { - hash[i + j * 4] = (this.state[j] >>> (24 - i * 8)) & 0xFF; - } - } - return hash; - } - - private copy(): Sha256 { - let item = new Sha256(); - item.state = this.state.slice(); - item.data = this.data.slice(); - item.bitlen = this.bitlen; - item.datalen = this.datalen; - return item; - } - - public update(input: Uint8Array | number[]) { - /* tslint:disable-next-line:prefer-for-of */ - for (let i = 0; i < input.length; i++) { - const b = input[i]; - this.data[this.datalen] = b; - this.datalen++; - - if (this.datalen >= 64) { - this.transform(); - this.bitlen = JSBI.add(this.bitlen, JSBI.BigInt(512)); - this.datalen = 0; - } - } - } - - public digest(): Uint8Array { - let item = this.copy(); - return item.final(); - } - - public hexdigest() { - return Array.from(this.digest()).map((x) => { - x = x & 0xFF; - return (x < 0xf) ? "0" + x.toString(16) : x.toString(16); - }).join(""); - } -} - -export class AES128 { - // AES128 ECB mode - private static readonly NB = 4; - private static readonly NK = 4; - private static readonly NR = 10; - - private static readonly sbox: Uint8Array = Uint8Array.from([ - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 - ]); - - private static readonly rcon: Uint8Array = Uint8Array.from([ - 0x8D, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A - ]); - - private roundKey: Uint8Array; - - constructor(key: Uint8Array) { - this.roundKey = AES128.keyExpansion(key); - } - - public encryptBlock(input: Uint8Array): Uint8Array { - if (input.length !== 16) { - throw new Error("Invalid block length"); - } - let state = input.slice(); - AES128.addRoundKey(0, state, this.roundKey); - for (let round = 1; ; round++) { - AES128.subBytes(state); - AES128.shiftRows(state); - if (round === 10) { - break; - } - AES128.mixColumns(state); - AES128.addRoundKey(round, state, this.roundKey); - } - AES128.addRoundKey(AES128.NR, state, this.roundKey); - return state; - } - - private static keyExpansion(key: Uint8Array): Uint8Array { - if (key.length !== 16) { - throw new Error("Key should be 16 bytes"); - } - - let roundKey = new Uint8Array(176); - // first round key is the key itself - for (let i = 0; i < AES128.NK * 4; i++) { - roundKey[i] = key[i]; - } - let temp = new Uint8Array(4); - // all other round keys generated from previous ones - for (let i = AES128.NK; i < AES128.NB * (AES128.NR + 1); i++) { - const k = (i - 1) * 4; - temp[0] = roundKey[k + 0]; - temp[1] = roundKey[k + 1]; - temp[2] = roundKey[k + 2]; - temp[3] = roundKey[k + 3]; - - if (i % AES128.NK === 0) { - // AES RotWord() - { - const first = temp[0]; - temp[0] = temp[1]; - temp[1] = temp[2]; - temp[2] = temp[3]; - temp[3] = first; - } - // AES SubWord() - { - temp[0] = AES128.sbox[temp[0]]; - temp[1] = AES128.sbox[temp[1]]; - temp[2] = AES128.sbox[temp[2]]; - temp[3] = AES128.sbox[temp[3]]; - } - - temp[0] ^= AES128.rcon[i / AES128.NK]; - } - { - const j = i * 4; - const k = (i - AES128.NK) * 4; - roundKey[j + 0] = roundKey[k + 0] ^ temp[0]; - roundKey[j + 1] = roundKey[k + 1] ^ temp[1]; - roundKey[j + 2] = roundKey[k + 2] ^ temp[2]; - roundKey[j + 3] = roundKey[k + 3] ^ temp[3]; - } - } - return roundKey; - } - - private static addRoundKey(round: number, state: Uint8Array, roundKey: Uint8Array) { - for (let i = 0; i < 4; i++) { - for (let j = 0; j < 4; j++) { - state[i * 4 + j] ^= roundKey[(round * AES128.NB * 4) + (i * AES128.NB) + j]; - state[i * 4 + j] &= 0xFF; - } - } - } - - private static subBytes(state: Uint8Array) { - for (let i = 0; i < 4; i++) { - for (let j = 0; j < 4; j++) { - state[j * 4 + i] = AES128.sbox[state[j * 4 + i]]; - } - } - } - - private static shiftRows(state: Uint8Array) { - // rotate first row 1 columns to left - let temp: number = state[0 * 4 + 1]; - state[0 * 4 + 1] = state[1 * 4 + 1]; - state[1 * 4 + 1] = state[2 * 4 + 1]; - state[2 * 4 + 1] = state[3 * 4 + 1]; - state[3 * 4 + 1] = temp; - // rotate second row 2 columns to left - temp = state[0 * 4 + 2]; - state[0 * 4 + 2] = state[2 * 4 + 2]; - state[2 * 4 + 2] = temp; - temp = state[1 * 4 + 2]; - state[1 * 4 + 2] = state[3 * 4 + 2]; - state[3 * 4 + 2] = temp; - // rotate thirdd row 3 columns to left - temp = state[0 * 4 + 3]; - state[0 * 4 + 3] = state[3 * 4 + 3]; - state[3 * 4 + 3] = state[2 * 4 + 3]; - state[2 * 4 + 3] = state[1 * 4 + 3]; - state[1 * 4 + 3] = temp; - } - - private static mixColumns(state: Uint8Array) { - let tmp1: number; - let tmp2: number; - - function xtime(x: number): number { - return (x << 1) ^ (((x >>> 7) & 1) * 0x1B); - } - - for (let i = 0; i < 4; i++) { - const t = state[i * 4 + 0]; - tmp1 = state[i * 4 + 0] ^ state[i * 4 + 1] ^ state[i * 4 + 2] ^ state[i * 4 + 3]; - tmp2 = xtime(state[i * 4 + 0] ^ state[i * 4 + 1]); - state[i * 4 + 0] ^= tmp2 ^ tmp1; - tmp2 = xtime(state[i * 4 + 1] ^ state[i * 4 + 2]); - state[i * 4 + 1] ^= tmp2 ^ tmp1; - tmp2 = xtime(state[i * 4 + 2] ^ state[i * 4 + 3]); - state[i * 4 + 2] ^= tmp2 ^ tmp1; - tmp2 = xtime(state[i * 4 + 3] ^ t); - state[i * 4 + 3] ^= tmp2 ^ tmp1; - } - } -} - export function insydeAcerSwitch(arr: Uint8Array): Uint8Array { if (arr.length !== 32) { throw new Error("Input array should have 32 length");