java.security.InvalidKeyException 在使用 RSA 的 Java AES 密钥交换期间抛出
java.security.InvalidKeyException thrown during Java AES key exchange using RSA
我正在尝试在 Java 中制作一个 client/server 程序,允许服务器将使用 AES 加密的消息发送到客户端。现在,我在创建密钥交换协议时遇到了问题。此密钥交换当前的工作方式是:
- 客户端生成 RSA public/private 密钥对
- 客户端向服务器发送他的 RSA public 密钥
- 服务器使用客户端的 RSA public 密钥生成并加密 AES 密钥
- 服务器向客户端发送加密的 AES 密钥
- 双方现在都有正确的 AES 密钥,所有消息都可以使用 AES 加密
但是,每次进入第三步时,我都无法使用客户端的 RSA public 密钥加密生成的 AES 密钥,因为出现此错误:
java.security.InvalidKeyException: No installed provider supports this key: javax.crypto.spec.SecretKeySpec
at java.base/javax.crypto.Cipher.chooseProvider(Cipher.java:919)
at java.base/javax.crypto.Cipher.init(Cipher.java:1275)
at java.base/javax.crypto.Cipher.init(Cipher.java:1212)
at test.Server.<init>(Server.java:50)
at test.Start.main(Start.java:11)
因此,我无法完成我正在尝试执行的 AES 密钥交换。
Server.java用来做服务器端的事,Client.java用来做客户端的事。我的 Server.java 文件如下所示:
public class Server {
private ServerSocket serverSocket; // Server socket
private Socket socket; // Socket
private BufferedReader in; // Reading from stream
private PrintWriter out; // Writing to stream
private Key key; // AES key used for encryption
// Constructor
public Server() {
// Initialize the server socket
try {
// Setup connections
serverSocket = new ServerSocket(12345);
socket = serverSocket.accept();
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(newInputStreamReader(socket.getInputStream()));
// Receive the client's public RSA key
byte[] encodedClientKey = Base64.getDecoder().decode(in.readLine());
Key clientRSAKey = new SecretKeySpec(encodedClientKey, 0, encodedClientKey.length, "RSA");
// Generate AES key
KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES");
aesKeyGen.init(256);
key = aesKeyGen.generateKey();
// Encrypt the AES key using the client's RSA public key
Cipher c = Cipher.getInstance("RSA");
c.init(Cipher.ENCRYPT_MODE, clientRSAKey);
byte[] encryptedAESKey = c.doFinal(key.getEncoded());
// Send the encrypted AES key to the client
sendUnencrypted(Base64.getEncoder().encodeToString(encryptedAESKey));
} catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
| IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
}
// Receive an unencrypted message
public String receiveUnencrypted() {
try {
// Wait until the stream is ready to be read
while (true)
if (in.ready())
break;
return in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
// Send an unencrypted message
public void sendUnencrypted(String message) {
out.println(message);
out.flush();
}
// Send an encrypted message
public void send(String message) {
try {
// Encrypt the message
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.ENCRYPT_MODE, key);
String encoded = Base64.getEncoder().encodeToString(message.getBytes("utf-8"));
byte[] encrypted = c.doFinal(encoded.getBytes());
String encryptedString = Base64.getEncoder().encodeToString(encrypted);
// Send the encrypted message
out.println(encryptedString);
out.flush();
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException
| BadPaddingException | UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
我的 Client.java 文件如下所示:
public class Client {
private Socket socket; // Socket
private BufferedReader in; // Reading from stream
private PrintWriter out; // Writing to stream
private Key key; // AES key
// Constructor
public Client() {
try {
// Create streams to server
socket = new Socket("127.0.0.1", 12345);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// Generate an RSA key pair
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair kp = keyGen.generateKeyPair();
// Send out our public key to the server
byte[] publicKey = kp.getPublic().getEncoded();
sendUnencrypted(Base64.getEncoder().encodeToString(publicKey));
// Recieve and decrypt the AES key sent from the server
String encryptedKey = receiveUnencrypted();
Cipher c = Cipher.getInstance("RSA");
c.init(Cipher.DECRYPT_MODE, kp.getPrivate());
byte[] AESKey = c.doFinal(encryptedKey.getBytes());
key = new SecretKeySpec(AESKey, 0, AESKey.length, "AES");
} catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
| IllegalBlockSizeException | BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// Receive an unencrypted message
public String receiveUnencrypted() {
try {
// Wait until the stream is ready to be read
while (true)
if (in.ready())
break;
return in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
// Send an unencrypted message
public void sendUnencrypted(String message) {
out.println(message);
out.flush();
}
// Receive an encrypted message
public String receive() {
try {
// Wait until the stream is ready to be read
while (true)
if (in.ready())
break;
// Obtain the encrypted message
String encrypted = in.readLine();
// Decrypt and return the message
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.DECRYPT_MODE, key);
byte[] decoded = Base64.getDecoder().decode(encrypted);
String utf8 = new String(c.doFinal(decoded));
String plaintext = new String(Base64.getDecoder().decode(utf8));
// Return the message
return plaintext;
} catch (IOException | InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException
| IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
return null;
}
}
Start.java用于初始化服务器和客户端。
package test;
import java.util.Scanner;
public class Start {
public static void main(String args[]) {
Scanner scan = new Scanner(System.in);
System.out.println("1.) Create data server.\n2.) Connect to data server.\nPlease select an option: ");
int option = scan.nextInt();
if (option == 1) { // Setup a server if they choose option one
Server s = new Server();
s.send("Hello");
} else if (option == 2) { // Setup a client if they choose option two
Client c = new Client();
System.out.println(c.receive());
}
// Close scanner
scan.close();
}
}
首先,您不能使用 SecretKeySpec
来恢复 RSA public 密钥。在 Server
的构造函数中,更改
Key clientRSAKey = new SecretKeySpec(encodedClientKey, 0, encodedClientKey.length, "RSA");
到
Key clientRSAKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(encodedClientKey));
其次,您需要对base64编码的加密密钥进行解码。在您的 Client
构造函数中,更改
String encryptedKey = receiveUnencrypted();
到
byte[] encryptedKey = Base64.getDecoder().decode(receiveUnencrypted());
最后,在您的 Client
构造函数中,更改
byte[] AESKey = c.doFinal(encryptedKey.getBytes());
到
byte[] AESKey = c.doFinal(encryptedKey);
我正在尝试在 Java 中制作一个 client/server 程序,允许服务器将使用 AES 加密的消息发送到客户端。现在,我在创建密钥交换协议时遇到了问题。此密钥交换当前的工作方式是:
- 客户端生成 RSA public/private 密钥对
- 客户端向服务器发送他的 RSA public 密钥
- 服务器使用客户端的 RSA public 密钥生成并加密 AES 密钥
- 服务器向客户端发送加密的 AES 密钥
- 双方现在都有正确的 AES 密钥,所有消息都可以使用 AES 加密
但是,每次进入第三步时,我都无法使用客户端的 RSA public 密钥加密生成的 AES 密钥,因为出现此错误:
java.security.InvalidKeyException: No installed provider supports this key: javax.crypto.spec.SecretKeySpec
at java.base/javax.crypto.Cipher.chooseProvider(Cipher.java:919)
at java.base/javax.crypto.Cipher.init(Cipher.java:1275)
at java.base/javax.crypto.Cipher.init(Cipher.java:1212)
at test.Server.<init>(Server.java:50)
at test.Start.main(Start.java:11)
因此,我无法完成我正在尝试执行的 AES 密钥交换。
Server.java用来做服务器端的事,Client.java用来做客户端的事。我的 Server.java 文件如下所示:
public class Server {
private ServerSocket serverSocket; // Server socket
private Socket socket; // Socket
private BufferedReader in; // Reading from stream
private PrintWriter out; // Writing to stream
private Key key; // AES key used for encryption
// Constructor
public Server() {
// Initialize the server socket
try {
// Setup connections
serverSocket = new ServerSocket(12345);
socket = serverSocket.accept();
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(newInputStreamReader(socket.getInputStream()));
// Receive the client's public RSA key
byte[] encodedClientKey = Base64.getDecoder().decode(in.readLine());
Key clientRSAKey = new SecretKeySpec(encodedClientKey, 0, encodedClientKey.length, "RSA");
// Generate AES key
KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES");
aesKeyGen.init(256);
key = aesKeyGen.generateKey();
// Encrypt the AES key using the client's RSA public key
Cipher c = Cipher.getInstance("RSA");
c.init(Cipher.ENCRYPT_MODE, clientRSAKey);
byte[] encryptedAESKey = c.doFinal(key.getEncoded());
// Send the encrypted AES key to the client
sendUnencrypted(Base64.getEncoder().encodeToString(encryptedAESKey));
} catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
| IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
}
// Receive an unencrypted message
public String receiveUnencrypted() {
try {
// Wait until the stream is ready to be read
while (true)
if (in.ready())
break;
return in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
// Send an unencrypted message
public void sendUnencrypted(String message) {
out.println(message);
out.flush();
}
// Send an encrypted message
public void send(String message) {
try {
// Encrypt the message
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.ENCRYPT_MODE, key);
String encoded = Base64.getEncoder().encodeToString(message.getBytes("utf-8"));
byte[] encrypted = c.doFinal(encoded.getBytes());
String encryptedString = Base64.getEncoder().encodeToString(encrypted);
// Send the encrypted message
out.println(encryptedString);
out.flush();
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException
| BadPaddingException | UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
我的 Client.java 文件如下所示:
public class Client {
private Socket socket; // Socket
private BufferedReader in; // Reading from stream
private PrintWriter out; // Writing to stream
private Key key; // AES key
// Constructor
public Client() {
try {
// Create streams to server
socket = new Socket("127.0.0.1", 12345);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// Generate an RSA key pair
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair kp = keyGen.generateKeyPair();
// Send out our public key to the server
byte[] publicKey = kp.getPublic().getEncoded();
sendUnencrypted(Base64.getEncoder().encodeToString(publicKey));
// Recieve and decrypt the AES key sent from the server
String encryptedKey = receiveUnencrypted();
Cipher c = Cipher.getInstance("RSA");
c.init(Cipher.DECRYPT_MODE, kp.getPrivate());
byte[] AESKey = c.doFinal(encryptedKey.getBytes());
key = new SecretKeySpec(AESKey, 0, AESKey.length, "AES");
} catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
| IllegalBlockSizeException | BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// Receive an unencrypted message
public String receiveUnencrypted() {
try {
// Wait until the stream is ready to be read
while (true)
if (in.ready())
break;
return in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
// Send an unencrypted message
public void sendUnencrypted(String message) {
out.println(message);
out.flush();
}
// Receive an encrypted message
public String receive() {
try {
// Wait until the stream is ready to be read
while (true)
if (in.ready())
break;
// Obtain the encrypted message
String encrypted = in.readLine();
// Decrypt and return the message
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.DECRYPT_MODE, key);
byte[] decoded = Base64.getDecoder().decode(encrypted);
String utf8 = new String(c.doFinal(decoded));
String plaintext = new String(Base64.getDecoder().decode(utf8));
// Return the message
return plaintext;
} catch (IOException | InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException
| IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
return null;
}
}
Start.java用于初始化服务器和客户端。
package test;
import java.util.Scanner;
public class Start {
public static void main(String args[]) {
Scanner scan = new Scanner(System.in);
System.out.println("1.) Create data server.\n2.) Connect to data server.\nPlease select an option: ");
int option = scan.nextInt();
if (option == 1) { // Setup a server if they choose option one
Server s = new Server();
s.send("Hello");
} else if (option == 2) { // Setup a client if they choose option two
Client c = new Client();
System.out.println(c.receive());
}
// Close scanner
scan.close();
}
}
首先,您不能使用 SecretKeySpec
来恢复 RSA public 密钥。在 Server
的构造函数中,更改
Key clientRSAKey = new SecretKeySpec(encodedClientKey, 0, encodedClientKey.length, "RSA");
到
Key clientRSAKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(encodedClientKey));
其次,您需要对base64编码的加密密钥进行解码。在您的 Client
构造函数中,更改
String encryptedKey = receiveUnencrypted();
到
byte[] encryptedKey = Base64.getDecoder().decode(receiveUnencrypted());
最后,在您的 Client
构造函数中,更改
byte[] AESKey = c.doFinal(encryptedKey.getBytes());
到
byte[] AESKey = c.doFinal(encryptedKey);