Java利用 AES/ECB/PKCS5Padding 算法加解密

Java利用  AES/ECB/PKCS5Padding 算法加解密。

    package com.newland.njwpayment.utils;  
      
    import javax.crypto.Cipher;  
    import javax.crypto.spec.SecretKeySpec;  
      
    import Decoder.BASE64Decoder;  
    import Decoder.BASE64Encoder;  
      
    /** 
     * AES加解密 
     * 
     * Created by yyh on 2015/10/9. 
     */  
    public class AESUtils {  
      
        /** 
         * 密钥算法 
         */  
        private static final String ALGORITHM = "AES";  
        /** 
         * 加解密算法/工作模式/填充方式 
         */  
        private static final String ALGORITHM_STR = "AES/ECB/PKCS5Padding";  
      
        /** 
         * SecretKeySpec类是KeySpec接口的实现类,用于构建秘密密钥规范 
         */  
        private SecretKeySpec key;  
      
        public AESUtils(String hexKey) {  
            key = new SecretKeySpec(hexKey.getBytes(), ALGORITHM);  
        }  
      
        /** 
         * AES加密 
         * @param data 
         * @return 
         * @throws Exception 
         */  
        public String encryptData(String data) throws Exception {  
            Cipher cipher = Cipher.getInstance(ALGORITHM_STR); // 创建密码器  
            cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化  
            return new BASE64Encoder().encode(cipher.doFinal(data.getBytes()));  
        }  
      
        /** 
         * AES解密 
         * @param base64Data 
         * @return 
         * @throws Exception 
         */  
        public String decryptData(String base64Data) throws Exception{  
            Cipher cipher = Cipher.getInstance(ALGORITHM_STR);  
            cipher.init(Cipher.DECRYPT_MODE, key);  
            return new String(cipher.doFinal(new BASE64Decoder().decodeBuffer(base64Data)));  
        }  
      
        /** 
         * hex字符串 转 byte数组 
         * @param s 
         * @return 
         */  
        private static byte[] hex2byte(String s) {  
            if (s.length() % 2 == 0) {  
                return hex2byte (s.getBytes(), 0, s.length() >> 1);  
            } else {  
                return hex2byte("0"+s);  
            }  
        }  
      
        private static byte[] hex2byte (byte[] b, int offset, int len) {  
            byte[] d = new byte[len];  
            for (int i=0; i>1] |= Character.digit((char) b[offset+i], 16) << shift;  
            }  
            return d;  
        }  
      
        public static void main(String[] args) throws Exception {  
            AESUtil util = new AESUtil("abcdefghijklmnop"); // 密钥  
            System.out.println("cardNo:"+util.encryptData("1234")); // 加密  
            System.out.println("exp:"+util.decryptData("34+Jzs4KkwaCQWVyyAgwLA==")); // 解密  
        }  
    }  


其中,BASE64Decoder与BASE64Encoder这两个类可以通过Jre System Library下面的rt.jar找到,这里顺便提及一下,sun.misc.BASE64Encoder找不到jar包的两种解决方法:

1、直接添加JRE System Library,在Eclipse里面项目右击->Java build path->JRE System Library...

2、导入已提取封装好的jar包。下载地址:sun.misc.BASE64Decoder.jar 下载

另外,还需要注意的是,AES密钥一般是16个字节为一块,然后对这一整块进行加密,如果不够16个字节,就需要补位,也就是16字节对齐。

AES简介

高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥,具体的加密流程如下图:
加密流程图
下面简单介绍下各个部分的作用与意义:

  • 明文P

    没有经过加密的数据。

  • 密钥K

    用来加密明文的密码,在对称加密算法中,加密与解密的密钥是相同的。密钥为接收方与发送方协商产生,但不可以直接在网络上传输,否则会导致密钥泄漏,通常是通过非对称加密算法加密密钥,然后再通过网络传输给对方,或者直接面对面商量密钥。密钥是绝对不可以泄漏的,否则会被攻击者还原密文,窃取机密数据。

  • AES加密函数

    设AES加密函数为E,则 C = E(K, P),其中P为明文,K为密钥,C为密文。也就是说,把明文P和密钥K作为加密函数的参数输入,则加密函数E会输出密文C。

  • 密文C

    经加密函数处理后的数据

  • AES解密函数

    设AES解密函数为D,则 P = D(K, C),其中C为密文,K为密钥,P为明文。也就是说,把密文C和密钥K作为解密函数的参数输入,则解密函数会输出明文P。

