同系列文章:
- 国家商用密码(一)SM2椭圆曲线公钥密码算法
- 国家商用密码(二)C#:基于BouncyCastle实现SM3密码杂凑算法
- 国家商用密码(三)C#:从HashAlgorithm类派生实现SM3密码杂凑算法
- 国家商用密码(四)开放动态库及演示程序
- 国家商用密码(五)基于SM2的软件授权码生成及校验
- 国家商用密码(六)椭圆曲线加密算法密钥生成器
- 国家商用密码(七)在Apache MINA上实现二进制流的SM4编解码器
- 国家商用密码(八)在Apache MINA上实现文本流的SM4编解码器
- 国家商用密码(九)在Apache MINA上实现二进制流数据报文的SM4编解码器
- 国家商用密码(十)在Apache MINA上实现文本流数据报文的SM4编解码器
- 国家商用密码(11)在Netty 5.0.X上实现文本流的SM4编解码器
- 国家商用密码(12)在Netty 4.1.12.Final上实现文本流的SM4编解码器
- 国家商用密码(13)在DotNetty 0.4.5上实现文本流的SM4编解码器
/* ---------------------------------------------------------- * 文件名称:SM3.cs * * 作者:秦建辉 * * QQ:36748897 * * 博客:http://www.firstsolver.com/wordpress/ * * 开发环境: * Visual Studio V2013 * .NET Framework 4.5 * BouncyCastle Release 1.7 * * 版本历史: * V1.0 2015年05月28日 * 基于BouncyCastle 实现SM3密码杂凑算法 * * * 参考资料: * http://www.oscca.gov.cn/UpFile/20101222141857786.pdf * * 说明: * SM3生成256位散列值 * * 测试数据 * 输入:"abc" * 哈希值:66C7F0F4 62EEEDD9 D1F2D46B DC10E4E2 4167C487 5CF2F7A2 297DA02B 8F4BA8E0 * * 输入:"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd" * 哈希值:DEBE9FF9 2275B8A1 38604889 C18E5A4D 6FDB70E5 387E5765 293DCBA3 9C0C5732 * ------------------------------------------------------------ */ using Org.BouncyCastle.Crypto; using System; namespace Splash { /// <summary> /// SM3密码杂凑算法 /// </summary> public class SM3 : IDigest { /// <summary> /// 杂凑值长度(字节数) /// </summary> public const int SM3_HASH_BYTES = 32; /// <summary> /// 分组长度(字节数) /// </summary> public const int SM3_InputBlockSize = 64; /// <summary> /// 初始状态向量 /// </summary> private static readonly UInt32[] IV = { 0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600, 0xA96F30BC, 0x163138AA, 0xE38DEE4D, 0xB0FB0E4E }; /// <summary> /// 填充数据 /// </summary> private static readonly byte[] SM3_PADDING = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /// <summary> /// 当前状态向量 /// </summary> private UInt32[] V = new UInt32[SM3_HASH_BYTES >> 2]; /// <summary> /// 内部数据缓冲区 /// </summary> private UInt32[] W = new UInt32[68]; /// <summary> /// 4字节数据单元存储器 /// </summary> private byte[] M = new byte[4]; /// <summary> /// 已处理的字节计数 /// </summary> private UInt64 BytesCount = 0; /// <summary> /// 缓冲区X存储位置偏移量 /// </summary> private int XOff = 0; /// <summary> /// 缓冲区M存储位置偏移量 /// </summary> private int MOff = 0; /// <summary> /// 构造函数 /// </summary> public SM3() { Reset(); } /// <summary> /// 拷贝构造函数 /// </summary> /// <param name="t">要复制的对象实例</param> public SM3(SM3 t) { BytesCount = t.BytesCount; XOff = t.XOff; if (XOff > 0) Array.Copy(t.W, W, XOff); MOff = t.MOff; if (MOff > 0) Array.Copy(t.M, M, MOff); // 拷贝状态向量 Array.Copy(t.V, V, V.Length); } /// <summary> /// 恢复到初始状态 /// </summary> public void Reset() { BytesCount = 0; XOff = 0; MOff = 0; Array.Copy(IV, V, V.Length); // 清除敏感数据 Array.Clear(W, 0, W.Length); } /// <summary> /// 密码杂凑算法名称 /// </summary> public string AlgorithmName { get { return "SM3"; } } /// <summary> /// 内部缓冲区大小 /// </summary> /// <returns>内部缓冲区大小</returns> public int GetByteLength() { return SM3_InputBlockSize; } /// <summary> /// 杂凑值长度,256比特,32字节 /// </summary> /// <returns>杂凑值长度</returns> public int GetDigestSize() { return SM3_HASH_BYTES; } /// <summary> /// 处理单个数据 /// </summary> /// <param name="input">输入的单字节数据</param> public void Update(byte input) { M[MOff++] = input; if (MOff == 4) { ProcessWord(M, 0); MOff = 0; } BytesCount++; } /// <summary> /// 处理批量数据 /// </summary> /// <param name="input">包含输入数据的字节数组</param> /// <param name="inOff">数据在字节数组中的起始偏移量</param> /// <param name="length">数据长度</param> public void BlockUpdate(byte[] input, int inOff, int length) { while ((MOff != 0) && (length > 0)) { Update(input[inOff]); inOff++; length--; } while (length >= 4) { ProcessWord(input, inOff); inOff += 4; length -= 4; BytesCount += 4; } while (length > 0) { Update(input[inOff]); inOff++; length--; } } /// <summary> /// 获取最终的杂凑值 /// </summary> /// <param name="output">用于存储最终杂凑值的字节数组</param> /// <param name="outOff">存放数据的起始位置</param> /// <returns>写入数据的长度</returns> public int DoFinal(byte[] output, int outOff) { Finish(); foreach(UInt32 n in V) { output[outOff++] = (byte)(n >> 24); output[outOff++] = (byte)(n >> 16); output[outOff++] = (byte)(n >> 8); output[outOff++] = (byte)(n & 0xFF); } Reset(); return SM3_HASH_BYTES; } private void ProcessWord(byte[] input, int inOff) { W[XOff++] = (UInt32)((input[inOff] << 24) | (input[inOff + 1] << 16) | (input[inOff + 2] << 8) | input[inOff + 3]); if (XOff == 16) { ProcessBlock(); } } private void ProcessBlock() { UInt32[] W1 = new UInt32[64]; // 消息扩展(生成132个4字节数据) // a:将消息分组B(i)划分为16个4字节整型数据 // b:W[j] = P1(W[j-16] ^ W[j-9] ^ ROTL(W[j-3],15)) ^ ROTL(W[j - 13],7) ^ W[j-6] for (int j = 16; j < 68; j++) { W[j] = P1(W[j - 16] ^ W[j - 9] ^ ROTL(W[j - 3], 15)) ^ ROTL(W[j - 13], 7) ^ W[j - 6]; } // c:W1[j] = W[j] ^ W[j+4] for (int j = 0; j < 64; j++) { W1[j] = W[j] ^ W[j + 4]; } // 压缩函数 UInt32 A = V[0]; UInt32 B = V[1]; UInt32 C = V[2]; UInt32 D = V[3]; UInt32 E = V[4]; UInt32 F = V[5]; UInt32 G = V[6]; UInt32 H = V[7]; for (int j = 0; j < 16; j++) { UInt32 Q = ROTL(A, 12); UInt32 SS1 = ROTL((Q + E + ROTL(0x79CC4519, j)), 7); UInt32 SS2 = SS1 ^ Q; UInt32 TT1 = FF0(A, B, C) + D + SS2 + W1[j]; UInt32 TT2 = GG0(E, F, G) + H + SS1 + W[j]; D = C; C = ROTL(B, 9); B = A; A = TT1; H = G; G = ROTL(F, 19); F = E; E = P0(TT2); } for (int j = 16; j < 64; j++) { UInt32 Q = ROTL(A, 12); UInt32 SS1 = ROTL((Q + E + ROTL(0x7A879D8A, j)), 7); UInt32 SS2 = SS1 ^ Q; UInt32 TT1 = FF1(A, B, C) + D + SS2 + W1[j]; UInt32 TT2 = GG1(E, F, G) + H + SS1 + W[j]; D = C; C = ROTL(B, 9); B = A; A = TT1; H = G; G = ROTL(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; // 重置缓冲区 XOff = 0; } private void Finish() { // 计算实际消息比特长度 UInt64 BitsLength = BytesCount << 3; // 计算填充字节数 int LeftBytes = (XOff << 2) + MOff; int PaddingBytes = (LeftBytes < 56) ? (56 - LeftBytes) : (120 - LeftBytes); // 加入填充数据块 BlockUpdate(SM3_PADDING, 0, PaddingBytes); // 加入实际消息比特长度 byte[] L = BitConverter.GetBytes(BitsLength); Array.Reverse(L); BlockUpdate(L, 0, 8); } // 四字节无符号整数位循环左移位操作 private UInt32 ROTL(UInt32 x, int n) { return (x << n) | (x >> (32 - n)); } // 布尔函数 private UInt32 FF0(UInt32 x, UInt32 y, UInt32 z) { return x ^ y ^ z; } private UInt32 FF1(UInt32 x, UInt32 y, UInt32 z) { return (x & y) | (x & z) | (y & z); } private UInt32 GG0(UInt32 x, UInt32 y, UInt32 z) { return x ^ y ^ z; } private UInt32 GG1(UInt32 x, UInt32 y, UInt32 z) { return (x & y) | (~x & z); } // 置换函数 private UInt32 P0(UInt32 x) { return x ^ ROTL(x, 9) ^ ROTL(x, 17); } private UInt32 P1(UInt32 x) { return x ^ ROTL(x, 15) ^ ROTL(x, 23); } } }