AES算法demo(Java实现)

目录

引言

Cipher工具类简介

AES对称加密算法demo

 AES算法流程图

字节代换/逆字节代换

行移位/行移位逆变换

列混合/逆列混合 

轮秘钥加

秘钥扩展算法

加/解密

最终代码

AESUtil

UnicodeCNUtil

引言

        最近使用到了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。

  1. DES(Data Encryption Standard):数据加密标准,速度较快,适用于加密大量数据的场合;
  2. AES(Advanced Encryption Standard):高级加密标准,是下一代的加密算法标准,速度快,安全级别高。
  3. 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;
        }

    }
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
AES算法Java实现可以通过Java的加密库javax.crypto来实现。具体步骤如下: 1. 导入相应的包,引入javax.crypto.Cipher和javax.crypto.spec.SecretKeySpec类。 2. 创建一个Cipher对象,指定使用AES算法。 3. 创建一个SecretKeySpec对象,将密钥以字节数组的形式传递给它。 4. 使用Cipher对象的init()方法初始化加密/解密模式和密钥。 5. 调用Cipher对象的doFinal()方法,传入要加密/解密的数据。 6. 处理加密/解密后的数据。 以下是一个简单的AES加密和解密的示例代码: ```java import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; public class AESExample { private static final String key = "0123456789abcdef"; // 密钥,必须为16字节长度的字符串 public static byte[] encrypt(byte[] data) throws Exception { SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); return cipher.doFinal(data); } public static byte[] decrypt(byte[] encryptedData) throws Exception { SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); return cipher.doFinal(encryptedData); } public static void main(String[] args) throws Exception { String text = "搞事情"; byte[] encryptedData = encrypt(text.getBytes()); String base64EncryptedData = new String(java.util.Base64.getEncoder().encode(encryptedData)); System.out.println("AES加密后:" + base64EncryptedData); byte[] decryptedData = decrypt(java.util.Base64.getDecoder().decode(base64EncryptedData)); String decryptedText = new String(decryptedData); System.out.println("AES解密后:" + decryptedText); } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值