GmSSL库
注意编译的时候加上 -lgmssl 选项
一、sm3算法
— sm3杂凑算法
#include <stdio.h>
#include <string.h>
#include <gmssl/sm3.h>
#define SM3_DIGEST_LENGTH 32
int main(int argc, char *argv[])
{
// 检查参数
if (argc != 2) {
printf("Usage: %s <message>\n", argv[0]);
return 1;
}
const char *message = argv[1];
size_t message_len = strlen(message);
// SM3哈希结果缓冲区
unsigned char sm3_hash[SM3_DIGEST_LENGTH];
// SM3上下文结构
SM3_CTX sm3_ctx;
// 初始化SM3上下文
sm3_init(&sm3_ctx);
// 更新哈希计算,可以多次调用处理大数据
sm3_update(&sm3_ctx, (unsigned char *)message, message_len);
// 完成哈希计算,获取最终结果
sm3_finish(&sm3_ctx, sm3_hash);
// 打印原始消息
printf("Message: %s\n", message);
// 打印SM3哈希结果
printf("SM3 Hash: ");
for (int i = 0; i < SM3_DIGEST_LENGTH; i++) {
printf("%02x", sm3_hash[i]);
}
printf("\n");
return 0;
}
— sm3 hmac算法
#include <stdio.h>
#include <string.h>
#include <gmssl/hmac.h>
#include <gmssl/sm3.h>
void print_hex(const char *label, const unsigned char *data, size_t len) {
printf("%s: ", label);
for (size_t i = 0; i < len; i++) {
printf("%02x", data[i]);
}
printf("\n");
}
int main() {
// 预定义的十六进制密钥 (32字节全零)
const unsigned char key[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
// 预定义的十六进制消息 (12字节全零)
const unsigned char message[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
// 计算HMAC-SM3
unsigned char hmac[1024] = {0};
size_t hmac_len = 1024;
HMAC_CTX ctx;
// 初始化HMAC上下文
if (hmac_init(&ctx, DIGEST_sm3(), key, sizeof(key)) != 1) {
fprintf(stderr, "HMAC init failed\n");
return 1;
}
// 更新消息数据
if (hmac_update(&ctx, message, sizeof(message)) != 1) {
fprintf(stderr, "HMAC update failed\n");
return 1;
}
// 获取HMAC结果
if (hmac_finish(&ctx, hmac, &hmac_len) != 1) {
fprintf(stderr, "HMAC finish failed\n");
return 1;
}
// 验证输出长度
if (hmac_len != SM3_DIGEST_SIZE) {
fprintf(stderr, "Error: Unexpected HMAC length %zu (expected %d)\n",
hmac_len, SM3_DIGEST_SIZE);
return 1;
}
// 打印结果
print_hex("Key (hex)", key, sizeof(key));
print_hex("Message (hex)", message, sizeof(message));
print_hex("HMAC-SM3 (hex)", hmac, hmac_len);
return 0;
}
二、sm4算法
— ECB模式 包括包括0填充和PKCS#7 填充方式
#include <stdio.h>
#include <string.h>
#include <gmssl/sm4.h>
#include <gmssl/hex.h>
// 打印十六进制数据
void print_hex(const char* label, const uint8_t* data, size_t datalen) {
printf("%s: ", label);
for (size_t i = 0; i < datalen; i++) {
printf("%02X", data[i]);
}
printf("\n");
}
// PKCS#7填充
int pkcs7_pad(uint8_t* buf, size_t buflen, size_t datalen, int block_size) {
if (datalen >= buflen || block_size <= 0 || block_size > 255) {
return -1;
}
int pad_len = block_size - (datalen % block_size);
for (size_t i = datalen; i < datalen + pad_len; i++) {
buf[i] = (uint8_t)pad_len;
}
return datalen + pad_len;
}
// PKCS#7去填充
int pkcs7_unpad(uint8_t* buf, size_t buflen) {
if (buflen == 0) return -1;
uint8_t pad_len = buf[buflen - 1];
if (pad_len > buflen) return -1;
for (size_t i = buflen - pad_len; i < buflen; i++) {
if (buf[i] != pad_len) return -1;
}
return buflen - pad_len;
}
// 使用0填充的SM4 ECB加密
int sm4_ecb_encrypt_zero_pad(const uint8_t* key, const uint8_t* in, size_t inlen, uint8_t* out) {
SM4_KEY sm4_key;
sm4_set_encrypt_key(&sm4_key, key);
// 0填充到16字节倍数
size_t padded_len = ((inlen + 15) / 16) * 16;
uint8_t padded_data[padded_len];
memcpy(padded_data, in, inlen);
memset(padded_data + inlen, 0, padded_len - inlen);
for (size_t i = 0; i < padded_len; i += 16) {
sm4_encrypt(&sm4_key, padded_data + i, out + i);
}
return padded_len;
}
// 使用0填充的SM4 ECB解密
int sm4_ecb_decrypt_zero_pad(const uint8_t* key, const uint8_t* in, size_t inlen, uint8_t* out) {
if (inlen % 16 != 0) {
return -1;
}
SM4_KEY sm4_key;
sm4_set_decrypt_key(&sm4_key, key);
for (size_t i = 0; i < inlen; i += 16) {
sm4_encrypt(&sm4_key, in + i, out + i); // 注意:在ECB模式下,解密也是使用sm4_encrypt函数,只是密钥不同
}
// 去除0填充需要知道原始数据长度,这里返回全部数据
return inlen;
}
// 使用PKCS#7填充的SM4 ECB加密
int sm4_ecb_encrypt_pkcs7(const uint8_t* key, const uint8_t* in, size_t inlen, uint8_t* out) {
SM4_KEY sm4_key;
sm4_set_encrypt_key(&sm4_key, key);
// PKCS#7填充
size_t padded_len = ((inlen + 15) / 16) * 16;
uint8_t padded_data[padded_len];
memcpy(padded_data, in, inlen);
pkcs7_pad(padded_data, padded_len, inlen, 16);
for (size_t i = 0; i < padded_len; i += 16) {
sm4_encrypt(&sm4_key, padded_data + i, out + i);
}
return padded_len;
}
// 使用PKCS#7填充的SM4 ECB解密
int sm4_ecb_decrypt_pkcs7(const uint8_t* key, const uint8_t* in, size_t inlen, uint8_t* out) {
if (inlen % 16 != 0) {
return -1;
}
SM4_KEY sm4_key;
sm4_set_decrypt_key(&sm4_key, key);
for (size_t i = 0; i < inlen; i += 16) {
sm4_encrypt(&sm4_key, in + i, out + i); // 注意:在ECB模式下,解密也是使用sm4_encrypt函数,只是密钥不同
}
// 去除PKCS#7填充
return pkcs7_unpad(out, inlen);
}
int main() {
// SM4密钥 (16字节)
uint8_t key[16] = {
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10
};
// 测试数据
uint8_t plaintext[] = "Hello, SM4 ECB encryption! This is a test.";
size_t plaintext_len = strlen((char*)plaintext);
printf("=== SM4 ECB Encryption/Decryption Demo ===\n");
print_hex("Key", key, sizeof(key));
print_hex("Plaintext", plaintext, plaintext_len);
printf("Plaintext length: %zu\n", plaintext_len);
// 1. 使用0填充加密解密
printf("\n[Zero Padding]\n");
uint8_t ciphertext_zero[256] = {0};
uint8_t decrypted_zero[256] = {0};
// 加密
int ciphertext_zero_len = sm4_ecb_encrypt_zero_pad(key, plaintext, plaintext_len, ciphertext_zero);
print_hex("Ciphertext (Zero pad)", ciphertext_zero, ciphertext_zero_len);
// 解密
int decrypted_zero_len = sm4_ecb_decrypt_zero_pad(key, ciphertext_zero, ciphertext_zero_len, decrypted_zero);
printf("Decrypted length: %d\n", decrypted_zero_len);
print_hex("Decrypted data (Zero pad)", decrypted_zero, decrypted_zero_len);
printf("Decrypted text: %.*s\n", decrypted_zero_len, decrypted_zero);
// 2. 使用PKCS#7填充加密解密
printf("\n[PKCS#7 Padding]\n");
uint8_t ciphertext_pkcs7[256] = {0};
uint8_t decrypted_pkcs7[256] = {0};
// 加密
int ciphertext_pkcs7_len = sm4_ecb_encrypt_pkcs7(key, plaintext, plaintext_len, ciphertext_pkcs7);
print_hex("Ciphertext (PKCS#7)", ciphertext_pkcs7, ciphertext_pkcs7_len);
// 解密
int decrypted_pkcs7_len = sm4_ecb_decrypt_pkcs7(key, ciphertext_pkcs7, ciphertext_pkcs7_len, decrypted_pkcs7);
if (decrypted_pkcs7_len < 0) {
printf("Decryption failed (invalid padding)\n");
} else {
printf("Decrypted length: %d\n", decrypted_pkcs7_len);
print_hex("Decrypted data (PKCS#7)", decrypted_pkcs7, decrypted_pkcs7_len);
printf("Decrypted text: %.*s\n", decrypted_pkcs7_len, decrypted_pkcs7);
}
return 0;
}
—CBC模式 包括包括0填充和PKCS#7 填充方式
#include <stdio.h>
#include <string.h>
#include <gmssl/sm4.h>
#include <gmssl/hex.h>
#include <gmssl/rand.h>
// 打印十六进制数据
void print_hex(const char* label, const uint8_t* data, size_t datalen) {
printf("%s: ", label);
for (size_t i = 0; i < datalen; i++) {
printf("%02X", data[i]);
}
printf("\n");
}
// PKCS#7填充
int pkcs7_pad(uint8_t* buf, size_t buflen, size_t datalen, int block_size) {
if (datalen >= buflen || block_size <= 0 || block_size > 255) {
return -1;
}
int pad_len = block_size - (datalen % block_size);
for (size_t i = datalen; i < datalen + pad_len; i++) {
buf[i] = (uint8_t)pad_len;
}
return datalen + pad_len;
}
// PKCS#7去填充
int pkcs7_unpad(uint8_t* buf, size_t buflen) {
if (buflen == 0) return -1;
uint8_t pad_len = buf[buflen - 1];
if (pad_len > buflen) return -1;
for (size_t i = buflen - pad_len; i < buflen; i++) {
if (buf[i] != pad_len) return -1;
}
return buflen - pad_len;
}
// 使用0填充的SM4 CBC加密
int sm4_cbc_encrypt_zero_pad(const uint8_t* key, const uint8_t* iv,
const uint8_t* in, size_t inlen, uint8_t* out) {
SM4_KEY sm4_key;
uint8_t ivec[SM4_BLOCK_SIZE];
sm4_set_encrypt_key(&sm4_key, key);
memcpy(ivec, iv, SM4_BLOCK_SIZE);
// 0填充到16字节倍数
size_t padded_len = ((inlen + 15) / 16) * 16;
uint8_t padded_data[padded_len];
memcpy(padded_data, in, inlen);
memset(padded_data + inlen, 0, padded_len - inlen);
for (size_t i = 0; i < padded_len; i += SM4_BLOCK_SIZE) {
// 异或IV
for (int j = 0; j < SM4_BLOCK_SIZE; j++) {
padded_data[i + j] ^= ivec[j];
}
sm4_encrypt(&sm4_key, padded_data + i, out + i);
// 更新IV为当前密文块
memcpy(ivec, out + i, SM4_BLOCK_SIZE);
}
return padded_len;
}
// 使用0填充的SM4 CBC解密
int sm4_cbc_decrypt_zero_pad(const uint8_t* key, const uint8_t* iv,
const uint8_t* in, size_t inlen, uint8_t* out) {
if (inlen % SM4_BLOCK_SIZE != 0) {
return -1;
}
SM4_KEY sm4_key;
uint8_t ivec[SM4_BLOCK_SIZE];
uint8_t temp[SM4_BLOCK_SIZE];
sm4_set_decrypt_key(&sm4_key, key);
memcpy(ivec, iv, SM4_BLOCK_SIZE);
for (size_t i = 0; i < inlen; i += SM4_BLOCK_SIZE) {
// 解密当前块
sm4_encrypt(&sm4_key, in + i, temp);
// 异或IV
for (int j = 0; j < SM4_BLOCK_SIZE; j++) {
out[i + j] = temp[j] ^ ivec[j];
}
// 更新IV为当前密文块
memcpy(ivec, in + i, SM4_BLOCK_SIZE);
}
// 返回解密数据长度(等于输入长度)
return inlen;
}
// 使用PKCS#7填充的SM4 CBC加密
int sm4_cbc_encrypt_pkcs7(const uint8_t* key, const uint8_t* iv,
const uint8_t* in, size_t inlen, uint8_t* out) {
SM4_KEY sm4_key;
uint8_t ivec[SM4_BLOCK_SIZE];
sm4_set_encrypt_key(&sm4_key, key);
memcpy(ivec, iv, SM4_BLOCK_SIZE);
// PKCS#7填充
size_t padded_len = ((inlen + 15) / 16) * 16;
uint8_t padded_data[padded_len];
memcpy(padded_data, in, inlen);
pkcs7_pad(padded_data, padded_len, inlen, SM4_BLOCK_SIZE);
for (size_t i = 0; i < padded_len; i += SM4_BLOCK_SIZE) {
// 异或IV
for (int j = 0; j < SM4_BLOCK_SIZE; j++) {
padded_data[i + j] ^= ivec[j];
}
sm4_encrypt(&sm4_key, padded_data + i, out + i);
// 更新IV为当前密文块
memcpy(ivec, out + i, SM4_BLOCK_SIZE);
}
return padded_len;
}
// 使用PKCS#7填充的SM4 CBC解密
int sm4_cbc_decrypt_pkcs7(const uint8_t* key, const uint8_t* iv,
const uint8_t* in, size_t inlen, uint8_t* out) {
if (inlen % SM4_BLOCK_SIZE != 0) {
return -1;
}
SM4_KEY sm4_key;
uint8_t ivec[SM4_BLOCK_SIZE];
uint8_t temp[SM4_BLOCK_SIZE];
sm4_set_decrypt_key(&sm4_key, key);
memcpy(ivec, iv, SM4_BLOCK_SIZE);
for (size_t i = 0; i < inlen; i += SM4_BLOCK_SIZE) {
// 解密当前块
sm4_encrypt(&sm4_key, in + i, temp);
// 异或IV
for (int j = 0; j < SM4_BLOCK_SIZE; j++) {
out[i + j] = temp[j] ^ ivec[j];
}
// 更新IV为当前密文块
memcpy(ivec, in + i, SM4_BLOCK_SIZE);
}
// 去除PKCS#7填充
return pkcs7_unpad(out, inlen);
}
int main() {
// SM4密钥 (16字节)
uint8_t key[SM4_BLOCK_SIZE] = {
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10
};
// 初始化向量IV (16字节)
uint8_t iv[SM4_BLOCK_SIZE];
rand_bytes(iv, SM4_BLOCK_SIZE); // 使用随机IV
// 测试数据
uint8_t plaintext[] = "Hello, SM4 CBC encryption! This is a test.";
size_t plaintext_len = strlen((char*)plaintext);
printf("=== SM4 CBC Encryption/Decryption Demo ===\n");
print_hex("Key", key, sizeof(key));
print_hex("IV", iv, sizeof(iv));
print_hex("Plaintext", plaintext, plaintext_len);
printf("Plaintext length: %zu\n", plaintext_len);
// 1. 使用0填充加密解密
printf("\n[Zero Padding]\n");
uint8_t ciphertext_zero[256] = {0};
uint8_t decrypted_zero[256] = {0};
// 加密
int ciphertext_zero_len = sm4_cbc_encrypt_zero_pad(key, iv, plaintext, plaintext_len, ciphertext_zero);
print_hex("Ciphertext (Zero pad)", ciphertext_zero, ciphertext_zero_len);
// 解密
int decrypted_zero_len = sm4_cbc_decrypt_zero_pad(key, iv, ciphertext_zero, ciphertext_zero_len, decrypted_zero);
printf("Decrypted length: %d\n", decrypted_zero_len);
print_hex("Decrypted data (Zero pad)", decrypted_zero, decrypted_zero_len);
printf("Decrypted text: %.*s\n", decrypted_zero_len, decrypted_zero);
// 2. 使用PKCS#7填充加密解密
printf("\n[PKCS#7 Padding]\n");
uint8_t ciphertext_pkcs7[256] = {0};
uint8_t decrypted_pkcs7[256] = {0};
// 加密
int ciphertext_pkcs7_len = sm4_cbc_encrypt_pkcs7(key, iv, plaintext, plaintext_len, ciphertext_pkcs7);
print_hex("Ciphertext (PKCS#7)", ciphertext_pkcs7, ciphertext_pkcs7_len);
// 解密
int decrypted_pkcs7_len = sm4_cbc_decrypt_pkcs7(key, iv, ciphertext_pkcs7, ciphertext_pkcs7_len, decrypted_pkcs7);
if (decrypted_pkcs7_len < 0) {
printf("Decryption failed (invalid padding)\n");
} else {
printf("Decrypted length: %d\n", decrypted_pkcs7_len);
print_hex("Decrypted data (PKCS#7)", decrypted_pkcs7, decrypted_pkcs7_len);
printf("Decrypted text: %.*s\n", decrypted_pkcs7_len, decrypted_pkcs7);
}
return 0;
}