【C#】各种加密算法

算法 密钥类型 加密解密的特点
对称加密算法 通讯双方有且只有一个共同的密钥K 加密方使用密钥K加密,解密方使用密钥K解密
非对称加密算法 密钥有分私钥和公钥; 通讯双方分别持有自己的私钥和对方的公钥;密方使用自己的私钥加密数据,解密方使用对方的公钥解密数据;加密方使用对方的公钥加密数据,解密方使用自己的私钥解密数据;
不可逆加密算法 加密后不可解密成原有明文

对称加密算法

DES

已破解,不再安全,基本没有企业在用了

3DES

计算密钥时间太长、加密效率不高,所以也基本上不用

IDEA

常用的电子邮件加密算法
工作模式只有ECB
密钥长度128位
算法公开、计算量小、加密速度快、加密效率高、被破解风险高。

AES

最常用的对称加密算法
密钥建立时间短、灵敏性好、内存需求低(不管怎样,反正就是好)
实际使用中,使用工作模式为CTR(最好用BC去实现),此工作模式需要引入IV参数(16位的字节数组)
密钥长度128/192/256,其中192与256需要配置无政策限制权限文件(JDK6)
填充模式最常用的两种PKCS5Padding和PKCS7Padding,其中后者只有BC独有。

#region AES加密解密
        /// <summary>
        ///  AES base64 加密算法;Key 为16位
        /// </summary>
        /// <param name="Data">需要加密的字符串</param>
        /// <returns></returns>
        public static string RST_AesEncrypt_Base64(string Data)
        {
    
    
            if (string.IsNullOrEmpty(Data))
            {
    
    
                return null;
            }
            if (string.IsNullOrEmpty(Key))
            {
    
    
                return null;
            }
            string Vector = Key.Substring(0, 16);
            Byte[] plainBytes = Encoding.UTF8.GetBytes(Data);
            Byte[] bKey = new Byte[32];
            Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);
            Byte[] bVector = new Byte[16];
            Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length);
            Byte[] Cryptograph = null; // 加密后的密文  
            Rijndael Aes = Rijndael.Create();
            //add 
            Aes.Mode = CipherMode.CBC;//兼任其他语言的des
            Aes.BlockSize = 128;
            Aes.Padding = PaddingMode.PKCS7;
            //add end
            try
            {
    
    
                // 开辟一块内存流  
                using (MemoryStream Memory = new MemoryStream())
                {
    
    
                    // 把内存流对象包装成加密流对象  
                    using (CryptoStream Encryptor = new CryptoStream(Memory,
                     Aes.CreateEncryptor(bKey, bVector),
                     CryptoStreamMode.Write))
                    {
    
    
                        // 明文数据写入加密流  
                        Encryptor.Write(plainBytes, 0, plainBytes.Length);
                        Encryptor.FlushFinalBlock();

                        Cryptograph = Memory.ToArray();
                    }
                }
            }
            catch
            {
    
    
                Cryptograph = null;
            }
            return Convert.ToBase64String(Cryptograph);
        }

        /// <summary>
        ///  AES base64 解密算法;Key为16位
        /// </summary>
        /// <param name="Data">需要解密的字符串</param>
        /// <param name="Key">Key为16位 密钥</param>
        /// <returns></returns>
        public static string RST_AesDecrypt_Base64(string Data)
        {
    
    
            try
            {
    
    
                if (string.IsNullOrEmpty(Data))
                {
    
    
                    return null;
                }
                if (string.IsNullOrEmpty(Key))
                {
    
    
                    return null;
                }
                string Vector = Key.Substring(0, 16);
                Byte[] encryptedBytes = Convert.FromBase64String(Data);
                Byte[] bKey = new Byte[32];
                Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);
                Byte[] bVector = new Byte[16];
                Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length);
                Byte[] original = null; // 解密后的明文  
                Rijndael Aes = Rijndael.Create();
                //add 
                Aes.Mode = CipherMode.CBC;//兼任其他语言的des
                Aes.BlockSize = 128;
                Aes.Padding = PaddingMode.PKCS7;
                //add end
                try
                {
    
    
                    // 开辟一块内存流,存储密文  
                    using (MemoryStream Memory = new MemoryStream(encryptedBytes))
                    {
    
    
                        //把内存流对象包装成加密流对象  
                        using (CryptoStream Decryptor = new CryptoStream(Memory,
                        Aes.CreateDecryptor(bKey, bVector),
                        CryptoStreamMode.Read))
                        {
    
    
                            // 明文存储区  
                            using (MemoryStream originalMemory = new MemoryStream())
                            {
    
    
                                Byte[] Buffer = new Byte[1024];
                                Int32 readBytes = 0;
                                while ((readBytes = Decryptor.Read(Buffer, 0, Buffer.Length)) > 0)
                                {
    
    
                                    originalMemory.Write(Buffer, 0, readBytes);
                                }
                                original = originalMemory.ToArray();
                            }
                        }
                    }
                }
                catch
                {
    
    
                    original = null;
                }
                return Encoding.UTF8.GetString(original);
            }
            catch {
    
     return null; }
        }

        /// <summary>
        /// 密钥16位或者32位的AES base64加密
        /// </summary>
        /// <param name="value">需要进行加密的明文字符串</param>
        /// <param name="key">16位或者32位的密钥</param>
        /// <param name="iv">16位以上的向量;默认为:"*Gc_Yy_Cq_@_Ztl_99*"</param>
        /// <returns>AES加密之后的密文</returns>
        public static string AesEncrypt(string value, string key, string iv = "")
        {
    
    
            if (string.IsNullOrEmpty(value)) return string.Empty;
            if (string.IsNullOrEmpty(key))
            {
    
    
                key = Key;
            }
            if (key.Length < 16) throw new Exception("指定的密钥长度不能少于16位。");
            if (key.Length > 32) throw new Exception("指定的密钥长度不能多于32位。");
            if (key.Length != 16 && key.Length != 24 && key.Length != 32) throw new Exception("指定的密钥长度不明确。");
            if (string.IsNullOrEmpty(iv))
            {
    
    
                iv = vector;
            }
            if (!string.IsNullOrEmpty(iv))
            {
    
    
                if (iv.Length < 16) throw new Exception("指定的向量长度不能少于16位。");
            }

            var _keyByte = Encoding.UTF8.GetBytes(key);
            var _valueByte = Encoding.UTF8.GetBytes(value);
            using (var aes = new RijndaelManaged())
            {
    
    
                aes.IV = !string.IsNullOrEmpty(iv) ? Encoding.UTF8.GetBytes(iv) : Encoding.UTF8.GetBytes(key.Substring(0, 16));
                aes.Key = _keyByte;
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.PKCS7;
                var cryptoTransform = aes.CreateEncryptor();
                var resultArray = cryptoTransform.TransformFinalBlock(_valueByte, 0, _valueByte.Length);
                return Convert.ToBase64String(resultArray, 0, resultArray.Length);
            }
        }

        /// <summary>
        /// 密钥16位或者32位的AES base64解密
        /// </summary>
        /// <param name="value">需要解密的密文</param>
        /// <param name="key">16位或者32位的密钥需和加密时的密钥保持一致</param>
        /// <param name="iv">16位以上的向量需和加密时的向量保持一致;默认为:"*Gc_Yy_Cq_@_Ztl_99*"</param>
        /// <returns>AES解密之后的明文</returns>
        public static string AesDecrypt(string value, string key, string iv = "")
        {
    
    
            if (string.IsNullOrEmpty(value)) return string.Empty;
            if (string.IsNullOrEmpty(key))
            {
    
    
                key = Key;
            }
            if (key.Length < 16) throw new Exception("指定的密钥长度不能少于16位。");
            if (key.Length > 32) throw new Exception("指定的密钥长度不能多于32位。");
            if (key.Length != 16 && key.Length != 24 && key.Length != 32) throw new Exception("指定的密钥长度不明确。");
            if (string.IsNullOrEmpty(iv))
            {
    
    
                iv = vector;
            }
            if (!string.IsNullOrEmpty(iv))
            {
    
    
                if (iv.Length < 16) throw new Exception("指定的向量长度不能少于16位。");
            }

            var _keyByte = Encoding.UTF8.GetBytes(key);
            var _valueByte = Convert.FromBase64String(value);
            using (var aes = new RijndaelManaged())
            {
    
    
                aes.IV = !string.IsNullOrEmpty(iv) ? Encoding.UTF8.GetBytes(iv) : Encoding.UTF8.GetBytes(key.Substring(0, 16));
                aes.Key = _keyByte;
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.PKCS7;
                var cryptoTransform = aes.CreateDecryptor();
                var resultArray = cryptoTransform.TransformFinalBlock(_valueByte, 0, _valueByte.Length);
                return Encoding.UTF8.GetString(resultArray);
            }
        }
        #endregion

