实验目标
在BMP图片中实现ASCII码信息隐藏,并且可恢复密文。为了提高加密等级,采用将密文按每个比特隐藏进载体每个数据字节的方式。
前置知识
1.BMP位图
BMP位图是一种与设备无关的图像文件格式,使用广泛,采用位映射存储格式,可选图片深度,支持BI_RGB(无压缩)、BI_RLE8和BI_RLE4等压缩方式。采取小端存储方式。
BMP文件的数据按照文件头开始的先后分为4个部分:
BMP文件头:说明文件的类型、大小、数据偏移量。
位图信息头:说明图像的尺寸、深度、压缩方法、颜色索引数等特性。
颜色表/调色板(可选):对于使用索引颜色的图像,颜色表包含图像中使用的所有颜色,这在颜色深度较低时非常常见。
位图数据:根据biBitCount
和biCompression
的值,以不同的方式存储像素数据。
BMP图像深度可选1bit、4bit、8bit、16bit、24bit及32bit。1bit深度下每个像素只能表示两种颜色,一般是黑和白;4~24bit深度下每个像素能从(n=4,8,16)种颜色中选取一种来表示;24位颜色模式允许每个像素直接定义其RGB值一般不使用颜色表;32bit深度在24bit深度基础上增加8bit表示像素透明度(alpha层)。
根据BMP文件的结构,其文件头第11~14个字节保存了从文件头开始到实际图片数据之间的字节的偏移量,我们可以据此定位。
2.char类型
在C语言标准中,char
类型的大小被定义为1个字节,并在绝大多数现代环境中占据8位bit。在此次实验中使用char型处理数据。
3.ASCII码
ASCII码使用7或8位二进制数组合来表示128或256种字符。标准ASCII码使用7位二进制数(剩下一位固定为0)来表示所有的大写和小写字母,数字0到9、标点符号,以及在美式英语中使用的特殊控制字符。正好能保存在一个char型结构里。
逻辑分析
要将密文逐比特隐藏进载体图片,首先要定位到位图数据起始处或数据内的其他什么地方,咱定位到起始处,然后要将密文比特与载体字节结合,再塞到载体中,并且密文结束后要给出一段有一定特征的比特,来标识密文的结束,信息隐藏就结束哩。然后为了读取密文,程序要定位到密文开始的地方,然后读到结束标志后停止,并翻译出信息就大功告成哩。
代码实现(C语言)
首先我们的密文(ASCII码)要翻译成二进制数串。
// 将字符串转换为二进制
void string_to_binary(char *s, char *out)
{
char *out_p = out;
char *s_p = s;
while (*s_p)
{
unsigned char c = *s_p++;
for (int i = 7; i >= 0; --i)
{
*out_p = ((c & (1 << i)) ? '1' : '0');
out_p++;
}
}
*out_p = '\0';
}
在原文件中获取图片偏移量(块中fp是指向BMP图片文件起始位置的指针)。
// 获取图片偏移量
fseek(fp, 10, SEEK_SET);
unsigned char buffer[4];
fread(buffer, 1, 4, fp);
unsigned int picoffset = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
逐字节隐藏信息(c2change是操作数据用的一个char型变量,咱这里从原文件读数据,写入密文,再写入新文件;写入结束标志的话可以挑一个不会被使用的8位二进制作为结束标志在最后写入)。
while (binary[i] != '\0')
{
fread(&c2change, 1, 1, fp);
c2change = (c2change & 0xFE) | (binary[i] - '0');
// fseek(fp_new, -1, SEEK_CUR);
fwrite(&c2change, 1, 1, fp_new);
i++;
}
提取信息时,定位到密文初始处,从每个字节中取出密文,凑齐8个就翻译出一个字符。(我这里以'0000 0000'作为结束标志)。
while (1)
{
fread(&cthechange, 1, 1, fp);
now_character = (now_character << 1) | (cthechange & 1);
i++;
if (i % 8 == 0)
{
// 判断是否为结束标志
if (now_character == '\0')
{
out[j] = '\0';
break;
}
else
{
out[j] = now_character;
j++;
i = 0;
}
}
}
然后再加点创建新文件、一些文件操作、一些变量定义啥的就完成辣!
代码测试
好的,现在我们搞一个BMP位图:
分辨率 64x54,位深度32
隐藏密文1919810
用winhex观察
成功改写哩,让我们来对比下隐藏前后的两图:
现在图中右侧即是隐藏了数据的图片,用魔棒工具选区后发现有一小部分像素未被选中,即是被改写哩,从图中左下,我选择了从下从左第一个像素点,可见其颜色'e4d2aa'变成了'e5d2aa'。另外从调色板可以看出,多了一些相相相相相相相相当相似的颜色,根本看不出来嘛!!!!
从winhex上来看也是一片虚无口牙!!!!真是完美的隐藏!!!
咱的人机交互和操作也是丝滑得一匹吖!
一些问题
我没写防止密文串二进制位数比BMP文件数据字节还多得检测,一次隐藏太多就完蛋了(悲)。
附上资源链接
链接指向一压缩包,MD5值为 bad072fe7aa2de2245a4bab8a0001faf 。包中有一原BMP csdn.bmp和隐藏入1919810的csdn_new.bmp。还有我写的C语言代码,可以编译下玩玩。解压码是“csdn”。
链接:https://pan.baidu.com/s/1pr6vKYYI7WqKRB--RUIgkQ?pwd=chvi
提取码:chvi