javax.crypto.BadPaddingException:数据必须以零开头,客户端无法从服务器解密

javax.crypto.BadPaddingException:数据必须以零开头,客户端无法从服务器解密,java,encryption,cryptography,rsa,public-key-encryption,Java,Encryption,Cryptography,Rsa,Public Key Encryption,运行代码时出现编译错误 Error: javax.crypto.BadPaddingException: Data must start with zero 在这一行testClient.java byte[] newPlainText = cipher.doFinal(cipherTextFromServer); 客户端无法解密从服务器加密的消息。 我的代码有错误吗 //TestServer.java public class TestServer { public static voi

运行代码时出现编译错误

Error: javax.crypto.BadPaddingException: Data must start with zero
在这一行testClient.java

byte[] newPlainText = cipher.doFinal(cipherTextFromServer);
客户端无法解密从服务器加密的消息。 我的代码有错误吗

//TestServer.java

public class TestServer {

public static void main(String[] args) throws Exception{
    //set variables for port number, RSA key size
    final int port = 3344;
    final int RSAKeySize = 1024;
    final String newline = "\n";
    //set public key, sockets, server text, plain text
    PublicKey pubKey = null;
    PrivateKey priKey = null;
    ServerSocket server = null;
    Socket client = null;
    String serverText = "Hello Client! This is an authentication message from server";
    byte[] plainText = serverText.getBytes("UTF8");
    //initialize RSA
    try {
        System.out.println("Start generating RSA key");
        KeyPairGenerator RSAKeyGen = KeyPairGenerator.getInstance("RSA");
        SecureRandom random = new SecureRandom();
        RSAKeyGen.initialize(RSAKeySize,random);
        KeyPair pair = RSAKeyGen.generateKeyPair();
        System.out.println("Finish generating RSA key");
        pubKey = pair.getPublic();
        priKey = pair.getPrivate();
    }catch (GeneralSecurityException e){
        System.out.println(e.getLocalizedMessage() + newline);
        System.out.println("Error initialising encryption. Exiting.\n");
        System.exit(0);
    }
    //initialize cryptography, set cipherText
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    System.out.println("RSA cipher object and provider"+cipher.getProvider().getInfo());
    System.out.println("Start Encryption for plainText");
    cipher.init(Cipher.ENCRYPT_MODE, pubKey);
    byte[] cipherText = cipher.doFinal(plainText);
    System.out.println("Finish Encryption to cipherText: ");
    BASE64Encoder base64 = new BASE64Encoder();
    String encryptedValue = base64.encode(cipherText);
    //String encryptedValue = new sun.misc.BASE64Encoder().encode(cipherText);
    System.out.println(new String(cipherText,"UTF8"));
    System.out.println("Base64");
    System.out.println(encryptedValue);
    //initialize socket connection
    try{
        server = new ServerSocket(port);
        client = server.accept();
    }catch(IOException e){
        System.out.println("Error initialising I/O.\n");
        System.exit(0);
    }
    //send server private key
    try{
        System.out.println("Send private key out");
        System.out.println(DatatypeConverter.printHexBinary(priKey.getEncoded()));
        ByteBuffer bb = ByteBuffer.allocate(4);
        bb.putInt(priKey.getEncoded().length);
        client.getOutputStream().write(bb.array());
        client.getOutputStream().write(pubKey.getEncoded());
        client.getOutputStream().flush();
    }catch (IOException e){
        System.out.println("I/O Error");
        System.exit(0);
    }
    //send cipherText
    ObjectOutputStream obOut = new ObjectOutputStream(client.getOutputStream());
    obOut.writeObject(encryptedValue);
    obOut.flush();
    client.close();
}
}

//TestClient.java