非对称加密算法

RSA

RSA公钥加密算法是1977年由罗纳德·李维斯特
(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。RSA就是他们三人姓氏开头字母拼在一起组成的
RSA是目前最有影响力和最常用的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。
加密和解密花费时间长、速度慢,它不适合于对文件加密而只适用于对少量数据进行加密。

   #region RSA加密解密:采用公钥,私钥的模式

        #region 私钥加密,公钥解密

        /// <summary>
        /// RSA私钥加密
        /// </summary>
        /// <param name="privateKey">Java格式的RSA私钥 base64格式</param>
        /// <param name="contentData">待加密的数据;调用方法Encoding.GetEncoding("UTF-8").GetBytes(contentData)</param>
        /// <param name="algorithm">加密算法</param>
        /// <returns>RSA私钥加密之后的密文</returns>
        public static string EncryptWithPrivateKey(string privateKey, byte[] contentData, string algorithm = "RSA/ECB/PKCS1Padding")
        {
    
    
            return Convert.ToBase64String(EncryptWithPrivateKey(Convert.FromBase64String(privateKey), contentData, algorithm));
        }

        private static byte[] Transform(AsymmetricKeyParameter key, byte[] contentData, string algorithm, bool forEncryption)
        {
    
    
            var c = CipherUtilities.GetCipher(algorithm);
            c.Init(forEncryption, new ParametersWithRandom(key));
            return c.DoFinal(contentData);
        }

        /// <summary>
        /// RSA私钥加密
        /// </summary>
        /// <param name="privateKey">Java格式的RSA私钥</param>
        /// <param name="contentData">待加密的数据;调用方法Encoding.GetEncoding("UTF-8").GetBytes(contentData)</param>
        /// <param name="algorithm">加密算法</param>
        /// <returns>RSA私钥加密之后的密文</returns>
        public static byte[] EncryptWithPrivateKey(byte[] privateKey, byte[] contentData, string algorithm = "RSA/ECB/PKCS1Padding")
        {
    
    
            RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(privateKey);
            return Transform(privateKeyParam, contentData, algorithm, true);
        }

        /// <summary>
        /// RSA公钥解密
        /// </summary>
        /// <param name="publicKey">Java格式的RSA公钥  base64格式</param>
        /// <param name="content">待解密数据 base64格式</param>
        /// <param name="encoding">解密出来的数据编码格式,默认UTF-8</param>
        /// <param name="algorithm">加密算法</param>
        /// <returns>RSA私钥解密之后的明文</returns>
        public static string DecryptWithPublicKey(string publicKey, string content, string encoding = "UTF-8", string algorithm = "RSA/ECB/PKCS1Padding")
        {
    
    
            return Encoding.GetEncoding(encoding).GetString(DecryptWithPublicKey(Convert.FromBase64String(publicKey), Convert.FromBase64String(content), algorithm));
        }

        /// <summary>
        /// RSA公钥解密
        /// </summary>
        /// <param name="publicKey">Java格式的RSA公钥</param>
        /// <param name="contentData">待解密数据</param>
        /// <param name="algorithm">加密算法</param>
        /// <returns>RSA私钥解密之后的明文</returns>
        public static byte[] DecryptWithPublicKey(byte[] publicKey, byte[] contentData, string algorithm = "RSA/ECB/PKCS1Padding")
        {
    
    
            RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(publicKey);
            return Transform(publicKeyParam, contentData, algorithm, false);
        }
        #endregion

        #region 公钥加密,私钥解密

        /// <summary>
        /// RSA公钥加密
        /// </summary>
        /// <param name="xmlPublicKey">加密公钥;为空则默认系统公钥</param>
        /// <param name="enptStr">需要加密的明文字符串</param>
        /// <param name="encoding">编码格式;默认:UTF-8</param>
        /// <returns>RSA公钥加密的密文</returns>
        public static string RSAEncrypt_Public(string xmlPublicKey, string enptStr, string encoding = "UTF-8")
        {
    
    
            if (string.IsNullOrEmpty(xmlPublicKey))
            {
    
    
                xmlPublicKey = _publicKey;
            }
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
    
    
                byte[] cipherbytes;
                rsa.FromXmlString(xmlPublicKey);
                cipherbytes = rsa.Encrypt(Encoding.GetEncoding(encoding).GetBytes(enptStr), false);
                return Convert.ToBase64String(cipherbytes);
            }
        }

        /// <summary>
        /// RSA私钥解密
        /// </summary>
        /// <param name="xmlPrivateKey">解密私钥;为空则默认系统公钥</param>
        /// <param name="enptStr">需要加密的明文字符串</param>
        /// <param name="encoding">编码格式;默认:UTF-8</param>
        /// <returns>RSA私钥解密的明文</returns>
        public static string RSADecrypt_Private(string xmlPrivateKey, string enptStr, string encoding = "UTF-8")
        {
    
    
            if (string.IsNullOrEmpty(xmlPrivateKey))
            {
    
    
                xmlPrivateKey = _privateKey;
            }
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
    
    
                byte[] cipherbytes;
                rsa.FromXmlString(xmlPrivateKey);
                cipherbytes = rsa.Decrypt(Convert.FromBase64String(enptStr), false);
                return Encoding.GetEncoding(encoding).GetString(cipherbytes);
            }
        }
        #endregion

        #region 使用同一容器的名称进行RSA加密解密

        /// <summary>
        /// 进行 RSA 加密
        /// </summary>
        /// <param name="sourceStr">源字符串</param>
        /// <returns>加密后字符串</returns>
        public static string RsaEncrypt(string sourceStr)
        {
    
    
            Param = new CspParameters();
            //密匙容器的名称,保持加密解密一致才能解密成功
            Param.KeyContainerName = "Navis";
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(Param))
            {
    
    
                //将要加密的字符串转换成字节数组
                byte[] plaindata = Encoding.Default.GetBytes(sourceStr);
                //通过字节数组进行加密
                byte[] encryptdata = rsa.Encrypt(plaindata, false);
                //将加密后的字节数组转换成字符串
                return Convert.ToBase64String(encryptdata);
            }
        }

        /// <summary>
        /// 通过RSA 加密方式进行解密
        /// </summary>
        /// <param name="codingStr">加密字符串</param>
        /// <returns>解密后字符串</returns>
        public static string RsaDesEncrypt(string codingStr)
        {
    
    
            Param = new CspParameters();
            Param.KeyContainerName = "Navis";
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(Param))
            {
    
    
                byte[] encryptdata = Convert.FromBase64String(codingStr);
                byte[] decryptdata = rsa.Decrypt(encryptdata, false);
                return Encoding.Default.GetString(decryptdata);
            }
        }
        #endregion

        #region RSA分段加密:待加密的字符串拆开,每段长度都小于等于限制长度,然后分段加密

        /// <summary>
        /// RSA分段加密
        /// </summary>
        /// <param name="xmlPublicKey">RSA C#公钥</param>
        /// <param name="enptStr">需要进行RSA加密的长字符串</param>
        /// <returns>返回RSA加密后的密文</returns>
        public static String SubRSAEncrypt(string xmlPublicKey, string enptStr)
        {
    
    
            RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
            provider.FromXmlString(xmlPublicKey);
            Byte[] bytes = Encoding.Default.GetBytes(enptStr);
            int MaxBlockSize = provider.KeySize / 8 - 11;  //加密块最大长度限制

            if (bytes.Length <= MaxBlockSize)
                return Convert.ToBase64String(provider.Encrypt(bytes, false));

            using (MemoryStream PlaiStream = new MemoryStream(bytes))
            using (MemoryStream CrypStream = new MemoryStream())
            {
    
    
                Byte[] Buffer = new Byte[MaxBlockSize];
                int BlockSize = PlaiStream.Read(Buffer, 0, MaxBlockSize);

                while (BlockSize > 0)
                {
    
    
                    Byte[] ToEncrypt = new Byte[BlockSize];
                    Array.Copy(Buffer, 0, ToEncrypt, 0, BlockSize);

                    Byte[] Cryptograph = provider.Encrypt(ToEncrypt, false);
                    CrypStream.Write(Cryptograph, 0, Cryptograph.Length);

                    BlockSize = PlaiStream.Read(Buffer, 0, MaxBlockSize);
                }

                return Convert.ToBase64String(CrypStream.ToArray(), Base64FormattingOptions.None);
            }

        }

        /// <summary>
        /// RSA分段解密,应对长字符串
        /// </summary>
        /// <param name="xmlPrivateKey">RSA C#私钥</param>
        /// <param name="enptStr">需要解密的长字符串</param>
        /// <returns>返回RSA分段解密的明文</returns>
        public static String SubRSADecrypt(string xmlPrivateKey, string enptStr)
        {
    
    
            RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
            provider.FromXmlString(xmlPrivateKey);
            Byte[] bytes = Convert.FromBase64String(enptStr);
            int MaxBlockSize = provider.KeySize / 8;  //解密块最大长度限制

            if (bytes.Length <= MaxBlockSize)
                return Encoding.Default.GetString(provider.Decrypt(bytes, false));

            using (MemoryStream CrypStream = new MemoryStream(bytes))
            using (MemoryStream PlaiStream = new MemoryStream())
            {
    
    
                Byte[] Buffer = new Byte[MaxBlockSize];
                int BlockSize = CrypStream.Read(Buffer, 0, MaxBlockSize);

                while (BlockSize > 0)
                {
    
    
                    Byte[] ToDecrypt = new Byte[BlockSize];
                    Array.Copy(Buffer, 0, ToDecrypt, 0, BlockSize);

                    Byte[] Plaintext = provider.Decrypt(ToDecrypt, false);
                    PlaiStream.Write(Plaintext, 0, Plaintext.Length);

                    BlockSize = CrypStream.Read(Buffer, 0, MaxBlockSize);
                }

                return Encoding.Default.GetString(PlaiStream.ToArray());
            }
        }
        #endregion

        #endregion

