zcy_dev 将单文件ZUC256拆分为多文件,并封装init update final 方法 #1

Merged
zcy merged 4 commits from zcy_dev into main 2025-09-03 09:09:06 +00:00
12 changed files with 408 additions and 0 deletions
Showing only changes of commit 1b4c192180 - Show all commits

103
README.md
View File

@@ -10,3 +10,106 @@
sudo apt-get install scons
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. 打印结果并校验是否一致。
* 可直接运行验证整体流程是否正确。
---

View 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: 替换为高效批量实现(可选)
}
}
}

View 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)
? "=== 测试成功: 解密结果与明文一致 ==="
: "=== 测试失败: 解密结果与明文不一致 ===");
}
}

View 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);
}
}

View 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");
}
}

View 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;
}
}

View 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: 填入
};
}

View 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);
}
}