Created
June 18, 2019 14:19
-
-
Save vincenting/d25620f89f91342115d315666d67e18e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const HEX_BYTES_RELATIONS = [ | |
["0", "0000"], | |
["1", "0001"], | |
["2", "0010"], | |
["3", "0011"], | |
["4", "0100"], | |
["5", "0101"], | |
["6", "0110"], | |
["7", "0111"], | |
["8", "1000"], | |
["9", "1001"], | |
["A", "1010"], | |
["B", "1011"], | |
["C", "1100"], | |
["D", "1101"], | |
["E", "1110"], | |
["F", "1111"] | |
]; | |
const S_BOX_PERMUTE_TABLE_S1 = [ | |
[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7], | |
[0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8], | |
[4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0], | |
[15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13] | |
]; | |
const S_BOX_PERMUTE_TABLE_S2 = [ | |
[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10], | |
[3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5], | |
[0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15], | |
[13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9] | |
]; | |
const S_BOX_PERMUTE_TABLE_S3 = [ | |
[10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8], | |
[13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1], | |
[13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7], | |
[1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12] | |
]; | |
const S_BOX_PERMUTE_TABLE_S4 = [ | |
[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15], | |
[13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9], | |
[10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4], | |
[3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14] | |
]; | |
const S_BOX_PERMUTE_TABLE_S5 = [ | |
[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9], | |
[14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6], | |
[4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14], | |
[11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3] | |
]; | |
const S_BOX_PERMUTE_TABLE_S6 = [ | |
[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11], | |
[10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8], | |
[9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6], | |
[4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13] | |
]; | |
const S_BOX_PERMUTE_TABLE_S7 = [ | |
[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1], | |
[13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6], | |
[1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2], | |
[6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12] | |
]; | |
const S_BOX_PERMUTE_TABLE_S8 = [ | |
[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7], | |
[1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2], | |
[7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8], | |
[2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11] | |
]; | |
const P_PERMUTE_SWOP_INDEXS = [ | |
[0, 15], | |
[1, 6], | |
[2, 19], | |
[3, 20], | |
[4, 28], | |
[5, 11], | |
[6, 27], | |
[7, 16], | |
[8, 0], | |
[9, 14], | |
[10, 22], | |
[11, 25], | |
[12, 4], | |
[13, 17], | |
[14, 30], | |
[15, 9], | |
[16, 1], | |
[17, 7], | |
[18, 23], | |
[19, 13], | |
[20, 31], | |
[21, 26], | |
[22, 2], | |
[23, 8], | |
[24, 18], | |
[25, 12], | |
[26, 29], | |
[27, 5], | |
[28, 21], | |
[29, 10], | |
[30, 3], | |
[31, 24] | |
]; | |
const FINALLY_PERMUTE_SWOP_INDEXS = [ | |
[0, 39], | |
[1, 7], | |
[2, 47], | |
[3, 15], | |
[4, 55], | |
[5, 23], | |
[6, 63], | |
[7, 31], | |
[8, 38], | |
[9, 6], | |
[10, 46], | |
[11, 14], | |
[12, 54], | |
[13, 22], | |
[14, 62], | |
[15, 30], | |
[16, 37], | |
[17, 5], | |
[18, 45], | |
[19, 13], | |
[20, 53], | |
[21, 21], | |
[22, 61], | |
[23, 29], | |
[24, 36], | |
[25, 4], | |
[26, 44], | |
[27, 12], | |
[28, 52], | |
[29, 20], | |
[30, 60], | |
[31, 28], | |
[32, 35], | |
[33, 3], | |
[34, 43], | |
[35, 11], | |
[36, 51], | |
[37, 19], | |
[38, 59], | |
[39, 27], | |
[40, 34], | |
[41, 2], | |
[42, 42], | |
[43, 10], | |
[44, 50], | |
[45, 18], | |
[46, 58], | |
[47, 26], | |
[48, 33], | |
[49, 1], | |
[50, 41], | |
[51, 9], | |
[52, 49], | |
[53, 17], | |
[54, 57], | |
[55, 25], | |
[56, 32], | |
[57, 0], | |
[58, 40], | |
[59, 8], | |
[60, 48], | |
[61, 16], | |
[62, 56], | |
[63, 24] | |
]; | |
const GENERATE_KEYS_SWOP_KEYS = [ | |
13, | |
16, | |
10, | |
23, | |
0, | |
4, | |
2, | |
27, | |
14, | |
5, | |
20, | |
9, | |
22, | |
18, | |
11, | |
3, | |
25, | |
7, | |
15, | |
6, | |
26, | |
19, | |
12, | |
1, | |
40, | |
51, | |
30, | |
36, | |
46, | |
54, | |
29, | |
39, | |
50, | |
44, | |
32, | |
47, | |
43, | |
48, | |
38, | |
55, | |
33, | |
52, | |
45, | |
41, | |
49, | |
35, | |
28, | |
31 | |
]; | |
const HEX_TO_BYTES_MAP = HEX_BYTES_RELATIONS.reduce( | |
(ret, [k, v]) => ({ ...ret, [k]: v }), | |
{} | |
); | |
const BYTES_TO_HEX_MAP = HEX_BYTES_RELATIONS.reduce( | |
(ret, [v, k]) => ({ ...ret, [k]: v }), | |
{} | |
); | |
function xor(byteOne: number[], byteTwo: number[]): number[] { | |
let xorByte = new Array(byteOne.length); | |
for (let i = 0; i < byteOne.length; i++) { | |
xorByte[i] = byteOne[i] ^ byteTwo[i]; | |
} | |
return xorByte; | |
} | |
function convertStringToByteLikeArray(str: string): number[] { | |
const ret = new Array(64).fill(0); | |
const size = Math.min(str.length, 4); | |
for (let i = 0; i < size; i++) { | |
const k = str.charCodeAt(i); | |
for (let j = 0; j < 16; j++) { | |
let pow = 1, | |
m = 0; | |
for (m = 15; m > j; m--) { | |
pow *= 2; | |
} | |
ret[16 * i + j] = ~~(k / pow) % 2; | |
} | |
} | |
return ret; | |
} | |
function sBoxPermute(expandByte: number[]): number[] { | |
const sBoxByte = new Array(32); | |
let binary = ""; | |
for (let m = 0; m < 8; m++) { | |
var i = 0, | |
j = 0; | |
i = expandByte[m * 6 + 0] * 2 + expandByte[m * 6 + 5]; | |
j = | |
expandByte[m * 6 + 1] * 2 * 2 * 2 + | |
expandByte[m * 6 + 2] * 2 * 2 + | |
expandByte[m * 6 + 3] * 2 + | |
expandByte[m * 6 + 4]; | |
switch (m) { | |
case 0: | |
binary = HEX_BYTES_RELATIONS[S_BOX_PERMUTE_TABLE_S1[i][j]][1]; | |
break; | |
case 1: | |
binary = HEX_BYTES_RELATIONS[S_BOX_PERMUTE_TABLE_S2[i][j]][1]; | |
break; | |
case 2: | |
binary = HEX_BYTES_RELATIONS[S_BOX_PERMUTE_TABLE_S3[i][j]][1]; | |
break; | |
case 3: | |
binary = HEX_BYTES_RELATIONS[S_BOX_PERMUTE_TABLE_S4[i][j]][1]; | |
break; | |
case 4: | |
binary = HEX_BYTES_RELATIONS[S_BOX_PERMUTE_TABLE_S5[i][j]][1]; | |
break; | |
case 5: | |
binary = HEX_BYTES_RELATIONS[S_BOX_PERMUTE_TABLE_S6[i][j]][1]; | |
break; | |
case 6: | |
binary = HEX_BYTES_RELATIONS[S_BOX_PERMUTE_TABLE_S7[i][j]][1]; | |
break; | |
case 7: | |
binary = HEX_BYTES_RELATIONS[S_BOX_PERMUTE_TABLE_S8[i][j]][1]; | |
break; | |
} | |
sBoxByte[m * 4 + 0] = ~~binary.substring(0, 1); | |
sBoxByte[m * 4 + 1] = ~~binary.substring(1, 2); | |
sBoxByte[m * 4 + 2] = ~~binary.substring(2, 3); | |
sBoxByte[m * 4 + 3] = ~~binary.substring(3, 4); | |
} | |
return sBoxByte; | |
} | |
function initPermute(originalData: number[]): number[] { | |
var ipByte = new Array(64); | |
for (let i = 0, m = 1, n = 0; i < 4; i++, m += 2, n += 2) { | |
for (let j = 7, k = 0; j >= 0; j--, k++) { | |
ipByte[i * 8 + k] = originalData[j * 8 + m]; | |
ipByte[i * 8 + k + 32] = originalData[j * 8 + n]; | |
} | |
} | |
return ipByte; | |
} | |
function expandPermute(rightData: number[]): number[] { | |
var epByte = new Array(48); | |
for (let i = 0; i < 8; i++) { | |
if (i == 0) { | |
epByte[i * 6 + 0] = rightData[31]; | |
} else { | |
epByte[i * 6 + 0] = rightData[i * 4 - 1]; | |
} | |
epByte[i * 6 + 1] = rightData[i * 4 + 0]; | |
epByte[i * 6 + 2] = rightData[i * 4 + 1]; | |
epByte[i * 6 + 3] = rightData[i * 4 + 2]; | |
epByte[i * 6 + 4] = rightData[i * 4 + 3]; | |
if (i == 7) { | |
epByte[i * 6 + 5] = rightData[0]; | |
} else { | |
epByte[i * 6 + 5] = rightData[i * 4 + 4]; | |
} | |
} | |
return epByte; | |
} | |
function pPermute(sBoxByte: number[]): number[] { | |
const pBoxPermute = new Array(32); | |
for (let i = 0; i < P_PERMUTE_SWOP_INDEXS.length; i++) { | |
const [left, right] = P_PERMUTE_SWOP_INDEXS[i]; | |
pBoxPermute[left] = sBoxByte[right]; | |
} | |
return pBoxPermute; | |
} | |
function finallyPermute(endByte: number[]): number[] { | |
var fpByte = new Array(64); | |
for (let i = 0; i < FINALLY_PERMUTE_SWOP_INDEXS.length; i++) { | |
const [left, right] = FINALLY_PERMUTE_SWOP_INDEXS[i]; | |
fpByte[left] = endByte[right]; | |
} | |
return fpByte; | |
} | |
function generateKeys(keyByte: number[]): [number[]] { | |
const key = new Array(56); | |
const keys = new Array(16).fill(undefined).map(() => []); | |
const loop = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]; | |
for (let i = 0; i < 7; i++) { | |
for (let j = 0, k = 7; j < 8; j++, k--) { | |
key[i * 8 + j] = keyByte[8 * k + i]; | |
} | |
} | |
for (let i = 0; i < 16; i++) { | |
var tempLeft = 0; | |
var tempRight = 0; | |
for (let j = 0; j < loop[i]; j++) { | |
tempLeft = key[0]; | |
tempRight = key[28]; | |
for (let k = 0; k < 27; k++) { | |
key[k] = key[k + 1]; | |
key[28 + k] = key[29 + k]; | |
} | |
key[27] = tempLeft; | |
key[55] = tempRight; | |
} | |
for (let m = 0; m < 48; m++) { | |
keys[i][m] = key[GENERATE_KEYS_SWOP_KEYS[m]]; | |
} | |
} | |
return keys as [number[]]; | |
} | |
function enc(dataByte: number[], keyByte: number[]): number[] { | |
const keys = generateKeys(keyByte); | |
const ipByte = initPermute(dataByte); | |
const ipLeft = new Array(32).fill(0); | |
const ipRight = new Array(32).fill(0); | |
const tempLeft = new Array(32).fill(0); | |
for (let k = 0; k < 32; k++) { | |
ipLeft[k] = ipByte[k]; | |
ipRight[k] = ipByte[32 + k]; | |
} | |
for (let i = 0; i < 16; i++) { | |
for (let j = 0; j < 32; j++) { | |
tempLeft[j] = ipLeft[j]; | |
ipLeft[j] = ipRight[j]; | |
} | |
var key = new Array(48); | |
for (let j = 0; j < 48; j++) { | |
key[j] = keys[i][j]; | |
} | |
var tempRight = xor( | |
pPermute(sBoxPermute(xor(expandPermute(ipRight), key))), | |
tempLeft | |
); | |
for (let j = 0; j < 32; j++) { | |
ipRight[j] = tempRight[j]; | |
} | |
} | |
var finalData = new Array(64); | |
for (let i = 0; i < 32; i++) { | |
finalData[i] = ipRight[i]; | |
finalData[32 + i] = ipLeft[i]; | |
} | |
return finallyPermute(finalData); | |
} | |
function dec(dataByte: number[], keyByte: number[]) { | |
const keys = generateKeys(keyByte); | |
const ipByte = initPermute(dataByte); | |
const ipLeft = new Array(32).fill(0); | |
const ipRight = new Array(32).fill(0); | |
const tempLeft = new Array(32).fill(0); | |
for (let k = 0; k < 32; k++) { | |
ipLeft[k] = ipByte[k]; | |
ipRight[k] = ipByte[32 + k]; | |
} | |
for (let i = 15; i >= 0; i--) { | |
for (let j = 0; j < 32; j++) { | |
tempLeft[j] = ipLeft[j]; | |
ipLeft[j] = ipRight[j]; | |
} | |
var key = new Array(48); | |
for (let m = 0; m < 48; m++) { | |
key[m] = keys[i][m]; | |
} | |
var tempRight = xor( | |
pPermute(sBoxPermute(xor(expandPermute(ipRight), key))), | |
tempLeft | |
); | |
for (let n = 0; n < 32; n++) { | |
ipRight[n] = tempRight[n]; | |
} | |
} | |
var finalData = new Array(64); | |
for (let i = 0; i < 32; i++) { | |
finalData[i] = ipRight[i]; | |
finalData[32 + i] = ipLeft[i]; | |
} | |
return finallyPermute(finalData); | |
} | |
function convertHexToByte4(hexString: string): string { | |
return HEX_TO_BYTES_MAP[hexString]!; | |
} | |
function convertHexToByte64(hexString: string): string { | |
var binary = ""; | |
for (let i = 0; i < 16; i++) { | |
binary += convertHexToByte4(hexString.substring(i, i + 1)); | |
} | |
return binary; | |
} | |
function convertByte4ToHex(byteData: string): string { | |
return BYTES_TO_HEX_MAP[byteData]; | |
} | |
function convertStringToChunkedByteLikeArray(str: string): [number[]] { | |
const keyBytes = []; | |
const iterator = Math.ceil(str.length / 4); | |
for (let i = 0; i < iterator; i++) { | |
keyBytes[i] = convertStringToByteLikeArray( | |
str.substring(i * 4 + 0, i * 4 + 4) | |
); | |
} | |
return keyBytes as [number[]]; | |
} | |
function convertByte64ToHex(byteData: number[]): string { | |
let ret = ""; | |
for (let i = 0; i < 16; i++) { | |
ret += convertByte4ToHex(byteData.slice(i * 4, i * 4 + 4).join("")); | |
} | |
return ret; | |
} | |
function convertByte64ToString(byteData: number[]): string { | |
let ret = ""; | |
for (let i = 0; i < 4; i++) { | |
let count = 0; | |
for (let j = 0; j < 16; j++) { | |
let pow = 1; | |
// reverse calculation for convertStringToByteLikeArray | |
for (let m = 15; m > j; m--) { | |
pow *= 2; | |
} | |
count += ~~byteData[16 * i + j] * pow; | |
} | |
if (count != 0) { | |
ret += String.fromCharCode(count); | |
} | |
} | |
return ret; | |
} | |
function encypt(data: string, ...keys: string[]): string { | |
if (!data) return data; | |
const size = data.length; | |
const keyBytes = keys.map(convertStringToChunkedByteLikeArray); | |
const iterator = Math.ceil(size / 4); | |
let ret = ""; | |
for (let i = 0; i < iterator; i++) { | |
let encyptedBytes = convertStringToByteLikeArray( | |
data.substring(i * 4, i * 4 + 4) | |
); | |
for (let i = 0; i < keys.length; i++) { | |
const currentKeyByte = keyBytes[i]; | |
for (let j = 0; j < currentKeyByte.length; j++) { | |
encyptedBytes = enc(encyptedBytes, currentKeyByte[j]); | |
} | |
} | |
ret += convertByte64ToHex(encyptedBytes); | |
} | |
return ret; | |
} | |
function decrypt(data: string, ...keys: string[]): string { | |
if (!data) return ""; | |
const size = data.length; | |
const keyBytes = keys.map(convertStringToChunkedByteLikeArray); | |
const iterator = ~~size / 16; | |
let ret = ""; | |
for (let i = 0; i < iterator; i++) { | |
const strByte = convertHexToByte64( | |
data.substring(i * 16 + 0, i * 16 + 16) | |
); | |
const intByte = new Array(64).fill(0).map((_, i) => ~~strByte[i]); | |
let currentByte = intByte; | |
for (let i = keys.length - 1; i > -1; i--) { | |
const currentKeyByte = keyBytes[i]; | |
for (let j = currentKeyByte.length - 1; j > -1; j--) { | |
currentByte = dec(currentByte, currentKeyByte[j]); | |
} | |
} | |
ret += convertByte64ToString(currentByte); | |
} | |
return ret; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment