(Java)AES加密流程 矩阵运算 演示

目录

一、实验题目

二、实验要求

三、算法描述

四、算法设计

五、运行结果

六、具体代码


本代码实现了  https://coolshell.cn/wp-content/uploads/2010/10/rijndael_ingles2004.swf   链接中 swf 文件中 的AES流程演示。

SWF文件可以用播放器或者浏览器打开观看具体流程。这个文件很清晰的展示了流程!

说明:本代码并没有实现字符串加密,也没有实现解密相关,仅仅将AES加密流程矩阵运算以代码展示出。

一、实验题目

AES加密与解密

二、实验要求

1、在深入理解 AES 加密 /解密算法理论的基础上,设计一个 AES 加密 解密软件系统;

2、完成一个明文分组的加解密,明文和密钥是十六进制,长度都为 128 比特( 16 个16 进制数),输入明文和密钥,输出密文,进行加密后,能够进行正确的解密;

3、程序运行时,要求输出每一轮使用的密钥,以及每一轮加密或解密之后的 16 进制表示的值;

三、算法描述

AES的加密公式为C = E(K,P),在加密函数E中,会执行一个轮函数,并且执行10次这个轮函数,这个轮函数的前9次执行的操作是一样的,只有第10次有所不同。也就是说,一个明文分组会被加密10轮。AES的核心就是实现一轮中的所有操作。

AES算法主要可以分为秘钥扩展、字节替换、行移位、列混合和轮秘钥加这5个步骤。

图1:AES的十轮原理图
  1. 秘钥扩展(KeyExpansions):AES128中原始秘钥key为16字节,运算中需要11个矩阵大小的秘钥,每一列所包含的32位记为一个uint32_t W,所以秘钥扩展一共需要生产44个列W,即uint32_t W[44]。

 

图2:密钥扩展示意图
  1. 字节替换(SubBytes):一个非线性的替换步骤,根据查S-box表把一个字节替换为另一个字节。

图3:字节代换示意图

3、行移位(ShiftRows):将数据矩阵的每一行循环移位一定长度。自上到下分别循环左移0,1,2,3位

图4:行移位示意图

4、列混合(MixColumns):将数据矩阵乘以一个固定的矩阵,增加混淆程度。

图5:列混合示意图

5、轮秘钥加(AddRoundKey):将数据矩阵与秘钥矩阵进行异或操作。

图6:密钥加示意图

四、算法设计

我具体实现的是固定输入下的AES演示,输入为一个4x4的十六进制矩阵,输出为每轮操作后的矩阵样式,及每轮的轮密钥。

密钥生成(KeyExpansions):先初始化Rcon[]数组和初始密钥,存储在44x4的Roundkey[]数组中,生成完成密钥之后,为方便操作,再将需要用到的密钥存储在新数组int[][] Roundkeynew中 。

在加密过程中,需要 Nr+1 个轮密钥,需要构造 4(Nr+1 )个 32 位字。首先将输入的 4 个字节直接复制到扩展密钥数组的前 4 个字中, 得到 W[0],W[1],W[2],W[3]; 然后每次用 4 个字填充扩展密钥数余下的部分。

具体生成步骤:移位-> S-Box变换 ->异或

//Roundkey[i-1][j] 先移位,再s-box变换

int s = Roundkey[i-1][(j+1)%4];  //移位

int k = sBox[s/16][s-s/16*16];   //s-box变换

Roundkey[i][j] = Roundkey[i-4][j]^Rcon[i/4-1][j]^k;

字节替换(SubBytes):直接创建有一个二维int数组sBox存储代换字节,代换时只需要将十六分位和个位直接变成数组的行列坐标,找出对应的十六进制数即为所求。

行移位(ShiftRows):第一行循环左移0位,第二行循环左移1位,第三行循环左移2位,第四行循环左移3位。

列混合(MixColumns):列混合其实就是对一个状态的每一列去乘一个矩阵,其中乘法是在有限域GF(2^8)内进行的,不可约多项式为x^8+x^4+x^2+x+1。这里重点是有限域GF(2^8)上的乘法。采用的算法的原理如下:

