使用RSA交换Java AES密钥期间抛出java.security.InvalidKeyException

TigerThePredator:

我正在尝试使用Java编写客户端/服务器程序,该程序允许服务器将使用AES加密的消息发送到客户端。现在,我在创建密钥交换协议时遇到了问题。该密钥交换流的工作方式是:

  1. 客户端生成RSA公钥/私钥对
  2. 客户端将其RSA公钥发送到服务器
  3. 服务器使用客户端的RSA公钥生成并加密AES密钥
  4. 服务器将加密的AES密钥发送到客户端
  5. 双方现在都具有正确的AES密钥,并且可以使用AES加密所有消息

但是,每次进入第三步时,我都无法使用客户端的RSA公钥对生成的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();
    }
}
zhh:

首先,您不能用于SecretKeySpec还原RSA公钥。在您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);

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

java.security.InvalidKeyException:无效的密钥格式

java.security.InvalidKeyException:参数丢失

初始化密码时,Java密码抛出异常:java.security.InvalidKeyException:密钥大小非法

java.security.InvalidKeyException:解密期间密钥大小错误

获取异常java.security.InvalidKeyException:无效的AES密钥长度:29个字节?

java.security.InvalidKeyException:密钥大小错误

Android XML RSA,错误:java.security.InvalidKeyException:传递给RSA的未知密钥类型

是什么导致错误“ java.security.InvalidKeyException:参数丢失”?

java.security.InvalidKeyException:错误的算法:需要DESede或TripleDES

线程“主”中的异常java.security.InvalidKeyException:密钥大小非法。密钥的char长度为44

InvalidKeyException:无效的密钥格式Java

Java 1.7 + JSCH:java.security.InvalidKeyException:此算法的密钥太长

java.security.InvalidKeyException:从PEM文件生成公共私钥时的无效密钥格式

java.security.InvalidKeyException:Android中的密钥大小或默认参数非法

得到 java.security.InvalidKeyException: IOException: ObjectIdentifier() -- 数据不是对象 ID (tag = -96)

Java 11 - 橢圓曲線私鑰 - java.security.InvalidKeyException: IOException : DER input, Integer tag error

InvalidKeyException密钥大小非法

InvalidKeyException: 无效的密钥格式

JAVA 11 - 橢圓曲線私鑰 - 引起:java.security.InvalidKeyException:IOException:版本不匹配:(支持:00,解析:01

InvalidKeyException:非法密钥大小-加密类的Java代码引发异常-如何解决?

InvalidKeyException:从Java中的PEM文件读取EC私钥时,密钥格式无效

InvalidKeyException:密钥库操作在Android设备上的RSA解密上失败

使用MSCAPI和IAIK的InvalidKeyException

使用RSA进行AES密钥交换的AES加密通信

Spring saml:密钥太长,无法解包:invalidkeyexception

get()期间的Java HashMap密钥交换

Java的RSA与套接字连接交换密钥

Java中与RSA进行3DES密钥交换

将SHA1和RSA与java.security.Signature和MessageDigest和Cipher结合使用