维基百科对隐写术的定义:隐写术是一门关于信息隐藏的技巧与科学,所谓信息隐藏指的是不让除预期的接收者之外的任何人知晓信息的传递事件或者信息的内容。 一般来说,隐写的信息看起来像一些其他的东西,例如一张购物清单,一篇文章,一篇图画或者其他“伪装”(cover)的消息。
LSB全称leastsignificant bit,是一种基于图片最低有效位修改储存信息的隐写方法,图片采用像素点构乘,利用人肉眼视觉分辨率的限制,像素点的低位变化引起图片整体的变化微乎其微,肉眼不足与察觉出异常。同样的MLSB旨在不被人眼察觉出异常的情况下,尽可能的多藏几位信息,从而提高消息隐藏的效率和容量。
比如:
右图嵌入了隐写术的定义,但与左图看不出差距来。
下边在matlab上实现隐写术工作流程:
首先强调的一点是载体图片的格式问题,png图片是一种无损压缩的位图片形格式,也只有在无损压缩或者无压缩的图片(BMP)上实现lsb隐写。如果图像是jpg图片的话,就没法使用lsb隐写了,原因是jpg图片对像数进行了有损压缩,我们修改的信息就可能会在压缩的过程中被破坏。而png图片虽然也有压缩,但却是无损压缩,这样我们修改的信息也就能得到正确的表达,不至于丢失。BMP的图片也是一样的,是没有经过压缩的。BMP图片一般是特别的大的,因为BMP把所有的像数都按原样储存,没有进行压缩。png图片中的图像像数一般是由RGB三原色(红绿蓝)组成,每一种颜色占用8位,取值范围为0x00~0xFF,即有256种颜色,一共包含了256的3次方的颜色,即16777216种颜色。而人类的眼睛可以区分约1000万种不同的颜色,这就意味着人类的眼睛无法区分余下的颜色大约有6777216种。
代码流程:
1、LSB/MLSB消息嵌入编写函数实现图片变量中最低位嵌入隐藏消息
函数输入:图片变量名、消息内容、需要隐藏到最低几位、隐藏在RGB三图层的哪一个
函数输出:嵌入消息的图片变量
首先对message进行编码,在此使用‘UTF-8’编码,为了方便后续信息提取,设置一个结束位使用strcat函数连接在message后边。实验中设置的结束标志位为char‘4’,并使用unicode2native函数将Unicode码转为数字字节。
编码后的消息是以字符char的格式存储的,且形式为十进制,接下来,将字符消息转换为二进制,并把这些二进制编码整合到一个数组msg中。
将msg中的‘0’、‘1’按序隐藏在图片的低lsb(设置的隐藏位数)位中,每个像素点隐藏lsb个,则所需的像素点载体为length(msg)/lsb,如果不足则在消息末尾再次补位,注意这里补位的内容还是结束标志位char‘4‘。
像素点的数据格式为uint8(无符号整型),表示范围为0~255的使用八位二进制数表示的十进制数据,对数据取模2^lsb,则得到数据的低lsb位,将得到的低lsb位数据减去,加上msg隐藏信息(将lsb位隐藏信息转为十进制后再运算),这样就完成了低位数据的替换。返回替换后的,既隐藏了消息的图片变量。下边给出LSB/MLSB嵌入程序:
function [image_result] = LSBembed(image, message, lsb, color)
% lsbembed
% image: the picture's matrix name
% message: the data you want to hide in the picture
% lsb: lsb-rightmost LSBs
% color: 1-red, 2-green, 3-blue
msg_origin = unicode2native(strcat(message, char(4)), 'UTF-8'); % UTF-8 encode, 'EOT' is the end tag
msg_bin = dec2bin(msg_origin, 8); % convert to binary
msg = strjoin(cellstr(msg_bin)','');
len = length(msg) / lsb;
while len ~= fix(len)
strcat(msg, char(4));
len = length(msg) / lsb;
end
tmp = blanks(len);
for i = 1 : len
tmp(i) = char(bin2dec(msg((i - 1) * lsb + 1 : i * lsb)));
end
tmp=double(tmp);
% use Red, Green or Blue
layer = image(:, :, color);
for i = 1 : len
layer(i) = layer(i) - mod(layer(i), 2^lsb) + tmp(i);% only to be consistent with front
end
% save the picture
image_result = image;
image_result(:, :, color) = layer;
% imshow(image_result);
% imwrite(image_result, 'result.png'); %
end
2、LSB/MLSB消息提取 在上边嵌入程序的基础上编写函数LSB_extract进行信息的提取。 函数输入:嵌入了消息的图片变量名、需要隐藏到最低几位、隐藏在RGB三图层的哪一个 函数输出:消息内容 从消息的角度来说,消息的提取基本上是消息嵌入的逆过程(图片载体不可逆)
先获取每个像素点的低lsb位,因为编码采用的’UTF-8’,因此每提取出8位,整合到一起,转化为十进制,作为消息信息的一个字节。提取消息检测到结束标志位‘4’时,停止消息提取。然后使用native2unicode将数字字节转换为unicode编码,完成消息的显示。
下边是消息提取函数:
function [msg_origin] = LSB_extract(image, lsb, color)
% LSB_extract(name, lsb) LSB in steganography (extract)
% name: the picture's path and name
% lsb: lsb-rightmost LSBs
% color: 1-red, 2-green, 3-blue
layer = image(:, :, color);
tmp = blanks(0);
n = prod(size(layer));
% if lsb ~= 2, then you need to change something below
for i = 1 : n * lsb / 8
tmp((i - 1) * 4 + 1 : i * 4) = mod(layer((i - 1) * 4 + 1 : i * 4), 2^lsb);
msg((i - 1) * 8 + 1 : i * 8) = dec2bin(tmp((i - 1) * 4 + 1 : i * 4), lsb)';
msg_origin(i) = bin2dec(msg((i - 1) * 8 + 1 : i * 8));
if msg_origin(i) == 4 % EOT is the end tag
break;
end
end
msg_origin = native2unicode(msg_origin,'UTF-8');
msg_origin = msg_origin(1:end-1);
end
3、隐写测试 调用上边的消息嵌入和提取函数,编写程序进行一个小小的隐写术测试。 测试时选择隐藏两位,选取B色道。 测试程序如下:
%LSB 隐写术
%
clear
close all
clc
message=input('请输入隐写内容: message=');
image=imread('wolf1.png');
subplot(121)
imshow(image)
title('Original')
image_result=LSBembed(image,message,2,3);
subplot(122)
imshow(image_result)
title('隐写图像')
msg_origin=LSB_extract(image_result,2,3);
msgbox({' 隐写内容: ',msg_origin,' '},'结果');