代码仓库:代码、嵌入提取使用的图像、jpeg_tool库、实验报告_Gitee

实验环境:MATLAB 2022a

LSB空域隐写

原理

我们知道,一个像素点是由R(red)B(blue)G(green)三原色组成的,通过调配这三种颜色,我们可以得到所有的颜色。
比如白色(255,255,255),二进制就是bin(11111111,11111111,11111111),黑色(0,0,0),二进制就是(00000000,00000000,00000000)。

既然如此,我们将每个二进制的最后一位给替换成别的,比如将(255,255,255)替换成(254,254,254),bin(11111110,11111110,11111110),肉眼根本分辨不出。

因此我们将需要的信息转成二进制,再将每一位替换掉三元组的最后一位,便完成了LSB隐写。

值对现象原理

但是,LSB隐写有明显的统计特征——“值对现象”。

因为密文具有随机性,
可认为密文的二进制比特流中的0和1是均匀的

将二进制的最后一位替换成密文的比特后,
原图像的灰度值的奇数和偶数将会趋于相同

比如,颜色值为100的本来有10个,为101的有100个,在嵌入随机密文后,它们的个数有可能趋于相同——也就是颜色值为100的和101的都变成55个。

实验内容

载体选取:BMP格式灰度图像。
嵌入信息:JPG图像。
嵌入大小:227680bits。

若BMP图像不方便寻找,可用MATLAB将jpg图像转换成BMP:

% 将jpg转换成bmp图像
A=imread('avatar.jpg');
imwrite(A,'cover.bmp','bmp');

嵌入信息程序:

clear  % 清空变量
close all % 关闭打开的图像窗口 Picture = imread('cover.bmp');
Double_Picture = Picture;
Double_Picture = double(Double_Picture); %读取秘密信息文件为二进制数字流,为嵌入图像做准备
wen.txt_id = fopen ('avatar2.jpg','r');
[msg, len] = fread(wen.txt_id, 'ubit1'); %根据LSB算法,将秘密信息的二进制数字流隐藏入连续的像素中
[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 %将得到的隐密图像保存为stego.bmp,并利用Matlab将载体图与隐密图画在同一对话框中进行比较
Double_Picture=uint8(Double_Picture);
imwrite(Double_Picture, 'stego1.bmp');
subplot(121);imshow(Picture);title('未嵌入信息的图像');
subplot(122);imshow(Double_Picture);title('嵌入信息的图像'); fclose(wen.txt_id);

运行结果:

提取程序:

clear  %清空变量

% 利用Matlab自带函数读取隐密图像stego. bmp,得到隐密图像的信息并将图像转化为二进制
Picture = imread( 'stego1.bmp' );
Picture = double(Picture);
[m, n] = size(Picture); % 打开存放秘密信息的文件,若没有则新建一个文件。顺序提取图像相应像素LSB的秘密信息,存储在打开的文件中并保存
frr = fopen('message.jpg', 'w');
len = 227680;
%test = [];
p = 1;
for f2 = 1:n
for f1 = 1:m
%lowbit = bitand(Picture(f1, f2), 1);
%test = [test lowbit]; % 注意!如果做数组cat操作,会严重增加提取程序运行时长
fwrite(frr, bitand(Picture(f1, f2), 1), 'ubit1');
if p == len
break;
end
p=p+1;
end
if p == len
break;
end
end
%fwrite(frr, test);
fclose(frr);

提取结果存储为message.jpg

注意,不要尝试将内容全部写入一个数组,然后再统一用fwrite写入,因为matlab的数组cat操作很慢,数据量太大了耗时很长。我多加了一行cat操作,结果给老师检查的时候翻车了qwq。

值对现象展示程序:

I=imread('cover.bmp');
O=imread('stego1.bmp');
I=I(1:200000);
O=O(1:200000);
%subplot(121);
x=100;
histogram(I, 0:1:x);
set(gca, 'xtick', 0:2:x); % 横坐标每隔2显示刻度
grid on;
hold on;
%subplot(122);
histogram(O, 0:1:x);
set(gca, 'xtick', 0:2:x); % 横坐标每隔2显示刻度
grid on;

值对现象运行结果:

上图中,蓝色是嵌入前,橙色是嵌入后。现象极其明显。

DCT域隐写

实验要求,完成3种嵌入方案:JSTEGF4F5

载体选取:JPEG格式灰度图像。
嵌入信息:随机生成的0-1比特流。
嵌入长度:JSteg:28684bits;F4:45000bits;F5:32700bits。(长度与图像本身能够用于嵌入的AC系数个数、算法对AC系数的利用率有关)
嵌入思路:

本实验使用jpeg_toolbox库对JPEG图像进行读写操作,因此,若jpeg_toolbox文件夹尚未添加到当前路径,将会出现如下报错:

解决办法:右键文件夹-添加到路径-选定的文件夹。

JSteg

JSteg信息隐藏算法是LSB替换思想在DCT域的实现。
嵌入过程的关键步骤:将原始图像的AC系数中最低的位平面“替换”为要隐藏的秘密信息。这里的“替换”遵循如下规则:
(1)忽略-1、0、1;
(2)若AC系数为2i,秘密比特为0,该系数不变;
(3)若AC系数为2i,秘密比特为1,该系数变为2i+1;
(4)若AC系数为2i+1,秘密比特为0,该系数变为2i;
(5)若AC系数为2i+1,秘密比特为1,该系数不变。
(6)AC系数为负数时,其二进制的实际含义是正数。(如表2-1所示)

在本课程中,DCT系数为负时,认为它是相应正数的补码

因此,负数的奇偶性和其他正常的JSteg说法不一样。
如,AC系数为(-16)₁₀ = (01111)₂。当秘密比特为0时,载密系数是(-17)₁₀ = (01110)₂。

嵌入程序stego_JSteg.m

% 更改嵌入算法时,需要将下文JSteg_simulation替换成其他函数
% 并修改算法名称name、嵌入信息长度messageLen等变量
COVER='cover.jpg';
STEGO='stego.jpg';
name='JSteg';
messageLen=28684; message=randi([0 1],1,messageLen);%0000); %生成随机数,作为隐藏信息
save('message','message','-ascii'); %保存秘密信息 tic;
[nzAC]=JSteg_simulation(COVER,STEGO,message);
T=toc; fprintf('-----------------------------------\n');
fprintf('%s simulation finished\n', name);
fprintf('cover image: %s\n',COVER);
fprintf('stego image: %s\n',STEGO);
fprintf('number of nzACs in cover: %i\n',nzAC);
fprintf('bits of message: %d\n',length(message));
fprintf('elapsed time: %.4f seconds\n',T);
fprintf('-----------------------------------\n');

