当前位置: 首页 > news >正文

C语言使用GmSSL库实现sm3、sm4算法

GmSSL库

GmSSL库github链接

注意编译的时候加上 -lgmssl 选项

一、sm3算法

— sm3杂凑算法

#include <stdio.h>
#include <string.h>
#include <gmssl/sm3.h>
#define SM3_DIGEST_LENGTH 32int 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-SM3unsigned 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) {// 异或IVfor (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);// 异或IVfor (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) {// 异或IVfor (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);// 异或IVfor (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;
}
http://www.lryc.cn/news/607094.html

相关文章:

  • Linux----信号
  • Docker学习其二(容器卷,Docker网络,Compose)
  • cocosCreator2.4 googlePlay登录升级、API 35、16KB内存页面的支持
  • 特征工程 --- 特征提取
  • (一)LoRA微调BERT:为何在单分类任务中表现优异,而在多分类任务中效果不佳?
  • 【C++】类和对象 上
  • 逻辑回归算法中的一些问题
  • Leetcode——53. 最大子数组和
  • elementui中rules的validator 用法
  • 在线教程丨全球首个 MoE 视频生成模型!阿里 Wan2.2 开源,消费级显卡也能跑出电影级 AI 视频
  • Windows11 WSL安装Ubntu22.04,交叉编译C语言应用程序
  • 网站建设服务器从入门到上手
  • 《n8n基础教学》第一节:如何使用编辑器UI界面
  • 如何优雅删除Docker镜像和容器(保姆级别)
  • 服务器地域选择指南:深度分析北京/上海/广州节点对网站速度的影响
  • FreeSWITCH与Java交互实战:从EslEvent解析到Spring Boot生态整合的全指南
  • 分布式弹幕系统设计
  • Git 误删分支怎么恢复
  • ABP VNext + Dapr Workflows:轻量级分布式工作流
  • stl的MATLAB读取与显示
  • Blender 4.5 安装指南:快速配置中文版,适用于Win/mac/Linux系统
  • 【Mysql】字段隐式转换对where条件和join关联条件的影响
  • 安全专家发现利用多层跳转技术窃取Microsoft 365登录凭证的新型钓鱼攻击
  • 基于Pipeline架构的光存储读取程序 Qt版本
  • 九、Maven入门学习记录
  • 学习游戏制作记录(各种水晶能力以及多晶体)8.1
  • k8s之NDS解析到Ingress服务暴露
  • Wisdom SSH开启高效管理服务器的大门
  • Git之远程仓库
  • 【全网首个公开VMware vCenter 靶场环境】 Vulntarget-o 正式上线