我正在编写一个存储电子邮件帐户信息的课程。某些属性(如电子邮件地址,帐户密码和服务器名称)以加密形式存储在私有变量中。
Property Setter对数据进行加密,Getter对其进行解密。
是的我知道在软件中存储加密密钥本质上是不安全的,但是当我找到替代方案时,该代码将会被更改。可能使用用户输入的密钥或将用于生成正确密钥的密码。目前,该计划仅供个人使用。
当我尝试序列化加密信息时,信息以纯文本形式发送到xml文件,因为使用Property Getter访问信息,当然这会解密数据。
我并不特别想要暴露额外的加密属性,并将未加密的属性标记为序列化程序忽略 - 它似乎不够优雅且可能不太安全。
我当然可以在将主程序传递给属性设置器之前在主程序中执行de / encryption,但是我想知道如果我想重新使用'那么这是否可以在类中完成以保持整洁。 EmailAccount'类。
此外,我希望暂时至少以纯文本形式使用xml文件,这样我才能确保en / decryption正常工作。我意识到我可以加密整个文件,但这是为了以后。
以下是' EmailAccount'的简化版本。上课..
Public Class EmailAccount
Public Enum UseSSL
Yes
No
End Enum
Dim _imapPwd As String
Dim _smtpPwd As String
Dim _user As String
Dim _imapServer As String
Dim _smtpServer As String
Dim _usessl As UseSSL
Dim _imapPort As Integer
Dim _smtpPort As Integer
Public Property User As String
Set(value As String)
_user = Encrypt(value)
End Set
Get
Return Decrypt(_user)
End Get
End Property
Public Property ImapPassword As String
Set(value As String)
_imapPwd = Encrypt(value)
End Set
Get
Return Decrypt(_imapPwd)
End Get
End Property
Public Property ImapServer As String
Set(value As String)
_imapServer = Encrypt(value)
End Set
Get
Return Decrypt(_imapServer)
End Get
End Property
Public Sub New()
User = "noemailset@nowhere.com"
ImapPassword = "nopasswordfddfsg"
ImapServer = "no.imap.server"
SmtpPassword = "nopasswordsdfgdf"
SmtpServer = "no.smtp.server"
ImapPort = -1
SmtpPort = -1
SslState = UseSSL.Yes
End Sub
Private Function Encrypt(clearText As String) As String
Dim EncryptionKey As String = "crypto key goes here"
Dim clearBytes As Byte() = Encoding.Unicode.GetBytes(clearText)
Using encryptor As Aes = Aes.Create()
Dim pdb As New Rfc2898DeriveBytes(EncryptionKey, New Byte() {&H49, &H76, &H61, &H6E, &H20, &H4D,
&H65, &H64, &H76, &H65, &H64, &H65,
&H76})
encryptor.Key = pdb.GetBytes(32)
encryptor.IV = pdb.GetBytes(16)
Using ms As New MemoryStream()
Using cs As New CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write)
cs.Write(clearBytes, 0, clearBytes.Length)
cs.Close()
End Using
clearText = Convert.ToBase64String(ms.ToArray())
End Using
End Using
Return clearText
End Function
Private Function Decrypt(cipherText As String) As String
Dim EncryptionKey As String = "crypto key goes here"
Dim cipherBytes As Byte() = Convert.FromBase64String(cipherText)
Using encryptor As Aes = Aes.Create()
Dim pdb As New Rfc2898DeriveBytes(EncryptionKey, New Byte() {&H49, &H76, &H61, &H6E, &H20, &H4D,
&H65, &H64, &H76, &H65, &H64, &H65,
&H76})
encryptor.Key = pdb.GetBytes(32)
encryptor.IV = pdb.GetBytes(16)
Using ms As New MemoryStream()
Using cs As New CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write)
cs.Write(cipherBytes, 0, cipherBytes.Length)
cs.Close()
End Using
cipherText = Encoding.Unicode.GetString(ms.ToArray())
End Using
End Using
Return cipherText
End Function
End Class
在我的主要表单中,我有以下步骤来序列化数据。
''' <summary>
''' Convert a class state into XML
''' </summary>
''' <typeparam name="T">The type of object</typeparam>
''' <param name="obj">The object to serilize</param>
''' <param name="FilePath">The path to the XML</param>
Public Shared Sub Serialize(Of T)(ByVal obj As T, Filepath As String)
Dim XmlBuddy As New System.Xml.Serialization.XmlSerializer(GetType(T))
Dim MySettings As New System.Xml.XmlWriterSettings()
MySettings.Indent = True
MySettings.CloseOutput = True
Dim MyWriter As System.Xml.XmlWriter = System.Xml.XmlWriter.Create(Filepath, MySettings)
XmlBuddy.Serialize(MyWriter, obj)
MyWriter.Flush()
MyWriter.Close()
End Sub
答案 0 :(得分:0)
您可以在加密中执行相同的操作,并在序列化程序流中使用CryptoStream
。这使用BinaryFormatter
:
Private Sub SaveEmails(data As List(Of EmailAccount), password As String,
Filepath As String)
' ToDo: further hashing, maybe
Dim key As Byte() = GetPasswordHash(passW, 32, 62700)
Dim iv(15) As Byte
Using rng As New RNGCryptoServiceProvider
rng.GetNonZeroBytes(iv)
End Using
' ToDo: Try/Catch
If File.Exists(Filepath) Then File.Delete(Filepath)
Using rij = Rijndael.Create()
rij.Padding = PaddingMode.ISO10126
Using cryptor As ICryptoTransform = rij.CreateEncryptor(key, iv),
fs As New FileStream(Filepath, FileMode.CreateNew, FileAccess.Write)
' write the iv to bare stream
fs.Write(iv, 0, iv.Length)
Using cs = New CryptoStream(fs, cryptor, CryptoStreamMode.Write)
Dim bf = New BinaryFormatter
bf.Serialize(cs, data)
' may not be needed - doesnt hurt
cs.FlushFinalBlock()
End Using
End Using
End Using
End Sub
Private Function LoadEmails(passW As String,
Filepath As String) As List(Of EmailAccount)
Dim iv(15) As Byte
Dim key As Byte() = GetPasswordHash(passW, 32, 62700)
Dim emails As List(Of EmailAccount)
Using rijAlg = Rijndael.Create()
rijAlg.Padding = PaddingMode.ISO10126
' to do: check if exists
Using fs As New FileStream(Filepath, FileMode.Open)
' read the IV first
fs.Read(iv, 0, iv.Length)
' USING encryptor AND CryptoStream
Using encryptor As ICryptoTransform = rijAlg.CreateDecryptor(key, iv),
cs As New CryptoStream(fs, encryptor, CryptoStreamMode.Read)
Dim bf As New BinaryFormatter
emails = CType(bf.Deserialize(cs), List(Of EmailAccount))
End Using
End Using
End Using
Return emails
End Function
Private Function GetPasswordHash(pw As String, count As Int32, iter As Int32) As Byte()
Dim salt As Byte() = {&H49, &H76, &H61, &H6E, &H20, &H4D,
&H65, &H64, &H76, &H65, &H64, &H65, &H76}
Using pbkdf As New Rfc2898DeriveBytes(pw, salt,
iter)
Return pbkdf.GetBytes(count)
End Using
End Function
一个区别是使用随机IV并将其写入基本流并从基本流中读取,这样每次保存文件时都可以使用新的文件,而不必将其保存在任何地方。这些可以是Crypto类的共享方法来创建CryptoStream
,以便代码可以单独处理。
密码也有点不同。那个hasher是分开的,所以如果你改变迭代或方法,加密器和解密器最终不会使用不同的方法。
用法,测试:
Dim EmailAccts As New List(Of EmailAccount)
EmailAccts.Add(New EmailAccount With {.User = "Ziggy@ziggysplace.net", .SMTPPass = "secret!pass",
.UseSSL = True, .SMTPServer = "yadayada", .SMTPPort = -42})
EmailAccts.Add(New EmailAccount With {.User = "david@somewhere.com", .SMTPPass = "$tack!overflow$",
.UseSSL = False, .SMTPServer = "blahblah", .SMTPPort = 314})
Dim password As String = "AWeak!pa$$WorD!"
SaveEmails(EmailAccts, password, "C:\Temp\secretemails.bin")
Dim newEmails = LoadEmails(password, "C:\Temp\secretemails.bin")
' is everyone ok?
For Each email In newEmails
Console.WriteLine("{0} ... {1}", email.User, email.SMTPPass)
Next
Mine只是一类简单的自动属性,因为加密不被使用。每个人都活了下来:
Ziggy@ziggysplace.net ...秘密!通过
david@somewhere.com ... $ tack!overflow $