DSA

数字签名算法,是一种标准的 DSS(数字签名标准);

ECC(椭圆曲线加密算法)

ECC和RSA相比,在许多方面都有对绝对的优势,主要体现在以下方面:

  1. 抗攻击性强。相同的密钥长度,其抗攻击性要强很多倍。
  2. 计算量小,处理速度快。ECC总的速度比RSA、DSA要快得多。
  3. 存储空间占用小。ECC的密钥尺寸和系统参数与RSA、DSA相比要小得多,意味着它所占的存贮空间要小得多。这对于加密算法在IC卡上的应用具有特别重要的意义。
  4. 带宽要求低。当对长消息进行加解密时,三类密码系统有相同的带宽要求,但应用于短消息时ECC带宽要求却低得多。带宽要求低使ECC在无线网络领域具有广泛的应用前景。

SM2算法就是ECC椭圆曲线密码机制,但在签名、密钥交换方面不同于ECDSA、ECDH等国际标准,而是采取了更为安全的机制。另外,SM2推荐了一条256位的曲线作为标准曲线。属于国密,即国产密码算法(国密算法)是指国家密码局认定的国产商用密码算法

SM2主类

using System;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using System.Text;
 
namespace Com.Mlq.SM
{
    
    
	
	public class SM2
	{
    
    
		public static SM2 Instance
		{
    
    
			get
			{
    
    
				return new SM2();
			}
			
		}
		public static SM2 InstanceTest
		{
    
    
			get
			{
    
    
				return new SM2();
			}
			
		}
 