在这里简单介绍下对称加密算法与非对称加密算法的区别。

  • 对称加密算法

    加密和解密用到的密钥是相同的,这种加密方式加密速度非常快,适合经常发送数据的场合。缺点是密钥的传输比较麻烦。

  • 非对称加密算法

    加密和解密用的密钥是不同的,这种加密方式是用数学上的难解问题构造的,通常加密解密的速度比较慢,适合偶尔发送数据的场合。优点是密钥传输方便。常见的非对称加密算法为RSA、ECC和EIGamal。

实际中,一般是通过RSA加密AES的密钥,传输到接收方,接收方解密得到AES密钥,然后发送方和接收方用AES密钥来通信。

本文下面AES原理的介绍参考自《现代密码学教程》,AES的实现在介绍完原理后开始。

AES的基本结构

AES为分组密码,分组密码也就是把明文分成一组一组的,每组长度相等,每次加密一组数据,直到加密完整个明文。在AES标准规范中,分组长度只能是128位,也就是说,每个分组为16个字节(每个字节8位)。密钥的长度可以使用128位、192位或256位。密钥的长度不同,推荐加密轮数也不同,如下表所示:

AES 密钥长度(32位比特字) 分组长度(32位比特字) 加密轮数
AES-128 4 4 10
AES-192 6 4 12
AES-256 8 4 14

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

AES的处理单位是字节,128位的输入明文分组P和输入密钥K都被分成16个字节,分别记为P = P0 P1 … P15 和 K = K0 K1 … K15。如,明文分组为P = abcdefghijklmnop,其中的字符a对应P0,p对应P15。一般地,明文分组用字节为单位的正方形矩阵描述,称为状态矩阵。在算法的每一轮中,状态矩阵的内容不断发生变化,最后的结果作为密文输出。该矩阵中字节的排列顺序为从上到下、从左至右依次排列,如下图所示:
state

现在假设明文分组P为”abcdefghijklmnop”,则对应上面生成的状态矩阵图如下:
state2
上图中,0x61为字符a的十六进制表示。可以看到,明文经过AES加密后,已经面目全非。

类似地,128位密钥也是用字节为单位的矩阵表示,矩阵的每一列被称为1个32位比特字。通过密钥编排函数该密钥矩阵被扩展成一个44个字组成的序列W[0],W[1], … ,W[43],该序列的前4个元素W[0],W[1],W[2],W[3]是原始密钥,用于加密运算中的初始密钥加(下面介绍);后面40个字分为10组,每组4个字(128比特)分别用于10轮加密运算中的轮密钥加,如下图所示:
keystate
上图中,设K = “abcdefghijklmnop”,则K0 = a, K15 = p, W[0] = K0 K1 K2 K3 = “abcd”。

AES的整体结构如下图所示,其中的W[0,3]是指W[0]、W[1]、W[2]和W[3]串联组成的128位密钥。加密的第1轮到第9轮的轮函数一样,包括4个操作:字节代换、行位移、列混合和轮密钥加。最后一轮迭代不执行列混合。另外,在第一轮迭代之前,先将明文和原始密钥进行一次异或加密操作。
aes_struct
上图也展示了AES解密过程,解密过程仍为10轮,每一轮的操作是加密操作的逆操作。由于AES的4个轮操作都是可逆的,因此,解密操作的一轮就是顺序执行逆行移位、逆字节代换、轮密钥加和逆列混合。同加密操作类似,最后一轮不执行逆列混合,在第1轮解密之前,要执行1次密钥加操作。



你可能感兴趣的:(Java编程,java,aes,算法,AES算法)