AES是基於數據塊的加密方式,即每次處理的數據是一塊(16字節),當數據不是16字節的倍數時填充,這就是所謂的分組密碼(區別於基於比特位的流密碼),16字節是分組長度。css
ECB和CBC的加密結果是不同的,二者的模式不一樣,並且CBC會在第一個密碼塊運算時加入一個初始化向量。java
AES-128-CBC方式與AES-128方式不一樣的地方:
AES-128-CBC能夠本身定義「密鑰」和「偏移量「,AES-128是jdk自動生成的「密鑰」,因此AES-128-CBC更靈活。
算法
代碼實例:markdown
package com.client; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; /**AES 是一種可逆加密算法,對用戶的敏感信息加密處理 * 對原始數據進行AES加密後,在進行Base64編碼轉化; */ public class AesCBC { /* * 加密用的Key 能夠用26個字母和數字組成 * 此處使用AES-128-CBC加密模式,key須要爲16位。 */ private static String sKey = "sklhdflsjfsdgdeg"; private static String ivParameter = "cfbsdfgsdfxccvd1"; private static AesCBC instance = null; private AesCBC() { } public static AesCBC getInstance() { if (instance == null) { instance = new AesCBC(); } return instance; } // 加密 public String encrypt(String sSrc, String encodingFormat, String sKey, String ivParameter) throws Exception { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); byte[] raw = sKey.getBytes(); SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes()); //使用CBC模式,須要一個向量iv,可增長加密算法的強度 cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); byte[] encrypted = cipher.doFinal(sSrc.getBytes(encodingFormat)); return new BASE64Encoder().encode(encrypted); //此處使用BASE64作轉碼。 } // 解密 public String decrypt(String sSrc, String encodingFormat, String sKey, String ivParameter) throws Exception { try { byte[] raw = sKey.getBytes("ASCII"); SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes()); cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc); //先用base64解密 byte[] original = cipher.doFinal(encrypted1); String originalString = new String(original, encodingFormat); return originalString; } catch (Exception ex) { return null; } } public static void main(String[] args) throws Exception { // 須要加密的字串 String cSrc = "我來自中國"; System.out.println(cSrc); // 加密 long lStart = System.currentTimeMillis(); String enString = AesCBC.getInstance() .encrypt(cSrc, "utf-8", sKey, ivParameter); System.out.println("加密後的字串是:" + enString); long lUseTime = System.currentTimeMillis() - lStart; System.out.println("加密耗時:" + lUseTime + "毫秒"); // 解密 lStart = System.currentTimeMillis(); String DeString = AesCBC.getInstance() .decrypt(enString, "utf-8", sKey, ivParameter); System.out.println("解密後的字串是:" + DeString); lUseTime = System.currentTimeMillis() - lStart; System.out.println("解密耗時:" + lUseTime + "毫秒"); } }
bcprov-jdk16-146.jar
maven
加密代碼以下:ide
/** * * @author ngh * AES128 算法 * * CBC 模式 * * PKCS7Padding 填充模式 * * CBC模式須要添加一個參數iv * * 介於java 不支持PKCS7Padding,只支持PKCS5Padding 可是PKCS7Padding 和 PKCS5Padding 沒有什麼區別 * 要實如今java端用PKCS7Padding填充,須要用到bouncycastle組件來實現 */ public class AES { // 算法名稱 final String KEY_ALGORITHM = "AES"; // 加解密算法/模式/填充方式 final String algorithmStr = "AES/CBC/PKCS7Padding"; // private Key key; private Cipher cipher; boolean isInited = false; byte[] iv = { 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x30, 0x35, 0x30, 0x36, 0x30, 0x37, 0x30, 0x38 }; public void init(byte[] keyBytes) { // 若是密鑰不足16位,那麼就補足. 這個if 中的內容很重要 int base = 16; if ((keyBytes.length % base) != 0) { int groups = (keyBytes.length / base) + (((keyBytes.length % base) != 0) ? 1 : 0); byte[] temp = new byte[groups * base]; Arrays.fill(temp, (byte) 0); System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length); keyBytes = temp; } // 初始化 Security.addProvider(new BouncyCastleProvider()); // 轉化成JAVA的密鑰格式 key = new SecretKeySpec(keyBytes, KEY_ALGORITHM); try { // 初始化cipher cipher = Cipher.getInstance(algorithmStr, "BC"); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchPaddingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchProviderException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 加密方法 * * @param content * 要加密的字符串 * @param keyBytes * 加密密鑰 * @return */ public byte[] encrypt(byte[] content, byte[] keyBytes) { byte[] encryptedText = null; init(keyBytes); System.out.println("IV:" + new String(iv)); try { cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); encryptedText = cipher.doFinal(content); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return encryptedText; } /** * 解密方法 * * @param encryptedData * 要解密的字符串 * @param keyBytes * 解密密鑰 * @return */ public byte[] decrypt(byte[] encryptedData, byte[] keyBytes) { byte[] encryptedText = null; init(keyBytes); System.out.println("IV:" + new String(iv)); try { cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); encryptedText = cipher.doFinal(encryptedData); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return encryptedText; } }
public class Test { public static void main(String[] args) { AES aes = new AES(); // 加解密 密鑰 byte[] keybytes = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 }; String content = "1"; // 加密字符串 System.out.println("加密前的:" + content); System.out.println("加密密鑰:" + new String(keybytes)); // 加密方法 byte[] enc = aes.encrypt(content.getBytes(), keybytes); System.out.println("加密後的內容:" + new String(Hex.encode(enc))); // 解密方法 byte[] dec = aes.decrypt(enc, keybytes); System.out.println("解密後的內容:" + new String(dec)); } }