Skip to content

Commit 9434cd6

Browse files
committed
Fix a bunch of problems about Flexible Transfer
Decryption part is WIP. Encryption part is verified.
1 parent 3dea2eb commit 9434cd6

9 files changed

Lines changed: 207 additions & 54 deletions

File tree

package-lock.json

Lines changed: 0 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
"vitest": "^3.1.2"
2727
},
2828
"dependencies": {
29-
"@lukeed/csprng": "^1.1.0",
3029
"@noble/hashes": "^2.2.0",
3130
"@otplib/plugin-base32-enc-dec": "^12.0.1",
3231
"@otplib/plugin-crypto-js": "^12.0.1",

src/javascript/CSPRNGHelper.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* 跨环境初始化密码学安全的随机数提供者 (CSPRNG)
3+
* 在模块加载时只执行一次,避免每次调用都做环境判断
4+
*/
5+
const getCryptoProvider = () => {
6+
// 1. 现代浏览器 / Deno / Bun / Node.js 19+ (Web Crypto API)
7+
if (
8+
typeof globalThis !== "undefined" &&
9+
globalThis.crypto &&
10+
typeof globalThis.crypto.getRandomValues === "function"
11+
) {
12+
return {
13+
getRandomValues: (arr) => globalThis.crypto.getRandomValues(arr),
14+
};
15+
}
16+
17+
// 2. 旧版 Node.js (CommonJS)
18+
// 使用 typeof require 避免在 Webpack/Vite 等构建工具中报错
19+
if (
20+
typeof process !== "undefined" &&
21+
process.versions &&
22+
process.versions.node &&
23+
typeof require === "function"
24+
) {
25+
try {
26+
const crypto = require("crypto");
27+
// Node.js 15+ 提供的 webcrypto 属性
28+
if (
29+
crypto.webcrypto &&
30+
typeof crypto.webcrypto.getRandomValues === "function"
31+
) {
32+
return {
33+
getRandomValues: (arr) => crypto.webcrypto.getRandomValues(arr),
34+
};
35+
}
36+
// Node.js 旧版的回退方案
37+
if (typeof crypto.randomFillSync === "function") {
38+
return {
39+
getRandomValues: (arr) => crypto.randomFillSync(arr),
40+
};
41+
}
42+
} catch (e) {
43+
// 捕获可能因构建工具导致的 require 错误
44+
}
45+
}
46+
47+
return null;
48+
};
49+
50+
const cryptoProvider = getCryptoProvider();
51+
52+
/**
53+
* 密码学安全的 0~1 浮点数生成器
54+
* 行为类似于 Math.random(),输出范围 [0, 1)
55+
*/
56+
export function secureRandom() {
57+
if (!cryptoProvider) {
58+
throw new Error("当前环境不支持密码学安全的随机数生成器 (CSPRNG)");
59+
}
60+
61+
// 生成 64 位(8字节)的随机数据
62+
const buffer = new Uint32Array(2);
63+
cryptoProvider.getRandomValues(buffer);
64+
65+
// Math.random() 需要 53 位的精度 (IEEE 754 双精度浮点数)
66+
// 我们保留第一个 32 位整数的 21 位 (buffer[0] >>> 11)
67+
// 以及第二个整数的全部 32 位 (buffer[1])
68+
// 2^21 = 2097152, 2^32 = 4294967296, 2^53 = 9007199254740992
69+
const high = buffer[0] >>> 11;
70+
const low = buffer[1];
71+
72+
// 计算公式: (high * 2^32 + low) / 2^53
73+
return (high * 4294967296 + low) / 2 ** 53;
74+
}
75+
76+
// 如果你需要同时支持 CommonJS 和 ESM 默认导出
77+
export default secureRandom;
78+
export { secureRandom as random };

src/javascript/CoreHandler.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,9 @@ export class AdvancedEncConfig {
124124
}
125125

126126
//标头,用于自动识别高级加密数据,理论上需要附加正常加密/解密时绝不可能在开头出现的Base64编码范围内字符
127-
const ADVANCED_ENC_MAGIC = "+=";
127+
export const ADVANCED_ENC_MAGIC = "+=";
128128
//标头,用于自动识别灵活传输数据
129-
const FLEXIBLE_TRANSFER_MAGIC = "=/";
129+
export const FLEXIBLE_TRANSFER_MAGIC = "=/";
130130

131131
// =/+= +=/=
132132
export class CallbackObj {
@@ -207,12 +207,14 @@ export function Enc(
207207
}
208208

209209
//开始递归,初始化递归标志
210-
AdvancedEncObj.FlexibleTransfer.isRecursion = true;
211-
AdvancedEncObj.FlexibleTransfer.RecursionSeqNum = 0;
210+
let RecursiveAdvancedEncObj = AdvancedEncObj;
211+
RecursiveAdvancedEncObj.FlexibleTransfer.isRecursion = true;
212+
RecursiveAdvancedEncObj.FlexibleTransfer.RecursionSeqNum = 0;
212213

213214
if (AdvancedEncObj.FlexibleTransfer.MessengeID == -1) {
214215
//随机消息ID
215-
AdvancedEncObj.FlexibleTransfer.MessengeID = GetRandomIndex(4096);
216+
RecursiveAdvancedEncObj.FlexibleTransfer.MessengeID =
217+
GetRandomIndex(4096);
216218
}
217219

218220
let ResultArray = new Array(SlicedDataArray.length);
@@ -221,10 +223,10 @@ export function Enc(
221223
{ output: SlicedDataArray[i] },
222224
key,
223225
WenyanConfigObj,
224-
AdvancedEncObj,
226+
RecursiveAdvancedEncObj,
225227
callback
226228
);
227-
AdvancedEncObj.FlexibleTransfer.RecursionSeqNum++;
229+
RecursiveAdvancedEncObj.FlexibleTransfer.RecursionSeqNum++;
228230
}
229231
return ResultArray;
230232
}
@@ -261,7 +263,11 @@ export function Enc(
261263
AdvancedEncObj.TOTPBaseKey !== null &&
262264
AdvancedEncObj.TOTPBaseKey !== undefined
263265
? AdvancedEncObj.TOTPBaseKey
264-
: key
266+
: key,
267+
AdvancedEncObj.FlexibleTransfer !== null &&
268+
AdvancedEncObj.FlexibleTransfer !== undefined
269+
? AdvancedEncObj.FlexibleTransfer
270+
: new FlexibleTransferConfig()
265271
);
266272
} catch (err) {
267273
//遇到错误即AdvancedEncObj是一个null或者某个不可读取属性的非法值,自动缺省

src/javascript/EncryptHelper.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
wordArrayToUint8Array,
1717
Uint8ArrayTostring,
1818
GetRandomIndex,
19+
GetSecureRandomIndex,
1920
getStep,
2021
i2osp,
2122
} from "./Misc.js";
@@ -307,8 +308,8 @@ export function Encrypt(
307308
let TempArray = null;
308309
if (!AdvancedEncObj.Enable) {
309310
//执行非高级安全模式的加密
310-
RandomBytes.push(GetRandomIndex(256));
311-
RandomBytes.push(GetRandomIndex(256));
311+
RandomBytes.push(GetSecureRandomIndex(256));
312+
RandomBytes.push(GetSecureRandomIndex(256));
312313

313314
OriginalData = AES_256_CTR_E(OriginalData, key, RandomBytes); //AES-256-CTR加密
314315

@@ -319,11 +320,11 @@ export function Encrypt(
319320
//执行高级安全模式的加密
320321
if (AdvancedEncObj.UseStrongIV) {
321322
for (let i = 0; i < 16; i++) {
322-
RandomBytes.push(GetRandomIndex(256)); //获取十六个随机数字作为完整的IV
323+
RandomBytes.push(GetSecureRandomIndex(256)); //获取十六个随机数字作为完整的IV
323324
}
324325
} else {
325-
RandomBytes.push(GetRandomIndex(256));
326-
RandomBytes.push(GetRandomIndex(256));
326+
RandomBytes.push(GetSecureRandomIndex(256));
327+
RandomBytes.push(GetSecureRandomIndex(256));
327328
}
328329

329330
OriginalData = AES_256_CTR_HMAC_SHA256_E(
@@ -446,7 +447,7 @@ export function EnAONT(Data) {
446447

447448
for (let i = 0; i < 32; i++) {
448449
//获取随机种子
449-
Seed[i] = GetRandomIndex(256);
450+
Seed[i] = GetSecureRandomIndex(256);
450451
}
451452

452453
//生成掩码,使用mgf1算法,配合SHA256

src/javascript/Misc.js

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
import { Base64 } from "js-base64";
1313
import MersenneTwister from "mersenne-twister"; //兼容性
1414
import CryptoJS from "crypto-js";
15-
import { random } from "@lukeed/csprng"; //密码学安全随机数的封装
16-
import { FlexibleTransferConfig } from "./CoreHandler";
15+
import { random } from "./CSPRNGHelper"; //密码学安全随机数的封装
16+
import { FlexibleTransferConfig, FLEXIBLE_TRANSFER_MAGIC } from "./CoreHandler";
1717

1818
const SIG_DECRYPT_JP = "桜込凪雫実沢";
1919
const SIG_DECRYPT_CN = "玚俟玊欤瞐珏";
@@ -80,8 +80,18 @@ export function GetRandomIndex(length) {
8080
// 取随机数
8181
let Rand;
8282

83+
Rand = Math.floor(MT.random() * length);
84+
85+
return Rand;
86+
}
87+
88+
export function GetSecureRandomIndex(length) {
89+
// 取随机数
90+
let Rand;
91+
Rand = Math.floor(MT.random() * length);
92+
8393
try {
84-
Rand = Math.floor((random(1).at(0) / 256) * length);
94+
Rand = Math.floor(random() * length);
8595
} catch (err) {
8696
Rand = Math.floor(MT.random() * length);
8797
}
@@ -237,13 +247,13 @@ export function packFlexibleTransferConfig(
237247
const low24 = ((ser & 0x1ff) << 15) | (aont << 14) | safeIv;
238248

239249
//将 24 位区块映射为 Uint8Array (大端序)
240-
const buffer = new Uint8Array(6);
241-
buffer[0] = (high24 >> 16) & 0xff;
242-
buffer[1] = (high24 >> 8) & 0xff;
243-
buffer[2] = high24 & 0xff;
244-
buffer[3] = (low24 >> 16) & 0xff;
245-
buffer[4] = (low24 >> 8) & 0xff;
246-
buffer[5] = low24 & 0xff;
250+
const ResultBuffer = new Uint8Array(6);
251+
ResultBuffer[0] = (high24 >> 16) & 0xff;
252+
ResultBuffer[1] = (high24 >> 8) & 0xff;
253+
ResultBuffer[2] = high24 & 0xff;
254+
ResultBuffer[3] = (low24 >> 16) & 0xff;
255+
ResultBuffer[4] = (low24 >> 8) & 0xff;
256+
ResultBuffer[5] = low24 & 0xff;
247257

248258
//加密逻辑(若传入了 KEY)
249259
if (key) {
@@ -285,15 +295,15 @@ export function packFlexibleTransferConfig(
285295
}
286296

287297
// 掩码异或,加密前 34 bits
288-
buffer[0] ^= keystream[0];
289-
buffer[1] ^= keystream[1];
290-
buffer[2] ^= keystream[2];
291-
buffer[3] ^= keystream[3];
298+
ResultBuffer[0] ^= keystream[0];
299+
ResultBuffer[1] ^= keystream[1];
300+
ResultBuffer[2] ^= keystream[2];
301+
ResultBuffer[3] ^= keystream[3];
292302
// 0xC0 = 11000000,异或高2位,保留低6位和第5字节的8位(合计 14bit IV)绝对明文
293-
buffer[4] ^= keystream[4] & 0xc0;
303+
ResultBuffer[4] ^= keystream[4] & 0xc0;
294304
}
295305

296-
return buffer;
306+
return ResultBuffer;
297307
}
298308

299309
/**
@@ -586,14 +596,18 @@ export function insertEncryptMarks(
586596
// 距离就是原字符串剩下的字符数
587597
const distanceToEnd = L - i2;
588598
// 生成 sub2 并插入
589-
const sub2 = sub2EncryptProvider(
590-
distanceToEnd,
591-
FlexibleTransferConfigObj.MessengeID,
592-
FlexibleTransferConfigObj.RecursionSeqNum,
593-
FlexibleTransferConfigObj.UseAONT,
594-
key,
595-
GetRandomIndex(16384)
596-
);
599+
const sub2 =
600+
FLEXIBLE_TRANSFER_MAGIC +
601+
Base64.fromUint8Array(
602+
sub2EncryptProvider(
603+
distanceToEnd,
604+
FlexibleTransferConfigObj.MessengeID,
605+
FlexibleTransferConfigObj.RecursionSeqNum,
606+
FlexibleTransferConfigObj.UseAONT,
607+
key,
608+
GetRandomIndex(16384)
609+
)
610+
);
597611
return originalStr.slice(0, i2) + sub2 + originalStr.slice(i2);
598612
}
599613

@@ -622,7 +636,18 @@ export function insertEncryptMarks(
622636
}
623637

624638
// Step 3: 生成并插入 sub2
625-
const sub2 = sub2EncryptProvider(distanceToEnd);
639+
const sub2 =
640+
FLEXIBLE_TRANSFER_MAGIC +
641+
Base64.fromUint8Array(
642+
sub2EncryptProvider(
643+
distanceToEnd,
644+
FlexibleTransferConfigObj.MessengeID,
645+
FlexibleTransferConfigObj.RecursionSeqNum,
646+
FlexibleTransferConfigObj.UseAONT,
647+
key,
648+
GetSecureRandomIndex(16384)
649+
)
650+
);
626651
return strAfterSub1.slice(0, i2) + sub2 + strAfterSub1.slice(i2);
627652
}
628653
}

src/javascript/main.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ export class Abracadabra {
179179

180180
/**
181181
* 魔曰 获取加密/解密后的结果
182-
* @returns {string | Uint8Array} 根据此前指定的输出类型,可能是字符串或字节数组
182+
* @returns {string | Uint8Array} 根据此前指定的输出类型,可能是字符串或字节数组;或者分段传输输出的多个结果
183183
*/
184-
Output(): string | Uint8Array;
184+
Output(): string | Uint8Array | string[] | Uint8Array[];
185185
}

src/javascript/main.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,10 @@ export class Abracadabra {
225225
throw "Null Output, please input some data at first.";
226226
}
227227
if (typeof this.#res == "object") {
228-
if (this.#output == Abracadabra.TEXT) {
228+
if (this.#output == Abracadabra.TEXT && !Array.isArray(this.#res)) {
229+
//解密结果
229230
return this.#res.output; //要输出字符串,那么直接输出字符串,解密总会有字符串
230-
} else {
231+
} else if (!Array.isArray(this.#res)) {
231232
//如果要输出UINT8
232233
if (this.#res.output_B != null) {
233234
//如果有现成的可用,直接输出现成的。
@@ -239,6 +240,28 @@ export class Abracadabra {
239240

240241
return encodedData;
241242
}
243+
} else {
244+
//分段输出的加密或者解密结果。
245+
if (this.#output == Abracadabra.TEXT) {
246+
if (typeof this.#res[0] === "string") {
247+
return this.#res;
248+
} else {
249+
// 简洁写法:实例化一次,循环解码
250+
const decoder = new TextDecoder();
251+
const strArr = this.#res.map((u8a) => decoder.decode(u8a));
252+
return strArr;
253+
}
254+
} else {
255+
//输出Uint8
256+
if (typeof this.#res[0] === "string") {
257+
// 简洁写法:实例化一次,循环解码
258+
const decoder = new TextEncoder();
259+
const U8Arr = this.#res.map((str) => decoder.encode(str));
260+
return U8Arr;
261+
} else {
262+
return this.#res;
263+
}
264+
}
242265
}
243266
} else if (typeof this.#res == "string") {
244267
//如果是字符串类型,那么就是加密结果

0 commit comments

Comments
 (0)