目录
引言
最近使用到了AES算法实现了加解密操作。通过查看源码得知使用的是javax.crypto中的Cipher类,于是想研究下AES算法底层是如何实现的。
Cipher工具类简介
这里我直接贴出源码中关于Cipher的说明:
此类提供用于加密和解密的密码密码功能。 它构成了 Java 加密扩展 (JCE) 框架的核心。
/**
Java 平台的每个实现都需要支持以下带括号的密钥大小的标准Cipher转换:
AES/CBC/NoPadding (128)
AES/CBC/PKCS5Padding (128)
AES/ECB/NoPadding (128)
AES/ECB/PKCS5Padding (128)
DES/CBC/NoPadding (56)
DES/CBC/PKCS5Padding (56)
DES/ECB/NoPadding (56)
DES/ECB/PKCS5Padding (56)
DESede/CBC/NoPadding (168)
DESede/CBC/PKCS5Padding (168)
DESede/ECB/NoPadding (168)
DESede/ECB/PKCS5Padding (168)
RSA/ECB/PKCS1Padding (1024, 2048)
RSA/ECB/OAEPWithSHA-1AndMGF1Padding (1024, 2048)
RSA/ECB/OAEPWithSHA-256AndMGF1Padding (1024, 2048)
*/
package javax.crypto;
public class Cipher {
...
//细节不说明了
}
我们可以看出Cipher类已经封装好了很多加解密算法,除了对称加密算法中的AES、DES,还有非对称加密算法RSA。
- DES(Data Encryption Standard):数据加密标准,速度较快,适用于加密大量数据的场合;
- AES(Advanced Encryption Standard):高级加密标准,是下一代的加密算法标准,速度快,安全级别高。
- RSA(Ron Rivest、Adi Shamir、Leonard Adleman): 由RSA公司发明,是一个支持变长密钥的公共密钥算法,需要加密的文件块的长度也是可变的、例如github中的我们本地与远程仓库的认证就需要rsa算法认证;
AES对称加密算法demo
关于AES算法的详细底层原理可以看AES 加密算法的原理详解,我这里从方法级别进行相关解说。
AES算法流程图
AES为分组加解密算法,也就是把明文分成一组一组的,每组长度相等(末组需要补齐长度)。每次加密一组数据,直到加密整个明文。在AES标准规范中,分组长度只能是128位,也就是说,每个分组为16个字节(每个字节8位)。密钥的长度可以使用128位(16字节)、192位(24字节)或256位(32字节)。密钥的长度不同,推荐加密轮数也不同,比如16字节的秘钥就需要加密10轮。
字节代换/逆字节代换
将明文的每个组(构成一个状态矩阵)的每个元素需要映射为一个新的字节,根据高位作为行号,低位作为列号,进行映射。加密中有加密映射表,解密也即有解密映射表。
/**
* 字节代换:正映射
*/
private static final int[] S1=
{ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, /*0*/
0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, /*1*/
0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, /*2*/
0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, /*3*/
0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, /*4*/
0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, /*5*/
0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, /*6*/
0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, /*7*/
0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, /*8*/
0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, /*9*/
0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, /*a*/
0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, /*b*/
0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, /*c*/
0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, /*d*/
0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, /*e*/
0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16 /*f*/
};
/**
* 字节代换:逆映射
*/
private static final int[] S2=
{ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb, /*0*/
0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb, /*1*/
0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e, /*2*/
0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25, /*3*/
0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92, /*4*/
0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84, /*5*/
0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06, /*6*/
0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b, /*7*/
0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73, /*8*/
0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e, /*9*/
0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b, /*a*/
0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4, /*b*/
0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f, /*c*/
0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef, /*d*/
0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61, /*e*/
0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d /*f*/
};
行移位/行移位逆变换
行移位即将矩阵中的元素根据行号进行不同单位的移位操作,这边是左移位。
/**
* 行移位
* @param array 操作的4x4矩阵
* @param encode 加密或解密的标志
*/
private void shiftRows(int[][] array,boolean encode) {
for(int i=0;i<4;i++){
for(int j=0;j<i;j++){ //第i行移动i次
if(encode) { //加密时用 行移位
int temp = array[i][0];
array[i][0] = array[i][1];
array[i][1] = array[i][2];
array[i][2] = array[i][3];
array[i][3] = temp;
}else{ //解密时用 逆行移位
int temp = array[i][3];
array[i][3] = array[i][2];
array[i][2] = array[i][1];
array[i][1] = array[i][0];
array[i][0] = temp;
}
}
}
}
列混合/逆列混合
列混合是通过矩阵相乘实现的,需要有一个常数矩阵,逆列混合也需要有对应的逆常数矩阵。
/**
* AES乘法
* @param a 操作矩阵中的数
* @param le 常数矩阵中的数
* @return
*/
private int aesMultiple(int a,int le){
int thr=le&0x8;
int sec=le&0x4;
int fir=le&0x2;
int firMod=le%2;
int result=0;
if(thr>0){
int b=a;
for(int i=1;i<=3;++i){
b=b<<1;
if(b>=256){
b=b^0x11b;
}
}
b=b%256;
result=result^b;
}
if(sec>0){
int b=a;
for(int i=1;i<=2;i++){
b=b<<1;
if(b>=256){
b=b^0x11b;
}
}
b=b%256;
result=result^b;
}
if(fir>0){
int b=a<<1;
if(b>=256){
b=b^0x11b;
}
b=b%256;
result=result^b;
}
if(firMod>0){
result=result^a;
}
return result;
}
/**
* AES乘法计算
* @param array 操作的4x4矩阵
* @param encode 加密或解密的标志
*/
private void mixColumns(int[][] array,boolean encode) {
for(int i=0;i<4;i++){
int temp0=array[0][i];
int temp1=array[1][i];
int temp2=array[2][i];
int temp3=array[3][i];
if(encode){
/** 常数矩阵
{ {2, 3, 1, 1},
{1, 2, 3, 1},
{1, 1, 2, 3},
{3, 1, 1, 2 }}
*/
array[0][i]=aesMultiple(temp0,2)^aesMultiple(temp1,3)^temp2^temp3;
array[1][i]=temp0^aesMultiple(temp1,2)^aesMultiple(temp2,3)^temp3;
array[2][i]=temp0^temp1^aesMultiple(temp2,2)^aesMultiple(temp3,3);
array[3][i]=aesMultiple(temp0,3)^temp1^temp2^aesMultiple(temp3,2);
}else{
/** 常数矩阵
{ {0E, 0B, 0D, 09},
{09, 0E, 0B, 0D},
{0D, 09, 0E, 0B},
{0B, 0D, 09, 0E }}
*/
array[0][i]=aesMultiple(temp0,14)^aesMultiple(temp1,11)^aesMultiple(temp2,13)^aesMultiple(temp3,9);
array[1][i]=aesMultiple(temp0,9)^aesMultiple(temp1,14)^aesMultiple(temp2,11)^aesMultiple(temp3,13);
array[2][i]=aesMultiple(temp0,13)^aesMultiple(temp1,9)^aesMultiple(temp2,14)^aesMultiple(temp3,11);
array[3][i]=aesMultiple(temp0,11)^aesMultiple(temp1,13)^aesMultiple(temp2,9)^aesMultiple(temp3,14);
}
}
}
轮秘钥加
其依据是“任何数的自身的异或结果都为0”。加密过程中,每轮的输入与轮子密钥异或一次;因此,解密时再异或上该轮的轮子密钥即可恢复。
/**
* 秘钥轮加
* @param array 操作的4x4矩阵
* @param k 秘钥
*/
private void addRoundKey(int[][] array, int[][] k) {
for(int i=0;i<4;++i){
for(int j=0;j<4;++j){
array[i][j]=array[i][j] ^ k[j][i];
}
}
}
秘钥扩展算法
这部分原理可参考密码算法详解——AES,说的比较详细,我只列出实例图和源码。
/**
* 扩展秘钥
* @param key 秘钥矩阵
* @param w 秘钥扩展结果
*/
private void extendKey(int[][] key,int[][][] w){
for(int i=0;i<4;i++){
for(int j=0;j<4;++j){
w[0][i][j]=key[j][i];
}
}
for(int i=1;i<11;i++){
for(int j=0;j<4;j++){
int[] temp=new int[4];
if(j==0){
temp[0]=w[i-1][3][1];
temp[1]=w[i-1][3][2];
temp[2]=w[i-1][3][3];
temp[3]=w[i-1][3][0];
for(int k=0;k<4;k++){
int m=temp[k];
int row=m/16;
int col=m%16;
temp[k]=S1[row*DIMENSION+col];
if(k==0){
temp[k]=temp[k]^RC[i-1];
}
}
}else{
temp[0]=w[i][j-1][0];
temp[1]=w[i][j-1][1];
temp[2]=w[i][j-1][2];
temp[3]=w[i][j-1][3];
}
for(int l=0;l<4;++l){
w[i][j][l]=w[i-1][j][l]^temp[l];
}
}
}
}
加/解密
/**
* AES加密方法,得到密文
* @param str
* @return
*/
public String encryptByByAES(String str) {
int[][] p = getKeyMatrix(Key);
char[] content=completeString(str);
int size=content.length;
char[] encryResult=new char[size];
for(int i=0;i<size/16;++i){
int[][] contentToInt=new int[4][4];
for(int j=0;j<4;j++){
for(int k=0;k<4;++k){
contentToInt[j][k]=content[16*i+j*4+k];
}
}
aesDetail(contentToInt,p,true);
for(int j=0;j<4;++j){
for(int k=0;k<4;++k){
encryResult[16*i+j*4+k]=(char)contentToInt[j][k];
}
}
}
return String.valueOf(encryResult);
}
/**
* AES解密方法,获得明文
* @param str
* @return
*/
public String decryptByAES(String str){
int[][] p = getKeyMatrix(Key);
char[] content=completeString(str);
int size=content.length;
char[] decrptResult=new char[size];
for(int i=0;i<size/16;++i){
int[][] contentToInt=new int[4][4];
for(int j=0;j<4;j++){
for(int k=0;k<4;++k){
contentToInt[j][k]=content[16*i+j*4+k];
}
}
aesDetail(contentToInt,p,false);
for(int j=0;j<4;++j){
for(int k=0;k<4;++k){
decrptResult[16*i+j*4+k]=(char)contentToInt[j][k];
}
}
}
return String.valueOf(decrptResult);
}
最终代码
在这为了适配中文添加了一个工具类,可将Unicode编码转为汉字。
AESUtil
public class AESUtil {
/**
* 轮数
*/
private static int NR=10;
/**
* 二维表维度
*/
private static final int DIMENSION=16;
/**
* 字节代换:正映射
*/
private static final int[] S1=
{ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, /*0*/
0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, /*1*/
0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, /*2*/
0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, /*3*/
0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, /*4*/
0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, /*5*/
0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, /*6*/
0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, /*7*/
0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, /*8*/
0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, /*9*/
0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, /*a*/
0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, /*b*/
0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, /*c*/
0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, /*d*/
0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, /*e*/
0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16 /*f*/
};
/**
* 字节代换:逆映射
*/
private static final int[] S2=
{ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb, /*0*/
0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb, /*1*/
0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e, /*2*/
0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25, /*3*/
0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92, /*4*/
0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84, /*5*/
0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06, /*6*/
0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b, /*7*/
0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73, /*8*/
0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e, /*9*/
0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b, /*a*/
0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4, /*b*/
0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f, /*c*/
0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef, /*d*/
0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61, /*e*/
0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d /*f*/
};
private String Key;
/**
* 构造函数
* @param Key 秘钥字符串 要求,长度大于16
*/
public AESUtil(String Key){
if(Key.length()<16)
throw new RuntimeException();
this.Key=Key;
}
public void setKey(String key) {
Key = key;
}
/**
* 常量轮值表
*/
private static int[] RC={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36};
/**
* 字节代换
* @param array 操作的4x4矩阵
* @param encode 加密或解密的标志
*/
private void subBytes(int[][] array,boolean encode){
int i,j;
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++) {
int temp=array[i][j];
int row=temp/16;
int col=temp%16;
if(encode){
array[i][j]=S1[row*16+col];
}else{
array[i][j]=S2[row*16+col];
}
}
}
/**
* 行移位
* @param array 操作的4x4矩阵
* @param encode 加密或解密的标志
*/
private void shiftRows(int[][] array,boolean encode) {
for(int i=0;i<4;i++){
for(int j=0;j<i;j++){ //第i行移动i次
if(encode) { //加密时用 行移位
int temp = array[i][0];
array[i][0] = array[i][1];
array[i][1] = array[i][2];
array[i][2] = array[i][3];
array[i][3] = temp;
}else{ //解密时用 逆行移位
int temp = array[i][3];
array[i][3] = array[i][2];
array[i][2] = array[i][1];
array[i][1] = array[i][0];
array[i][0] = temp;
}
}
}
}
/**
* AES乘法
* @param a 操作矩阵中的数
* @param le 常数矩阵中的数
* @return
*/
private int aesMultiple(int a,int le){
int thr=le&0x8;
int sec=le&0x4;
int fir=le&0x2;
int firMod=le%2;
int result=0;
if(thr>0){
int b=a;
for(int i=1;i<=3;++i){
b=b<<1;
if(b>=256){
b=b^0x11b;
}
}
b=b%256;
result=result^b;
}
if(sec>0){
int b=a;
for(int i=1;i<=2;i++){
b=b<<1;
if(b>=256){
b=b^0x11b;
}
}
b=b%256;
result=result^b;
}
if(fir>0){
int b=a<<1;
if(b>=256){
b=b^0x11b;
}
b=b%256;
result=result^b;
}
if(firMod>0){
result=result^a;
}
return result;
}
/**
* AES乘法计算
* @param array 操作的4x4矩阵
* @param encode 加密或解密的标志
*/
private void mixColumns(int[][] array,boolean encode) {
for(int i=0;i<4;i++){
int temp0=array[0][i];
int temp1=array[1][i];
int temp2=array[2][i];
int temp3=array[3][i];
if(encode){
/** 常数矩阵
{ {2, 3, 1, 1},
{1, 2, 3, 1},
{1, 1, 2, 3},
{3, 1, 1, 2 }}
*/
array[0][i]=aesMultiple(temp0,2)^aesMultiple(temp1,3)^temp2^temp3;
array[1][i]=temp0^aesMultiple(temp1,2)^aesMultiple(temp2,3)^temp3;
array[2][i]=temp0^temp1^aesMultiple(temp2,2)^aesMultiple(temp3,3);
array[3][i]=aesMultiple(temp0,3)^temp1^temp2^aesMultiple(temp3,2);
}else{
/** 常数矩阵
{ {0E, 0B, 0D, 09},
{09, 0E, 0B, 0D},
{0D, 09, 0E, 0B},
{0B, 0D, 09, 0E }}
*/
array[0][i]=aesMultiple(temp0,14)^aesMultiple(temp1,11)^aesMultiple(temp2,13)^aesMultiple(temp3,9);
array[1][i]=aesMultiple(temp0,9)^aesMultiple(temp1,14)^aesMultiple(temp2,11)^aesMultiple(temp3,13);
array[2][i]=aesMultiple(temp0,13)^aesMultiple(temp1,9)^aesMultiple(temp2,14)^aesMultiple(temp3,11);
array[3][i]=aesMultiple(temp0,11)^aesMultiple(temp1,13)^aesMultiple(temp2,9)^aesMultiple(temp3,14);
}
}
}
/**
* 扩展秘钥
* @param key 秘钥矩阵
* @param w 秘钥扩展结果
*/
private void extendKey(int[][] key,int[][][] w){
for(int i=0;i<4;i++){
for(int j=0;j<4;++j){
w[0][i][j]=key[j][i];
}
}
for(int i=1;i<11;i++){
for(int j=0;j<4;j++){
int[] temp=new int[4];
if(j==0){
temp[0]=w[i-1][3][1];
temp[1]=w[i-1][3][2];
temp[2]=w[i-1][3][3];
temp[3]=w[i-1][3][0];
for(int k=0;k<4;k++){
int m=temp[k];
int row=m/16;
int col=m%16;
temp[k]=S1[row*DIMENSION+col];
if(k==0){
temp[k]=temp[k]^RC[i-1];
}
}
}else{
temp[0]=w[i][j-1][0];
temp[1]=w[i][j-1][1];
temp[2]=w[i][j-1][2];
temp[3]=w[i][j-1][3];
}
for(int l=0;l<4;++l){
w[i][j][l]=w[i-1][j][l]^temp[l];
}
}
}
}
/**
* 秘钥轮加
* @param array 操作的4x4矩阵
* @param k 秘钥
*/
private void addRoundKey(int[][] array, int[][] k) {
for(int i=0;i<4;++i){
for(int j=0;j<4;++j){
array[i][j]=array[i][j] ^ k[j][i];
}
}
}
/**
* char转int,针对秘钥,秘钥需要为0~9或者a~f,或者 A~F的字符组成
* @param ch char
* @return
*/
private int char2Int(char ch){
if(Character.isDigit(ch))
return ch-'0';
if(ch<'A' || (ch>'F'&&ch<'a') ||ch>'z')
return -1;
if(Character.isLowerCase(ch))
return ch-'a'+10;
if(Character.isUpperCase(ch))
return ch-'A'+10;
return -1;
}
/**
* AES算法详细流程
* @param content 转为unicode码的需要加解密的内容
* @param pKey 秘钥矩阵
* @param encode 加解密标志
*/
private void aesDetail(int[][] content,int[][] pKey,boolean encode){
int[][][] p=new int[11][4][4];
extendKey(pKey,p);
if(encode){
addRoundKey(content,p[0]);
for(int i=1;i<=NR;i++){
subBytes(content, true);
shiftRows(content,true);
if(i!=10){
mixColumns(content,true);
}
addRoundKey(content,p[i]);
}
}else{
addRoundKey(content,p[10]);
for(int i=9;i>=0;--i){
shiftRows(content,false);
subBytes(content,false);
addRoundKey(content,p[i]);
if(i!=0){
mixColumns(content,false);
}
}
}
}
/**
* 当str的长度不为16的整数倍时需要填充至整数倍
* @param str
* @return
*/
private char[] completeString(String str){
int len=str.length();
int size=len;
if(len%16!=0){
size=(len/16+1)*16;
}
char[] content =new char[size];
for(int i=0;i<len;i++){
content[i]=str.charAt(i);
}
for(int i=len;i<size;i++){
content[i]=0;
}
return content;
}
/**
* 根据秘钥String 获取秘钥矩阵
* @param key
* @return
*/
private int[][] getKeyMatrix(String key){
int[][] p=new int[4][4];
char[] charKey = key.toCharArray();
for (int i = 0; i < 4; ++i) {
for (int m = 0; m < 4; m++) {
int index = 4 * i + m;
p[i][m] = 16 * char2Int(charKey[index]) + char2Int(charKey[index + 1]);
}
}
return p;
}
/**
* AES加密方法,得到密文
* @param str
* @return
*/
public String encryptByByAES(String str) {
int[][] p = getKeyMatrix(Key);
char[] content=completeString(str);
int size=content.length;
char[] encryResult=new char[size];
for(int i=0;i<size/16;++i){
int[][] contentToInt=new int[4][4];
for(int j=0;j<4;j++){
for(int k=0;k<4;++k){
contentToInt[j][k]=content[16*i+j*4+k];
}
}
aesDetail(contentToInt,p,true);
for(int j=0;j<4;++j){
for(int k=0;k<4;++k){
encryResult[16*i+j*4+k]=(char)contentToInt[j][k];
}
}
}
return String.valueOf(encryResult);
}
/**
* AES解密方法,获得明文
* @param str
* @return
*/
public String decryptByAES(String str){
int[][] p = getKeyMatrix(Key);
char[] content=completeString(str);
int size=content.length;
char[] decrptResult=new char[size];
for(int i=0;i<size/16;++i){
int[][] contentToInt=new int[4][4];
for(int j=0;j<4;j++){
for(int k=0;k<4;++k){
contentToInt[j][k]=content[16*i+j*4+k];
}
}
aesDetail(contentToInt,p,false);
for(int j=0;j<4;++j){
for(int k=0;k<4;++k){
decrptResult[16*i+j*4+k]=(char)contentToInt[j][k];
}
}
}
return String.valueOf(decrptResult);
}
}
UnicodeCNUtil
import java.io.UnsupportedEncodingException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class UnicodeCNUtil {
/**
* unicode编码转换为汉字
* @param unicodeStr 待转化的编码
* @return 返回转化后的汉子
*/
public static String UnicodeToCN(String unicodeStr) {
Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
Matcher matcher = pattern.matcher(unicodeStr);
char ch;
while (matcher.find()) {
//group
String group = matcher.group(2);
//ch:'李四'
ch = (char) Integer.parseInt(group, 16);
//group1
String group1 = matcher.group(1);
unicodeStr = unicodeStr.replace(group1, ch + "");
}
return unicodeStr.replace("\\", "").trim();
}
/**
* 汉字转化为Unicode编码
* @param CN 待转化的中文
* @return 返回转化之后的unicode编码
*/
public static String CNToUnicode(String CN) {
try {
StringBuffer out = new StringBuffer("");
//直接获取字符串的unicode二进制
byte[] bytes = CN.getBytes("unicode");
//然后将其byte转换成对应的16进制表示即可
for (int i = 0; i < bytes.length - 1; i += 2) {
out.append("\\u");
String str = Integer.toHexString(bytes[i + 1] & 0xff);
for (int j = str.length(); j < 2; j++) {
out.append("0");
}
String str1 = Integer.toHexString(bytes[i] & 0xff);
out.append(str1);
out.append(str);
}
return out.toString();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
}
}