1,关于数据区隐写
数据区隐写,即将数据写入到数据区中。相比文件外壳隐写和保留区隐写,更为隐蔽,隐藏的信息容量相对较大。在数据区隐写会造成图像变化,所以需要控制写入方式,以及改写量。使得在普通肉眼难以辨别的更改中实现数据的隐藏。至于其他的隐写方法请看:简单信息隐藏技术的实现与讨论。
2,24位bmp图像简介
要在bmp图像进行数据区隐写,必须要知道它的数据结构。否则,可能会破坏图像。 这是bmp的文件结构。
- 位图文件头(bitmap-file header)包含了图像类型、图像大小、图像数据存放地址和两个保留未使用的字段。(14字节)
- 位图信息头(bitmap-information header)(40字节)
- 彩色表/调色板(color table)[24位bmp图没有调色板]
- 位图数据(bitmap-data)
24位bmp图像数据存储的是实际的颜色数据,每个像素用3字节表示,分别是红绿蓝。文件头和信息头共占了54个字节。
3.程序设计思路
将bmp和txt读入之后,其实就是两个字符串。接下来要做的就是设计一个算法让它们合并。 考虑到如果直接替换数据区字符。会使像素点有巨大改变。所以,每个字符我只改末尾的一个bit,这样一来,像素点的变化会非常小,几乎没有区别。而且,我尽可能让更改的bit分散在数据区。为了方便提取,我在保留区记录了两个值,他们的异或值就是数据区隐藏信息字节的间隔值。
4.代码
01 |
//hid.cpp by kryptosx |
02 |
//隐藏程序代码 |
03 |
#include <iostream> |
04 |
#include <fstream> |
05 |
#include <bitset> |
06 |
#include<cstdlib> |
07 |
#include "stdio.h" |
08 |
using namespace std;
|
09 |
string pstr; |
10 |
string tstr; |
11 |
string stemp; |
12 |
const int py=54; //数据区开始位置(因为从0算起)
|
13 |
int main( int argc, char * argv[])
|
14 |
{ |
15 |
if (argc!=3)
|
16 |
{
|
17 |
puts ( "error:参数错误" );
|
18 |
return 0;
|
19 |
}
|
20 |
ifstream pic(argv[1]);
|
21 |
ifstream txt(argv[2]);
|
22 |
if (!pic.is_open() || !txt.is_open())
|
23 |
{
|
24 |
perror ( "文件打开失败" );
|
25 |
return 0;
|
26 |
}
|
27 |
while (getline(pic,stemp))
|
28 |
{
|
29 |
pstr+=stemp;
|
30 |
stemp.clear();
|
31 |
}
|
32 |
while (getline(txt,stemp))
|
33 |
{
|
34 |
tstr+=stemp;
|
35 |
stemp.clear();
|
36 |
}
|
37 |
int pl=pstr.size();
|
38 |
int tl=tstr.size();
|
39 |
|
40 |
if (tl>100)
|
41 |
{
|
42 |
puts ( "字符过多" );
|
43 |
printf ( "%d" ,tl);
|
44 |
return 0;
|
45 |
}
|
46 |
if (tl==0)
|
47 |
{
|
48 |
puts ( "没有字符" );
|
49 |
return 0;
|
50 |
}
|
51 |
int ty=(pl-py)/(tl*8); //计算间隔
|
52 |
int tp= rand ()%256;
|
53 |
pstr[6]=tl^tp;
|
54 |
pstr[7]=tp; //记录隐藏信息的长度到保留区中
|
55 |
for ( int i=py,j=0;j!=tl;++j) //把隐藏的信息转化成bit,写入到间隔的字节的最后一位。
|
56 |
{
|
57 |
bitset<8> bt(tstr[j]);
|
58 |
for ( int k=0;k!=8;k++)
|
59 |
{
|
60 |
if (bt[8-k-1]== true ) pstr[i]|=1;
|
61 |
else pstr[i]&=~1;
|
62 |
i+=ty;
|
63 |
}
|
64 |
}
|
65 |
ofstream out( "out.bmp" );
|
66 |
out<<pstr<<endl;
|
67 |
pic.close(); //关闭文件流
|
68 |
txt.close();
|
69 |
out.close();
|
70 |
return 0;
|
71 |
} |
01 |
//creck.cpp by kryptosx |
02 |
//数据提取代码 |
03 |
#include <iostream> |
04 |
#include <fstream> |
05 |
#include <bitset> |
06 |
#include<cstdlib> |
07 |
#include "stdio.h" |
08 |
using namespace std;
|
09 |
string pstr; |
10 |
string stemp; |
11 |
const int py=54;
|
12 |
int main( int argc, char * argv[])
|
13 |
{ |
14 |
if (argc!=2)
|
15 |
{
|
16 |
puts ( "error:参数错误" );
|
17 |
return 0;
|
18 |
}
|
19 |
ifstream pic(argv[1]);
|
20 |
if (!pic.is_open())
|
21 |
{
|
22 |
perror ( "文件打开失败" );
|
23 |
return 0;
|
24 |
}
|
25 |
while (getline(pic,stemp))
|
26 |
{
|
27 |
pstr+=stemp;
|
28 |
}
|
29 |
30 |
int pl=pstr.size();
|
31 |
int tl=pstr[6]^pstr[7]; //从保留区提取出隐藏信息的长度
|
32 |
int ty=(pl-py)/(tl*8); //计算间隔
|
33 |
|
34 |
char temp=0;
|
35 |
ofstream out( "out.txt" );
|
36 |
for ( int i=py,j=0;j!=tl;++j) //提取每个隐写字节末尾的bit,然后重组成隐藏信息。
|
37 |
{
|
38 |
temp=0;
|
39 |
for ( int k=0;k!=8;k++)
|
40 |
{
|
41 |
temp<<=1;
|
42 |
temp+=bitset<8>(pstr[i])[0];
|
43 |
i+=ty;
|
44 |
}
|
45 |
out<<temp;
|
46 |
}
|
47 |
pic.close();
|
48 |
out.close();
|
49 |
return 0;
|
50 |
} |
5.总结
这是一个很简单的图片数据区隐写程序,基于24位bmp图像。基本实现了需要的功能,分散的写入使得肉眼难以发现异常,其次,无需原图也可以提取信息。
转载请注明:旅途@KryptosX » 基于24位bmp图片数据区隐写的实现
时间: 2024-08-31 19:21:21