        public static readonly string[] sm2_param = {
    
    
			"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",// p,0
			"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",// a,1
			"28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",// b,2
			"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",// n,3
			"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",// gx,4
			"BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0" // gy,5
	    };
 
        public string[] ecc_param = sm2_param;
		
		public readonly BigInteger ecc_p;
		public readonly BigInteger ecc_a;
		public readonly BigInteger ecc_b;
		public readonly BigInteger ecc_n;
		public readonly BigInteger ecc_gx;
		public readonly BigInteger ecc_gy;
		
		public readonly ECCurve ecc_curve;
		public readonly ECPoint ecc_point_g;
		
		public readonly ECDomainParameters ecc_bc_spec;
		
		public readonly ECKeyPairGenerator ecc_key_pair_generator;
 
        private SM2()
		{
    
    
			ecc_param = sm2_param;
 
            ECFieldElement ecc_gx_fieldelement;
			ECFieldElement ecc_gy_fieldelement;
			
			ecc_p = new BigInteger(ecc_param[0], 16);
			ecc_a = new BigInteger(ecc_param[1], 16);
			ecc_b = new BigInteger(ecc_param[2], 16);
			ecc_n = new BigInteger(ecc_param[3], 16);
			ecc_gx = new BigInteger(ecc_param[4], 16);
			ecc_gy = new BigInteger(ecc_param[5], 16);
 
 
            ecc_gx_fieldelement = new FpFieldElement(ecc_p, ecc_gx);
            ecc_gy_fieldelement = new FpFieldElement(ecc_p, ecc_gy);
 
            ecc_curve = new FpCurve(ecc_p, ecc_a, ecc_b);
            ecc_point_g = new FpPoint(ecc_curve, ecc_gx_fieldelement, ecc_gy_fieldelement);
			
			ecc_bc_spec = new ECDomainParameters(ecc_curve, ecc_point_g, ecc_n);
			
			ECKeyGenerationParameters ecc_ecgenparam;
            ecc_ecgenparam = new ECKeyGenerationParameters(ecc_bc_spec, new SecureRandom());
			
			ecc_key_pair_generator = new ECKeyPairGenerator();
			ecc_key_pair_generator.Init(ecc_ecgenparam);
		}
 
