1. 概述
简单来说,加密就是将明文信息编码的过程,只有授权用户才能理解或访问这些信息。
原始消息称为明文,通过加密算法(即密码器)处理后生成密文,只有授权用户通过解密才能读取。
本文将详细解析 Java 中提供加密和解密核心功能的 Cipher
类。
2. Cipher 类详解
Java 加密扩展(JCE)是 Java 加密架构(JCA)的一部分,为应用程序提供加密/解密密码器以及私有数据哈希功能。
位于 javax.crypto
包中的 Cipher
类是 JCE 框架的核心,提供加密和解密功能。
2.1. 实例化 Cipher
要创建 Cipher
对象,需调用静态 getInstance
方法,传入请求的转换名称。可选地,可指定提供者名称。
以下示例展示 Cipher
的实例化:
public class Encryptor {
public byte[] encryptMessage(byte[] message, byte[] keyBytes)
throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
//...
}
}
转换字符串 AES/ECB/PKCS5Padding
告诉 getInstance
方法创建:
也可仅指定算法名称实例化:
Cipher cipher = Cipher.getInstance("AES");
此时 Java 会使用提供者默认的模式和填充方案。
⚠️ 注意:当满足以下条件时 getInstance
会抛出异常:
NoSuchAlgorithmException
:转换参数为null
/空/格式错误,或提供者不支持NoSuchPaddingException
:包含不支持的填充方案
2.2. 线程安全性
Cipher
是有状态且无内部同步的类。方法如 init()
或 update()
会改变实例的内部状态。
因此 Cipher
类是线程不安全的! 每次加密/解密操作都应创建新实例。
2.3. 密钥管理
Key
接口表示加密操作的密钥。密钥是包含编码密钥、编码格式和算法的透明容器。
通常通过以下方式获取密钥:
以下从字节数组创建对称密钥:
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
2.4. 初始化 Cipher
**调用 init()
方法初始化 Cipher
**,需传入:
Key
或Certificate
- 操作模式(
opmode
)
可选参数:
- 随机源:默认使用最高优先级提供者的
SecureRandom
实现 - 算法特定参数:如
IvParameterSpec
用于指定初始化向量
可用操作模式:
初始化示例:
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// ...
❌ init
可能抛出 InvalidKeyException
,常见原因:
- 密钥长度/编码无效
- 密钥大小超过配置的 JCE 管辖策略限制
使用证书的示例:
public byte[] encryptMessage(byte[] message, Certificate certificate)
throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, certificate);
// ...
}
Cipher
会自动从证书获取公钥进行加密。
2.5. 加密与解密
初始化后调用 doFinal()
执行操作,返回加密/解密后的字节数组。
✅ doFinal()
会重置 Cipher
状态到初始化后的状态,可复用实例处理新消息。
加密方法示例:
public byte[] encryptMessage(byte[] message, byte[] keyBytes)
throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException,
BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(message);
}
解密只需将模式改为 DECRYPT_MODE
:
public byte[] decryptMessage(byte[] encryptedMessage, byte[] keyBytes)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException,
BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(encryptedMessage);
}
2.6. 安全提供者
JCE 采用提供者架构,允许像 BouncyCastle 这样的加密库作为安全提供者无缝接入。
添加 BouncyCastle 提供者有两种方式:
静态添加
修改 <JAVA_HOME>/jre/lib/security/java.security
文件,在列表末尾添加:
...
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=org.bouncycastle.jce.provider.BouncyCastleProvider
⚠️ 属性键格式为 security.provider.N
,N
是列表中最后一个序号+1。
动态添加
无需修改配置文件,直接调用:
Security.addProvider(new BouncyCastleProvider());
初始化时指定提供者:
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");
BC
即 BouncyCastle 的简称。通过 Security.getProviders()
可获取所有已注册提供者。
3. 加密解密测试
编写测试验证加密解密流程。使用 AES-128 算法,断言解密结果与原始消息一致:
@Test
public void whenIsEncryptedAndDecrypted_thenDecryptedEqualsOriginal()
throws Exception {
String encryptionKeyString = "thisisa128bitkey";
String originalMessage = "This is a secret message";
byte[] encryptionKeyBytes = encryptionKeyString.getBytes();
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(encryptionKeyBytes, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedMessageBytes = cipher.doFinal(message.getBytes());
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decryptedMessageBytes = cipher.doFinal(encryptedMessageBytes);
assertThat(originalMessage).isEqualTo(new String(decryptedMessageBytes));
}
4. 总结
本文详细解析了 Cipher
类的核心功能及使用示例。更多细节可参考:
所有示例代码可在 GitHub 项目 中找到,基于 Maven 构建,可直接导入运行。