这个需求很简单就是存储数据库密码,因为链接数据库的需要用到,加密就必须要用对称加密算法,于是简单调研了一下对称加密算法,经过对比最后选择了AES算法-CBC模式
怎么理解对称加密
加密:接收秘钥key和明文,然后输出密文。
解密:通过key解密密文,得到明文
例: 加密 123 =》AES( 123 + key ) =》@#$ 解密 @#$ =》AES( key + @#$ ) =》123
对比
这里简单对我了解过的对称加密算法做个比较
算法 | 密钥长度 | 运算速度 | 安全性 | 资源消耗 |
DES | 56/64 | 较快 | 低(完全依赖密钥,易受穷举搜索法攻击) | 中 |
AES | 128/192/256 | 快 | 高(ECB模式生成固定密钥安全性低,CBC模式每次生成的密文都不同安全性高) | 低 |
IDEA | 128 | 较慢 | 高(军事级,可抗差值分析和相关分析) | 中 |
1、DES(Data Encryption Standard):对称算法,数据加密标准,速度较快,适用于加密大量数据的场合;
2、IDEA(International Data Encryption Algorithm)国际数据加密算法,使用 128位密钥提供非常强的安全性;
3、AES(Advanced Encryption Standard):高级加密标准,对称算法,是下一代的加密算法标准,速度快,安全级别高,在21世纪AES 标准的一个实现是 Rijndael算法;
密钥长度直接决定加密强度,DES算法由于密钥过短,可以在短时间内被暴力破解,所以现在已经不安全了。
算法选择
既然要使用对称加密算法,那么就必须要考虑两点,安全性和性能,那么针对上面三种算法,显而易见的AES的CBC模式是不二之选
代码demo实现
import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; public class SecretUtil { //这里需要设置你的32位字节密钥 public static final String ENCRYPT_OR_DECRYPT_KEY = "1234567890abcdef1234567890abcdef"; // 256位密钥 = 32 bytes Key: //CBC模式是安全性较高的AES加密模式,它需要一个随机数作为IV参数,这样对于同一份明文,每次生成的密文都不同 public static final byte[] BYTES_KEY = ENCRYPT_OR_DECRYPT_KEY.getBytes(StandardCharsets.UTF_8); public static final String INSTANCE = "AES/CBC/PKCS5Padding"; public static final String AES = "AES"; public static void main(String[] args) throws Exception { String password = "你来打我呀!"; String encryptStr1 = encrypt(password); System.out.println("第一次加密:" + encryptStr1); String decryptStr1 = decrypt(encryptStr1); System.out.println("第一次解密:" + decryptStr1); String encryptStr2 = encrypt(password); System.out.println("我每次加密都不一样:" + encryptStr2); String decryptStr2 = decrypt(encryptStr1); System.out.println("但我每次都能得到你:" + decryptStr2); } // 加密 public static String encrypt(String password) throws Exception { Cipher cipher = Cipher.getInstance(INSTANCE); SecretKeySpec keySpec = new SecretKeySpec(BYTES_KEY, AES); // CBC模式需要生成一个16 bytes的initialization vector SecureRandom sr = SecureRandom.getInstanceStrong(); byte[] iv = sr.generateSeed(16); IvParameterSpec ivps = new IvParameterSpec(iv); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivps); byte[] data = cipher.doFinal(password.getBytes(StandardCharsets.UTF_8)); // IV不需要保密,把IV和密文一起返回 return DatatypeConverter.printBase64Binary(join(iv, data)); } // 解密 public static String decrypt(String password) throws Exception { byte[] iv = new byte[16]; byte[] input = DatatypeConverter.parseBase64Binary(password); byte[] data = new byte[input.length - 16]; // 把password分割成IV和密文 System.arraycopy(input, 0, iv, 0, 16); System.arraycopy(input, 16, data, 0, data.length); // 解密 Cipher cipher = Cipher.getInstance(INSTANCE); SecretKeySpec keySpec = new SecretKeySpec(BYTES_KEY, AES); IvParameterSpec ivps = new IvParameterSpec(iv); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivps); return new String(cipher.doFinal(data), StandardCharsets.UTF_8); } public static byte[] join(byte[] bs1, byte[] bs2) { byte[] r = new byte[bs1.length + bs2.length]; System.arraycopy(bs1, 0, r, 0, bs1.length); System.arraycopy(bs2, 0, r, bs1.length, bs2.length); return r; } }
输出验证:
好了,对称加密算法之AES算法-CBC模式的简单应用就介绍到这里