图像隐写算法LSB—Least Significant Bits,又称最不显著位。LSB算法就是将秘密信息嵌入到载体图像像素值得最低有效位,改变这一位置对载体图像的品质影响最小。

原理如下:

以实验用的24位真彩图为例,每个像素用3Byte表示,每Byte分别表示R、G、B三色的亮度,亮度取值范围位0~0xFF。采用LSB算法就是将图像信息的每一Byte的最后一位二进制替换为待嵌入的秘密信息的一位,按顺序进行。因为对最后一位的替换操作其实就是对亮度信息的加一或减一,对颜色影响甚微,所以肉眼难以察觉,这就达到了隐藏信息的目的。对于24位真彩图,所能嵌入的最大秘密信息的大小为像素数量的3/8字节

步骤如下:

  1. 以二进制的方式读取载体图像并分别头数据与像素数据
  2. 用二进制秘密信息中的每一笔特信息替换与之对应的载体数据的最低有效位
  3. 利用得到的新的二进制数据构造图像,即得到含有秘密信息的隐秘图像
/***
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图像信息隐藏的更多相关文章

  1. BMP 图像信息隐藏及检测

    原理简介 针对文件结构的信息隐藏方法需详细掌握文件的格式,利用文件结构块之间的关系或根据块数据和块大小之间的关系来隐藏信息. BMP(Bitmap-File)图形文件是 Windows 采用的常见图形 ...

  2. Python实现图像信息隐藏

    Python实现图像信息隐藏 之前学习密码学的时候老师有提到过『信息隐藏』,现在用图像的方法尝试一下.思想是:把信息藏到RGB通道中的B通道,然后利用奇偶性可以恢复过来 原理 从源图中提取文字图像信息 ...

  3. Windows 备用数据流(ADS)的妙用___转载

    NTFS交换数据流(Alternate Data Streams,简称ADS)是NTFS磁盘格式的一个特性,在NTFS文件系统下,每个文件都可以存在多个数据流.通俗的理解,就是其它文件可以“寄宿”在某 ...

  4. delphi视频聊天

    用Delphi开发视频聊天软件 一.引言 我们知道视频聊天软件的关键技术在于采集视频,并实时传输给聊天软件在线的人.对于视频的采集,这里采用微软公司的关于数字视频的一个软件包VFW(Video for ...

  5. 用Delphi开发视频聊天软件

    摘要:目前网上视频聊天软件.视频会议软件.可视IP电话软件随处可见,你是否想自己做一个玩玩?其实这类软件无非是视频加上网络而建成的.如果熟悉视频捕捉和网络传输技术,根本就难不倒你.微软为软件开发人员提 ...

  6. 60701BMP彩色图像转化为灰度及二值图像

    1 概述 多媒体技术是一门综合了多种学科的新技术,其涉及到计算机科学与技术.通信和网络技术.人工智能技术.微电子技术.数字信号处理.图形处 理技术.声像技术等诸多学科.许多新技术的不断出现和体验,带给 ...

  7. 将文件内容隐藏在bmp位图中

    首先要实现这个功能,你必须知道bmp位图文件的格式,这里我就不多说了,请看:http://www.cnblogs.com/xiehy/archive/2011/06/07/2074405.html 接 ...

  8. BMP文件格式分析

    前两天要做一个读取bmp文件的小程序,顺便查找了一些关于BMP格式的文章,现在post上来. 简介 BMP(Bitmap-File)图形文件是Windows采用的图形文件格式,在Windows环境下运 ...

  9. 注册表-各种功能-隐藏IE、隐藏硬盘、禁用硬件

    1.在[我的电脑]上隐藏软驱 在[开始]→[运行]→输入[Regedit]→[HKEY_CURRENT_USER]→[Software] →[Microsoft] →[Windows]→[Curren ...

随机推荐

  1. 七牛云图床存储+Alfread工作流+使用QSHELL

    layout: post title: 七牛云图床存储+Alfread工作流+使用QSHELL 来源:http://www.cnblogs.com/cmi-sh-love/p/8901620.html ...

  2. Java自学-数组 创建数组

    Java 如何创建一个数组 数组是一个固定长度的,包含了相同类型数据的 容器 步骤 1 : 声明数组 int[] a; 声明了一个数组变量. []表示该变量是一个数组 int 表示数组里的每一个元素都 ...

  3. Python进阶----计算机基础知识(操作系统多道技术),进程概念, 并发概念,并行概念,多进程实现

    Python进阶----计算机基础知识(操作系统多道技术),进程概念, 并发概念,并行概念,多进程实现 一丶进程基础知识 什么是程序: ​   程序就是一堆文件 什么是进程: ​   进程就是一个正在 ...

  4. 【转载】 C#中使用decimal.Parse方法将字符串转换为十进制decimal类型

    在C#编程过程中,很多时候涉及到数据类型的转换,例如将字符串类型的变量转换为十进制decimal类型就是一个常见的类型转换操作,decimal.Parse方法是C#中专门用来将字符串转换为decima ...

  5. 英语foteball足球foteball单词

    现代足球起源地是在英格兰.传说在11世纪,英格兰与丹麦之间有过一场战争,战争结束后,英格兰人在清理战争废墟时发现一个丹麦入侵者的头骨,出于愤恨,他们便用脚去踢这个头骨,一群小孩见了便也来踢,不过他们发 ...

  6. Hive中的HiveServer2、Beeline及数据的压缩和存储

    1.使用HiveServer2及Beeline HiveServer2的作用:将hive变成一种server服务对外开放,多个客户端可以连接. 启动namenode.datanode.resource ...

  7. Yii2 路由美化

    一.美化路由形式 如:localhost/index.php?r=site/index 这种路由形式对SEO不友好,那么是否可以对路由进行一下美化呢?在Yii2中我们可以将路由必成以下的形式: 如:l ...

  8. Linux命令——uname

    简介 uname用于输出系统信息. uname参数 -a :所有系统相关的资讯,包括底下的数据都会被列出来:-s :系统核心名称-r :核心的版本-m :本系统的硬件名称,例如 i686 或 x86_ ...

  9. Windows与Linux之间海量文件的传输与Linux下大小写敏感问题

    Windows与Linux之间海量文件的传输与Linux下大小写敏感问题 mount.cifs 支持通过网络文件系统挂载,不过需要安装cifs-utils,也可通过mount -t cifs挂载,详细 ...

  10. KMP算法的时间复杂度与next数组分析

    一.什么是 KMP 算法 KMP 算法是一种改进的字符串匹配算法,用于判断一个字符串是否是另一个字符串的子串 二.KMP 算法的时间复杂度 O(m+n) 三.Next 数组 - KMP 算法的核心 K ...