#include <openssl/evp.h> #include <openssl/rand.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define SM4_KEY_SIZE 16 #define SM4_BLOCK_SIZE 16 void handle_errors() { ERR_print_errors_fp(stderr); abort(); } /* int sm4_encrypt_file(const char *input_file, const char *output_file, const unsigned char *key) { FILE *in_file = fopen(input_file, "rb"); FILE *out_file = fopen(output_file, "wb"); if (!in_file || !out_file) { perror("Failed to open file"); return 0; } EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); if (!ctx) handle_errors(); unsigned char iv[SM4_BLOCK_SIZE]; if (!RAND_bytes(iv, SM4_BLOCK_SIZE)) handle_errors(); fwrite(iv, 1, SM4_BLOCK_SIZE, out_file); if (1 != EVP_EncryptInit_ex(ctx, EVP_sm4_cbc(), NULL, key, iv)) handle_errors(); unsigned char in_buf[1024]; unsigned char out_buf[1024 + SM4_BLOCK_SIZE]; int out_len; int final_len; while (1) { size_t in_len = fread(in_buf, 1, sizeof(in_buf), in_file); if (in_len <= 0) break; if (1 != EVP_EncryptUpdate(ctx, out_buf, &out_len, in_buf, in_len)) handle_errors(); fwrite(out_buf, 1, out_len, out_file); } if (1 != EVP_EncryptFinal_ex(ctx, out_buf, &final_len)) handle_errors(); fwrite(out_buf, 1, final_len, out_file); EVP_CIPHER_CTX_free(ctx); fclose(in_file); fclose(out_file); return 1; } */ int sm4_decrypt_file(const char *input_file, const char *output_file, const unsigned char *key) { FILE *in_file = fopen(input_file, "rb"); FILE *out_file = fopen(output_file, "wb"); if (!in_file || !out_file) { perror("Failed to open file"); return 0; } EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); if (!ctx) handle_errors(); unsigned char iv[SM4_BLOCK_SIZE]; fread(iv, 1, SM4_BLOCK_SIZE, in_file); if (1 != EVP_DecryptInit_ex(ctx, EVP_sm4_cbc(), NULL, key, iv)) handle_errors(); unsigned char in_buf[1024 + S
时间: 2025-06-27 11:05:34 浏览: 11
### SM4_CBC模式下文件解密的C语言实现
以下是基于OpenSSL库中EVP接口实现SM4_CBC模式下文件解密的完整C代码示例:
#### 解密函数说明
为了完成文件解密操作,需定义一个解密函数 `Decrypt_SM4_File`。该函数会读取加密后的输入文件,并将其通过SM4_CBC模式解密后写入到指定的目标文件中。
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#define KEY_SIZE 16 // SM4 密钥长度 (128-bit)
#define IV_SIZE 16 // 初始化向量长度 (128-bit)
// 解密函数
int Decrypt_SM4_File(const char* input_file, const char* output_file, const unsigned char* key, const unsigned char* iv) {
FILE *in = fopen(input_file, "rb");
if (!in) {
fprintf(stderr, "Error: Unable to open input file.\n");
return -1;
}
FILE *out = fopen(output_file, "wb");
if (!out) {
fclose(in);
fprintf(stderr, "Error: Unable to open output file.\n");
return -1;
}
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
// 初始化解密上下文
if (!EVP_DecryptInit_ex(&ctx, EVP_sm4_cbc(), NULL, key, iv)) {
fprintf(stderr, "Error: Failed to initialize decryption context.\n");
goto cleanup;
}
unsigned char in_buf[1024];
unsigned char out_buf[1024 + EVP_MAX_BLOCK_LENGTH];
int in_len, out_len;
while ((in_len = fread(in_buf, 1, sizeof(in_buf), in))) {
if (!EVP_DecryptUpdate(&ctx, out_buf, &out_len, in_buf, in_len)) {
fprintf(stderr, "Error: Decryption failed during update phase.\n");
goto cleanup;
}
fwrite(out_buf, 1, out_len, out);
}
// 处理最后的数据块
if (!EVP_DecryptFinal_ex(&ctx, out_buf, &out_len)) {
fprintf(stderr, "Error: Decryption failed during finalization phase.\n");
goto cleanup;
}
fwrite(out_buf, 1, out_len, out);
cleanup:
EVP_CIPHER_CTX_cleanup(&ctx);
fclose(in);
fclose(out);
return 0;
}
```
---
#### 主程序调用示例
以下为主程序部分,用于设置密钥、初始化向量以及调用上述解密函数。
```c
int main(int argc, char **argv) {
if (argc != 5) {
printf("Usage: %s <input_encrypted_file> <output_decrypted_file> <key_hex> <iv_hex>\n", argv[0]);
return -1;
}
const char *input_file = argv[1];
const char *output_file = argv[2];
// 将十六进制字符串转换为字节数组
unsigned char key[KEY_SIZE], iv[IV_SIZE];
if (strlen(argv[3]) != 2 * KEY_SIZE || strlen(argv[4]) != 2 * IV_SIZE) {
fprintf(stderr, "Error: Key and IV must be exactly 16 bytes long.\n");
return -1;
}
for (int i = 0; i < KEY_SIZE; ++i) {
sscanf(argv[3] + 2 * i, "%2hhx", &key[i]);
}
for (int i = 0; i < IV_SIZE; ++i) {
sscanf(argv[4] + 2 * i, "%2hhx", &iv[i]);
}
// 调用解密函数
if (Decrypt_SM4_File(input_file, output_file, key, iv) == 0) {
printf("Decryption completed successfully!\n");
} else {
printf("Decryption failed.\n");
}
return 0;
}
```
---
#### 关键点解析
1. **EVP接口的选择**
使用 `EVP_sm4_cbc()` 函数指针来指定SM4_CBC模式[^1]。
2. **密钥与初始向量**
需要用户提供合法的16字节密钥和初始向量(分别对应于SM4算法的要求)。这些参数通常以十六进制形式传递给程序并进行转换处理[^2]。
3. **错误处理机制**
在每一步可能失败的操作之后都加入了详细的错误检测逻辑,以便及时发现潜在问题并终止执行流程[^3]。
4. **内存管理**
所有的动态分配资源均被妥善释放,避免造成内存泄漏等问题发生[^4]。
---
阅读全文
相关推荐


















