java对称加密(AES)

Java代码 复制代码 收藏代码
  1. /**  
  2.  * AESHelper.java  
  3.  * cn.com.songjy.test  
  4.  *  
  5.  * Function: TODO   
  6.  *  
  7.  *   ver     date           author  
  8.  * ──────────────────────────────────  
  9.  *           2012-6-29      songjianyong  
  10.  *  
  11.  * Copyright (c) 2012, TNT All Rights Reserved.  
  12. */  
  13.   
  14. package cn.com.songjy.test;   
  15.   
  16. import java.io.UnsupportedEncodingException;   
  17. import java.security.InvalidKeyException;   
  18. import java.security.NoSuchAlgorithmException;   
  19. import java.security.SecureRandom;   
  20.   
  21. import javax.crypto.BadPaddingException;   
  22. import javax.crypto.Cipher;   
  23. import javax.crypto.IllegalBlockSizeException;   
  24. import javax.crypto.KeyGenerator;   
  25. import javax.crypto.NoSuchPaddingException;   
  26. import javax.crypto.SecretKey;   
  27. import javax.crypto.spec.SecretKeySpec;   
  28.   
  29. /**  
  30.  * ClassName:AESHelper  
  31.  *  
  32.  * @author   songjianyong  
  33.  * @version  1.0  
  34.  * @since    v1.0  
  35.  * @Date     2012-6-29 下午2:06:07   
  36.  */  
  37. public class AESHelper {   
  38.   
  39.     /**  
  40.      * @method main  
  41.      * @param args  
  42.      * @throws   
  43.      * @since v1.0  
  44.      */  
  45.   
  46.     public static void main(String[] args) {   
  47.   
  48.         String content = "宋建勇";   
  49.         String password = "12345678";   
  50.         byte[] encryptResult = encrypt(content, password);//加密   
  51.         byte[] decryptResult = decrypt(encryptResult,password);//解密   
  52.         System.out.println("解密后:" + new String(decryptResult));   
  53.            
  54.         /*容易出错的地方,请看下面代码*/  
  55.         System.out.println("***********************************************");   
  56.         try {   
  57.             String encryptResultStr = new String(encryptResult,"utf-8");   
  58.             decryptResult = decrypt(encryptResultStr.getBytes("utf-8"),password);   
  59.             System.out.println("解密后:" + new String(decryptResult));   
  60.         } catch (UnsupportedEncodingException e) {   
  61.             e.printStackTrace();   
  62.         } catch (Exception e) {   
  63.             // TODO: handle exception   
  64.         }   
  65.         /*则,系统会报出如下异常:javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher  
  66.     at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)  
  67.     at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)  
  68.     at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)  
  69.     at javax.crypto.Cipher.doFinal(DashoA13*..)  
  70.     at cn.com.songjy.test.ASCHelper.decrypt(ASCHelper.java:131)  
  71.     at cn.com.songjy.test.ASCHelper.main(ASCHelper.java:58)  
  72.          * */  
  73.         /*这主要是因为加密后的byte数组是不能强制转换成字符串的, 换言之,字符串和byte数组在这种情况下不是互逆的,  
  74.          * 要避免这种情况,我们需要做一些修订,可以考虑将二进制数据转换成十六进制表示,  
  75.          * 主要有两个方法:将二进制转换成16进制(见方法parseByte2HexStr)或是将16进制转换为二进制(见方法parseHexStr2Byte)*/  
  76.            
  77.         /*然后,我们再修订以上测试代码*/  
  78.         System.out.println("***********************************************");   
  79.         String encryptResultStr = parseByte2HexStr(encryptResult);   
  80.         System.out.println("加密后:" + encryptResultStr);   
  81.         byte[] decryptFrom = parseHexStr2Byte(encryptResultStr);   
  82.         decryptResult = decrypt(decryptFrom,password);//解码   
  83.         System.out.println("解密后:" + new String(decryptResult));   
  84.     }   
  85.   
  86.     /**  
  87.      * 加密  
  88.      * @method encrypt  
  89.      * @param content   需要加密的内容  
  90.      * @param password  加密密码  
  91.      * @return  
  92.      * @throws   
  93.      * @since v1.0  
  94.      */  
  95.     public static byte[] encrypt(String content, String password){   
  96.         try {   
  97.             KeyGenerator kgen = KeyGenerator.getInstance("AES");   
  98.             kgen.init(128, new SecureRandom(password.getBytes()));   
  99.             SecretKey secretKey = kgen.generateKey();   
  100.             byte[] enCodeFormat = secretKey.getEncoded();   
  101.             SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");   
  102.             Cipher cipher = Cipher.getInstance("AES");// 创建密码器   
  103.             byte[] byteContent = content.getBytes("utf-8");   
  104.             cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化   
  105.             byte[] result = cipher.doFinal(byteContent);   
  106.             return result; // 加密   
  107.         } catch (NoSuchAlgorithmException e) {   
  108.             e.printStackTrace();   
  109.         }catch (NoSuchPaddingException e) {   
  110.             e.printStackTrace();   
  111.         }catch (UnsupportedEncodingException e) {   
  112.             e.printStackTrace();   
  113.         }catch (InvalidKeyException e) {   
  114.             e.printStackTrace();   
  115.         }catch (IllegalBlockSizeException e) {   
  116.             e.printStackTrace();   
  117.         }catch (BadPaddingException e) {   
  118.             e.printStackTrace();   
  119.         }   
  120.         return null;   
  121.     }   
  122.        
  123.     /**  
  124.      * 解密  
  125.      * @method decrypt  
  126.      * @param content   待解密内容  
  127.      * @param password  解密密钥  
  128.      * @return  
  129.      * @throws   
  130.      * @since v1.0  
  131.      */  
  132.     public static byte[] decrypt(byte[] content, String password){   
  133.         try {   
  134.             KeyGenerator kgen = KeyGenerator.getInstance("AES");   
  135.             kgen.init(128, new SecureRandom(password.getBytes()));   
  136.             SecretKey secretKey = kgen.generateKey();   
  137.             byte[] enCodeFormat = secretKey.getEncoded();   
  138.             SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");   
  139.             Cipher cipher = Cipher.getInstance("AES");// 创建密码器   
  140.             cipher.init(Cipher.DECRYPT_MODE, key);// 初始化   
  141.             byte[] result = cipher.doFinal(content);   
  142.             return result; // 解密   
  143.         } catch (NoSuchAlgorithmException e) {   
  144.             e.printStackTrace();   
  145.         }catch (NoSuchPaddingException e) {   
  146.             e.printStackTrace();   
  147.         }catch (InvalidKeyException e) {   
  148.             e.printStackTrace();   
  149.         }catch (IllegalBlockSizeException e) {   
  150.             e.printStackTrace();   
  151.         }catch (BadPaddingException e) {   
  152.             e.printStackTrace();   
  153.         }   
  154.            
  155.         return null;   
  156.     }   
  157.        
  158.     /**  
  159.      * 将二进制转换成16进制  
  160.      * @method parseByte2HexStr  
  161.      * @param buf  
  162.      * @return  
  163.      * @throws   
  164.      * @since v1.0  
  165.      */  
  166.     public static String parseByte2HexStr(byte buf[]){   
  167.         StringBuffer sb = new StringBuffer();   
  168.         for(int i = 0; i < buf.length; i++){   
  169.             String hex = Integer.toHexString(buf[i] & 0xFF);   
  170.             if (hex.length() == 1) {   
  171.                 hex = '0' + hex;   
  172.             }   
  173.             sb.append(hex.toUpperCase());   
  174.         }   
  175.         return sb.toString();   
  176.     }   
  177.        
  178.     /**  
  179.      * 将16进制转换为二进制  
  180.      * @method parseHexStr2Byte  
  181.      * @param hexStr  
  182.      * @return  
  183.      * @throws   
  184.      * @since v1.0  
  185.      */  
  186.     public static byte[] parseHexStr2Byte(String hexStr){   
  187.         if(hexStr.length() < 1)   
  188.             return null;   
  189.         byte[] result = new byte[hexStr.length()/2];   
  190.         for (int i = 0;i< hexStr.length()/2; i++) {   
  191.             int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);   
  192.             int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);   
  193.             result[i] = (byte) (high * 16 + low);   
  194.         }   
  195.         return result;   
  196.     }   
  197.        
  198.     /**  
  199.      * 另外一种加密方式--这种加密方式有两种限制  
  200.      * 1、密钥必须是16位的  
  201.      * 2、待加密内容的长度必须是16的倍数,如果不是16的倍数,就会出如下异常  
  202.      * javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes  
  203.         at com.sun.crypto.provider.SunJCE_f.a(DashoA13*..)  
  204.         at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)  
  205.         at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)  
  206.         at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)  
  207.         at javax.crypto.Cipher.doFinal(DashoA13*..)  
  208.         要解决如上异常,可以通过补全传入加密内容等方式进行避免。  
  209.      * @method encrypt2  
  210.      * @param content   需要加密的内容  
  211.      * @param password  加密密码  
  212.      * @return  
  213.      * @throws   
  214.      * @since v1.0  
  215.      */  
  216.     public static byte[] encrypt2(String content, String password){   
  217.         try {   
  218.             SecretKeySpec key = new SecretKeySpec(password.getBytes(), "AES");   
  219.             Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");   
  220.             byte[] byteContent = content.getBytes("utf-8");   
  221.             cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化   
  222.             byte[] result = cipher.doFinal(byteContent);   
  223.             return result; // 加密   
  224.         } catch (NoSuchAlgorithmException e) {   
  225.             e.printStackTrace();   
  226.         } catch (NoSuchPaddingException e) {   
  227.             e.printStackTrace();   
  228.         } catch (UnsupportedEncodingException e) {   
  229.             e.printStackTrace();   
  230.         } catch (InvalidKeyException e) {   
  231.             e.printStackTrace();   
  232.         } catch (IllegalBlockSizeException e) {   
  233.             e.printStackTrace();   
  234.         } catch (BadPaddingException e) {   
  235.             e.printStackTrace();   
  236.         }   
  237.         return null;   
  238.     }   
  239.        
  240.        
  241. }  
