加密解密算法以及对应.Net实现

引言

最近在倒弄数据存储传输过程中的加密解密方法,本文不是笔者亲身研究所得,而是对几篇博客中的知识点的学习摘抄记录,以作总结。

加密解密

说到加密,可能大家最熟悉的就是MD5了,它的用户密码就是采用的MD5进行加密。MD5实际上只是一种散列运算,或者可以称为单向的加密,
即是说无法根据密文(加密后的数据),推导出明文(原数据)。那么加密是什么呢?加密是通过对消息进行编码,建立一种安全的交流方式,
使得只有你和你所期望的接收者能够理解。那么怎么样才能叫安全呢?消息在接收方和发送方进行安全传递,一般要满足下面三个要点:
  1. 消息的发送方能够确定消息只有预期的接收方可以解密(不保证第三方无法获得,但保证第三方无法解密)。
  2. 消息的接收方可以确定消息是由谁发送的(消息的接收方可以确定消息的发送方)。
  3. 消息的接收方可以确定消息在途中没有被篡改过(必须确认消息的完整性)。
加密通常分为两种方式:对称加密和非对称加密,接下来我们先看看对称加密。

对称加密

对称加密的思路非常简单,就是含有一个称为密钥的东西,在消息发送前使用密钥对消息进行加密,在对方收到消息之后,使用相同的密钥进行
解密。根据密钥来产生加密后的消息(密文)的这一加工过程,由加密算法来完成,加密算法通常是公开的。它的流程如下:
  1. 发送方使用密钥对消息进行加密。
  2. 接收方使用同样的密钥对消息进行解密。
可以使用下面一副图来表示:
对称加密
对称加密存在这样两个问题:
  1. 虽然可以通过密钥来保证消息安全地进行传递,但是如何确保密钥安全地进行传递?因为发送者和接收者总有一次初始的通信,用来传递密钥,此时的安全如何保证?
  2. 接收者虽然可以根据密钥来解密消息,但因为存在上面的问题,消息有可能是由第三方(非法获得密钥)发来的,而接收方无法辨别。
为了解决上面两个问题,就需要介绍一下非对称加密。

非对称加密

非对称加密的接收者和发送者都持有两个密钥,一个是对外公开的,称为公钥,一个是自行保管的,称为私钥。非对称加密的规则是由某人A的公钥加密的消息,只能由A的私钥进行解密;由A的私钥加密的消息只能由A的公钥解密。此时我们可以得出接收方、发送方有两个公钥两个私钥一共四个密钥,我们先看看两种简单的方式,这两种方式都是只使用两个密钥。
第一种模式只使用接收方的公钥和私钥,称为加密模式。
在加密模式中,由消息的接收方发布公钥,持有私钥。比如发送方要发送消息“hello,jimmy”到接收方,它的步骤是:
  1. 发送方使用接收者的公钥进行加密消息,然后发送。
  2. 接收方使用自己的私钥对消息进行解密。
可以使用下面一幅图来描述:
非对称加密
在这种模式下,如果第三方截获了发送者发出的消息,因为他没有接收者的私钥,所以这个消息对他来说毫无意义。可见,它能够满足本文最开始提出的消息安全传递的要点一:消息的发送方能够确定消息只有预期的接收方可以解密(不保证第三方无法获得,但保证第三方无法解密)。
除此以外,因为接收方的公钥是公开的,任何人都可以使用这个公钥来加密消息并发往接收者,而接收者无法对消息进行判别,无法知道是由谁发送来的。所以,它不满足我们开始提出的消息安全传递的要点二:消息的接收方可以确定消息是由谁发送的(消息的接收方可以确定消息的发送方)。
这个问题可以在下面的认证模式中得到解决。
第二种模式只使用发送方的公钥和私钥,称为认证模式。
在认证模式中,由消息的发送方发布公钥,持有私钥。比如发送者要发送消息“Welcome to Tracefact.net”到接收者,它的步骤是:
  1. 发送者使用自己的私钥对消息进行加密,然后发送。
  2. 接收者使用发送者的公钥对消息进行解密。
