diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..bec17f1 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,23 @@ +var gulp = require("gulp"); +var ts = require("gulp-typescript"); +var tslint = require("gulp-tslint"); +var jasmine = require("gulp-jasmine"); +var tsProject = ts.createProject("tsconfig.json"); + +gulp.task("build", function() { + return tsProject.src() + .pipe(tsProject()) + .js.pipe(gulp.dest("dist")); +}); + +gulp.task('test', ['build'], function() { + return gulp.src("dist/*.spec.js").pipe(jasmine()); +}); + +gulp.task('tslint', function() { + return tsProject.src() + .pipe(tslint({"formatter": "verbose"})) + .pipe(tslint.report()); +}); + +gulp.task('default', ['tslint', 'build', 'test']) diff --git a/package.json b/package.json new file mode 100644 index 0000000..c90b587 --- /dev/null +++ b/package.json @@ -0,0 +1,37 @@ +{ + "name": "pwgen-for-bios", + "version": "2.0.0", + "description": "Password generator for BIOS", + "main": "decrypt_bios.js", + "dependencies": { + "@types/jasmine": "^2.8.3", + "gulp-jasmine": "^3.0.0", + "typescript": "^2.6.2" + }, + "devDependencies": { + "gulp": "^3.9.1", + "gulp-typescript": "^3.2.3", + "typescript": "^2.6.2" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/bacher09/pwgen-for-bios.git" + }, + "keywords": [ + "bios", + "keygen", + "password" + ], + "scripts": { + "gulp": "gulp" + }, + "author": "Slava Bacherikov", + "license": "GPL-3.0", + "bugs": { + "url": "https://github.com/bacher09/pwgen-for-bios/issues" + }, + "homepage": "https://github.com/bacher09/pwgen-for-bios#readme" +} diff --git a/spec/bios.spec.js b/spec/bios.spec.js deleted file mode 100644 index a100a8b..0000000 --- a/spec/bios.spec.js +++ /dev/null @@ -1,64 +0,0 @@ -var bios = require('../dist/decrypt_bios.js'); - -describe("Decrypt BIOS", function() { - it("Sony key for 1234567 is 9648669", function() { - expect(bios.Sony.solve("1234567")).toEqual(["9648669"]); - }); - - it("Sony input validation", function() { - expect(bios.Sony.check("1234")).toBe(false); - expect(bios.Sony.check("1234567")).toBe(true); - expect(bios.Sony.check("0123456")).toBe(true); - expect(bios.Sony.check("123o567")).toBe(false); - expect(bios.Sony.check("1234567D")).toBe(false); - }); - - it("Samsung key for 07088120410C0000 is 12345", function() { - expect(bios.Samsung.solve("07088120410C0000")).toEqual(["12345"]); - }); - - it("Samsung input validation", function() { - expect(bios.Samsung.check("07088120410C0000")).toBe(true); - expect(bios.Samsung.check("07088120410C000000")).toBe(false); - expect(bios.Samsung.check("07088120410C000O")).toBe(false); - expect(bios.Samsung.check("07088120410C")).toBe(true); - expect(bios.Samsung.check("07088120410C00")).toBe(true); - expect(bios.Samsung.check("0123456")).toBe(false); - expect(bios.Samsung.check("07088a20410C00")).toBe(true); - }); - - it("HPMini key for CNU1234ABC is e9l37fvcpe", function() { - expect(bios.HPMini.solve("CNU1234ABC")).toEqual(["e9l37fvcpe"]); - }); - - it("HPMini input validation", function() { - expect(bios.HPMini.check("CNU1234ABC")).toBe(true); - expect(bios.HPMini.check("CNU1234ABCV")).toBe(false); - expect(bios.HPMini.check("CNU12$4ABC")).toBe(false); - expect(bios.HPMini.check("CNU12п4ABC")).toBe(false); - }); - - it("Insyde key for 03133610 is 12891236", function() { - expect(bios.Insyde.solve("03133610")).toEqual(["12891236"]); - }); - - it("Insyde input validation", function() { - expect(bios.Insyde.check("12345678")).toBe(true); - expect(bios.Insyde.check("123456789")).toBe(false); - expect(bios.Insyde.check("1234o678")).toBe(false); - expect(bios.Insyde.check("12345678d")).toBe(false); - }); - - it("FSI 20 dec key for 1234-4321-1234-4321-1234 is 7122790 or 10cphf0b", function() { - expect(bios.FSI20DecOld.solve(bios.CleanSerial("1234-4321-1234-4321-1234"))) - .toEqual(["7122790", "10cphf0b"]); - - expect(bios.FSI20DecOld.solve(bios.CleanSerial("1234-4321-1234-4321-1236"))) - .toEqual(["7122790", "100phf0b"]); - }) - - it("FSI 20 hex key for AAAA-BBBB-CCCC-DEAD-BEEF is 64830592", function() { - expect(bios.FSI20Hex.solve(bios.CleanSerial("AAAA-BBBB-CCCC-DEAD-BEEF"))) - .toEqual(["64830592"]); - }); -}); diff --git a/src/decrypt_bios.ts b/src/decrypt_bios.ts deleted file mode 100644 index a59fe29..0000000 --- a/src/decrypt_bios.ts +++ /dev/null @@ -1,367 +0,0 @@ -type Predicate = (val: T) => boolean; -type Tuple = [A, B]; -type BIOSSolver = (val: string) => string[]; - -export const enum BIOSModels { - Sony = 1, - Samsung, - Phoenix, - HPCompaq, - FSIPhoenix, - FSILPhoenix, - FSIPPhoenix, - FSISPhoenix, - FSIXPhoenix, - Insyde, - HPMini -}; - -interface BIOSDecoder { - model: BIOSModels; - name: string; - description?: string; - examples?: string[]; - check: Predicate; - solve: BIOSSolver; -} - -type FindResult = Tuple; - -namespace Utils { - /* May be need add 51, 52 and 53 symbol */ - 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" - }; - /* Decode Keyboard code to Ascii symbol */ - export function keyboardEncToAscii(inKey: number[]): string { - let out = ""; - for (let i = 0; i < inKey.length; i++) { - if (inKey[i] === 0) return out; - if (inKey[i] in keyboardDict) { - out += keyboardDict[inKey[i]]; - } else { - return ""; - } - } - return out; - } -} - -/* Return password for old sony laptops - * password 7 digit number like 1234567 */ -function SonySolver(serial: string): string { - if (serial.length !== 7) { - return null; - } - const table = "0987654321876543210976543210982109876543109876543221098765436543210987"; - let code = ""; - for (let i = 0; i < serial.length; i++) { - code += table.charAt(parseInt(serial.charAt(i), 10) + 10 * i); - } - return code; -} - -/* Return password for samsung laptops - * 12 or 18 hexhecimal digits like 07088120410C0000 */ -function SamsungSolver(serial: string): string[] { - - 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(inKey: number[]): string { - let out = ""; - for (let i = 0; i < inKey.length; i++) { - if (inKey[i] === 0) return out; - if (inKey[i] < 32 || inKey[i] > 127) return undefined; - out += String.fromCharCode(inKey[i]); - } - - return out; - } - - function decryptHash(hash: number[], key: number, rotationMatrix: number[]) { - let outhash: number[] = []; - for (let i = 0; i < hash.length; i++) { - let val = ((hash[i] << (rotationMatrix[7 * key + i])) & 0xFF) | - (hash[i] >> (8 - rotationMatrix[7 * key + i])); - outhash.push(val); - } - return outhash; - } - - 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[]) => - Utils.keyboardEncToAscii(decryptHash(hash, key, matrix)); - - let scanCodePassword = calcScanCodePwd(rotationMatrix1); - if (scanCodePassword === "") { - scanCodePassword = calcScanCodePwd(rotationMatrix2); - } - - let asciiPassword1 = keyToAscii(decryptHash(hash, key, rotationMatrix1)); - let asciiPassword2 = keyToAscii(decryptHash(hash, key, rotationMatrix2)); - - // TODO: This might require polyfil - return [scanCodePassword, asciiPassword1, asciiPassword2]. - filter(code => code ? true : false); -} - -/* For HP/Compaq Netbooks. 10 chars */ -function HPMiniSolver(serial: string): string[] { - 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" - }; - - 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()]; - } -} - -/* Maybe need fixing for browsers where numbers is 32-bits */ -/* Some Acer, HP laptops. 8 digit */ -function InsydeSolver(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]; -} - -/* For Fujinsu-Siemens. 5x4 dicimal digits */ -function FSI20DecOldSolver(serial: string): string { - function swap (arr: T[], i1: number, i2: number): void { - let temp = arr[i1]; - arr[i1] = arr[i2]; - arr[i2] = temp; - }; - // op_arr - array with that operations do, ar1,ar2 - numbers */ - function interleave(op_arr: number[], ar1: number[], ar2: number[]) { - let arr = op_arr.slice(0); // copy array - arr[ar1[0]] = ((op_arr[ar2[0]] >> 4) | (op_arr[ar2[3]] << 4)) & 0xFF; - arr[ar1[1]] = ((op_arr[ar2[0]] & 0x0F) | (op_arr[ar2[3]] & 0xF0)); - arr[ar1[2]] = ((op_arr[ar2[1]] >> 4) | (op_arr[ar2[2]] << 4) & 0xFF); - arr[ar1[3]] = (op_arr[ar2[1]] & 0x0F) | (op_arr[ar2[2]] & 0xF0); - return arr; - } - - function codeToBytes(code: string): number[] { - let 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) - ]; - return numbers.reduce((acc, val) => { - 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 FSI20DecNewSolver(serial: string): string { - const f_keys = [ - "4798156302", "7201593846", "5412367098", "6587249310", - "9137605284", "3974018625", "8052974163" - ]; - - return [0, 2, 5, 11, 13, 15, 16].map((val, i, arr) => { - let temp = parseInt(serial.charAt(val), 10); - return f_keys[i].charAt(temp); - }).join(""); -} - -/* For Fujinsu-Siemens. 8 or 5x4 hexadecimal digits. */ -function FSI20HexSolver(serial: string): string { - - 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; - } - - 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); - - const table = generateCRC16Table(); - return hashToString(calculateHash(serial.slice(0, 4), table)) + - hashToString(calculateHash(serial.slice(4, 8), table)); -} - -export let CleanSerial = (serial: string) => serial.trim().replace(/-/gi, ""); - -export let Sony: BIOSDecoder = { - model: BIOSModels.Sony, - name: "Sony", - examples: ["1234567"], - check: (s) => /^\d{7}$/i.test(s), - solve: (s) => { - let res = SonySolver(s); - return res ? [res] : []; - } -}; - -export let Samsung: BIOSDecoder = { - model: BIOSModels.Samsung, - name: "Samsung", - examples: ["07088120410C0000"], - check: (s) => /^[0-9ABCDEF]+$/i.test(s) && ( - s.length === 12 || s.length === 14 || s.length === 16 - ), - solve: SamsungSolver -}; - -export let HPMini: BIOSDecoder = { - model: BIOSModels.HPMini, - name: "HPMini", - examples: ["CNU1234ABC"], - check: (s) => /^[0-9A-Z]{10}$/i.test(s), - solve: HPMiniSolver -}; - -export let Insyde: BIOSDecoder = { - model: BIOSModels.Insyde, - name: "Insyde H2O", - examples: ["03133610"], - check: (s) => /^\d{8}$/i.test(s), - solve: InsydeSolver -}; - -export let FSI20DecOld: BIOSDecoder = { - model: BIOSModels.FSIPhoenix, - name: "Fujitsu-Siemens decimal", - examples: ["1234-4321-1234-4321-1234"], - check: (s) => /^\d{20}$/i.test(s), - solve: (serial) => [FSI20DecNewSolver(serial), FSI20DecOldSolver(serial)] -}; - -export let FSI20Hex: BIOSDecoder = { - model: BIOSModels.FSILPhoenix, - name: "Fujitsu-Siemens hexdigits", - examples: ["AAAA-BBBB-CCCC-DEAD-BEEF"], - check: (s) => /^[0-9ABCDEF]{20}$/i.test(s), - solve: (serial) => [FSI20HexSolver(serial)] -}; - -export let Decoders: BIOSDecoder[] = [ - Sony, Samsung, HPMini, Insyde, FSI20DecOld -]; - -export function runDecoder(serial: string, decoder: BIOSDecoder): string[] { - return decoder.check(serial) ? decoder.solve(serial) : []; -} - -export function runDecoders(serial: string, decoders: BIOSDecoder[]): FindResult[] { - return decoders.map((dec: BIOSDecoder): FindResult => - [runDecoder(serial, dec), dec]).filter(res => res[0].length > 0); -} - -export let findPassword = (serial: string) => - runDecoders(CleanSerial(serial), Decoders); diff --git a/src/fsi.spec.ts b/src/fsi.spec.ts new file mode 100644 index 0000000..8ef19bd --- /dev/null +++ b/src/fsi.spec.ts @@ -0,0 +1,45 @@ +import { fsi20DecNewSolver, fsi20DecOldSolver, fsi20HexSolver } from "./fsi"; + +describe("Test Fujitsu-Siemens 5x4 hexadecimal BIOS", () => { + it("FSI key for 1234-4321-1234-4321-1234 is 35682708", () => { + expect(fsi20HexSolver("1234-4321-1234-4321-1234")).toEqual(["35683789"]); + }); + it("FSI key for AAAA-BBBB-CCCC-DEAD-BEEF is 64830592", () => { + expect(fsi20HexSolver("AAAA-BBBB-CCCC-DEAD-BEEF")).toEqual(["64830592"]); + expect(fsi20HexSolver("AAAABBBBCCCCDEADBEEF")).toEqual(["64830592"]); + }); + it("test invalid keys", () => { + expect(fsi20HexSolver("AAAA-BBBB-CCCC-DEAD-CODE")).toEqual([]); + expect(fsi20HexSolver("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([]); + }); +}); diff --git a/src/fsi.ts b/src/fsi.ts new file mode 100644 index 0000000..472ba8d --- /dev/null +++ b/src/fsi.ts @@ -0,0 +1,144 @@ +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 fsi20HexKeygen(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(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, arr) => { + let temp = parseInt(serial.charAt(val), 10); + return fKeys[i].charAt(temp); + }).join(""); +} + +export let fsi20HexSolver = makeSolver({ + name: "Fujitsu-Siemens hexdigits", + examples: ["AAAA-BBBB-CCCC-DEAD-BEEF"], + inputValidator: (s) => /^[0-9ABCDEF]{20}$/i.test(s), + fun: (code: string) => [fsi20HexKeygen(code)] +}); + +export let fsi20DecNewSolver = makeSolver({ + name: "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: "Fujitsu-Siemens decimal old", + examples: ["1234-4321-1234-4321-1234"], + inputValidator: (s) => /^\d{20}$/i.test(s), + fun: (code: string) => [fsi20DecOldKeygen(code)] +}); diff --git a/src/hpmini.spec.ts b/src/hpmini.spec.ts new file mode 100644 index 0000000..1cd614e --- /dev/null +++ b/src/hpmini.spec.ts @@ -0,0 +1,14 @@ +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("test invalid keys", () => { + expect(hpMiniSolver("CNU12345678")).toEqual([]); + expect(hpMiniSolver("CNU1234")).toEqual([]); + }); +}); diff --git a/src/hpmini.ts b/src/hpmini.ts new file mode 100644 index 0000000..609936c --- /dev/null +++ b/src/hpmini.ts @@ -0,0 +1,43 @@ +/* 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", + examples: ["CNU1234ABC"], + inputValidator: (s) => /^[0-9A-Z]{10}$/i.test(s), + fun: hpMiniKeygen +}); diff --git a/src/insyde.spec.ts b/src/insyde.spec.ts new file mode 100644 index 0000000..d5b0481 --- /dev/null +++ b/src/insyde.spec.ts @@ -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([]); + }); +}); diff --git a/src/insyde.ts b/src/insyde.ts new file mode 100644 index 0000000..eb2623e --- /dev/null +++ b/src/insyde.ts @@ -0,0 +1,32 @@ +/* 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: "Insyde H2O", + examples: ["03133610"], + inputValidator: (s) => /^\d{8}$/i.test(s), + fun: insydeKeygen +}); diff --git a/src/samsung.spec.ts b/src/samsung.spec.ts new file mode 100644 index 0000000..a03db75 --- /dev/null +++ b/src/samsung.spec.ts @@ -0,0 +1,18 @@ +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("test invalid keys", () => { + expect(samsungSolver("1AA9CD4638C01860Z0")).toEqual([]); + expect(samsungSolver("1AA9CD4638C01860000")).toEqual([]); + }); +}); diff --git a/src/samsung.ts b/src/samsung.ts new file mode 100644 index 0000000..36c9088 --- /dev/null +++ b/src/samsung.ts @@ -0,0 +1,78 @@ +/* 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", + examples: ["07088120410C0000"], + inputValidator: (s) => /^[0-9ABCDEF]+$/i.test(s) && ( + s.length === 12 || s.length === 14 || s.length === 16 || s.length === 18 + ), + fun: samsungKeygen +}); diff --git a/src/sony.spec.ts b/src/sony.spec.ts new file mode 100644 index 0000000..3497995 --- /dev/null +++ b/src/sony.spec.ts @@ -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([]); + }); +}); diff --git a/src/sony.ts b/src/sony.ts new file mode 100644 index 0000000..964f088 --- /dev/null +++ b/src/sony.ts @@ -0,0 +1,22 @@ +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", + examples: ["1234567"], + inputValidator: (s) => /^\d{7}$/i.test(s), + fun: (code: string) => { + let res = sonyKeygen(code); + return res ? [res] : []; + } +}); diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..c990d79 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,76 @@ +export type Predicate = (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; +} + +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[]; +} + +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" +}; + +/* 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; +} + +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; +} diff --git a/tsconfig.json b/tsconfig.json index 065b750..d6fb44d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,13 +3,14 @@ "module": "commonjs", "target": "es3", "noImplicitAny": true, - "sourceMap": false, - "outDir": "javascript/" + "strictNullChecks": true, + "sourceMap": true, + "outDir": "dist/" }, "exclude": [ "node_modules" ], "files": [ - "src/decrypt_bios.ts" + "src/*.ts" ] } diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..828c857 --- /dev/null +++ b/tslint.json @@ -0,0 +1,17 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended" + ], + "jsRules": {}, + "rules": { + "trailing-comma": [true, {"multiline": "never", "singleline": "never"}], + "variable-name": [true, "ban-keywords", "check-format"], + "prefer-const": false, + "interface-name": [true, "never-prefix"], + "object-literal-key-quotes": false, + "object-literal-sort-keys": false, + "no-namespace": false + }, + "rulesDirectory": [] +}