BMP位圖文件加密

24位BMP位圖文件 
要利用BMP位圖進行加密首先需要了解BMP文件的存放格式,24位真彩BMP位圖文件包括3
部分: 
第一部分是BMP文件頭:前2個字節是“BM”,是用於識別BMP文件的標誌;第3、4、5、6
字節存放的是位圖文件的大小,以字節爲單位;第7、8、9、10字節是保留的,必須爲0
;第11、12、13、14字節給出位圖陣列相對於文件頭的偏移。 
第二部分是點位圖信息:從第29個字節開始,第29、30字節描述的是像素的位數;第35
、36、37、38字節確定圖像字節數的多少,但通常此項爲空。 
第三部分是位圖陣列:從第39個字節開始,每3個字節表示一個像素,這3個字節依次表
示該像素的紅、綠、藍亮度分量值。要從位圖文件中“擠"出用來隱藏其他重要信息的存
儲空間,就需要從這裏入手。 
實現原理 
根據亮度公式:I=0.3R+0.59G+0.11B可以知道人眼對於綠色分量最爲敏感,對藍色分
量最不敏感,綠色分量值改變1個單位就相當於藍色分量改變5個、紅色分量改變2個單位
。折算爲二進制,紅色分量可以改變其低兩位、綠色分量可以改變其最低位、藍色分量
可以改變其低三位。這樣就可以從描述每個像素的3個字節中得到2+1+3=6個比特的冗
餘信息位用於存儲其他文件的比特流。按此比率,從一幅24位BMP位圖中可以得到的最大
存儲空間爲:((位圖文件大小-40)×6)/(3×8),大約是其位圖文件長度的1/4。

由於位圖文件中每3個字節只能提供6個比特的存儲空間,所以需要12個字節才能完整保
存源文件的3個字節。 
本文制定的加密協議是先通過程序窗口輸入密碼,從位圖文件的第39個字節即位圖陣列
部分開始存儲,依次爲:源文件名、分割符“*”、源文件的長度、分割符“*”、源
文件的內容。其中源文件內容的每個字節需與密碼相異或,以起到對文件進一步加密的
效果。 
這裏需要特別指出的是:如果在網絡傳輸時該文件被截獲,從中將加密文件恢復出來的
可能性是非常小的。首先,從外觀上加密後的文件和一般的BMP文件沒有任何區別,而且
加密前後位圖文件大小也不會發生變化,不會引起截獲者的注意。其次,由於只有大約1
/4的空間存有隱含信息,對於被加密信息而言,其他3/4的內容都是冗餘位。在密碼學上
,往往採取加大冗餘位的方式來提高加密的可靠性,顯然這種擁有75%的冗餘碼的加密
方法還是頗爲可靠的。最後,破譯者並不知曉加密所採取的協議,而且待加密的內容都
同加密密鑰經過了異或運算,在沒有正確解密密碼的情況下也是很難破譯的。 
源文件的加密 
由於進行加密處理的過程中要頻繁進行位運算,所以選用在這方面較有優勢的Micorsoft
Visual C++ 6.0作爲開發工具。 
加密的關鍵是將待加密信息組成比特流,並將其按規定的格式依次填入載體位圖文件的
指定位中。首先要做好準備工作,由於每12個位圖文件的字節恰好可以用於保存3個源文
件的字節,而12又是3的整數倍,所以可以設定每12個字節爲一個循環。下面5個數組中
存放的數據用於處理每個循環中的各個字節所要進行的移位量和掩碼值等: 
//填冗餘位時的移位序列 
int move1[13]={6,5,2,0,7,4,2,1,-2,6,4,3,0}; 
//源文件的字節掩碼序列 
unsigned char mask1[13]={192,32,28,3,128,112,12,2,1,192,48,8,7}; 
//位圖文件的字節掩碼序列 
unsigned char 
mask2[13]={252,254,248,252,254,248,252,254,251,252,252,254,248}; 
//爲1時,存放待加密信息的緩存指針加一 
int add1[13]={0,0,0,1,0,0,0,0,1,0,0,0,1}; 
//爲1時,存放BMP文件的緩存指針加一 
int add2[13]={1,1,1,1,1,1,1,1,0,1,1,1,1}; 
接下來通過CFile類的Open()、ReadFile()等相關函數將待加密的源文件和用作加密載體
的位圖文件內容分別讀取到緩存buf1和buf2中,在此需要強調的是緩存的類型不能是通
常的char型,而必須是unsigned char型,否則會在處理帶有漢字的文件時出現錯誤。如
果源文件和載體位圖文件的大小不滿足1∶4的必要條件會導致空指針的異常錯誤,所以
要在進行加密算法之前先對源文件和載體位圖文件的大小進行比較。 
下面是部分主要代碼: 
//將源文件的文件名、文件長度、分割符、內容填入buf3緩存 
total=3+FileName1.GetLength()+str.GetLength()+FileLen1; 
buf3=new unsigned char[total]; 
for(int i0=0;i0<FileName1.GetLength()+str.GetLength()+1;i0++) 
buf3[i0]=title[i0]; 
i0++; 
//從第39個字節開始存儲其他信息 
pointer2=38; 
buf3[i0]=‘*’; 
//把文件內容與加密密鑰相異或 
for(int i1=0;i1<FileLen1;i1++) 
buf3[i0+i1+1]=buf1[i1]^PSW; 
while(pointer1<=total) 