嵌入程序调用的函数JSteg_simulation.m

function [ncAC]=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_Location=DCT; % 复制DCT
AC_Location(1:8:end,1:8:end)=false; % 将DC系数置0
AC_Location(abs(AC_Location)<=1)=0; % 将绝对值小于等于1的位置置为0
AC_Location=find(AC_Location); %找出DCT中不为DC系数、绝对值大于1的位置 ncAC=numel(AC_Location); % 得到绝对值大于1的AC系数个数 messageLen=length(message); %信息过长
if(messageLen>ncAC)
error('ERROR (too long message)');
end i_DCT=1; for i_MSG=1:messageLen
if(i_DCT>ncAC) % 没有更多可供注入密文的AC系数
fprintf('Max messageLength is %d.\n', i_MSG-1);
error('ERROR (too long message)');
end
DCTInfo=DCT(AC_Location(i_DCT));
if(DCTInfo>0)
DCT(AC_Location(i_DCT))=DCTInfo+message(i_MSG)-mod(DCTInfo,2);
else
DCT(AC_Location(i_DCT))=DCTInfo+message(i_MSG)-mod(DCTInfo+1,2);
end
i_DCT=i_DCT+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,2,1);imshow(COVER);
title('未嵌入信息的图像'); subplot(2,2,2);histogram(PrimeDCT);axis([-10,10,0,2*1e4]);
title('嵌入前的图像DCT系数直方图'); subplot(2,2,3);imshow(STEGO);
title('嵌入信息的图像'); subplot(2,2,4);histogram(DCT);axis([-10,10,0,2*1e4]);
title('嵌入后的图像DCT系数直方图');

运行结果:

提取程序extract_JSteg.m

% 更改提取算法时,需要将下文JSteg_extract替换成其他函数
% 并修改算法名称name、嵌入信息长度messageLen等变量
STEGO='stego.jpg';
name='JSteg';
messageLen=28684; tic;
messageHiden=JSteg_extract(STEGO,messageLen);
T=toc; save('messageHiden','messageHiden','-ascii'); %保存提取出来的秘密信息 fprintf('-----------------------------------\n');
fprintf('%s extract finished\n', name);
fprintf('elapsed time: %.4f seconds\n',T);
fprintf('-----------------------------------\n');