        public virtual byte[] Sm2GetZ(byte[] userId, ECPoint userKey)
		{
    
    
			SM3Digest sm3 = new SM3Digest();
			byte[] p;
			// userId length
			int len = userId.Length * 8;
			sm3.Update((byte) (len >> 8 & 0x00ff));
			sm3.Update((byte) (len & 0x00ff));
			
			// userId
            sm3.BlockUpdate(userId, 0, userId.Length);
			
			// a,b
			p = ecc_a.ToByteArray();
            sm3.BlockUpdate(p, 0, p.Length);
            p = ecc_b.ToByteArray();
            sm3.BlockUpdate(p, 0, p.Length);
			// gx,gy
            p = ecc_gx.ToByteArray();
            sm3.BlockUpdate(p, 0, p.Length);
            p = ecc_gy.ToByteArray();
            sm3.BlockUpdate(p, 0, p.Length);
			
			// x,y
            p = userKey.X.ToBigInteger().ToByteArray();
            sm3.BlockUpdate(p, 0, p.Length);
            p = userKey.Y.ToBigInteger().ToByteArray();
            sm3.BlockUpdate(p, 0, p.Length);
			
			// Z
			byte[] md = new byte[sm3.GetDigestSize()];
			sm3.DoFinal(md, 0);
			
			return md;
		}
		
	}
}