//把將從buf3緩存中提取出來的比特流填入載體位圖的每個字節的冗餘比特位中 
if(move1[pointer3]>0) 
buf2[pointer2]=(buf2[pointer2]&mask2[pointer3])|((buf3[pointer1]&mask1[poin
ter3])>> 
move1[pointer3]); 
else 
buf2[pointer2]=(buf2[pointer2]&mask2[pointer3])|((buf3[pointer1]&mask1[poin
ter3]) 
<<(move1[pointer3]*(-1))); 
if(add1[pointer3]==1) 
pointer1++; //修正指針 
if(add2[pointer3]==1) 
pointer2++; //修正指針 
pointer3++; //修正指針 
pointer3%=13; 

程序跳出While循環時,已經將源文信息和位圖信息按協議融合好了,剩下的工作就是調
用MFC的CFile類的Write()和Close()成員函數將產生的密文從緩存保存到磁盤上的文件
,即含有加密信息的位圖文件。 
可以通過ACDSee等看圖軟件比較一下不含任何其他信息的原始位圖文件和新產生的融合
有密文信息的位圖文件,用肉眼是看不出它們的區別的,而且文件長度也沒有發生變化
。 
加密信息的恢復 
和大多數加解密程序一樣,本方法的解密和加密過程也是很類似的,只要將流程逆轉即
可。其實現的主要思路是按照協議將作爲載體的位圖文件中的指定位信息提取出來組成
比特流,並將此比特流拆分恢復成原始的源文信息。首先設定好移位值和掩碼: 
//合併文件信息字節時的移位序列 
int move2[13]={6,5,2,0,7,4,2,1,-2,6,4,3,0}; 
//位圖文件字節的掩碼序列 
unsigned char mask2[13]={3,1,7,3,1,7,3,1,4,3,3,1,7}; 
//爲1時,存放待恢復信息的緩存指針加一 
int add1[13]={0,0,0,1,0,0,0,0,1,0,0,0,1}; 
//爲1時,存放含有加密信息的BMP文件內容的緩存指針加一 
int add2[13]={1,1,1,1,1,1,1,1,0,1,1,1,1}; 
然後再通過CFile類的Open()、Read()等文件處理函數將含有加密信息的位圖文件內容讀
取到緩存中,下面進行的就是密文的提取與恢復工作: 
//其他文件的信息是從第39個字節開始存放的 
pointer2=38; 
//buf3緩存清零 
memset(buf3,0,FileLen2); 
//計算異或運算值 
PSW=MakePSW(); 
while(true) 

//從位圖文件的字節中提取出存儲的信息流並重組成待恢復的文件字節序列 
if(move2[pointer3]>0) 
buf3[pointer1]|=(buf2[pointer2]&mask2[pointer3])<<move2[pointer3]; 
else 
buf3[pointer1]|=(buf2[pointer2]&mask2[pointer3])>>(move2[pointer3]*(-1)); 

if(add1[pointer3]==1) 

if(buf3[pointer1]==‘*’) 
//分割符記數 
times++; 
if((pointer1>=0)&&(times==0)) 

CString str; 
str.Format(“%c”,buf3[pointer1]); 
//提取待恢復的文件名 
FileName1+=str; 

if((times==1)&&(buf3[pointer1]!=‘*’)) 

temp[pointer4]=buf3[pointer1]; pointer4++; 

if((times==2)&&(buf3[pointer1]==‘*’)) 

temp[pointer4]=0; 
//提取待恢復的文件長度 
FileLen1=static_cast<DWORD>(atoi 
(temp)); 
pointer4=0; 

if(times>=2) 

//通過再次異或運算恢復出源文件內容 
buf1[pointer4]=buf3[pointer1]^PSW; 
pointer4++; 

if(pointer4>FileLen1) 
//文件恢復完畢則跳出循環 
break; 
pointer1++; //修正指針 

if(add2[pointer3]==1) 
pointer2++;//修正指針 
pointer3++;//修正指針 
pointer3%=13; 

最後,根據已經從位圖中提取出來的源文件的文件名、文件擴展名,將解密出來的信息
按原來的文件名重新恢復出來。顯然如果在解密時輸入的密碼不正確的話,解出來的信
息是無法識別的。 
小 結 
該方法將重要信息隱藏於位圖文件中可以對其起到很好的保護作用,尤其是其載體爲普
通的24位BMP位圖文件,幾乎不會有人能意識到裏面會含有其他的信息。我們在利用電子
郵件發送機要文件時可以先將其隱藏於位圖之中,然後將此位圖以附件形式發送出去,
即使郵件被攔截偵聽,也不至於造成泄密。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章