Skip to content

Commit 6d169a6

Browse files
committed
Fix compression logic.
Update docs.
1 parent fd6caf6 commit 6d169a6

7 files changed

Lines changed: 66 additions & 34 deletions

File tree

docs/.vitepress/config.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ export default withMermaid({
5454
{ text: "Demo", link: "https://abra.js.org" },
5555
],
5656

57+
outline: { level: [2, 3] },
58+
5759
sidebar: [
5860
{ text: "快速开始", link: "/document/quick-start.md" },
5961
{ text: "功能对比", link: "/document/comparison.md" },
@@ -94,11 +96,11 @@ export default withMermaid({
9496
{ text: "Demo页", link: "https://abra.js.org" },
9597
{ text: "GitHub仓库", link: "https://github.com/SheepChef/Abracadabra" },
9698
],
99+
97100
logo: "/logo.png",
98101
socialLinks: [
99102
{ icon: "github", link: "https://github.com/SheepChef/Abracadabra" },
100103
],
101-
102104
// 文章翻页
103105
docFooter: {
104106
prev: "上一篇",

docs/document/flexible.md

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
灵活分段传输 是魔曰针对超长文本或二进制文件传输设计的核心扩展机制。
44

5-
## 实用功能与应用场景
5+
## 功能
66

77
在实际使用中,灵活分段传输能提供以下关键的实用体验:
88

@@ -11,20 +11,24 @@
1111
- **消除字频统计特征**:超长密文如果单条转换并大段发送,容易暴露句式重复率或呈现字频特征。分段传输使用一维值噪声(`ValueNoise1D`)对数据进行动态长度切片,允许用户分开甚至跨平台发送密文,可有效减弱长文本在统计学上的特征关联。
1212
- **全有或全无保护(AONT)**:开启 AONT 后,密文分段深度纠缠。解密时必须集齐 100% 的分段,即便只缺失任意一个分段,也无法还原出明文的任何局部片段,有效防止信息局部泄露。
1313

14-
## 核心实现机制
14+
## 实现机制
1515

1616
为了支持分批分发与无序重组,魔曰在底层实现了四项核心机制:
1717

18-
### 一维值噪声切分
18+
### 噪声分段
1919

2020
程序使用一维值噪声(`ValueNoise1D`)与余弦平滑插值,在设定的上下限区间内平滑、自适应地产生每一段的分段大小。这种长度分布相比纯随机数更具平滑度,使生成的古文段落长短过渡更加自然。
2121

22-
### AONT(全有或全无)变换
22+
### AONT
2323

2424
在分段加密前,程序采用基于 MGF1-SHA256 的 4 轮 Feistel 结构操作,对明文进行全有或全无变换(AONT)。
2525

2626
此过程使得所有数据字节彼此纠缠,任何一点数据被篡改或者缺失都会在解密时引发雪崩效应,导致整体数据不可读。此过程是密码学安全的。
2727

28+
启用 AONT 时,系统将在 AONT 执行前对全文进行整体压缩;禁用时,则对各数据段进行独立压缩。通常整体压缩的效率优于独立压缩。所用压缩算法与常规加密模式一致。
29+
30+
AONT 默认开启,除非用户主动关闭。
31+
2832
::: tip 这意味着什么?
2933

3034
开启 AONT 意味着,缺失/修改任意一个或多个段落的密文,都会导致整条消息完全无法解密,即**全有或全无**。接收方必须完整地接收到某条消息的**所有**密文段落,才能解密该条消息,否则完全无法解密。
@@ -37,34 +41,38 @@
3741

3842
> Luby, Michael; Rackoff, Charles (April 1988), "How to Construct Pseudorandom Permutations from Pseudorandom Functions", SIAM Journal on Computing, 17 (2): 373–386, doi:10.1137/0217022, ISSN 0097-5397.
3943
40-
### 固定 10 字符标头
44+
### 标头
4145

4246
每个加密后的分段 Base64 数据中,都会被随机插入一个固定长度为 10 字符的标头,格式为 `... /=xxxxxxxx ...`
4347

4448
- `"/="` 为灵活分段的魔数标识。
45-
- 后续 8 字符(48 bits)承载经主密钥 CTR 局部混淆的元数据:包含用于定位结束位置以重置转轮(`RoundReset`)的 `lengthToBoundary` (9 bits)、局部 `iv` (14 bits)、`messageID` (12 bits)、`SerialNumber` (12 bits) 和 AONT 状态。
49+
- 后续 8 字符(48 bits)承载经主密钥 CTR 加密的元数据:包含用于定位结束位置以重置转轮(`RoundReset`)的 `lengthToBoundary` (9 bits)、局部 `iv` (14 bits)、`messageID` (12 bits)、`SerialNumber` (12 bits) 和 AONT 状态。
50+
51+
由于标头被加密,且在随机位置插入,其不会引入任何额外的密文特征。
4652

47-
### 转轮状态隔离与排序还原
53+
### 混合解密
54+
55+
用户可将多个密文消息混在一起解密,前提是它们均启用了灵活传输,且都使用同一个密钥加密。
4856

4957
解密时,解映射器通过 `lengthToBoundary` 精确识别出当前分段的边界,在分段交界处重置三重转轮的状态以避免跨段状态污染。随后,按照 MessageID 归类,并在同一消息下基于 SerialNumber 升序排列,合并拼接后执行 DeAONT 与解密。
5058

5159
::: tip 提示
5260

53-
当一次性导入多个属于不同消息(即 `MessageID` 不同)的密文段落进行合并解密时,**所有消息的加密密码必须保持一致**
61+
当一次性导入多个属于不同消息(即 `MessageID` 不同)的密文段落进行合并解密时,**所有消息必须均启用了灵活分段传输,且加密密码必须保持一致**
5462

55-
由于解密函数在单次运行中仅接受单一密钥参数,若各消息的密码不同,将无法在同一次调用中成功解密。
63+
由于解密函数在单次运行中仅接受单一密钥参数,若各消息的密码不同,或未携带分段加密标头,将无法在同一次调用中成功解密。
5664

5765
:::
5866

59-
::: warning 警告
67+
::: warning ID 碰撞
6068

6169
单条消息分段传输的分段数量上限为 4096 段。
6270

63-
同时,两条本应是不同 ID 的消息,有 1/4096 (0.024%) 的概率发生 `MessageID` 碰撞。一旦发生 ID 碰撞,将无法将这两条 ID 相同的消息混在一起进行合并解密。
71+
两条本应是不同 ID 的消息,有 1/4096 (0.024%) 的概率发生 `MessageID` 碰撞。一旦发生 ID 碰撞,将无法将这两条 ID 相同的消息混在一起进行合并解密。
6472

6573
:::
6674

67-
## 核心配置参数
75+
## 配置参数
6876

6977
在调用 `WenyanInput` 加密时,可在配置项中传入 `FlexibleTransfer` 的相关参数:
7078

@@ -81,9 +89,19 @@
8189

8290
:::
8391

84-
## 灵活分段传输流程
92+
::: warning 限制
93+
94+
在处理不同长度的数据时,可接受的每段字节数量上下限也有所不同。
95+
96+
所有**压缩后**长度在 40KB 以内的数据均可使用最低下限(10 字节),若压缩后数据长度 X 大于 40KB,则给定的每段字节数量下限 N 必须满足 `4096 * N >= X`,否则程序将会报错。
97+
98+
分段灵活传输能接受的最大数据长度为 1520KB(1.48MB),若压缩后数据长度大于此上限,程序也将报错。
99+
100+
:::
101+
102+
## 流程
85103

86-
### 加密与分段流程
104+
### 加密与分段
87105

88106
```mermaid
89107
flowchart TD
@@ -105,7 +123,7 @@ flowchart TD
105123
LoopNext -- 是 --> Output[输出多段文言文密文]
106124
```
107125

108-
### 解密与重组流程
126+
### 解密与重组
109127

110128
```mermaid
111129
flowchart TD

docs/document/js-deploy.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ let Abra = new Abracadabra(InputMode, OutputMode);
4444
使用`Uint8Array`作为输入/输出方式,魔曰可以加解密任意二进制(图片/视频/任何文件),但是不推荐这么做。
4545
:::
4646

47-
### WenyanInput() 文言仿真加解密函数
47+
### WenyanInput() 文言仿真
4848

4949
`WenyanInput()` 函数用来对数据执行文言文仿真加解密。
5050

@@ -230,7 +230,7 @@ Abra.WenyanInput(TestTemp, "DECRYPT", "ABRACADABRA", null, {
230230

231231
在无错误的情况下, `WenyanInput()` 函数的返回值通常是 `0`
232232

233-
### OldInput() 传统加密函数
233+
### OldInput() 传统加密
234234

235235
::: warning 已终止支持
236236

@@ -277,7 +277,7 @@ Abra.OldInput(input, mode, key, q);
277277

278278
在无错误的情况下, `OldInput()` 函数的返回值通常是 `0`
279279

280-
### BearDecode() 熊曰解密函数
280+
### BearDecode() 熊曰解密
281281

282282
`BearDecode()` 允许用户解密熊曰密文。
283283

@@ -294,7 +294,7 @@ Abra.BearDecode(
294294
let Result = Abra.Output(); //获取输出,输出只会是字符串
295295
```
296296

297-
### Output()
297+
### Output() 输出
298298

299299
```js
300300
import { Abracadabra } from "abracadabra-cn";

docs/document/luhn-compress.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66

77
压缩管线在数据被送入 AES 加密前执行。魔曰采用双算法自适应策略,根据输入数据的大小和内容类型自动选择最优算法,以平衡压缩效率与头部开销。
88

9-
### 双算法自适应策略
9+
### 自适应压缩
1010

1111
- **Unishox2 压缩(适用于短文本 < 1024 字节)**
1212
传统的压缩算法(如 Gzip)含有较重的头部元数据,压缩极短文本时反而会导致体积膨胀。魔曰采用针对短文本优化编码的 **Unishox2** 算法。若 Unishox2 压缩后未能减小体积,程序会回落并尝试 **Gzip** 压缩。
1313
- **Gzip 压缩(适用于大文本 > 1024 字节)**
1414
对于超过 1KB 的数据,魔曰直接使用 **Gzip** 执行高压缩比的压缩。若 Gzip 压缩后未能减小体积,则输出原始未压缩数据。
1515

16-
### URL 定向字典优化
16+
### URL 字典优化
1717

1818
在短文本(Unishox2)模式下,魔曰针对常见的协议头、常用网盘域名、搜索引擎、版本控制站点及种子特征码等编排了 12 套特定的预置字典。
1919
若识别到匹配的特征链接,会使用特定字典压缩,并在压缩数据末尾附加一个标识字节(`libmark`,取值 `243~254`)和 `255` 结束符。这在加密磁力链接(推荐使用十六进制特征码)或云盘链接时,能显著提高压缩比。
@@ -67,7 +67,7 @@ flowchart TD
6767

6868
解密数据后,系统必须判断密钥是否正确以及密文是否完整。魔曰使用轻量级的 [**卢恩算法**](https://zh.wikipedia.org/zh-cn/%E5%8D%A2%E6%81%A9%E7%AE%97%E6%B3%95)(US2950048,ISO/IEC 7812-1) 对数据执行快速校验。
6969

70-
### 算法特征
70+
### 卢恩算法
7171

7272
- **极简性**:校验码仅占用 1 个字节,避免了 HMAC-SHA256(32 字节)等安全签名导致密文过长的问题。
7373
- **定位**:主要用于检测传输中的随机字符损坏或解密密码错误(检错率约为 70%)。它属于**非密码学强完整性校验**。如需对抗针对密文的主动篡改与完整性攻击,请在高级加密套件中开启 **HMAC-SHA256**

docs/document/wenyan.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
4. **语素映射与级联混淆**:按模板语法,将 Base64 字符逐个通过三重转轮混淆,并映射为对应词性的汉字,同时随机填充虚词。
1717
5. **标点与段落格式化**:在句间插入合理的标点符号或换行符,并进行标点闭合校验。
1818

19-
## 载荷分配与句式选择
19+
## 载荷分配
2020

2121
### 自适应分段
2222

@@ -34,7 +34,7 @@
3434

3535
对于单段密文,仿真器会将其总字符数均分为三份,按比例(2:6:2)分别分配给 **Begin(引入段)****Main(论述段)****End(收尾段)**。每一段都拥有一个独立的句式库,用于保证文章有合理的“起承转合”结构。
3636

37-
### 句式选择与风格过滤
37+
## 句式选择
3838

3939
对于每一段的负载量,算法的选择流程分为两个主要阶段:
4040

@@ -92,7 +92,7 @@ flowchart TD
9292
SegLoopNext -- 是 --> Output[生成完整的短句模板二维数组]
9393
```
9494

95-
## 语素映射与标点组装
95+
## 映射和标点控制
9696

9797
在选定句式序列后,程序会将所有选中的句式解析为语素(Token)数组,并使用双层循环进行遍历与替换:
9898

src/javascript/CompressionHelper.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,11 @@ function GZIP_DECOMPRESS(Data) {
109109
} catch (err) {
110110
return Data;
111111
}
112-
return DataOutput;
112+
if (DataOutput == undefined) {
113+
return Data;
114+
} else {
115+
return DataOutput;
116+
}
113117
} else {
114118
return Data;
115119
}

src/javascript/CoreHandler.js

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,10 @@ export function Enc(
250250
: [20, 80]
251251
); //重新组装一个新对象,以自动缺省未传入值
252252

253-
//提前压缩,递归时候避免重复压缩。校验码仍然保留。
254-
OriginalData = Compress(OriginalData);
253+
//有AONT的时候提前压缩,递归时候避免重复压缩。校验码仍然保留。
254+
if (AdvancedEncObj.FlexibleTransfer.UseAONT) {
255+
OriginalData = Compress(OriginalData);
256+
}
255257

256258
// 开始执行分段,分段采用余弦插值噪声
257259
let PayloadLengthArray = distributeFlexibleTransfer(
@@ -570,10 +572,13 @@ export function Dec(
570572
}
571573
//开始执行ANOT,以及最终处理
572574
if (MergedResultArray[i].UseAONT) {
573-
MergedResultArray[i] = DeAONT(MergedResultArray[i]);
575+
if (MergedResultArray[i].byteLength > 1) {
576+
MergedResultArray[i] = DeAONT(MergedResultArray[i]);
577+
}
578+
//解压缩
579+
MergedResultArray[i] = Decompress(MergedResultArray[i]);
574580
}
575-
//解压缩
576-
MergedResultArray[i] = Decompress(MergedResultArray[i]);
581+
577582
//组装最终要传回去的对象
578583
MergedResultArray[i] = new DecResultDataObj(
579584
Uint8ArrayTostring(MergedResultArray[i]),
@@ -630,8 +635,11 @@ export function Dec(
630635
TempStr2Int = Decrypt(TempStr2Int, key, AdvancedEncObj);
631636
}
632637

633-
//解压缩,仅在传入的不是FlexibleDataObj时候才允许执行。
634-
if (!(input instanceof FlexibleTransferDataObj)) {
638+
//解压缩,仅在传入的不是FlexibleDataObj时候,或者ANOT未开启的时候,才允许执行。
639+
if (
640+
!(input instanceof FlexibleTransferDataObj) ||
641+
(input instanceof FlexibleTransferDataObj && !input.UseAONT)
642+
) {
635643
TempStr2Int = Decompress(TempStr2Int);
636644
}
637645
} catch (err) {

0 commit comments

Comments
 (0)