.NET 中的密钥加密






2.73/5 (18投票s)
2004年11月28日
6分钟阅读

106838

1502
实现密钥加密。
对称密码学(密钥加密)
引言
本教程将展示如何在 .NET Framework 1.1 中通过 System.Security.Cryptography
实现对称密码学/密钥加密。
背景
密码学是研究如何打乱数据,以便
- 任何窃取它的人都无法解密它。
- 您的目标收件人将能够轻松解密它。
在这方面,它也涵盖了多种“罪过”,即爱管闲事的人无法阅读,甚至更糟的是,无法修改发送给其他收件人的消息。
密码学中的重要术语
将实际消息转换为编码形式(打乱)称为加密或编码,反之(解密)称为解密或解码。要加密的消息称为明文或消息文本。加密过程的输出称为密文或密码。发送消息文本的人称为发件人,打算接收消息文本的人称为收件人。以明文而不是密文发送消息给收件人称为明文发送。打算在发件人和收件人之间入侵/窃取密文的人称为入侵者或攻击者。用于加密或密码学工作的数据转换集合称为密码算法或简称为密码,通常转换通过一个或多个密钥参数化。破解密码的艺术称为密码分析,开发和破解密码的艺术统称为密码学。
密码学类型
有两种加密技术。
- 对称或传统加密
- 非对称或公钥加密
我们将只讨论对称密码学或加密方案。
对称或传统加密是早期使用的一种非常古老的加密方案,也称为密钥加密。在该方案中,发件人和收件人共享相同的加密和解密密钥。显然,该方案使用数学中旧的替换和置换函数来将明文的一个字符替换为另一个字符进行加密和解密,因此得名对称加密方案。该方案如下图所示
.NET Framework 为我们提供了以下密钥加密算法
- DES CryptoServiceProvider
- RC2 CryptoServiceProvider
- Rijndael Managed / AES(高级加密标准)
- TripleDESCryptoServiceProvider
分组密码
分组密码以纯组合方式操作,对大块明文逐块应用固定转换,最常见的分组大小是八字节。由于每个分组都经过大量处理,因此分组密码提供更高的安全性。然而,分组密码算法的执行速度往往较慢。
分组密码对每个分组使用相同的加密算法。因此,当使用相同的密钥和算法加密时,明文分组将始终返回相同的密文。因为这种行为可以用来破解密码,所以引入了密码模式,它根据早期分组加密的反馈修改加密过程。由此产生的加密提供了比简单分组加密更高的安全性。
分组密码模式
- 密码块链 (CBC) 模式引入了反馈。在加密每个明文块之前,它会与前一个块的密文通过位级异或运算结合。这确保即使明文包含许多相同的块,它们也会加密成不同的密文块。初始化向量在加密第一个明文块之前,通过位级异或运算与它结合。
- 密码反馈 (CFB) 模式将明文小增量处理成密文,而不是一次处理整个块。此模式使用一个长度为一个块的移位寄存器,并将其分成多个部分。例如,如果块大小为八字节,每次处理一个字节,则移位寄存器将分成八个部分。
- 电子密码本 (ECB) 模式单独加密每个块。这意味着任何相同且位于同一消息中,或使用相同密钥加密的不同消息中的明文块,都将转换为相同的密文块。
填充
大多数明文消息不包含完全填满块的字节数。通常,没有足够的字节来填满最后一个块。发生这种情况时,会将填充字符串添加到文本中。例如,如果块长度为 64 位,而最后一个块只包含 40 位,则会添加 24 位填充。
填充模式
- PKCS #7 填充字符串由一系列字节组成,每个字节都等于添加的填充字节总数。例如,如果需要添加 24 位(3 字节)填充,则填充字符串为 "03 03 03"。
- 零填充字符串由设置为零的字节组成。
我们将只使用 TripleDES 和 Rinjndael 算法。
让我们在 .NET Framework 1.1 中实现这个概念。我们将以 Radix/Base64 格式加密和解密数据以实现标准化。启动一个新的 Windows 应用程序项目并命名为“数字签名”,然后执行以下操作。
在 FORM1 上添加以下控件(界面应如下图所示:有关更清晰的说明,请下载代码)。
- 名为
Session Key
的 Groupbox,其中包含以下控件- 一个标签控件,文本为“选择一个密钥短语来派生密钥,或留空以派生一个随机会话密钥”。
- 一个名为“
TxtKeyPharse
”的文本框控件,并将其Multiline
属性设置为true
。
- 名为
Padding Mode
的 Groupbox,其中包含以下控件- 名为
Radiobutton2
的单选按钮,其Text
属性为“Zeros”。 - 名为
Radiobutton5
的单选按钮,其Text
属性为“PKCS7 (Default)”。
- 名为
- 名为
Block Mode
的 Groupbox,其中包含以下控件- 名为
Radiobutton1
的单选按钮,其Text
属性为“CBC (Cipher BlockChaining) Default mode”。 - 名为
Radiobutton3
的单选按钮,其Text
属性为“ECB (Electronic Codebook)”。 - 名为
Radiobutton4
的单选按钮,其Text
属性为“CFB (Cipher Feedback)”。
- 名为
- 包含以下控件的 Groupbox
- 三个名为
txtPlaintex
、TxtEncrypt
、TxtDecrypt
的文本框。后两个的只读属性设置为true
。 - 一个名为
Label1
的标签控件,其Text
属性为“在此处输入您的明文”。 - 一个名为
Button1
的按钮,其Text
属性为“Encrypt”。 - 一个名为
Button3
的按钮,其Text
属性为“Decrypt”。 - 名为 Cipher mode 的 Groupbox,其中包含以下控件
- 名为
Radiobutton10
的单选按钮,其Text
属性为“TripleDES”。 - 名为
Radiobutton11
的单选按钮,其Text
属性为“Rinjndael/AES”。
- 名为
- 三个名为
- 底部有一个标签控件
Label3
,用于显示所选密码的有效密钥/块大小。
界面就这些了。现在是编码时间。让我们开始吧
“Form1”的代码清单
Imports System.Security.Cryptography
Imports System.Text
Imports System.IO
Public Class Form1
Inherits System.Windows.Forms.Form
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
'set defaults inilizations for
Me.RadioButton1.Checked = True 'padding,
Me.RadioButton5.Checked = True 'cipher modes
Me.RadioButton10.Checked = True 'Algorithm
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles
Button3.Click
Dim fromEncrypt() As Byte, roundtrip As String
Dim d As String
'check TripleDEs was selected
If Me.RadioButton10.Checked = True Then
' Now decryption
Dim decryptor As ICryptoTransform = Tdes.CreateDecryptor(MyKey, MyIV)
'Now decrypt the previously encrypted message using the decryptor
' obtained in the above step.
'use main memory for I/O.
Dim msDecrypt As New MemoryStream(Encrypted1)
'get CryptoStream for decrypted data
Dim csDecrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)
fromEncrypt = New Byte(Encrypted1.Length) {}
'Read the data out of the crypto stream.
csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length)
'Convert the byte array back into a string.
roundtrip = Encoding.ASCII.GetString(fromEncrypt)
TxtDecrypt.Text = (roundtrip)
'get valid TripleDES key (or Block) sizes through KeySizes enumrator
Dim myKeySizes1 As KeySizes
For Each myKeySizes1 In Tdes.LegalKeySizes
With myKeySizes1
d = "Triple DES Legal key (or Block) sizes in bits:" & vbCrLf _
& "Max=" & .MaxSize & " bits " & _
"(" & (.MaxSize / 8) & " bytes)" & vbCrLf _
& "Min=" & .MinSize & " bits " & _
"(" & (.MinSize / 8) & " bytes)" & vbCrLf _
& "Skip=" & .SkipSize & " bits " & _
"(" & (.SkipSize / 8) & " bytes)"
End With
Next
'display them
MsgBox(d, MsgBoxStyle.Information)
Exit Sub
End If ' 10
'check TripleDEs was selected
If Me.RadioButton11.Checked = True Then
' Now decryption
Dim decryptor As ICryptoTransform = Rinjndael.CreateDecryptor(MyKey, MyIV)
'Now decrypt the previously encrypted message using the decryptor
' obtained in the above step.
'use main memory for I/O.
Dim msDecrypt As New MemoryStream(Encrypted1)
'get CryptoStream for decrypted data
Dim csDecrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)
fromEncrypt = New Byte(Encrypted1.Length) {}
'Read the data out of the crypto stream.
csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length)
'Convert the byte array back into a string.
roundtrip = Encoding.ASCII.GetString(fromEncrypt)
TxtDecrypt.Text = (roundtrip)
'get valid Rinjndael key (or Block) sizes through KeySizes enumrator
Dim myKeySizes As KeySizes
For Each myKeySizes In Rinjndael.LegalKeySizes
With myKeySizes
d = "Rijndael/AES Legal key (or Block) sizes in bits:" & vbCrLf _
& "Max=" & .MaxSize & " bits " & _
"(" & (.MaxSize / 8) & " bytes)" & vbCrLf _
& "Min=" & .MinSize & " bits " & _
"(" & (.MinSize / 8) & " bytes)" & vbCrLf _
& "Skip=" & .SkipSize & " bits " & _
"(" & (.SkipSize / 8) & " bytes"
End With
Next
'display them
MsgBox(d, MsgBoxStyle.Information)
Exit Sub
End If '11
End Sub
Private Sub Button1_Click_1(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim fromEncrypt() As Byte
Dim encrypted() As Byte
Dim toEncrypt() As Byte
Dim roundtrip As String
Dim key1() As Byte
Dim abytSalt() As Byte
Dim abytKey() As Byte
Dim str As String
'first set ICryptoTransform for encryption later
Dim encryptor As ICryptoTransform
'RandomNumberGenerator
Dim rng As RandomNumberGenerator = RandomNumberGenerator.Create()
' check to see if no key pharse is entered
If Me.TxtKeyPharse.Text = "" Then
'derive random key
Keypharse = False
End If
' check to see CFB mode is selected it will not work on rinjndael
' convert to default
If Me.RadioButton4.Checked = True Then
PdMode = CipherMode.CBC
End If
If Keypharse Then 'if Enter key pharse in textbox
'asssgin key to string variable
str = Me.TxtKeyPharse.Text
If Me.RadioButton10.Checked = True Then 'seleect TDES
' Tdes is used so set key and iv/salt arrays to valid size
ReDim abytSalt(11) '12 bit Salt
ReDim abytKey(23) '24 bit key
'use PasswordDeriveBytes instance to derive a key
Dim pdb As New PasswordDeriveBytes(str, abytSalt)
'fill salt array to specfied size
rng.GetBytes(abytSalt)
'Get the same amount of bytes as the current abytKey length
abytKey = pdb.GetBytes(abytKey.Length)
'set padding mode
Tdes.Padding = Padd
'set cipher mode
Tdes.Mode = PdMode
'assign key
Tdes.Key = abytKey
'set key
MyKey = Tdes.Key
'Get IV.
Tdes.GenerateIV()
'set iv
MyIV = Tdes.IV
'CreateEncryptor for encryption later
encryptor = Tdes.CreateEncryptor(MyKey, MyIV)
End If ' 10
If Me.RadioButton11.Checked = True Then 'Rijndael is selected
'Rinjndael is used so set key and iv/salt arrays to valid size
' A good rule-of-thumb is to make the salt 1/2 the length of the key.
ReDim abytSalt(15) '16 bit salt
ReDim abytKey(31) '32 bit key
'use PasswordDeriveBytes instance to derive a key
Dim pdb As New PasswordDeriveBytes(str, abytSalt)
'fill salt array to specfied size
rng.GetBytes(abytSalt)
'Get the same amount of bytes as the current abytKey length
abytKey = pdb.GetBytes(abytKey.Length)
'set padding mode
Rinjndael.Padding = Padd
'set cipher mode
Rinjndael.Mode = PdMode
' assign key
Rinjndael.Key = abytKey
'set key
MyKey = Rinjndael.Key
'Get IV.
Rinjndael.GenerateIV()
'set IV
MyIV = Rinjndael.IV
'CreateEncryptor for encryption later
encryptor = Rinjndael.CreateEncryptor(MyKey, MyIV)
End If '11
Else 'no Keypharse is selected then derive random key and IV
'see which alogrithm is seected
If Me.RadioButton10.Checked = True Then 'TDES is used
'set padding mode
Tdes.Padding = Padd
'set cipher mode
Tdes.Mode = PdMode
'genrate random key
Tdes.GenerateKey()
'genrate random iv
Tdes.GenerateIV()
'set values
MyKey = Tdes.Key
'set iv
MyIV = Tdes.IV
'CreateEncryptor for encryption later
encryptor = Tdes.CreateEncryptor(MyKey, MyIV)
End If
If Me.RadioButton11.Checked = True Then 'Rinjndael is used
'set padding mode
Rinjndael.Padding = Padd
'set cipher mode
Rinjndael.Mode = PdMode
'genrate random key
Rinjndael.GenerateKey()
'genrate random iv
Rinjndael.GenerateIV()
'set values
MyKey = Rinjndael.Key
MyIV = Rinjndael.IV
'CreateEncryptor for encryption later
encryptor = Rinjndael.CreateEncryptor(MyKey, MyIV)
End If
End If 'Keypharse
'Encrypt the data. Whether TripleDES or Rinjndael is selected
'use main memory for I/O.
Dim msEncrypt As New MemoryStream
'get CryptoStream for encrypted data
Dim csEncrypt As New CryptoStream(msEncrypt, encryptor, _
CryptoStreamMode.Write)
'Convert the data to a byte array.
toEncrypt = Encoding.ASCII.GetBytes(Me.txtPlaintex.Text)
'Write all data to the crypto stream and flush it.
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length)
csEncrypt.FlushFinalBlock()
'Get encrypted array of bytes.
encrypted = msEncrypt.ToArray()
Encrypted1 = encrypted
'convert to base64/Radix form
TxtEncrypt.Text = Convert.ToBase64String(encrypted)
End Sub
Private Sub RadioButton1_CheckedChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs)
Handles RadioButton1.CheckedChanged, RadioButton3.CheckedChanged, _
RadioButton4.CheckedChanged
'return selected cipher mode number
PdMode = Pmode(sender.tabindex)
End Sub
Private Sub RadioButton6_CheckedChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs)
Handles RadioButton6.CheckedChanged, RadioButton5.CheckedChanged, _
RadioButton2.CheckedChanged
'return selected padding mode number
Padd = Padding(sender.tabindex)
End Sub
Private Sub TxtKeyPharse_TextChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles
TxtKeyPharse.TextChanged
'set to true if dat is enterned to know in future that key
'will be derived from key phrase
Keypharse = True
End Sub
Private Sub Button4_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles
Button4.Click
Help.ShowHelp(Me, Tut)
End Sub
End Class
所有代码都做了什么?
- 根据是否输入密钥文本以及选择适当的填充、密码和算法,加密按钮将为您加密文本。
- 之后,按解密按钮将解密 Base64 格式的文本。
- 有关详细解释,请参阅代码注释。
现在执行以下操作
- 为变量的全局声明添加一个名为“Global”的模块。
模块“Global”的代码清单
Imports System.Security.Cryptography
Imports System.Text
Module Global
'creates new instance of Tripldes
Public Tdes As New TripleDESCryptoServiceProvider
'creates new instance of Rinjndael
Public Rinjndael As New RijndaelManaged
'Stores key whether from phrase or random
Public MyKey() As Byte
'Stores random IV
Public MyIV() As Byte
'store encrypted data
Public Encrypted1() As Byte
'store decrypted data
Public Decrypted1() As Byte
'Unicode encoding instnace
Public MyEncoder As New UTF8Encoding
'flag to remember that key was derived from phrase
Public Keypharse As Boolean = False
'stores padding mode
Public Padd As Int16
'Store cipher mode
Public PdMode As Int16
'Function that will return selected Padding mode number
Public Function Padding(ByVal mode As Int16) As Int16
Padding = mode
Return Padding
End Function
'Function that will return selected Cipher block mode number
Public Function Pmode(ByVal mode As Int16) As Int16
Pmode = mode
Return Pmode
End Function
End Module 'global
我总是乐于助人,所以如果您对我的文章有任何疑问或建议,请随时给我发电子邮件。您也可以通过MSN Messenger,屏幕名为“Maxima”联系我。