ARTICLE DETAIL

资讯详情

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

Matlab RSA图像加密:密钥生成、像素分块与模幂运算实现拆解

Matlab RSA图像加密:密钥生成、像素分块与模幂运算实现拆解 简介这是一份面向图像加密入门者与Matlab开发者的RSA图像加密解密完整实现可用于数字图像保密传输、教学实验与算法复现。代码基于Matlab 2019b编写主程序main.m可直接运行配套一系列功能函数完成密钥生成、像素级加密与解密还原操作门槛低适合初学者对照学习。压缩包共收录29个文件其中包含13个.m源码文件、14张运行效果图以及txt与md说明文档整体大小仅750KB结构简洁、便于快速定位核心代码与验证结果。目前已有114人学习程序经过亲测可运行替换自己的图像数据即可观察RSA加密解密效果同时附带的说明文档有助于理解算法流程与参数设置。1. RSA图像加密公钥密码用在像素矩阵上的第一道坎拿一张灰度图直接套RSA很多人第一次跑出来的密文图像根本不是噪声而是还能看出原图轮廓的“马赛克”。原因倒不在RSA本身而是像素值0到255这个取值范围远小于公钥模数n加密后统计分布被n“吸收”得不彻底直接从密文灰度直方图就能反推明文分布。这套基于Matlab的RSA图像加密解密源码SIT_Image_Encryption.m那一组文件含密钥生成、进制转换、加解密主函数解决的正是这条链路上的三个问题把图像像素高效地转成RSA能处理的大整数、在n的比特长度约束下做分块、以及解密端如何无损还原成灰度矩阵。适合正在做数字图像处理课设、或者想把公钥密码和图像内容保护结合起来的Matlab开发者。下面先从RSA的参数含义讲起再逐层拆到源码调用链。2. RSA数学基础与图像二进制表达的映射关系2.1 密钥生成三个参数的实际含义RSA走的是“大整数分解困难”这条路。密钥生成阶段要做的事是随机挑两个不相等的大素数p和q算模数np×q再算欧拉函数φ(n)(p−1)(q−1)。之后选一个公钥指数e要求1eφ(n)且gcd(e,φ(n))1最后用扩展欧几里得算法求e关于φ(n)的模逆元素d满足e×d ≡ 1 (mod φ(n))。这里有个关键点e和n组成公钥对外公开d是私钥核心必须保密。p、q在算出n和d之后原则上是销毁的工程实现里也有存起来给CRT解密用的做法。从图像加密的角度看这三个参数直接决定了两件事密文块长度由n的比特位数决定和加解密耗时e和d的比特长度决定模幂运算次数。源码里的SF_Key_Gen.m做的就是这件事从函数命名习惯看它内部大概率调用了Q_fun.m和P_fun.m来做素数候选生成与素性检测。参数符号在图像加密中的作用常见设置模数n决定每个密文块的比特长度必须大于明文块数值灰度演示建议512位公钥指数e加密端模幂运算的指数影响加密速度常用65537私钥指数d解密端模幂运算的指数位数接近n由扩展欧几里得算出欧拉函数φ(n)中间量生成密钥后通常不参与图像运算随私钥保存或丢弃公钥指数e直接写65537是工程上的常见做法。这个数是费马数F42¹⁶1二进制表示只有两个比特为1模幂运算可以用平方-乘算法大幅减少乘法次数。源码里如果看到e是写死的大数走的多半也是这个思路。反过来如果e取得太小比如e3在同余方程上有小指数攻击的风险图像又是高度结构化的数据明文块与加密结果的对应关系容易被穷举验证。2.2 灰度图像为什么要做进制转换图像像素和RSA之间的第一个矛盾就是进制。一幅M×N的8位灰度图在Matlab里是一个uint8矩阵每个元素是0到255的整数。RSA加密要求明文m是整数且满足0≤mn直接把0到255的像素值作为m去加密数学上没问题效果上很差一方面明文字节只有8位加密后密文cm^e mod n的取值范围被n的位数撑大解密后虽然能还原但密文没法直接显示成有意义的图像另一方面全图只有256个不同明文值相同像素加密结果完全相同密文图像会呈现明显的分层轮廓。所以实际做法是先把像素序列按n的比特长度分块再把每个块拼成一个大整数。源码里那一堆进制转换函数Dec2Bin.m、Binary2Dec.m、Hex2Bin.m、h2b.m、convert2bin.m就是在做这个桥接。Dec2Bin把十进制像素值转成二进制位串convert2bin负责把位串按块拼接成RSA能处理的大整数Hex2Bin和h2b处理的是密钥或中间结果以十六进制表达时的转换。为什么要经过二进制而不是直接拼十进制因为RSA密文的中间计算经常以十六进制展示二进制位串与十六进制之间的转换可以用查表法一次映射4位比反复除以256的十进制余数运算快得多。2.3 分块与填充明文块数值必须小于n分块大小的计算规则设n的二进制位数为bits_n每个块能承载的明文最大值由log₂(m) bits_n约束。对8位灰度图如果n是512位每个块最多放64字节也就是64个相邻像素拼成一个大整数。用整数表达就是每个块的值等于把64个字节视为一个bignum低位在前或高位在前都行只要加解密两端约定一致。Matlab里做这个拼接常见写法是把像素行向量按块长做加权累加。% 分块拼接示例将像素向量按块长拼成大整数序列 % pix_vec : uint8 行向量长度能被 block_len 整除 % block_len : 每个块包含的像素个数条件 256^block_len n function blocks pixel_blocks_to_bigint(pix_vec, block_len) n_blocks numel(pix_vec) / block_len; % 重排成 [block_len, n_blocks] 矩阵每列是一个块 pix_mat reshape(pix_vec, block_len, n_blocks); % 列方向加权累加第一个像素为最低字节weight 按 256 幂递增 weights uint64(256) .^ (0:block_len-1); blocks zeros(1, n_blocks, uint64); for k 1:n_blocks tmp uint64(pix_mat(:, k)); blocks(k) sum(tmp .* weights); end end这段代码的逻辑每列代表一个块块的第一个像素作为最低有效字节权重数组weights按照256的幂递增累加结果blocks就是可以直接送进SF_Encrypt.m的明文大整数序列。参数block_len不能随意放大粗略估算条件是256^block_len n即block_len×8 bits_n。超过这个限制拼出来的大整数会大于nRSA模运算会对明文做隐式取模解密还原不回原始像素这是最常见的解密后图像花屏的原因。排错时优先级最高的检查项先算n的位数再算block_len×8两者必须满足严格小于关系。另外要留意数据类型上限用uint64做累加意味着这个写法更适用于n在512位以内、block_len不超过8的小规模演示。真正512位以上的RSAMatlab自带类型装不下密文需要借助Symbolic Math Toolbox的vpa或Java的BigInteger接口。源码里Scalling.m的出现很可能就是在加密前后对数据做移位或缩放保证整数转换和像素显示范围不互相冲突。3. Matlab源码拆解从SF_Key_Gen到SF_Decryption的调用路径3.1 文件清单与职责划分压缩包里那套代码按功能分四组密钥生成、格式转换、加解密核心、运行入口。SIT_Image_Encryption.m是主入口加解密逻辑分散在多个SF_前缀的m文件里。从命名习惯和调用关系看函数划分比较细这也符合Matlab图像加密demo的一贯风格。文件名分组职责推测SIT_Image_Encryption.m入口读图、调度密钥生成与加解密、输出密文和还原图SF_Key_Gen.m密钥生成p、q、n、e、d返回公私钥结构体Q_fun.m / P_fun.m密钥素数候选生成与Miller-Rabin素性检测f_fun.m密钥计算欧拉函数φ(n)或辅助验证gcd(e,φ)1SF_Encrypt.m加密输入明文大整数序列与公钥输出密文大整数序列SF_Decryption.m解密输入密文与私钥用模幂运算还原明文大整数序列Dec2Bin.m / Binary2Dec.m转换十进制像素与二进制位串互转Hex2Bin.m / h2b.m转换十六进制与二进制互转convert2bin.m转换将像素矩阵转换成按块划分的二进制位序列Scalling.m显示加解密结果与灰度显示范围之间的缩放映射阅读顺序建议从SIT_Image_Encryption.m开始沿调用链往下走先看每个函数的输入输出再回头读内部实现。比从头到尾逐个文件扫效率高也更容易定位解密还原失败时到底断在哪一环。3.2 加密链路像素块如何变成密文加密端的核心逻辑是取出每个明文大整数m用公钥e和n做模幂运算cm^e mod n。Matlab里对几百位的大整数做模幂不能用内置的power或^直接算必须自己实现平方-乘算法或者借助Java的BigInteger.modPow。% 模幂运算示例计算 base^exp mod mod % 采用二进制展开的平方-乘算法避免中间结果溢出 function result mod_pow(base, exp, mod) result 1; base mod(base, mod); e_bits de2bi(exp); % 转为二进制位低位在前 for i numel(e_bits):-1:1 result mod(result * result, mod); % 每轮先平方 if e_bits(i) 1 result mod(result * base, mod); % 当前位为1则乘base end end end逐行说明result初始为1是模幂运算的乘法单位元循环从指数e的最高位往低位走每轮先做一次平方再取模遇到当前位为1再做一次乘法乘法之后立即取模保证中间结果始终小于mod。这个算法的乘法次数约等于log₂(e)加上e中比特位为1的个数。对于512位n、e65537的情况平方大约512次乘法只有2次耗时主要压在加密分块的数量上而不是单次模幂上。加密链路的数据流是uint8图像矩阵转成灰度convert2bin展成位串Dec2Bin按块拼成大整数SF_Encrypt逐块模幂得到密文大整数序列。这里有个容易踩的坑密文大整数数值远大于255直接imshow会全白或全黑必须先对密文矩阵做归一化再转uint8否则所谓密文图就是一张死黑图容易误判为加密失败。3.3 解密链路CRT加速与Scalling还原解密端数学上就是再算一次模幂mc^d mod n。实际工程里很少直接对d做完整比特长度的模幂而是用中国剩余定理加速先把d拆成d mod (p−1)和d mod (q−1)分别在模p和模q下做模幂再用CRT合并结果。对于图像这种海量分组的场景加速比接近4倍收益非常明显。% 基于CRT的RSA解密示例输入密文c、私钥d、素数p、q、模数n function m rsa_decrypt_crt(c, d, p, q, n) dp mod(d, p-1); % 私钥指数在模p-1下的缩减 dq mod(d, q-1); % 私钥指数在模q-1下的缩减 m1 mod_pow(c, dp, p); % 模p下的部分解 m2 mod_pow(c, dq, q); % 模q下的部分解 qinv modinv(q, p); % q 在模 p 下的逆元 h mod((m1 - m2) * qinv, p); m m2 q * h; % CRT合并得到模n下的明文 end参数含义dp和dq分别是d关于(p−1)、(q−1)的缩减指数依据费马小定理指数可以模(p−1)和(q−1)缩小而不影响结果qinv是q在模p下的逆元可以在密钥生成阶段预计算并随私钥一起存储。合并时h保证了m在两个模下同时满足同余条件。解密完成后拿到的m序列再走Binary2Dec和Dec2Bin把大整数拆回原始像素块最后用Scalling做反缩放得到可以imshow的灰度矩阵。判断标准解密图与原图的PSNR大于50dB基本可以认定还原过程没有信息损失。如果出现个别像素偏差1到2个灰度级多半是Scalling缩放取整导致的不一定是RSA解密本身出错。4. 跑通demoMatlab 2019b下的完整操作与参数验证4.1 运行环境与版本兼容这套源码的开发版本标注是Matlab 2019b。操作前的准备把解压得到的文件夹整体加入Matlab搜索路径而不是只双击打开某个m文件。因为SIT_Image_Encryption.m会调用同目录下的SF_Key_Gen.m、SF_Encrypt.m等函数脚本所在目录必须是当前路径否则直接提示Undefined function或file not found。% 将代码根目录加入搜索路径并确认 addpath(你的解压路径/SIT_Image_Encryption); savepath; % 保存路径设置避免下次重来 which SF_Key_Gen % 验证能找到密钥生成函数执行完这段再打开SIT_Image_Encryption.m直接点Run。如果首次运行报错优先检查两个地方一是路径里有没有中文或空格Matlab对含中文的路径支持不稳定建议把整个文件夹放到纯英文路径下二是Images子目录下的原图文件名是否与脚本里写死的路径一致demo常见的坑是脚本找lena.png而实际放的是Orignal.jpg。4.2 一次完整的加密解密运行主脚本内部大致是下面这段调用链。用这段代码可以单独验证某个环节是否正常也方便替换成自己的测试图。% 主流程示例读图、生成密钥、加密、解密、对比 img imread(Images/Orignal.jpg); if size(img, 3) 3 img rgb2gray(img); % 统一转灰度简化处理 end [pub_key, priv_key] SF_Key_Gen(512); % 512位RSA密钥 cipher_blocks SF_Encrypt(img, pub_key); plain_blocks SF_Decryption(cipher_blocks, priv_key); restored reshape(plain_blocks, size(img)); psnr_val psnr(uint8(restored), uint8(img)); fprintf(PSNR %.2f dB\n, psnr_val);逻辑说明先读图并转灰度保证输入是单通道uint8矩阵SF_Key_Gen(512)里的512是模数n的比特位数传得越大越安全但耗时指数级上升加密返回密文大整数序列解密后restored是double矩阵需要转回uint8再和原图比较。PSNR超过50dB说明加解密闭环无损PSNR为Inf说明restored与原图完全一致这在尺寸较小的测试图上很常见。参数方面的实际经验n设512位时一次完整加解密演示在普通笔记本上大约2到4秒主要耗时在SF_Encrypt对每个分块做模幂n1024位时时间会拉到几十秒量级不适合大图演示。如果只是想看流程跑通建议先用128×128或256×256的小图把n设成256位几秒内就能看到结果。4.3 运行结果图里能观察到的现象源码压缩包里带了三张运行结果图正常输出应当包含三类图像原始灰度图作为对照基准显示原图纹理细节。加密后的密文图看起来是均匀的椒盐噪声肉眼读不出任何轮廓如果还能看出原图边缘说明分块拼接方式有问题或e取值太小。解密还原图与原图逐像素一致肉眼不可分辨差异。判断加密效果可以自己算一个量化指标。明文图像的像素值高度集中加密后的密文大整数序列如果映射回0到255显示直方图应当接近均匀分布。% 加密效果检查密文灰度分布的均匀性 cipher_img mat2gray(cipher_blocks); % 归一化到[0,1] cipher_img im2uint8(cipher_img); % 转uint8显示 histogram(cipher_blocks, 64); % 观察分布是否平坦如果直方图呈现明显多峰或与原图直方图形状类似说明加密没有把统计特征打散。这时候按两个方向排查p、q生成时是否太接近比如相差小于10的几十次方量级这会让n容易被费马分解法在可接受时间内破解以及e是否过小小指数在明文块较短的场景里容易被低密度明文攻击还原。5. 进阶RSA图像加密的小明文攻击防护与混合加密5.1 确定性加密带来的轮廓泄露RSA是确定性加密算法同样的明文m在相同密钥下永远得到同样的密文c。图像里大面积平坦区域比如天空、白墙、桌面存在大量连续相同像素。直接逐块加密后这些区域的密文块完全一致映射成灰度图后还是会形成一片均匀区域攻击者可以从密文图里直接数出平坦区域的位置和形状。这个性质不是RSA的漏洞而是确定性公钥加密在结构化数据上的固有特征。对策有两条路。一是给每个明文块加随机填充PKCS#1 v1.5的随机填充方案就能让相同像素块每次加密产生不同密文代价是密文膨胀每个块要额外带上随机字节。二是放弃全图直接加密改用混合加密框架这也是实际系统里更常见的工程选型。5.2 混合框架RSA只加密置乱参数考虑到RSA模幂运算的耗时图像加密里更实用的做法是先对图像做置乱再用轻量级算法处理像素RSA只负责保护置乱的密钥参数。Arnold置乱是常见的置乱手段通过迭代变换把像素位置打散置乱次数和行列参数作为密钥内容。RSA加密的只是这几十字节的参数既保证了对攻击者的门槛又把耗时降了几个数量级。% 混合加密思路用RSA加密Arnold置乱的迭代次数 iter 5; % 置乱迭代次数作为密钥内容 enc_iter SF_Encrypt(iter, pub_key); % 用RSA加密这个参数 % 图像本体用Arnold置乱迭代 iter 次后得到置乱图 % 后续像素级的扩散可以用Logistic映射或DNA编码来完成 dec_iter SF_Decryption(enc_iter, priv_key); % 解密出迭代次数这里的关键切换在于RSA的输入从整幅图像变成了一个标量参数明文空间从几万字节骤减到几个字节加密耗时可以忽略不计。图像本体的保护由置乱和后续像素级操作完成。这种方案的附带收益是私钥泄露的风险面缩小了即使拿到私钥攻击者也只能还原出置乱参数图像内容本身还被第二层加密保护着。5.3 用直方图和像素相关性验证混合加密效果最后给出一个简便的验证方法。加密算法改没改到位跑三个指标就知道明文密文的直方图差异、相邻像素相关系数、解密还原的PSNR。前两个指标不需要额外工具箱用Matlab自带函数就能算。% 相邻像素水平相关性计算 img_vec double(img(:)); shifted circshift(img_vec, 1); corr_val corrcoef(img_vec, shifted); fprintf(明文相邻像素相关系数: %.4f\n, corr_val(1,2)); % 密文做同样计算相关系数应当趋近于0 cipher_vec double(cipher_img(:)); shifted_c circshift(cipher_vec, 1); corr_val_c corrcoef(cipher_vec, shifted_c); fprintf(密文相邻像素相关系数: %.4f\n, corr_val_c(1,2));corrcoef返回2×2相关系数矩阵取(1,2)位置就是两组数据的皮尔逊相关系数。明文图像的相邻像素相关系数通常在0.9以上因为图像内容有强烈的空间连续性加密后如果算法有效这个系数会掉到0.1以下甚至趋近于0。如果测出来密文相关系数还在0.5以上说明加密只是对数值做了小幅扰动没有把像素间的统计关联打断。这时候回头检查密钥位数和分块逻辑比盲目加大图片尺寸更有效。本文还有配套的精品资源点击获取
返回列表