/**
 * AESHelper.java
 * cn.com.songjy.test
 *
 * Function: TODO 
 *
 *   ver     date      		author
 * ──────────────────────────────────
 *   		 2012-6-29 		songjianyong
 *
 * Copyright (c) 2012, TNT All Rights Reserved.
*/

package cn.com.songjy.test;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * ClassName:AESHelper
 *
 * @author   songjianyong
 * @version  1.0
 * @since    v1.0
 * @Date	 2012-6-29 下午2:06:07 
 */
public class AESHelper {

	/**
	 * @method main
	 * @param args
	 * @throws 
	 * @since v1.0
	 */

	public static void main(String[] args) {

		String content = "宋建勇";
		String password = "12345678";
		byte[] encryptResult = encrypt(content, password);//加密
		byte[] decryptResult = decrypt(encryptResult,password);//解密
		System.out.println("解密后:" + new String(decryptResult));
		
		/*容易出错的地方,请看下面代码*/
		System.out.println("***********************************************");
		try {
			String encryptResultStr = new String(encryptResult,"utf-8");
			decryptResult = decrypt(encryptResultStr.getBytes("utf-8"),password);
			System.out.println("解密后:" + new String(decryptResult));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (Exception e) {
			// TODO: handle exception
		}
		/*则,系统会报出如下异常: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*..)
	at cn.com.songjy.test.ASCHelper.decrypt(ASCHelper.java:131)
	at cn.com.songjy.test.ASCHelper.main(ASCHelper.java:58)
		 * */
		/*这主要是因为加密后的byte数组是不能强制转换成字符串的, 换言之,字符串和byte数组在这种情况下不是互逆的,
		 * 要避免这种情况,我们需要做一些修订,可以考虑将二进制数据转换成十六进制表示,
		 * 主要有两个方法:将二进制转换成16进制(见方法parseByte2HexStr)或是将16进制转换为二进制(见方法parseHexStr2Byte)*/
		
		/*然后,我们再修订以上测试代码*/
		System.out.println("***********************************************");
		String encryptResultStr = parseByte2HexStr(encryptResult);
		System.out.println("加密后:" + encryptResultStr);
		byte[] decryptFrom = parseHexStr2Byte(encryptResultStr);
		decryptResult = decrypt(decryptFrom,password);//解码
		System.out.println("解密后:" + new String(decryptResult));
	}

	/**
	 * 加密
	 * @method encrypt
	 * @param content	需要加密的内容
	 * @param password	加密密码
	 * @return
	 * @throws 
	 * @since v1.0
	 */
	public static byte[] encrypt(String content, String password){
		try {
			KeyGenerator kgen = KeyGenerator.getInstance("AES");
			kgen.init(128, new SecureRandom(password.getBytes()));
			SecretKey secretKey = kgen.generateKey();
			byte[] enCodeFormat = secretKey.getEncoded();
			SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
			Cipher cipher = Cipher.getInstance("AES");// 创建密码器
			byte[] byteContent = content.getBytes("utf-8");
			cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
			byte[] result = cipher.doFinal(byteContent);
			return result; // 加密
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}catch (NoSuchPaddingException e) {
			e.printStackTrace();
		}catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}catch (InvalidKeyException e) {
			e.printStackTrace();
		}catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		}catch (BadPaddingException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 解密
	 * @method decrypt
	 * @param content	待解密内容
	 * @param password	解密密钥
	 * @return
	 * @throws 
	 * @since v1.0
	 */
	public static byte[] decrypt(byte[] content, String password){
		try {
			KeyGenerator kgen = KeyGenerator.getInstance("AES");
			kgen.init(128, new SecureRandom(password.getBytes()));
			SecretKey secretKey = kgen.generateKey();
			byte[] enCodeFormat = secretKey.getEncoded();
			SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
			Cipher cipher = Cipher.getInstance("AES");// 创建密码器
			cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
			byte[] result = cipher.doFinal(content);
			return result; // 解密
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}catch (NoSuchPaddingException e) {
			e.printStackTrace();
		}catch (InvalidKeyException e) {
			e.printStackTrace();
		}catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		}catch (BadPaddingException e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
	/**
	 * 将二进制转换成16进制
	 * @method parseByte2HexStr
	 * @param buf
	 * @return
	 * @throws 
	 * @since v1.0
	 */
	public static String parseByte2HexStr(byte buf[]){
		StringBuffer sb = new StringBuffer();
		for(int i = 0; i < buf.length; i++){
			String hex = Integer.toHexString(buf[i] & 0xFF);
			if (hex.length() == 1) {
				hex = '0' + hex;
			}
			sb.append(hex.toUpperCase());
		}
		return sb.toString();
	}
	
	/**
	 * 将16进制转换为二进制
	 * @method parseHexStr2Byte
	 * @param hexStr
	 * @return
	 * @throws 
	 * @since v1.0
	 */
	public static byte[] parseHexStr2Byte(String hexStr){
		if(hexStr.length() < 1)
			return null;
		byte[] result = new byte[hexStr.length()/2];
		for (int i = 0;i< hexStr.length()/2; i++) {
			int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);
			int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
			result[i] = (byte) (high * 16 + low);
		}
		return result;
	}
	
	/**
	 * 另外一种加密方式--这种加密方式有两种限制
	 * 1、密钥必须是16位的
	 * 2、待加密内容的长度必须是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*..)
		要解决如上异常,可以通过补全传入加密内容等方式进行避免。
	 * @method encrypt2
	 * @param content	需要加密的内容
	 * @param password	加密密码
	 * @return
	 * @throws 
	 * @since v1.0
	 */
	public static byte[] encrypt2(String content, String password){
		try {
			SecretKeySpec key = new SecretKeySpec(password.getBytes(), "AES");
			Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
			byte[] byteContent = content.getBytes("utf-8");
			cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
			byte[] result = cipher.doFinal(byteContent);
			return result; // 加密
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	
}




测试效果:

解密后:宋建勇
***********************************************
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*..)
at cn.com.songjy.test.ASCHelper.decrypt(ASCHelper.java:141)
at cn.com.songjy.test.ASCHelper.main(ASCHelper.java:58)
java.lang.NullPointerException
at java.lang.String.<init>(String.java:594)
at cn.com.songjy.test.ASCHelper.main(ASCHelper.java:59)
***********************************************
加密后:961000B09BDDA1F81E81EF3EFDC3A926
解密后:宋建勇

原文地址:https://www.cnblogs.com/firstdream/p/5478393.html