以下是使用 OpenSSL 库进行 SM3 消息摘要和文件加密的 C++ 示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <iostream>
#include <fstream>
#include <string>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/sm3.h>

// 计算字符串的 SM3 摘要值
std::string sm3_hash_string(const std::string& str) {
unsigned char md[SM3_DIGEST_LENGTH];
SM3(reinterpret_cast<const unsigned char*>(str.data()), str.size(), md);
std::string hash_str(reinterpret_cast<const char*>(md), SM3_DIGEST_LENGTH);
return hash_str;
}

// 计算文件的 SM3 摘要值
std::string sm3_hash_file(const std::string& file_path) {
unsigned char md[SM3_DIGEST_LENGTH];
std::ifstream input(file_path, std::ios::binary);
if (input) {
EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(mdctx, EVP_sm3(), nullptr);
const size_t buf_size = 4096;
char buf[buf_size];
while (input.read(buf, buf_size)) {
EVP_DigestUpdate(mdctx, buf, buf_size);
}
size_t remain_size = input.gcount();
EVP_DigestUpdate(mdctx, buf, remain_size);
EVP_DigestFinal_ex(mdctx, md, nullptr);
EVP_MD_CTX_free(mdctx);
input.close();
std::string hash_str(reinterpret_cast<const char*>(md), SM3_DIGEST_LENGTH);
return hash_str;
}
else {
throw std::runtime_error("fail to open file " + file_path);
}
}

// 使用密码对文件进行加密
void encrypt_file(const std::string& input_file_path, const std::string& output_file_path, const std::string& password) {
std::ifstream input(input_file_path, std::ios::binary);
std::ofstream output(output_file_path, std::ios::binary);
if (input && output) {
const int key_len = EVP_MAX_KEY_LENGTH;
const int iv_len = EVP_MAX_IV_LENGTH;
unsigned char key[key_len];
unsigned char iv[iv_len];
EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sm3(), nullptr, reinterpret_cast<const unsigned char*>(password.data()), password.size(), 1, key, iv);
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key, iv);
const size_t buf_size = 4096;
char buf[buf_size];
while (input.read(buf, buf_size)) {
int len = input.gcount();
int out_len = 0;
EVP_EncryptUpdate(ctx, reinterpret_cast<unsigned char*>(buf), &out_len, reinterpret_cast<unsigned char*>(buf), len);
output.write(buf, out_len);
}
int len = input.gcount();
int out_len = 0;
EVP_EncryptFinal_ex(ctx, reinterpret_cast<unsigned char*>(buf), &out_len);
output.write(buf, out_len);
EVP_CIPHER_CTX_free(ctx);
input.close();
output.close();
}
else {
throw std::runtime_error("fail to open input/output file.");
}

}

int main() {
std::string str = "message to be hashed";
std::cout << "SM3 hash of string \"" << str << "\": " << sm3_hash_string(str) << std::endl;
std::string file_path = "test.txt";
std::cout << "SM3 hash of file \"" << file_path << "\": " << sm3_hash_file(file_path) << std::endl;
std::string password = "123456";
try {
encrypt_file(file_path, "test_encrypted.txt", password);
}
catch (const std::exception& e) {
std::cout << "Error: " << e.what() << std::endl;
}
return 0;
}

上述代码中,使用 SM3 函数对字符串或文件内容进行摘要;使用 EVP_BytesToKey 函数生成密码加密密钥和初始化向量,并使用 EVP_EncryptInit_ex 函数初始化加密上下文,在循环中调用 EVP_EncryptUpdate 函数对文件进行逐块加密,最后调用 EVP_EncryptFinal_ex 函数完成加密过程,将结果写入新的加密文件中。