1. 简介

RSA,全称 Rivest–Shamir–Adleman,是一种非对称加密算法。它与 DESAES 这类对称加密算法不同的是,RSA 使用一对密钥:

  • 公钥(Public Key):可以公开分享,用于加密数据
  • 私钥(Private Key):必须严格保密,用于解密数据

本文将带你了解如何在 Java 中生成、存储并使用 RSA 密钥对进行加解密操作。


2. 生成 RSA 密钥对

在进行加密操作前,我们首先需要生成一对 RSA 密钥。Java 提供了 KeyPairGenerator 类来帮助我们快速生成密钥对:

KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048);
KeyPair pair = generator.generateKeyPair();

✅ 这里我们初始化了密钥长度为 2048 位,这是目前比较安全且通用的长度。

接着,我们可以分别提取出私钥和公钥:

PrivateKey privateKey = pair.getPrivate();
PublicKey publicKey = pair.getPublic();

公钥用于加密,私钥用于解密。


3. 将密钥存储到文件中

密钥对如果只保存在内存中显然不靠谱,尤其在生产环境中,密钥通常需要长期保存。这时候,将密钥写入文件是更稳妥的做法。

保存密钥

我们可以使用 getEncoded() 方法获取密钥的字节内容,并写入文件:

try (FileOutputStream fos = new FileOutputStream("public.key")) {
    fos.write(publicKey.getEncoded());
}

读取密钥

读取时,先将文件内容读为字节数组,再通过 KeyFactory 恢复成密钥对象:

File publicKeyFile = new File("public.key");
byte[] publicKeyBytes = Files.readAllBytes(publicKeyFile.toPath());

KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

⚠️ 注意:这里使用的是 X509EncodedKeySpec,它是 getEncoded() 方法默认的编码格式。

私钥的读写流程与公钥一致,只需将 X509EncodedKeySpec 替换为 PKCS8EncodedKeySpec

🔒 安全提醒:私钥文件一定要妥善保管,权限控制要严格,避免泄露!


4. 字符串加解密操作

加密

假设我们有如下待加密的字符串:

String secretMessage = "Baeldung secret message";

我们使用 Cipher 类进行加密操作:

Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);

byte[] secretMessageBytes = secretMessage.getBytes(StandardCharsets.UTF_8);
byte[] encryptedMessageBytes = encryptCipher.doFinal(secretMessageBytes);

为了便于存储或传输(比如通过 REST API),通常会对加密后的字节数组进行 Base64 编码:

String encodedMessage = Base64.getEncoder().encodeToString(encryptedMessageBytes);

解密

解密时,我们需要用私钥初始化 Cipher 并调用 doFinal 方法:

Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);

byte[] decryptedMessageBytes = decryptCipher.doFinal(encryptedMessageBytes);
String decryptedMessage = new String(decryptedMessageBytes, StandardCharsets.UTF_8);

最后验证一下是否还原成功:

assertEquals(secretMessage, decryptedMessage);

5. 文件加解密操作

RSA 也可以用于对整个文件进行加密。

加密文件

比如我们创建一个临时文件:

Path tempFile = Files.createTempFile("temp", "txt");
Files.writeString(tempFile, "some secret message");

读取文件内容并加密:

byte[] fileBytes = Files.readAllBytes(tempFile);

Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedFileBytes = encryptCipher.doFinal(fileBytes);

将加密后的内容写回文件:

try (FileOutputStream stream = new FileOutputStream(tempFile.toFile())) {
    stream.write(encryptedFileBytes);
}

解密文件

解密流程类似,只是 Cipher 初始化为解密模式并使用私钥:

byte[] encryptedFileBytes = Files.readAllBytes(tempFile);

Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedFileBytes = decryptCipher.doFinal(encryptedFileBytes);

try (FileOutputStream stream = new FileOutputStream(tempFile.toFile())) {
    stream.write(decryptedFileBytes);
}

最后验证文件内容是否还原成功:

String fileContent = Files.readString(tempFile);
Assertions.assertEquals("some secret message", fileContent);

6. 总结

本文我们学习了如何在 Java 中:

  • 生成 RSA 密钥对
  • 将密钥保存到文件中
  • 对字符串和文件进行加解密操作

RSA 是非对称加密的经典算法,虽然性能不如 AES,但在密钥交换、数字签名等场景下具有不可替代的优势。

🔐 小贴士:RSA 适合加密小量数据,大量数据建议使用混合加密(RSA + AES)。


原始标题:RSA in Java | Baeldung