SM4加密算法(JAVA语言实现)

1、SM4算法简介

中国国家密码管理局于2006年1月6日发布第7号公告,将我国无线局域网产品的加密算法确定为SM4算法(原SMS4)。这是国内官方公布的第一个商用密码算法。

SM4分组密码算法是一个迭代分钟密码算法,由加解密算法和密钥扩展算法组成,SM4分组密码算法采用非平衡Feistel结构,明文分组长度为128bit,密钥长度为128bit。加密算法与密钥扩展算法都采用32轮非线性迭代结构。解密算法与加密算法的结构相同,只是轮密钥的使用顺序相反,解密轮密钥是加密轮密钥的逆序。

加密首先要生成一套加密密钥,从用户处获得一个128bit的初始密钥并将其分为4组,之后对应的与系统参数FK进行异或运算,之后将产生的结果进行32轮迭代(包含:与固定参数CKi的异或运算、S盒替换、循环移位、移位之后的异或运算)最后生成32个轮子密钥,每个轮子密钥32bit,分别供每一轮运算中使用。

SM4算法的S盒替换与AES算法中的S盒替换类似:输入的前4位为行号,后4位为列号,行列交叉点处的数值即为替换结果。

SM4算法的加密流程为首先从用户处获得128bit的明文,之后将明文分为4组,每组32bit,之后将其进过轮函数F变换,一共进行32轮次,最后再经过反序变换之后的到加密后的结果。

SM4中的合成置换T是一个可逆置换,由非线性变换 和线性变换L复合而成。其中是由4个并行的S盒代替构成。为国定的8bit输入和8bit输出的代替。并且非线性变换是线性变换L的输入。

在SM4算法中S盒是固定不变的,而且系统参数CKi的取值也是不变的,系统参数一共有32个。

SM4的解密过程与加密过程结构完全相同,不同的仅仅是轮秘钥的使用顺序。加密轮密钥的使用顺序是,

而解密时密钥的使用顺序为加密时候的反序:

 

2、密码算法程序各模块详细设计

2.1  核心模块主要实现算法的流程

SM4加密算法(JAVA语言实现)_第1张图片

 图1  SM4加密算法流程示意图

SM4加密算法(JAVA语言实现)_第2张图片

图2  SM4密钥扩展算法流程图

3、核心模块的函数说明和实现方式

3.1 轮密钥扩展算法核心代码

private void SMS4KeyExt(byte[] Key, int[] rk, int CryptFlag) {
		int r, mid;
		int[] x = new int[4];     
		int[] tmp = new int[4];    
		for (int i = 0; i < 4; i++) {
//使用下面的语句,实现对初始秘钥的分组(分为4组)
			tmp[0] = Key[0 + 4 * i] & 0xFF;

			tmp[1] = Key[1 + 4 * i] & 0xff;

			tmp[2] = Key[2 + 4 * i] & 0xff;

			tmp[3] = Key[3 + 4 * i] & 0xff;
			
x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3];
x[i]=Key[0+4*i]<<24|Key[1+4*i]<<16|Key[2+4*i]<<8|Key[3+4*i];
}
/*******************************
 * 系统参数FK的取值(取值固定)
 *******************************/
		x[0] ^= 0xa3b1bac6;	//Key (0)与FK(0)异或运算之后的结果
		x[1] ^= 0x56aa3350;	//Key (1)与FK(1)异或运算之后的结果
		x[2] ^= 0x677d9197;	//Key (2)与FK(2)异或运算之后的结果
		x[3] ^= 0xb27022dc;	//Key (3)与FK(3)异或运算之后的结果
		for (r = 0; r < 32; r += 4) {
			//实现K(r+1)、K(r+2)、K(r+3)与CK(i)的异或运算操作
			mid = x[1] ^ x[2] ^ x[3] ^ CK[r + 0];  
			//调用函数ByteSub实现非线性变换
			mid = ByteSub(mid);	
			// 将变换之后的结果与自身的循环左移13、23位做异或运算
			rk[r + 0] = x[0] ^= L2(mid); // rk0=K4  
			
			//下面的操作与以上雷同
			mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1];
			mid = ByteSub(mid);
			rk[r + 1] = x[1] ^= L2(mid); // rk1=K5
			
			mid = x[3] ^ x[0] ^ x[1] ^ CK[r + 2];
			mid = ByteSub(mid);
			rk[r + 2] = x[2] ^= L2(mid); // rk2=K6
			
			
			mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3];
			mid = ByteSub(mid);
			rk[r + 3] = x[3] ^= L2(mid); // rk3=K7
		}