提取程序调用的提取函数JSteg_extract.m

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 AC_Location=DCT; % 复制DCT
AC_Location(1:8:end,1:8:end)=false; % 将DC系数置0
AC_Location(abs(AC_Location)<=1)=0; % 将绝对值小于等于1的位置置为0
AC_Location=find(AC_Location); %找出DCT中不为DC系数、绝对值大于1的位置 i_DCT=1; for i_MSG=1:messageLen
DCTInfo=DCT(AC_Location(i_DCT));
if(DCTInfo>0)
message(1,i_MSG)=mod(DCTInfo,2);
else
message(1,i_MSG)=mod(DCTInfo+1,2);
end
i_DCT=i_DCT+1;
end

后面的两个算法不贴出完整代码,代码仓库里面都有。也懒得解释实验现象了,实验报告都给得很清楚。

简单介绍一下剩下两个实验的原理吧。

F4

F4信息隐藏算法是JSteg的改进。

F4算法中,当嵌入系数的最低位和密文不符时,将系数的绝对值一律减1,而非对最低位直接取反,从而较好地避免了值对现象。

它的替换,和JSteg的区别是:

①它对1和-1也进行操作。当嵌入系数的最低位和密文不符时,1和-1都将变成0。此时,该位的信息嵌入被视为无效,需要继续取下一位AC系数进行嵌入

②嵌入时,统一直接减1。如原值是6,对应二进制是110,在JSteg中,嵌入后是111;在F4中,嵌入后是101。

体现出来的变换规则如下表2-2:

F5

F5的特点是矩阵编码,能够减小数据的修改量,并置乱DCT系数(本实验无置乱要求)。

矩阵编码:将k比特秘密消息嵌入到(2^k-1)个AC系数中,只修改1个位置。

其实,它的原理就和海明码纠错原理一样。
海明码(也叫汉明码)具有一位纠错能力。和海明码有些不同的是,矩阵编码不要求将AC系数计算得到的校验码添加到AC系数中去纠错,而是以计算得到的校验码作为秘密信息

假设一共有H1,H2,H3,H4,H5,H6,...,H15这十五个数,它们的位置对应着二进制0001,0010,0011,…,1111。

将所有二进制最低位为1位置的数选出来异或,也就是b1=H1⊕H3⊕H5⊕H7⊕H9⊕H11⊕H13⊕H15,能得到1比特信息。
同理,将所有二进制第二位为1位置的数选出来,也就是b2=H2⊕H3⊕H6⊕H7⊕H10⊕H9⊕H9,也能得到1比特信息。

综上,一共能得到4比特信息。

倘若这4比特和4比特密文相符合,那就不用改密文。
假如不同,b1、b2、b3、b4的某些与密文不符合的可能组合一共有15种,这15种组合分别对应着需要修改的AC系数的位置。如下图所示。

这就是F5的修改原则——每(2^k-1)位AC系数,只需要最多改1位,就能得到k比特的密文信息。其中AC系数的分组大小可自行选择,修改的方式与F4保持一致,也是绝对值直接减1。

在本实验中,我选择以3个AC系数为一组,一次嵌入密文比特量k为2,分别定义为a1,a2,a3,b1,b2。嵌入过程的关键步骤是矩阵编码,遵循如下规则:
(1)忽略0;
(2)当系数被修改成0时,换位置重新嵌入。
(3)b1=a1⊕a2, b2=a2⊕a3,则不修改数据;
(4)b1≠a1⊕a2, b2=a2⊕a3,则修改a1;
(5)b1=a1⊕a2, b2≠a2⊕a3,则修改a3;
(6)b1≠a1⊕a2, b2≠a2⊕a3,则修改a2;
(7)正奇数和负偶数代表秘密消息1,正偶数和负奇数代表秘密消息0;
(8)AC系数为负数时,其二进制的实际含义是正数。
提取秘密消息时,只需令b1=a1⊕a2, b2=a2⊕a3。

简单贴一下F5的信息隐藏和提取关键代码:

信息隐藏的关键代码:

