.Net中加密解密相关知识

最近在看我所在项目系统里支付方面的代码,里面包括很多加密解密方面的知识,结合平时对加密解密的了解,对.net里加解密做一个总结。

最开始遇到加密解密,可能和大家一样,MD5加密,读大学的时候 ,我喜欢了解一些安全方面知识,当时很多小型网站都存在SQL注入,找个小工具,很轻松跑出用户帐号和密码,一看密码是16位或32位,一般都是MD5加密后没有再修改过,通过http://www.cmd5.com/ http://www.xmd5.org/ 等网站,直接就“解密”成原始明文了(但现在这些网站已开始收费了)。最后过了一段时间才知道,原来这个是Hash散列加密,不可逆的,这些网站都通过人工学把不同帐号跑出来存储到数据库,查询的时候从数据库查询了。

         .Net框架集成了常用加解密的类库,在System.Security.Cryptography命名空间下,包括可逆向加密和不可逆加密。可逆向加密又包括对称加密和非对称加密。

         对称加密常用的有DES(Data Encryption Standard),TripleDES(基于DES,对一块数据用三个不通密钥进行3次加密)DES的密钥Key8字节,初始向量IV也为8字节;TripleDES的密钥Key24字节,初始向量IV8字节。都以8字节为一个块进行加密。还有AES(Advanced Encryption Standard),根据我的理解,AES只是一个标准,现在一般用该标准的算法为Rijndael

         非对称加密常用的有RSA,它通过公钥加密,私钥解密,并且他还可以用私钥签名,公钥验证的功能,一般应用于网络交互,比如IPS支付时,我们需要向IPS申请一个公钥,我们通过公钥加密一些关键字符,就只有IPS的私钥才能解密了。但在使用过程中,常常添加了比如散列比较等,而且非对称算法比对称算法慢很多,非对称公钥加密也常用来加密较少字段或者加密临时对称加密Key使用。

         不可逆加密主要是散列算法加密,常见的有MD5SHA1算法。MD5可以生产16字节的不可逆数字,SHA1可以生成20字节的不可逆数字。MD5有时表现出来是32位的数字或字符,这是每个字节的16进制展现。经常能看到的16位的MD5值,是取的MD5从第8位到第23位(包括23)之间的数字。一般在下载一些软件的时候,也会提示该软件MD5值是多少,帮助下载下来后验证,可以写个小工具通过从读取软件到内存流,再计算MD5,来校验软件。

         下面直接写出TripleDES加密解密方法,步骤可以见注释:

        public static byte[] IV = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };//加密IV向量

 

        public static string EncryptString(string plainText, string key)

        {

            //如果Key不到24位,则用0补

            key = key.PadLeft(24, '0');

            byte[] bKey = Encoding.UTF8.GetBytes(key.Substring(0, 24));

            // 把字符串明文转换成utf-8编码的字节流

            byte[] plainTextArray = Encoding.UTF8.GetBytes(plainText);

            try

            {

                // 用MemoryStream存放加密后的数据流

                using (MemoryStream mStream = new MemoryStream())

                {

                    // 使用MemoryStream 和Key、IV新建一个CryptoStream 对象

                    using (CryptoStream cStream = new CryptoStream(mStream,

                        new TripleDESCryptoServiceProvider().CreateEncryptor(bKey, IV),

                        CryptoStreamMode.Write))

                    {

                        // 将加密后的字节流写入MemoryStream

                        cStream.Write(plainTextArray, 0, plainTextArray.Length);

                        //把缓冲区更新到MemoryStream

                        cStream.FlushFinalBlock();

 

                        // 把解密后的数据流转成字节流,并转换成Base64编码

                        return Convert.ToBase64String(mStream.ToArray());

                    }

                }

            }

            catch (Exception ex)

            {

                throw ex;

            }

        }

        public static string DecryptString(string encryptedData, string key)

        {

            //如果Key不到24位,则用0补

            key = key.PadLeft(24, '0');

            byte[] bKey = Encoding.UTF8.GetBytes(key.Substring(0, 24));

            // 把字符串明文转换成utf-8编码的字节流

            byte[] encryptedDataArray = Convert.FromBase64String(encryptedData);

            try

            {

                // MemoryStream存放加密后的数据流

                using (MemoryStream msDecrypt = new MemoryStream(encryptedDataArray))

                {

                    // 使用MemoryStream 和key、IV新建一个CryptoStream 对象

                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt,

                        new TripleDESCryptoServiceProvider().CreateDecryptor(bKey, IV),

                        CryptoStreamMode.Read))

                    {

                        byte[] decryptDataArray = new byte[encryptedDataArray.Length];

                        // 把解密后的数据读入到DecryptDataArray

                        csDecrypt.Read(decryptDataArray, 0, decryptDataArray.Length);

 

                        return Encoding.UTF8.GetString(decryptDataArray);

                    }

                }

            }

            catch (Exception ex)

            {

                throw ex;

            }

        }

