DataOutputStream仅在关闭时发送

时间:2018-04-12 18:45:48

标签: java

当我在没有close方法的情况下运行此代码时,服务器无法接收消息!

客户端:

        Socket con = new Socket(InetAddress.getByName("localhost"), 12345);

        InputStream is = con.getInputStream();
        OutputStream os = con.getOutputStream();

        byte[] key = new byte[]{5};

        DataOutputStream dos = EncryptIO.getEncryptedOutputStream(key, os);
        DataInputStream dis = EncryptIO.getEncryptedInputStream(key, is);

        dos.writeUTF("Player 2");
        dos.close(); //with this the server receives the message
        String opUsername = dis.readUTF();

服务器:

        ServerSocket serverSocket = new ServerSocket(12345);
        Socket con = serverSocket.accept();

        InputStream is = con.getInputStream();
        OutputStream os = con.getOutputStream();

        byte[] key = new byte[]{5};

        DataOutputStream dos = EncryptIO.getEncryptedOutputStream(key, os);
        DataInputStream dis = EncryptIO.getEncryptedInputStream(key, is);

        String opUsername = dis.readUTF();
        System.out.println(opUsername);

        dos.writeUTF("Player 1"); //this line isn't reached because DataInputStream waits for the data

在DataOutput / InputStream下面是Cipherstreams底层没有它们可以工作!

EncryptIO代码:

public static DataInputStream getEncryptedInputStream(byte[] key, InputStream is) throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchPaddingException {
    try {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, EncryptIO.getAESKey(key), EncryptIO.getIV(key));
        CipherInputStream cis = new CipherInputStream(is, cipher);
        return new DataInputStream(cis);
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(EncryptIO.class.getName()).log(Level.SEVERE, null, ex);
    }
    return null;
}

public static DataOutputStream getEncryptedOutputStream(byte[] key, OutputStream os) throws InvalidKeyException, NoSuchPaddingException, InvalidAlgorithmParameterException {
    try {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, EncryptIO.getAESKey(key), EncryptIO.getIV(key));
        CipherOutputStream cos = new CipherOutputStream(os, cipher);
        return new DataOutputStream(cos);
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(EncryptIO.class.getName()).log(Level.SEVERE, null, ex);
    }
    return null;
}

如何让DataOutputStream通过加密发送数据而不关闭?

提前致谢

1 个答案:

答案 0 :(得分:2)

Cipher.getInstance("AES/CBC/PKCS5Padding")

您正在使用带有PKCS5Padding的CBC模式的AES密码。根据{{​​3}}(重新格式化,包含原始链接):

  

<强> AES

     

NIST在Java Cryptography Architecture Standard Algorithm Name Documentation for JDK 8中指定的高级加密标准。   也被称为Joan Daemen和Vincent的Rijndael算法   Rijmen,AES是128位分组密码,支持128,192和128的密钥   256位。

     

要仅使用一个有效密钥大小的AES密码,请使用该格式   AES_,其中可以是128,192或256。

  

<强> CBC

     

密码块链接模式,如FIPS 197中所定义。

  

<强> PKCS5Padding

     

FIPS PUB 81中描述的填充方案。

因此,一个块密码,可能是128位(16字节),带填充。

请注意密码算法模式

  

CFB,CFBx

     

密码反馈模式,如RSA Laboratories, "PKCS #5: Password-Based Encryption Standard," version 1.5, November 1993中所定义。

     

使用CFB和OFB等模式,分组密码可以加密数据   单位小于密码的实际块大小。请求时   在这种模式下,您可以选择指定要的位数   通过将此数字附加到模式名称来一次处理,如图所示   在“DES / CFB8 / NoPadding”和“DES / OFB32 / PKCS5Padding”中   转换。如果未指定此类号码,则特定于提供者   使用默认值。 (例如,SunJCE提供程序使用默认值   DES的64位。)因此,块密码可以转换为面向字节的   通过使用8位模式(如CFB8或OFB8 )来流密码。

因此"AES/CFB8/NoPadding"或类似内容应该作为非阻塞流密码。但是,您可能仍需要flush()。并且可能会对性能产生影响。