public class TestClient {

public static void main(String[] args){ 
    //throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, ClassNotFoundException, 
    //InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
    //set variable for port, socket, server public key
    final int port = 3344;
    Socket sock = null;
    Key serverPubKey = null;
    final int RSAKeySize = 1024;
    final String newline = "\n";
    Key priKey = null;
    //setup connection by creating socket
    try{
        sock = new Socket(InetAddress.getLocalHost(),port);
    }catch(UnknownHostException e){
        System.out.println("Unknown host.");
        System.exit(1);
    }catch(IOException e){
        System.out.println("No I/O");
        System.exit(1);
    }
    //get public key from server
    try{
        byte[] lenb = new byte[4];
        sock.getInputStream().read(lenb,0,4);
        ByteBuffer bb = ByteBuffer.wrap(lenb);
        int len = bb.getInt();
        System.out.println(len);
        byte[] servPubKeyBytes = new byte[len];
        sock.getInputStream().read(servPubKeyBytes);
        System.out.println(DatatypeConverter.printHexBinary(servPubKeyBytes));
        X509EncodedKeySpec ks = new X509EncodedKeySpec(servPubKeyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        serverPubKey = kf.generatePublic(ks);
        System.out.println(DatatypeConverter.printHexBinary(serverPubKey.getEncoded()));
        //PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));

    }catch (IOException e) {
        System.out.println("Error obtaining server public key 1.");
        System.exit(0);
    } catch (NoSuchAlgorithmException e) {
        System.out.println("Error obtaining server public key 2.");
        System.exit(0);
    } catch (InvalidKeySpecException e) {
        System.out.println("Error obtaining server public key 3.");
        System.exit(0);
    }
    try {
        System.out.println("Start generating RSA key");
        KeyPairGenerator RSAKeyGen = KeyPairGenerator.getInstance("RSA");
        SecureRandom random = new SecureRandom();
        RSAKeyGen.initialize(RSAKeySize, random);
        KeyPair pair = RSAKeyGen.generateKeyPair();
        System.out.println("Finish generating RSA key");
        priKey = pair.getPrivate();
    }catch (GeneralSecurityException e){
        System.out.println(e.getLocalizedMessage() + newline);
        System.out.println("Error initialising encryption. Exiting.\n");
        System.exit(0);
    }
    try{
    //Decrypt message from server
        BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
        String message = in.readLine();
        //ObjectInputStream obIn = new ObjectInputStream(sock.getInputStream());
        //Object obj = obIn.readObject();
        System.out.println(message);
        byte[] cipherTextFromServer = new BASE64Decoder().decodeBuffer(message);
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        System.out.println("Start decryption");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        byte[] newPlainText = cipher.doFinal(cipherTextFromServer);
        System.out.println("Finish decryption: ");
        System.out.println(new String(newPlainText,"UTF8"));
        sock.close();
    }catch(Exception e){
        e.printStackTrace();
    }   
}

}

您的代码看起来完全崩溃了。使用服务器上生成的公钥加密数据,然后使用客户端上生成的私钥解密数据。这是行不通的,因为密钥对不匹配

为了进一步混淆问题,您似乎尝试在服务器和客户端之间发送密钥,但这看起来也坏了,例如

ByteBuffer bb = ByteBuffer.allocate(4);
bb.putInt(priKey.getEncoded().length);
client.getOutputStream().write(bb.array());
client.getOutputStream().write(pubKey.getEncoded()); // pubKey?!!

你应该彻底重新考虑你的设计。私钥通常不会集中生成并向外分发。相反,请考虑让客户端生成密钥对并将其公钥发送到服务器,服务器可以使用它来加密数据。

您的代码看起来完全被破坏了。使用服务器上生成的公钥加密数据,然后使用客户端上生成的私钥解密数据。这是行不通的,因为密钥对不匹配

为了进一步混淆问题,您似乎尝试在服务器和客户端之间发送密钥,但这看起来也坏了,例如

ByteBuffer bb = ByteBuffer.allocate(4);
bb.putInt(priKey.getEncoded().length);
client.getOutputStream().write(bb.array());
client.getOutputStream().write(pubKey.getEncoded()); // pubKey?!!

你应该彻底重新考虑你的设计。私钥通常不会集中生成并向外分发。相反,请考虑让客户端生成密钥对并将其公钥发送到服务器,服务器可以使用它来加密数据。

您忽略了<>代码>返回流(读)(< /代码>方法> < /p>的返回值。 您正在使用
ObjectOutputStream
在服务器端写入编码值,并使用
InputStreamReader
在客户端读取编码值

最终的结果是
servPubKeyBytes
cipherTextFromServer
包含一些垃圾,当您将它们传递到密码中时,它会意外中断

首先,通过测试客户端是否正确读取所有数据来修复I/O代码

其次,检查加密和解密代码是否工作,方法是在同一应用程序中使用它,而不使用任何类型的I/O


第三,将工作I/O与工作enc/dec代码结合起来。

您忽略了
InputStream.read()
方法的返回值

您正在使用
ObjectOutputStream
在服务器端写入编码值,并使用
InputStreamReader
在客户端读取编码值

最终的结果是
servPubKeyBytes
cipherTextFromServer
包含一些垃圾,当您将它们传递到密码中时,它会意外中断

首先,通过测试客户端是否正确读取所有数据来修复I/O代码

其次,检查加密和解密代码是否工作,方法是在同一应用程序中使用它,而不使用任何类型的I/O


<P>第三,将工作I/O与工作EnC/DEC代码结合。

CiffTraveServer为NULL/VALUE。你需要建立关于公钥的信任(例如使用PKI)。但是注意,只发送公钥容易受到中间人攻击;您还需要建立与公钥相关的信任(例如,通过使用PKI)。