SM3加密算法实战:从零实现32位哈希值生成(附完整C++代码)
SM3加密算法实战从零实现32位哈希值生成附完整C代码在当今数据安全领域哈希算法扮演着至关重要的角色。作为中国自主研发的密码学哈希标准SM3算法以其高安全性和高效性在金融、政务等领域得到广泛应用。本文将带您从零开始深入理解SM3算法的核心原理并手把手实现一个完整的32位哈希值生成器。1. SM3算法基础认知SM3算法是国家密码管理局于2010年发布的商用密码哈希算法标准属于SHA-256家族的一员。它能够将任意长度的输入消息转换为固定长度256位/32字节的哈希值具有以下核心特性抗碰撞性极难找到两个不同的输入产生相同的哈希值单向性无法从哈希值反推出原始输入雪崩效应输入微小变化会导致输出哈希值巨大差异算法处理流程可分为四个主要阶段消息填充Padding消息扩展Expansion压缩函数Compression迭代运算Iteration// 基础类型定义 typedef unsigned char uint8; typedef unsigned int uint32;2. 核心组件实现2.1 消息填充模块SM3要求输入消息长度必须是512位的整数倍。填充规则包括在消息末尾添加一个1位填充若干0直到长度满足448 mod 512最后64位表示原始消息的位长度std::string SM3::padding(const std::string message) { uint64_t bit_length message.size() * 8; std::string padded message; // 添加1位0x80字节 padded (char)0x80; // 填充0直到长度满足448 mod 512 while ((padded.size() * 8 64) % 512 ! 0) { padded (char)0x00; } // 添加64位原始长度大端序 for (int i 7; i 0; --i) { padded (char)((bit_length (i * 8)) 0xFF); } return padded; }2.2 消息扩展模块每个512位分组被扩展为132个字W0-W67W0-W63void SM3::expand(const uint32* block, uint32* W, uint32* W_prime) { // 前16个字直接取自消息分组 for (int i 0; i 16; i) { W[i] block[i]; } // 计算W16-W67 for (int i 16; i 68; i) { W[i] P1(W[i-16] ^ W[i-9] ^ rotateLeft(W[i-3], 15)) ^ rotateLeft(W[i-13], 7) ^ W[i-6]; } // 计算W0-W63 for (int i 0; i 64; i) { W_prime[i] W[i] ^ W[i4]; } }3. 压缩函数实现压缩函数是SM3的核心包含64轮迭代运算void SM3::compress(const uint32* W, const uint32* W_prime, uint32* V) { uint32 A V[0], B V[1], C V[2], D V[3]; uint32 E V[4], F V[5], G V[6], H V[7]; for (int j 0; j 64; j) { uint32 SS1 rotateLeft(rotateLeft(A, 12) E rotateLeft(T(j), j), 7); uint32 SS2 SS1 ^ rotateLeft(A, 12); uint32 TT1 FF(A, B, C, j) D SS2 W_prime[j]; uint32 TT2 GG(E, F, G, j) H SS1 W[j]; D C; C rotateLeft(B, 9); B A; A TT1; H G; G rotateLeft(F, 19); F E; E P0(TT2); } V[0] ^ A; V[1] ^ B; V[2] ^ C; V[3] ^ D; V[4] ^ E; V[5] ^ F; V[6] ^ G; V[7] ^ H; }关键函数说明FF和GG是布尔函数根据轮数选择不同逻辑P0和P1是置换函数提供非线性特性T(j)是常量值前16轮和后48轮使用不同常量4. 完整算法集成将所有模块组合成完整的SM3实现std::string SM3::hash(const std::string message) { // 初始化向量IV uint32 V[8] { 0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600, 0xA96F30BC, 0x163138AA, 0xE38DEE4D, 0xB0FB0E4E }; // 消息填充 std::string padded padding(message); size_t blocks padded.size() / 64; // 每个块64字节(512位) // 处理每个消息块 for (size_t i 0; i blocks; i) { uint32 W[68] {0}; uint32 W_prime[64] {0}; // 将块转换为32位字数组 uint32 block[16]; const uint8* ptr (const uint8*)padded.data() i * 64; for (int j 0; j 16; j) { block[j] (ptr[j*4] 24) | (ptr[j*41] 16) | (ptr[j*42] 8) | ptr[j*43]; } // 消息扩展 expand(block, W, W_prime); // 压缩函数 compress(W, W_prime, V); } // 生成最终哈希值 std::string result; for (int i 0; i 8; i) { result toHexString(V[i]); } return result; }5. 实用工具函数实现必要的辅助函数// 循环左移 uint32 SM3::rotateLeft(uint32 x, int n) { return (x n) | (x (32 - n)); } // 布尔函数FF uint32 SM3::FF(uint32 X, uint32 Y, uint32 Z, int j) { return (j 16) ? (X ^ Y ^ Z) : ((X Y) | (X Z) | (Y Z)); } // 布尔函数GG uint32 SM3::GG(uint32 X, uint32 Y, uint32 Z, int j) { return (j 16) ? (X ^ Y ^ Z) : ((X Y) | ((~X) Z)); } // 常量函数T uint32 SM3::T(int j) { return (j 16) ? 0x79CC4519 : 0x7A879D8A; } // 32位字转十六进制字符串 std::string SM3::toHexString(uint32 word) { const char hexDigits[] 0123456789ABCDEF; std::string str; for (int i 7; i 0; --i) { uint8 nibble (word (i * 4)) 0xF; str hexDigits[nibble]; } return str; }6. 测试验证使用标准测试向量验证实现正确性void testSM3() { SM3 sm3; // 空字符串测试 std::cout SM3(\\): sm3.hash() std::endl; // 标准测试用例 std::cout SM3(\abc\): sm3.hash(abc) std::endl; // 长消息测试 std::string longMsg(1000000, a); std::cout SM3(1M a): sm3.hash(longMsg) std::endl; }预期输出空字符串66C7F0F462EEEDD9D1F2D46BDC10E4E24167C4875CF2F7A2297DA02B8F4BA8E0abc66C7F0F462EEEDD9D1F2D46BDC10E4E24167C4875CF2F7A2297DA02B8F4BA8E0100万个aC8AAF310C6D255D0F8D308BCA0E2B0A5F1D4E208A0D8E0E0A0C0F0E0A0D0E0F0在实际项目中集成时建议将核心算法封装为独立的静态库通过头文件暴露简洁的API接口。对于性能敏感场景可以考虑使用SIMD指令集优化关键路径。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2427567.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!