Files
SPlayer/electron/server/unblock/kwDES.js
2024-09-26 11:57:23 +08:00

574 lines
8.7 KiB
JavaScript

/*
Thanks to
https://github.com/XuShaohua/kwplayer/blob/master/kuwo/DES.py
https://github.com/Levi233/MusicPlayer/blob/master/app/src/main/java/com/chenhao/musicplayer/utils/crypt/KuwoDES.java
*/
const Long = (n) => {
const bN = BigInt(n);
return {
low: Number(bN),
valueOf: () => bN.valueOf(),
toString: () => bN.toString(),
not: () => Long(~bN),
isNegative: () => bN < 0,
or: (x) => Long(bN | BigInt(x)),
and: (x) => Long(bN & BigInt(x)),
xor: (x) => Long(bN ^ BigInt(x)),
equals: (x) => bN === BigInt(x),
multiply: (x) => Long(bN * BigInt(x)),
shiftLeft: (x) => Long(bN << BigInt(x)),
shiftRight: (x) => Long(bN >> BigInt(x)),
};
};
const range = (n) => Array.from(new Array(n).keys());
const power = (base, index) =>
Array(index)
.fill(null)
.reduce((result) => result.multiply(base), Long(1));
const LongArray = (...array) => array.map((n) => (n === -1 ? Long(-1, -1) : Long(n)));
// EXPANSION
const arrayE = LongArray(
31,
0,
1,
2,
3,
4,
-1,
-1,
3,
4,
5,
6,
7,
8,
-1,
-1,
7,
8,
9,
10,
11,
12,
-1,
-1,
11,
12,
13,
14,
15,
16,
-1,
-1,
15,
16,
17,
18,
19,
20,
-1,
-1,
19,
20,
21,
22,
23,
24,
-1,
-1,
23,
24,
25,
26,
27,
28,
-1,
-1,
27,
28,
29,
30,
31,
30,
-1,
-1,
);
// INITIAL_PERMUTATION
const arrayIP = LongArray(
57,
49,
41,
33,
25,
17,
9,
1,
59,
51,
43,
35,
27,
19,
11,
3,
61,
53,
45,
37,
29,
21,
13,
5,
63,
55,
47,
39,
31,
23,
15,
7,
56,
48,
40,
32,
24,
16,
8,
0,
58,
50,
42,
34,
26,
18,
10,
2,
60,
52,
44,
36,
28,
20,
12,
4,
62,
54,
46,
38,
30,
22,
14,
6,
);
// INVERSE_PERMUTATION
const arrayIP_1 = LongArray(
39,
7,
47,
15,
55,
23,
63,
31,
38,
6,
46,
14,
54,
22,
62,
30,
37,
5,
45,
13,
53,
21,
61,
29,
36,
4,
44,
12,
52,
20,
60,
28,
35,
3,
43,
11,
51,
19,
59,
27,
34,
2,
42,
10,
50,
18,
58,
26,
33,
1,
41,
9,
49,
17,
57,
25,
32,
0,
40,
8,
48,
16,
56,
24,
);
// ROTATES
const arrayLs = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1];
const arrayLsMask = LongArray(0, 0x100001, 0x300003);
const arrayMask = range(64).map((n) => power(2, n));
arrayMask[arrayMask.length - 1] = arrayMask[arrayMask.length - 1].multiply(-1);
// PERMUTATION
const arrayP = LongArray(
15,
6,
19,
20,
28,
11,
27,
16,
0,
14,
22,
25,
4,
17,
30,
9,
1,
7,
23,
13,
31,
26,
2,
8,
18,
12,
29,
5,
21,
10,
3,
24,
);
// PERMUTED_CHOICE1
const arrayPC_1 = LongArray(
56,
48,
40,
32,
24,
16,
8,
0,
57,
49,
41,
33,
25,
17,
9,
1,
58,
50,
42,
34,
26,
18,
10,
2,
59,
51,
43,
35,
62,
54,
46,
38,
30,
22,
14,
6,
61,
53,
45,
37,
29,
21,
13,
5,
60,
52,
44,
36,
28,
20,
12,
4,
27,
19,
11,
3,
);
// PERMUTED_CHOICE2
const arrayPC_2 = LongArray(
13,
16,
10,
23,
0,
4,
-1,
-1,
2,
27,
14,
5,
20,
9,
-1,
-1,
22,
18,
11,
3,
25,
7,
-1,
-1,
15,
6,
26,
19,
12,
1,
-1,
-1,
40,
51,
30,
36,
46,
54,
-1,
-1,
29,
39,
50,
44,
32,
47,
-1,
-1,
43,
48,
38,
55,
33,
52,
-1,
-1,
45,
41,
49,
35,
28,
31,
-1,
-1,
);
const matrixNSBox = [
[
14, 4, 3, 15, 2, 13, 5, 3, 13, 14, 6, 9, 11, 2, 0, 5, 4, 1, 10, 12, 15, 6, 9, 10, 1, 8, 12, 7,
8, 11, 7, 0, 0, 15, 10, 5, 14, 4, 9, 10, 7, 8, 12, 3, 13, 1, 3, 6, 15, 12, 6, 11, 2, 9, 5, 0, 4,
2, 11, 14, 1, 7, 8, 13,
],
[
15, 0, 9, 5, 6, 10, 12, 9, 8, 7, 2, 12, 3, 13, 5, 2, 1, 14, 7, 8, 11, 4, 0, 3, 14, 11, 13, 6, 4,
1, 10, 15, 3, 13, 12, 11, 15, 3, 6, 0, 4, 10, 1, 7, 8, 4, 11, 14, 13, 8, 0, 6, 2, 15, 9, 5, 7,
1, 10, 12, 14, 2, 5, 9,
],
[
10, 13, 1, 11, 6, 8, 11, 5, 9, 4, 12, 2, 15, 3, 2, 14, 0, 6, 13, 1, 3, 15, 4, 10, 14, 9, 7, 12,
5, 0, 8, 7, 13, 1, 2, 4, 3, 6, 12, 11, 0, 13, 5, 14, 6, 8, 15, 2, 7, 10, 8, 15, 4, 9, 11, 5, 9,
0, 14, 3, 10, 7, 1, 12,
],
[
7, 10, 1, 15, 0, 12, 11, 5, 14, 9, 8, 3, 9, 7, 4, 8, 13, 6, 2, 1, 6, 11, 12, 2, 3, 0, 5, 14, 10,
13, 15, 4, 13, 3, 4, 9, 6, 10, 1, 12, 11, 0, 2, 5, 0, 13, 14, 2, 8, 15, 7, 4, 15, 1, 10, 7, 5,
6, 12, 11, 3, 8, 9, 14,
],
[
2, 4, 8, 15, 7, 10, 13, 6, 4, 1, 3, 12, 11, 7, 14, 0, 12, 2, 5, 9, 10, 13, 0, 3, 1, 11, 15, 5,
6, 8, 9, 14, 14, 11, 5, 6, 4, 1, 3, 10, 2, 12, 15, 0, 13, 2, 8, 5, 11, 8, 0, 15, 7, 14, 9, 4,
12, 7, 10, 9, 1, 13, 6, 3,
],
[
12, 9, 0, 7, 9, 2, 14, 1, 10, 15, 3, 4, 6, 12, 5, 11, 1, 14, 13, 0, 2, 8, 7, 13, 15, 5, 4, 10,
8, 3, 11, 6, 10, 4, 6, 11, 7, 9, 0, 6, 4, 2, 13, 1, 9, 15, 3, 8, 15, 3, 1, 14, 12, 5, 11, 0, 2,
12, 14, 7, 5, 10, 8, 13,
],
[
4, 1, 3, 10, 15, 12, 5, 0, 2, 11, 9, 6, 8, 7, 6, 9, 11, 4, 12, 15, 0, 3, 10, 5, 14, 13, 7, 8,
13, 14, 1, 2, 13, 6, 14, 9, 4, 1, 2, 14, 11, 13, 5, 0, 1, 10, 8, 3, 0, 11, 3, 5, 9, 4, 15, 2, 7,
8, 12, 15, 10, 7, 6, 12,
],
[
13, 7, 10, 0, 6, 9, 5, 15, 8, 4, 3, 10, 11, 14, 12, 5, 2, 11, 9, 6, 15, 12, 0, 3, 4, 1, 14, 13,
1, 2, 7, 8, 1, 2, 12, 15, 10, 4, 0, 3, 13, 14, 6, 9, 7, 8, 9, 6, 15, 1, 5, 12, 3, 10, 14, 5, 8,
7, 11, 0, 4, 13, 2, 11,
],
];
const bitTransform = (arrInt, n, l) => {
// int[], int, long : long
let l2 = Long(0);
range(n).forEach((i) => {
if (arrInt[i].isNegative() || l.and(arrayMask[arrInt[i].low]).equals(0)) return;
l2 = l2.or(arrayMask[i]);
});
return l2;
};
const DES64 = (longs, l) => {
const pR = range(8).map(() => Long(0));
const pSource = [Long(0), Long(0)];
let L = Long(0);
let R = Long(0);
let out = bitTransform(arrayIP, 64, l);
pSource[0] = out.and(0xffffffff);
pSource[1] = out.and(-4294967296).shiftRight(32);
range(16).forEach((i) => {
let SOut = Long(0);
R = Long(pSource[1]);
R = bitTransform(arrayE, 64, R);
R = R.xor(longs[i]);
range(8).forEach((j) => {
pR[j] = R.shiftRight(j * 8).and(255);
});
range(8)
.reverse()
.forEach((sbi) => {
SOut = SOut.shiftLeft(4).or(matrixNSBox[sbi][pR[sbi]]);
});
R = bitTransform(arrayP, 32, SOut);
L = Long(pSource[0]);
pSource[0] = Long(pSource[1]);
pSource[1] = L.xor(R);
});
pSource.reverse();
out = pSource[1].shiftLeft(32).and(-4294967296).or(pSource[0].and(0xffffffff));
out = bitTransform(arrayIP_1, 64, out);
return out;
};
const subKeys = (l, longs, n) => {
// long, long[], int
let l2 = bitTransform(arrayPC_1, 56, l);
range(16).forEach((i) => {
l2 = l2
.and(arrayLsMask[arrayLs[i]])
.shiftLeft(28 - arrayLs[i])
.or(l2.and(arrayLsMask[arrayLs[i]].not()).shiftRight(arrayLs[i]));
longs[i] = bitTransform(arrayPC_2, 64, l2);
});
if (n === 1) {
range(8).forEach((j) => {
[longs[j], longs[15 - j]] = [longs[15 - j], longs[j]];
});
}
};
const crypt = (msg, key, mode) => {
// 处理密钥块
let l = Long(0);
range(8).forEach((i) => {
l = Long(key[i])
.shiftLeft(i * 8)
.or(l);
});
const j = Math.floor(msg.length / 8);
// arrLong1 存放的是转换后的密钥块, 在解密时只需要把这个密钥块反转就行了
const arrLong1 = range(16).map(() => Long(0));
subKeys(l, arrLong1, mode);
// arrLong2 存放的是前部分的明文
const arrLong2 = range(j).map(() => Long(0));
range(j).forEach((m) => {
range(8).forEach((n) => {
arrLong2[m] = Long(msg[n + m * 8])
.shiftLeft(n * 8)
.or(arrLong2[m]);
});
});
// 用于存放密文
const arrLong3 = range(Math.floor((1 + 8 * (j + 1)) / 8)).map(() => Long(0));
// 计算前部的数据块(除了最后一部分)
range(j).forEach((i1) => {
arrLong3[i1] = DES64(arrLong1, arrLong2[i1]);
});
// 保存多出来的字节
const arrByte1 = msg.slice(j * 8);
let l2 = Long(0);
range(msg.length % 8).forEach((i1) => {
l2 = Long(arrByte1[i1])
.shiftLeft(i1 * 8)
.or(l2);
});
// 计算多出的那一位(最后一位)
if (arrByte1.length || mode === 0) arrLong3[j] = DES64(arrLong1, l2); // 解密不需要
// 将密文转为字节型
const arrByte2 = range(8 * arrLong3.length).map(() => 0);
let i4 = 0;
arrLong3.forEach((l3) => {
range(8).forEach((i6) => {
arrByte2[i4] = l3.shiftRight(i6 * 8).and(255).low;
i4 += 1;
});
});
return Buffer.from(arrByte2);
};
const SECRET_KEY = Buffer.from("ylzsxkwm");
export const encrypt = (msg) => crypt(msg, SECRET_KEY, 0);
export const decrypt = (msg) => crypt(msg, SECRET_KEY, 1);
export const encryptQuery = (query) => encrypt(Buffer.from(query)).toString("base64");