.NET 中的加密 (第一部分)






4.38/5 (22投票s)
使用 .NET Framework 的加密类来保护您的数据。
引言
在 .NET 出现之前,加密通常需要使用非托管的 Win32 API,这是一种非常晦涩的加密或解密数据的方式。.NET 为此提供了一组类(实际上是一个完整的命名空间)。现在,您可以使用许多使用不同预定义算法的类来通过加密保护您的数据。在 .NET 中,Cryptography 命名空间下定义了三种类型的加密。它们是 AsymmetricAlgorithm
、SymmetricAlgorithm
和 HashAlgorithm
。这三个类(以及 .NET 中的加密类型)都是抽象类。本文将讨论 SymmetricAlgorithm
。其余部分将在后续文章中讨论。
注意:虽然大多数加密类都是用托管代码实现的,但许多类使用了 CryptoAPI 库。如果您在类名中看到 CryptoServiceProvider
,例如 DESCryptoServiceProvider
,则可以推断出它们使用了该库。
对称加密算法基础
对称加密算法使用用户定义的密钥(或密码)进行工作。这意味着,当您要实现对称加密算法来加密/解密您的数据时,您必须定义一个密码或密钥,该密钥将用于加密或解密您的数据。以下是对称加密算法的特点。
- 加密的强度取决于密钥(密码)的安全性。如果您提供一个更长的密钥,则破解该代码将更难。因为黑客需要更多的时间来找出密钥。
- 它基于简单的数学运算。因此,它的速度很快。所以,如果您处理大量数据,这是最佳选择。
- 这种算法的一个缺点是,密钥应该被双方(加密者和需要解密该信息/数据的人)都知道。
- 对称加密算法可以被黑客使用暴力破解。但如果您定义了一个好的密钥,那么破解可能需要很长时间(甚至不可能)。
- 由于密钥是用户定义的,通常,根据用户的习惯,它会存在于字典中。所以黑客可以使用暴力破解和字典来解码/解密您的信息。但是更长的密钥可以长时间保护数据,因为它需要很长时间才能被破解。
除了密钥或密码之外,对称算法的加密或解密过程还涉及另一件事。那就是初始化向量(IV)。IV 用于初始化编码(加密/解密)。在所有对称算法类中,我们都有一个名为 Mode
的属性。IV 在这里使用。如果我们将 Mode 属性设置为 CipherMode.CBC(Cipher Block Chaining,密码块链接),那么使用此模式,数据块的每个块都通过取自前一个块的值来处理。也就是说,如果系统正在处理第三个数据块,它将使用第二个块(已处理)的一些信息。当它处理第二个块时,它将取自第一个块的值。但由于第一个块之前没有块,因此它将使用 IV 来处理第一个块。此技术可确保任何两个相同的块都不会产生相同的输出,从而使数据更加安全。而如果您使用 Mode = CipherMode.ECB(Electronic Codebook Mode,电子密码本模式),则它不使用链接(使用先前处理的块信息来处理下一个块)。如果您想处理大型消息,此模式很有帮助,因为它消耗的资源和时间更少。它还允许您从数据中间开始处理,如果某些数据已损坏。
因此,到目前为止,我们已经看到对称加密涉及两个重要内容。它们是密钥(密钥或密码)和初始化向量(IV)。现在,让我们看看一些支持对称加密的算法。
对称算法和 SymmetricAlgorithm 类
以下是对称算法及其类,并附带一些密钥信息。
算法名称 | 算法类(抽象) | 有效密钥大小(比特) | 默认密钥大小(比特) | 默认实现类 |
DES | DES | 64 | 64 | DESCryptoServiceProvider |
TripleDES | TripleDES | 128, 192 | 192 | TripleDESCryptoServiceProvider |
RC2 | RC2 | 40-128 | 128 | RC2CryptoServiceProvider |
RijnDael | RijnDael | 128, 192, 256 | 256 | RijnDaelManaged |
需要注意的是,所有这些算法类都继承自名为 SymmetricAlgorithm 的抽象类。您可以看到每个类支持不同的密钥大小。同样,它们也支持不同的 IV 大小。如前所述,所有这些类都是抽象的,因此我们无法直接创建任何这些类的实例。但是 SymmetricAlgorithm 类(它也是一个抽象类)公开了一个名为 Create 的共享方法,该方法可用于创建类的具体实例,而无需担心其实现方式。也就是说,您可以使用它来完成此操作:
Dim mRC2 As RC2 = RC2.Create()
这将返回 RC2 的默认实现实例,而无需担心如何实现 RC2 类(这是一个抽象类)。此技术在需要通用代码时很有用,因为 Microsoft 以后可能会更新 RC2 类的实现更改。在这种情况下,您的代码将自动获取这些更改并正常工作。或者,RC2 类代码将来可能以托管代码形式编写,因此您的代码可以接受它。同样,您也可以使用以下语句:
Dim mCrypto as RC2 = SymmetricAlgorithm.Create("RC2")
这也将返回 RC2 对象(默认实现)。在这种情况下,您使用的是重载的 Create 函数,该函数以算法名称作为参数并返回该算法的对象。此 Create 方法从 SymmetricAlgorithm
类使用,并且如前所述,所有使用 Symmetric Algorithm 的其他类都继承了 SymmetricAlgorithm
类,因此,您会在上面定义的所有类中找到此 Create 方法。这意味着如果您使用 RC2.Create("DES")
,它也会起作用并返回 DES 对象。但是通过 RC2 类获取 DES 对象似乎不太好。
上述机制比看起来更有用。我们可以定义自己的类,使用自己的算法,并以同样的方式使用它。但是,为此,我们需要对 machine.config 文件进行一些小的更改。我在这里不进行描述。您可以参考 Wrox Cryptography 书籍(本文的参考书目部分)获取更多信息。
现在,让我们看看 SymmetricAlgorithm
类的一些属性和方法。
- BlockSize:一次处理的数据块大小。较长的数据将被分成数据块(块)进行处理,如果数据小于块大小,则会进行填充(使用一些默认值填充)。
- Key:用于处理数据的秘密值。此密钥通过字节数组提供。
- KeySize:密钥的总大小(以比特为单位)。
- IV:数据处理的初始化向量(如上所述)。以字节数组形式提供。
- LegalBlockSizes:返回 BlockSize 枚举,该枚举告诉您块大小的合法值,包括最大值、最小值和 Skip 值。Skip 值表示最后一个合法值应该加上多少才能得到下一个值。例如,如果最小值是 32,Skip 值是 16,则表示下一个合法值将是 48、64 等。
- Mode:获取或设置操作模式。如上所述。值为 CipherMode 枚举之一。
- Padding:获取或设置填充(块的空白区域应如何填充)值是 PaddingMode 枚举值之一。
- LegalKeySizes:与 LegalBlockSizes 相同,但处理 KeySize。
- Create:如上所述,用于创建默认算法实现类。
- CreateEncryptor:返回 ICryptoTransform 对象,该对象可用于手动加密数据。稍后将讨论。
- CreateDecryptor:返回 ICryptoTransform 对象,该对象可用于手动解密数据。稍后将讨论。
- GenerateKey 和 GenerateIV:如果在加密或解密过程中 Key 和 IV 为 null,则使用这些方法生成默认的 Key 和 IV。
- ValidKeySize:检查给定的密钥是否对此算法有效。
- Clear:清除所有资源并删除内存信息,如密钥和 IV。
现在,在编写代码之前,让我们讨论另外两件对理解代码很有用的事情。
CreateEncryptor 和 CreateDecryptor
SymmetricAlgorithm 类的 CreateEncryptor 和 CreateDecryptor 方法返回 ICryptoTransform 对象。ICryptoTransform 是一个接口,由希望按块处理数据的类实现。此处理可以是加密、解密、哈希、base 64 编码/解码等。此接口的基本目的是执行数据的按块处理。您可以直接使用其实例,但在大多数情况下,为了方便起见,我们会将其传递给另一个名为 CryptoStream 的类。让我们看一个如何使用它的例子。
Dim mCrypt as DES = SymmetricAlgorithm.Create("DES")
Dim mTransform as ICryptoTransform = mCrypt.CreateEncryptor()
CreateEncryptor
或 CreateDecryptor
是重载函数。如果您不向其传递任何内容,则将使用默认的 Key 和 IV(使用 SymmetricAlgoruthm 类的 GenerateKey 和 GenerateIV 方法)来获取 Key 和 IV。在其他情况下,您可以将 IV 和 Key 传递给 CreateEncryptor 和 CreateDecryptor 对象。这样,就可以使用我们定义的密钥和 IV 进行加密或解密。
CryptoStream 类
CryptoStream
类用于在读取或写入数据时对其进行加密或解密。它简单地包装了普通的 Stream 类。它使用缓冲访问,让您不必担心管理缓冲区、块大小、填充等。您可以使用以下代码获取其实例。
Dim mCrypt as DES = SymmetricAlgorithm.Create("DES")
Dim mTransform as ICryptoTransform = mCrypt.CreateEncryptor()
Dim mStream as New CryptoStream(fileStream, mTransform, CryptoStreamMode.Read)
fileStream 是任何普通文件的流(或者可能是 MemoryStream
),它负责从磁盘(文件)或内存中读取数据。现在,使用此 mStream
对象和 StreamReader/StreamWriter 对象来读取/写入数据。当您读取/写入数据时,您将获得加密/解密后的信息,具体取决于 ICryptoTransform 对象(它是使用 CreateEncryptor 或 CreateDecryptor 创建的)。
编写示例代码。
现在我们对 SymmetricAlgorithm 有了足够的信息。最后,让我们来看一小段代码,它将加密然后解密数据。我假设您有一个带有名为 txtData 的文本框和一个命令按钮的窗体。在此命令按钮的 Click 事件中编写此代码。此代码将加密文本框内的文本,在消息框中显示它,将其写入文本框,解密它,在消息框中显示,然后写回文本框。
Dim mCryptProv as SymmetricAlgorithm
Dim mMemStr as MemoryStream
'Encrypt the Data in the textbox txtData, show that in MessageBox
'and write back to textbox
'Here You can provide the name of any class which supports
SymmetricAlgorithm Like DES mCryptProv = SymmetricAlgorithm.Create("Rijndael")
'The encrypted data will be stored in the memory, so we need a memory stream
'object
mMemStr = New MemoryStream()
'Create the ICryptTransform Object. (We are using default Key and IV here).
Dim mTransform As ICryptoTransform = mCryptProv.CreateEncryptor()
'Create the Crypto Stream for writing, and pass that MemoryStream
'(where to write after encryption), and ICryptoTransform Object.
Dim mCSWriter As New CryptoStream(mMemStr, mTransform, CryptoStreamMode.Write)
'This StreamWriter object will be used to write
'Encrypted data to the Memory Stream
'Pass it the object of CryptoStream
Dim mSWriter As New StreamWriter(mCSWriter)
mSWriter.Write(Me.txtData.Text)
'Write data after encryption
mSWriter.Flush() 'Make sure to write everything from Stream
mCSWriter.FlushFinalBlock() 'Flush the CryptoStream as well
您可能已经注意到,在这段代码中我们没有在任何地方使用 IV 和 Key。实际上,.NET Framework 会为我们生成它,因为我们为了方便代码没有指定它。但是本文随附的示例使用了用户定义的 Key 和 IV。现在,加密后的数据已通过 MemoryStream 对象写入内存。现在,让我们从内存中获取这些数据。
'The Data has been written in the Memory, But we need to display that
'back to text box and want to show in Messagebox. So do the following
'Create byte array to receive data
Dim mBytes(mMemStr.Length - 1) As Byte
mMemStr.Position = 0 'Move to beginning of data
'Read All data from the memory
mMemStr.Read(mBytes, 0, mMemStr.Length)
'But this data is in Bytes, and we need to convert it to string.
'String conversion address to the problem of Encoding format. We are
'using UTF8 Encoding to encode data from byte to string
Dim mEnc As New Text.UTF8Encoding()
Dim mEncData As String = mEnc.GetString(mBytes)
MsgBox("Encrypted Data is : " & vbCrLf & mEncData)
Me.txtData.Text = mEncData
将字节转换为字符串涉及编码。我在这里使用 UTF8Encoding。最后,让我们解密该数据,然后在消息框和 TextBox 中再次显示它。
'Now let's decrypt that data from the memory.
'Since our data is in the memory, So we need to reuse the same
'MemoryStream Object.
'Move Memorty position to back
mMemStr.Position = 0
mTransform = mCryptProv.CreateDecryptor()
Dim mCSReader As New CryptoStream(mMemStr, mTransform, CryptoStreamMode.Read)
Dim mStrREader As New StreamReader(mCSReader)
Dim mDecData As String = mStrREader.ReadToEnd()
MsgBox("Decrypted Data is : " & vbCrLf & mDecData)
Me.txtData.Text = mDecData
到此为止。要解密该数据,我们使用了相同的内存流。我们首先将位置移到开头,以便我们可以从流的开头读取。然后,我们使用 SymmetricAlgorithm 对象的 CreateDecryptor 方法创建了 ICryptoTransform 对象。我们重用了上一段代码中用于加密数据的对象。您可以创建一个新对象(使用新变量)。然后,我们需要一个 StreamReader 来为我们从内存中读取数据。在读取数据的同时,它还会解密数据,因为我们在创建 StreamReader 对象时传递了 CryptoStream 对象。
结束语
在结束本文之际,我想说 .NET 为我们提供了一种非常托管的方式来使用内置类来保护我们的数据。现在使用那些老式的 Crypto API 没有问题了,尽管许多类在后台使用了那些 Crypto API。但是我们可以安全地使用这些类,而无需担心这些类的实现。在下一篇文章(我希望很快会发布)中,我将讨论 AsymmetricAlgorithm 的误解和用法。
关于示例代码
本文提供的示例代码允许您选择要用于加密或解密数据的算法(如上图所示)。它还允许您指定自己的 IV 和 Key。代码有两种工作方式。一种是使用文本框,意味着您在文本框中输入内容,然后对其进行加密或解密。其次,您可以选择文件来加密或解密它们。
参考文献
本文提供的信息来自 Microsoft Developer Network (MSDN) 和 Wrox Publications 的《Cryptography in .NET》一书。我只使用了该书的一个样本章节(第 2 章)。其余部分使用了我在 .NET 中处理加密的经验。
关于作者
Sameers(theAngrycodeR)于 2002 年 2 月获得了计算机科学硕士学位。他是 City Soft(巴基斯坦)的项目经理,并已开发和管理了多个项目。他在 Visual Basic 6 中证明了他的专业知识,现在正在 VB .NET 中工作。他是 CodeProject.com 和 Microsoft .NET Community Site GotDotNet 的许多文章的作者。他还向 Planet-Source-Code.com 提交了许多源代码。有关作者的完整信息可以在 这里找到。