OpenCV 基于logistic混沌对图像加密与解密

痞子三分冷 提交于 2020-02-01 02:54:55

标题数字图像加密方法分析

一、数字图像加密方法基本要求和分类
1.1图像加密算法要求
①安全性。混淆和扩散是设计具有计算安全性的密码的必要条件。 ②实时性。加密算法的使用不能给图像数据传输和存取带来过大的延迟。 ③数据量不发生膨胀。 ④数据格式不变。
1.2 数字图像加密算法分类
①基于空间域的像素置乱 ②基于混沌加密 ③基于变换域加密 ④基于秘密分割与秘密共享加密 ⑤基于神经网络和元胞自动机加密 ⑥基于盲源分离加密。

二、数字图像加密方法介绍
2.1 基于空间域的像素置乱
置乱变换可以快速地打乱像素位置,破坏图像中原有的空间有序性和局部相关性,把图像变得杂乱无章、无法识别,使图像呈现一种类似噪声的形式。为了保证加密之后还能正确恢复,置乱变换必须为一一映射。常用置乱方法有:Arnold变换及其扩展变换、Baker映射、幻方变换、魔方变换、基于S盒的置乱、基于拉伸折叠思想的置乱、基于Scan语言的置乱、基于骑士巡游的置乱、基于随机数排序的置乱、基于像素值排序的自适应置乱、基于线映射的置乱、基于队列的置乱和基于四叉树编码的置乱等。在上述置乱方法中,Arnold变换及其扩展变换采用了矩阵变换的形式,它们同Baker映射一样都能快速地将相邻像素分散开,像素的移动具有混沌特性,而且耗费的计算量很小。基于仿射变换的置乱使得所有的像素点均可能改变了位置,而猫映射、广义猫映射、二维双尺度矩形映射没有改变(0,0)处像素的位置,这可能成为包含置乱操作在内的整个算法的安全漏洞。基于猫映射变换、幻方变换、骑士巡游的置乱对图像的长宽比例有限制,使得它们的适用范围有限。基于随机数排序的置乱先产生一个随机数序列,将该序列中各数值的大小对应设置为图像中各像素的权值,按权值大小对像素进行排序,以达到置乱的效果。基于像素值排序的自适应置乱用图像中一部分像素值的大小对应作为图像中另一部分像素的权值,按权值大小对这另一部分像素进行排序;如此交替赋以权值并进行排序,以达到置乱的效果。基于排序的置乱算法时间复杂度较高,而且为了存储对应的像素位置,可能还需要额外的存储空间,所以空间复杂度也较高。基于四叉树编码的置乱结合了无损压缩编码,它在形成四叉树之后对四叉树的内部节点和叶子节点进行置乱,以达到加密的效果。
目前已有的置乱算法大都不改变像素值,它们通过对明密文的像素直接进行比对就可能发现置乱规律,安全性较低。同时,由于离散数字图像是有限点集,在置乱变换若干次以后图像终究会回复到初始状态,因此只要知道加密算法,按照密文空间的任意一个状态来进行迭代,都会在有限步内恢复出明文。
2.2 基于混沌的加密
混沌系统是非线性的系统,表现出非常复杂的伪随机性,符合混淆规则。它对初始条件和控制参数非常敏感,任何微小的初始偏差都会被指数式放大,符合扩散规则。同时,它又是确定性的,可由非线性系统的方程、参数和初始条件完全确定。因此,初始状态和少量参数的变化就可以产生满足密码学基本特征的混沌密码序列,将混沌理论与加密技术相结合,可以形成良好的图像加密系统。目前常用于图像加密的混沌系统有:Logistic混沌映射、Chebychev映射、分段线形混沌映射、Cubic映射、标准映射、Henon映射、Lorenz混沌映射、蔡氏混沌、Rossler混沌系统、二维Sinai映射、Chen’s混沌系统等。在基于混沌的图像加密方法中,有的利用混沌系统产生伪随机序列,进行序列密码形式的加密。有些利用混沌的遍历性,对产生的伪随机序列作处理,得到像素置乱后的位置,然后对像素位置进行置乱。有些利用一些混沌计算表达式可逆的特点,将像素值代入混沌计算式以进行像素的代换和扩散。与传统加密算法相比,混沌图像加密算法密钥空间大,实现简单,加密速度快。但是,基于混沌的图像加密存在以下不足:①计算机的有限精度可能导致混沌序列的周期比较短,随机性不好。 ②现有的混沌加密技术大都基于一维或二维混沌系统,容易受到相空间重构方法攻击。 ③一些混沌加密算法采用了形式比较复杂的混沌系统,速度较慢,无法实现实时的加密。
2.3 基于变换域的加密
变换域中每一个系数的改变都会导致图像空间域中所有像素值的改变,因此可以通过在变换域对系数进行处理来达到加密的效果。由于计算机精度有限,基于变换域的加密算法在变换与反变换时存在数据精度损失,解密后的图像与明文不会完全相同。另外,如果将从空域映射到变换域的操作仅仅作为一个加密运算步骤,而未将其结合到压缩编码中,那么所耗费的计算量就没有得到充分利用。在不要求解密所得与明文完全一致的情况下,应优先采用结合有损压缩的加密算法。 如果仅置乱量化后的系数的位置或改变系数的符号,则安全性不高。类似于分析空域像素直接加密的算法,攻击者可以通过比对明、密文图像变换域量化后的系数来找出置乱规律,从而破解加密算法。所以,基于变换域的数字图像加密也需要代换、扩散操作。 如果针对频域所有量化后的系数进行全局的置乱、代换、扩散,那么就可能极大地破坏量化后系数的大小分布规律,使得压缩效果不好。如果加密算法先在空间域进行像素的置乱,然后进行空域到变换域的变换、量化,最后加密量化后系数,那么逆向操作(即解密)之后的图像质量会受到很大影响,而且由于一开始就破坏了图像中的局部相关性和空间有序性,压缩效果也不好。 综上,为了降低加密对压缩的影响并保留较好的图像质量,在变换域系数被量化之前尽量不采用加密操作,并且在变换域系数被量化后,应采取局部置乱、代换和扩散的方法,这样才能减少加密的数据量,提高加密效率。
2.4 基于秘密分割与秘密共享的加密
秘密分割就是把消息分成许多碎片,每一个碎片本身不代表任何意义,但把这些碎片放到一起就可以重现原来的信息。该方法存在的问题是:当分割后的碎片中任一个出现问题(如丢失)时,整个信息就不能恢复出来。这种思想用于图像加密就是先把明文图像按某种算法进行分割,并把分割后的数据交给不同的接收者,需要保存数据的所有接收者共同参与,才能恢复出原始明文。 基于秘密分割与秘密共享的方法在用于图像加密时,会使得密文数据量发生膨胀,给本来数据量就大的图像带来更大的存储、传输负担。
2.5 基于神经网络和元胞自动机加密
人工神经网络是由许多简单的、高度互联的神经元构成的,它对外部输入进行动态的信息处理,其特点是并行分布处理模式。此外,神经网络还具有非线性、联想记忆的特点,因此适合于信息的加密。
2.6 基于盲源分离的加密
它在源信号和混合参数均未知的情况下,能够从混合信号中分离得到源信号的估计。当混合信号个数少于源信号个数时,通常不可能完全分开所有的源信号,这就是求解极为困难的盲源分离欠定难题。 由于盲源分离存在顺序和幅度模糊性,解密得到的图像可能发生顺序变化和像素值反转。并且,盲源分离通常无法分离强相关信号。当明文图像之间相关性较强时,在盲源分离解密之前,必须对加密图像信号进行去相关预处理,如高通滤波、多分辨率子带分解等,这增加了解密运算量。另外,基于盲源分离的图像加密要求密钥图像与明文图像大小相等、数目相同,这对密钥的设置与产生提出了更高的要求。所以,它不适合作为图像加密算法。
三、加密算法对比及现有图像加密算法不足
3.1 加密算法对比
以上6类加密算法以对应的主要操作(如置乱、生成混沌序列、空间域到变换域的转换等)为基本运算,综合比较如下:
在这里插入图片描述