可以用下面一副图来表述:
认证模式
在这种模式下,假如发送方叫做Ken,接收方叫做Matthew,因为Matthew只能使用Ken的公钥对消息进行解密,而无法使用Molly、Sandy或者任何其他人公钥对消息进行解密,所以他一定能够确定消息是由Ken发送来的。因此,这个模式满足了前面提出的消息安全传递的要点二。
与此同时,因为Ken的公钥是公开的,任何截获了该消息的第三方都能够使用Ken的公钥来对消息进行解密,换言之,消息现在是不安全的。因此,与加密模式正好相反,它无法满足前面提出的消息安全传递的要点一。
而不管是采用加密模式还是认证模式,都没有解决加密解密中的要点三:接收方必须能够确认消息没有被改动过。为了解决这个问题,又引入了数字签名。

数字签名

数字签名实际上就是上面非对称加密时的认证模式,只不过做了一点点的改进,加入了散列算法。大家比较熟悉的散列算法可能就是MD5了,很多开源论坛都采用了这个算法。散列算法有三个特点:一是不可逆的,由结果无法推算出原数据;二是原数据哪怕是一丁点儿的变化,都会使散列值产生巨大的变化;三是不论多么大或者多么少的数据,总会产生固定长度的散列值(常见的为32位64位)。产生的散列值通常称为消息的摘要(digest)。
那么如何通过引入散列函数来保证数据的完整性呢?也就是接收方能够确认消息确实是由发送方发来的,而没有在中途被修改过。具体的过程如下:
  1. 发送方将想要进行传递的消息进行一个散列运算,得到消息摘要。
  2. 发送方使用自己的私钥对摘要进行加密,将消息和加密后的摘要发送给接收方。
  3. 接收方使用发送方的公钥对消息和消息摘要进行解密(确认了发送方)。
  4. 接收方对收到的消息进行散列运算,得到一个消息摘要。
  5. 接收方将上一步获得的消息摘要与发送方发来的消息摘要进行对比。如果相同,说明消息没有被改动过;如果不同,说明消息已经被篡改。
这个过程可以用下面的一副图来表述:
数字签名
我们可以看出,数字签名通过引入散列算法,将非对称加密的认证模式又加强了一步,确保了消息的完整性。除此以外,注意到上面的非对称加密算法,只是对消息摘要进行了加密,而没有对消息本身进行加密。非对称加密是一个非常耗时的操作,由于只对消息摘要加密,使得运算量大幅减少,所以这样能够显著地提高程序的执行速度。同时,它依然没有确保消息不被第三方截获到,不仅如此,因为此时消息是以明文进行传递,第三方甚至不需要发送方的公钥,就可以直接查看消息。
为了解决这样的问题,只需要将非对称加密的认证模式、加密模式以及消息摘要进行一个结合就可以了,这也就是下面的高级模式。

高级实现

由于这个过程比上面稍微复杂了一些,我们将其分为发送方和接收方两部分来看。先看看发送方需要执行的步骤:
  1. 将消息进行散列运算,得到消息摘要。
  2. 使用自己的私钥对消息摘要加密(认证模式:确保了接收方能够确认自己)。
  3. 使用接收方的公钥对消息进行加密(加密模式:确保了消息只能由期望的接收方解密)。
  4. 发送消息和消息摘要。
接下来我们看一下接收方所执行的步骤:
  1. 使用发送方的公钥对消息摘要进行解密(确认了消息是由谁发送的)。
  2. 使用自己的私钥对消息进行解密(安全地获得了实际应获得的信息)。
  3. 将消息进行散列运算,获得消息摘要。
  4. 将上一步获得的消息摘要 和 第一步解密的消息摘要进行对比(确认了消息是否被篡改)。
