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图片数据区隐写的实现