2016-09-12 84 views
1

我在寫一個存儲電子郵件帳戶信息的類。某些屬性(如電子郵件地址,帳戶密碼和服務器名稱)以加密形式存儲在私有變量中。序列化加密的類屬性

屬性setter對數據進行加密和解密消氣吧。

是的,我知道,存儲在軟件中的加密密鑰本質上是不安全的,但該代碼將在稍後的時候我可以找出一個替代改變。可能使用用戶輸入的密鑰或將用於生成正確密鑰的密碼。目前,該程序僅供個人使用。

當我試圖序列的加密信息,因爲信息是使用屬性getter其解密過程的數據訪問的信息被髮送到XML文件中明文。

我特別不希望有暴露一個額外的加密性能,並標記一個未加密通過串行忽視 - 它似乎不雅,可能不太安全。

我當然可以在主程序中傳遞給屬性setter之前進行de/encryption,但是我想知道如果我想重用'EmailAccount'類。

此外,我寧願暫時至少有明文XML文件,這樣我可以保證的是,EN /解密工作。我意識到我可以加密整個文件,但這是爲了以後。

下面是「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 = "[email protected]" 
     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,以便代碼可以單獨處理。

密碼散列也有一些不同。這個哈希是分開的,所以如果你改變迭代或方法,加密器和解密器不會最終使用不同的方法。

使用,測試:

Dim EmailAccts As New List(Of EmailAccount) 
EmailAccts.Add(New EmailAccount With {.User = "[email protected]", .SMTPPass = "secret!pass", 
             .UseSSL = True, .SMTPServer = "yadayada", .SMTPPort = -42}) 
EmailAccts.Add(New EmailAccount With {.User = "[email protected]", .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 

礦只是一個簡單的類自動屬性,因爲正在使用的密碼心不是。每個人都活了下來:

[email protected] ......密傳
[email protected] ... $粘性溢出$

+0

看起來我有很多需要了解加密等。非常感謝。所有冰雹Plutonix! –

+0

您也可以使用隨機數來計算迭代PW散列的時間並將其保存到基本流。枯萎是值得的麻煩取決於你的防範。請注意,如果它有幫助。 – Plutonix