//CryptFlag为1时进行加密操作,CryptFlag为0时进行解密操作
// 解密时轮密钥使用顺序:rk31,rk30,...,rk0,下面主要实现对上面生成的轮子秘钥的逆序作用
		if (CryptFlag == DECRYPT) {
			for (r = 0; r < 16; r++) {
				mid = rk[r];

				rk[r] = rk[31 - r];

				rk[31 - r] = mid;
			}
		}
	}

SM4的轮密钥扩展算法严格的按照SM4轮密钥扩展算法流程图来进行操作和变换演示。

3.2 SM4加密算法核心代码

/**********************************
* 功能说明:SM4加密算法实现
* 参数说明:Input      输入的明文
* 		 Output     待输出的密文
* 		 rk         轮密钥
 ***********************************/
void SMS4Crypt(byte[] Input, byte[] Output, int[] rk) {
	int r, mid;
	int[] x = new int[4];
	int[] tmp = new int[4];
	for (int i = 0; i < 4; i++) {
		tmp[0] = Input[0 + 4 * i] & 0xff;
		tmp[1] = Input[1 + 4 * i] & 0xff;
		tmp[2] = Input[2 + 4 * i] & 0xff;
		tmp[3] = Input[3 + 4 * i] & 0xff;
		x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3];
x[i]=(Input[0+4*i]<<24|Input[1+4*i]<<16|Input[2+4*i]<<8|Input[3+4*i]);}
/**************************************
 * 进行32轮的加密变换操作
 **************************************/
for (r = 0; r < 32; r += 4) {
	mid = x[1] ^ x[2] ^ x[3] ^ rk[r + 0];
//X(r+1)、X(r+2)、X(r+3)与轮密钥进行异或运算
	mid = ByteSub(mid);					//S盒置换
	x[0] = x[0] ^ L1(mid); // x4		//线性变换L
			
//下面的内容操作类似
	mid = x[2] ^ x[3] ^ x[0] ^ rk[r + 1];
	mid = ByteSub(mid);
	x[1] = x[1] ^ L1(mid); // x5

	mid = x[3] ^ x[0] ^ x[1] ^ rk[r + 2];
	mid = ByteSub(mid);
	x[2] = x[2] ^ L1(mid); // x6

	mid = x[0] ^ x[1] ^ x[2] ^ rk[r + 3];
	mid = ByteSub(mid);
	x[3] = x[3] ^ L1(mid); // x7
}
// Reverse
/*******************
 * 反序变换
 *******************/
for (int j = 0; j < 16; j += 4) {
	Output[j    ] = (byte) (x[3 - j / 4] >>> 24 & 0xFF);
	Output[j + 1] = (byte) (x[3 - j / 4] >>> 16 & 0xFF);
	Output[j + 2] = (byte) (x[3 - j / 4] >>> 8 & 0xFF);
	Output[j + 3] = (byte) (x[3 - j / 4] & 0xFF);
		}
	}

3.3 SM4解密算法核心代码

SM4的解密算法与加密算法类似,唯一不同之处就是使用的轮子密钥的顺序不同,SM4解密使用的轮子密钥与加密使用的轮子密钥正好顺序相反。在编码过程之中通过一个标志性数据——CryptFlag来确定是产生加密轮子密钥还是解密轮子密钥,当CryptFlag为1时进行加密操作,CryptFlag为0时进行解密操作。

4、程序测试

4.1 程序测试过程

在此次实验过程中为了简洁实现对编码的验证,采用直接在程序中加入代加密明文进行加密的方式,中间自动转换为16进制数据类型:

在控制台显示待加密明文与加密密钥以及加密轮密钥:

SM4加密算法(JAVA语言实现)_第3张图片

显示加密过程与加密结果:

SM4加密算法(JAVA语言实现)_第4张图片

将加密后的密文用于解密,验证程序的正确性:

解密轮密钥:

SM4加密算法(JAVA语言实现)_第5张图片

解密结果:

SM4加密算法(JAVA语言实现)_第6张图片

经过验证核实,表示正确无误,程序正确!

之后显示多分组加密结果的显示:

SM4加密算法(JAVA语言实现)_第7张图片

5、参考文献

[1] 张仕斌,万武南,张金全,孙宣东 《应用密码学》  西安电子科技大学出版社,2009.12

[2] 张健等 《密码学原理及应用技术》 清华大学出版,2011.08

[3] 国内一些技术博客

[4] 中国知网上的一些论文          

[5] java帮助文档

 

源代码下载:https://download.csdn.net/download/fly_hps/10724893

你可能感兴趣的:(【密码学】,———密码学)