2016-09-12 2 views
1

Я пишу класс, в котором хранятся данные учетной записи электронной почты. Некоторые свойства, такие как адрес электронной почты, пароль учетной записи и имена серверов, хранятся в зашифрованном виде в частных переменных.Сериализация зашифрованных свойств класса

Сетка свойств шифрует данные, и Геттер расшифровывает ее.

Да, я знаю, что хранение ключа шифрования в программном обеспечении по своей сути небезопасно, но этот код будет изменен позже, когда я смогу найти альтернативу. Вероятно, используя ключ, введенный пользователем, или пароль, который будет использоваться для генерации правильного ключа. В настоящий момент программа предназначена для личного использования.

Когда я пытаюсь выполнить сериализацию зашифрованной информации, информация отправляется в XML-файл в виде обычного текста, поскольку доступ к информации осуществляется с помощью Property Getter, который, конечно же, расшифровывает данные.

Я не особо хочу, чтобы выставляли дополнительное зашифрованное свойство и отмечали незашифрованный, который должен игнорировать сериализатор - он кажется неэлегантным и, возможно, менее безопасным.

Я мог бы, конечно же, сделать дешифрование в основной программе до того, как оно будет передано в средство настройки свойств, но мне интересно, можно ли это сделать в классе, чтобы сохранить что-то опрятное, если я хочу повторно использовать «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 = "[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 

Mine был только простой класс авто свойств, так как используется криптография, что не. Все выжили:

[email protected] ... секрет пройти
[email protected] ... $ липкость переполнить $

+0

Похоже, мне нужно много узнать о шифровании и т. Д. Большое спасибо. Все град Плутоникс! –

+0

Вы также можете использовать случайное число для количества времени для итерации хеша PW и сохранения его в базовом потоке. Увядание, которое стоит, зависит от того, на что вы защищаете. Пожалуйста, поддержите, если это поможет. – Plutonix

Смежные вопросы