用BMP文件实现数据加密

软件世界

数据加密有许多方法,而我们将利用BMP(BitMap-File,位图)文件作“掩护”来保护你的数据──谁又会知道你的桌面墙纸后可能就藏着你的重要数据呢?

加密原理

BMP是Windows采用的图形文件格式,是Windows系统内部各种图形操作的基础。其文件分四个部分:位图文件头、位图信息头、彩色表和图像数据阵列。其中位图文件头中包含了位图文件的长度(在4至6字节),也就是说,它自身的独特的结构特性是Windows依靠此文件信息对位图文件进行操作,而并不理会实际的文件长度到底是多少!并且Windows和一些图形软件(如:ACDSee等)都对位图文件有“自动纠错功能”,不信?你可以用十六进制编辑器在位图文件中写一些垃圾数据,结果只是造成图片的错位或是产生颜色的偏移,而图形本身还是可以辨认的!现在,我们来做个小实验:假设当前目录中存在BMP文件Bmpfile.bmp和另一文件other.txt,进入DOS,键入“copy bmpfile.bmp + other.txt new.bmp”,然后打开new.bmp,看到了什么了吗?显示与bmpfile.bmp一模一样!其实other.txt已经被bmp文件很好地保护了起来(new.bmp的长度是bmpfile.bmp和other.txt两文件长度的总和),连Windows也没有察觉它的存在。这样,我们就有了用BMP做加密文件的载体的前提条件了──我们可以将数据文件挂接到位图文件的后面或将文件拆分然后散布到位图文件的各个部分。
其实在Windows中应该还存在许多这样的媒体文件,它们都可以作为被加密文件的载体被我们所利用。有兴趣的朋友可以通过十六进制编辑器和简单的实验(如上述的copy实验)来验证其是否可为我所用。

代码实现

好了,我们现在用VB6做一个简单的模型来实现这个功能(数据文件挂接到位图文件的后面):
新建一工程,加载控件Microsoft Common Dialog Control 6.0,并放置一个到窗体上,命名为CDLog,再将以下代码写入窗体代码区即可。
Option Explicit
'用于存放位图所占实际存储空间
Dim glBmpSize As Long
Private Sub Form_Load()
On Error GoTo Exit_This
Dim sBmpFileName As String
Dim sFileName As String
Dim sPassword As String
Dim bFlag As Boolean
Me.Hide
sPassword = ""
CDlog.Filter = "请选择位图文件(*.BMP)|*.bmp"
CDlog.ShowOpen
sBmpFileName = CDlog.filename
CDlog.filename = ""
'获取位图文件是否含有加密文件的信息
'-True则进行文件加密;False则进行解密
bFlag = GetBmpMsg(sBmpFileName)
If bFlag Then
CDlog.Filter = "请选择要挂接的文件(*.*)|*.*"
CDlog.ShowOpen
sFileName = CDlog.filename
'获取加密时的密码
sPassword = InputBox("请输入密码:")
If sBmpFileName = sFileName Then
MsgBox "不能以自身为载体加密此文件!", vbOKOnly + vbExclamation
Else
'加密/挂接文件
Call LinkBmpFile(sBmpFileName, sFileName, sPassword)
MsgBox "文件加密成功!", vbOKOnly + vbInformation
End If
Else
'获取解密所需密码
sPassword = InputBox("位图文件中含有加密文件!" & vbCrLf & vbCrLf & "请输入密码:")
'获取文件保存信息
CDlog.Filter = "请保存要提取的文件(*.*)|*.*"
CDlog.ShowSave
sFileName = CDlog.filename
If sBmpFileName = sFileName Then
MsgBox "不能将文件保存为载体文件!", vbOKOnly + vbExclamation
Else
'分离/解密文件
Call SplitBmpFile(sBmpFileName,sFileName,sPassword)
MsgBox "文件解密成功!", vbOKOnly + vbInformation
End If
End If
Exit_This:
End
End Sub
Private Function GetBmpMsg(sBmpFile As String) As Boolean
'此函数完成Bmp文件是否含有加密文件的判断
'-True不包含加密文件;False包含加密文件
'假设位图不包含加密文件
GetBmpMsg = True
Open sBmpFile For Binary Access Read As #1
'获取bmp图片长度
Seek #1, 3
Get #1, , glBmpSize
Close #1
'若文件长度与图片实际长度不一致
'可断定位图文件中包含加密文件
If glBmpSize < FileLen(sBmpFile) Then
GetBmpMsg = False
End If
End Function
Private Sub LinkBmpFile(sBmpFile As String, sFile As String, sPass As String)
'此过程实现待加密文件与位图文件的挂接和加密操作
Dim iCount As Integer
Dim iPassLen As Integer
Dim bytBuffer As Byte
Open sBmpFile For Binary As #1
Open sFile For Binary Access Read As #2
'跳至位图文件操作位置,即文件结尾
Seek #1, glBmpSize
Do While Not EOF(1)
Get #1, , bytBuffer
Loop
iPassLen = Len(sPass)
iCount = 1
'挂接文件,并以“异或”操作对字节进行加密
Get #2, , bytBuffer
Do While Not EOF(2)
If iPassLen > 0 Then
'加密字节
bytBuffer = bytBuffer Xor Asc(Mid(sPass, iCount, 1))
'iCount顺序指向密码的不同位置
iCount = (iCount Mod iPassLen) + 1
End If
Put #1, , bytBuffer
Get #2, , bytBuffer
Loop
Close #2
Close #1
End Sub
Private Sub SplitBmpFile(sBmpFile As String, sFile As String, sPass As String)
'此过程实现待加密文件与位图文件的分离和解密操作
Dim iCount As Integer
Dim iPassLen As Integer
Dim bytBuffer As Byte
Open sBmpFile For Binary Access Read As #1
Open sFile For Binary Access Write As #2
'跳至位图文件操作位置
'即实际位图长度的下一位置(被挂接文件启始位置)
Seek #1, glBmpSize + 1
iPassLen = Len(sPass)
iCount = 1
'分离文件,并以“异或”操作对字节进行解密
Get #1, , bytBuffer
Do While Not EOF(1)
If iPassLen > 0 Then
'解密字节
bytBuffer = bytBuffer Xor Asc(Mid(sPass, iCount, 1))
'iCount顺序指向密码的不同位置
iCount = (iCount Mod iPassLen) + 1
End If
Put #2, , bytBuffer
Get #1, , bytBuffer
Loop
Close #2
Close #1
End Sub
(此程序在Windows Me/VB 6.0中调试通过)
注意:此程序仅使用了简单的异或(XOR)操作进行加密,而且密码是通过Inputbox以明文方式获取的,有兴趣的朋友可进一步对它进行补充完善。
最后再说两句,许多经典加密算法都是公开的,本人认为但凡加密,最主要的是两点:密码的选择与保护和加密算法,使用经典加密算法加密的文件主要要做好密码的保护工作;而如果你能自己写一加密算法,有足够的复杂度,不能被反编译轻易获取流程,而且此小程序只能被你一人或几人专用,可以说你的重要数据的密文被破解的可能性将很小,你的重要数据也会得到很好的保护。