Skip to content

Sikesibian/MySMSys

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

基于商密算法的文件加解密工具 (MySMSys-v3)

0. 前情提要

# 作业2:基于商密算法的文件加解密工具
## 1. 基本功能
- C/C++/其它语言实现。Windows/Linux/Mac不限
- 输入一个目录和SM2公钥,递归对该文件夹下的所有文件加密、解密
- 注意保护好自己的文件,建一个测试目录,防止无法恢复
- 随机生成SM4密钥来加解密文件(需要考虑填充、模式)(密文长度为16*N, N表示填充后的分组个数)
- 输入的公钥加密SM4密钥(密文长度为97 + 16)
- 加密、解密功能分开(可以认为有两个程序,一个是加密,一个是解密)

提示:可以用两种方式表示加密后的文件:

- 一个文件的方式:文件前97+16字节是加密后的对称密钥,后面是加密后的文件内容(16*N)
- 两个文件的方式:一个文件放加密后的对称密钥97+16字节,另一个放加密后的文件内容

## 2. 高级功能
- 判断文件是加密的还是没加密的
- 能够校验解密后文件的完整性(考虑计算文件杂凑值)
- 图形化操作界面(选择文件夹、展示进度等)
- 其它

## 3. 提交要求
- 时间,2周(12月9日deadline)

1. 任务描述