可以看到,通过上面这种方式,使用了接收方、发送方全部的四个密钥,再配合使用消息摘要,使得前面提出的安全传递的所有三个条件全都满足了。那么是不是这种方法就是最好的呢?不是的,因为我们已经说过了,非对称加密是一种很耗时的操作,所以这个方案是很低效的。实际上,我们可以通过它来解决对称加密中的密钥传递问题,如果你已经忘记了可以翻到前面再看一看,也就是说,我们可以使用这里的高级实现方式来进行对称加密中密钥的传递,对于之后实际的数据传递,采用对称加密方式来完成,因为此时已经是安全的了。

证书机制

与数字签名相关的一个概念就是证书机制了,证书是用来做什么呢?在上面的各种模式中,我们一直使用了这样一个假设,就是接收方或者发送方所持有的、对方的公钥总是正确的(确实是对方公布的)。而实际上除非对方手把手将公钥交给我们,否则如果不采取措施,双方在网络中传递公钥时,一样有可能被篡改。那么怎样解决这个问题呢?这时就需要证书机制了:可以引入一个公正的第三方,当某一方想要发布公钥时,它将自身的身份信息及公钥提交给这个第三方,第三方对其身份进行证实,如果没有问题,则将其信息和公钥打包成为证书(Certificate)。而这个公正的第三方,就是常说的证书颁发机构(Certificate Authority)。当我们需要获取公钥时,只需要获得其证书,然后从中提取出公钥就可以了。

常见的加密解密方法

加密解密方法很多,通过对字节流的操作,也很容易的实现自定义的加密解密方法。常见的加密解密方法大致如下:

1、常用密钥算法

密钥算法用来对敏感数据、摘要、签名等信息进行加密,常用的密钥算法包括:
DES(Data Encryption Standard):数据加密标准,速度较快,适用于加密大量数据的场合; 
3DES(Triple DES):是基于DES,对一块数据用三个不同的密钥进行三次加密,强度更高; 
RC2和 RC4:用变长密钥对大量数据进行加密,比 DES 快; 
IDEA(International Data Encryption Algorithm)国际数据加密算法,使用 128 位密钥提供非常强的安全性; 
RSA:由 RSA 公司发明,是一个支持变长密钥的公共密钥算法,需要加密的文件快的长度也是可变的;
DSA(Digital Signature Algorithm):数字签名算法,是一种标准的 DSS(数字签名标准); 
AES(Advanced Encryption Standard):高级加密标准,是下一代的加密算法标准,速度快,安全级别高,目前 AES 标准的一个实现是 Rijndael 算法; 
BLOWFISH,它使用变长的密钥,长度可达448位,运行速度很快; 
其它算法,如ElGamal、Deffie-Hellman、新型椭圆曲线算法ECC等。

2、单向散列算法

单向散列函数一般用于产生消息摘要,密钥加密等,常见的有:
MD5(Message Digest Algorithm 5):是RSA数据安全公司开发的一种单向散列算法,MD5被广泛使用,可以用来把不同长度的数据块进行暗码运算成一个128位的数值; 
SHA(Secure Hash Algorithm)这是一种较新的散列算法,可以对任意长度的数据运算生成一个160位的数值; 
MAC(Message Authentication Code):消息认证代码,是一种使用密钥的单向函数,可以用它们在系统上或用户之间认证文件或消息。HMAC(用于消息认证的密钥散列法)就是这种函数的一个例子。 
CRC(Cyclic Redundancy Check):循环冗余校验码,CRC校验由于实现简单,检错能力强,被广泛使用在各种数据校验应用中。占用系统资源少,用软硬件均能实现,是进行数据传输差错检测地一种很好的手段(CRC 并不是严格意义上的散列算法,但它的作用与散列算法大致相同,所以归于此类)。

3、其它数据算法

其它数据算法包括一些常用编码算法及其与明文(ASCII、Unicode 等)转换等,如 Base 64、Quoted Printable、EBCDIC 等。

.Net中加密解密的支持