1、  GF(2^8)中任何数乘0x01都不变

2、  GF(2^8)中计算乘0x02,可以分两种情况考虑:

(1)、原数值小于(1000 0000)2,即0x80的时候,乘2后第8个比特不会溢出,那么结果就是原数值左移一位;

(2)、原数值大于(1000 0000)2,即0x80的时候,乘2后第8个比特会溢出,结果需要减去一个不可约多项式(x8+x4+x2+x+1),注意到GF(2^8)中的减法就是加法,那么结果就为原数值左移一位后(乘2)再与(0001 1011)2即0x1b进行异或(这里x8已经减掉了,只需要再减去x4+x2+x+1)。

if(content[p][j]>127)  s=s^(content[p][j]*2-256)^0x1B;

if(content[p][j]<128)  s=s^(content[p][j]*2);

轮秘钥加(AddRoundKey):就是简单地将数据矩阵与秘钥矩阵进行逐个异或操作。

重复十轮(第十轮无列混合)之后ToHexString输出

五、运行结果

由于结果太长故将截图分条显示

六、具体代码

public class Rijdael {
	

	static int sBox[][] = {
			{0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76},
			{0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0},
			{0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15},
			{0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75},
			
			{0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84},
			{0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf},
			{0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8},
			{0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2},
			
			{0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73},
			{0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb},
			{0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79},
			{0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08},
			
			{0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a},
			{0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e},
			{0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf},
			{0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16},			
	};
	
	
	public static void main(String[] args) {
		//秘钥装填
		int[][] Roundkey = new int[44][4];
		
				Roundkey[0][0]=0x2b;Roundkey[1][0]=0x28;Roundkey[2][0]=0xab;Roundkey[3][0]=0x09;
				Roundkey[0][1]=0x7e;Roundkey[1][1]=0xae;Roundkey[2][1]=0xf7;Roundkey[3][1]=0xcf;
				Roundkey[0][2]=0x15;Roundkey[1][2]=0xd2;Roundkey[2][2]=0x15;Roundkey[3][2]=0x4f;
				Roundkey[0][3]=0x16;Roundkey[1][3]=0xa6;Roundkey[2][3]=0x88;Roundkey[3][3]=0x3c;
	
				
		int[][] Rcon = {
						{0x01,0x00,0x00,0x00},
						{0x02,0x00,0x00,0x00},
						{0x04,0x00,0x00,0x00},
						{0x08,0x00,0x00,0x00},
						
						{0x10,0x00,0x00,0x00},
						{0x20,0x00,0x00,0x00},
						{0x40,0x00,0x00,0x00},
						{0x80,0x00,0x00,0x00},
						
						{0x1b,0x00,0x00,0x00},
						{0x36,0x00,0x00,0x00}
				};
		//密钥生成
		for(int i=4;i<44;i++) {
			for(int j=0;j<4;j++) {
				if(i%4==0) {
					//Roundkey[i-1][j] 先移位,再s-box变换
					int s = Roundkey[i-1][(j+1)%4];  //移位
					int k = sBox[s/16][s-s/16*16];   //s-box变换
					Roundkey[i][j] = Roundkey[i-4][j]^Rcon[i/4-1][j]^k;
				}
				if(i%4!=0) {
					Roundkey[i][j] = Roundkey[i-4][j]^Roundkey[i-1][j];
				}
			}			
		}
		int[][] Roundkeynew = new int[4][40];
        //新数组
		for(int i=0;i<4;i++) {
			for(int j=0;j<40;j++) {
				Roundkeynew[i][j]=Roundkey[j+4][i];
			}
		}
				
		//初始信息
		int [][] content = {
				{0x19,0xa0,0x9a,0xe9},
				{0x3d,0xf4,0xc6,0xf8},
				{0xe3,0xe2,0x8d,0x48},
				{0xbe,0x2b,0x2a,0x08}
		};
		
		int [][] contentnew ={
				{0,0,0,0},
				{0,0,0,0},
				{0,0,0,0},
				{0,0,0,0}
		};
		
		//10轮变换    第十轮没得列混淆
		for(int n=0;n<10;n++) {
			//1。字节代换
			for(int i=0;i<4;i++) {
				for(int j=0;j<4;j++) {
					content[i][j] = sBox[content[i][j]/16][content[i][j]-content[i][j]/16*16];
				}
			}
			System.out.println(n+1+"轮字节代换后:");
			for(int i=0;i<4;i++) {
				for(int j=0;j<4;j++) {
					System.out.print(Integer.toHexString(content[i][j])+" ");
				}
				System.out.println();
			}
			//2。行移位 左移
			int t;
			t=content[1][0]; content[1][0]=content[1][1]; 
			content[1][1]=content[1][2]; content[1][2]=content[1][3]; content[1][3]=t;
			
			t=content[2][3]; content[2][3]=content[2][1]; content[2][1]=t;
			t=content[2][2]; content[2][2]=content[2][0]; content[2][0]=t;
			
			t=content[3][3]; content[3][3]=content[3][2]; content[3][2]=content[3][1];
			content[3][1]=content[3][0]; content[3][0]=t;
			System.out.println(n+1+"轮行移位后:");
			for(int i=0;i<4;i++) {
				for(int j=0;j<4;j++) {
					System.out.print(Integer.toHexString(content[i][j])+" ");
				}
				System.out.println();
			}

			//3。列混淆
			
			int [][] mix = {
					{2,3,1,1},
					{1,2,3,1},
					{1,1,2,3},
					{3,1,1,2}
			};
			
			
			if(n!=9) {
				
				for(int j=0;j<4;j++) {//content的列
					for(int i=0;i<4;i++) {//mix的行
						int s=0;    
						for(int p=0;p<4;p++) {//mix的列
							//content[p][j]*mix[i][j]  (4个值xor之后是content[i][j])
							if(mix[i][p]==1) s=s^content[p][j];
							if(mix[i][p]==2) {
								if(content[p][j]>127)  s=s^(content[p][j]*2-256)^0x1B;
								if(content[p][j]<128)  s=s^(content[p][j]*2);								
							}
							if(mix[i][p]==3) {
								if(content[p][j]>127)  s=s^(content[p][j]*2-256)^0x1B^content[p][j];
							
								if(content[p][j]<128)  s=s^(content[p][j]*2)^content[p][j];
							}
						}
						contentnew[i][j]=s;
					}
				}
			}
			if(n==9) {
				for(int i=0;i<4;i++) {
					for(int j=0;j<4;j++) {
						contentnew[i][j]=content[i][j];
					}
				}
			}
			//测试
			System.out.println(n+1+"轮列混淆后:");
			for(int i=0;i<4;i++) {
				for(int j=0;j<4;j++) {
					System.out.print(Integer.toHexString(contentnew[i][j])+" ");
				}
				System.out.println();
			}

			//4.密钥加
			for(int i=0;i<4;i++) {
				for(int j=0;j<4;j++) {
					contentnew[i][j]=contentnew[i][j]^Roundkeynew[i][4*n+j];
				}
			}
			
			//测试
			System.out.println(n+1+"轮密钥加后:");
			for(int i=0;i<4;i++) {
				for(int j=0;j<4;j++) {
					System.out.print(Integer.toHexString(contentnew[i][j])+" ");
				}
				System.out.println();
			}
			
			//更新content值
			for(int i=0;i<4;i++) {
				for(int j=0;j<4;j++) {
					content[i][j]=contentnew[i][j];
				}
			}
			
		}
		//10论之后
		for(int i=0;i<4;i++) {
			for(int j=0;j<4;j++) {
				System.out.print(Integer.toHexString(contentnew[i][j])+"   \t");
			}
			System.out.println();
		}
		
	}
}

还有个写的巨好的AES加解密解析!!!不过只有看完了我的博客才能看到这个哈哈哈哈哈……

https://zhuanlan.zhihu.com/p/78913397  强推!!!

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值