zoukankan      html  css  js  c++  java
  • JAVA实现AES加密

    1. 因子

           上次介绍了《JAVA实现DES加密》,中间提到近些年DES使用越来越少,原因就在于其使用56位密钥,比较容易被破解,近些年来逐渐被AES替代,AES已经变成目前对称加密中最流行算法之一;AES可以使用128、192、和256位密钥,并且用128位分组加密和解密数据。本文就简单介绍如何通过JAVA实现AES加密。

    2. JAVA实现

    闲话少许,掠过AES加密原理及算法,关于这些直接搜索专业网站吧,我们直接看JAVA的具体实现。

    2.1 加密

    代码有详细解释,不多废话。
    1. /** 
    2.  * 加密 
    3.  *  
    4.  * @param content 需要加密的内容 
    5.  * @param password  加密密码 
    6.  * @return 
    7.  */  
    8. public static byte[] encrypt(String content, String password) {  
    9.         try {             
    10.                 KeyGenerator kgen = KeyGenerator.getInstance("AES");  
    11.                 kgen.init(128, new SecureRandom(password.getBytes()));  
    12.                 SecretKey secretKey = kgen.generateKey();  
    13.                 byte[] enCodeFormat = secretKey.getEncoded();  
    14.                 SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");  
    15.                 Cipher cipher = Cipher.getInstance("AES");// 创建密码器   
    16.                 byte[] byteContent = content.getBytes("utf-8");  
    17.                 cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化   
    18.                 byte[] result = cipher.doFinal(byteContent);  
    19.                 return result; // 加密   
    20.         } catch (NoSuchAlgorithmException e) {  
    21.                 e.printStackTrace();  
    22.         } catch (NoSuchPaddingException e) {  
    23.                 e.printStackTrace();  
    24.         } catch (InvalidKeyException e) {  
    25.                 e.printStackTrace();  
    26.         } catch (UnsupportedEncodingException e) {  
    27.                 e.printStackTrace();  
    28.         } catch (IllegalBlockSizeException e) {  
    29.                 e.printStackTrace();  
    30.         } catch (BadPaddingException e) {  
    31.                 e.printStackTrace();  
    32.         }  
    33.         return null;  
    34. }  

    2.2 解密

    代码有详细注释,不多废话
    注意:解密的时候要传入byte数组
    1. /**解密 
    2.  * @param content  待解密内容 
    3.  * @param password 解密密钥 
    4.  * @return 
    5.  */  
    6. public static byte[] decrypt(byte[] content, String password) {  
    7.         try {  
    8.                  KeyGenerator kgen = KeyGenerator.getInstance("AES");  
    9.                  kgen.init(128, new SecureRandom(password.getBytes()));  
    10.                  SecretKey secretKey = kgen.generateKey();  
    11.                  byte[] enCodeFormat = secretKey.getEncoded();  
    12.                  SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");              
    13.                  Cipher cipher = Cipher.getInstance("AES");// 创建密码器   
    14.                 cipher.init(Cipher.DECRYPT_MODE, key);// 初始化   
    15.                 byte[] result = cipher.doFinal(content);  
    16.                 return result; // 加密   
    17.         } catch (NoSuchAlgorithmException e) {  
    18.                 e.printStackTrace();  
    19.         } catch (NoSuchPaddingException e) {  
    20.                 e.printStackTrace();  
    21.         } catch (InvalidKeyException e) {  
    22.                 e.printStackTrace();  
    23.         } catch (IllegalBlockSizeException e) {  
    24.                 e.printStackTrace();  
    25.         } catch (BadPaddingException e) {  
    26.                 e.printStackTrace();  
    27.         }  
    28.         return null;  
    29. }  

    2.3 测试代码

    1. String content = "test";  
    2. String password = "12345678";  
    3. //加密   
    4. System.out.println("加密前:" + content);  
    5. byte[] encryptResult = encrypt(content, password);  
    6. //解密   
    7. byte[] decryptResult = decrypt(encryptResult,password);  
    8. System.out.println("解密后:" + new String(decryptResult));  
    输出结果如下:
    加密前:test
    解密后:test

    2.4 容易出错的地方

    但是如果我们将测试代码修改一下,如下:
    1. String content = "test";  
    2. String password = "12345678";  
    3. //加密   
    4. System.out.println("加密前:" + content);  
    5. byte[] encryptResult = encrypt(content, password);  
    6. try {  
    7.         String encryptResultStr = new String(encryptResult,"utf-8");  
    8.         //解密   
    9.         byte[] decryptResult = decrypt(encryptResultStr.getBytes("utf-8"),password);  
    10.         System.out.println("解密后:" + new String(decryptResult));  
    11. catch (UnsupportedEncodingException e) {  
    12.         e.printStackTrace();  
    13. }  
    则,系统会报出如下异常:
    javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
            at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
            at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
            at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
            at javax.crypto.Cipher.doFinal(DashoA13*..)
    这主要是因为加密后的byte数组是不能强制转换成字符串的,换言之:字符串和byte数组在这种情况下不是互逆的;要避免这种情况,我们需要做一些修订,可以考虑将二进制数据转换成十六进制表示,主要有如下两个方法:

    2.4.1将二进制转换成16进制

    1. /**将二进制转换成16进制 
    2.  * @param buf 
    3.  * @return 
    4.  */  
    5. public static String parseByte2HexStr(byte buf[]) {  
    6.         StringBuffer sb = new StringBuffer();  
    7.         for (int i = 0; i < buf.length; i++) {  
    8.                 String hex = Integer.toHexString(buf[i] & 0xFF);  
    9.                 if (hex.length() == 1) {  
    10.                         hex = '0' + hex;  
    11.                 }  
    12.                 sb.append(hex.toUpperCase());  
    13.         }  
    14.         return sb.toString();  
    15. }  

    2.4.2 将16进制转换为二进制

    1. /**将16进制转换为二进制 
    2.  * @param hexStr 
    3.  * @return 
    4.  */  
    5. public static byte[] parseHexStr2Byte(String hexStr) {  
    6.         if (hexStr.length() < 1)  
    7.                 return null;  
    8.         byte[] result = new byte[hexStr.length()/2];  
    9.         for (int i = 0;i< hexStr.length()/2; i++) {  
    10.                 int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);  
    11.                 int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);  
    12.                 result[i] = (byte) (high * 16 + low);  
    13.         }  
    14.         return result;  
    15. }  
    然后,我们再修订以上测试代码,如下:
    1. String content = "test";  
    2. String password = "12345678";  
    3. //加密   
    4. System.out.println("加密前:" + content);  
    5. byte[] encryptResult = encrypt(content, password);  
    6. String encryptResultStr = parseByte2HexStr(encryptResult);  
    7. System.out.println("加密后:" + encryptResultStr);  
    8. //解密   
    9. byte[] decryptFrom = parseHexStr2Byte(encryptResultStr);  
    10. byte[] decryptResult = decrypt(decryptFrom,password);  
    11. System.out.println("解密后:" + new String(decryptResult));  
    测试结果如下:
    加密前:test
    加密后:73C58BAFE578C59366D8C995CD0B9D6D
    解密后:test
     

    2.5 另外一种加密方式

    还有一种加密方式,大家可以参考如下:
    1. /** 
    2.       * 加密 
    3.       * 
    4.       * @param content 需要加密的内容 
    5.       * @param password  加密密码 
    6.       * @return 
    7.       */  
    8.      public static byte[] encrypt2(String content, String password) {  
    9.              try {  
    10.                      SecretKeySpec key = new SecretKeySpec(password.getBytes(), "AES");  
    11.                      Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");  
    12.                      byte[] byteContent = content.getBytes("utf-8");  
    13.                      cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化   
    14.                      byte[] result = cipher.doFinal(byteContent);  
    15.                      return result; // 加密   
    16.              } catch (NoSuchAlgorithmException e) {  
    17.                      e.printStackTrace();  
    18.              } catch (NoSuchPaddingException e) {  
    19.                      e.printStackTrace();  
    20.              } catch (InvalidKeyException e) {  
    21.                      e.printStackTrace();  
    22.              } catch (UnsupportedEncodingException e) {  
    23.                      e.printStackTrace();  
    24.              } catch (IllegalBlockSizeException e) {  
    25.                      e.printStackTrace();  
    26.              } catch (BadPaddingException e) {  
    27.                      e.printStackTrace();  
    28.              }  
    29.              return null;  
    30.      }  
    这种加密方式有两种限制
    • 密钥必须是16位的
    • 待加密内容的长度必须是16的倍数,如果不是16的倍数,就会出如下异常:
    javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
            at com.sun.crypto.provider.SunJCE_f.a(DashoA13*..)
            at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
            at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
            at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
            at javax.crypto.Cipher.doFinal(DashoA13*..)
    要解决如上异常,可以通过补全传入加密内容等方式进行避免。
  • 相关阅读:
    flock对文件锁定读写操作的问题 简单
    hdu 2899 Strange Fuction(二分)
    hdu 2199 Can you solve this equation? (二分)
    poj 3080 Blue Jeans (KMP)
    poj 2823 Sliding Window (单调队列)
    poj 2001 Shortest Prefixes (trie)
    poj 2503 Babelfish (trie)
    poj 1936 All in All
    hdu 3507 Print Article (DP, Monotone Queue)
    fzu 1894 志愿者选拔 (单调队列)
  • 原文地址:https://www.cnblogs.com/wnlja/p/4241978.html
Copyright © 2011-2022 走看看