圖像隱寫(xiě)算法LSB—Least Significant Bits,又稱(chēng)最不顯著位。LSB算法就是將秘密信息嵌入到載體圖像像素值得最低有效位,改變這一位置對(duì)載體圖像的品質(zhì)影響最小。
原理如下:
以實(shí)驗(yàn)用的24位真彩圖為例,每個(gè)像素用3Byte表示,每Byte分別表示R、G、B三色的亮度,亮度取值范圍位0~0xFF。采用LSB算法就是將圖像信息的每一Byte的最后一位二進(jìn)制替換為待嵌入的秘密信息的一位,按順序進(jìn)行。因?yàn)閷?duì)最后一位的替換操作其實(shí)就是對(duì)亮度信息的加一或減一,對(duì)顏色影響甚微,所以肉眼難以察覺(jué),這就達(dá)到了隱藏信息的目的。對(duì)于24位真彩圖,所能嵌入的最大秘密信息的大小為像素?cái)?shù)量的3/8字節(jié)
步驟如下:
以二進(jìn)制的方式讀取載體圖像并分別頭數(shù)據(jù)與像素?cái)?shù)據(jù)
用二進(jìn)制秘密信息中的每一筆特信息替換與之對(duì)應(yīng)的載體數(shù)據(jù)的最低有效位
利用得到的新的二進(jìn)制數(shù)據(jù)構(gòu)造圖像,即得到含有秘密信息的隱秘圖像
/***change.c***/#include<stdio.h>#include<stdlib.h>#include"define.h"int main(){ //創(chuàng)建頭文件,信息頭結(jié)構(gòu)變量 BMP_FILE_HEADER fileHeader; BMP_INFO_HEADER infoHeader; //打開(kāi)載體圖像文件,新建修改后的圖像文件 FILE *file = fopen("football.bmp","rb"); FILE *newFile = fopen("change.bmp","wbx"); //讀取文件頭,信息頭 fread(&fileHeader,14,1,file); fread(&infoHeader,40,1,file); //讀取24位真彩圖像的像素信息 RGB *img = (RGB *)malloc(infoHeader.sizeImage); fread(img,infoHeader.sizeImage,1,file); printf("Picture Size(width x height):%d x %d \n", infoHeader.width, infoHeader.height); //對(duì)圖片內(nèi)容進(jìn)行修改,每隔五個(gè)像素染黑一個(gè)像素 int i = 0; for (i = 0; i < infoHeader.sizeImage / 3; i += 5) { img[i].red = 0; img[i].green = 0; img[i].blue = 0; } printf("fwirte\n"); //將新的二進(jìn)制文件寫(xiě)入到新文件中 fwrite(&fileHeader,14,1,newFile); fwrite(&infoHeader,40,1,newFile); fwrite(img,infoHeader.sizeImage,1,newFile); fclose(file); fclose(newFile); return 0;}
修改圖像內(nèi)容的核心代碼如下:
int i = 0;for (i = 0; i < infoHeader.sizeImage / 3; i += 5){ img[i].red = 0; img[i].green = 0; img[i].blue = 0;}
infoHeader.sizeImage表示圖像數(shù)據(jù)的字節(jié)數(shù),在24位真彩位圖中,表示每個(gè)像素需要三個(gè)字節(jié),infoHeader.sizeImage/3表示位圖總像素?cái)?shù)
循環(huán)體中將每個(gè)顏色分量的亮度賦值為0,讓像素變黑,最終得到修改后的圖像。
以上是處理BMP圖像信息的原理。
下面通過(guò)LSB算法隱藏秘密信息,這里把define.h文件作為秘密信息隱藏,也可以選擇任何大小合適的文件作為秘密信息。
/***define.c***/typedef unsigned short WORD; //2 bytetypedef unsigned int DWORD; //4 bytetypedef unsigned char BYTE; //1 byte//head of filetypedef struct BMP_FILE_HEADER{ WORD type; DWORD size; WORD reserved1; WORD reserved2; DWORD offBits;}BMP_FILE_HEADER;//head of infomationtypedef struct BMP_INFO_HEADER{ DWORD size; int width; int height; WORD planes; WORD bitCount; DWORD compression; DWORD sizeImage; int xPelsPerMeter; int yPelsPerMeter; DWORD colorUsed; DWORD colorImportant;}BMP_INFO_HEADER;//RGBQUADtypedef struct RGBQUAD{ BYTE blue; BYTE green; BYTE red; BYTE reserved;}RGBQUAD;//RGBtypedef struct RGB{ BYTE blue; BYTE green; BYTE red;}RGB;
隱藏信息代碼:
/***hide.c***/#include<stdio.h>#include<stdlib.h>#include<sys/stat.h>#include<unistd.h>#include"define.h"//獲取文件大小int getFileSizeSystemCall(char *strFileName){ struct stat temp; stat(strFileName,&temp); return temp.st_size;}int main(){ //創(chuàng)建文件頭,信息頭結(jié)構(gòu)體變量 BMP_FILE_HEADER fileHeader; BMP_INFO_HEADER infoHeader; //打開(kāi)載體圖像文件,讀取文件頭和信息頭,打開(kāi)隱秘圖像信息 FILE *file = fopen("football.bmp","rb"); FILE *newFile = fopen("hide.bmp","wbx"); fread(&fileHeader,14,1,file); fread(&infoHeader,40,1,file); //讀取秘密信息文件“define.h” int infoSize = getFileSizeSystemCall("define.h"); printf("info size : %d\n",infoSize); BYTE *info = (BYTE *)malloc(infoSize); FILE *infoFile = fopen("define.h","rb"); fread(info,infoSize,1,infoFile); //讀取24位真彩圖像像素信息 BYTE *img = (BYTE *)malloc(infoHeader.sizeImage); fread(img,infoHeader.sizeImage,1,file); printf("Picture Size (Width x height) : %d x %d\n",infoHeader.width,infoHeader.height); printf("Can hide %d byte infomation\n",infoHeader.sizeImage/8); //LBS算法實(shí)現(xiàn),把隱秘信息的每一個(gè)字節(jié)8bit按照低字節(jié)到高字節(jié)的順序隱藏到像素信息的 //每8byte中的最低位 int i = 0,j = 1; BYTE tmp = 0x00; for(i = 0; i < infoSize; i++) { for(j = 0; j < 8; j++) { tmp = info[i] &0x01; if(tmp) { img[i*8+j] = img[i * 8 + j] | 0x01; } else { img[i*8+j] = img[i * 8 + j] & 0xfe; } info[i] = info[i] >> 1; } } //將修改后的二進(jìn)制數(shù)據(jù)寫(xiě)入到隱秘圖像文件中 fwrite(&fileHeader,14,1,newFile); fwrite(&infoHeader,40,1,newFile); fwrite(img,infoHeader.sizeImage,1,newFile); fclose(file); fclose(newFile); return 0;}
LSB算法實(shí)現(xiàn):
int i = 0,j = 1;BYTE tmp = 0x00;for(i = 0; i < infoSize; i++){ for(j = 0; j < 8; j++) { tmp = info[i] &0x01; if(tmp) { img[i*8+j] = img[i * 8 + j] | 0x01; } else { img[i*8+j] = img[i * 8 + j] & 0xfe; } info[i] = info[i] >> 1; }}
info[i]是存儲(chǔ)秘密信息的數(shù)組,通過(guò)把像素Byte數(shù)據(jù)與0x01按位或運(yùn)算使得最后一位為1,通過(guò)把像素Byte數(shù)據(jù)與0xfe(1111,1110)做按位與運(yùn)算使得最后一位為0(0 & x = 0)
stat函數(shù)用來(lái)獲取指定路徑下文件或文件夾的屬性。路徑可以不指定。
使用md5sum命令查看兩張圖片的MD5 HASH值
再對(duì)比一下文件的16進(jìn)制內(nèi)容,先使用xxd命令生成16進(jìn)制內(nèi)容:
xxd football.bmp > football.hex
xxd hide.bmp > hide.hex
再使用sed命令查看對(duì)比第五行內(nèi)容
sed -n 5p football.hex
sed -n 5p hide.hex
很明顯的可以看到像素?cái)?shù)據(jù)的每一字節(jié)的最后一位發(fā)生了變化,驗(yàn)證了LSB算法的原理。
提取信息
/***extract.c***/#include<stdio.h>#include<stdlib.h>#include"define.h"int main(){ //創(chuàng)建頭文件,信息頭結(jié)構(gòu)體變量 BMP_FILE_HEADER fileHeader; BMP_INFO_HEADER infoHeader; //讀取隱秘圖像文件,創(chuàng)建秘密信息文件 FILE *file = fopen("hide.bmp","rb"); FILE *extractFile = fopen("extract.txt","wbx"); BYTE *info = (BYTE *)malloc(738); //讀取頭文件,信息頭 fread(&fileHeader,14,1,file); fread(&infoHeader,40,1,file); //讀取24位真彩圖像的像素信息 BYTE *img = (BYTE *)malloc(infoHeader.sizeImage); fread(img,infoHeader.sizeImage,1,file); printf("Picture size : %d x %d \n",infoHeader.width,infoHeader.height); //信息提取部分,根據(jù)秘密信息的長(zhǎng)度,依次讀取隱秘圖像信息像素信息的最低bit,憑借成Byte int i = 0,j = 0; BYTE tmp = 0x00,ttmp = 0x00; for(i = 0; i < 738; i++) { tmp = 0x00; for(j = 0; j < 8; j++) { /*取每8位bit像素信息的最后一位拼接為1Byte的秘密信息*/ ttmp = img[i*8+j] & 0x01; ttmp = ttmp << j; //左移j位 tmp += ttmp; //每一位累加得到1Byte的tmp值 } info[i] = tmp; } //將提取的信息寫(xiě)入到秘密文件中 fwrite(info,738,1,extractFile); fclose(file); fclose(extractFile); return 0;}
使用md5sum查看兩個(gè)文件是否相同
md5sum define.h extract.txt
提取過(guò)程就是隱藏過(guò)程的逆過(guò)程,實(shí)現(xiàn)原理和隱藏過(guò)程類(lèi)似。需要注意的是,此處使用的文件長(zhǎng)度是固定的秘密信息的長(zhǎng)度,并且提前知道了隱藏信息包含在了指定圖片中。在實(shí)際處理中,在隱藏秘密信息時(shí),往往還需要一個(gè)嵌入標(biāo)識(shí)和長(zhǎng)度信息,來(lái)幫助程序判斷圖片中是否包含秘密信息,并說(shuō)明秘密信息長(zhǎng)度
拓展
修改 hide.c 并使用手動(dòng)輸入的數(shù)字作為密鑰來(lái)規(guī)定秘密信息隱藏與載體圖片的起始位置。
修改 extract.c 并根據(jù)輸入的秘鑰提取秘密信息
每 Byte 像素信息隱藏 2bit 的秘密信息(MLSB 算法)
分類(lèi): 實(shí)驗(yàn)樓
聯(lián)系客服