【问题标题】:how do you save text data into binary file to be unreadable你如何将文本数据保存到二进制文件中以使其不可读
【发布时间】:2016-02-06 15:01:27
【问题描述】:

好吧,我只是无法在整个网络上找到一个好的简单示例来帮助我实现我的目标,而无需学习有关 vbnet 某些主题的全新章节。 我想保存重要的“设置”,例如用户计算机可以用来从他们的计算机访问远程服务器的管理密码。

在示例中,只要数据不是诸如“这是我的密码”之类的文本但不会显示 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

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

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

【问题讨论】:

  • So how do i get program user not to see the human readable information of binary text files 回答:加密目前谷歌搜索产生了数千个结果,请选择你的毒药。
  • 另外,我不知道这个问题已经在这里回答了多少次了。这是一个单独的例子stackoverflow.com/questions/7982933/…
  • @codexer。 SO中的伟大之处在于弹出并使用复制粘贴的简单示例。比在 21 天内阅读 vbnet 效果更好。
  • 这不仅仅是复制粘贴,而是试图理解所提出的解决方案。您可以编写满足您需要的代码,但如果您无法理解它,您将无法学习或获得任何成果。
  • @codexer 如果那是您的风格,则不会试图吸引您。对于一门新语言,我发现复制粘贴并获得我的解决方案和学习更容易。有时我会在以后更好地理解这件事。对于我来说,没有什么比 SO 更好的了。这是我的风格。它对我来说很好用。当我问我的时候,我已经在 SO 和其他许多论坛中失去了理智。无论如何,你的 cmets 还是很感激的。

标签: vb.net


【解决方案1】:

写入二进制文件时,文本不会被混淆。从技术上讲,您视为奇数字符的数字也不是不可读的 - 如果有人知道数据类型,他们可以计算出值。

为了使其不可读,您可以逐个加密每个字符串(如建议的欺骗链接中所示),或将您的流“包装”在Cryptostream 中。由于您希望BinaryWriter 会为您做一些伪加密,您可以完全跳过它。另一种选择是将信息存储在一个类中并使用CryptoStream 将其序列化以将其写出。

下面的代码使用类来保存这些不同的设置,并使用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:

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)

测试结果:

管理员
一些密码
地址(mysvr)
2016 年 2 月 6 日下午 13:56:44

您可以通过将二进制写入器包装在CryptoStream 中来执行类似的操作。序列化一个对象的价值在于只需一行代码就可以保存所有的值。

【讨论】:

  • 谢谢@plutonix。将测试此代码。看起来很像我要找的东西。
  • 编辑显示需要的导入和处理 ICryptoTransform 对象的轻微修改
  • @webzy 如果这回答了问题,请单击复选标记,以便将其从未回答列表中移出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-22
  • 1970-01-01
  • 1970-01-01
  • 2014-10-18
  • 2011-11-07
  • 1970-01-01
相关资源
最近更新 更多