SM2工具类

using Com.Mlq.SM;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Utilities.Encoders;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace Com.Mlq.SM
{
    
    
    class SM2Utils
    {
    
    
        public static void GenerateKeyPair()
        {
    
    
            SM2 sm2 = SM2.Instance;
            AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.GenerateKeyPair();  
            ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.Private;  
            ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.Public;  
            BigInteger privateKey = ecpriv.D;  
            ECPoint publicKey = ecpub.Q;
 
            System.Console.Out.WriteLine("公钥: " + Encoding.Default.GetString(Hex.Encode(publicKey.GetEncoded())).ToUpper());
            System.Console.Out.WriteLine("私钥: " + Encoding.Default.GetString(Hex.Encode(privateKey.ToByteArray())).ToUpper());  
        }
 
        public static String Encrypt(byte[] publicKey,byte[] data)
        {
    
    
            if (null == publicKey || publicKey.Length == 0)
            {
    
    
                return null;
            }
            if (data == null || data.Length == 0)
            {
    
    
                return null;
            }
 
            byte[] source = new byte[data.Length];
            Array.Copy(data, 0, source, 0, data.Length);
 
            Cipher cipher = new Cipher();
            SM2 sm2 = SM2.Instance;
 
            ECPoint userKey = sm2.ecc_curve.DecodePoint(publicKey);
 
            ECPoint c1 = cipher.Init_enc(sm2, userKey);
            cipher.Encrypt(source);
 
            byte[] c3 = new byte[32];
            cipher.Dofinal(c3);
 
            String sc1 = Encoding.Default.GetString(Hex.Encode(c1.GetEncoded()));
            String sc2 = Encoding.Default.GetString(Hex.Encode(source));
            String sc3 = Encoding.Default.GetString(Hex.Encode(c3));
 
            return (sc1 + sc2 + sc3).ToUpper();
        }
 
        public static byte[] Decrypt(byte[] privateKey, byte[] encryptedData)
        {
    
    
            if (null == privateKey || privateKey.Length == 0)
            {
    
    
                return null;
            }
            if (encryptedData == null || encryptedData.Length == 0)
            {
    
    
                return null;
            }
 
            String data = Encoding.Default.GetString(Hex.Encode(encryptedData));
 
            byte[] c1Bytes = Hex.Decode(Encoding.Default.GetBytes(data.Substring(0 , 130)));
            int c2Len = encryptedData.Length - 97;
            byte[] c2 = Hex.Decode(Encoding.Default.GetBytes(data.Substring(130 , 2 * c2Len)));
            byte[] c3 = Hex.Decode(Encoding.Default.GetBytes(data.Substring(130 + 2 * c2Len , 64)));
 
            SM2 sm2 = SM2.Instance;
            BigInteger userD = new BigInteger(1, privateKey);
 
            ECPoint c1 = sm2.ecc_curve.DecodePoint(c1Bytes);
            Cipher cipher = new Cipher();
            cipher.Init_dec(userD, c1);
            cipher.Decrypt(c2);
            cipher.Dofinal(c3);
 
            return c2;
        }
 
        //[STAThread]
        //public static void Main()
        //{
    
    
        //    GenerateKeyPair();
 
        //    String plainText = "ererfeiisgod";
        //    byte[] sourceData = Encoding.Default.GetBytes(plainText);
 
        //    //下面的秘钥可以使用generateKeyPair()生成的秘钥内容  
        //    // 国密规范正式私钥  
        //    String prik = "3690655E33D5EA3D9A4AE1A1ADD766FDEA045CDEAA43A9206FB8C430CEFE0D94";
        //    // 国密规范正式公钥  
        //    String pubk = "04F6E0C3345AE42B51E06BF50B98834988D54EBC7460FE135A48171BC0629EAE205EEDE253A530608178A98F1E19BB737302813BA39ED3FA3C51639D7A20C7391A";
 
        //    System.Console.Out.WriteLine("加密: ");
        //    String cipherText = SM2Utils.Encrypt(Hex.Decode(pubk), sourceData);
        //    System.Console.Out.WriteLine(cipherText);
        //    System.Console.Out.WriteLine("解密: ");
        //    plainText = Encoding.Default.GetString(SM2Utils.Decrypt(Hex.Decode(prik), Hex.Decode(cipherText)));
        //    System.Console.Out.WriteLine(plainText);
 
        //    Console.ReadLine();
        //}
    }
}

