在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
本文主要讲解“国密加密算法”SM系列之SM3的C#实现方法,加密规则请详阅国密局发布的文档。 首先需第三方Nuget包:Portable.BouncyCastle (源码来自http://www.bouncycastle.org/csharp/) 1.1常规处理 /// <summary> /// General /// </summary> public abstract class GeneralDigest : IDigest { /// <summary> /// 内部缓冲区的大小 /// </summary> private const int ByteLength = 64; /// <summary> /// 消息摘要 /// </summary> private readonly byte[] XBuf; /// <summary> /// 待更新的消息摘要的索引 /// </summary> private int XBufOff; /// <summary> /// 待更新的消息摘要的大小 /// </summary> private long ByteCount; /// <summary> /// 构造函数 /// </summary> internal GeneralDigest() { XBuf = new byte[4]; } /// <summary> /// 复制构造函数 /// </summary> /// <param name="t"></param> internal GeneralDigest(GeneralDigest t) { XBuf = new byte[t.XBuf.Length]; Array.Copy(t.XBuf, 0, XBuf, 0, t.XBuf.Length); XBufOff = t.XBufOff; ByteCount = t.ByteCount; } /// <summary> /// 用一个字节更新消息摘要。 /// </summary> /// <param name="input"></param> public void Update(byte input) { XBuf[XBufOff++] = input; if (XBufOff == XBuf.Length) { ProcessWord(XBuf, 0); XBufOff = 0; } ByteCount++; } /// <summary> /// 用字节块更新消息摘要 /// </summary> /// <param name="input"></param> /// <param name="inOff"></param> /// <param name="length"></param> public void BlockUpdate(byte[] input, int inOff, int length) { //更新当前消息摘要 while ((XBufOff != 0) && (length > 0)) { Update(input[inOff]); inOff++; length--; } //处理完整的消息摘要 while (length > XBuf.Length) { ProcessWord(input, inOff); inOff += XBuf.Length; length -= XBuf.Length; ByteCount += XBuf.Length; } //填充剩余的消息摘要 while (length > 0) { Update(input[inOff]); inOff++; length--; } } /// <summary> /// 产生最终的摘要值 /// </summary> public void Finish() { long bitLength = (ByteCount << 3); //添加字节 Update(unchecked((byte)128)); while (XBufOff != 0) Update(unchecked((byte)0)); ProcessLength(bitLength); ProcessBlock(); } /// <summary> /// 重启 /// </summary> public virtual void Reset() { ByteCount = 0; XBufOff = 0; Array.Clear(XBuf, 0, XBuf.Length); } /// <summary> /// 摘要应用其压缩功能的内部缓冲区的大小 /// </summary> /// <returns></returns> public int GetByteLength() { return ByteLength; } /// <summary> /// 处理消息摘要 /// ABCDEFGH 串联 /// </summary> /// <param name="input"></param> /// <param name="inOff"></param> internal abstract void ProcessWord(byte[] input, int inOff); internal abstract void ProcessLength(long bitLength); /// <summary> /// 迭代压缩 /// </summary> internal abstract void ProcessBlock(); /// <summary> /// 算法名称 /// </summary> public abstract string AlgorithmName { get; } /// <summary> /// 消息摘要生成的摘要的大小 /// </summary> /// <returns></returns> public abstract int GetDigestSize(); /// <summary> /// 关闭摘要,产生最终的摘要值。doFinal调用使摘要复位。 /// </summary> /// <param name="output"></param> /// <param name="outOff"></param> /// <returns></returns> public abstract int DoFinal(byte[] output, int outOff); } 1.2 执行无符号按位右移 /// <summary> /// 使用指定的数字执行无符号按位右移 /// </summary> public class SupportClass { /// <summary> /// 使用指定的数字执行无符号按位右移 /// </summary> /// <param name="number">要操作的编号</param> /// <param name="bits">要移位的比特数</param> /// <returns>移位操作产生的数字</returns> public static int URShift(int number, int bits) { if (number >= 0) return number >> bits; else return (number >> bits) + (2 << ~bits); } /// <summary> /// 使用指定的数字执行无符号按位右移 /// </summary> /// <param name="number">要操作的编号</param> /// <param name="bits">要移位的比特数</param> /// <returns>移位操作产生的数字</returns> public static int URShift(int number, long bits) { return URShift(number, (int)bits); } /// <summary> /// 使用指定的数字执行无符号按位右移 /// </summary> /// <param name="number">要操作的编号</param> /// <param name="bits">要移位的比特数</param> /// <returns>移位操作产生的数字</returns> public static long URShift(long number, int bits) { if (number >= 0) return number >> bits; else return (number >> bits) + (2L << ~bits); } /// <summary> /// 使用指定的数字执行无符号按位右移 /// </summary> /// <param name="number">要操作的编号</param> /// <param name="bits">要移位的比特数</param> /// <returns>移位操作产生的数字</returns> public static long URShift(long number, long bits) { return URShift(number, (int)bits); } } 1.3 SM3处理 /// <summary> /// /// ⊕ 等价于 ^ /// ^ 等价于 & /// v 等价于 | /// </summary> public class SM3Digest : GeneralDigest { public override string AlgorithmName { get { return "SM3"; } } /// <summary> /// 消息摘要生成的摘要的大小 /// </summary> /// <returns></returns> public override int GetDigestSize() { return DigestLength; } /// <summary> /// SM3算法产生的哈希值大小 /// </summary> private const int DigestLength = 32; /// <summary> /// 初始值IV /// </summary> private static readonly int[] IV = new int[] { 0x7380166f, 0x4914b2b9, 0x172442d7, unchecked((int)0xda8a0600), unchecked((int)0xa96f30bc), 0x163138aa, unchecked((int)0xe38dee4d), unchecked((int)0xb0fb0e4e) }; /// <summary> /// 备份的字寄存器 /// </summary> private readonly int[] v = new int[8]; /// <summary> /// 使用中的字寄存器 /// </summary> private readonly int[] v_ = new int[8]; private static readonly int[] X0 = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; private readonly int[] X = new int[68]; private int xOff; /// <summary> /// 0到15的Tj常量 /// </summary> private readonly int TOne = 0x79cc4519; /// <summary> /// 16到63的Tj常量 /// </summary> private readonly int TSecond = 0x7a879d8a; public SM3Digest() { Reset(); } /// <summary> /// 复制构造函数 /// </summary> /// <param name="t"></param> public SM3Digest(SM3Digest t) : base(t) { Array.Copy(t.X, 0, X, 0, t.X.Length); xOff = t.xOff; Array.Copy(t.v, 0, v, 0, t.v.Length); } /// <summary> /// 将复制的对象状态还原到该对象。 /// 此方法的实现应尝试避免或最小化内存分配以执行重置。 /// </summary> public override void Reset() { base.Reset(); Array.Copy(IV, 0, v, 0, IV.Length); xOff = 0; Array.Copy(X0, 0, X, 0, X0.Length); } internal override void ProcessBlock() { int j; int[] ww = X; //64位比特串 int[] ww_ = new int[64]; #region 块消息扩展 //消息扩展16 TO 67 for (j = 16; j < 68; j++) { ww[j] = P1(ww[j - 16] ^ ww[j - 9] ^ (Rotate(ww[j - 3], 15))) ^ (Rotate(ww[j - 13], 7)) ^ ww[j - 6]; } //消息扩展0 TO 63 for (j = 0; j < 64; j++) { ww_[j] = ww[j] ^ ww[j + 4]; } #endregion #region 压缩函数 int[] vv = v; int[] vv_ = v_;//A,B,C,D,E,F,G,H为字寄存器 Array.Copy(vv, 0, vv_, 0, IV.Length); //中间变量SS1,SS2,TT1,TT2 int SS1, SS2, TT1, TT2; int aaa; //将消息分组B(i)划分为16个字 for (j = 0; j < 16; j++) { aaa = Rotate(vv_[0], 12); SS1 = aaa + vv_[4] + Rotate(TOne, j); SS1 = Rotate(SS1, 7); SS2 = SS1 ^ aaa; TT1 = FFOne(vv_[0], vv_[1], vv_[2]) + vv_[3] + SS2 + ww_[j]; TT2 = GGOne(vv_[4], vv_[5], vv_[6]) + vv_[7] + SS1 + ww[j]; #region 更新各个寄存器 vv_[3] = vv_[2]; vv_[2] = Rotate(vv_[1], 9); vv_[1] = vv_[0]; vv_[0] = TT1; vv_[7] = vv_[6]; vv_[6] = Rotate(vv_[5], 19); vv_[5] = vv_[4]; vv_[4] = P0(TT2); #endregion } for (j = 16; j < 64; j++) { aaa = Rotate(vv_[0], 12); SS1 = aaa + vv_[4] + Rotate(TSecond, j); SS1 = Rotate(SS1, 7); SS2 = SS1 ^ aaa; TT1 = FFSecond(vv_[0], vv_[1], vv_[2]) + vv_[3] + SS2 + ww_[j]; TT2 = GGSecond(vv_[4], vv_[5], vv_[6]) + vv_[7] + SS1 + ww[j]; #region 更新各个寄存器 vv_[3] = vv_[2]; vv_[2] = Rotate(vv_[1], 9); vv_[1] = vv_[0]; vv_[0] = TT1; vv_[7] = vv_[6]; vv_[6] = Rotate(vv_[5], 19); vv_[5] = vv_[4]; vv_[4] = P0(TT2); #endregion } #endregion //256比特的杂凑值y =vv_(j+1) ABCDEFGH for (j = 0; j < 8; j++) { vv[j] ^= vv_[j]; } // Reset xOff = 0; Array.Copy(X0, 0, X, 0, X0.Length); } internal override void ProcessWord(byte[] in_Renamed, int inOff) { int n = in_Renamed[inOff] << 24; n |= (in_Renamed[++inOff] & 0xff) << 16; n |= (in_Renamed[++inOff] & 0xff) << 8; n |= (in_Renamed[++inOff] & 0xff); X[xOff] = n; if (++xOff == 16) { ProcessBlock(); } } internal override void ProcessLength(long bitLength) { if (xOff > 14) { ProcessBlock(); } X[14] = (int)(SupportClass.URShift(bitLength, 32)); X[15] = (int)(bitLength & unchecked((int)0xffffffff)); } /// <summary> /// 写入到大端 /// </summary> /// <param name="n"></param> /// <param name="bs"></param> /// <param name="off"></param> public static void IntToBigEndian(int n, byte[] bs, int off) { bs[off] = (byte)(SupportClass.URShift(n, 24)); bs[++off] = (byte)(SupportClass.URShift(n, 16)); bs[++off] = (byte)(SupportClass.URShift(n, 8)); bs[++off] = (byte)(n); } /// <summary> /// 关闭摘要,产生最终的摘要值。doFinal调用使摘要复位。 /// </summary> /// <param name="out_Renamed"></param> /// <param name="outOff"></param> /// <returns></returns> public override int DoFinal(byte[] out_Renamed, int outOff) { Finish(); for (int i = 0; i < 8; i++) { IntToBigEndian(v[i], out_Renamed, outOff + i * 4); } Reset(); return DigestLength; } /// <summary> /// x循环左移n比特运算 /// </summary> /// <param name="x"></param> /// <param name="n"></param> /// <returns></returns> private static int Rotate(int x, int n) { return (x << n) | (SupportClass.URShift(x, (32 - n))); } #region 置换函数 /// <summary> /// 置换函数P0 /// </summary> /// <param name="x"></param> /// <returns></returns> private static int P0(int x) { return (x) ^ Rotate(x, 9) ^ Rotate(x, 17); } /// <summary> /// 置换函数P1 /// </summary> /// <param name="x"></param> /// <returns></returns> private static int P1(int x) { return (x) ^ Rotate(x, 15) ^ Rotate(x, 23); } #endregion #region 布尔函数 /// <summary> /// 0到15的布尔函数FF (X⊕^Y⊕Z) /// </summary> /// <param name="X"></param> /// <param name="Y"></param> /// <param name="Z"></param> /// <returns></returns> private static int FFOne(int X, int Y, int Z) { return (X ^ Y ^ Z); } /// <summary> /// 16到63的布尔函数FF /// </summary> /// <param name="X"></param> /// <param name="Y"></param> /// <param name="Z"></param> /// <returns></returns> private static int FFSecond(int X, int Y, int Z) { return ((X & Y) | (X & Z) | (Y & Z)); } /// <summary> /// 0到15的布尔函数GG /// </summary> /// <param name="X"></param> /// <param name="Y"></param> /// <param name="Z"></param> /// <returns></returns> private static int GGOne(int X, int Y, int Z) { return (X ^ Y ^ Z); } /// <summary> /// 16到63的布尔函数GG /// 全部评论
专题导读
热门推荐
热门话题
阅读排行榜
|
请发表评论