记得在很久以前,听过一个朋友说过图片水印加密技术(他好像也是从书上看来的),图片水印加密技术——就是将文字信息转化为对应的二进制信息后,写入BMP图片中,例如某文字的二进制码为01001001,则分别将0、1、0、0、1、0、0、1写入bmp图片的八个像素中,从而达到隐藏信息的作用,最后也可用特定的程序将信息还原。

          但在他告诉我的方法中,对文本编码方式有特殊要求,特别是中文——必须是GB2312编码,否则还原后的文字将是乱码。并且,仅仅这样对文字进行隐藏是不太安全的,对方只要有一个类似的加解密软件,便可将信息全部还原。

          我在研究这种算法一段时间后,有了一些想法——我们可以现将文本信息进行一次AES加密(或其他的加密算法)后,在将加密后的密文写入bmp图片中。这样对文本信息进行处理后,密文既有隐藏式加密的隐秘性,又有算法式加密的复杂性,可谓是一种更强的加密方式!

因此,我将我的方法写成了一个.net类库,并改进了文本的二进制编码方式,使其不受特定编码的限制。

以下是代码,望高手赐教!!

(类库中包含AES加密模块,也可改为其他加密算法)

 

 

代码
Imports System.Security
Imports System.Security.Cryptography
Imports System.Text
Imports System.IO
Imports System.Runtime.Serialization.Formatters

Public Class AesWithBMP

<Serializable()> Public Structure KeyFileStructure ‘可用此结构来创建一个密钥文件
Public strKey As String ’密钥
Public strIV As String ‘初始向量
Public IsEnCryptWithBMP As Boolean ’是否写入bmp图片
Public IsInputBMPWithEnCrypt As Boolean ‘写入bmp图片的内容是否经过AES加密
End Structure

Public Sub CreateKeyFile(ByVal strKey As String, ByVal strIV As String, ByVal IsEnCryptWithBMP As Boolean, ByVal IsInputBMPWithEnCrypt As Boolean, ByVal KeySaveName As String, Optional ByVal IsRewriteKeyFile As Boolean = False) ’此函数用于在指定路径创建一个密钥文件

Dim fStream As FileStream = Nothing

Try

If Not File.Exists(KeySaveName) Then

Dim KeyStructure As New KeyFileStructure
With KeyStructure
.strKey
= strKey
.strIV
= strIV
.IsEnCryptWithBMP
= IsEnCryptWithBMP
.IsInputBMPWithEnCrypt
= IsInputBMPWithEnCrypt
End With

Dim kFomatter As New Binary.BinaryFormatter

fStream
= New FileStream(KeySaveName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)

kFomatter.Serialize(fStream, KeyStructure) ‘将密钥结构序列化

Else

If IsRewriteKeyFile Then ’当发现同名密钥文件时是否覆盖

Dim KeyStructure As New KeyFileStructure
With KeyStructure
.strKey
= strKey
.strIV
= strIV
.IsEnCryptWithBMP
= IsEnCryptWithBMP
.IsInputBMPWithEnCrypt
= IsInputBMPWithEnCrypt
End With

Dim kFomatter As New Binary.BinaryFormatter

fStream
= New FileStream(KeySaveName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)

kFomatter.Serialize(fStream, KeyStructure)

KeyStructure
= Nothing

End If

End If

Finally

If fStream IsNot Nothing Then fStream.Close()

End Try

End Sub

Public Sub GetKeyFile(ByVal SBKName As String, ByRef out_KeyFile As KeyFileStructure) ‘此过程用于从密钥文件中获取密钥等信息

Dim fStream As FileStream = Nothing

Try

Dim kFomatter As New Binary.BinaryFormatter
fStream
= New FileStream(SBKName, FileMode.Open, FileAccess.Read)

out_KeyFile
= kFomatter.Deserialize(fStream)

Finally

If fStream IsNot Nothing Then fStream.Close()

End Try

End Sub


Private Sub EnCrypt(ByVal SourceFileName As String, ByVal ResultFileName As String, ByVal Key As String, ByVal IV As String) ’对指定文件进行AES加密,并保存到指定路径

Dim myCryptoStream As CryptoStream = Nothing
Dim SourceFileStream As FileStream = Nothing
Dim ResultFileStream As FileStream = Nothing
Dim myAESProvider As AesCryptoServiceProvider = Nothing

Try

myAESProvider
= New AesCryptoServiceProvider

myAESProvider.Key
= ASCIIEncoding.ASCII.GetBytes(Key)
myAESProvider.IV
= ASCIIEncoding.ASCII.GetBytes(IV)

Dim myICryptoTransform As ICryptoTransform = myAESProvider.CreateEncryptor(myAESProvider.Key, myAESProvider.IV)