不可逆加密算法(哈希、散列、摘要)

散列是信息的提炼,通常其长度要比信息小得多,且为一个固定长度。加密性强的散列一定是不可逆的,这就意味着通过散列结果,无法推出任何部分的原始信息。任何输入信息的变化,哪怕仅一位,都将导致散列结果的明显变化,这称之为雪崩效应。散列还应该是防冲突的,即找不出具有相同散列结果的两条信息。具有这些特性的散列结果就可以用于验证信息是否被修改。

SHA1

        /// <summary>
        /// SHA1 加密 
        /// </summary>
        /// <param name="content">需要加密字符串</param>
        /// <param name="encode">指定加密编码</param>
        /// <param name="upperOrLower">大小写格式(大写:X2;小写:x2)默认小写</param> 
        public static string SHA1Encrypt(string content, Encoding encode, string upperOrLower = "x2")
        {
    
    
            try
            {
    
    
                var buffer = encode.GetBytes(content);//用指定编码转为bytes数组
                var data = SHA1.Create().ComputeHash(buffer);
                var sb = new StringBuilder();
                foreach (var t in data)
                {
    
    
                    sb.Append(t.ToString(upperOrLower));
                }

                return sb.ToString();
            }
            catch (Exception ex)
            {
    
    
                return "SHA1加密出错:" + ex.Message;
            }
        }

        /// <summary>
        /// SHA256加密
        /// </summary>
        /// <param name="strIN">要加密的string字符串</param>
        /// <returns>SHA256加密之后的密文</returns>
        public static string SHA256Encrypt(string strIN)
        {
    
    
            byte[] tmpByte;
            SHA256 sha256 = new SHA256Managed();
            tmpByte = sha256.ComputeHash(GetKeyByteArray(strIN));

            StringBuilder rst = new StringBuilder();
            for (int i = 0; i < tmpByte.Length; i++)
            {
    
    
                rst.Append(tmpByte[i].ToString("x2"));
            }
            sha256.Clear();
            return rst.ToString();
        }
        
        /// <summary>
        /// 获取要加密的string字符串字节数组
        /// </summary>
        /// <param name="strKey">待加密字符串</param>
        /// <returns>加密数组</returns>
        private static byte[] GetKeyByteArray(string strKey)
        {
    
    
            UTF8Encoding Asc = new UTF8Encoding();
            int tmpStrLen = strKey.Length;
            byte[] tmpByte = new byte[tmpStrLen - 1];
            tmpByte = Asc.GetBytes(strKey);
            return tmpByte;
        }

