Arnold变换

本篇是迈入图像加密后所选择研究的第一个加密方法,选择这种方法的缘由是基于密码的发展过程并结合图像的存储形式所能想到最直接的便是进行像素置换,而这种方法如果单独使用的话不符合现代密码学中的Kerckhoffs准则,即算法不能公开,属于古典密码范畴;由于离散数字图像是有限点集,这种反复变换的结果在开始阶段时,像素点的位置变化会出现相当程度的混乱,但由于动力系统固有的特性,在迭代进行到一定步数时会恢复到原来的位置,即变换具有庞加莱回复性,这样,只要知道加密矩阵,按照密文空间的任意一个状态来进行迭代,都会在有限步内恢复出明文(即要传输的原图像),这种攻击对于现代的计算机来说其计算时间是很短的,因而其保密性不高。
参考博客为:
1、Arnold变换详解
2、二值图像加密之Arnold变换加密
非常感谢

概述

其实这种方法本质上是将图像进行置乱,打乱其像素排列,这种变换具有周期性,即对图像连续变化后最终可以复原,变换的周期和图像尺寸、参数等相关,分为狭义变换和广义变换

第一种研究——图像为正方形,边长为N个像素

狭义变换

公式

狭义变换

原理

先做X方向的错切变换,再做y轴方向的错切变换,最后的模运算相当于切割回填操作
这里介绍一下图像处理里的错切变换的知识:

错切变换

图像错切的原理就是保持图像上各点的某一坐标不变,将另一个坐标进行线性变化,有X方向与Y方向的错切变换。

  • X方向:
    X方向错切变换
    也就是:
    x’=x-y*tana
    y’=y
    由上可以看出y坐标没变
  • y方向:
    y方向错切变换
    也就是:
    x’=x
    y=y-x*tana
    由上可以看出x坐标没变

所以狭义Arnold变换如图所示,图片选自参考博客,再次感谢:
图示变换过程
由上图我们可以看出,(b)做了X侧切,其实就是y坐标没动,x坐标变动了一个y单位,而(c)在(b)的基础上做了Y侧切,其实就是x坐标没动,y坐标先翻倍后变动了一个x单位
最后取模就是为了不改变图像大小,将空余位置进行了回填
那还有没有其他方式的变化呢,当然有,这只是一种狭义的变换,只不过这种变换刚好会让像素变到一个新的位置,而且没有两个像素变换后的位置相同,这就不会导致图像信息的丢失,因此错切的方式是有要求的,见广义Arnold变换

变换周期

Arnold的变换周期可通过计算机来计算,与N有关,有关学者研究发现,对于给定的正整数N,Arnold的周期m,当m>2时,满足:m<=N2/2,还有一种确定方法就是
周期确定
使上式成立的最小的n即为周期,例如N=32时,周期M=24,且经过6次迭代变换后置乱效果最好,那么还需要迭代18次才能恢复原样

代码实现与效果展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static void narrowArnold(File ImageFile, String outImageFilePath, int times) throws IOException {
BufferedImage image=ImageIO.read(ImageFile);
int N=image.getHeight();
if(N!=image.getWidth()) {
System.out.println("请输入一张长宽相等的图片");
}else {
int [][]imageArray=new int[N][N];
for(int x=0;x<N;x++) {
for(int y=0;y<N;y++) {
imageArray[x][y]=image.getRGB(x, y);
}
}
int [][]outArray=new int[N][N];
BufferedImage outImage=new BufferedImage(N,N,image.getType());
for(int i=0;i<times;i++) {
for(int x=0;x<N;x++) {
for(int y=0;y<N;y++) {
int newX=(x+y)%N;
int newY=(x+2*y)%N;
outArray[newX][newY]=imageArray[x][y];
outImage.setRGB(newX, newY, outArray[newX][newY]);
}
}
imageArray=outArray;
outArray=new int[N][N];
String path=outImageFilePath+Integer.toString(i)+".png";
File outFile=new File(path);
ImageIO.write(outImage, "png",outFile );
}
}
}

选用64X64的图片进行变换,经研究发现其周期为48,结果如下图所示:
狭义变换效果
由图我们可以看出,在经过48次变换后又恢复到原图
但是周期越长,恢复时间也越长,而Arnold变换具有逆变换,通过逆变换可以方便地进行图像恢复。

逆变换

公式

逆变换公式

代码实现与效果展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static void narrowResArnold(File targetFile) throws IOException{
BufferedImage image=ImageIO.read(targetFile);
int N=image.getHeight();
int [][]imageArray=new int[N][N];
for(int x=0;x<N;x++) {
for(int y=0;y<N;y++) {
imageArray[x][y]=image.getRGB(x, y);
}
}
BufferedImage outImage=new BufferedImage(N,N,image.getType());
int [][]outArray=new int[N][N];
for(int x=0;x<N;x++) {
for(int y=0;y<N;y++) {
int oldX=(2*x-y)%N;
if(oldX<0) {
oldX=(oldX+N)%N;
}
int oldY=(-1*x+y)%N;
if(oldY<0) {
oldY=(oldY+N)%N;
}
outArray[oldX][oldY]=imageArray[x][y];
outImage.setRGB(oldX, oldY, outArray[oldX][oldY]);
}
}
File outFile=new File("E:\\大学课程\\大三下学期\\创新设计\\Arnold\\狭义逆变换.png");
ImageIO.write(outImage,"png",outFile);
}

我们在这里选用的是javaTest47这张图片,经过逆变换后:
狭义逆变换结果 原结果
发现两者是相同的,证明是可以逆变换的