常见的加密和编码算法都已经在 .NET Framework中得到了实现,为编码人员提供了极大的便利性,实现这些算法的名称空间是:System.Security.Cryptography。System.Security.Cryptography 命名空间提供加密服务,包括安全的数据编码和解码,以及许多其他操作,例如散列法、随机数字生成和消息身份验证,按照对称与非对称的分类方式,大致如下图所示:
.Net加密
上面的类按照名称还可以分为两组,一组后缀为“CryptoServiceProvider”的,是对于底层Windows API的包装类,一组后缀为“Managed”,是在.NET中全新编写的类。下面我们对.Net中支持的加密方式做进一步介绍。

1、私钥加密

私钥加密又称为对称加密,因为同一密钥既用于加密又用于解密。私钥加密算法非常快(与公钥算法相比),特别适用于对较大的数据流执行加密转换。.NET Framework 提供以下实现私钥加密算法的类:
DES:DESCryptoServiceProvider 
RC2:RC2CryptoServiceProvider 
Rijndael(AES):RijndaelManaged 
3DES:TripleDESCryptoServiceProvider

2、公钥加密和数字签名

公钥加密使用一个必须对未经授权的用户保密的私钥和一个可以对任何人公开的公钥。用公钥加密的数据只能用私钥解密,而用私钥签名的数据只能用公钥验证。公钥可以被任何人使用;该密钥用于加密要发送到私钥持有者的数据。两个密钥对于通信会话都是唯一的。公钥加密算法也称为不对称算法,原因是需要用一个密钥加密数据而需要用另一个密钥来解密数据。.NET Framework 提供以下实现公钥加密算法的类: 
DSA:DSACryptoServiceProvider 
RSA:RSACryptoServiceProvider 

3、哈希(Hash)值

哈希算法将任意长度的二进制值映射为固定长度的较小二进制值,这个小的二进制值称为哈希值。哈希值是一段数据唯一且极其紧凑的数值表示形式。如果散列一段明文而且哪怕只更改该段落的一个字母,随后的哈希都将产生不同的值。要找到散列为同一个值的两个不同的输入,在计算上是不可能的,所以数据的哈希值可以检验数据的完整性。.NET Framework 提供以下实现数字签名算法的类: 
HMAC:HMACSHA1 (HMAC 为一种使用密钥的 Hash 算法) 
MAC:MACTripleDES 
MD5:MD5CryptoServiceProvider 
SHA1:SHA1Managed、SHA256Managed、SHA384Managed、SH7747.net12Managed

4、随机数生成

加密密钥需要尽可能地随机,以便使生成的密钥很难再现,所以随机数生成是许多加密操作不可分割的组成部分。在 .NET Framework 中,RNGCryptoServiceProvider 是随机数生成器算法的实现,对于数据算法,.NET Framework 则在其它命名空间中实现,如 Convert 类实现 Base 64 编码,System.Text 来实现编码方式的转换等。

从以上来看,.NET Framework 对于数据加密/编码还是支持比较好,大大地方便了开发人员,但美中不足的是,.NET Framework 中的数据加密算法仍然不够完全,如 IDEA、BLOWFISH、其它算法,如ElGamal、Deffie-Hellman、ECC 等,对于一些其它的数据校验算法支持也不够,如 CRC、SFV 等,开发人员只能去从早期代码做移植或者寻找第三方厂商的实现。

.Net加密示例

为了更好的理解.Net中的加密解密方法的运用,我们通过代码示例来了解。

MD5加密

MD5全称是message-digest algorithm 5,简单的说就是单向的加密,即是说无法根据密文推导出明文。MD5主要用途:
  1. 对一段信息生成信息摘要,该摘要对该信息具有唯一性,可以作为数字签名。
  2. 用于验证文件的有效性(是否有丢失或损坏的数据),
  3. 对用户密码的加密,
  4. 在哈希函数中计算散列值
从上边的主要用途中我们看到,由于算法的某些不可逆特征,在加密应用上有较好的安全性。通过使用MD5加密算法,我们输入一个任意长度的字节串,都会生成一个128位的整数。所以根据这一点MD5被广泛的用作密码加密。