**3.2 现有图像加密算法不足**
一些针对像素的空域加密算法看起来很复杂,但是没有综合运用置乱、代换、扩散操作,明密文对中存在很强的线性关系,它们容易受到选择明文攻击。	一些加密算法对任何明文加密时,实际使用的都是相同的等效密钥,即没有充分利用明文的数据信息来影响等效密钥的产生,这样的算法容易被选择明文攻击。	有的算法将加密过程与编码过程相融合,为了不影响压缩,采用的加密操作太简单,算法不安全。有的算法采用了选择加密的方法,即仅对变换域中少量的重要系数进行加密,攻击者可以通过忽略或者代换被加密的部分来窥探原始明文图像中的内容。	一些加密算法针对比特位单独进行操作,计算量较大。由于在内存中是以字节为单位存储数据的,计算机在处理每一个比特位时实际上需要耗费对整个字节进行操作的时间,因此总的计算量很大。

四、基于logistic混沌加密
根据上述分析,基于混沌加密的方法相对比较适用于对图像进行加密。其中logistic产生的序列具有非周期、不收敛、有较好的雪崩效应、随机性好的特点。(像素位置、像素都进行变换)

1)Logistic映射公式
在这里插入图片描述

2)加密解密算法(像素位置、大小)
一般的加密过程分为两个模块,一部分是像素融合模块,一部分是像素置乱模块。两模块之间相互独立,均可单独对图像进行有效的加密操作。为了提高加密的安全性,通常将两种加密方式结合起来使用。其中比特级的加密方式可以只进行一步置乱操作,但在效果上却可以达到像素融合的目的。下面是具体算法:
第一步,先将原始图像的像素值二维矩阵由 L 行 R 列转换成 L × R 行一列的形式,每一行有一个十进制数,表示一个像素值。
第二步,由于要做比特级的操作,我们就要将原始图片的每一位像素值由十进制化成二进制形式,像素值在区间(0,255)上,所以每个十进制像素值由八位二进制数表示,不足八位的高位由 0 补齐。具体换算公式为:
在这里插入图片描述
其中,i=1,2,…,8,xi表示二进制数的第 i 位(第一位为最低位),yi是原始像素,[yi/2]表示除以2再取整。把每一位二进制数看成是一个数,换算过后由十进制数表示的 L × R 行一列的矩阵就变成了 L ×R 行八列的形式。
第三步,将 L × R 行八列的矩阵继续整形成 L × R × 8 行一列的形式。
第四步,利用式(1)及初始值生成混沌序列,即迭代 Logistic 映射直到产生 L × R × 8个完全不同的值为止,记作{Ai,i=1,2,…,LxRx8},其中LxR是需要加密图像的大小。
第五步,对混沌序列{Ai,i=1,2,…,LxRx8}进行排序,得到位置索引,根据位置索引对上述 L × R ×8 行一列形式的矩阵进行置乱。
第六步,对置乱后的 L × R × 8 行一列形式的矩阵做第一步到第三步的逆操作。即先由 L × R × 8 行一列形式整形成 L × R 行八列的形式;再把 L × R 行八列矩阵每一行的八个数看成是二进制的每一位合并成一个二进制数,将这个二进制数换算成一个十进制数,L× R 行八列的矩阵变成 L × R 行一列;最后将L × R 行一列的矩阵还原成 L 行 R 列的形式成为加密图像。
解密过程是加密过程的逆运算。

	//对图像加密
	/*
	src:待加密图像
	dest:加密后的图像
	U:分岔系数,返回变量
	x0:初始状态,返回变量
	*/
	void encry_1channels(Mat src, Mat& dest, double& U, double& X0)
	{
		/*
		U:分岔系数---当3. 569 945 6<U<4时系统处于混沌状态
		X0:初始状态,但X0的微小变化对图像加密的影响是巨大的,即雪崩效应
		*/
		cvtColor(src, src, COLOR_RGB2GRAY);
		const int MAX1 = 1e5 + 79;
		//随机生成秘钥
		default_random_engine e;
		uniform_real_distribution<double> u(3.600001, 3.999901);
		U = u(e);
		default_random_engine e_x;
		uniform_real_distribution<double> u_x(0.450001, 0.888801);
		X0 = u_x(e_x);

		Mat image = src.clone();

		//标记号,等于图像列数(从0开始计数)
		int sign = src.cols - 1;

		vector<pair<double, int >> x;
		//初始状态
		x.push_back({ X0,0 });


		double temp;
		//生成混沌序列
		for (int i = 1; i <= sign; ++i) {
			temp = U * x[i - 1].first*(1 - x[i - 1].first);
			x.push_back({ temp,i });
		}
		//对序列进行排序
		sort(x.begin(), x.end());
		/****************************************************************************************************/
		/****************************************************************************************************
												图像加密
		****************************************************************************************************/
		/****************************************************************************************************/
		int i = 0;
		/*打乱像素位置*/
		for (int r = 0; r < image.rows; ++r) {
			for (int c = 0; c < image.cols; ++c) {
				//逐个遍历像素

				if (i > sign)
					i = 0;
				int temps = x[i].second;
				//交换操作
				unsigned char  pixel = image.at<TYPE>(r, temps);
				image.at<TYPE>(r, temps) = image.at<TYPE>(r, c);
				image.at<TYPE>(r, c) = pixel;
				i++;
			}
		}
		/*像素混沌*/
		for (int r = 0; r < image.rows; ++r) {
			for (int c = 0; c < image.cols; ++c) {
				if (i > times16bits) {
					i = 1;
				}
				int l = x[i].first*MAX1;
				l = l % BASE16BITS;
				image.at<TYPE>(r, c) = image.at<TYPE>(r, c) ^ l;
				i++;
			}
		}
		dest = image.clone();
	}

	//图像解密
	/*
	
	*/
	
	void decry_1channels(Mat src, Mat& dest, double U, double X0)
	{
		const int MAX1 = 1e5 + 79;
		Mat image = src.clone();

		//标记
		int sign = src.cols - 1;

		vector<pair<double, int >> x;

		//初始状态
		x.push_back({ X0,0 });
		double temp;
		//生成混沌序列
		for (int i = 1; i <= sign; ++i) {
			temp = U * x[i - 1].first*(1 - x[i - 1].first);
			x.push_back({ temp,i });
		}
		//对序列进行排序
		sort(x.begin(), x.end());

		/****************************************************************************************************/
		/****************************************************************************************************
												图像解密
		****************************************************************************************************/
		/****************************************************************************************************/
		int i = 1;
		/*像素值恢复*/
		for (int r = 0; r < image.rows; ++r) {
			for (int c = 0; c < image.cols; ++c) {
				if (i > times16bits) {
					i = 1;
				}
				int l = x[i].first*MAX1;
				l = l % BASE16BITS;
				image.at<TYPE>(r, c) = image.at<TYPE>(r, c) ^ l;
				i++;
			}
		}
		i = sign;
		/*像素位置恢复*/
		for (int r = image.rows - 1; r >= 0; --r) {
			for (int c = image.cols - 1; c >= 0; --c) {
				if (i < 0)
					i = sign;
				int temps = x[i].second;

				unsigned char pixel = image.at<TYPE>(r, temps);
				image.at<TYPE>(r, temps) = image.at<TYPE>(r, c);
				image.at<TYPE>(r, c) = pixel;

				i--;
			}
		}
		dest = image.clone();
	}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!