diff --git a/src/dell/encode.ts b/src/dell/encode.ts index 4b8aff4..1964f43 100644 --- a/src/dell/encode.ts +++ b/src/dell/encode.ts @@ -39,6 +39,26 @@ const md5magic2 = [ 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[]; +} + // TODO: maybe get rid from Math.pow function rol(x: number, bitsrot: number): number { // n >>> 0 used to convert signed number to unsigned @@ -46,221 +66,310 @@ function rol(x: number, bitsrot: number): number { return ((x >>> 0) / Math.pow(2, 32 - bitsrot)) | (((x >>> 0) << bitsrot) | 0 ); } -function blockEncode(encBlock: number[], f1: any, f2: any, f3: any, f4: any, f5: any, repeater: number) { - // reinit each run - let encData = [ 0x67452301 | 0, 0xEFCDAB89 | 0, 0x98BADCFE | 0, 0x10325476 | 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); +} - let A = encData[0] | 0; // For bit alignment - let B = encData[1] | 0; - let C = encData[2] | 0; - let D = encData[3] | 0; +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; - function f_shortcut(func: any, key: number, num: number): number { - return (A + f1(func, B, C , D, md5magic[num] + encBlock[ key ])) | 0; + 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]; } - function f_shortcut2(func: any, key: number, num: number): number { - return (A + f1(func, B, C, D, md5magic2[num] + encBlock[key])) | 0; + + 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; } - const S = [ [ 7, 12, 17, 22 ], - [ 5, 9, 14, 20 ], - [ 4, 11, 16, 23 ], - [ 6, 10, 15, 21 ] ]; - let t: number = 0; - - for (let j = 0; j <= repeater; j++) { - if (repeater === 16) { // 1f66 - A |= 0x100097; - B ^= 0xA0008; - C |= 0x60606161 - j; - D ^= 0x50501010 + j; - for (let i = 0; i < 64; i++) { - switch (i >> 4) { - case 0: - t = f_shortcut2(f2, i & 15, i + 16 | 0); - break; - case 1: - t = f_shortcut2(f3, (i * 5 + 1) & 15, i + 32 | 0); - break; - case 2: - t = f_shortcut2(f4, (i * 3 + 5) & 15, i - 2 * (i & 12) + 12); - break; - case 3: - t = f_shortcut2(f5, (i * 7) & 15, 2 * (i & 3) - (i & 15) + 12); - break; - } - A = D, D = C, C = B, B = rol(t, S[i >> 4][i & 3]) + B | 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.encData[0] += this.A; + this.encData[1] += this.B; + this.encData[2] += this.C; + this.encData[3] += this.D; + } - } else if (repeater === 22) { - A |= 0xA08097; - B ^= 0xA010908; - C |= 0x60606161 - j; - D ^= 0x50501010 + j; + 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++) { - let k = (i & 15) - ((i & 12) << 1) + 12; switch (i >> 4) { case 0: - t = f_shortcut2(f2, i & 15, i + 32 | 0); + t = this.calculate(this.f2, i & 15, i + 16 | 0); break; case 1: - t = f_shortcut2(f3, (i * 5 + 1) & 15, (i & 15) | 0); + t = this.calculate(this.f3, (i * 5 + 1) & 15, i + 32 | 0); break; case 2: - t = f_shortcut2(f4, (i * 3 + 5) & 15, k + 16 | 0); + t = this.calculate(this.f4, (i * 3 + 5) & 15, i - 2 * (i & 12) + 12); break; case 3: - t = f_shortcut2(f5, (i * 7) & 15, k + 48 | 0); + t = this.calculate(this.f5, (i * 7) & 15, 2 * (i & 3) - (i & 15) + 12); break; } - A = D, D = C, C = B, B = rol(t, S[i >> 4][i & 3]) + B | 0; - } - } else { - if (repeater) { - A |= 0x97; - B ^= 0x8; - C |= (0x60606161 - j); - D ^= (0x50501010 + j); + 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.encData[0] += this.A; + this.encData[1] += this.B; + this.encData[2] += this.C; + this.encData[3] += this.D; + } + + 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 = f_shortcut(f2, i & 15, i); // Use half byte + t = this.calculate(this.f4, (i * 3 + 5) & 15, 2 * (i & 3) - i + 44); break; case 1: - t = f_shortcut(f3, (i * 5 + 1) & 15, i); + t = this.calculate(this.f5, (i * 7) & 15, 2 * (i & 3) - i + 76); break; case 2: - t = f_shortcut(f4, (i * 3 + 5) & 15, i); + t = this.calculate(this.f2, i & 15, (i & 15) | 0); break; case 3: - t = f_shortcut(f5, (i * 7) & 15, i); + t = this.calculate(this.f3, (i * 5 + 1) & 15, i - 32 | 0); break; } - A = D, D = C, C = B, B = (rol(t, S[i >> 4][i & 3]) + B) | 0; + 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.encData[0] += this.A; + this.encData[1] += this.B; + this.encData[2] += this.C; + this.encData[3] += this.D; } - encData[0] += A; - encData[1] += B; - encData[2] += C; - encData[3] += D; } - if (repeater === 16) { // 1F66 - for (let j = 0; j <= 20; j++) { // 1D3B - A |= 0x97; - B ^= 0x8; - C |= 0x50501010 - j; - D ^= 0x60606161 + j; +} + +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 = f_shortcut2(f4, (i * 3 + 5) & 15, 2 * (i & 3) - i + 44); + t = this.calculate(this.f2, i & 15, i + 32 | 0); break; case 1: - t = f_shortcut2(f5, (i * 7) & 15, 2 * (i & 3) - i + 76); + t = this.calculate(this.f3, (i * 5 + 1) & 15, (i & 15) | 0); break; case 2: - t = f_shortcut2(f2, i & 15, (i & 15) | 0); + t = this.calculate(this.f4, (i * 3 + 5) & 15, k + 16 | 0); break; case 3: - t = f_shortcut2(f3, (i * 5 + 1) & 15, i - 32 | 0); + t = this.calculate(this.f5, (i * 7) & 15, k + 48 | 0); break; } - let g = (i >> 4) + 2; - A = D, D = C, C = B, B = rol(t, S[g & 3][i & 3]) + B | 0; + this.A = this.D; + this.D = this.C; + this.C = this.B; + this.B = rol(t, rotationTable[i >> 4][i & 3]) + this.B | 0; } - encData[0] += A; - encData[1] += B; - encData[2] += C; - encData[3] += D; + this.encData[0] += this.A; + this.encData[1] += this.B; + this.encData[2] += this.C; + this.encData[3] += this.D; } - } else if (repeater === 22) { - for (let j = 0; j <= 16; j++) { - A |= 0x100097; - B ^= 0xA0008; - C |= 0x50501010 - j; - D ^= 0x60606161 + j; + + 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 = f_shortcut2(f4, ((i & 15) * 3 + 5) & 15, k + 16); + t = this.calculate(this.f4, ((i & 15) * 3 + 5) & 15, k + 16); break; case 1: - t = f_shortcut2(f5, ((i & 3) * 7 + (i & 12) + 4) & 15, (i & 15) + 32); + t = this.calculate(this.f5, ((i & 3) * 7 + (i & 12) + 4) & 15, (i & 15) + 32); break; case 2: - t = f_shortcut2(f2, k & 15, k); + t = this.calculate(this.f2, k & 15, k); break; case 3: - t = f_shortcut2(f3, ((i & 15) * 5 + 1) & 15, (i & 15) + 48); + t = this.calculate(this.f3, ((i & 15) * 5 + 1) & 15, (i & 15) + 48); break; } let g = (i >> 4) + 2; - A = D, D = C, C = B, B = rol(t, S[g & 3][i & 3]) + B | 0; + this.A = this.D; + this.D = this.C; + this.C = this.B; + this.B = rol(t, rotationTable[g & 3][i & 3]) + this.B | 0; } - encData[0] += A; - encData[1] += B; - encData[2] += C; - encData[3] += D; + this.encData[0] += this.A; + this.encData[1] += this.B; + this.encData[2] += this.C; + this.encData[3] += this.D; } } - return encData.map((v) => v | 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(func: any, num1: number, num2: number, num3: number, key: number) { - return (func(num1, num2, num3) + key) | 0; // For bit alignment -} +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 +}; -// Negative functions -function encF1N(func: any, num1: number, num2: number, num3: number, key: number) { - return encF1(func, num1, num2, num3, -key); -} -function encF2N(num1: number, num2: number, num3: number) { - return encF2(num1, num2, ~num3); -} - -function encF4N(num1: number, num2: number, num3: number) { - return encF4(num1, ~num2, num3); -} - -function encF5N(num1: number, num2: number, num3: number) { - return encF5(~num1, num2, num3); -} - -export function choseEncode(encBlock: number[], tag: DellTag): number[] { - - /* Main part */ - if (tag === DellTag.TagD35B) { - return blockEncode(encBlock, encF1, encF2, encF3, encF4, encF5, 0); - } else if (tag === DellTag.Tag1D3B) { - return blockEncode(encBlock, encF1N, encF2N, encF3, encF4N, encF5N, 20); - } else if (tag === DellTag.Tag1F66) { - return blockEncode(encBlock, encF1N, encF2N, encF3, encF4N, encF5N, 16); - } else if (tag === DellTag.Tag6FF1) { - return blockEncode(encBlock, encF1N, encF2N, encF3, encF4N, encF5N, 22); - } else { - return blockEncode(encBlock, encF1N, encF2N, encF3, encF4N, encF5N, 0); - } +export function blockEncode(encBlock: number[], tag: DellTag): number[] { + return encoders[tag].encode(encBlock); } diff --git a/src/dell/index.ts b/src/dell/index.ts index 6c7f49e..a356960 100644 --- a/src/dell/index.ts +++ b/src/dell/index.ts @@ -1,6 +1,6 @@ /* tslint:disable:no-bitwise */ import { makeSolver } from "../utils"; -import { choseEncode } from "./encode"; +import { blockEncode } from "./encode"; import { DellTag, SuffixType } from "./types"; export { DellTag, SuffixType}; @@ -13,7 +13,7 @@ const encscans: number[] = [ 0x24, 0x23, 0x31, 0x20, 0x1E, 0x08, 0x2D, 0x21, 0x04, 0x0B, 0x12, 0x2E ]; -const extraCharacters: {[key: string]: string} = { +const extraCharacters: {readonly [P in DellTag]?: string} = { "2A7B": "012345679abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0", "1D3B": "0BfIUG1kuPvc8A9Nl5DLZYSno7Ka6HMgqsJWm65yCQR94b21OTp7VFX2z0jihE33d4xtrew0", "1F66": "0ewr3d4xtUG1ku0BfIp7VFb21OTSno7KDLZYqsJWa6HMgCQR94m65y9Nl5Pvc8AjihE3X2z0", @@ -76,8 +76,9 @@ export function calculateSuffix(serial: number[], tag: DellTag, type: SuffixType suffix[i] = v & 0xFF; }); - if ((tag as string) in extraCharacters) { - codesTable = extraCharacters[tag as string].split("").map((s) => s.charCodeAt(0)); + let table = extraCharacters[tag]; + if (table !== undefined) { + codesTable = table.split("").map((s) => s.charCodeAt(0)); } else { codesTable = encscans; } @@ -109,9 +110,9 @@ export function calculateSuffix(serial: number[], tag: DellTag, type: SuffixType 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 ((tag as string) in extraCharacters) { - let table = extraCharacters[tag as string]; + 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]); @@ -182,7 +183,7 @@ export function keygenDell(serial: string, tag: DellTag, type: SuffixType): stri } } encBlock[14] = cnt << 3; - let decodedBytes = intArrayToByte(choseEncode(encBlock, tag)); + let decodedBytes = intArrayToByte(blockEncode(encBlock, tag)); return resultToString(decodedBytes, tag); } diff --git a/tslint.json b/tslint.json index 32a0cf8..5f28eff 100644 --- a/tslint.json +++ b/tslint.json @@ -17,7 +17,25 @@ "indent": [true, "spaces", 4], "no-null-keyword": true, "encoding": true, - "no-namespace": true + "no-namespace": true, + "max-classes-per-file": [false], + "member-ordering": [true, {"order": [ + "private-static-field", + "protected-static-field", + "public-static-field", + "private-instance-field", + "protected-instance-field", + "public-instance-field", + "private-constructor", + "protected-constructor", + "public-constructor", + "private-instance-method", + "protected-instance-method", + "public-instance-method", + "private-static-method", + "protected-static-method", + "public-static-method" + ]}] }, "rulesDirectory": [] }