简单信息隐藏技术的实现与讨论.docx
《简单信息隐藏技术的实现与讨论.docx》由会员分享,可在线阅读,更多相关《简单信息隐藏技术的实现与讨论.docx(15页珍藏版)》请在冰豆网上搜索。
简单信息隐藏技术的实现与讨论
图像的信息隐藏技术的实现与讨论
1.引言
数字图像的信息隐藏技术是数字图像处理领域中最具挑战性、最为活跃的研究课题之一。
本文概述了数字图像的信息隐藏技术,并给出了一个新的基于彩色静止数字图像的信息隐藏算法。
数字图像可分为静止图像和动态图像两种,后者一般称为视频图像。
视频图像的每一帧均可看作是一幅静止图像,但是这些静止图像之间并不是相互孤立的,而是存在时间轴上的相关性。
静止图像是像素(Pixel)的集合,相邻像素点所对应的实际距离称为图像的空间分辨率。
根据像素颜色信息的不同,数字图像可分为二值图像、灰度图像以及彩色图像。
数字图像的最终感受者是人的眼睛,人眼感受到的两幅质量非常相同的数字图像的像素值可能存在很大的差别。
这样,依赖于人的视觉系统(HumanVisualSystem,HVS)的不完善性,就为数字图像的失真压缩和信息隐藏提供了非常巨大的施展空间。
信息隐藏与信息加密是不尽相同的,信息加密是隐藏信息的内容,而信息隐藏是隐藏信息的存在性,信息隐藏比信息加密更为安全,因为它不容易引起攻击者的注意。
2.信息隐藏技术综述
2.1信息隐藏简介
信息隐藏(InformationHiding),也称作数据隐藏(DataHiding),或称作数字水印(DigitalWatermarking)。
简单来讲,信息隐藏是指将某一信号(一般称之为签字信号,SignatureSignal)嵌入(embedding)另一信号(一般称之为主信号,HostSignal,或称之为掩护媒体,cover-media)的过程,掩护媒体经嵌入信息后变成一个伪装媒体(stegano-media)。
这一嵌入过程需要满足下列条件:
·签字信号的不可感知性(Imperceptibility)。
换句话讲,签字信号嵌入后,主信号的感知特性没有明显的改变,签字信号被主信号"隐藏"了起来。
·签字信号的鲁棒性(Robustness)。
签字信号对主信号的各种失真变换,如失真信号压缩、仿射变换、加噪、A/D或D/A转换等,以及各种恶意性攻击(MaliciousAttack),都应体现出一定的鲁棒性。
除非主信号的感知特性被明显的破坏,签字信号将很难被去除。
·一般来讲,签字信号的嵌入不增加主信号的存储空间和传输带宽。
也就是说,签字信号嵌入后,"表面"上很难觉察到信息的改变。
信息隐藏的发展历史可以一直追溯到"匿形术(Steganography)"的使用。
"匿形术"一词来源于古希腊文中"隐藏的"和"图形"两个词语的组合。
虽然"匿形术"与"密码术(Cryptography)"都是致力于信息的保密技术,但是,两者的设计思想却完全不同。
"密码术"主要通过设计加密技术,使保密信息不可读,但是对于非授权者来讲,虽然他无法获知保密信息的具体内容,却能意识到保密信息的存在。
而"匿形术"则致力于通过设计精妙的方法,使得非授权者根本无从得知保密信息的存在与否。
相对于现代密码学来讲,信息隐藏的最大优势在于它并不限制对主信号的存取和访问,而是致力于签字信号的安全保密性。
2.2信息隐藏的关键技术
信息隐藏技术的关键在于如何处理签字信号的鲁棒性、不可感知性、以及所嵌入的数据量这三者之间的关系。
判断信息隐藏算法优劣的一般衡量准则为:
1).对于主信号发生的部分失真,签字信号是否具备一定的鲁棒性。
2).对于有意或无意的窃取、干扰或去除操作,签字信号是否具备一定的"抵抗"能力,从而保证隐藏信息的安全可靠和完整性。
3).签字信号的嵌入是否严重降低了主信号的感知效果。
4).数据嵌入量的大小。
对于某一特定的信息隐藏算法来讲,它不可能在上述的衡量准则下同时达到最优。
显然,数据的嵌入量越大,签字信号对原始主信号感知效果的影响也会越大;而签字信号的鲁棒性越好,其不可感知性也会就随之降低,反之亦然。
由于信息隐藏的应用领域十分宽广,不同的应用背景对其技术要求也不尽相同。
因此,有必要从不同的应用背景出发对信息隐藏技术进行分类,进而分别研究它们的技术需求。
根据应用背景的不同,信息隐藏技术大致可分为三类:
(1)版权保护(CopyrightProtection)
到目前为止,信息隐藏技术的绝大部分研究成果都是在这一应用领域中取得的。
信息隐藏技术在应用于版权保护时,所嵌入的签字信号通常被称作"数字水印(DigitalWatermark)"。
版权保护所需嵌入的数据量最小,但对签字信号的安全性和鲁棒性要求也最高,甚至是十分苛刻的。
为明确起见,应用于版权保护的信息隐藏技术一般称作"鲁棒型水印技术",而所嵌入的签字信号则相应的称作"鲁棒型水印(RobustWatermark)",从而与下文将要提到的"脆弱型水印"区别开来。
而一般所提到的"数字水印"则多指鲁棒型水印。
由于鲁棒型数字水印用于确认主信号的原作者或版权的合法拥有者,它必须保证对原始版权的准确无误的标识。
因为数字水印时刻面临着用户或侵权者有意或恶意的破坏,因此,鲁棒型水印技术必须保证在主信号可能发生的各种失真变换下,以及各种恶意攻击下都具备很高的抵抗能力。
与此同时,由于要求保证原始信号的感知效果尽可能不被破坏,因此对鲁棒型水印的不可见性也有很高的要求。
如何设计一套完美的数字水印算法,并伴随以制订相应的安全体系结构和标准,从而实现真正实用的版权保护方案,是信息隐藏技术最具挑战性也最具吸引力的一个课题。
(2)数据完整性鉴定(IntegrityAuthentication)
数据完整性鉴定,又称作数据篡改验证(TamperProof),是指对某一信号的真伪或完整性的判别,并进一步需要指出该信号与原始真实信号的差别,即提供有关证据指明真实信号可能经历的篡改操作[7]。
更形式化的讲,假定接收到一多媒体信号g(图像、音频或视频信号),初步判断它很可能是某一原始真实信号f的修改版本。
数据篡改验证的任务就是在对原始信号f的具体内容不可知的情况下,以最大的可能判断是否g=f。
一般的数据篡改验证过程如图3所示。
图3数据篡改验证一般过程
实用的数据篡改验证方法应致力于满足以下要求:
·以最大的可能指出是否有某种形式的篡改操作发生;
·提供对篡改后信号失真程度的度量方法;
·在无从得知原始真实信号的内容或其他与真实信号内容相关的信息的条件下,判断可能发生的篡改操作的具体类别,如判别是滤波、压缩,还是替代操作等;与此同时,应根据具体的应用背景,对经篡改后的信号给出相应的可信度;
·无需维护和同步操作任何与原始信号相分离的其它附加数据,即可恢复重建原始真实信号。
"脆弱型水印(FragileWatermark)"技术为数据篡改验证提供了一种新的解决途径。
该水印技术在原始真实信号中嵌入某种标记信息,通过鉴别这些标记信息的改动,达到对原始数据完整性检验的目的。
因此,与鲁棒型水印不同的是,脆弱型水印应随着主信号的变动而做出相应的改变,即体现出脆弱性。
但是,脆弱型水印的脆弱性并不是绝对的。
对主信号的某些必要性操作,如修剪或压缩,脆弱型水印也应体现出一定的鲁棒性,从而将这些不影响主信号最终可信度的操作与那些蓄意破坏操作区分开来。
另一方面,对脆弱型水印的不可见性和所嵌入数据量的要求与鲁棒型水印是近似的。
(3)扩充数据的嵌入(AugmentationDataEmbedding)
扩充数据包括对主信号的描述或参考信息、控制信息以及其它媒体信号等等。
描述信息可以是特征定位信息、标题或内容注释信息等,而控制信息的嵌入则可实现对主信号的存取控制和监测。
例如,一方面针对不同所有权级别的用户,可以分别授予不同的存取权限。
另一方面,也可通过嵌入一类通常被称作"时间印章(TimeStamp)"的信息,以跟踪某一特定内容对象的创建、行为以及被修改的历史。
这样,利用信息隐藏技术可实现对这一对象历史使用操作信息的记录,而无需在原信号上附加头文件或历史文件,因为使用附加文件,一来容易被改动或丢失,二来需要更多的传输带宽和存储空间。
与此同时,在给定的主信号中还可嵌入其它完整而有意义的媒体信号,例如在给定视频序列中嵌入另一视频序列。
因此,信息隐藏技术提供了这样一种非常有意义而且极具魅力的应用前景,它允许用户将多媒体信息剪裁成他们所需要的形式和内容[8]。
例如,在某一频道内收看电视,可以通过信息隐藏方法在所播放的同一个电视节目中嵌入更多的镜头以及多种语言跟踪,使用户能够按照个人的喜好和指定的语言方式播放。
这在一定意义上实现了视频点播(VideoonDemand,VOD)的功能,而其最大的优点在于它减少了一般VOD服务所需的传输带宽和存储空间。
显然,相对于数字水印来讲,扩充数据的嵌入所需隐藏的数据量较大,大量数据的嵌入对签字信号的不可见性提出了挑战。
另一方面,由于扩充数据本身的可利用价值,签字信号一般不会受到蓄意攻击的困扰。
但是,对于主信号的尺度变换、剪切或对比度增强等操作,特别是失真编码,扩充数据嵌入技术也要具备一定的鲁棒性。
2.3彩色图像的BMP文件格式
BMP图像文件格式,是微软公司为其WINDOWS环境设置的标准图像格式,并且内含了一套图像处理的API函数。
随着WINDOWS在世界范围内的普及,BMP文件格式越来越多地被各种应用软件所支持。
BMP图像文件是位图文件,位图表示的是将一幅图像分割成栅格,栅格的每一点称为像素,每一个像素具有自己的RGB值,即一幅图像是由一系列像素点构成的点阵。
位图文件格式支持4位RLE(行程长度编码)以及8位和24位编码。
在本文中我们只处理24位格式。
24位BMP图像文件的结构特点为:
①每个文件只能非压缩地存放一幅彩色图像;②文件头由54个字节的数据段组成,其中包含有该位图文件的类型、大小、图像尺寸及打印格式等;③从第55个字节开始,是该文件的图像数据部分,数据的排列顺序以图像的左下角为起点,从左到右、从下到上,每连续3个字节便描述图像一个像素点的颜色信息,这三个字节分别代表蓝、绿、红三基色在此像素中的亮度,若某连续三个字节为:
00H,00H,FFH,则表示该像素的颜色为纯红色。
以下我们详细讨论位图文件的具体结构。
BR>2.4.1位图文件的标头
标头包含位图文件的类型大小信息和版面信息。
结构如下[2]:
typedefstructtagBITMAPFILEHEADER{
UINTbfType;
DWORDbfSize;
UINTbfReserved1;
UINTbfReserved2;
DWORDbfOffBits;
}BITMAPFILEHEADER;
下面是对这个清单中的代码元素的说明:
bfType:
指定文件类型,其值始终为"BM"。
bfSize:
指定整个文件的大小(以字节为单位)。
bfReserved1:
保留--一般为0。
bfReserved2:
保留--一般为0。
bfOffBits:
指定从BitmapFileHeader到图像首部的字节偏移量。
现在我们已经知道位图标头的用途就是标识位图文件。
读取位图文件的每个程序都使用位图标头来进行文件验证。
2.4.2位图信息标头
随后的标头称为信息标头,其中包含图像本身的属性。
下面说明如何指定Windows3.0(或更高版本)设备独立位图(DIB)的大小和颜色格式:
typedefstructtagBITMAPINFOHEADER{
DWORDbiSize;//BITMAPINFOHEADER结构所需的字节数
LONGbiWidth;//位图的宽度(以象素为单位)
LONGbiHeight;//位图的高度(以象素为单位)
WORDbiPlanes;//目标设备的位面数。
这个成员变量的值必须为1
WORDbiBitCount;//每个象素的位数。
其值必须为1、4、8或24
DWORDbiCompression;//压缩位图的压缩类型。
在24位格式中,该变量被设置为0
DWORDbiSizeImage;//图像字节大小。
如果位图的格式是BI_RGB,则将此成员变量设置为0是有效的
LONGbiXPelsPerMeter;
//为位图指定目标设备水平分辨率(以"象素/米"为单位)。
程序可用该值从最符合当前设备特征的资源群组中选择一个位图
LONGbiYPelsPerMeter;//为位图指定目标设备的垂直分辨率(以"象素/米"为单位)
DWORDbiClrUsed;
//指定位图实际所用的颜色表中的颜色索引数。
如果biBitCount设为24,则biClrUsed指定用来优化Windows调色板性能的参考颜色表
DWORDbiClrImportant;//指定对位图的显示有重要影响的颜色索引数。
如果此值为0,则所有颜色都很重要
}BITMAPINFOHEADER;
现在已定义了创建图像所需的全部信息。
2.4.3图像数据
在24位格式中,图像中的每个象素都由存储为三字节的RGB序列表示。
每个扫描行都被补足到4位。
图像是自底而上存储的,即第一个扫描行是图像中的最后一个扫描行。
下图显示了位图文件的标头(BITMAPHEADER)和位图信息标头(BITMAPINFOHEADER)以及部分图像数据:
图4位图文件局部示例
2.5基于彩色静止数字图像的信息隐藏算法
在分析了信息隐藏算法的基本框架和彩色图像的BMP文件格式后,本文提出一种基于彩色静止数字图像的信息隐藏算法,分别如图5和图6所示。
算法4.1(基于彩色静止数字图像的信息隐藏嵌入算法)
1)将待隐藏信息(以下称签字信号)的字节长度写入BMP文件标头部分的保留字节中;
2)将签字信号转化为二进制数据码流;
3)将BMP文件图像数据部分的每个字节的高7位依次异或后再与上述二进制数码流异或后的结果写入最低位;
图5基于彩色静止数字图像的信息隐藏嵌入过程
算法4.2(基于彩色静止数字图像的信息隐藏提取算法)
1)读BMP文件标头部分的保留字节值,设为L,若为0则没有隐藏信息,终止算法;若不为0则其值为隐藏信息的字节长度;
2)将BMP文件图像数据部分的每个字节8位依次异或,并保存其结果;
3)重复第
(2)步,使每8个BMP文件图像数据部分字节经过运算后组成一个隐藏信息字节;
4)重复
(2)、(3)直到隐藏信息字节长度为L。
图6基于彩色静止数字图像的信息隐藏提取过程
可以证明,提取后的信息就是嵌入的签字信号。
以签字信号的一个位S为例,设对应的一个位图数据字节为X7X6X5X4X3X2X1X0,嵌入签字信号后的位图数据字节为X7X6X5X4X3X2X1X0',其中:
X0'=X7⊕X6⊕X5⊕X4⊕X3⊕X2⊕X1⊕S
设提取后的签字信号为S',则,
S'=X7⊕X6⊕X5⊕X4⊕X3⊕X2⊕X1⊕X0'
=(X7⊕X6⊕X5⊕X4⊕X3⊕X2⊕X1⊕X7)⊕(X6⊕X5⊕X4⊕X3⊕X2⊕X1⊕S)
=(X7⊕X6⊕X5⊕X4⊕X3⊕X2⊕X1⊕X7)⊕(X6⊕X5⊕X4⊕X3⊕X2⊕X1)⊕S
=S
证毕。
3.算法实现
1、HideInfo.cpp:
/*1.BMP文件头
BMP文件头数据结构含有BMP文件的类型、
文件大小和位图起始位置等信息。
其结构定义如下:
*/
typedefstructtagBitMapFileHeader
{
bytebfType[2];//位图文件的类型,必须为"BM"
bytebfSize[4];//位图文件的大小,以字节为单位
bytebfReserved1[2];//位图文件保留字,必须为0
bytebfReserved2[2];//位图文件保留字,必须为0
bytebfOffBits[4];//位图数据的起始位置,以相对于位图文件头的偏移量表示,以字节为单位
}*BitMap;//该结构占据14个字节。
/*功能:
返回图像的长度*/
intgetValue(byte*A,intnum)
{
intresult=0;
for(inti=num-1;i>0;i--)
{
result+=A[i];
result=result<<8;
}
result+=A[0];
returnresult;
}
/*功能:
将信息隐藏到图片中*/
voidhideInFo()
{
FILE*fp;
chardata[MAX];
charpath[MAX];
BitOperateoperate;
stringpath1="请输入图片路径(如:
c:
\\pics\\1.bmp)";
cout<chartemp3[100];
cin.getline(temp3,100,'\n');
cin.getline(path,sizeof(path),'\n');
if((fp=fopen(path,"r+"))==NULL)
{
cout<<"打开文件的时候出现错误!
"<
return;
}
BitMapmap=//存放文件头信息;
(BitMap)malloc(sizeof(structtagBitMapFileHeader));
fread(map,sizeof(structtagBitMapFileHeader),1,fp);
printf("请输入您要隐藏的信息:
\n");
cin.getline(data,MAX,'\n');
intdatalength=strlen(data);
intmaplength=getValue(map->bfSize,4);
intdatabegin=getValue(map->bfOffBits,4);
if((datalength*8)>(maplength-databegin))
{
printf("隐藏信息太长!
请选择一个更大的图片或者将信息分块隐藏\n");
return;
}
//首先将文件的长度隐藏起来;
bytetemp[32];
fseek(fp,databegin,SEEK_SET);//定位到数据块的起点;
fread(temp,sizeof(char)*32,1,fp);
intcopy=datalength;
for(inti=31;i>=0;i--)
{
boolv=(bool)(copy%2);
temp[i]=operate.bitSet(temp[i],1,v);
copy=copy/2;
}
fseek(fp,databegin,SEEK_SET);//定位到数据块的起点;
fwrite(temp,sizeof(byte)*32,1,fp);
//以下将数据信息隐藏到图像中;
inttimes=0;
bytech[8];
while(times//加上隐藏的文件长度信息;
{
fseek(fp,databegin+32+times*8,SEEK_SET);//定位到数据块的起点;
fread(ch,sizeof(byte),8,fp);//读出8个字节;
for(inti=7;i>=0;i--)
ch[i]=operate.bitSet(ch[i],1,operate.bitAt(data[times],8-i));
fseek(fp,databegin+32+times*8,SEEK_SET);//定位到数据块的起点;
fwrite(ch,sizeof(byte),8,fp);//写入8个字节;
times++;
}
fclose(fp);
cout<<"隐藏成功,按任意键退出"<}
/*将图片中隐藏的信息提取出来*/
voidgetInFo()
{
FILE*fp;
bytedata[MAX];
BitOperateoperate;
charpath[MAX];
cout<<"请输入图片路径(如:
c:
\\pics\\1.bmp)"<chartemp3[100];
cin.getline(temp3,100,'\n');
cin.getline(path,sizeof(path),'\n');
if((fp=fopen(path,"r+"))==NULL){
cout<<"打开文件的时候出现错误!
"<
return;
}
BitMapmap=//存放文件头信息;
(BitMap)malloc(sizeof(structtagBitMapFileHeader));
fread(map,sizeof(structtagBitMapFileHeader),1,fp);
intdatabegin=getValue(map->bfOffBits,4);//得到数据块开始的偏移地址;
//获取文件的长度;
intdatalength=0;
//首先将隐藏文件的长度读出来;
bytetemp[32];
fseek(fp,databegin,SEEK_SET);//定位到数据块的起点;
fread(temp,sizeof(char)*32,1,fp);
for(inti=0;i<31;i++)
{
datalength+=(int)operate.bitAt(temp[i],1);
datalength=datalength<<1;
}
datalength+=(int)operate.bitAt(temp[31],1);
//printf("\n\nDatalength=%d\n",datalength);
inttimes=0;
bytech[8];
while(times//加上隐藏的文件长度信息;
{
fseek(fp,databegin+32+times*8,SEEK_SET);
fread(ch,sizeof(byte),8,fp);//读出8个字节;
//printf("\nch=%s\n",ch);
data[times]=0;
for(inti=0;i<7;i++)
{
data[times]+=(int)operate.bitAt(ch[i],1);
data[times]=data[times]*2;
}
data[times]+=(int)operate.bitAt(ch[7],1);
printf("%c",data[times]);
times++;
}
fclose(fp);
}
2、BitOperate.cpp
/*功能:
把ch从右数的第position位设置为value;*/
byteBitOperate:
:
bitSet(bytech,shortposition,boolvalue)
{
bytetemp