All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.schlichtherle.crypto.io.CipherOutputStream Maven / Gradle / Ivy

Go to download

TrueZIP is a Java based Virtual File System (VFS) to enable transparent, multi-threaded read/write access to archive files (ZIP, TAR etc.) as if they were directories. Archive files may be arbitrarily nested and the nesting level is only limited by heap and file system size.

The newest version!
/*
 * Copyright (C) 2005-2010 Schlichtherle IT Services
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.schlichtherle.crypto.io;

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.InvalidCipherTextException;

/**
 * Similar to {@code javax.crypto.CipherOutputStream},
 * with some exceptions:
 * 
    *
  • This implementation uses Bouncy Castle's lightweight API. * In particular, a {@link BufferedBlockCipher} is used for ciphering. *
  • The {@link #cipher} used for encryption or decryption is accessible to * subclasses. *
  • The {@code flush()} method just flushes the underlying output stream * and has no effect on the cipher. *
  • A {@link #finish()} method has been added to allow finishing the output * (probably producing padding bytes) without closing the output. * This could be used in a subclass to produce a trailer with additional * information about the ciphered data (e.g. a MAC). *
* * @author Christian Schlichtherle */ public class CipherOutputStream extends FilterOutputStream { /** The buffered block cipher used for preprocessing the output. */ protected BufferedBlockCipher cipher; /** * The buffer used for preprocessing the output. * This buffer is autosized to the largest buffer written to this stream. */ private byte[] outBuf = new byte[0]; /** Whether this stream has been closed or not. */ private boolean closed; /** * Creates a new instance of CipherOutputStream. * Please note that unlike {@code javax.crypto.CipherOutputStream}, * the cipher does not need to be initialized before calling this * constructor. * However, the cipher must be initialized before anything is actually * written to this stream or before this stream is closed. * * @param out The output stream to write the encrypted or decrypted data to. * Maybe {@code null} if initialized by the subclass constructor. * @param cipher The cipher to use for encryption or decryption. * Maybe {@code null} for subsequent initialization by a subclass. */ public CipherOutputStream(OutputStream out, BufferedBlockCipher cipher) { super(out); this.cipher = cipher; } /** * Ciphers and writes the given byte to the underlying output stream. * * @param b The byte to cipher and write. * * @throws IOException If out or cipher aren't properly initialized, * the stream has been closed or an I/O error occured. */ public void write(final int b) throws IOException { ensureInit(); int outLen = cipher.getUpdateOutputSize(1); if (outLen > outBuf.length) outBuf = new byte[outLen]; outLen = cipher.processByte((byte) b, outBuf, 0); if (outLen > 0) out.write(outBuf, 0, outLen); } /** * Ciphers and writes the contents of the given byte array to the * underlying output stream. * * @param buf The buffer holding the data to cipher and write. * @param off The start offset in the data buffer. * @param len The number of bytes to cipher and write. * * @throws IOException If out or cipher aren't properly initialized, * the stream has been closed or an I/O error occured. */ public void write(final byte[] buf, final int off, final int len) throws IOException { ensureInit(); int outLen = cipher.getUpdateOutputSize(len); if (outLen > outBuf.length) outBuf = new byte[outLen]; outLen = cipher.processBytes(buf, off, len, outBuf, 0); out.write(outBuf, 0, outLen); } /** * Finishes this stream and resets it to it's initial state. * Calling this method causes all remaining buffered bytes to be written, * padding to be added if necessary and the underlying output stream to * get flushed. *

* Please note that subsequent calls to any write operations after this * method may cause an error in the output data if padding is used! * * @throws IOException If out or cipher aren't properly initialized, * the stream has been closed, an I/O error occured the cipher * text is invalid, i.e. required padding information is missing. */ public void finish() throws IOException { ensureInit(); int outLen = cipher.getOutputSize(0); if (outLen > outBuf.length) outBuf = new byte[outLen]; try { outLen = cipher.doFinal(outBuf, 0); } catch (InvalidCipherTextException icte) { IOException ioe = new IOException(icte.toString()); ioe.initCause(icte); throw ioe; } out.write(outBuf, 0, outLen); out.flush(); //outBuf = new byte[0]; } /** * Ensures that this stream is open and has been initialized. * * @throws IOException If the preconditions do not hold. */ private final void ensureInit() throws IOException { if (cipher == null) throw new IOException("CipherOutputStream has already been closed or is not initialized!"); } /** * Closes this output stream and releases any resources associated with it. * This method calls {@link #finish()} and then closes and nullifies * the underlying output stream {@link #out} and the cipher {@link #cipher}. * * @throws IOException If an I/O error occurs. */ public void close() throws IOException { // Order is important here! if (!closed) { closed = true; try { finish(); } finally { cipher = null; super.close(); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy