java实现AES加解密

近些年DES使用越来越少,原因就在于其使用56位密钥,比较容易被破解,近些年来逐渐被AES替代,AES已经变成目前对称加密中最流行算法之一;
AES可以使用128、192、和256位密钥,并且用128位分组加密和解密数据。本文就简单介绍如何通过JAVA实现AES加密。

/**
* AES加密字符串
* @param content 需要被加密的字符串
* @param password 加密需要的密码
* @return 密文
*/
public static String aesEncrypt(String content, byte [] password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者

kgen.init(128, new SecureRandom(password));// 利用用户密码作为随机数初始化出
// 128位的key生产者
//加密没关系,SecureRandom是生成安全随机数序列,password.getBytes()是种子,只要种子相同,序列就一样,所以解密只要有password就行

SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥

byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥,如果此密钥不支持编码,则返回// null。

SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥

Cipher cipher = Cipher.getInstance("AES");// 创建密码器

byte[] byteContent = content.getBytes(StandardCharsets.UTF_8);

cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化为加密模式的密码器

byte[] result = cipher.doFinal(byteContent);// 加密

return Base64.getEncoder().encodeToString(result);//返回字节数据用Base64编码,解密之前先用Base64解码

} catch (Exception e) {
e.printStackTrace();
}
return null;
}

注意:加密后的byte数组是不能强制转换成字符串的,换言之:字符串和byte数组在这种情况下不是互逆的;要避免这种情况,可以考虑将二进制数据转换成十六进制表示或者用Base64编码成字符串表示;

/**
* 解密AES加密过的字符串
* @param content AES加密过过的内容
* @param password 加密时的密码
* @return 明文
*/
public static String aesDecrypt(String content, byte [] password) {
try {
//base64解码
byte [] message = Base64.getDecoder().decode(content);
KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
kgen.init(128, new SecureRandom(password));
SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
cipher.init(Cipher.DECRYPT_MODE, key);// 初始化为解密模式的密码器
byte[] result = cipher.doFinal(message);
return new String(result,StandardCharsets.UTF_8); // 明文

} catch (Exception e) {
e.printStackTrace();
}
return null;
}


另外一种加密方式

/**
* 加密
* @param content 需要加密的内容, 待加密内容的长度必须是16的倍数
* @param password 加密密码, 密钥必须是16位的
* @return
*/
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 (Exception e) {
    e.printStackTrace();
   }
    return null;
}

这种加密方式有两种限制:
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*..)
要解决如上异常,可以通过补全传入加密内容等方式进行避免。

posted @ 2020-03-02 20:21  MsencSir  阅读(1705)  评论(0编辑  收藏  举报