How can I force a CipherOutputStream to finish encrypting but leave the underlying stream open?
Asked Answered
T

3

8

I have a CipherOutputStream backed by another OutputStream. After I have finished writing all the data I need encrypted to the CipherOutputStream, I need to append some unencrypted data.

The documentation for CipherOutputStream says that calling flush() will not force the final block out of the encryptor; for that I need to call close(). But close() also closes the underlying OutputStream, which I still need to write more to.

How can I force the last block out of the encryptor without closing the stream? Do I need to write my own NonClosingCipherOutputStream?

Talkathon answered 27/3, 2011 at 12:7 Comment(0)
B
8

If you don't have a reference to the Cipher, you could pass a FilterOutputStream to the method that creates the CipherOutputStream. In the FilterOutputStream, override the close method so that it doesn't actually close the stream.

Blockus answered 27/3, 2011 at 12:59 Comment(1)
I would use this answer as the basic for creating something like your NonClosingCipherOutputStream, but inspired by the example of DigestOutputStream.on(...) I would create a cipherFinish() method after which the stream simply passes data onto the underlying os.Gripe
E
2

maybe you can wrap your outputstream before putting into an cipheroutputstream

/**
 * Represents an {@code OutputStream} that does not close the underlying output stream on a call to {@link #close()}.
 * This may be useful for encapsulating an {@code OutputStream} into other output streams that does not have to be
 * closed, while closing the outer streams or reader.
 */
public class NotClosingOutputStream extends OutputStream {

    /** The underlying output stream. */
    private final OutputStream out;

    /**
     * Creates a new output stream that does not close the given output stream on a call to {@link #close()}.
     * 
     * @param out
     *            the output stream
     */
    public NotClosingOutputStream(final OutputStream out) {
        this.out = out;
    }

    /*
     * DELEGATION TO OUTPUT STREAM
     */

    @Override
    public void close() throws IOException {
        // do nothing here, since we don't want to close the underlying input stream
    }

    @Override
    public void write(final int b) throws IOException {
        out.write(b);
    }

    @Override
    public void write(final byte[] b) throws IOException {
        out.write(b);
    }

    @Override
    public void write(final byte[] b, final int off, final int len) throws IOException {
        out.write(b, off, len);
    }

    @Override
    public void flush() throws IOException {
        out.flush();
    }
}

hope that helps

Eris answered 16/8, 2013 at 0:5 Comment(0)
K
0

If you have a reference to the Cipher object that the CipherOutputStream wraps, you should be able to do what CipherOutputStream.close() does:

Call Cipher.doFinal, then flush() the CiperOutputStream, and continue.

Kreindler answered 27/3, 2011 at 12:21 Comment(1)
So I voted this up initially because it seemed like a good idea, but it's not. cipher.doFinal() returns the same bytes over and over, so if you do manually insert them into the output stream, then write more stuff, and eventually close the CipherOutputStream, they are inserted again.Talkathon

© 2022 - 2024 — McMap. All rights reserved.