在线版
要使用 AES/CBC/PKCS7Padding 模式需要添加依赖
org.bouncycastle bcprov-jdk16 1.46
AES 工具类
// 加密算法private static final String ENCRY_ALGORITHM = "AES";// 加密算法/加密模式/填充类型private static final String CIPHER_MODE = "AES/CBC/PKCS7Padding";// 设置iv偏移量,ECB加密模式不需要设置 iv 偏移量private static final String IV = "0000000000000000";// 设置加密字符集private static final String CHARACTER = "UTF-8";// 加密密码长度。默认 16 byte * 8 = 128 bitprivate static final int PWD_SIZE = 16;static { // 添加 AES/CBC/PKCS7Padding 支持 Security.addProvider(new BouncyCastleProvider());}public static void main(String[] args) { String str = "NiHao"; byte[] encryptAES = encryptAES(str, "1234567899874563"); byte[] decryptAES = decryptAES(encryptAES, "1234567899874563"); System.out.println(new String(decryptAES));}/** * 密码长度不足补"0" */private static byte[] pwdHandler(String password) throws UnsupportedEncodingException { byte[] data = null; if (password == null) { password = ""; } StringBuffer sb = new StringBuffer(PWD_SIZE); sb.append(password); while (sb.length() < PWD_SIZE) { sb.append("0"); } if (sb.length() > PWD_SIZE) { sb.setLength(PWD_SIZE); } data = sb.toString().getBytes(CHARACTER); return data;}/** * AES 加密 * * @param cleartext 明文 * @param key 密钥 * @return */public static byte[] encryptAES(String cleartext, String key) { try { // 获取加密密钥 SecretKeySpec keySpec = new SecretKeySpec(pwdHandler(key), ENCRY_ALGORITHM); // 获取Cipher实例 Cipher cipher = Cipher.getInstance(CIPHER_MODE); // 查看数据块位数 默认为16(byte) * 8 =128 bit // System.out.println("数据块位数(byte):" + cipher.getBlockSize()); // 初始化Cipher实例。设置执行模式以及加密密钥 cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(IV.getBytes(CHARACTER))); // 执行 byte[] cipherTextBytes = cipher.doFinal(cleartext.getBytes(CHARACTER)); return cipherTextBytes; } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return null;}/** * AES 解密 * * @param ciphertext 密文 * @param key 密钥 * @return */public static byte[] decryptAES(byte[] ciphertext, String key) { try { // 获取解密密钥 SecretKeySpec keySpec = new SecretKeySpec(pwdHandler(key), ENCRY_ALGORITHM); // 获取Cipher实例 Cipher cipher = Cipher.getInstance(CIPHER_MODE); // 查看数据块位数 默认为16(byte) * 8 =128 bit // System.out.println("数据块位数(byte):" + cipher.getBlockSize()); // 初始化Cipher实例。设置执行模式以及加密密钥 cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(IV.getBytes(CHARACTER))); // 执行 byte[] clearTextBytes = cipher.doFinal(ciphertext); return clearTextBytes; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } // 解密错误 返回 null return null;}
加密后通常配合 Base64 进行编码
public static void main(String[] args) { String str = "NiHao"; byte[] encryptAES = encryptAES(str, "1234567899874563"); String encryptBase64 = encryptBase64(encryptAES); byte[] decryptBase64 = decryptBase64(encryptBase64); byte[] decryptAES = decryptAES(decryptBase64, "1234567899874563"); System.out.println(new String(decryptAES));}/** * BASE64 加密 * * @param cleartext 明文 * @return 密文 */public static String encryptBase64(byte[] cleartext) { BASE64Encoder base64Encoder = new BASE64Encoder(); String cipherText = base64Encoder.encode(cleartext); return cipherText;}/** * BASE64 解密 * * @param cipherText 密文 * @return 明文 */public static byte[] decryptBase64(String cipherText) { try { BASE64Decoder base64Decoder = new BASE64Decoder(); byte[] cipherTextBytes = base64Decoder.decodeBuffer(cipherText); return cipherTextBytes; } catch (IOException e) { e.printStackTrace(); } // 解密错误返回 null return null;}
也可以使用 16 进制编码
public static void main(String[] args) { String str = "NiHao"; byte[] encryptAES = encryptAES(str, "1234567899874563"); String encryptHex = encryptHex(encryptAES); byte[] decryptHex = decryptHex(encryptHex); byte[] decryptAES = decryptAES(decryptHex, "1234567899874563"); System.out.println(new String(decryptAES));}/** * HEX 加密(字节数组转成16进制字符串) * * @param clearText 明文 * @return 密文 */public static String encryptHex(byte[] clearText) { // 一个字节的数, StringBuffer sb = new StringBuffer(clearText.length * 2); String tmp = ""; for (int n = 0; n < clearText.length; n++) { // 整数转成十六进制表示 tmp = (java.lang.Integer.toHexString(clearText[n] & 0XFF)); if (tmp.length() == 1) { sb.append("0"); } sb.append(tmp); } // 转成大写 String cipherText = sb.toString().toUpperCase(); return cipherText;}/** * HEX 解密(16进制字符串转换成字节数组) * * @param cipherText 密文 * @return 明文 */public static byte[] decryptHex(String cipherText) { if (cipherText == null || cipherText.length() < 2) { return new byte[0]; } cipherText = cipherText.toLowerCase(); int l = cipherText.length() / 2; byte[] cipherTextBytes = new byte[l]; for (int i = 0; i < l; ++i) { String tmp = cipherText.substring(2 * i, 2 * i + 2); cipherTextBytes[i] = (byte) (Integer.parseInt(tmp, 16) & 0xFF); } return cipherTextBytes;}
编码后若作为 URL 参数还需进行 URI 转换
public static String encodeURIComponent(String s) { String result = null; try { result = URLEncoder.encode(s, CHARACTER) .replaceAll("\\+", "%20") .replaceAll("\\%21", "!") .replaceAll("\\%27", "'") .replaceAll("\\%28", "(") .replaceAll("\\%29", ")") .replaceAll("\\%7E", "~"); } catch (UnsupportedEncodingException e) { result = s; } return result;}public static String decodeURIComponent(String s) { if (s == null) { return null; } String result = null; try { result = URLDecoder.decode(s, CHARACTER); } catch (UnsupportedEncodingException e) { result = s; } return result;}