嗯,我无法在网上找到一个很好的简单例子来帮助我实现我的目标,而无需在vbnet中学习一些关于某个主题的全新章节。 我想保存重要的"设置"例如管理密码,用户计算机可以使用它来从他们的计算机访问远程服务器。
在示例中,只要数据不是文本,例如&#34,我就让程序正常工作;这是我的密码"但不会透露像1232.78或布尔值
这样的数字使用记事本可以轻松地从文件中读取纯文本,即字符串。
有没有办法避免显示文本数据在二进制文件中明显可见?
Imports System
Imports System.IO
Public Class Form2
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Const fileName As String = "AppSettings.txt"
Using writer As BinaryWriter = New BinaryWriter(File.Open(fileName, FileMode.Create))
writer.Write("This is my secret password")
writer.Write(1.25F)
writer.Write("c:\Temp")
writer.Write(10)
writer.Write(True)
End Using
End Sub
end class
当我用记事本打开文件AppSettings.txt时显示
This is my secret password ?c:\Temp
其他一些无法在此显示的角色。 当我读取文本文件时,文本文件中的所有数据都能正确读取。
那么我如何让程序用户不要看到二进制文本文件的人类可读信息?
答案 0 :(得分:2)
写入二进制文件时,文本不会被混淆。从技术上讲,你看到奇数字符的数字也不是不可读的 - 如果有人知道数据类型,他们可以计算出值。
为了使其不可读,您可以逐个加密每个字符串(如在建议的欺骗链接中),或者在Cryptostream
中“包裹”您的流。既然你希望BinaryWriter
为你做一些伪加密,你可以完全跳过它。另一种方法是将信息存储在类中,并使用CryptoStream
将其序列化以将其写出。
下面的代码使用Class来保存这些不同的设置,使用BinaryFormatter
来序列化类。串行器将防止必须逐位写出数据,如果您要扩展或更改要保存的数据,只需修改类,而不是加密代码。服务器信息类:
<Serializable>
Public Class SvrSettings
Public Property Server As String
Public Property UserName As String
Public Property Password As String
Public Property SomeInt As Int32
Public Property SomethingElse As DateTime
' add anything else to be encrypted
End Class
' elsewhere put the data to save/encrypt in an instance:
SvrData = New SvrSettings
SvrData.UserName = "admin"
SvrData.Password = "some password"
SvrData.SomeInt = 42
SvrData.SomethingElse = DateTime.Now
SvrData.Server = "addressof(mysvr)"
保存到加密的二进制文件。您将需要一些新的进口:
Imports System.Security.Cryptography
Imports System.Runtime.Serialization.Formatters.Binary
'...
Dim password As String = "AWeakPassword"
Dim key As Byte() = Encoding.UTF8.GetBytes(password)
Dim iv(15) As Byte
Using rng As New RNGCryptoServiceProvider
rng.GetNonZeroBytes(iv)
End Using
Using rijAlg = Rijndael.Create()
rijAlg.Padding = PaddingMode.ISO10126
' USING encryptor AND filestream
Using encryptor As ICryptoTransform = rijAlg.CreateEncryptor(key, iv),
fs As New FileStream("C:\Temp\crypto.bin",
FileMode.OpenOrCreate Or FileMode.Truncate)
' save iv to "naked" filestream
fs.Write(iv, 0, iv.Length)
Using cs As New CryptoStream(fs, encryptor, CryptoStreamMode.Write)
Dim bf As New BinaryFormatter
bf.Serialize(cs, SvrData)
' may not be needed - doesnt hurt
cs.FlushFinalBlock()
End Using
End Using
End Using
序列化意味着同时保存该类中的所有数据。 CryptoStream
包裹FileStream
并进行实际加密。
您需要iv
来重新读取数据,而不是将其存储在某个地方,这会将其写入文件流,然后再将其写入CryptoStream
。读回来:
' read back to a new instance
Dim newSvrData As SvrSettings
Using rijAlg = Rijndael.Create()
rijAlg.Padding = PaddingMode.ISO10126
Using fs As New FileStream("C:\Temp\crypto.bin", 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
newSvrData = CType(bf.Deserialize(cs), SvrSettings)
End Using
End Using
End Using
' test if the data made the round trip:
Console.WriteLine(newSvrData.UserName)
Console.WriteLine(newSvrData.Password)
Console.WriteLine(newSvrData.Server)
Console.WriteLine(newSvrData.SomethingElse)
测试结果:
管理员
一些密码
addressof(MYSVR)
2/6/2016 13:56:44 PM
您可以通过将其包装在CryptoStream
中与二进制编写器进行类似的操作。序列化对象的价值在于它只是一行代码来保存所有值。