安全算法
安全算法
安全算法概览
安全相关的常见的算法分为2大类:消息摘要算法
和 加密算法
类别 | 算法 | 区别 |
---|---|---|
消息摘要算法 | MD5, SHA1, SHA256, HmacMD5, HmacSHA1,Hmac512 | 其中HMAC 是带有秘钥的摘要算法。签名数据,数据本身可读,数据被修改时被发现 |
加密算法 | DES,3DES,AES,RSA | 其中 RSA 是非对称加解密算法,即 加密和解密使用的不是同一个秘钥。加密,数据不可读。防止获取 |
误区
- 有人经常把 摘要算法 也叫做 加密算法,这个是错误的认知。凡是加密就一定能解密,凡是不能解密的算法都不能叫做加密算法。
- 有人把Base64 也叫做加密算法,这个也是错误的,Base64 只能叫做编码算法。和 2进制转16进制 的算法本质上没有区别,而且Base64 算法没有秘钥的概念。
- 非对称秘钥可以互换加解密:公钥不一定是用来加密的, 私钥也不一定是用来解密的。
性能
- 基于JMH 的加解密性能测试(仅供参考)
Benchmark Mode Cnt Score Error Units
CipherPerformTest.encryptByCBC avgt 10 5893.295 ± 315.086 ns/op
CipherPerformTest.encryptByCFB avgt 10 6224.839 ± 28.337 ns/op
CipherPerformTest.encryptByOFB avgt 10 6275.740 ± 177.735 ns/op
CipherPerformTest.encryptByGCM avgt 10 12310.963 ± 326.713 ns/op
CipherPerformTest.decryptByGCM avgt 10 11029.540 ± 236.242 ns/op
CipherPerformTest.encryptRSA avgt 10 26761.729 ± 639.838 ns/op
-
AES 中 GCM 模式加解密耗时约是其他模式2倍左右
-
非对称 RSA 加解密耗时约是AES-GCM 2倍多
实现
AES加密
public static byte[] encryptGCM(byte[] secretKey, String algorithm, byte[] text, byte [] iv) {
SecretKeySpec keySpec = new SecretKeySpec(secretKey, algorithm);
try {
Cipher cipher = Cipher.getInstance(GCM_CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, new GCMParameterSpec(128,iv));
return cipher.doFinal(text);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException | InvalidAlgorithmParameterException e) {
log.error(e.getMessage(), e);
}
return null;
}
AES 解密
public static byte[] decryptGCM(byte[] secretKey, String algorithm, byte[] text,byte [] iv) {
SecretKeySpec keySpec = new SecretKeySpec(secretKey, algorithm);
try {
Cipher cipher = Cipher.getInstance(GCM_CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, keySpec, new GCMParameterSpec(128,iv));
return cipher.doFinal(text);
} catch (NoSuchAlgorithmException | IllegalBlockSizeException | BadPaddingException | InvalidKeyException | NoSuchPaddingException | InvalidAlgorithmParameterException e) {
log.error(e.getMessage(), e);
}
return null;
}
RSA 加密
public static byte[] encryptRSA(KeyPair keyPair, String content) {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
return cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
}
RSA 解密
public static byte[] decryptRSA(KeyPair keyPair, byte[] cryptedContent) {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
return cipher.doFinal(cryptedContent);
}
恢复秘钥
// 通用读取密钥
PublicKey publicKey = KeyFactory.getInstance("EC").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(privateKeyStr)));
// 通用读取私钥
PrivateKey privateKey = KeyFactory.getInstance("EC").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyStr)));
// 恢复RSA私钥
RSAPrivateKey privateKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyStr)));
// 恢复RSA 公钥
RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(privateKeyStr)));
第三方实现
BouncyCastle
- Bouncycstle 是一个开源的第三方密码包,其中包含了大量的密码算法
- Bouncycstle 是JCE的实现
添加依赖
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>1.64</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-ext-jdk15to18</artifactId>
<version>1.64</version>
</dependency>
添加Provider
- 想使用BouncyCastle, 仅仅添加依赖是不够的, 因为JVM还是无法找到它
动态添加
Security.addProvider(new BouncyCastleProvider());
- 该方法可以全局添加,比如:SpringBoot Main方法里
静态添加
- 将下载的jar包 添加到
$JAVA_HOME/jre/lib/ext
下 - 修改
$JAVA_HOME/jre/lib/security/java.security
, 写入配置security.provider.2=org.bouncycastle.jce.provider.BouncyCastleProvider