这里实现的是AES加密算法的CBC模式的NoPadding加密
下图是官方文档中Cipher的provider。后面的padding为填充模式,即CBC为128位加密算法,加密内容的byte[]字节数组位数必须是16的倍数,否则会抛异常 Input length not multiple of 16 bytes
CBC加密提供了两种填充方式,NoPadding是默认不填充。因此不够16位的部分,下面用空格进行了填充凑位数。
另外CBC加密除了提供AES加密必须的密钥key以外,还要一个响亮iv,应该是增加加密复杂度的。
以下源码是自己的CBC模式的实现,加密字段返回16进制字符串,解密时,同样通过AES/CBC/NoPadding方式,把16进制字符串转换为二进制byte[]字节数组后再解密,然后根据编码转为原字符串。
import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; /** * Aes加密工具类--暂时只实现CBC NoPadding加密 * * @author flysand **/ public class AesUtils { /** * 加密 加密方式AES/CBC/NoPadding 不足16位倍数,补空格 * * @param sSrc 加密内容 * @param encodingFormat 编码格式 * @param sKey 密钥key * @param ivParameter 向量 * @return * @throws Exception */ public static String encrypt(String sSrc, String encodingFormat, String sKey, String ivParameter) throws Exception { byte[] sSrcArray = sSrc.getBytes(encodingFormat); int length = sSrcArray.length; byte[] lastArr; //不足16倍数位,补充空 if (length % 16 != 0) { byte[] temp = new byte[16 - length % 16]; //用空格补位 byte[] fArr = " ".getBytes(encodingFormat); for (int i = 0; i < temp.length; i++) { temp[i] = fArr[0]; } lastArr = new byte[length + temp.length]; for (int i = 0; i < length; i++) { lastArr[i] = sSrcArray[i]; } for (int i = 0; i < temp.length; i++) { lastArr[length + i] = temp[i]; } } else { lastArr = sSrcArray; } //根据农银需求,采用AES/CBC/NoPadding加密方式 Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); byte[] raw = sKey.getBytes(encodingFormat); 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(lastArr); //直接转为16进制传参 return parseByte2HexStr(encrypted); } /** * 解密 根据加密方式AES/CBC/NoPadding解密 * * @param sSrc 加密内容 * @param encodingFormat 编码格式 * @param sKey 密钥key * @param ivParameter 向量 * @return * @throws Exception */ public static String decrypt(String sSrc, String encodingFormat, String sKey, String ivParameter) throws Exception { try { byte[] raw = sKey.getBytes(encodingFormat); SecretKeySpec keySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes(encodingFormat)); cipher.init(Cipher.DECRYPT_MODE, keySpec, iv); //转为二进制字节数组 byte[] encrypted = hex2byte(sSrc); byte[] original = cipher.doFinal(encrypted); String originalString = new String(original, encodingFormat); return originalString; } catch (Exception ex) { return null; } } /** * 将十六进制字符串转换成二进制字节数组 * * @param strHex * @return */ public static byte[] hex2byte(String strHex) { if (strHex == null) { return null; } int l = strHex.length(); if (l % 2 == 1) { return null; } byte[] b = new byte[l / 2]; for (int i = 0; i != l / 2; i++) { b[i] = (byte) Integer.parseInt(strHex.substring(i * 2, i * 2 + 2), 16); } return b; } /** * 将二进制字节数组转换成16进制字符串 * * @param buf * @return */ 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(); } }