SourceFileStream
= New FileStream(SourceFileName, FileMode.Open, FileAccess.Read, FileShare.None)

ResultFileStream
= New FileStream(ResultFileName, FileMode.Create, FileAccess.Write)

myCryptoStream
= New CryptoStream(ResultFileStream, myICryptoTransform, CryptoStreamMode.Write)

Dim InputByteArray(SourceFileStream.Length - 1) As Byte

SourceFileStream.Read(InputByteArray,
0, InputByteArray.Length)

myCryptoStream.Write(InputByteArray,
0, InputByteArray.Length)

Finally

If myCryptoStream IsNot Nothing Then myCryptoStream.Close()
If SourceFileStream IsNot Nothing Then SourceFileStream.Close()
If ResultFileStream IsNot Nothing Then ResultFileStream.Close()
If myAESProvider IsNot Nothing Then myAESProvider.Clear()

End Try

End Sub

Private Sub DeCrypt(ByVal SourceFileName As String, ByVal ResultFileName As String, ByVal Key As String, ByVal IV As String) ‘对指定文件进行AES解密,并将明文保存到指定路径

Dim myCryptoStream As CryptoStream = Nothing
Dim SourceFileStream As FileStream = Nothing
Dim ResultFileStream As FileStream = Nothing
Dim myAESProvider As AesCryptoServiceProvider = Nothing

Try

myAESProvider
= New AesCryptoServiceProvider

myAESProvider.Key
= ASCIIEncoding.ASCII.GetBytes(Key)
myAESProvider.IV
= ASCIIEncoding.ASCII.GetBytes(IV)

Dim myICryptoTransform As ICryptoTransform = myAESProvider.CreateDecryptor(myAESProvider.Key, myAESProvider.IV)

SourceFileStream
= New FileStream(SourceFileName, FileMode.Open, FileAccess.Read, FileShare.None)

ResultFileStream
= New FileStream(ResultFileName, FileMode.Create, FileAccess.Write)

myCryptoStream
= New CryptoStream(ResultFileStream, myICryptoTransform, CryptoStreamMode.Write)

Dim InputByteArray(SourceFileStream.Length - 1) As Byte

SourceFileStream.Read(InputByteArray,
0, InputByteArray.Length)

myCryptoStream.Write(InputByteArray,
0, InputByteArray.Length)

Finally

If myCryptoStream IsNot Nothing Then myCryptoStream.Close()
If SourceFileStream IsNot Nothing Then SourceFileStream.Close()
If ResultFileStream IsNot Nothing Then ResultFileStream.Close()
If myAESProvider IsNot Nothing Then myAESProvider.Clear()

End Try

End Sub


Public Sub AES_EnCrypt(ByVal SourceFileName As String, ByVal ResultFileName As String, ByVal Key As String, ByVal IV As String, ByVal IsEnCryption As Boolean) ‘主调用过程,用于控制AES加解密过程的调用顺序

If IsEnCryption Then

EnCrypt(SourceFileName, ResultFileName, Key, IV)

Else

DeCrypt(SourceFileName, ResultFileName, Key, IV)

End If

End Sub

Private Function GetBitOfByte(ByVal b As Byte) As Byte() ’将一字节数分解为八个二进制位

Dim res(7) As Byte

For i As Integer = 0 To 7

res(
7 - i) = (b >> i) And 1

Next

Return res

End Function

Private Sub EnCryptWithBMP(ByVal SourceFileName As String, ByVal ResultBMPName As String, Optional ByVal IsInputBMPWithEnCrypt As Boolean = False, Optional ByVal strKey As String = "", Optional ByVal strIV As String = "") ‘次调用过程,控制图片水印加密过程的调用顺序

If IsInputBMPWithEnCrypt Then

Dim tempFileName As String = Path.GetTempFileName
EnCrypt(SourceFileName, tempFileName, strKey, strIV)
InputTextToBMP(tempFileName, ResultBMPName)
File.Delete(tempFileName)

Else

InputTextToBMP(SourceFileName, ResultBMPName)

End If

End Sub

Private Sub DeCryptWithBMP(ByVal SourceBMPName As String, ByVal ResultFileName As String, Optional ByVal IsInputBMPWithEnCrypt As Boolean = False, Optional ByVal strKey As String = "", Optional ByVal strIV As String = "") ’次调用过程,控制图片水印解密过程的调用顺序

If IsInputBMPWithEnCrypt Then

Dim tempFileName As String = Path.GetTempFileName
GetTextFromBMP(SourceBMPName, tempFileName)

DeCrypt(tempFileName, ResultFileName, strKey, strIV)
File.Delete(tempFileName)

Else

GetTextFromBMP(SourceBMPName, ResultFileName)

