zoukankan      html  css  js  c++  java
  • C#实现SM3国密加密

    本文主要讲解“国密加密算法”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
            /// </summary>
            /// <param name="X"></param>
            /// <param name="Y"></param>
            /// <param name="Z"></param>
            /// <returns></returns>
            private static int GGSecond(int X, int Y, int Z)
            {
                return ((X & Y) | (~X & Z));
            }
            #endregion
        }

    1.4调用

        /// <summary>
        /// Sm3算法(10进制的ASCII)  
        /// 在SHA-256基础上改进实现的一种算法  
        /// 对标国际MD5算法和SHA算法
        /// </summary>
        public static class Sm3Crypto
        {
            /// <summary>
            /// sm3加密(使用自定义密钥)
            /// </summary>
            /// <param name="data"></param>
            /// <returns></returns>
            public static byte[] ToSM3byte(string data, string key)
            {
                byte[] msg1 = Encoding.Default.GetBytes(data);
                byte[] key1 = Encoding.Default.GetBytes(key);
    
                KeyParameter keyParameter = new KeyParameter(key1); 
                SM3Digest sm3 = new SM3Digest();
    
                HMac mac = new HMac(sm3);//带密钥的杂凑算法
                mac.Init(keyParameter);
                mac.BlockUpdate(msg1, 0, msg1.Length);
                byte[] result = new byte[mac.GetMacSize()];
    
                mac.DoFinal(result, 0);
                return Hex.Encode(result);
            }
    
            /// <summary>
            /// sm3加密
            /// </summary>
            /// <param name="data"></param>
            /// <returns></returns>
            public static byte[] ToSM3byte(this string data)
            { 
                var msg = data.ToHexByte();//把字符串转成16进制的ASCII码 
                SM3Digest sm3 = new SM3Digest();
                sm3.BlockUpdate(msg, 0, msg.Length);
                byte[] md = new byte[sm3.GetDigestSize()];//SM3算法产生的哈希值大小
                sm3.DoFinal(md, 0);
                return Hex.Encode(md);
            }
    /// <summary> /// 字符串转16进制字节数组 /// </summary> /// <param name="data"></param> /// <returns></returns> public byte[] ToHexByte(string data) { byte[] msg1 = Encoding.Default.GetBytes(data); string hexString = BytesToHexString(msg1); byte[] returnBytes = new byte[hexString.Length / 2]; for (int i = 0; i < returnBytes.Length; i++) returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 10); return returnBytes; }
    /// <summary> /// byte[]数组转16进制字符串 /// </summary> /// <param name="input">byte[]数组</param> /// <returns>16进制字符串</returns> public string BytesToHexString(byte[] input) { StringBuilder hexString = new StringBuilder(64); for (int i = 0; i < input.Length; i++) { hexString.Append(String.Format("{0:X2}", input[i])); } return hexString.ToString(); } }
  • 相关阅读:
    C# Sleep延时方法
    浅谈模糊测试
    python time模块常用方法小结
    Markdown使用小结
    关于测试用例设计、评审及用例质量评估的思考
    关于评估软件产品质量的思考
    关于软件测试工程师进阶提升的思考
    关于软件测试中回归测试的思考
    测试技术的思考 ---- 读《微软的软件测试之道》有感系列
    vue-learning:22
  • 原文地址:https://www.cnblogs.com/raniynight/p/14077903.html
Copyright © 2011-2022 走看看