简体   繁体   中英

Close CipherOutputStream without DataOutputStream & Socket

I'm working with Cipher where connection is being held on the underlying socket and dataoutputstream . Now according to CipherOutputStream documentation, that in order to let the final block out of the encryptor, we need to call close() . So using it with try-with-resource also closes the underlying stream which I don't want cuz I need them for further operations.

So is there any method or implementation which will help me in closing the cipheroutputstream without dataoutputstream and socket .? I heard about FilterOutputStream but I don't have any idea how to work with them.

My Code:

public class ClientHandler implements Runnable {
Socket msock;
DataInputStream dis;
DataOutputStream dos;
String ip;
private miniClientHandler(Socket msock) {
            this.msock = msock;
        }
@Override
public void run() {
    try {
        dis = new DataInputStream(msock.getInputStream());
        dos = new DataOutputStream(msock.getOutputStream());

        ip = msock.getInetAddress().getHostAddress();

        String msg = dis.readLine();
        System.out.println(msg);

        if (msg.equals("Download")) {

                    String file2dl = dis.readLine(); //2
                    File file = new File(sharedDirectory.toString() + "\\" + file2dl);
                    dos.writeLong(file.length()); //3+

                    //AES-128 bit key initialization.
                    byte[] keyvalue = "AES128BitPasswd".getBytes();
                    SecretKey key = new SecretKeySpec(keyvalue, "AES");

                    //Initialize the Cipher.
                    Cipher encCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                    encCipher.init(Cipher.ENCRYPT_MODE, key);

                    //Get the IV from cipher.
                    IvParameterSpec spec = null;
                    try {
                        spec = encCipher.getParameters().getParameterSpec(IvParameterSpec.class);
                    } catch (InvalidParameterSpecException ex) {
                        Logger.getLogger(PeersController.class.getName()).log(Level.SEVERE, null, ex);
                    }

                    byte[] iv = spec.getIV();

                    dos.write(iv, 0, iv.length); //4+

                    //Encryption Mechanism.
                    try (FileInputStream fis = new FileInputStream(file)) {
                        try (CipherOutputStream cos = new CipherOutputStream(dos, encCipher)) {
                            int read;
                            byte[] buffer = new byte[1024 * 1024];
                            while ((read = fis.read(buffer)) != -1) {
                                cos.write(buffer, 0, read); //5+ due to dos as underlying parameter of cos.
                            }
                        }
                    }

                    String message = dis.readLine();
                    System.out.println(message);
                    if (message.equals("Fetching Done")) {
                        System.out.println("Fetching Done!");
                    } else if (message.equals("Fetching Drop")) {
                        System.out.println("Fetching Denied!");
                    }
                }
            } catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) {
                System.out.println(e.getMessage());
            }
        }

    }


Now since cos is wrapped in try-with-resource, when the while loop ends, it closes the stream and the underlying dos stream which have further wrapped msock resulting the whole socket to close and my remaining code left useless.

Leftover code:

    String message = dis.readLine();
    System.out.println(message);
    if (message.equals("Fetching Done")) {
        System.out.println("Fetching Done!");
     } else if (message.equals("Fetching Drop")) {
                 System.out.println("Fetching Denied!");
     }

I somehow manage to solve my problem myself with the help of @EJP recommendation to create my own Cipher object via update() & doFinal() .

Code:

//Encryption Mechanism.
  try (FileInputStream fis = new FileInputStream(file)) {

       byte[] buffer = new byte[1024 * 1024];
       byte[] cipherBlock = new byte[encCipher.getOutputSize(buffer.length)];
       int cipherBytes;
       int read;
       while ((read = fis.read(buffer)) != -1) {
              cipherBytes = encCipher.update(buffer, 0, read, cipherBlock);
              dos.write(cipherBlock, 0, cipherBytes);
        }
        cipherBytes = encCipher.doFinal(cipherBlock, 0); //let out the last block out of the encryptor.
        dos.write(cipherBlock, 0, cipherBytes);
     } catch (ShortBufferException | IllegalBlockSizeException | BadPaddingException ex) {
              Logger.getLogger(PeersController.class.getName()).log(Level.SEVERE, null, ex);
       }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM