多媒体安全实验,总共有4个,分别是像素域的LSB替换算法,JSTEG算法,F4算法,F5算法
实验环境
matlab2022Ra
像素域LSB替换
实现算法
原理特别简单,就是在像素点的最低bit位嵌入信息,这个实验的目的主要还是给学生练手的(熟练使用matlab)
选用的图像是灰度图像(即一个像素占8bits)
picture=imread("your picture");
double_picture=picture;
double_picture=double(double_picture);
wen.txt_id=fopen("secret_message","r");
[msg,len]=fread(wen.txt_id,'ubit1');
[m,n]=size(double_picture);
p=1;
for f2=1:n
for f1=1:m
double_picture(f1,f2)=double_picture(f1,f2)-mod(double_picture(f1,f2),2)+msg(p,1);
if p==len
break;
end
p=p+1
end
if p==len
break;
end
end
double_picture=uint8(double_picture);
imwrite(double_picture,"save_changed_picture");
subplot(121);imshow(picture);title("未嵌入信息的图像");
subplot(122);imshow(double_picture);title("嵌入信息的图像");
fclose(wen.txt_id);
检验
一开始是说要直接看值对现象的,但是说实话,值对现象这个条件还是太严苛了(之前说值对时, 嵌入的信息是加密后的随机的01序列,并且每个像素值,高7位一致时 最低为 0,1的概率相等,这样值对现象才明显),然而现实是残酷的,我的实验的值对现象非常不明显(甚至没有。
最后换了个办法检验。
我取所有高7位相同的像素点出来,算他们最低位为1和0的差值。
最后累加,这样子效果会比较明显
Picture_old=imread('original_picture');
Picture_new=imread('changed_picture');
%len=80;
Double_Picture_old=Picture_old;
Double_Picture_old=double(Double_Picture_old);
Double_Picture_new=Picture_new;
Double_Picture_new=double(Double_Picture_new);
%count1=zeros(1,256);
%count2=zeros(1,256);
[m,n]=size(Double_Picture_old);
%subplot(121);imhist(Picture_old);
%subplot(122);imhist(Picture_new);
[H1,D1]=imhist(Picture_old);
%subplot(121);imhist(Picture_old);title("test");
a=0;
b=0;
for f1=0:2:255
bit0=H1(D1 == f1);
bit1=H1(D1 == f1+1);
a=abs(bit0-bit1);
b=b+a;
end
%disp(a);
disp(b);
[H2,D2]=imhist(Picture_new);
b=0;
for f1=0:2:255
bit0=H2(D2 == f1);
bit1=H2(D2 == f1+1);
a=abs(bit0-bit1);
b=b+a;
end
disp(b);
JSTEG嵌入
说白了就是DCT域的LSB嵌入
算法实现
函数功能
function [AC]=JSTEG_simulation(COVER,STEGO,message)
try
jobj=jpeg_read(COVER); %读取cover图片
PrimeDCT=jobj.coef_arrays{1};%读取DCT系数
DCT=PrimeDCT;
catch
error('ERROR (problem with the cover image)');
end
AC=numel(DCT)-numel(DCT(1:8:end,1:8:end)); %计算AC系数个数
messageLen=length(message); %隐秘信息长度
%信息过长
if(messageLen>AC)
error('ERROR (too long message)');
end
changeable=true(size(DCT)); %生成一个布尔矩阵
changeable(1:8:end,1:8:end)=false; %DC系数的位置置为false
changeable=find(changeable); %找出布尔矩阵中为true的位置
idD=1;
for id=1:messageLen
while(abs(DCT(changeable(idD)))<=1) %嵌入ac系数绝对值大于1的位置
idD=idD+1;
if(idD>=AC)
break;
end
end
DCTInfo=DCT(changeable(idD));
if(message(id)~=mod(DCTInfo,2)) %LSB与隐藏信息不同
fprintf("DCT %x lowest bit %x input message %x\n",DCTInfo,mod(DCTInfo,2),message(id));
if(DCTInfo<0)
if(mod(DCTInfo,2)) % 负数 偶加奇减
DCT(changeable(idD))=DCTInfo+1;
else
DCT(changeable(idD))=DCTInfo-1;
end
else
if(mod(DCTInfo,2)) %正数 偶减奇加
DCT(changeable(idD))=DCTInfo-1;
else
DCT(changeable(idD))=DCTInfo+1;
end
end
fprintf("last DCT:%x\n",DCT(changeable(idD)));
end
idD=idD+1;
end
%histogram(DCT) %直方图
%%% save the resulting stego image
try
jobj.coef_arrays{1} = DCT; %写入隐藏信息后的图像
jobj.optimize_coding = 1;
jpeg_write(jobj,STEGO);
catch
error('ERROR (problem with saving the stego image)');
end
%显示未嵌入信息的图像
subplot(2,3,1);
imshow(COVER);
title('未嵌入信息的图像');
%显示未嵌入信息的图像的DCT系数直方图
subplot(2,3,2);
histogram(PrimeDCT);
axis([-10,10,0,2*1e4]);
title('嵌入前的图像DCT系数直方图');
% 灰度直方图
I=imread(COVER);
subplot(2,3,3);
imhist(I);
title('未嵌入信息的灰度直方图');
%显示嵌入信息的图像
subplot(2,3,4);
imshow(STEGO);
title('嵌入信息的图像');
%显示嵌入信息的图像的DCT系数直方图
subplot(2,3,5);
histogram(DCT);
axis([-10,10,0,2*1e4]);
title('嵌入后的图像DCT系数直方图');
% 灰度直方图
I=imread(STEGO);
subplot(2,3,6);
imhist(I);
title('嵌入信息的灰度直方图');
主程序
COVER='cover.jpg';
STEGO='stego.jpg';
message=randi([0 1],1,20000); %生成随机数,作为隐藏信息
save('message','message','-ascii'); %保存秘密信息
tic;
[nzAC]=JSTEG_simulation(COVER,STEGO,message);
T=toc;
fprintf('-----------------------------------\n');
fprintf('JSTEG simulation finished\n');
fprintf('cover image: %s\n',COVER);
fprintf('stego image: %s\n',STEGO);
fprintf('number of nzACs in cover: %i\n',nzAC);
fprintf('elapsed time: %.4f seconds\n',T);
fprintf('-----------------------------------\n');
check
还是值对现象,但是这个实验我的值对现象效果挺明显的(乐
函数
function message=JSTEG_extract(STEGO,messageLen)
try
jobj=jpeg_read(STEGO); %读取stego图片
DCT=jobj.coef_arrays{1};%读取DCT系数
catch
error('ERROR (problem with the cover image)');
end
changeable=true(size(DCT)); %生成一个布尔矩阵
changeable(1:8:end,1:8:end)=false; %DC系数的位置置为false
changeable=find(changeable); %找出布尔矩阵中为true的位置
idD=1;
for id=1:messageLen
while(abs(DCT(changeable(idD)))<=1)
idD=idD+1;
end
message(1,id)=mod(DCT(changeable(idD)),2); %不管怎么样 1表示数据为1,0表示数据为0
idD=idD+1;
end
主程序
STEGO='stego.jpg';
messageLen=20000;
tic;
messageHiden=JSTEG_extract(STEGO,messageLen);
T=toc;
save('messageHiden','messageHiden','-ascii'); %保存提取出来的秘密信息
fprintf('-----------------------------------\n');
fprintf('JSTEG extract finished\n');
fprintf('elapsed time: %.4f seconds\n',T);
fprintf('-----------------------------------\n');
F4
算法
函数
function [AC]=F4_simulation(COVER,STEGO,message)
try
jobj=jpeg_read(COVER); %读取cover图片
PrimeDCT=jobj.coef_arrays{1};%读取DCT系数
DCT=PrimeDCT;
catch
error('ERROR (problem with the cover image)');
end
AC=numel(DCT)-numel(DCT(1:8:end,1:8:end)); %计算AC系数个数
messageLen=length(message);
%信息过长
if(messageLen>AC)
error('ERROR (too long message)');
end
changeable=true(size(DCT)); %生成一个布尔矩阵
changeable(1:8:end,1:8:end)=false; %DC系数的位置置为false
changeable=find(changeable); %找出布尔矩阵中为true的位置
id=1;
idD=1;
while(id<=messageLen)
while(DCT(changeable(idD))==0)
idD=idD+1;
if(idD>=AC)
break;
end
end %F4算法中,用正奇数和负偶数代表秘密消息1、负奇 数和正偶数代表秘密消息0
if(message(id)~=mod(DCT(changeable(idD)),2)) %LSB与隐藏信息不同 -1
if(DCT(changeable(idD))>0)
DCT(changeable(idD))=DCT(changeable(idD))-1;
end
else %LSB与隐藏信息相同 +1
if(DCT(changeable(idD))<0)
DCT(changeable(idD))=DCT(changeable(idD))+1;
end
end
if(DCT(changeable(idD))==0)
id=id-1;
end
id=id+1;
idD=idD+1;
end
%%% save the resulting stego image
try
jobj.coef_arrays{1} = DCT;
jobj.optimize_coding = 1;
jpeg_write(jobj,STEGO);
catch
error('ERROR (problem with saving the stego image)');
end
%显示未嵌入信息的图像
subplot(2,3,1);
imshow(COVER);
title('未嵌入信息的图像');
%显示未嵌入信息的图像的DCT系数直方图
subplot(2,3,2);
histogram(PrimeDCT);
axis([-10,10,0,2*1e4]);
title('嵌入前的图像DCT系数直方图');
% 灰度直方图
I=imread(COVER);
subplot(2,3,3);
imhist(I);
title('未嵌入信息的灰度直方图');
%显示嵌入信息的图像
subplot(2,3,4);
imshow(STEGO);
title('嵌入信息的图像');
%显示嵌入信息的图像的DCT系数直方图
subplot(2,3,5);
histogram(DCT);
axis([-10,10,0,2*1e4]);
title('嵌入后的图像DCT系数直方图');
% 灰度直方图
I=imread(STEGO);
subplot(2,3,6);
imhist(I);
title('嵌入信息的灰度直方图');
主程序
COVER='cover.jpg';
STEGO='stego.jpg';
message=randi([0 1],1,30000); %生成随机数,作为隐藏信息
save('message','message','-ascii'); %保存秘密信息
tic;
[nzAC]=F4_simulation(COVER,STEGO,message);
T=toc;
fprintf('-----------------------------------\n');
fprintf('F4 simulation finished\n');
fprintf('cover image: %s\n',COVER);
fprintf('stego image: %s\n',STEGO);
fprintf('number of nzACs in cover: %i\n',nzAC);
fprintf('elapsed time: %.4f seconds\n',T);
fprintf('-----------------------------------\n');
check
这个算法会导致DCT系数是-1和1的频率大幅下降
函数
function message=F4_extract(STEGO,messageLen)
try
jobj=jpeg_read(STEGO); %读取stego图片
DCT=jobj.coef_arrays{1};%读取DCT系数
catch
error('ERROR (problem with the cover image)');
end
AC=numel(DCT)-numel(DCT(1:8:end,1:8:end)); %计算AC系数个数
changeable=true(size(DCT)); %生成一个布尔矩阵
changeable(1:8:end,1:8:end)=false; %DC系数的位置置为false
changeable=find(changeable); %找出布尔矩阵中为true的位置
idD=1;
for id=1:messageLen
while(DCT(changeable(idD))==0)
idD=idD+1;
end
if(DCT(changeable(idD))>0)
message(1,id)=mod(DCT(changeable(idD)),2);
else
if(mod(DCT(changeable(idD)),2)==1) % 1表示数据为0 0表示实际数据为1
message(1,id)=0;
else
message(1,id)=1;
end
end
idD=idD+1;
end
主程序
STEGO='stego.jpg';
messageLen=30000;
tic;
messageHiden=F4_extract(STEGO,messageLen);
T=toc;
save('messageHiden','messageHiden','-ascii'); %保存提取出来的秘密信息
fprintf('-----------------------------------\n');
fprintf('F4 extract finished\n');
fprintf('elapsed time: %.4f seconds\n',T);
fprintf('-----------------------------------\n');
F5
算法
COVER = 'cover.jpg';
STEGO='stego.jpg';
SEED=99;
message=randi([0 1],1,10000);
save('message','message','-ascii');
try
jobj=jpeg_read(COVER);
PrimeDCT=jobj.coef_arrays{1};
DCT=PrimeDCT;
catch
error('Error (problem with the cover image)');
end
AC = numel(DCT)-numel(DCT(1:8:end,1:8:end)); % 得到ac系数的个数
if(length(message)>AC)
error('ERROR (too ling message)');
end
changeable=true(size(DCT)); %生成一个布尔矩阵
changeable(1:8:end,1:8:end)=false;%DC系数的位置置为false
changeable=find(changeable);%找出布尔矩阵中为true的位置
rand('state',SEED);
changeable=changeable(randperm(AC));
idD=1;
len=length(message);
id=1;
while id<len
id1=message(id);
id2=message(id+1);
%fprintf("%d %d \n",id1,id2);
count=1;
choosed_DCT=[1,2,3];
choosed_count=[1,2,3];
while count<=3
while (abs(DCT(changeable(idD)))<=1)
DCT(changeable(idD))=0; %判断修改后的DCT系数是否变为0,若没有则继续嵌入下一组数 据;若系数变为0,则本次隐藏无效,返回继续嵌入本组数据
idD=idD+1; %这里采取取到1就变0的策略,简化流程
if(idD>=AC)
break;
end
end
choosed_DCT(count)=DCT(changeable(idD));
choosed_count(count)=idD;
count=count+1;
idD=idD+1;
end
%fprintf("%d %d %d\n",choosed_DCT(1),choosed_DCT(2),choosed_DCT(3));
% id1=choosed_DCT(1)^choosed_DCT(2),id2=choosed_DCT(2)^choosed_DCT(3)
if (id1~=mod(choosed_DCT(1)^choosed_DCT(2),2)) && (id2~=mod(choosed_DCT(2)^choosed_DCT(2),3))
choosed_DCT(2)=choosed_DCT(2)-sign(choosed_DCT(2));
elseif (id1~=mod(choosed_DCT(1)^choosed_DCT(2),2))
choosed_DCT(1)=choosed_DCT(1)-sign(choosed_DCT(1));
else
choosed_DCT(3)=choosed_DCT(3)-sign(choosed_DCT(3));
end
for i=1:(count-1)
DCT(changeable(choosed_count(i)))=choosed_DCT(i);
end
id=id+2;
end
try
jobj.coef_arrays{1}=DCT;
jobj.optimize_coding=1;
jpeg_write(jobj,STEGO);
catch
error('ERROR (problem with saving the stego image)');
end
%显示未嵌入信息的图像
subplot(2,3,1);
imshow(COVER);
title('未嵌入信息的图像');
%显示未嵌入信息的图像的DCT系数直方图
subplot(2,3,2);
histogram(PrimeDCT);
axis([-10,10,0,2*1e4]);
title('嵌入前的图像DCT系数直方图');
% 灰度直方图
I=imread(COVER);
subplot(2,3,3);
imhist(I);
title('未嵌入信息的灰度直方图');
%显示嵌入信息的图像
subplot(2,3,4);
imshow(STEGO);
title('嵌入信息的图像');
%显示嵌入信息的图像的DCT系数直方图
subplot(2,3,5);
histogram(DCT);
axis([-10,10,0,2*1e4]);
title('嵌入后的图像DCT系数直方图');
% 灰度直方图
I=imread(STEGO);
subplot(2,3,6);
imhist(I);
title('嵌入信息的灰度直方图');
check
STEGO='stego.jpg';
SEED=99;
mlen=10000;
try
jobj=jpeg_read(STEGO);
DCT=jobj.coef_arrays{1};
catch
error('ERROR (problem with the STEGO image)');
end
AC = numel(DCT)-numel(DCT(1:8:end,1:8:end));
changeable=true(size(DCT));
changeable(1:8:end,1:8:end)=false;
changeable=find(changeable);
rand('state',SEED);
changeable=changeable(randperm(AC));
idD=1;
while id<mlen
id1 = id;
id2 = id+1;
count=1;
choosed_DCT=[1,2,3];
choosed_count=[1,2,3];
while count<=3
while(DCT(changeable(idD))==0)
idD=idD+1;
end
choosed_DCT(count)=DCT(changeable(idD));
choosed_count(count)=idD;
idD=idD+1;
count=count+1;
end
% id1=choosed_DCT(1)^choosed_DCT(2),id2=choosed_DCT(2)^choosed_DCT(3)
message(1,id1)=choosed_DCT(1)^choosed_DCT(2);
message(1,id2)=choosed_DCT(2)^choosed_DCT(3);
id=id+2;
end
save('messageHiden','message','-ascii');
致谢
感谢学长的blog!