Java中的RSA加密
- java
- RSA
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密鑰以及如何使用它們來加密和解密消息和文件。