AC_Location=DCT; % 复制DCT
AC_Location(1:8:end,1:8:end)=false; % 将DC系数置0
AC_Location=find(AC_Location); %找出DCT中不为DC系数、不为0的位置 ncAC=numel(AC_Location); % 得到AC系数总数 messageLen=length(message); % 得到密文的数量 %信息过长
if(messageLen/2>ncAC/3)
error('ERROR (too long message)');
end i_DCT=1;
i_MSG=1; while i_MSG+1<=messageLen
if(i_DCT+2>ncAC) % 没有更多可供注入密文的AC系数
fprintf('Max messageLength is %d.\n', i_MSG-2);
error('ERROR (too long message)');
end
DCTInfo=DCT(AC_Location(i_DCT:i_DCT+2));
DCTInfo(DCTInfo<0)=DCTInfo(DCTInfo<0)+1; % 将所有负数+1,改变最低位
xor1=bitxor(mod(DCTInfo(1),2),mod(DCTInfo(2),2)); % a1按位异或a2
xor2=bitxor(mod(DCTInfo(2),2),mod(DCTInfo(3),2)); % a2按位异或a3
tobe_change=i_DCT;
if(message(i_MSG)==xor1) % 判断异或值,确定修改位
if(message(i_MSG+1)==xor2)
tobe_change=-1;
else
tobe_change=tobe_change+2;
end
else
if(message(i_MSG+1)~=xor2)
tobe_change=tobe_change+1;
end
end
if(tobe_change~=-1) % 需要修改
if(DCT(AC_Location(tobe_change))>0) % 正数减1
DCT(AC_Location(tobe_change))=DCT(AC_Location(tobe_change))-1;
else % 负数加1
DCT(AC_Location(tobe_change))=DCT(AC_Location(tobe_change))+1;
end
if(DCT(AC_Location(tobe_change))==0) % 如果嵌入后是0,这两位密文重新嵌入
i_MSG=i_MSG-2;
AC_Location(tobe_change)=[]; % 删除这一位置
ncAC=ncAC-1;
i_DCT=i_DCT-3; % 复用未被修改的AC系数
end
end
i_DCT=i_DCT+3;
i_MSG=i_MSG+2; % for循环内循环索引改变不生效
end

若AC系数分组较大,如选择分组大小为15,则不建议继续采用if-else写“确定修改位”部分,而应该反向打表
首先将异或值不同的位按序直接转换成二进制,比如b1,b2,b3不同,应直接计算得到1110,然后查1110对应的是ACT系数7,则直接修改第七个ACT系数。

提取的关键代码:

AC_Location=DCT; % 复制DCT
AC_Location(1:8:end,1:8:end)=false; % 将DC系数置0
AC_Location=find(AC_Location); %找出DCT中不为DC系数、不为0的位置 i_DCT=1; for i_MSG=1:2:messageLen
DCTInfo=DCT(AC_Location(i_DCT:i_DCT+2));
DCTInfo(DCTInfo<0)=DCTInfo(DCTInfo<0)+1; % 将所有负数+1后,改变最低位
message(1,i_MSG)=bitxor(mod(DCTInfo(1),2),mod(DCTInfo(2),2)); % a1按位异或a2
message(1,i_MSG+1)=bitxor(mod(DCTInfo(2),2),mod(DCTInfo(3),2)); % a2按位异或a3
i_DCT=i_DCT+3;
end

可以看到,提取算法非常简单。其实嵌入算法也是很简单的,就是在F4的基础上,加了一个异或判断修改位。

【HUST】网安|多媒体数据安全实验|LSB隐写和DCT域JSTEG+F4+F5隐写及检测的更多相关文章

  1. 轻松月薪过万,NISP证书含金量有多重|NISP管理中心|网安伴|nisp

    nisp一级证书含金量 NISP一级证书是面向各个行业工作人员信息安全意识普及化和网络信息安全基础培训的国家级验证.持NISP一级证书可以从信息安全保密较高的单位得到加分.证书由中国信息安全测评中心授 ...

  2. ssh远程端口转发&&windows系统提权之信息收集&&网安工具分享(部分)

    一.ssh远程端口转发 背景:当我们在渗透过程中,获取到内网的一台仅有内网IP的服务器后,我们可以通过ssh隧道,将内网某个主机的端口进行远程转发 1.网络拓扑图 假设获取的服务器为web服务器,we ...

  3. 想学渗透测试,应该考CISP-PTE还是NISP-PT?|网安伴nisp和cisp

    其实两者都可,但要看考生的实际需求! 为什么说两者都可以? 两个证书都由中国信息安全测评中心颁发,CISP-PTE全称国家注册渗透测试工程师,NISP-PT全称国家信息安全水平考试-渗透测试工程师专项 ...

  4. 2022年NISP考试时间|NISP一级考试时间|NISP|网安伴|NISP管理中心

    NISP一级~~国家信息安全水平考试一级证书 NISP一级证书是由中国信息安全测评中心颁发的国家级认证证书.面向全社会各行各业通用的信息安全意识普及和信息安全保护知识培训,是在任何单位和工作中都应具备 ...

  5. F5隐写工具使用

      0x00 前言 今天在实验吧看到一个图片隐写的题目,用了stegslove和winHex分析一通发现并没有什么有效信息.看了评论区大佬的提示说用到了F5隐写工具,所以百度教程用了一下,发现确实解决 ...

  6. 用Python做2048游戏 网易云课堂配套实验课。通过GUI来体验编程的乐趣。

    第1节 认识wxpython 第2节 画几个形状 第3节 再做个计算器 第4节 最后实现个2048游戏 实验1-认识wxpython 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiy ...

  7. 2019 第二届 科成安洵杯 官方WriteUp -17网安

    长文预警:对应源码请加企鹅群获取:861677907 0x01 WEB 1.1 勇闯贪吃蛇大冒险 一进去就看出来是一道web页面JS的小游戏,提示说输入CDUESTC CTF即可闯关成功,但是存在着d ...

  8. 全国高校网安联赛Web专场~WriteUp

    1.Sign 题目:Good Luck!flag{X-nuca@GoodLuck!} Flag直接写在题目上了,flag{X-nuca@GoodLuck!} 2.BaseCoding 提示:这是编码不 ...

  9. 360网安学习笔记——Web安全原理与实践

    网络安全 基本技能: 1.编程语言 2.计算机网络 3.操作系统 4.office 专业技能 1.web安全 2.网络安全 3.渗透测试 4.代码审计 能力提升 1.书籍 2.站点 3.安全平台 We ...

  10. 网安日记③之通过iis搭建ftp并使用通过serv-u搭建ftp

    通过iis搭建ftp并使用通过serv-u搭建ftp 安装iis的ftp访问 由于在安装iis时勾选了ftp服务,我们直接在iis界面右键ftp服务打开属性查看本地路径 在电脑目录下打开安装目录,并在 ...