这里加密用csDecrypt写到内存流中,解密用csDecrypt流读取解码后的字符读到临时byte[]变量里,其实都可以一样,这里不同方法都可以读写出来,最后加密的结果直接转换成Base64编码,方便网络传输。默认new TripleDESCryptoServiceProvider().IVKey就可以读取一个默认的KeyIV。除此之外,还有加密模式和填充模式的选择,这里用的默认模式,可以设置Mode,Padding来分别设置加密模式和填充模式,这块我也只是了解,当要求如果严格的时候,需要再仔细看下。

         RSA加密解密方法如下:

        public static string[] GenerateKeys()

        {

            string[] sKeys = new string[2];

            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

            //私钥

            sKeys[0] = rsa.ToXmlString(true);

            //公钥

            sKeys[1] = rsa.ToXmlString(false);

 

            return sKeys;

        }

 

        public static string EncryptString(string sSource, string sPublicKey)

        {

            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

            string plaintext = sSource;

            try

            {

                //导入公钥加密

                rsa.FromXmlString(sPublicKey);

                byte[] cipherbytes = rsa.Encrypt(Encoding.UTF8.GetBytes(plaintext), false);

 

                return Convert.ToBase64String(cipherbytes);

            }

            catch (Exception ex)

            {

                throw ex;

            }

        }

        public static string DecryptString(string sSource, string sPrivateKey)

        {

            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

            try

            {

                //导入私钥解密

                rsa.FromXmlString(sPrivateKey);

                byte[] byteEn = Convert.FromBase64String(sSource);

                byte[] plaintbytes = rsa.Decrypt(byteEn, false);

 

                return Encoding.UTF8.GetString(plaintbytes);

            }

            catch (Exception ex)

            {

                throw ex;

            }

        }

         由于非对称加密公钥和私钥表现成一个xml的字符串,这里用GenerateKeys方法返回一个默认的公钥私钥对。私钥类试:

<RSAKeyValue><Modulus>qZ0BKzsUNJR5x9TUYfAaDzuLuJ6uxT3eE9Zqd2MKQ+FmS1az43uH8bGHerWoStl2tSXUDENQ0AieaxFpn/BTJZ33rmT3PPxv6022vwB+17XYfCDigb7db30jKIefDydQMEC8P/4EAEp6/IiE4H35P+2dwoN3/p4U+C2aTFIpQ78=</Modulus><Exponent>AQAB</Exponent><P>7GkvmXofKoNwEUEtVtYT0Na04Ua4cZA25GfK5ZB8XsxMyTEr9pNMjNZLJlRAG1TeOSM2qOisofGfytQHidU/rw==</P><Q>t6rjt7IXXRF8/ye+bnzhvFvRv0fo0wObdYTuD8d4ruxLI8p847cfI+IGIyXGz7lXkLOuAVk5hVfpFqgx3WCw8Q==</Q><DP>VI0eIAcERIEzwIgN/iOcfLF9iaBwcPVCHJhegZIWWRU6VS6H6a0u0KQHxpKVRvEodUj50Jk+vMCdBL6mX45sMw==</DP><DQ>q/VsdL1h0HoiLIZabfmwI3lYHJ3H52C2OUY22UEpxaRoCV94pH77wc3JbzjcNfnSeSExJgQSrbyL9/GLljgEEQ==</DQ><InverseQ>ppiIZBMKM74wSwSyBVoYNjScnW2Hjf3kP+q15GONazTp9Gx8uSQViy8UI+GCqMT/8p5ySzVISwF2jWFw8uhhog==</InverseQ><D>KQ6QUd6jLXcjY3PpVSvBox5O3AnNVIF9WF/2tZ+LxJKzKFl8gfxNE/xdRx7h9fxd98uIYM+KqFDtyA0W/Fg4R+Uda1SHOLDgsdo1FISmQsCEK8E8jIINf7QeYTOPconvYDglznAfZBE0Ri+keLZPnsy6Pslths56wB40yW+GJwE=</D></RSAKeyValue>

公钥就只有ModulusExponent节点。

         散列算法MD5加密如:

 

        public static string GetMd5(string contents)

        {

            if (string.IsNullOrEmpty(contents))

            {

                return string.Empty;

            }

            StringBuilder result = new StringBuilder();

            System.Security.Cryptography.MD5CryptoServiceProvider md = new System.Security.Cryptography.MD5CryptoServiceProvider();

            byte[] hash = md.ComputeHash(System.Text.Encoding.UTF8.GetBytes(contents));

            md.Clear();

            for (int i = 0, len = hash.Length; i < len; i++)

            {

                //每个字符转换为16进制

                result.Append(hash[i].ToString("X").PadLeft(2, '0'));

            }

            return result.ToString();

        }

但在B/S网站中生产MD5值时,一般可以直接:

System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(source, "MD5");返回32位长的MD5值。

         以上介绍了可逆不可逆加密方式,和常用的加密解密算法,当然还有很多算法没有介绍,并且这些算法的深入使用也是有很多可以介绍的地方,但本篇作为抛砖引玉,以后更加深入使用时再仔细学习了解。

 

      最后上传测试代码,VS2008,.NET3.5下编译运行通过!

/Files/Lawson/EncryptionTests.rar

 

你可能感兴趣的:(.net)