【工具類】Java實現AES演算法 加密和解密
阿新 • • 發佈:2019-02-18
最近在學AES加密,通過網上學習查詢資料,封裝了一個AES加密解密工具類,說幾點:
- 演算法/模式/填充,這個最好使用"AES/CBC/PKCS5Padding","ECB"在IOS中不安全(網上查詢資料得知),不要使用預設填充
- 引數金鑰要使用16位,不使用"AES/CBC/PKCS5Padding"這種模式是不需要16位金鑰的,不過這種安全性比較高,關於安全性可以查詢下資料
- 這裡主要是程式碼方面,理論方面要查詢其他資料(修改版:第一次發的程式碼,跨域解密不出來,這次的可以了)
- (重點)Linux下解密一定要加上SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(secretKey.getBytes());否則會報錯,javax.crypto.BadPaddingException: Given final block not properly padded - (重點)使用Base64再包一層是為了防止加密後在變數之間傳遞丟字元
如果有不對的地方,請大家多指點。 多反饋。
模式/填充參考:
演算法/模式/填充 16位元組加密後資料長度 不滿16位元組加密後長度 AES/CBC/NoPadding 16 不支援 AES/CBC/PKCS5Padding 32 16 AES/CBC/ISO10126Padding 32 16 AES/CFB/NoPadding 16 原始資料長度 AES/CFB/PKCS5Padding 32 16 AES/ECB/NoPadding 16 不支援 AES/ECB/PKCS5Padding 32 16 AES/ECB/ISO10126Padding 32 16 AES/OFB/NoPadding 16 原始資料長度 AES/OFB/PKCS5Padding 32 16 AES/OFB/ISO10126Padding 32 16 AES/PCBC/NoPadding 16 不支援 AES/PCBC/PKCS5Padding 32 16 AES/PCBC/ISO10126Padding 32 16 多了一行。。。
程式碼如下:
package com.test; import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; /** * AES加密和解密工具類 * * @author zhancy */ public class AESUtilFinal { // AES密碼器 private static Cipher cipher; // 字串編碼 private static final String KEY_CHARSET = "UTF-8"; // 演算法方式 private static final String KEY_ALGORITHM = "AES"; // 演算法/模式/填充 private static final String CIPHER_ALGORITHM_CBC = "AES/CBC/PKCS5Padding"; // 私鑰大小128/192/256(bits)位 即:16/24/32bytes,暫時使用128,如果擴大需要更換java/jre裡面的jar包 private static final Integer PRIVATE_KEY_SIZE_BIT = 128; private static final Integer PRIVATE_KEY_SIZE_BYTE = 16; public static void main(String[] args) { String secretKey = "1234567812345678"; String text = "test123測試"; String miwen = encrypt(secretKey, text); System.out.println("密文為:" + miwen); String mingwen = decrypt(secretKey, miwen); System.out.println("明文為:" + mingwen); } /** * 加密 * * @param secretKey * 金鑰:加密的規則 16位 * @param plainText * 明文:要加密的內容 * @return cipherText * 密文:加密後的內容,如有異常返回空串:"" */ public static String encrypt(String secretKey, String plainText) { if (secretKey.length() != PRIVATE_KEY_SIZE_BYTE) { throw new RuntimeException("AESUtil:Invalid AES secretKey length (must be 16 bytes)"); } // 密文字串 String cipherText = ""; try { // 加密模式初始化引數 initParam(secretKey, Cipher.ENCRYPT_MODE); // 獲取加密內容的位元組陣列 byte[] bytePlainText = plainText.getBytes(KEY_CHARSET); // 執行加密 byte[] byteCipherText = cipher.doFinal(bytePlainText); cipherText = Base64.encodeBase64String(byteCipherText); } catch (Exception e) { throw new RuntimeException("AESUtil:encrypt fail!", e); } return cipherText; } /** * 解密 * * @param secretKey * 金鑰:加密的規則 16位 * @param cipherText * 密文:加密後的內容,即需要解密的內容 * @return plainText * 明文:解密後的內容即加密前的內容,如有異常返回空串:"" */ public static String decrypt(String secretKey, String cipherText) { if (secretKey.length() != PRIVATE_KEY_SIZE_BYTE) { throw new RuntimeException("AESUtil:Invalid AES secretKey length (must be 16 bytes)"); } // 明文字串 String plainText = ""; try { initParam(secretKey, Cipher.DECRYPT_MODE); // 將加密並編碼後的內容解碼成位元組陣列 byte[] byteCipherText = Base64.decodeBase64(cipherText); // 解密 byte[] bytePlainText = cipher.doFinal(byteCipherText); plainText = new String(bytePlainText, KEY_CHARSET); } catch (Exception e) { throw new RuntimeException("AESUtil:decrypt fail!", e); } return plainText; } /** * 初始化引數 * @param secretKey * 金鑰:加密的規則 16位 * @param mode * 加密模式:加密or解密 */ public static void initParam(String secretKey, int mode) { try { // 防止Linux下生成隨機key SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); secureRandom.setSeed(secretKey.getBytes()); // 獲取key生成器 KeyGenerator keygen = KeyGenerator.getInstance(KEY_ALGORITHM); keygen.init(PRIVATE_KEY_SIZE_BIT, secureRandom); // 獲得原始對稱金鑰的位元組陣列 byte[] raw = secretKey.getBytes(); // 根據位元組陣列生成AES內部金鑰 SecretKeySpec key = new SecretKeySpec(raw, KEY_ALGORITHM); // 根據指定演算法"AES/CBC/PKCS5Padding"例項化密碼器 cipher = Cipher.getInstance(CIPHER_ALGORITHM_CBC); IvParameterSpec iv = new IvParameterSpec(secretKey.getBytes()); System.out.println("iv:" + new String(iv.getIV())); cipher.init(mode, key, iv); } catch (Exception e) { throw new RuntimeException("AESUtil:initParam fail!", e); } } }