1.简介
RSA,或者换句话说, Rivest–Shamir–Adleman是一种非对称密码算法。它具有两个密钥,与诸如DES或AES之类的对称算法不同。我们可以与任何人共享的公共密钥用于加密数据。还有一个我们只为自己保留的私有数据,用于解密数据
在本教程中,我们将学习如何在Java中生成,存储和使用RSA密钥。
2.生成RSA密钥对
在开始实际的加密之前,我们需要生成我们的RSA密钥对。 java.security
包中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());
}
要从文件中读取密钥,我们首先需要将内容加载为字节数组:
File publicKeyFile = new File("public.key");
byte[] publicKeyBytes = Files.readAllBytes(publicKeyFile.toPath());
然后使用KeyFactory
重新创建实际实例:
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
keyFactory.generatePublic(publicKeySpec);
密钥字节内容需要用EncodedKeySpec
类包装。在这里,我们使用X509EncodedKeySpec,
它表示用于保存文件的Key::getEncoded
方法的默认算法。
在此示例中,我们保存并仅读取公共密钥文件。可以使用相同的步骤来处理私钥。
请记住,使用私钥将文件保持尽可能安全,并限制访问。未经授权的访问可能会带来安全问题。
4.使用字符串
现在,让我们看一下如何加密和解密简单字符串。首先,我们需要一些数据才能使用:
String secretMessage = "Baeldung secret message";
其次,我们需要Cipher
对象,以使用之前生成的公钥进行加密:
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
准备好之后,我们可以调用doFinal
方法来加密消息。请注意,它仅接受字节数组参数,因此我们需要在转换字符串之前:
byte[] secretMessageBytes = secretMessage.getBytes(StandardCharsets.UTF_8);)
byte[] encryptedMessageBytes = encryptCipher.doFinal(secretMessageBytes);
现在,我们的消息已成功编码。如果我们要将其存储在数据库中或通过REST API发送,则使用Base64 Alphabet对其进行编码会更方便:
String encodedMessage = Base64.getEncoder().encodeToString(encryptedMessageBytes);
这样,该消息将更具可读性并且更易于使用。
现在,让我们看看如何将消息解密为原始形式。为此,我们需要另一个Cipher
实例。这次,我们将使用解密模式和私钥对其进行初始化:
Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
doFinal
方法像以前一样调用密码:
byte[] decryptedMessageBytes = decryptCipher.doFinal(encryptedMessageBytes);
String decryptedMessage = new String(decryptedMessageBytes, StandardCharsets.UTF_8);
最后,让我们验证加密解密过程是否正确进行:
assertEquals(secretMessage, decryptedMessage);
5.处理文件
也可以加密整个文件。例如,让我们创建一个包含一些文本内容的临时文件:
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);
}
解密过程看起来非常相似。唯一的区别是在解密模式下使用私钥初始化的密码:
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密钥以及如何使用它们来加密和解密消息和文件。
0 评论