示例:

        public string GetMD5_32(string s, string _input_charset)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] t = md5.ComputeHash(Encoding.GetEncoding(_input_charset).GetBytes(s));
            StringBuilder sb = new StringBuilder(32);
            for (int i = 0; i < t.Length; i++)
            {
                sb.Append(t[i].ToString("x").PadLeft(2, '0'));//ToString("x")为十六进制表示,详细参考:https://msdn.microsoft.com/zh-cn/library/dwhawy9k
            }
            return sb.ToString();
        }
        public string GetMD5_16(string ConvertString)
        {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            string t2 = BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(ConvertString)), 4, 8);
            t2 = t2.Replace("-", "");
            return t2;
        }


SHA1加密

安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要。
示例:
        /// <summary>
        /// use sha1 to encrypt string
        /// </summary>
        public string SHA1_Encrypt(string Source_String)
        {
            byte[] StrRes = Encoding.Default.GetBytes(Source_String);
            HashAlgorithm iSHA = new SHA1CryptoServiceProvider();
            StrRes = iSHA.ComputeHash(StrRes);
            StringBuilder EnText = new StringBuilder();
            foreach (byte iByte in StrRes)
            {
                EnText.AppendFormat("{0:x2}", iByte);
            }
            return EnText.ToString();
        }

DES加密、解密

DES加密是对称加密,它使用一个 56 位的密钥以及附加的 8 位奇偶校验位,产生最大 64 位的分组大小。这是一个迭代的分组密码,使用称为 Feistel 的技术,其中将加密的文本块分成两半。使用子密钥对其中一半应用循环功能,然后将输出与另一半进行“异或”运算;接着交换这两半,这一过程会继续下去,但最后一个循环不交换。DES 使用 16 个循环,使用异或,置换,代换,移位操作四种基本运算。
示例:
        /// <summary>
        /// DES加密方法
        /// </summary>
        /// <param name="strPlain">明文</param>
        /// <param name="strDESKey">密钥</param>
        /// <param name="strDESIV">向量</param>
        /// <returns>密文</returns>
        public string DESEncrypt(string strPlain, string strDESKey, string strDESIV)
        {
            //把密钥转换成字节数组
            byte[] bytesDESKey = ASCIIEncoding.ASCII.GetBytes(strDESKey);
            //把向量转换成字节数组
            byte[] bytesDESIV = ASCIIEncoding.ASCII.GetBytes(strDESIV);
            //声明1个新的DES对象
            DESCryptoServiceProvider desEncrypt = new DESCryptoServiceProvider();
            //开辟一块内存流
            MemoryStream msEncrypt = new MemoryStream();
            //把内存流对象包装成加密流对象
            CryptoStream csEncrypt = new CryptoStream(msEncrypt, desEncrypt.CreateEncryptor(bytesDESKey, bytesDESIV), CryptoStreamMode.Write);
            //把加密流对象包装成写入流对象
            StreamWriter swEncrypt = new StreamWriter(csEncrypt);
            //写入流对象写入明文
            swEncrypt.WriteLine(strPlain);
            //写入流关闭
            swEncrypt.Close();
            //加密流关闭
            csEncrypt.Close();
            //把内存流转换成字节数组,内存流现在已经是密文了
            byte[] bytesCipher = msEncrypt.ToArray();
            //内存流关闭
            msEncrypt.Close();
            //把密文字节数组转换为字符串,并返回
            return UnicodeEncoding.Unicode.GetString(bytesCipher);
        }

        /// <summary>
        /// DES解密方法
        /// </summary>
        /// <param name="strCipher">密文</param>
        /// <param name="strDESKey">密钥</param>
        /// <param name="strDESIV">向量</param>
        /// <returns>明文</returns>
        public string DESDecrypt(string strCipher, string strDESKey, string strDESIV)
        {
            //把密钥转换成字节数组
            byte[] bytesDESKey = ASCIIEncoding.ASCII.GetBytes(strDESKey);
            //把向量转换成字节数组
            byte[] bytesDESIV = ASCIIEncoding.ASCII.GetBytes(strDESIV);
            //把密文转换成字节数组
            byte[] bytesCipher = UnicodeEncoding.Unicode.GetBytes(strCipher);
            //声明1个新的DES对象
            DESCryptoServiceProvider desDecrypt = new DESCryptoServiceProvider();
            //开辟一块内存流,并存放密文字节数组
            MemoryStream msDecrypt = new MemoryStream(bytesCipher);
            //把内存流对象包装成解密流对象
            CryptoStream csDecrypt = new CryptoStream(msDecrypt, desDecrypt.CreateDecryptor(bytesDESKey, bytesDESIV), CryptoStreamMode.Read);
            //把解密流对象包装成读出流对象
            StreamReader srDecrypt = new StreamReader(csDecrypt);
            //明文=读出流的读出内容
            string strPlainText = srDecrypt.ReadLine();
            //读出流关闭
            srDecrypt.Close();
            //解密流关闭
            csDecrypt.Close();
            //内存流关闭
            msDecrypt.Close();
            //返回明文
            return strPlainText;
        } 