MD5

MD5

 1 public static string EnMd5(string str)
 2 {
    
     
 3     string pwd = "";
 4     MD5 md5 = MD5.Create();
 5     //注意编码UTF8/Unicode
 6     byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(str));    
 7     for (int i = 0; i < s.Length; i++)
 8     {
    
    
 9         pwd = pwd + s[i].ToString("x2");
10     }
11     return pwd;
12 }

MD5(流Hash)

MD5(流Hash)

 1 public static string GetStreamMD5(Stream stream)
 2 {
    
    
 3     MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
 4 
 5     md5.ComputeHash(stream);
 6 
 7     byte[] hash = md5.Hash;
 8 
 9     StringBuilder result = new StringBuilder();
10 
11     foreach (byte byt in hash)
12     {
    
    
13         result.Append(String.Format("{0:X1}", byt));
14     }
15 
16     return result.ToString();
17 }

base64

        /// <summary>
        /// Base64解码
        /// </summary>
        /// <param name="s">需解码字符串</param>
        /// <returns></returns>
        public static string Decode(string s)
        {
    
    
            byte[] outputb = Convert.FromBase64String(s);
            return Encoding.Default.GetString(outputb);
        }

        /// <summary>
        /// Base64编码
        /// </summary>
        /// <param name="s">需编码字符串</param>
        /// <returns></returns>
        public static string EncodeByUTF8(string s)
        {
    
    
            System.Text.Encoding encode = System.Text.Encoding.UTF8;
            byte[] bytedata = encode.GetBytes(s);
            return Convert.ToBase64String(bytedata, 0, bytedata.Length);
        }

加密算法的选择

  1. 由于非对称加密算法的运行速度比对称加密算法的速度慢很多,当我们需要加密大量的数据时,建议采用对称加密算法,提高加解密速度。

  2. 对称加密算法不能实现签名,因此签名只能非对称算法。

  3. 由于对称加密算法的密钥管理是一个复杂的过程,密钥的管理直接决定着他的安全性,因此当数据量很小时,我们可以考虑采用非对称加密算法。

  4. 在实际的操作过程中,我们通常采用的方式是:采用非对称加密算法管理对称算法的密钥,然后用对称加密算法加密数据,这样我们就集成了两类加密算法的优点,既实现了加密速度快的优点,又实现了安全方便管理密钥的优点。

     那采用多少位的密钥呢?
    
     RSA建议采用1024位的数字,ECC建议采用160位,AES采用128为即可。
    

参考

【算法大杂烩】常见算法的归类和总结——非对称加密算法
【Java----加密解密】第十章 五种对称加密算法总结
【对称与非对称加密算法】
【C#】常用的加密算法:MD5、Base64、SHA1、SHA256、HmacSHA256、DES、AES、RSA
【C#】加密算法[汇总]
国密(国产密码)SM2、SM3、SM4 C#实现

猜你喜欢

转载自blog.csdn.net/weixin_44231544/article/details/125739924
今日推荐