AES快速实现实验报告
AES的快速实现
【实验目的】
- 通过本次实验,初步接触常用的加密算法软件快速实现方法。
- 鼓励同学们思考与探索新领域,增强编程能力与实践能力。
【实验环境】
Windows10 系统;64 位操作系统,基于 x64 的处理器;
Java version “13-ea” JYM: -Xms1024m -Xmx2048m 编译器:Eclipse;
【实验内容】
AES加解密软件快速实验
1. 算法原理
-
查表法的核心思想是将ByteSub、ShiftRows层和MixColumn层融合为查找表;
-
这三层能融合到一起的最本质的原因是都是只涉及到单个字节的操作;
-
AddRoundKey不能放到表里面的原因是涉及到字节间的操作;
-
解密方法需要对密钥进行MixColumn操作,这样才能运动到查表法;
2. 算法流程
- 表的构造
- 整体的流程
- 源代码
package aes;
import java.util.Scanner;
import gf.Oujilide;
public class AES_FAST {
//查表法快速实现aes
static int[][][] t = new int[4][256][4];
static int[][] mm = new int[4][4];
static int[][] kk = new int[4][4];
//准备工作:生成s盒;生成t表;把m变形;生成轮密钥
public static void pre_init(String m,String k,int flag){
Sbox.create(flag);
t = T_table.en_t(flag);
mm = AES.intmat(m);
kk = KAES.createK(k, 128);
}
public static int[][] inverse(int[][] k){
int[][] re =new int[4][4];
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
re[i][j] = k[j][i];
return re;
}
public static int[] add(int[][] t,int[] key) {
int[] re = new int[4];
for(int i=0;i<4;i++) {
re[i] = Oujilide.add(t[0][i], t[1][i]);
re[i] = Oujilide.add(re[i], t[2][i]);
re[i] = Oujilide.add(re[i], t[3][i]);
re[i] = Oujilide.add(re[i], key[i]);
}
return re;
}
static int[] co = new int[] {0,5,10,15};
static int[] co1 = new int[] {0,13,10,7};
public static int[][] round(int[][] m,int[][] key){
int[][] tmp = new int[4][4];
for(int j=0;j<4;j++) {
int[][] tt = new int[4][4];
for(int k=0;k<4;k++) {
int p = (j*4+co[k])%16;
tt[k] = t[k][m[p%4][p/4]];
}
tmp[j] = add(tt,key[j]);
}
return inverse(tmp);
}
public static int[][] roundni(int[][] m,int[][] key){
int[][] tmp = new int[4][4];
for(int j=0;j<4;j++) {
int[][] tt = new int[4][4];
for(int k=0;k<4;k++) {
int p = (j*4+co1[k])%16;
tt[k] = t[k][m[p%4][p/4]];
}
tmp[j] = add(tt,key[j]);
}
return inverse(tmp);
}
public static void aes_fast(String m,int flag) {
int[][]tmp = new int[4][4];//用来储存每一轮的密钥
long startTime = System.currentTimeMillis(); //获取开始时间
if(flag == 0)
{for(int j=0;j<4;j++) tmp[j] = kk[j];
mm = AES.AddRoundKey(mm,inverse(tmp));
/*开始9轮*/
for(int i=1;i<10;i++) {
for(int j=0;j<4;j++) tmp[j] = kk[i*4+j];
mm = round(mm,tmp);
}
/*最后一轮*/
for(int j=0;j<4;j++) tmp[j] = kk[10*4+j];
mm = AES.ByteSub(mm,flag);
mm = AES.ShiftRow(mm, flag);
mm = AES.AddRoundKey(mm,inverse(tmp));}
else {
for(int j=0;j<4;j++) tmp[j] = kk[10*4+j];
/*第一轮前*/
mm = AES.AddRoundKey(mm,inverse(tmp));
/*开始9轮*/
for(int i=1;i<10;i++) {
for(int j=0;j<4;j++) tmp[j] = kk[10*4-i*4+j];
mm = roundni(mm,inverse(AES.MixColumn(inverse(tmp), 1)));}
/*最后一轮*/
for(int j=0;j<4;j++) tmp[j] = kk[j];
mm = AES.ShiftRow(mm, flag);
mm = AES.ByteSub(mm,flag);
mm = AES.AddRoundKey(mm,inverse(tmp));
}
long endTime = System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间:" + (endTime - startTime) + "ms");
}
public static void main(String args[]) {
System.out.println("依次输入m,k,flag");
Scanner in = new Scanner(System.in);
String m = in.nextLine();
String k = in.nextLine();
int flag = in.nextInt();
pre_init(m,k,flag);
aes_fast(m,flag);
AES.play(mm);
in.close();
}
}
- 代码分析
本实验最大的优化在于将轮函数里面的三步运算直接合成为一步找表,这是一种典型的用空间换时间的办法,就跟之前aes实现的时候s盒是自己产生还是牺牲一定的空间去计算一样。但是如若把t盒计算的时间加在内,初略地分析只有在每一个t盒的使用次数超过t盒的大小也就是256的时候才会有时间上的优化,或者提前使用t盒的构造函数把t盒直接作为常量写在函数里。
3. 样例截图
-
源代码详见 src\aes\AES.java 和 src\aes\AES_FAST.java 测试样例见 readme;
-
测试样例截图为:




数据统计:
| 普通算法 | 快速算法 | |
|---|---|---|
| 1 | 81352336ns | 7397324ns |
| 2 | 79875449ns | 7396879ns |
| 3 | 85798552ns | 7849323ns |
| 平均 | 82342112ns | 7547842ns |
| bit/s | 1.5544*10^4 | 1.69584*10^5 |
4. 实验总结
| 1 | 81352336ns | 7397324ns |
|---|---|---|
| 2 | 79875449ns | 7396879ns |
| 3 | 85798552ns | 7849323ns |
| 平均 | 82342112ns | 7547842ns |
| bit/s | 1.5544*10^4 | 1.69584*10^5 |
4. 实验总结
通过本次实验,首先我复习了AES算法的原理,同时学会了优化算法的一种思维—寻找会进行重复运算的地方,将这个重复运算的东西存储到一个表里,利用空间来换取时间。另外,通过本实验可以看出,算法的性能大概提高了10倍左右,这是一个很惊人的数字,由此可见空间换取时间的策略是非常成功的。另外,在我进行了测试之后发现,如果把t表的生成时间计算在内,时间上并不能得到优化,这是因为用到t表的次数小于256,但是当加密的过程变多之后特别是打到千位数量级后,第二种方法的优势便明显的体现了出来。

1153

被折叠的 条评论
为什么被折叠?