广义变换

在前面我们知道,要想实现Arnold变换,错切的方式是有要求的,而这个要求就是广义Arnlod变换所表示的

公式

广义Arnold变换公式

代码实现与效果展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public static void broadArnold(File ImageFile, String outImageFilePath, int times,int a,int b) throws IOException {
BufferedImage image=ImageIO.read(ImageFile);
int N=image.getHeight();
if(N!=image.getWidth()) {
System.out.println("请输入一张长宽相等的图片");
}else {
int [][]imageArray=new int[N][N];
for(int x=0;x<N;x++) {
for(int y=0;y<N;y++) {
imageArray[x][y]=image.getRGB(x, y);
}
}
int [][]outArray=new int[N][N];
BufferedImage outImage=new BufferedImage(N,N,image.getType());
for(int i=0;i<times;i++) {
for(int x=0;x<N;x++) {
for(int y=0;y<N;y++) {
int newX=(x+a*y)%N;
int newY=(b*x+(a*b+1)*y)%N;
if(newX<0) {
newX=(newX+N)%N;
}
if(newY<0) {
newY=(newY+N)%N;
}
outArray[newX][newY]=imageArray[x][y];
outImage.setRGB(newX, newY, outArray[newX][newY]);
}
}
imageArray=outArray;
outArray=new int[N][N];
String path=outImageFilePath+Integer.toString(i)+".png";
File outFile=new File(path);
ImageIO.write(outImage, "png",outFile );
}
}
}

我们选用的a=3,b=2,结果如下所示:
广义变换结果
我们发现此时周期变小,变为了16

逆变换

公式

广义逆变换公式

代码实现与效果展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static void broadResArnold(File targetFile,int a,int b) throws IOException{
BufferedImage image=ImageIO.read(targetFile);
int N=image.getHeight();
int [][]imageArray=new int[N][N];
for(int x=0;x<N;x++) {
for(int y=0;y<N;y++) {
imageArray[x][y]=image.getRGB(x, y);
}
}
BufferedImage outImage=new BufferedImage(N,N,image.getType());
int [][]outArray=new int[N][N];
for(int x=0;x<N;x++) {
for(int y=0;y<N;y++) {
int oldX=((a*b+1)*x-a*y)%N;
if(oldX<0) {
oldX=(oldX+N)%N;
}
int oldY=(-1*b*x+y)%N;
if(oldY<0) {
oldY=(oldY+N)%N;
}
outArray[oldX][oldY]=imageArray[x][y];
outImage.setRGB(oldX, oldY, outArray[oldX][oldY]);
}
}
File outFile=new File("E:\\大学课程\\大三下学期\\创新设计\\Arnold\\广义逆变换.png");
ImageIO.write(outImage,"png",outFile);
}

我们选braodTest15这个图像进行逆变换,得到如下结果:
广义逆变换结果
广义逆变换原结果
我们发现结果是相同的,逆变换是有效的

应用

数字水印

数字水印技术接下来会进行学习,数字水印在我简单看来就是将一些隐秘或验证信息与原图像结合,但是如果攻击者破解了加密算法,那么信息也会被提取,所以可以先将加密后的信息采用Arnold变换进行置乱

图像置乱

这是Arnold变换所直观能体现出来的,图像置乱后得到杂乱无序的图像,嵌入其他图像中不会引起其他图像显著改变,这是因为置乱后像素分布均匀,相当于有个平均增强灰度的效果

图像置乱效果的评价

1、像素移动的距离;
2、像素分散的均匀度;
3、相对于原始图像的差别;
4、图像视觉感知效果

加密

像广义Arnold变换中a和b可以作为密钥,在不知道a和b的情况下是难以恢复原图的,并且难以发现统计规律
还可以将图像进行切割,对每个部分采用不同的a和b,分别加密

抗破坏

如果敌方截获了信息,但是又不能反置乱,此时若对图像进行破坏,对逆变换后的结果影响也不会太大
我们来做个实验,利用python随机将broadTest3(64X64)中的100个像素置为0

1
2
3
4
5
while count<=1000:
x=random.randint(0,64)%64
y=random.randint(0,64)%64
img.putpixel((x,y),0)
count+=1

然后对结果进行恢复,结果如下所示:
破坏恢复结果
我们发现最后恢复的大体轮廓是清晰的,只是有了一些噪音点,这些噪音点可以经过处理消掉

拓展思考

像图像这种以二维形式存储的数据可以通过Arnold变换来置乱加密,那么其他以二维形式存储的数据或者刻意采用二维形式存储也可以应用Arnold变换,这是值得关注的点。

不足之处

容易受到唯密文迭代攻击,可以穷举a和b来进行攻击,所以从根本上来说这种算法是不能公开的,因为一旦让敌方知晓了采用的是Arnold变换,耗费资源穷举也是可以(由于离散数字图像是有限点集,这种反复变换的结果在开始阶段时,像素点的位置变化会出现相当程度的混乱,但由于动力系统固有的特性,在迭代进行到一定步数时会恢复到原来的位置,即变换具有庞加莱回复性,这样,只要知道加密矩阵,按照密文空间的任意一个状态来进行迭代,都会在有限步内恢复出明文(即要传输的原图像),这种攻击对于现代的计算机来说其计算时间是很短的,因而其保密性不高),所以算法不能公开,所以不符合现代密码学中的Kerckhoffs准则,属于古典密码的范畴,所以应该思考其是否可以与其他方法相结合