實(shí)驗(yàn)要求:
利用LSB算法將自己姓名隱藏到一張彩色圖片
(R通道)中。
可以從圖片中提取出隱藏的信息
實(shí)驗(yàn)用的是bmp文件。
bmp文件頭(bmp file header):提供文件的格式、大小等信息
位圖信息頭(bitmap information):提供圖像數(shù)據(jù)的尺寸、位平面數(shù)、壓縮方式、顏色索引等信息
調(diào)色板(color palette):可選,如使用索引來表示圖像,調(diào)色板就是索引與其對(duì)應(yīng)的顏色的映射表
位圖數(shù)據(jù)(bitmap data):就是圖像數(shù)據(jù)啦_
推薦一個(gè)軟件(010 Editor),可以清楚的看到文件的二進(jìn)制格式

軟件介紹

bmp文件頭
可以看到偏移量為54個(gè)字節(jié)

每個(gè)像素的信息
所以可以用c++打開這個(gè)二進(jìn)制文件,然后將字符串轉(zhuǎn)化為二進(jìn)制,最后添加到R通道的最后一位。
思路簡單,但是代碼稍微復(fù)雜一點(diǎn)
代碼如下:
頭文件:
#pragma once
#include <windows.h>
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
class HideBmp
{
public:
HideBmp(char* hstr);
~HideBmp();
bool GetBmp(char* bmp);
bool hidestring();
bool showstring();
int strtobin(char* hidestr);
private:
BITMAPFILEHEADER *bmfh;//bmp文件信息
char* hidestr;//需要隱藏的字符串
LPBYTE pBuf; //存儲(chǔ)bmp文件
DWORD BmpSize; //bmp文件的大小
BYTE* bin_str; //字符串的二進(jìn)制形式
int strsize; //字符串的長度
};
zjx_lsb.cpp
#include "zjx_lsb.h"
#include <fstream>
#include <iostream>
#include <typeinfo>
#include <sstream>
HideBmp::HideBmp(char* hstr)
{
this->hidestr = hstr;
this->pBuf = 0;
this->BmpSize = 0;
this->bin_str = new BYTE[8*strlen(hidestr)];
this->strsize=strlen(hidestr);
}
HideBmp::~HideBmp()
{
}
//將字符串轉(zhuǎn)化為二進(jìn)制
int HideBmp::strtobin(char* hidestr)
{
char temp_str;
int count = 0;
char* temp_bin_str = new char[8];
for (int i = 0; i < strlen(hidestr); i++)
{
temp_str = hidestr[i];
for (int j = 0; j < 8; j++)
{
if (temp_str % 2 == 0)
{
temp_bin_str[j] = '0';
}
else
{
temp_bin_str[j] = '1';
}
temp_str /= 2;
}
for (int k = 0; k < 8; k++)
{
bin_str[count] = temp_bin_str[7 - k];
count++;
}
}
return 0;
}
/*將圖片的信息全部讀入pBuf中*/
bool HideBmp::GetBmp(char* bmp)
{
if (pBuf)
{
delete[] pBuf;
}
HANDLE hfile = CreateFileA(bmp, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
if (hfile == INVALID_HANDLE_VALUE)
{
return false;
}
BmpSize = GetFileSize(hfile,0);
ifstream inFile(bmp, ios::in | ios::binary);
if (!inFile.is_open()) {
cout << "open error" << endl;
return 0;
}
pBuf = new byte[BmpSize];
inFile.read((char*)pBuf,BmpSize);
cout << "讀入圖片成功" << endl;
inFile.close();
bmfh = (BITMAPFILEHEADER*)pBuf;
return TRUE;
}
bool HideBmp::hidestring()
{
strtobin(hidestr);
string FileName = "EncodeBmp.bmp";
LPBYTE rgbbegin = pBuf + bmfh->bfOffBits + 2;
for (int i = 0, count = 0; count < 8*strsize; count++, i += 3)
{
bin_str[count] = (bin_str[count] | 0xFE) & 0x1;
rgbbegin[i] = (rgbbegin[i] &0xFE)| bin_str[count];
}
cout << endl;
cout << "***********************" << endl;
cout << endl;
ofstream outfile(FileName,ios::out|ios::binary);
outfile.write((char*)pBuf, BmpSize);
outfile.close();
cout << "加密文件生成成功" << endl;
cout << endl;
cout << "***********************" << endl;
return TRUE;
}
bool HideBmp::showstring()
{
string FileName = "EncodeBmp.bmp";
char* DeStr=new char[8*strsize];
ifstream infile(FileName, ios::in | ios::binary);
LPBYTE de_pBuf=new BYTE[BmpSize];
infile.read((char*)de_pBuf, BmpSize);
LPBYTE rgbbegin = de_pBuf + bmfh->bfOffBits + 2;
for (int i = 0, count = 0; count < 8 * strsize; count++, i += 3)
{
if (rgbbegin[i] % 2 == 0)
DeStr[count] = '0';
else
DeStr[count] = '1';
}
stringstream ss;
int a;
char* str = new char[8];
char t = 0x1;
//將解密出的二進(jìn)制賦值
for (int i = 0; i < strsize; i++)
{
str[i] = 0x00;
for (int j = 0; j < 8; j++)
{
if (DeStr[i * 8 + j] == '1')
str[i] = str[i] | (t << (7 - j));
}
}
//輸出解密出的字符串
cout << endl;
cout << "***********************" << endl;
cout << "解密出的字符串:" << endl;
cout << endl;
for (int i = 0; i < strsize; i++)
{
cout << str[i];
}
cout << endl;
cout << endl;
cout << "***********************" << endl;
return true;
}
main.cpp
#include"zjx_lsb.h"
#include <iostream>
int main()
{
cout << "請(qǐng)輸入要隱藏的字符串" << endl;
//默認(rèn)200個(gè)字符串
char* hstr=new char[200] ;
cin >> hstr;
HideBmp hmp(hstr);
hmp.GetBmp("test.bmp");
hmp.hidestring();
hmp.showstring();
}
運(yùn)行截圖如下:

image.png
可以看到這兩個(gè)圖片有細(xì)微的差距

原圖.png

加密后的文件格式.png