ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MATLAB实现二维Logistic与Liu混沌图像加密:置乱、扩散与安全性分析

MATLAB实现二维Logistic与Liu混沌图像加密:置乱、扩散与安全性分析 做图像加密研究的人一定会频繁遇到“二维Logistic混沌映射 Liu混沌系统”这个经典组合。我第一次在MATLAB里跑通这套方案时印象非常深加密前一张Lena图的相邻像素相关性高达0.97加密后直接掉到0.01以下信息熵从7.4左右被顶到7.997附近。这种直观的反差比读十篇论文都管用。这篇文章把我实际用MATLAB实现图像加密、解密以及做安全性分析的过程完整整理出来包括置乱和扩散的先后顺序、Liu系统序列怎么量化、逆扩散为什么必须反着算、信息熵和相邻像素相关性这些指标怎么用代码算、怎么判断结果是否合格。适合刚接触混沌图像加密的学生、做课程设计或论文验证的人以及想快速复现“二维LogisticLiu”方案的开发者参考。1. 为什么图像加密要选混沌系统二维Logistic与Liu的定位1.1 图像加密和文本加密的本质差异很多人第一次接触图像加密时都会问为什么不直接用AES直接把像素当成字节流加密这个问题其实问到了点子上。AES当然可以对图像加密而且安全性有保证但它并没有利用图像的二维空间结构。图像数据有几个显著特点数据量巨大、相邻像素之间存在强相关性、本身存在大量视觉冗余。直接按文本方式加密往往计算开销偏大而且加密后的结果很难在视觉特性上直观评估。混沌系统在图像加密里的优势恰好是针对这些特点。混沌系统产生的序列有三个让人着迷的性质初值极端敏感、长期行为不可预测、轨道遍历性。初值极端敏感意味着只要密钥差一点点生成的整个序列就会完全不同这天然符合密码学里对密钥扩散的要求轨道遍历性意味着混沌序列能在取值空间里均匀游走可以用来把图像原本有规律的灰度分布打散成近似均匀的分布。AES和混沌加密不是对立关系而是不同层面的工具。AES是标准的对称分组密码安全模型非常成熟混沌加密则更讲究“用简单的迭代运算快速生成大量伪随机序列”在图像这种高冗余数据的场景里特别顺手。实际工程中也有人做“混沌序列 AES轮运算”的混合方案但作为起步和课程设计二维Logistic加Liu系统的组合已经足够说明问题。1.2 二维Logistic映射和Liu系统分别解决什么问题先说二维Logistic映射。一维Logistic映射形式是x(n1)μx(n)(1-x(n))它产生的序列随着μ的变化会出现倍周期分岔进入混沌区的参数范围也比较窄而且一维混沌系统在已知明文攻击面前安全性偏弱。二维Logistic映射把一维的状态变量扩展成两个互相耦合的变量典型形式是x(n1)r1·x(n)·(1-x(n))s1·y(n)² y(n1)r2·y(n)·(1-y(n))s2·x(n)²当r1、r2取在(1, 1.19]附近、s1、s2取接近0.1时系统进入混沌状态。注意这里x和y是互相牵制的x的下一步会受到y当前值平方的影响y的下一步也会受到x当前值平方的影响。这种耦合让序列的遍历性和随机性比一维系统强不少密钥空间也更大。在我实际使用中它最适合做置乱阶段的“随机索引生成器”。Liu混沌系统则是一组连续混沌常微分方程。跟Logistic这种离散映射不一样Liu系统有多个状态变量动力学行为更复杂方程形式通常是dx/dta(y-x) dy/dtbx-kxz dz/dt-czhx²参数取a10、b40、c2.5、k1、h4这类典型值时系统会进入混沌状态。因为是连续系统用MATLAB实现时要么用ode45求解要么自己写RK4迭代。它的状态变量随时间变化极其复杂取其中某个分量的小数部分做量化就能得到很好的灰度级密钥流。两个系统怎么分工呢我自己的做法是二维Logistic负责“乱序”也就是生成置乱索引Liu系统负责“乱值”也就是生成扩散用的密钥流。这样设计有个好处两个混沌源相互独立即使攻击者通过统计手段还原了某一类混沌序列的规律另一套序列仍然能保护密文。单系统加密最怕的就是被回归分析或机器学习方法逼近出系统方程双系统混用能明显提高这种攻击的难度。2. 加密流程拆解从置乱到扩散两个混沌序列各司其职2.1 整体加密框架图像加密的基本框架是“置乱 扩散”这个概念必须深刻理解。置乱是改变像素的位置像素本身的值没变但位置被重新排列原来相邻的像素被打散到远处。扩散是改变像素的值把明文图像的灰度信息“搅拌”进整个密文图像中让任何一个明文的微小变化都影响到后续所有密文。整体加密流程可以拆成这样几步读取灰度图像把二维矩阵展开成一维像素向量总共M×N个像素。用二维Logistic映射生成M×N长度的混沌序列对该序列排序得到随机置换索引。用置换索引对一维像素向量做全局置乱。用Liu系统生成另一条混沌序列量化成0到255的整数密钥流。将置乱后的像素向量和密钥流做链式扩散运算得到一维密文向量。把密文向量还原成M×N的矩阵保存或展示密文图像。这套流程的优点是置乱和扩散用的是两套独立随机源工序分明调试时也好定位问题。2.2 置乱阶段二维Logistic索引排序的具体做法二维Logistic生成序列的具体代码可以这么写function [x_seq, y_seq] logistic2d(r1, r2, s1, s2, x0, y0, N) % 二维Logistic映射 % r1, r2 控制在(1, 1.19]s1, s2 接近0.1系统处于混沌状态 burn 1000; % 丢弃暂态 x zeros(1, N burn); y zeros(1, N burn); x(1) x0; y(1) y0; for i 1 : N burn - 1 x(i 1) r1 * x(i) * (1 - x(i)) s1 * y(i)^2; y(i 1) r2 * y(i) * (1 - y(i)) s2 * x(i)^2; end x_seq x(burn 1 : end); y_seq y(burn 1 : end); end这里有两个容易忽略的细节。第一混沌系统迭代开始时往往有一段暂态这时的序列值和初值的关系比较“直接”容易被攻击者利用所以我把前1000次迭代丢弃掉。第二x和y的取值范围一定要保持在混沌区间内如果参数没有选对序列可能收敛到固定点或者进入周期环那后续置乱就没有随机性可言了。拿到x_seq之后用MATLAB内置的sort函数生成置换索引[~, idx] sort(x_seq); img_vec double(img(:)); shuffled img_vec(idx);sort的妙处在于它不是生成一个真随机排列而是通过对伪随机序列排序得到一个确定性的置换。解密只需要重新生成同样的x_seq再做一次sort就能得到同样的idx再用逆索引还原。这正是混沌序列可复现性带来的好处。有人会问为什么不直接用randperm生成随机索引因为randperm的随机性来自系统时钟每次运行结果都不同加密容易、解密难。混沌序列则是确定性的同样的初值和参数一定会产生同样的序列所以加密和解密都能稳定复现。这是混沌加密能成立的基础。2.3 扩散阶段Liu系统量化与链式反馈设计置乱改变了像素位置但像素的灰度值没有变化所以直方图仍然保留原始特征攻击者还能从灰度统计里分析出信息。扩散阶段就是要打破这一点。先用Liu系统生成连续的混沌状态序列。下面是RK4迭代的核心逻辑function seq liu_system(init, L) % Liu混沌系统使用四阶Runge-Kutta离散化 % 方程dx/dta(y-x)dy/dtbx-kxzdz/dt-czhx^2 a 10; b 40; c 2.5; k 1; h 4; dt 1e-3; burn 3000; total L burn; u init(:); seq_pre zeros(1, total); for i 1 : total seq_pre(i) u(1); k1 liu_rhs(u, a, b, c, k, h); k2 liu_rhs(u 0.5 * dt * k1, a, b, c, k, h); k3 liu_rhs(u 0.5 * dt * k2, a, b, c, k, h); k4 liu_rhs(u dt * k3, a, b, c, k, h); u u (dt / 6) * (k1 2 * k2 2 * k3 k4); end seq_pre seq_pre(burn 1 : end); seq mod(seq_pre - floor(seq_pre), 1); % 映射到[0,1) end function du liu_rhs(u, a, b, c, k, h) x u(1); y u(2); z u(3); du [a * (y - x); b * x - k * x * z; -c * z h * x^2]; end这里我取了Liu系统三个状态里的第一个分量通过mod(x - floor(x), 1)提取小数部分把连续混沌轨道的取值映射到[0,1)区间。注意不要直接把原始状态变量拿来做量化因为连续系统的状态变量范围可能很大直接取整会出现明显的周期分布。接下来做量化。量化这一步很容易踩坑如果你用floor(s * 255)因为s的取值范围是[0,1)结果只会落在0到254之间255这个灰度级永远不会出现密文直方图会少一个柱。更好的做法是用模运算扩展key_stream mod(floor(seq * 10000), 256);这样能把[0,1)区间放大到[0,10000)再取模到[0,255]256个灰度级别都能均匀覆盖。扩散运算我用了链式反馈方式而不是简单的逐像素异或。核心思想是让前一个密文像素参与当前像素的加密形成一条扩散链C(i) mod( P(i) C(i-1) S(i), 256 )其中P(i)是置乱后的像素值C(i)是密文像素C(0)是一个密钥常数S(i)是Liu系统生成的密钥流。这条链式结构的价值在于只要明文中任意一个像素发生改变从那个位置开始往后的所有密文都会被改变。这种雪崩效应是判断加密算法扩散性能的重要指标。对应的MATLAB扩散代码function c_vec diffusion(shuffled, key_stream, c0) L length(shuffled); c_vec zeros(1, L); c_vec(1) mod(shuffled(1) c0 key_stream(1), 256); for i 2 : L c_vec(i) mod(shuffled(i) c_vec(i-1) key_stream(i), 256); end c_vec uint8(c_vec); end模加的好处是结果始终落在0到255之间不会溢出也不需要复杂的位运算。用uint8存储还能直接还原成图像矩阵显示。3. 解密流程与MATLAB代码落地时的关键细节3.1 解密不是“恢复打乱”而是沿着加密链倒推解密是加密的逆过程但顺序必须完全反过来。如果加密时先置乱后扩散那么解密时应先逆扩散再逆置乱。很多人第一次写解密时就栽在这里先把置乱倒回去再处理扩散结果恢复出来的图像一片噪声。逆扩散的公式一眼就能看出来从加密公式反推P(i) mod( C(i) - C(i-1) - S(i), 256 )注意这里必须是C(i-1)也就是前一个密文像素。解密的时候必须从头到尾按顺序遍历密文向量因为每一步都依赖前一步的C(i-1)。代码实现function p_shuffled inv_diffusion(c_vec, key_stream, c0) L length(c_vec); p_shuffled zeros(1, L); c_vec double(c_vec); p_shuffled(1) mod(c_vec(1) - c0 - key_stream(1), 256); for i 2 : L p_shuffled(i) mod(c_vec(i) - c_vec(i-1) - key_stream(i), 256); end end逆置乱则需要把之前sort得到的idx索引转换回逆索引。假设用idx把元素重新排列那么逆索引inv_idx满足inv_idx(idx(i)) i。代码逻辑是function restored inv_scramble(decrypted_shuffled, idx) L length(idx); inv_idx zeros(1, L); inv_idx(idx) 1 : L; restored decrypted_shuffled(inv_idx); end最后把恢复出来的向量reshape回M×N矩阵转成uint8就是原始图像。3.2 容易翻车的三个细节我复现这个算法时踩过不少坑挑几个最典型的说。第一个是数据类型问题。MATLAB读入灰度图默认是uint8但混沌序列运算全是浮点数两者混着运算会出现大问题。所以加密前一定要转double解密恢复后再转回uint8。如果你在加密时忘了转double直接用uint8做mod运算MATLAB的mod会对小数截断结果就是加密时看起来正常解密后图像严重失真。第二个是序列长度匹配。图像的像素总数是M×N生成的混沌序列长度必须不小于M×N。我在二维Logistic函数里统一生成了N个点但有时候你会在循环里多生成几个或少生成几个导致后面置乱索引越界。稳妥的做法是用两个变量分别存序列长度和图像总像素数生成后立刻检查length(idx)是否等于numel(img)。第三个是Liu系统迭代稳定性。RK4的步长dt如果太大序列会出现发散或周期化如果太小迭代次数成倍增加256×256的图像还好512×512会明显变慢。我常用的dt是1e-3先迭代3000次作为暂态丢弃这样得到的序列稳定性和随机性都不错。如果你用的是ode45记得设置严格的相对误差容限否则不同版本MATLAB求解出的轨道路径会有差异。3.3 一条完整的加密解密调用流程把上面的函数串起来加密主流程大概是这样的% 密钥设置 para.r1 1.1; para.r2 1.1; para.s1 0.1; para.s2 0.1; para.x0 0.3; para.y0 0.5; para.liuInit [0.1; 0.2; 0.3]; para.c0 137; % 加密 img imread(lena.png); [img_h, img_w] size(img); L img_h * img_w; [x_seq, ~] logistic2d(para.r1, para.r2, para.s1, para.s2, para.x0, para.y0, L); [~, idx] sort(x_seq); img_vec double(img(:)); shuffled img_vec(idx); liu_seq liu_system(para.liuInit, L); key_stream mod(floor(liu_seq * 10000), 256); c_vec diffusion(shuffled, key_stream, para.c0); cipher_img reshape(c_vec, img_h, img_w); % 解密 p_shuffled inv_diffusion(c_vec, key_stream, para.c0); decrypted_vec inv_scramble(p_shuffled, idx); decrypted_img reshape(decrypted_vec, img_h, img_w); decrypted_img uint8(decrypted_img);这段代码的逻辑非常清晰。加密和解密使用同一个idx序列和同一个key_stream所以密钥就是二维Logistic的初值(x0,y0)和参数(r1,r2,s1,s2)再加上Liu系统的初值liuInit和扩散初始值c0。4. 安全性分析怎么做信息熵、相邻像素相关性及其他4.1 信息熵如何解读信息熵是用来衡量密文图像灰度分布随机性的指标。对于256级灰度图像信息熵的定义是H -Σ p(i)·log2(p(i))其中p(i)是灰度值i出现的概率。理想情况下如果256种灰度值出现的概率完全相等H应该等于log2(256)8。实际加密算法很难达到8但越接近8说明灰度分布越均匀统计特征越不明显。计算信息熵的MATLAB代码非常简单function H image_entropy(img) counts imhist(img); p counts / numel(img); p(p 0) []; H -sum(p .* log2(p)); end我测试标准Lena图时明文图像信息熵大约在7.4左右因为图像内容存在大量规律性灰度分布不均衡。加密后信息熵能达到7.997左右说明密文灰度的概率分布已经非常接近均匀。有一点要提醒信息熵高只是必要条件不是充分条件。一个完全随机的噪声图信息熵也很高但它未必是有效的密文所以要结合相关性、密钥敏感性、NPCR/UACI一起看。4.2 相邻像素相关性怎么算怎么判断相邻像素相关性是评价置乱效果的核心指标。明文图像因为内容连续相邻像素的灰度值往往非常接近相关性通常高达0.9以上好的置乱算法应该把相关性打到接近0。计算时需要分别考察水平、垂直和对角三个方向。以水平方向为例取出图像中每个像素在其右侧相邻位置的配对把所有配对组成两个等长向量求相关系数function r correlation_coef(img, direction) if strcmp(direction, h) a img(:, 1:end-1); b img(:, 2:end); elseif strcmp(direction, v) a img(1:end-1, :); b img(2:end, :); elseif strcmp(direction, d) a img(1:end-1, 1:end-1); b img(2:end, 2:end); else error(direction must be h/v/d); end a double(a(:)); b double(b(:)); tmp corrcoef(a, b); r tmp(1, 2); endcorrcoef内部会做均值归一化所以直接用它就行。除了算相关系数强烈建议把相邻像素对画成散点图。明文图像的散点图会聚集在yx这条对角线附近因为相邻像素值相近加密后散点图应该均匀铺满整个正方形区域几乎看不出任何线性关系。这个可视化效果在汇报和论文里非常加分。我的一组典型测试数据大致是这样测试项明文Lena加密后判断标准信息熵7.44517.9972越接近8越好水平相关系数0.97210.0031越接近0越好垂直相关系数0.98560.0024越接近0越好对角相关系数0.95900.0042越接近0越好当然每一次运行因为密钥不同会有小幅度波动但趋势是稳定的明文相关性在0.9以上密文相关性在0.01以下。4.3 密钥敏感性、密钥空间和NPCR/UACI除了信息熵和相关性完整的图像加密安全性分析通常还要补上这几项。密钥空间是抵御暴力破解的底气。当前方案里二维Logistic有x0、y0、r1、r2、s1、s2六组初值参数Liu系统有三维初值加上扩散用的c0哪怕按每组参数在连续区间里只取到10的15次方量级的有效精度总密钥空间也远超过2的100次方足够抵抗穷举攻击。密钥敏感性测试的做法是用密钥A加密明文得到C1然后把密钥A中的某个初值改动极小量比如把x0从0.3改成0.31e-15再用这个几乎相同的密钥加密同样的明文得到C2最后比较C1和C2的区别。好的加密算法应该让两个密文完全不同。NPCR和UACI是量化这种“微小明文变化引发密文剧变”的指标。NPCR表示两幅密文图像中灰度值不同的像素比例UACI表示两幅密文图像灰度差异的平均强度NPCR Σ (C1(i,j) ≠ C2(i,j) ? 1 : 0) / (M×N) × 100% UACI Σ |C1(i,j) - C2(i,j)| / 255 / (M×N) × 100%对于256级灰度图像NPCR理论值约99.6094%UACI理论值约33.4635%。实测时NPCR达到99.6%以上、UACI在33.3%到33.5%之间就说明算法对明文变化足够敏感。需要测试明文的一个像素值扰动把原图的某个像素加1分别加密两幅图然后计算NPCR和UACI。4.4 直方图分析为什么值得看一眼还有一个肉眼可判断的指标是灰度直方图。直接把加密前后的图片直方图对比一下明文图像的直方图往往跟随图像内容呈现明显的峰谷结构密文图像则应该像白噪声一样平铺。用imhist(cipher_img)扫一眼就能判断扩散是否到位。如果直方图上还能看到明显的轮廓或者周期性峰说明密钥流量化可能出了问题或者扩散链没起作用。5. 实测效果与踩坑记录从复现到改进的几点经验5.1 一次标准测试流程怎么跑我自己跑完整测试时流程基本固定下来也算是一个可复现的模板。第一步选测试图常用Lena、Peppers、Cameraman尺寸统一成256×256灰度图第二步写一个加密函数把密钥和图片路径作为参数第三步跑完加密后立即保存密文图像第四步一次性算出信息熵、三个方向的相关性、NPCR/UACI和直方图数据第五步用相同密钥解密用PSNR或肉眼确认恢复图像与原图像完全一致。这里特别建议把整个测试写成脚本而不是零散的命令行因为指标计算涉及的方向和图像比较多手动操作很容易漏项。脚本里固定随机生成一组有效密钥然后把所有结果存成表格方便回头核对。5.2 我在复现过程中踩过的坑第一个坑是置乱索引排序不稳定。二维Logistic序列有时候会出现连续几个非常接近的值虽然理论上是混沌的但浮点精度有限如果两个序列值完全相等sort返回的索引顺序在不同MATLAB版本里可能略有不同导致解密失败。解决方法是让序列之间尽量保留差异或者在加密前检查排序后的索引是否完全覆盖0到L-1。第二个坑是扩散运算里的模运算边界。mod(diff, 256)在MATLAB里返回0到255看起来没有问题但如果你的加密用的是bitxor而解密却用了mod相减那肯定对不上。加密和解密必须严格使用同一套运算体系混合使用位运算和模运算是最常见的错误。第三个坑是Liu系统的状态变量初值选择。初值必须避开所有分量为零的点否则系统可能停留在不动点序列退化成常数。我通常用[0.1; 0.2; 0.3]这类非零初值并且在生成序列后先计算一下最大值和最小值确认序列没有塌缩。第四个坑是解码时图像尺寸不对。加密前如果图像不是正方形reshape回M×N矩阵时搞错行列顺序图像就会错乱。建议加密前把图像尺寸统一或者在代码里用size函数动态获取M和N不要写死。5.3 想继续做深还能往哪个方向扩展这套“二维Logistic Liu”方案已经很完整但如果你想在它基础上做课程设计拓展或者论文改进有几个方向你可以尝试。一是彩色图像加密。不要简单地对R、G、B三个通道分别加密那样三个通道独立性强容易被统计攻击。更好的做法是把三个通道展开成一个长向量统一置乱或者对通道间做交叉扩散让通道之间的信息互相渗透。二是引入DNA编码。把灰度值转换成碱基序列再结合混沌序列做DNA运算比如异或、补码、替换等。DNA编码能进一步提高灰度扩散的复杂度在实际测试中往往能让相关性降到更低的水平。三是用压缩感知与混沌加密结合。先对图像做稀疏变换和降维再把测量矩阵用混沌序列控制实现“能压缩又能加密”的联合框架。这个方向适合研究生阶段做更偏应用的研究。四是改造为整数域混沌系统。直接使用浮点混沌系统在嵌入式设备里效率不高而且在不同的浮点环境下序列可能不一致。设计一个整数域混沌映射或者用定点化实现能让算法在C语言、FPGA上也能快速运行。最后补充几个实用的小建议如果你只是完成课程作业或者快速验证算法256×256的灰度图完全够用千万别一开始就拿高清彩色图折腾那样只会在数据转换上浪费大量时间。如果是论文写作记得把加密前后的直方图对比图、三方向相关性散点图都存好这些图是审稿人最关注的证据。另外所有测试代码尽量写成函数输入图片路径和密钥输出密文图像和各项指标。这样一来换图、换密钥、换尺寸都只需要改输入参数整个实验的可重复性会大幅提升。等你跑通现在的两套混沌系统之后再去看其他论文里的超混沌、四维系统会发现核心套路其实都是一样的先生成随机序列再做置乱和扩散最后用信息熵、相关性、NPCR/UACI去验证效果。把这个流程吃透了混沌图像加密这片领域的基本盘你就算是站住了。
返回列表