一个基于中国国家商用密码标准(ShangMi Standards)构建的安全文件加解密工具。本项目旨在满足:

  • 平台:目前仅支持 Windows 操作系统(WinAPI),未来可扩展至 Linux 和 macOS;
  • 语言:C 语言;
  • 功能:递归加密和解密指定目录下的所有文件;
  • 密码算法:采用 SM2(非对称加密)、SM4(对称加密)和 SM3(杂凑算法);
  • 密码学原理:使用随机生成的 SM4 密钥对文件进行加密,并利用 SM2 公钥加密该 SM4 密钥,实现数字信封机制;
  • 文件格式:采用一个文件的方式存储加密后的数据,文件头包含加密的 SM4 密钥和初始化向量 (IV),文件体为加密后的数据块,文件尾为原始数据的 SM3 杂凑值;
  • 文件完整性校验:通过 SM3 杂凑值校验解密后文件的完整性;
  • 测试:包含单元测试和集成测试;(已基于大文件(4GB Model)和大文件夹(Aircrack-ng 1.7)完成测试
  • 用户界面:提供命令行的方式(CLI)和 Windows 原生图形界面(GUI)。

2. 项目设计思路

2.1 数字信封

  1. 会话密钥生成:每次加密生成 128-bit 随机数作为 SM4 密钥 (MK) 和 初始化向量 (IV) 。
  2. 密钥封装:使用接收者的 SM2 公钥MK 进行非对称加密,生成 113 字节的加密密钥块 (Enc_Key_Blob) 。
  3. 数据加密:使用 MKIV,采用 SM4-CBC 模式对文件明文进行加密。
  4. 完整性校验:联合原始文件文件名计算原始明文的 SM3 杂凑值,用于解密后的完整性验证。

2.2 加密文件格式 (.smcr)

文件名: 出于保护目的,加密后的物理文件名并非明文。系统计算原始文件名的 SM3 杂凑值(Hex 字符串),并追加 .smcr 后缀作为输出文件名。

  • 例如:file1.bin -> 6af9dd105859973f6665ed30e6e01cf07b0c7505ed5609ff65df1826c16847c5.smcr
  • 原始文件名被加密存储在文件体内部,解密时自动恢复。

文件体结构: 文件头 (Header)、加密的元数据 (Metadata)、加密的内容 (Body) 和 完整性校验尾部 (Tail)。

+--------------------+----------+-----------------------------------------------------------------+
| Field              | Length   | Description                                                     |
+--------------------+----------+-----------------------------------------------------------------+
| Magic Number       | 4 B      | Fixed identifier 0x52434D53 (ASCII: "SMCR")                     |
| Encrypted SM4 Key  | 113 B    | SM4 session key encrypted with SM2 public key (includes header) |
| SM4 IV             | 16 B     | Initialization Vector (IV) for SM4-CBC mode                     |
+--------------------+----------+-----------------------------------------------------------------+
| Encrypted Filename | 256 B    | Encrypted original filename (fixed 256 bytes, zero-padded)      |
+--------------------+----------+-----------------------------------------------------------------+
| Encrypted Data     | N × 16 B | File content ciphertext (PKCS#7 padding aligned)                |
+--------------------+----------+-----------------------------------------------------------------+
| SM3 Hash           | 32 B     | SM3 hash of original plaintext file (for integrity check)       |
+--------------------+----------+-----------------------------------------------------------------+

注:Encrypted SM4 Key (113 Bytes) 包含 97 字节的 SM2 加密头16 字节的加密数据,总计 113 字节;所有的加密操作(文件名和文件内容)均基于 16 字节的 SM4 分组进行对齐。

2.3 密钥文件格式

为了便于存储与传输,SM2 密钥对采用类似于 PEM 的自定义文本格式存储。密钥数据被转换为 十六进制字符串 (Hex String) 并包裹在特定的头尾标识中。

2.3.1 私钥文件 (private.key)

总长度:130 字节 (固定)

+------------------------+--------+-------------------------------------------+
| Field                  | Length | Content/Description                       |
+------------------------+--------+-------------------------------------------+
| Header                 | 29 B   | "=== SM2 PRIVATE KEY FILE ===\n"          |
+------------------------+--------+-------------------------------------------+
| Private Key Hex String | 64 B   | 32-byte private key in hex string format  |
+------------------------+--------+-------------------------------------------+
| Footer                 | 37 B   | "\n=== END OF SM2 PRIVATE KEY FILE ===\n" |
+------------------------+--------+-------------------------------------------+

示例:

=== SM2 PRIVATE KEY FILE ===
04EAFD5F92626AD634A950342FBC49F90FC95576F739CFEA36EEA0EB1AC9B207
=== END OF SM2 PRIVATE KEY FILE ===

注:最后一行末尾包含换行符。

2.3.2 公钥文件 (public.key)

总长度:196 字节 (固定)

+------------------------+--------+------------------------------------------+
| Field                  | Length | Content/Description                      |
+------------------------+--------+------------------------------------------+
| Header                 | 28 B   | "=== SM2 PUBLIC KEY FILE ===\n"          |
+------------------------+--------+------------------------------------------+
| Public Key Hex String  | 130 B  | 65-byte public key in hex string format  |
+------------------------+--------+------------------------------------------+
| Footer                 | 36 B   | "\n=== END OF SM2 PUBLIC KEY FILE ===\n" |
+------------------------+--------+------------------------------------------+

示例:

=== SM2 PUBLIC KEY FILE ===
04647F8CE4F8E832CC356023BC284F5D62EFAA64CC57BE9E5555DE7A509BBEC577385E21F3C1569869A3B0843B28D6952D5C706AAC114BA25AD244FE8B05B69F0C
=== END OF SM2 PUBLIC KEY FILE ===

注:最后一行末尾包含换行符。

3. 项目结构

smsys-v3/
├── Makefile                # 自动化构建脚本 (目标: CLI, GUI, Test) 
├── include/                # 头文件定义
│   ├── app/                # 应用层逻辑定义 (用户管理, 入口封装)
│   ├── cli/                # 命令行交互定义 (颜色宏, 帮助信息)
│   ├── crypto_sm/          # 核心加密API与数据结构定义
│   ├── file_utils/         # 文件系统操作接口
│   └── config.h            # 全局配置 (日志级别, 颜色代码) 
├── lib/                    # 外部依赖库 (sm.dll)
├── src/                    # 源代码实现
│   ├── main.c              # CLI 程序入口
│   ├── app/                # 业务调度层 (参数解析, 流程控制)
│   ├── crypto_sm/          # 加解密具体实现 (encrypt_sm.c, decrypt_sm.c)
│   ├── file_utils/         # 目录遍历与文件工具 (dir_tools.c)
│   └── gui/                # Windows GUI 实现 (GDI绘图, 消息循环) 
└── tests/                  # 单元测试与集成测试代码

4. 文件间依赖关系

       [ GUI Layer ]               [ CLI Layer ]
             |                           |
    +-----------------+         +-----------------+
    |  gui_windows.c  |         |     main.c      |
    | (Win32 API/GDI) |         |  (Entry Point)  |
    +--------+--------+         +--------+--------+
             |                           |
             |                           v
             |    +----------------------------------------------+
             |    |               src/app/app_main.c             |
             |    |        (Command Dispatcher & Logic Glue)     |
             |    +----------------------+-----------------------+
             |                           |
             +---------------------------+
             |                           |
             v                           v
    +------------------+       +--------------------+
    |   crypto_api.c   |       |   file_utils/      |
    | (High Level API) |       | (file/dir_tools.c) |
    +--------+---------+       +--------------------+
             |
             v
    +------------------+------------------+
    |   encrypt_sm.c   |   decrypt_sm.c   |
    | (Core Enc Logic) | (Core Dec Logic) |
    +--------+---------+--------+---------+
             |                  |
             v                  v
    +-------------------------------------+
    |           lib/sm.dll (sm.h)         |
    |    (SM2/SM3/SM4 Algorithm Primitives)|
    +-------------------------------------+

5. 接口设计

5.1 命令行接口 (CLI)

  • genkeypair: 生成 SM2 公私钥对。
  • encrypt <file> <pubkey>: 单文件加密。
  • decrypt <file> <prikey>: 单文件解密。
  • encrypt -r <dir> <pubkey>: 递归加密目录下所有文件。
  • decrypt -r <dir> <prikey>: 递归解密目录下所有文件。

5.2 核心 C API

crypto_sm/crypto_api.h

/* Initialization Function */
// Initialize cryptographic API
int api_init();

/* Common Functions */
// Check if file is encrypted (magic number check)
int Is_File_Encrypted(cchar* file_path);
// Display file header information + filename
void Show_Header(cchar* file_path);

/* File Encryption/Decryption Functions */
// Encrypt a file
int Encrypt_File(cchar* ipath, cchar* pk);
// Decrypt a file
int Decrypt_File(cchar* ipath, cchar* sk);
// Encrypt a file with key file
int Encrypt_File_WithKeyFile(cchar* ipath, cchar* pubkey_path);
// Decrypt a file with key file
int Decrypt_File_WithKeyFile(cchar* ipath, cchar* prikey_path);

// Progress callback function type
typedef void (*Callback)(size_t current, size_t total);

/* Directory Encryption/Decryption Functions */
// Encrypt a directory recursively
int Encrypt_Dir_Recursive(cchar* dir_path, cchar* pk, Callback progress_callback);
// Decrypt a directory recursively
int Decrypt_Dir_Recursive(cchar* dir_path, cchar* sk, Callback progress_callback);
// Encrypt a directory recursively with key file
int Encrypt_Dir_Recursive_WithKeyFile(cchar* dir_path, cchar* pubkey_path, Callback progress_callback);
// Decrypt a directory recursively with key file
int Decrypt_Dir_Recursive_WithKeyFile(cchar* dir_path, cchar* prikey_path, Callback progress_callback);

/* SM2 Key Operations */
// Generate SM2 key pair
int Generate_SM2_KeyPair();
// Generate SM2 key from existing private key
int Generate_SM2_KeyFromSk(cchar* pri_key_path);

// Load SM2 public key from file
int Load_SM2_PubKey(cchar* key_path, uchar* pk);
// Load SM2 private key from file
int Load_SM2_PriKey(cchar* key_path, uchar* sk);
// Load SM2 keys from file
int Load_SM2_Keys(cchar* key_path, uchar* pk, uchar* sk);

// Save SM2 public key to file
int Save_SM2_PubKey(cchar* key_path, uchar* pk);
// Save SM2 private key to file
int Save_SM2_PriKey(cchar* key_path, uchar* sk);
// Save SM2 keys to file
int Save_SM2_Keys(cchar* key_path, uchar* pk, uchar* sk);

app/app_main.h

/* Application Main Entry Point */
int app_main(int argc, char *argv[]);

6. 局限性

  1. 跨平台 GUI 重构:目前的 GUI 深度依赖 Win API (windows.h, commctrl.h) 。未来计划使用 Qt 或 Electron 重写,以支持 Linux/macOS。
  2. 私钥加密保护:当前私钥文件存储的是裸数据。未来考虑实现对私钥文件本身进行口令加密
  3. 并行加速:对于包含大量小文件的目录,当前的单线程 DFS 效率有提升空间。未来可引入线程池(Thread Pool)并发处理文件队列。
  4. 更多工作模式支持:当前仅支持 SM4-CBC 模式。未来可扩展支持 SM4-CTR 等多种工作模式。

7. 编译与运行

7.1 编译环境要求

  • gcc version (>=) 15.2.0 (Rev8, Built by MSYS2 project)
  • GNU Make (>=) 4.4.1
  • Windows SDK (用于 GUI 资源编译)

7.2 构建命令

# 编译所有组件 (CLI 工具, GUI 工具, 测试程序)
make all

# 仅运行自动化测试(包括 API 和 CLI 的功能测试)
make test

# 清理构建文件
make clean

# 仅编译 GUI 工具
make gui

7.3.1 API 测试示例

========================================
 Starting API Unit Tests 
========================================
make[1]: Entering directory 'C:/Users/sike/Desktop/Graduat/Autumn/Homework/CryptoTechPractice/Homework/Hw2/code-v3'
 [Setup] Cleaning test environment...
make[1]: Leaving directory 'C:/Users/sike/Desktop/Graduat/Autumn/Homework/CryptoTechPractice/Homework/Hw2/code-v3'
make[1]: Entering directory 'C:/Users/sike/Desktop/Graduat/Autumn/Homework/CryptoTechPractice/Homework/Hw2/code-v3'
 [Setup] Generating random test files...
   -> Creating file1.bin (1MB)...
   -> Creating file2.bin (2MB)...
   -> Creating subdir/file3.bin (1MB)...
 [Setup] Backing up plaintext data...
make[1]: Leaving directory 'C:/Users/sike/Desktop/Graduat/Autumn/Homework/CryptoTechPractice/Homework/Hw2/code-v3'
make[1]: Entering directory 'C:/Users/sike/Desktop/Graduat/Autumn/Homework/CryptoTechPractice/Homework/Hw2/code-v3'
 [API] Running internal test suite...
Starting CLI test...
ShangMi(SM) File Encryption/Decryption Tool
Version: 0.3.0
Build Date: Dec  8 2025 20:28:28
CLI exited with code: 0
[*] [API 1/11] Running test: test_gen_keys
[+] Test test_gen_keys completed.
Public Key[65] = 046A47678201A68CD74486AF0A92A07252180B1CB879FB69ED118A3BEE8481CB47E6247D972B81CD4B6D6D23C58B42533DE3D899214AFD7940346EBA06EEE62EB4
Private Key[32] = FAF4A561B25EF124B5B50CAFBFD539CBC9DEE1C831CEDBB61556EAD8FFE68755

=== encryption with key ===
[*] [API 2/11] Running test: test_file_encryption
[+] Test test_file_encryption completed.
[*] [API 3/11] Running test: test_show_header
[+] Test test_show_header completed.

=== decryption with key ===
[*] [API 4/11] Running test: test_file_decryption_with_keyfile
[+] Test test_file_decryption_with_keyfile completed.

=== encryption with key file ===
[*] [API 5/11] Running test: test_file_encryption_with_keyfile
[+] Test test_file_encryption_with_keyfile completed.
[*] [API 6/11] Running test: test_show_header
[+] Test test_show_header completed.

=== decryption with key ===
[*] [API 7/11] Running test: test_file_decryption
[+] Test test_file_decryption completed.

=== directory encryption ===
[*] [API 8/11] Running test: test_dir_encryption
[+] Test test_dir_encryption completed.

=== directory decryption ===
[*] [API 9/11] Running test: test_dir_decryption
[+] Test test_dir_decryption completed.

=== directory encryption with key file ===
[*] [API 10/11] Running test: test_dir_encryption_with_keyfile
[+] Test test_dir_encryption_with_keyfile completed.

=== directory decryption with key file ===
[*] [API 11/11] Running test: test_dir_decryption_with_keyfile
[+] Test test_dir_decryption_with_keyfile completed.

[+] All API tests completed successfully.

make[1]: Leaving directory '...'
make[1]: Entering directory '...'
 [API] Verifying data integrity...
 [+] Files match originals after API tests.
make[1]: Leaving directory '...'
 [SUCCESS] API Tests Completed.

7.3 CLI 测试示例

========================================
 Starting CLI Integration Tests 
========================================
[*] [CLI 1/9] Cleaning environment...
[+] Environment cleaned.

[*] [CLI 2/9] Verifying Version Info...
    -> Executing: ././sm_cmd.exe version
ShangMi(SM) File Encryption/Decryption Tool
Version: 0.3.0
Build Date: Dec  8 2025 20:28:28
[+] Version command executed successfully.

[*] [CLI 3/9] Verifying Help Info...
    -> Executing: ././sm_cmd.exe help
Commands:
  encrypt <input_path> <public_key>  Encrypt file or directory
  decrypt <input_path> <private_key>  Decrypt file or directory
  encrypt -r <input_path> <public_key>  Encrypt directory recursively
  decrypt -r <input_path> <private_key>  Decrypt directory recursively
  genkeypair  Generate SM2 keypair (private + public)
  genkeypair -pri <private_key_file>  Generate SM2 keypair using provided private key
  version  Show program version
[+] Help command executed successfully.

[*] [CLI 4/9] Generating random test data...
[+] Test data generated successfully.


=== Generating Keys ===
[*] [CLI 5/9] Generating Keys...
    -> Executing: ././sm_cmd.exe genkeypair
[*] Generating new SM2 key pair...
[Success] SM2 Key Pair generation completed.
[+] Key pair generated successfully.


=== Encrypting and Decrypting Single Files ===
[*] [CLI 6/9] Encrypting Single File...
    -> Executing: ././sm_cmd.exe encrypt test_data/file1.bin .keys/public.key
[*] Starting single file ENCRYPTION on 'test_data/file1.bin'...
[+] Encryption completed successfully.

[*] [CLI 7/9] Decrypting Single File...
    -> Executing: ././sm_cmd.exe decrypt test_data/file1.bin.enc .keys/private.key
[*] Starting single file DECRYPTION on 'test_data/6af9dd105859973f6665ed30e6e01cf07b0c7505ed5609ff65df1826c16847c5.smcr'...
[+] Decryption completed successfully.


=== Encrypting and Decrypting Directory Recursively ===
[*] [CLI 8/9] Encrypting Directory (Recursive)...
    -> Executing: ././sm_cmd.exe encrypt -r test_data .keys/public.key
[*] Starting recursive ENCRYPTION on 'test_data'...
[+] Encryption completed successfully.

[*] [CLI 9/9] Decrypting Directory (Recursive)...
    -> Executing: ././sm_cmd.exe decrypt -r test_data .keys/private.key
[*] Starting recursive DECRYPTION on 'test_data'...
[+] Decryption completed successfully.

[*] [CLI] Verifying Data Integrity...
[+] Files match originals after CLI tests.
[+] CLI Integration Tests Completed Successfully!

========================================
 ALL TESTS PASSED SUCCESSFULLY!
========================================

7.4 GUI 示例

make gui 编译后会直接运行;双击 sm_gui.exe 也可以启动图形界面。

sm_gui

  • 单个文件加密/解密;
  • 递归目录加密/解密;
  • 自动识别/切换/生成密钥文件(public.keyprivate.key),默认存储在 <work_dir>/.keys/
  • 以加密文件数量为单位更新进度条;
  • 支持大文件(4.56 GB Model)和大文件夹(Aircrack-ng 1.7)测试。
  • 自动生成 .sm.log 日志文件,记录操作。

7.5 测试数据

详情见 tests/test_data/ 目录,Makefiletests/test_api.c,以及 .sm.log

8. Acknowledgements

Coding with Copilot and Gemini 3 Pro.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages