BMP图像信息隐藏
图像隐写算法LSB—Least Significant Bits,又称最不显著位。LSB算法就是将秘密信息嵌入到载体图像像素值得最低有效位,改变这一位置对载体图像的品质影响最小。
原理如下:
以实验用的24位真彩图为例,每个像素用3Byte表示,每Byte分别表示R、G、B三色的亮度,亮度取值范围位0~0xFF。采用LSB算法就是将图像信息的每一Byte的最后一位二进制替换为待嵌入的秘密信息的一位,按顺序进行。因为对最后一位的替换操作其实就是对亮度信息的加一或减一,对颜色影响甚微,所以肉眼难以察觉,这就达到了隐藏信息的目的。对于24位真彩图,所能嵌入的最大秘密信息的大小为像素数量的3/8字节
步骤如下:
- 以二进制的方式读取载体图像并分别头数据与像素数据
- 用二进制秘密信息中的每一笔特信息替换与之对应的载体数据的最低有效位
- 利用得到的新的二进制数据构造图像,即得到含有秘密信息的隐秘图像
/***
change.c
***/
#include<stdio.h>
#include<stdlib.h>
#include"define.h" int main()
{ //创建头文件,信息头结构变量
BMP_FILE_HEADER fileHeader;
BMP_INFO_HEADER infoHeader; //打开载体图像文件,新建修改后的图像文件
FILE *file = fopen("football.bmp","rb");
FILE *newFile = fopen("change.bmp","wbx"); //读取文件头,信息头
fread(&fileHeader,,,file);
fread(&infoHeader,,,file); //读取24位真彩图像的像素信息
RGB *img = (RGB *)malloc(infoHeader.sizeImage);
fread(img,infoHeader.sizeImage,,file); printf("Picture Size(width x height):%d x %d \n", infoHeader.width, infoHeader.height); //对图片内容进行修改,每隔五个像素染黑一个像素
int i = ;
for (i = ; i < infoHeader.sizeImage / ; i += )
{
img[i].red = ;
img[i].green = ;
img[i].blue = ;
}
printf("fwirte\n"); //将新的二进制文件写入到新文件中
fwrite(&fileHeader,,,newFile);
fwrite(&infoHeader,,,newFile);
fwrite(img,infoHeader.sizeImage,,newFile); fclose(file);
fclose(newFile);
return ;
}
修改图像内容的核心代码如下:
int i = ;
for (i = ; i < infoHeader.sizeImage / ; i += )
{
img[i].red = ;
img[i].green = ;
img[i].blue = ;
}
infoHeader.sizeImage表示图像数据的字节数,在24位真彩位图中,表示每个像素需要三个字节,infoHeader.sizeImage/3表示位图总像素数
循环体中将每个颜色分量的亮度赋值为0,让像素变黑,最终得到修改后的图像。
以上是处理BMP图像信息的原理。
下面通过LSB算法隐藏秘密信息,这里把define.h文件作为秘密信息隐藏,也可以选择任何大小合适的文件作为秘密信息。
/***
define.c
***/ typedef unsigned short WORD; //2 byte
typedef unsigned int DWORD; //4 byte
typedef unsigned char BYTE; //1 byte //head of file
typedef struct BMP_FILE_HEADER
{
WORD type;
DWORD size;
WORD reserved1;
WORD reserved2;
DWORD offBits;
}BMP_FILE_HEADER; //head of infomation
typedef struct BMP_INFO_HEADER
{
DWORD size;
int width;
int height;
WORD planes;
WORD bitCount;
DWORD compression;
DWORD sizeImage;
int xPelsPerMeter;
int yPelsPerMeter;
DWORD colorUsed;
DWORD colorImportant;
}BMP_INFO_HEADER; //RGBQUAD
typedef struct RGBQUAD
{
BYTE blue;
BYTE green;
BYTE red;
BYTE reserved;
}RGBQUAD; //RGB
typedef struct RGB
{
BYTE blue;
BYTE green;
BYTE red;
}RGB;
隐藏信息代码:
/***
hide.c
***/
#include<stdio.h>
#include<stdlib.h> #include<sys/stat.h>
#include<unistd.h> #include"define.h" //获取文件大小
int getFileSizeSystemCall(char *strFileName)
{
struct stat temp;
stat(strFileName,&temp);
return temp.st_size;
} int main()
{
//创建文件头,信息头结构体变量
BMP_FILE_HEADER fileHeader;
BMP_INFO_HEADER infoHeader; //打开载体图像文件,读取文件头和信息头,打开隐秘图像信息
FILE *file = fopen("football.bmp","rb");
FILE *newFile = fopen("hide.bmp","wbx");
fread(&fileHeader,,,file);
fread(&infoHeader,,,file); //读取秘密信息文件“define.h”
int infoSize = getFileSizeSystemCall("define.h");
printf("info size : %d\n",infoSize);
BYTE *info = (BYTE *)malloc(infoSize);
FILE *infoFile = fopen("define.h","rb");
fread(info,infoSize,,infoFile); //读取24位真彩图像像素信息
BYTE *img = (BYTE *)malloc(infoHeader.sizeImage);
fread(img,infoHeader.sizeImage,,file); printf("Picture Size (Width x height) : %d x %d\n",infoHeader.width,infoHeader.height);
printf("Can hide %d byte infomation\n",infoHeader.sizeImage/); //LBS算法实现,把隐秘信息的每一个字节8bit按照低字节到高字节的顺序隐藏到像素信息的
//每8byte中的最低位
int i = ,j = ;
BYTE tmp = 0x00;
for(i = ; i < infoSize; i++)
{
for(j = ; j < ; j++)
{
tmp = info[i] &0x01;
if(tmp)
{
img[i*+j] = img[i * + j] | 0x01;
}
else
{
img[i*+j] = img[i * + j] & 0xfe;
}
info[i] = info[i] >> ;
}
} //将修改后的二进制数据写入到隐秘图像文件中
fwrite(&fileHeader,,,newFile);
fwrite(&infoHeader,,,newFile);
fwrite(img,infoHeader.sizeImage,,newFile); fclose(file);
fclose(newFile);
return ;
}
LSB算法实现:
int i = ,j = ;
BYTE tmp = 0x00;
for(i = ; i < infoSize; i++)
{
for(j = ; j < ; j++)
{
tmp = info[i] &0x01;
if(tmp)
{
img[i*+j] = img[i * + j] | 0x01;
}
else
{
img[i*+j] = img[i * + j] & 0xfe;
}
info[i] = info[i] >> ;
}
}
info[i]是存储秘密信息的数组,通过把像素Byte数据与0x01按位或运算使得最后一位为1,通过把像素Byte数据与0xfe(1111,1110)做按位与运算使得最后一位为0(0 & x = 0)
stat函数用来获取指定路径下文件或文件夹的属性。路径可以不指定。
使用md5sum命令查看两张图片的MD5 HASH值

再对比一下文件的16进制内容,先使用xxd命令生成16进制内容:
xxd football.bmp > football.hex
xxd hide.bmp > hide.hex
再使用sed命令查看对比第五行内容
sed -n 5p football.hex
sed -n 5p hide.hex

很明显的可以看到像素数据的每一字节的最后一位发生了变化,验证了LSB算法的原理。
提取信息
/***
extract.c
***/
#include<stdio.h>
#include<stdlib.h>
#include"define.h" int main()
{
//创建头文件,信息头结构体变量
BMP_FILE_HEADER fileHeader;
BMP_INFO_HEADER infoHeader; //读取隐秘图像文件,创建秘密信息文件
FILE *file = fopen("hide.bmp","rb");
FILE *extractFile = fopen("extract.txt","wbx");
BYTE *info = (BYTE *)malloc(); //读取头文件,信息头
fread(&fileHeader,,,file);
fread(&infoHeader,,,file); //读取24位真彩图像的像素信息
BYTE *img = (BYTE *)malloc(infoHeader.sizeImage);
fread(img,infoHeader.sizeImage,,file); printf("Picture size : %d x %d \n",infoHeader.width,infoHeader.height); //信息提取部分,根据秘密信息的长度,依次读取隐秘图像信息像素信息的最低bit,凭借成Byte
int i = ,j = ;
BYTE tmp = 0x00,ttmp = 0x00;
for(i = ; i < ; i++)
{
tmp = 0x00;
for(j = ; j < ; j++)
{
/*取每8位bit像素信息的最后一位拼接为1Byte的秘密信息*/
ttmp = img[i*+j] & 0x01;
ttmp = ttmp << j; //左移j位
tmp += ttmp; //每一位累加得到1Byte的tmp值
}
info[i] = tmp;
} //将提取的信息写入到秘密文件中
fwrite(info,,,extractFile); fclose(file);
fclose(extractFile);
return ;
}
使用md5sum查看两个文件是否相同
md5sum define.h extract.txt