End If

End Sub

Public Sub AESwithBMP_EnCrypt(ByVal SourceFileName As String, ByVal ResultFileName As String, ByVal IsEnCryption As Boolean, Optional ByVal IsInputBMPWithEnCrypt As Boolean = False, Optional ByVal Key As String = "", Optional ByVal IV As String = "") ‘主调用过程,用于控制对图片水印的次调用过程的调用顺序

If IsEnCryption Then

If IsInputBMPWithEnCrypt Then

EnCryptWithBMP(SourceFileName, ResultFileName,
True, Key, IV)

Else

EnCryptWithBMP(SourceFileName, ResultFileName)

End If

Else

If IsInputBMPWithEnCrypt Then

DeCryptWithBMP(SourceFileName, ResultFileName,
True, Key, IV)

Else

DeCryptWithBMP(SourceFileName, ResultFileName)

End If

End If

End Sub

Private Sub InputTextToBMP(ByVal SourceFileName As String, ByVal BMPName As String) ’将指定的文本信息进行二进制编码后,写入指定bmp图片

Dim fStream As FileStream = Nothing
Dim bmpStream As FileStream = Nothing

Try

fStream
= New FileStream(SourceFileName, FileMode.Open, FileAccess.Read)
bmpStream
= New FileStream(BMPName, FileMode.Open, FileAccess.ReadWrite, FileShare.None)

Dim dm(1) As Byte
bmpStream.Read(dm,
0, 2)
If Not (dm(0) = 66 AndAlso dm(1) = 77) Then ’bmp图片的前两字节是文件类型标示位

Throw New ApplicationException("目标图片不是合法的BMP位图文件")

End If

Dim i As Integer
Dim BMP_Data(7) As Byte
Dim Text_Data(0) As Byte
Dim Input_Data(7) As Byte

bmpStream.Seek(
55, SeekOrigin.Begin) ‘将bmp图片的指针跳到第55字节,因为55字节后才是数据区。
For i = 0 To fStream.Length - 1

fStream.Read(Text_Data,
0, 1)

bmpStream.Read(BMP_Data,
0, 8)

Dim temp_Data() As Byte = GetBitOfByte(Text_Data(0))

For k As Integer = 0 To 7

If temp_Data(k) = 0 Then

Input_Data(k)
= BMP_Data(k) And 254
Else
Input_Data(k)
= BMP_Data(k) Or 1
End If

Next

bmpStream.Seek(
-8, SeekOrigin.Current)
bmpStream.Write(Input_Data,
0, 8)

Next

bmpStream.Read(BMP_Data,
0, 8)

For k As Integer = 0 To 7

Input_Data(k)
= BMP_Data(k) Or 1

Next

bmpStream.Seek(
-8, SeekOrigin.Current)
bmpStream.Write(Input_Data,
0, 8)

Finally

If fStream IsNot Nothing Then fStream.Close()
If bmpStream IsNot Nothing Then bmpStream.Close()

End Try

End Sub

Private Sub GetTextFromBMP(ByVal SourceBMPName As String, ByVal ResultFileName As String) ‘将指定bmp图片中的二进制信息还原为文本

Dim bmpStream As FileStream = Nothing
Dim fStream As FileStream = Nothing

Try

bmpStream
= New FileStream(SourceBMPName, FileMode.Open, FileAccess.Read, FileShare.None)
fStream
= New FileStream(ResultFileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)

Dim dm(1) As Byte
bmpStream.Read(dm,
0, 2)
If Not (dm(0) = 66 AndAlso dm(1) = 77) Then

Throw New ApplicationException("目标图片不是合法的BMP位图文件")

End If

bmpStream.Seek(
55, SeekOrigin.Begin)
Do

Dim BMP_Data(7) As Byte
Dim Text_Data(0) As Byte

bmpStream.Read(BMP_Data,
0, 8)

Dim temp_Data(7) As Byte

For k As Integer = 0 To 7

temp_Data(k)
= BMP_Data(k) And 1

Next

Dim resByte As Byte = GetByteFromBit(temp_Data)
If resByte = 255 Then

Exit Do

End If

fStream.WriteByte(resByte)

Loop

Finally

If fStream IsNot Nothing Then fStream.Close()
If bmpStream IsNot Nothing Then bmpStream.Close()

End Try

End Sub

Private Function GetByteFromBit(ByVal Bits() As Byte) As Byte ’根据八个二进制位算出对应的十进制数

Dim res As Byte

For i As Integer = 0 To 7

res
+= Bits(7 - i) * 2 ^ i

Next

Return res

End Function

End Class

 

posted on 2010-10-16 13:01  AniX  阅读(3584)  评论(1编辑  收藏  举报