框架初始化
This commit is contained in:
103
README.md
103
README.md
@@ -10,3 +10,106 @@
|
|||||||
sudo apt-get install scons
|
sudo apt-get install scons
|
||||||
sudo apt-get install build-essential
|
sudo apt-get install build-essential
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ZUC-256 Java 实现框架说明
|
||||||
|
|
||||||
|
本工程提供了一个 **分层、模块化的 ZUC-256 流密码算法框架**,按照 C 参考实现逻辑翻译为 Java 版本,便于后续在 JavaCard 环境中移植。
|
||||||
|
|
||||||
|
## 代码结构
|
||||||
|
|
||||||
|
```
|
||||||
|
com/iii/dragonstream/
|
||||||
|
│
|
||||||
|
├── Zuc256Tables.java // 常量表(S盒、D数组)
|
||||||
|
├── Zuc256State.java // 内部状态(LFSR、R1、R2)
|
||||||
|
├── Zuc256Util.java // 工具类(U32转换、位运算、线性变换、打印)
|
||||||
|
├── Zuc256Core.java // 算法核心(初始化、密钥字生成、密钥流生成)
|
||||||
|
├── Zuc256EncryptCtx.java // 加解密上下文(流密码分段处理)
|
||||||
|
├── Zuc256MacCtx.java // MAC 上下文骨架(EIA3 类似流程)
|
||||||
|
└── Zuc256Demo.java // 演示主程序(明文→加密→解密→验证)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 模块说明
|
||||||
|
|
||||||
|
### 1. `Zuc256Tables`
|
||||||
|
|
||||||
|
* 定义算法用到的 **S0/S1 S盒** 和 **常量数组 D**。
|
||||||
|
* 这些表与 C 代码保持一一对应,只是存储在 Java 的 `static final int[]` 或 `int[][]` 中。
|
||||||
|
* **填表后即可使用**,不涉及逻辑。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. `Zuc256State`
|
||||||
|
|
||||||
|
* 表示 ZUC-256 的 **运行时状态**。
|
||||||
|
* 包含:
|
||||||
|
|
||||||
|
* `lfsr[16]`:16 个 31bit LFSR 元素(用 int 保存,低 31 位有效);
|
||||||
|
* `r1, r2`:两个工作寄存器。
|
||||||
|
* 提供 `reset()` 方法清零。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. `Zuc256Util`
|
||||||
|
|
||||||
|
* **通用工具函数集合**:
|
||||||
|
|
||||||
|
* `getU32` / `putU32`:字节数组与 32bit 整数互转(大端);
|
||||||
|
* `add31`, `rot31`, `rot32`:位运算工具;
|
||||||
|
* `L1`, `L2`:线性变换骨架;
|
||||||
|
* `makeU31`, `makeU32`:拼接整数;
|
||||||
|
* `extractIv`:25B → 23B IV 转换(按标准规则实现);
|
||||||
|
* `printHex`:调试用十六进制打印。
|
||||||
|
* **注意**:JavaCard 环境中可去掉 `printHex`,避免额外依赖。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. `Zuc256Core`
|
||||||
|
|
||||||
|
* **算法内核**:
|
||||||
|
|
||||||
|
* `init`:根据 Key+IV 初始化状态(LFSR、R1/R2、预运行若干轮);
|
||||||
|
* `generateKeyword`:生成单个 32bit 密钥字;
|
||||||
|
* `generateKeystream`:批量生成密钥流。
|
||||||
|
* 该类仅依赖 `Zuc256State` 和 `Zuc256Tables`,是核心逻辑的承载处。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. `Zuc256EncryptCtx`
|
||||||
|
|
||||||
|
* **流密码上下文**,封装加解密 API:
|
||||||
|
|
||||||
|
* `init`:初始化状态;
|
||||||
|
* `update`:分段处理数据流,异或密钥流;
|
||||||
|
* `finish`:结束处理(流密码一般为空实现);
|
||||||
|
* `crypt`:一次性便利方法。
|
||||||
|
* 支持就地加解密,`in` 和 `out` 可相同。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. `Zuc256MacCtx`
|
||||||
|
|
||||||
|
* **MAC 骨架**(对应 ZUC-EIA3)。
|
||||||
|
* 包含:
|
||||||
|
|
||||||
|
* `init`:初始化并设置 MAC 长度;
|
||||||
|
* `update`:累积输入数据;
|
||||||
|
* `finish`:输出认证标签。
|
||||||
|
* 暂未实现细节,留空位便于后续扩展。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 7. `Zuc256Demo`
|
||||||
|
|
||||||
|
* **演示主程序**:完整展示 ZUC-256 加密/解密流程:
|
||||||
|
|
||||||
|
1. 准备明文、Key、IV;
|
||||||
|
2. 初始化状态,加密生成密文;
|
||||||
|
3. 重新初始化状态,解密得到明文;
|
||||||
|
4. 打印结果并校验是否一致。
|
||||||
|
* 可直接运行验证整体流程是否正确。
|
||||||
|
|
||||||
|
---
|
||||||
|
|||||||
35
src/com/zuc/zuc256/Zuc256Core.java
Normal file
35
src/com/zuc/zuc256/Zuc256Core.java
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package com.zuc.zuc256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZUC-256 核心:状态初始化、密钥字生成、密钥流生成。
|
||||||
|
* 仅保留对外 API 与内部步骤骨架,细节待填。
|
||||||
|
*/
|
||||||
|
public final class Zuc256Core {
|
||||||
|
|
||||||
|
private Zuc256Core() {}
|
||||||
|
|
||||||
|
/** 初始化状态(Key + IV) */
|
||||||
|
public static void init(Zuc256State st, byte[] key32, byte[] ivN) {
|
||||||
|
// TODO: 1) 按表和 key/iv 装载 LFSR 初值
|
||||||
|
// TODO: 2) 置 R1/R2
|
||||||
|
// TODO: 3) 预运行若干轮
|
||||||
|
throw new UnsupportedOperationException("TODO: init");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 生成单个 32bit 密钥字 */
|
||||||
|
public static int generateKeyword(Zuc256State st) {
|
||||||
|
// TODO: 1) BitReconstruction
|
||||||
|
// TODO: 2) 非线性变换 F -> W
|
||||||
|
// TODO: 3) LFSR 下一步(with/without carry 按标准)
|
||||||
|
// TODO: 4) 输出 W ⊕ X(??)(依实现)
|
||||||
|
throw new UnsupportedOperationException("TODO: generateKeyword");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 生成 nwords 个 32bit 密钥字到 ks[] */
|
||||||
|
public static void generateKeystream(Zuc256State st, int nwords, int[] ks) {
|
||||||
|
for (int i = 0; i < nwords; i++) {
|
||||||
|
ks[i] = generateKeyword(st); // TODO: 替换为高效批量实现(可选)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
51
src/com/zuc/zuc256/Zuc256Demo.java
Normal file
51
src/com/zuc/zuc256/Zuc256Demo.java
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package com.zuc.zuc256;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 演示主函数:保持与你的单文件示例一致的调用路径。
|
||||||
|
* 说明:核心函数仍未实现,运行会抛出 UnsupportedOperationException。
|
||||||
|
*/
|
||||||
|
public final class Zuc256Demo {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// 1. 明文
|
||||||
|
byte[] plaintext = "ZUC256对称加解密测试:1234567890".getBytes(StandardCharsets.UTF_8);
|
||||||
|
System.out.println("明文: " + new String(plaintext, StandardCharsets.UTF_8));
|
||||||
|
Zuc256Util.printHex("明文(十六进制)", plaintext, plaintext.length);
|
||||||
|
|
||||||
|
// 2. 密钥(32字节ASCII)
|
||||||
|
byte[] key = "0123456789abcdef0123456789abcdef".getBytes(StandardCharsets.US_ASCII);
|
||||||
|
Zuc256Util.printHex("密钥", key, key.length);
|
||||||
|
|
||||||
|
// 3. 初始向量(25字节ASCII) -> 提取 23 字节
|
||||||
|
byte[] inputIv25Byte = "0123456789abcdefg01234567".getBytes(StandardCharsets.US_ASCII);
|
||||||
|
byte[] iv = new byte[23];
|
||||||
|
// TODO: 按你的 C 规则提取
|
||||||
|
// Zuc256Util.extractIv(inputIv25Byte, iv);
|
||||||
|
Zuc256Util.printHex("提取后的IV(占位)", iv, iv.length);
|
||||||
|
|
||||||
|
// 4. 加密/解密缓冲区
|
||||||
|
byte[] ciphertext = new byte[plaintext.length];
|
||||||
|
byte[] decrypted = new byte[plaintext.length];
|
||||||
|
|
||||||
|
// 5. 加密
|
||||||
|
Zuc256EncryptCtx enc = new Zuc256EncryptCtx();
|
||||||
|
enc.init(key, iv);
|
||||||
|
enc.update(plaintext, 0, plaintext.length, ciphertext, 0);
|
||||||
|
Zuc256Util.printHex("密文", ciphertext, ciphertext.length);
|
||||||
|
|
||||||
|
// 6. 解密(重新初始化)
|
||||||
|
Zuc256EncryptCtx dec = new Zuc256EncryptCtx();
|
||||||
|
dec.init(key, iv);
|
||||||
|
dec.update(ciphertext, 0, ciphertext.length, decrypted, 0);
|
||||||
|
Zuc256Util.printHex("解密后", decrypted, decrypted.length);
|
||||||
|
System.out.println("解密文本: " + new String(decrypted, StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
// 7. 验证
|
||||||
|
System.out.println(Arrays.equals(plaintext, decrypted)
|
||||||
|
? "=== 测试成功: 解密结果与明文一致 ==="
|
||||||
|
: "=== 测试失败: 解密结果与明文不一致 ===");
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/com/zuc/zuc256/Zuc256EncryptCtx.java
Normal file
42
src/com/zuc/zuc256/Zuc256EncryptCtx.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package com.zuc.zuc256;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分段加/解密上下文(流密码:同一流程)。
|
||||||
|
* 注意:JavaCard 上尽量复用缓冲,避免额外分配。
|
||||||
|
*/
|
||||||
|
public final class Zuc256EncryptCtx {
|
||||||
|
private final Zuc256State st = new Zuc256State();
|
||||||
|
|
||||||
|
// 流水寄存(可选):缓存当前 32bit 密钥字与已用字节数
|
||||||
|
private int keystreamWord;
|
||||||
|
private int usedBytes;
|
||||||
|
|
||||||
|
public void init(byte[] key32, byte[] iv) {
|
||||||
|
Arrays.fill(st.lfsr, 0);
|
||||||
|
st.r1 = st.r2 = 0;
|
||||||
|
usedBytes = 4; // 令首次进入 update() 时强制拉取新字
|
||||||
|
Zuc256Core.init(st, key32, iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分段处理:in/out 可同缓冲(就地异或)。
|
||||||
|
*/
|
||||||
|
public void update(byte[] in, int inOff, int inLen, byte[] out, int outOff) {
|
||||||
|
// TODO: 逐字节与 keystreamWord 异或,4 字节耗尽后生成下一字
|
||||||
|
throw new UnsupportedOperationException("TODO: update");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finish(byte[] out, int outOff) {
|
||||||
|
// 流密码无填充;如需 MAC/尾处理,放到 MAC 上下文中
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 一次性处理(便利方法) */
|
||||||
|
public static void crypt(byte[] key32, byte[] iv, byte[] in, int inOff, int inLen, byte[] out, int outOff) {
|
||||||
|
Zuc256EncryptCtx ctx = new Zuc256EncryptCtx();
|
||||||
|
ctx.init(key32, iv);
|
||||||
|
ctx.update(in, inOff, inLen, out, outOff);
|
||||||
|
ctx.finish(out, outOff + inLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/com/zuc/zuc256/Zuc256MacCtx.java
Normal file
29
src/com/zuc/zuc256/Zuc256MacCtx.java
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package com.zuc.zuc256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MAC 上下文(可选:ZUC-256-EIA3 类似流程)
|
||||||
|
* 这里只给出骨架,按你的 C 代码把细节补齐。
|
||||||
|
*/
|
||||||
|
public final class Zuc256MacCtx {
|
||||||
|
private final Zuc256State st = new Zuc256State();
|
||||||
|
private int macBits; // 32/64/128...
|
||||||
|
private int acc; // 累加器/寄存器,视实现调整
|
||||||
|
|
||||||
|
public void init(byte[] key32, byte[] iv, int macBits) {
|
||||||
|
this.macBits = macBits;
|
||||||
|
this.acc = 0;
|
||||||
|
Zuc256Core.init(st, key32, iv);
|
||||||
|
// TODO: 若 MAC 需特殊 IV/派生,按 C 版本处理
|
||||||
|
throw new UnsupportedOperationException("TODO: MAC init details");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(byte[] data, int off, int len) {
|
||||||
|
// TODO: 消耗比特/字节流并累积 acc
|
||||||
|
throw new UnsupportedOperationException("TODO: MAC update");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finish(byte[] tag, int tagOff) {
|
||||||
|
// TODO: 输出 macBits 位标签到 tag[]
|
||||||
|
throw new UnsupportedOperationException("TODO: MAC finish");
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/com/zuc/zuc256/Zuc256State.java
Normal file
16
src/com/zuc/zuc256/Zuc256State.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package com.zuc.zuc256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZUC 内部状态:LFSR(16x31bit) + R1/R2。
|
||||||
|
* Java 中用 int 保存(仅低 31 位有效)。
|
||||||
|
*/
|
||||||
|
public final class Zuc256State {
|
||||||
|
public final int[] lfsr = new int[16]; // 线性反馈移位寄存器,31bit/项
|
||||||
|
public int r1; // 32bit working register
|
||||||
|
public int r2; // 32bit working register
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
for (int i = 0; i < lfsr.length; i++) lfsr[i] = 0;
|
||||||
|
r1 = 0; r2 = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/com/zuc/zuc256/Zuc256Tables.java
Normal file
28
src/com/zuc/zuc256/Zuc256Tables.java
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package com.zuc.zuc256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 常量表:S0/S1 与 ZUC256_D。
|
||||||
|
* 注意:JavaCard 目标环境建议将表定义为 static final 数组,按 int/short 存放。
|
||||||
|
* TODO: 将 C 版本中的表逐项拷入。
|
||||||
|
*/
|
||||||
|
public final class Zuc256Tables {
|
||||||
|
|
||||||
|
private Zuc256Tables() {}
|
||||||
|
|
||||||
|
// S盒:S0, S1
|
||||||
|
public static final int[] S0 = {
|
||||||
|
// TODO: 填入 256 项
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final int[] S1 = {
|
||||||
|
// TODO: 填入 256 项
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 常量数组 D(按标准/实现定义)
|
||||||
|
* 说明:根据你的 C 代码布局选择 int[?][?] 或 int[] 线性展开。
|
||||||
|
*/
|
||||||
|
public static final int[][] ZUC256_D = {
|
||||||
|
// TODO: 填入
|
||||||
|
};
|
||||||
|
}
|
||||||
104
src/com/zuc/zuc256/Zuc256Util.java
Normal file
104
src/com/zuc/zuc256/Zuc256Util.java
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
package com.zuc.zuc256;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 辅助工具:装载/存储、位运算、线性变换、打印等。
|
||||||
|
* 默认使用大端序(与大多数参考实现一致),如需小端请统一替换。
|
||||||
|
*/
|
||||||
|
public final class Zuc256Util {
|
||||||
|
|
||||||
|
private Zuc256Util() {}
|
||||||
|
|
||||||
|
// === Byte <-> U32 ===
|
||||||
|
|
||||||
|
/** 从 p[offset..offset+3] 读 32bit(大端) */
|
||||||
|
public static int getU32(byte[] p, int offset) {
|
||||||
|
// TODO: 如需小端,改为反序装载
|
||||||
|
int v = ((p[offset] & 0xFF) << 24)
|
||||||
|
| ((p[offset + 1] & 0xFF) << 16)
|
||||||
|
| ((p[offset + 2] & 0xFF) << 8)
|
||||||
|
| (p[offset + 3] & 0xFF);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 将 v 写入 p[offset..offset+3](大端) */
|
||||||
|
public static void putU32(byte[] p, int offset, int v) {
|
||||||
|
// TODO: 如需小端,改为反序存储
|
||||||
|
p[offset] = (byte)((v >>> 24) & 0xFF);
|
||||||
|
p[offset + 1] = (byte)((v >>> 16) & 0xFF);
|
||||||
|
p[offset + 2] = (byte)((v >>> 8) & 0xFF);
|
||||||
|
p[offset + 3] = (byte)(v & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// === 31/32 位运算 ===
|
||||||
|
|
||||||
|
/** 31 位加法(丢弃第 32 位),仅保留低 31 位 */
|
||||||
|
public static int add31(int a, int b) {
|
||||||
|
// TODO: 对齐 C 的具体实现细节(是否有进位回注)
|
||||||
|
return (a + b) & 0x7FFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 31 位循环左移(仅低 31 位参与) */
|
||||||
|
public static int rot31(int a, int k) {
|
||||||
|
int x = a & 0x7FFFFFFF;
|
||||||
|
k %= 31;
|
||||||
|
return ((x << k) | (x >>> (31 - k))) & 0x7FFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 32 位循环左移 */
|
||||||
|
public static int rot32(int a, int k) {
|
||||||
|
int s = k & 31;
|
||||||
|
return (a << s) | (a >>> (32 - s));
|
||||||
|
}
|
||||||
|
|
||||||
|
// === 线性变换(与标准一致) ===
|
||||||
|
|
||||||
|
public static int L1(int x) {
|
||||||
|
// TODO: 填入 L1 具体移位与异或
|
||||||
|
throw new UnsupportedOperationException("TODO: L1");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int L2(int x) {
|
||||||
|
// TODO: 填入 L2 具体移位与异或
|
||||||
|
throw new UnsupportedOperationException("TODO: L2");
|
||||||
|
}
|
||||||
|
|
||||||
|
// === 组装整数 ===
|
||||||
|
|
||||||
|
/** makeU31: 由 4 个 8bit 组为 31bit 值(按标准约定截断/掩码) */
|
||||||
|
public static int makeU31(int a, int b, int c, int d) {
|
||||||
|
// TODO: 对齐 C 代码的拼接与掩码方式
|
||||||
|
int v = ((a & 0xFF) << 23)
|
||||||
|
| ((b & 0xFF) << 15)
|
||||||
|
| ((c & 0xFF) << 7)
|
||||||
|
| ((d & 0x7F));
|
||||||
|
return v & 0x7FFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** makeU32: 由 4 个 8bit 组为 32bit 值(大端) */
|
||||||
|
public static int makeU32(int a, int b, int c, int d) {
|
||||||
|
return ((a & 0xFF) << 24)
|
||||||
|
| ((b & 0xFF) << 16)
|
||||||
|
| ((c & 0xFF) << 8)
|
||||||
|
| (d & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// === IV 处理与打印 ===
|
||||||
|
|
||||||
|
/** 将 25 字节输入提取/压缩为 23 字节 IV(按你的 C 规则) */
|
||||||
|
public static void extractIv(byte[] input25Byte, byte[] output23Byte) {
|
||||||
|
// TODO: 按 C 逻辑实现
|
||||||
|
throw new UnsupportedOperationException("TODO: extractIv");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 打印十六进制(调试用,生产/JC 环境可移除) */
|
||||||
|
public static void printHex(String label, byte[] data, int len) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
sb.append(String.format(Locale.ROOT, "%02X", data[i]));
|
||||||
|
if (i + 1 < len) sb.append(i % 16 == 15 ? "\n" : " ");
|
||||||
|
}
|
||||||
|
System.out.println(label + ":\n" + sb);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user