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

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

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

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

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

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

 

 




AESUtils 文件加密 aes加密图片_FileStream

AESUtils 文件加密 aes加密图片_AESUtils 文件加密_02

代码

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