实验要求:
利用LSB算法将自己姓名隐藏到一张彩色图片
(R通道)中。
可以从图片中提取出隐藏的信息
实验用的是bmp文件。
bmp文件头(bmp file header):提供文件的格式、大小等信息
位图信息头(bitmap information):提供图像数据的尺寸、位平面数、压缩方式、颜色索引等信息
调色板(color palette):可选,如使用索引来表示图像,调色板就是索引与其对应的颜色的映射表
位图数据(bitmap data):就是图像数据啦_
推荐一个软件(010 Editor),可以清楚的看到文件的二进制格式

软件介绍

bmp文件头
可以看到偏移量为54个字节

每个像素的信息
所以可以用c++打开这个二进制文件,然后将字符串转化为二进制,最后添加到R通道的最后一位。
思路简单,但是代码稍微复杂一点
代码如下:
头文件:
#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; //存储bmp文件
DWORD BmpSize; //bmp文件的大小
BYTE* bin_str; //字符串的二进制形式
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()
{
}
//将字符串转化为二进制
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;
//将解密出的二进制赋值
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 << "请输入要隐藏的字符串" << endl;
//默认200个字符串
char* hstr=new char[200] ;
cin >> hstr;
HideBmp hmp(hstr);
hmp.GetBmp("test.bmp");
hmp.hidestring();
hmp.showstring();
}
运行截图如下:

image.png
可以看到这两个图片有细微的差距

原图.png

加密后的文件格式.png