加密和解密序列化对象
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 个块或多或少是噪声。
好的,所以我正在尝试创建一个系统,通过它我可以序列化字典,然后加密它,然后可以解密它,然后恢复字典。
它还包括一些基于设置的选择语句,用户可以根据这些设置设置是始终、从不还是提示加密。
我一直在尝试遵循 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 个块或多或少是噪声。