提取过程就是隐藏过程的逆过程,实现原理和隐藏过程类似。需要注意的是,此处使用的文件长度是固定的秘密信息的长度,并且提前知道了隐藏信息包含在了指定图片中。在实际处理中,在隐藏秘密信息时,往往还需要一个嵌入标识和长度信息,来帮助程序判断图片中是否包含秘密信息,并说明秘密信息长度
拓展
修改 hide.c 并使用手动输入的数字作为密钥来规定秘密信息隐藏与载体图片的起始位置。
修改 extract.c 并根据输入的秘钥提取秘密信息
每 Byte 像素信息隐藏 2bit 的秘密信息(MLSB 算法)
BMP图像信息隐藏的更多相关文章
- BMP 图像信息隐藏及检测
原理简介 针对文件结构的信息隐藏方法需详细掌握文件的格式,利用文件结构块之间的关系或根据块数据和块大小之间的关系来隐藏信息. BMP(Bitmap-File)图形文件是 Windows 采用的常见图形 ...
- Python实现图像信息隐藏
Python实现图像信息隐藏 之前学习密码学的时候老师有提到过『信息隐藏』,现在用图像的方法尝试一下.思想是:把信息藏到RGB通道中的B通道,然后利用奇偶性可以恢复过来 原理 从源图中提取文字图像信息 ...
- Windows 备用数据流(ADS)的妙用___转载
NTFS交换数据流(Alternate Data Streams,简称ADS)是NTFS磁盘格式的一个特性,在NTFS文件系统下,每个文件都可以存在多个数据流.通俗的理解,就是其它文件可以“寄宿”在某 ...
- delphi视频聊天
用Delphi开发视频聊天软件 一.引言 我们知道视频聊天软件的关键技术在于采集视频,并实时传输给聊天软件在线的人.对于视频的采集,这里采用微软公司的关于数字视频的一个软件包VFW(Video for ...
- 用Delphi开发视频聊天软件
摘要:目前网上视频聊天软件.视频会议软件.可视IP电话软件随处可见,你是否想自己做一个玩玩?其实这类软件无非是视频加上网络而建成的.如果熟悉视频捕捉和网络传输技术,根本就难不倒你.微软为软件开发人员提 ...
- 60701BMP彩色图像转化为灰度及二值图像
1 概述 多媒体技术是一门综合了多种学科的新技术,其涉及到计算机科学与技术.通信和网络技术.人工智能技术.微电子技术.数字信号处理.图形处 理技术.声像技术等诸多学科.许多新技术的不断出现和体验,带给 ...
- 将文件内容隐藏在bmp位图中
首先要实现这个功能,你必须知道bmp位图文件的格式,这里我就不多说了,请看:http://www.cnblogs.com/xiehy/archive/2011/06/07/2074405.html 接 ...
- BMP文件格式分析
前两天要做一个读取bmp文件的小程序,顺便查找了一些关于BMP格式的文章,现在post上来. 简介 BMP(Bitmap-File)图形文件是Windows采用的图形文件格式,在Windows环境下运 ...
- 注册表-各种功能-隐藏IE、隐藏硬盘、禁用硬件
1.在[我的电脑]上隐藏软驱 在[开始]→[运行]→输入[Regedit]→[HKEY_CURRENT_USER]→[Software] →[Microsoft] →[Windows]→[Curren ...
随机推荐
- IIS7 URL重写如何针对二级域名重写
二级域名与站点主域名是绑在同一目录下,想实现访问二级域名重写至站点下的某个目录. 如: 访问so.abc.cn 实际访问的是站点根目录下的search目录下的文件 相当于so.abc.cn绑定至s ...
- java之mybatis之一对多关联映射
1.在一对多的关联映射中,表结构如下 2.实体类结构 User.java public class User implements Serializable{ private int id; priv ...
- 【转载】 C#中使用float.Parse方法将字符串转换为Float类型
在C#编程过程中,很多时候涉及到数据类型的转换,例如将字符串类型的变量转换为单精度Float类型就是一个常见的类型转换操作,float.Parse方法是C#中专门用来将字符串转换为float类型的,f ...
- html解决空格显示问题
在前端里面,大家都知道,html中输入空格或换行是识别不了是空格的,但是有时候需要实现,那么该如何解决呢?主要有以下几个方面: 1:常用的转义: 2:使用全角拼音,然后输入空格也可实现 3:用标签 ...
- Django:实现读写分离
库的配置 1.读写分离 settings配置 #settings.py 配置库信息,生成2个库 DATABASES = { 'default': { 'ENGINE': 'django.db.back ...
- MySQL 统计上一周从周一到周日的用户
这个功能按理说很常见,奇怪的是很难搜索到一个合适的.稍微整理了下,具体的就不展开了,注意这个表中的时间为毫秒,这条语句拷贝复制就能用.照顾大部分的无脑码农. SELECT case when FROM ...
- python关于try except的使用方法
一.常见错误总结 AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x IOError 输入/输出异常;基本上是无法打开文件 ImportError 无法引入 ...
- Linux命令——chgrp、chown、chmod
简介 这三个命令都用于更改文件permission(权限).即下图红框位置 除此之外还有个“连结”,那个指的是硬链接,不是软连接.FS使用inode区分不同文件,而目录树使用文件名区分不同文件,因此可 ...
- svn: E155004: Working copy '/data/www' locked.
svn: run 'svn cleanup' to remove locks (type 'svn help cleanup' for details) svn: E155004: Working c ...
- ThinkPHP模板之二
模板布局及变量比较,循环. controller <?php /** * Created by PhpStorm. * User: Sahara * Date: 2019/6/23 * Time ...