随机推荐

  1. 初探ASP.NET Core 3.x (2) - ASP.NET Core与ASP.NET前世今生

    本文地址:https://www.cnblogs.com/oberon-zjt0806/p/12210662.html 注意 本节是历史课,且绝大多数内容来自于百科或者其他的什么资料来源,如果不感兴趣 ...

  2. 炸裂:SpringAI内置DeepSeek啦!

    好消息,Spring AI 最新快照版已经内置 DeepSeek 了,所以以后项目中对接 DeepSeek 就方便多了.但因为快照版会有很多 Bug,所以今天咱们就来看稳定版的 Spring AI 如 ...

  3. 《刚刚问世》系列初窥篇-Java+Playwright自动化测试-14- iframe操作-下篇(详细教程)

    1.简介 通过前边两篇的学习,想必大家已经对iframe有了一定的认识和了解,是不是感觉和Python语言中的差不了多少,大同小异,最多就是不同开发语言的一些语法差异.今天这一篇主要是对iframe做 ...

  4. 解决黑群晖 Docker 日志八小时时间差的有效方法

    步骤一:登录黑群晖控制台 首先,我们需要登录到黑群晖控制台.可以通过SSH登录,或是直接在黑群晖控制台界面上操作. 步骤二:停止相关的Docker容器 在解决时间差问题之前,我们需要停止相关的Dock ...

  5. Chrome 133 里程碑式更新 - moveBefore, 或开启前端框架未来新纪元?

    相关背景: Chrome 133 版本(将于 2 月 4 日发布稳定版)引入了一个新的 DOM 操作方法:Node.prototype.moveBefore.这一方法虽然看似简单,但其意义重大,因为它 ...

  6. selenium自动化测试入门

    Selenium是一个基于浏览器的自动化测试工具,它提供了一种跨平台.跨浏览器的端到端的web自动化解决方案. Selenium是用于自动化控制浏览器做各种操作,打开网页,点击按钮,输入表单等等,可以 ...

  7. Joker 智能开发平台:低代码开发的革新力量

    在软件开发领域,开发效率与灵活性始终是开发者们追求的核心目标.随着技术的迅猛发展,低代码开发平台逐渐成为行业焦点,而 Joker 智能开发平台凭借其卓越的性能和创新的功能,脱颖而出,为开发者们带来了前 ...

  8. Linux下查询tomcat进程命令

    由于查询tomcat进程时将ps -ef|grep tomcat命令记错为ps -f|grep tomcat命令,因此对比两个命令进行区分. ps -f |grep tomcat执行结果: dgztc ...

  9. BUUCTF---RSA5(低加密指数广播攻击)

    题目 知识 加密指数e非常小 一份明文使用不同的模数n,相同的加密指数e进行多次加密 可以拿到每一份加密后的密文和对应的模数n.加密指数e 解密 由于模数n只能分解为p和q,所以当n很多时,p或q有相 ...

  10. [每日算法 - 阿里机试] leetcode19. 删除链表的倒数第 N 个结点 「 详细图释一看就懂!」

    入口 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer.https://le ...