使用ObjectOutputStream发送公钥的字节数组,加密某些内容,然后发回加密版本

时间:2017-05-29 12:45:49

标签: java encryption rsa

所以我有一个服务器端公钥和私钥,我的目的是向客户端发送公钥,客户端将使用密钥加密字符串,然后通过流发送字节,服务器将解密字节数组。

例外:

  

javax.crypto.BadPaddingException:解密错误

代码:

发送编码密钥。

                    handler.getOos().writeObject(publicKey.getEncoded());
                    handler.getOos().flush();

接收(编码密钥的)字节数组:

                        Object o = ois.readObject();
                        if (o instanceof byte[]) {
                            JChat.get().setServerPublicKey(KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec((byte[]) o)));
                            JChat.get().go();
                        }

go()方法(这里我使用DataOutputStream发送字节数组):

public void go() {
    String text = "hello darkness my old friend";
    byte[] encrypted = encrypt(text, serverPublicKey);
    try {
        handler.getDos().write(encrypted);
        handler.getDos().flush();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

在服务器端读取字节数组:

                        int count = dis.available();
                        byte[] in = new byte[count];
                        dis.readFully(in);
                        System.out.println(Server.decrypt(in, Server.get().getPrivateKey()));

解密方法抛出此异常:

javax.crypto.BadPaddingException: Decryption error
at sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:380)
at sun.security.rsa.RSAPadding.unpad(RSAPadding.java:291)
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:363)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:389)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at com.archiepking.Server.decrypt(Server.java:97)
at com.archiepking.net.ClientHandler$1.run(ClientHandler.java:44)
at java.lang.Thread.run(Thread.java:745)

关于我做错了什么的任何建议?请注意:

  

Dos = DataOutputStream Dis = DataInputStream Oos = ObjectOutputStream   Ois = ObjectInputStream

我使用两个不同的套接字,一个用于发送对象,另一个用于数据类型(因为我的聊天应用程序需要两个)。

我该怎么做才能解决此错误?

更多信息: 生成密钥:

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.genKeyPair();
        byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
        FileOutputStream fosPublic = new FileOutputStream("public");
        fosPublic.write(publicKeyBytes);
        fosPublic.close();

        byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
        FileOutputStream fosPrivate = new FileOutputStream("private");
        fosPrivate.write(privateKeyBytes);
        fosPrivate.close();

        publicKey = keyPair.getPublic();
        privateKey = keyPair.getPrivate();

2 个答案:

答案 0 :(得分:1)

问题是您使用DataInputStream.available()来确定要读取的字节数。那个方法不会做你显然认为它做的事情

从这个方法的Javadoc:

  

返回可读取的字节数的估计值(或   跳过此输入流而不会被下一个阻塞   此输入流的方法的调用者。下一个来电者可能是   相同的线程或另一个线程。单读或跳过这么多   字节不会阻塞,但可以读取或跳过更少的字节。

它只返回可以读取无阻塞的字节数,这可能远远小于您发送的实际字节数,特别是如果您使用网络套接字发送/接收那个数据。

解决方案:

  • 在写入字节之前,使用包含您正在编写的字节数的int方法编写writeInt
  • 在读取字节之前,调用readInt来读取将要跟随的字节数,并从该数字构造一个正确长度的字节数组。

答案 1 :(得分:0)

如果您正在使用ObjectOutputStream,为什么还要使用getEncoded将公钥转换为字节数组呢?您可以直接序列化对象。例如  。handler.getOos()的writeObject(公钥); 或者,如果必须使用编码版本,则删除ObjectOutputStream并改为使用ByteArrayOutputStream。