RSA加密解密


RSA加密算法是一种非对称加密算法。在公钥加密标准和电子商业中RSA被广泛使用。RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。
  RSA算法的可靠性基于分解极大的整数是很困难的。假如有人找到一种很快的分解因子的算法的话,那么用RSA加密的信息的可靠性就肯定会极度下降。但找到这样的算法的可能性是非常小的。今天只有短的RSA钥匙才可能被强力方式解破。到2008年为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。
示例(来自MSDN):
using System;
using System.Security.Cryptography;
using System.IO; 
using System.Text;

namespace Microsoft.Samples.Security.PublicKey
{
  class App
  {
    // Main entry point
    static void Main(string[] args)
    {
      // Instantiate 3 People for example. See the Person class below
      Person alice = new Person("Alice");
      Person bob = new Person("Bob");
      Person steve = new Person("Steve");

      // Messages that will exchanged. See CipherMessage class below
      CipherMessage aliceMessage;
      CipherMessage bobMessage;
      CipherMessage steveMessage;

      // Example of encrypting/decrypting your own message
      Console.WriteLine("Encrypting/Decrypting Your Own Message");
      Console.WriteLine("-----------------------------------------");

      // Alice encrypts a message using her own public key
      aliceMessage = alice.EncryptMessage("Alice wrote this message");
      // then using her private key can decrypt the message
      alice.DecryptMessage(aliceMessage);
      // Example of Exchanging Keys and Messages
      Console.WriteLine();
      Console.WriteLine("Exchanging Keys and Messages");
      Console.WriteLine("-----------------------------------------");

      // Alice Sends a copy of her public key to Bob and Steve
      bob.GetPublicKey(alice);
      steve.GetPublicKey(alice);

      // Bob and Steve both encrypt messages to send to Alice
      bobMessage = bob.EncryptMessage("Hi Alice! - Bob.");
      steveMessage = steve.EncryptMessage("How are you? - Steve");

      // Alice can decrypt and read both messages
      alice.DecryptMessage(bobMessage);
      alice.DecryptMessage(steveMessage);

      Console.WriteLine();
      Console.WriteLine("Private Key required to read the messages");
      Console.WriteLine("-----------------------------------------");

      // Steve cannot read the message that Bob encrypted
      steve.DecryptMessage(bobMessage);
      // Not even Bob can use the Message he encrypted for Alice.
      // The RSA private key is required to decrypt the RS2 key used
      // in the decryption.
      bob.DecryptMessage(bobMessage);

    } // method Main
  } // class App

  class CipherMessage
  {
    public byte[] cipherBytes;  // RC2 encrypted message text
    public byte[] rc2Key;       // RSA encrypted rc2 key
    public byte[] rc2IV;        // RC2 initialization vector
  }

  class Person
  {
    private RSACryptoServiceProvider rsa;
    private RC2CryptoServiceProvider rc2;
    private string name;

    // Maximum key size for the RC2 algorithm
    const int keySize = 128;

    // Person constructor
    public Person(string p_Name)
    {
      rsa = new RSACryptoServiceProvider();
      rc2 = new RC2CryptoServiceProvider();
      rc2.KeySize = keySize;
      name = p_Name;
    }

