如何将文本数据保存到二进制文件中是不可读的

时间:2016-02-06 15:01:28

标签: vb.net

嗯,我无法在网上找到一个很好的简单例子来帮助我实现我的目标,而无需在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

其他一些无法在此显示的角色。 当我读取文本文件时,文本文件中的所有数据都能正确读取。

那么我如何让程序用户不要看到二进制文本文件的人类可读信息?

1 个答案:

答案 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中与二进制编写器进行类似的操作。序列化对象的价值在于它只是一行代码来保存所有值。