加密和解密序列化对象

Encrypting and Decrypting a Serialized Object

好的,所以我正在尝试创建一个系统,通过它我可以序列化字典,然后加密它,然后可以解密它,然后恢复字典。

它还包括一些基于设置的选择语句,用户可以根据这些设置设置是始终、从不还是提示加密。

我一直在尝试遵循 CryptoStream Class 文档,但由于某些原因,这不起作用。我认为加密可能有效,但该文件比 none 加密的 .ser 等效文件小很多,所以我不知道。解密会产生一个 "Attempting to deserialize an empty stream." 错误,这很容易解释,但我不知道如何修复它。

备份和还原在没有加密的情况下工作正常。

这里是相关的子例程(如果更容易,还有 GIT link),我们将不胜感激!这是一个 A Level 计算项目,所以我对加密的实际强度并不太在意(真的不想开始使用散列和加盐),只是它有效。

加密备份:

Private Sub encryptBackup()
    Dim key As Byte()
    Dim IV As Byte() = New Byte() {}

    Using MD5 As New MD5CryptoServiceProvider
        Dim tmp = System.Text.Encoding.UTF8.GetBytes(InputBox("Please insert password:", "Password Input") & "This is most definitely not an obtuse amount of salt")
        key = MD5.ComputeHash(tmp)
        IV = MD5.ComputeHash(key)
    End Using
    Using cryptoRijndael = Rijndael.Create()

        Dim cryptoCryptor As ICryptoTransform = cryptoRijndael.CreateEncryptor(key, IV)
        Using fStream As New FileStream(fldBackupJobs & "\Backup Files\" & Strings.Replace(Strings.Replace(Now, ":", "_"), "/", ".") & ".bin", FileMode.OpenOrCreate), cStream As New CryptoStream(fStream, cryptoCryptor, CryptoStreamMode.Write)
            Dim Formatter As New BinaryFormatter
            Formatter.Serialize(cStream, photoJobs)
            MsgBox("Written to file")
        End Using
    End Using
End Sub

解密备份:

Private Sub decryptBackup(pathsStr As String)
    photoJobs = Nothing
    Dim key As Byte()
    Dim IV As Byte() = New Byte() {}
    Using MD5 As New MD5CryptoServiceProvider
        Dim tmp = System.Text.Encoding.UTF8.GetBytes(InputBox("Please insert password:", "Password Input") & "This is most definitely not an obtuse amount of salt")
        key = MD5.ComputeHash(tmp)
        IV = MD5.ComputeHash(key)
    End Using
    Using cryptoRijndael = Rijndael.Create()
        Dim cryptoCryptor As ICryptoTransform = cryptoRijndael.CreateEncryptor(key, IV)
        pathstr = OpenFileDialog.FileName
        Using fStream As New FileStream(pathstr, FileMode.Open), cStream As New CryptoStream(fStream, cryptoCryptor, CryptoStreamMode.Read)
            Dim Formatter As New BinaryFormatter
            photoJobs = CType(Formatter.Deserialize(cStream), Dictionary(Of String, PhotoJob))
            MsgBox("Backup Restored")
        End Using
    End Using
End Sub

和GIT Link:https://github.com/hughesjs/Photo-Gift-Manager

提前致谢!!

代码的第一部分让我停顿了一下,因为(GoTo 之后)看起来加密方法取决于文件扩展名。由于用户可以通过 Explorer 更改它,因此它非常脆弱。并且不要让用户选择:如果需要加密,就做;如果没有,不要。当然,加密方法不应该由他们决定(我们有大笔资金为他们做这些决定)。

使用 BindingList(of Animal) 加密,我手头正好有:

Dim key As Byte()
Dim iv As Byte() = New Byte() {}

' see notes below
Using MD5 As New MD5CryptoServiceProvider
    ' UTF8 not unicode; convert password to Byte()
    Dim tmp = Encoding.UTF8.GetBytes(password & "$*^!#" & password)
    ' hash the PW to get the crypto Key
    key = MD5.ComputeHash(tmp)
    ' hash the Key to get the IV
    iv = MD5.ComputeHash(key)
End Using
    
Using rijAlg = Rijndael.Create()
      
    ' Create cryptor using the Key and IV
    Dim cryptor As ICryptoTransform = rijAlg.CreateEncryptor(key, IV)

    ' Open a filestream for the output file, wrap it with
    ' a CryptoStream created with the cryptor in WRITE (output) mode
    Using fs As New FileStream("C:\Temp\crypto.bin", FileMode.OpenOrCreate),
       cs As New CryptoStream(fs, cryptor, CryptoStreamMode.Write)

        ' serialize collection to CryptoStream (to disk)
        Dim bf As New BinaryFormatter
        bf.Serialize(cs, mcol)
    End Using

End Using

要解密,请使用相同的密钥和 IV:

mcol = Nothing

' the comments above pertain, just in reverse
Using rijAlg = Rijndael.Create()
    Dim cryptor As ICryptoTransform = rijAlg.CreateDecryptor(key, iv)
    Using fs As New FileStream("C:\Temp\crypto.bin", FileMode.Open),
       cs As New CryptoStream(fs, cryptor, CryptoStreamMode.Read)

        Dim bf As New BinaryFormatter
        ' Convert object to type
        mcol = CType(bf.Deserialize(cs), BindingList(Of Animal))
    End Using
End Using

' test:
For Each a As Animal In mcol
    Console.WriteLine(a.Name)
Next

我所有的动物都在这次旅行中幸存:

Rover
Gizmo
Ziggy

主要问题似乎是您使用的流太多了。在您的解密器中,您试图从与读取文件的密码流无关的 memstream 反序列化。事实上,它只是在之前创建的。加密流基本上只是包装您正在使用的任何“真实”流。

此外,这一行表明您没有使用 Option Strict:

photoJobs = formatter.Deserialize(memStreamSerial)

Deserialize returns 一个对象,photoJobs 是过去帖子中的某种集合 IIRC。请注意,我的代码使用 CType 转换为 BindingList(Of Animal).

对于比“Hello, World”更复杂的任何内容,请使用 Option Strict。总是。


加密注意事项/注意事项

从密码中导出(散列)IV 是个坏主意:这些应该是独立的数据片段。每条数据的 IV 应该是唯一的(当 PW 被重用时就不会这样)并且是唯一的。我在 PW 中添加了一些任意文本,因此 MD5 哈希不是直接 从 teh PW 派生的,但它仍然是次优的。

其次,MD5已经过时了。

创建随机IV

Private Const MinSize = 7
Public Shared Function GetRandomBytes(size As Integer) As Byte()
    ' dont allow less than a sensible min
    Dim data(If(size < MinSize, MinSize, size)) As Byte

    Using rng As New RNGCryptoServiceProvider
        ' fill the array 
        rng.GetNonZeroBytes(data)
    End Using
    Return data

End Function

将其放入加密工具库中,因为您将把它用于 IV,并将 Salt 用于散列。示例:

 myIV = CryptoUtils.GetRandomBytes(15)

如果 IV 每次都是唯一的,技巧就变成了如何保存它以便在解密时可以使用相同的值。 IV 不需要保密,因此可以在将其传递给 CryptoStream 构造函数之前将其保存到 FileStream 中。 Decrypt 方法执行相反的操作。

这些也可以制成方法,因此每次都使用相同的过程。


最后,如果您的问题更简洁,它们会得到更好的接受。该错误清楚地表明存在加密问题,因此前 2 个块或多或少是噪声。