    // Used to send the rsa public key parameters
    public RSAParameters SendPublicKey() 
    {
      RSAParameters result = new RSAParameters();
      try 
      {
        result = rsa.ExportParameters(false);
      }
      catch (CryptographicException e)
      {
        Console.WriteLine(e.Message);
      }
      return result;
    }

    // Used to import the rsa public key parameters
    public void GetPublicKey(Person receiver)
    {
      try 
      {
        rsa.ImportParameters(receiver.SendPublicKey()); 
      }
      catch (CryptographicException e)
      {
        Console.WriteLine(e.Message);
      }
    }

    public CipherMessage EncryptMessage(string text)
    {
      // Convert string to a byte array
      CipherMessage message = new CipherMessage();
      byte[] plainBytes = Encoding.Unicode.GetBytes(text.ToCharArray());

      // A new key and iv are generated for every message
      rc2.GenerateKey();
      rc2.GenerateIV();

      // The rc2 initialization doesnt need to be encrypted, but will
      // be used in conjunction with the key to decrypt the message.
      message.rc2IV = rc2.IV;
      try 
      {
        // Encrypt the RC2 key using RSA encryption
        message.rc2Key = rsa.Encrypt(rc2.Key, false);
      }
      catch (CryptographicException e)
      {
        // The High Encryption Pack is required to run this  sample
        // because we are using a 128-bit key. See the readme for
        // additional information.
        Console.WriteLine("Encryption Failed. Ensure that the" + 
          " High Encryption Pack is installed.");
        Console.WriteLine("Error Message: " + e.Message);
        Environment.Exit(0);
      }
      // Encrypt the Text Message using RC2 (Symmetric algorithm)
      ICryptoTransform sse = rc2.CreateEncryptor();
      MemoryStream ms = new MemoryStream();
      CryptoStream cs = new CryptoStream(ms, sse, CryptoStreamMode.Write);
      try
      {
          cs.Write(plainBytes, 0, plainBytes.Length);
          cs.FlushFinalBlock();
          message.cipherBytes = ms.ToArray();
      }
      catch (Exception e)
      {
          Console.WriteLine(e.Message);
      }     
      finally
      {
        ms.Close();
        cs.Close();
      }
      return message;
    } // method EncryptMessage


    public void DecryptMessage(CipherMessage message)
    {
      // Get the RC2 Key and Initialization Vector
      rc2.IV = message.rc2IV;
      try 
      {
        // Try decrypting the rc2 key
        rc2.Key = rsa.Decrypt(message.rc2Key, false);
      }
      catch (CryptographicException e)
      {
        Console.WriteLine("Decryption Failed: " + e.Message);
        return;
      }
      
      ICryptoTransform ssd = rc2.CreateDecryptor();
      // Put the encrypted message in a memorystream
      MemoryStream ms = new MemoryStream(message.cipherBytes);
      // the CryptoStream will read cipher text from the MemoryStream
      CryptoStream cs = new CryptoStream(ms, ssd, CryptoStreamMode.Read);
      byte[] initialText = new Byte[message.cipherBytes.Length];

      try
      {
          // Decrypt the message and store in byte array
          cs.Read(initialText, 0, initialText.Length);
      }
      catch (Exception e)
      {
          Console.WriteLine(e.Message);
      }      
      finally 
      {
        ms.Close();
        cs.Close();
      }

      // Display the message received
      Console.WriteLine(name + " received the following message:");
      Console.WriteLine("  " + Encoding.Unicode.GetString(initialText));
    } // method DecryptMessage
  } // class Person
} // namespace PublicKey


此外还有AES加密算法,但是AES加密是一个新的可以用于保护电子数据的加密算法。其产生的密码是迭代对称的分组密码,代加密使用一个循环结构,在该循环中重复置换和替换输入数据。这种加密方法用的不是很多。

参考博客:
That's All.

原文地址:https://www.cnblogs.com/ice-/p/6165787.html