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

org.apache.commons.crypto.stream.CryptoOutputStream Maven / Gradle / Ivy

Go to download

Apache Commons Crypto is a cryptographic library optimized with AES-NI (Advanced Encryption Standard New Instructions). It provides Java API for both cipher level and Java stream level. Developers can use it to implement high performance AES encryption/decryption with the minimum code and effort. Please note that Crypto doesn't implement the cryptographic algorithm such as AES directly. It wraps to OpenSSL or JCE which implement the algorithms. Features -------- 1. Cipher API for low level cryptographic operations. 2. Java stream API (CryptoInputStream/CryptoOutputStream) for high level stream encryption/decryption. 3. Both optimized with high performance AES encryption/decryption. (1400 MB/s - 1700 MB/s throughput in modern Xeon processors). 4. JNI-based implementation to achieve comparable performance to the native C/C++ version based on OpenSsl. 5. Portable across various operating systems (currently only Linux/MacOSX/Windows); Apache Commons Crypto loads the library according to your machine environment (it checks system properties, `os.name` and `os.arch`). 6. Simple usage. Add the commons-crypto-(version).jar file to your classpath. Export restrictions ------------------- This distribution includes cryptographic software. The country in which you currently reside may have restrictions on the import, possession, use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check your country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted. See <http://www.wassenaar.org/> for more information. The U.S. Government Department of Commerce, Bureau of Industry and Security (BIS), has classified this software as Export Commodity Control Number (ECCN) 5D002.C.1, which includes information security software using or performing cryptographic functions with asymmetric algorithms. The form and manner of this Apache Software Foundation distribution makes it eligible for export under the License Exception ENC Technology Software Unrestricted (TSU) exception (see the BIS Export Administration Regulations, Section 740.13) for both object code and source code. The following provides more details on the included cryptographic software: * Commons Crypto use [Java Cryptography Extension](http://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html) provided by Java * Commons Crypto link to and use [OpenSSL](https://www.openssl.org/) ciphers

The newest version!
 /*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.commons.crypto.stream;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Objects;
import java.util.Properties;

import javax.crypto.Cipher;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.IvParameterSpec;

import org.apache.commons.crypto.cipher.CryptoCipher;
import org.apache.commons.crypto.stream.output.ChannelOutput;
import org.apache.commons.crypto.stream.output.Output;
import org.apache.commons.crypto.stream.output.StreamOutput;
import org.apache.commons.crypto.utils.Utils;

/**
 * {@link CryptoOutputStream} encrypts data and writes to the under layer
 * output. It supports any mode of operations such as AES CBC/CTR/GCM mode in
 * concept. It is not thread-safe.
 * 

* This class should only be used with blocking sinks. Using this class to wrap * a non-blocking sink may lead to high CPU usage. *

*/ public class CryptoOutputStream extends OutputStream implements WritableByteChannel { private final byte[] oneByteBuf = new byte[1]; /** The output. */ final Output output; // package protected for access by rypto classes; do not expose further /** the CryptoCipher instance */ final CryptoCipher cipher; // package protected for access by crypto classes; do not expose further /** The buffer size. */ private final int bufferSize; /** Crypto key for the cipher. */ final Key key; // package protected for access by crypto classes; do not expose further /** the algorithm parameters */ private final AlgorithmParameterSpec params; /** Flag to mark whether the output stream is closed. */ private boolean closed; /** * Input data buffer. The data starts at inBuffer.position() and ends at * inBuffer.limit(). */ ByteBuffer inBuffer; // package protected for access by crypto classes; do not expose further /** * Encrypted data buffer. The data starts at outBuffer.position() and ends * at outBuffer.limit(). */ ByteBuffer outBuffer; // package protected for access by crypto classes; do not expose further /** * Constructs a {@link CryptoOutputStream}. * * @param output the output stream. * @param cipher the CryptoCipher instance. * @param bufferSize the bufferSize. * @param key crypto key for the cipher. * @param params the algorithm parameters. * @throws IOException if an I/O error occurs. */ protected CryptoOutputStream(final Output output, final CryptoCipher cipher, final int bufferSize, final Key key, final AlgorithmParameterSpec params) throws IOException { this.output = output; this.bufferSize = CryptoInputStream.checkBufferSize(cipher, bufferSize); this.cipher = cipher; this.key = key; this.params = params; if (!(params instanceof IvParameterSpec)) { // other AlgorithmParameterSpec such as GCMParameterSpec is not // supported now. throw new IOException("Illegal parameters"); } inBuffer = ByteBuffer.allocateDirect(this.bufferSize); outBuffer = ByteBuffer.allocateDirect(this.bufferSize + cipher.getBlockSize()); initCipher(); } /** * Constructs a {@link CryptoOutputStream}. * * @param outputStream the output stream. * @param cipher the CryptoCipher instance. * @param bufferSize the bufferSize. * @param key crypto key for the cipher. * @param params the algorithm parameters. * @throws IOException if an I/O error occurs. */ @SuppressWarnings("resource") // Closing the instance closes the StreamOutput protected CryptoOutputStream(final OutputStream outputStream, final CryptoCipher cipher, final int bufferSize, final Key key, final AlgorithmParameterSpec params) throws IOException { this(new StreamOutput(outputStream, bufferSize), cipher, bufferSize, key, params); } /** * Constructs a {@link CryptoOutputStream}. * * @param transformation the name of the transformation, e.g., * AES/CBC/PKCS5Padding. * See the Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard transformation names. * @param properties The {@code Properties} class represents a set of * properties. * @param outputStream the output stream. * @param key crypto key for the cipher. * @param params the algorithm parameters. * @throws IOException if an I/O error occurs. */ @SuppressWarnings("resource") // The CryptoCipher returned by getCipherInstance() is closed by CryptoOutputStream. public CryptoOutputStream(final String transformation, final Properties properties, final OutputStream outputStream, final Key key, final AlgorithmParameterSpec params) throws IOException { this(outputStream, Utils.getCipherInstance(transformation, properties), CryptoInputStream.getBufferSize(properties), key, params); } /** * Constructs a {@link CryptoOutputStream}. * * @param transformation the name of the transformation, e.g., * AES/CBC/PKCS5Padding. * See the Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard transformation names. * @param properties The {@code Properties} class represents a set of * properties. * @param out the WritableByteChannel instance. * @param key crypto key for the cipher. * @param params the algorithm parameters. * @throws IOException if an I/O error occurs. */ @SuppressWarnings("resource") // The CryptoCipher returned by getCipherInstance() is closed by CryptoOutputStream. public CryptoOutputStream(final String transformation, final Properties properties, final WritableByteChannel out, final Key key, final AlgorithmParameterSpec params) throws IOException { this(out, Utils.getCipherInstance(transformation, properties), CryptoInputStream .getBufferSize(properties), key, params); } /** * Constructs a {@link CryptoOutputStream}. * * @param channel the WritableByteChannel instance. * @param cipher the cipher instance. * @param bufferSize the bufferSize. * @param key crypto key for the cipher. * @param params the algorithm parameters. * @throws IOException if an I/O error occurs. */ @SuppressWarnings("resource") // Closing the instance closes the ChannelOutput protected CryptoOutputStream(final WritableByteChannel channel, final CryptoCipher cipher, final int bufferSize, final Key key, final AlgorithmParameterSpec params) throws IOException { this(new ChannelOutput(channel), cipher, bufferSize, key, params); } /** * Checks whether the stream is closed. * * @throws IOException if an I/O error occurs. */ protected void checkStream() throws IOException { if (closed) { throw new IOException("Stream closed"); } } /** * Overrides the {@link OutputStream#close()}. Closes this output stream and * releases any system resources associated with this stream. * * @throws IOException if an I/O error occurs. */ @Override public void close() throws IOException { if (closed) { return; } try { encryptFinal(); output.close(); freeBuffers(); cipher.close(); super.close(); } finally { closed = true; } } /** * Does the encryption, input is {@link #inBuffer} and output is * {@link #outBuffer}. * * @throws IOException if an I/O error occurs. */ protected void encrypt() throws IOException { inBuffer.flip(); outBuffer.clear(); try { cipher.update(inBuffer, outBuffer); } catch (final ShortBufferException e) { throw new IOException(e); } inBuffer.clear(); outBuffer.flip(); // write to output while (outBuffer.hasRemaining()) { output.write(outBuffer); } } /** * Does final encryption of the last data. * * @throws IOException if an I/O error occurs. */ protected void encryptFinal() throws IOException { inBuffer.flip(); outBuffer.clear(); try { cipher.doFinal(inBuffer, outBuffer); } catch (final GeneralSecurityException e) { throw new IOException(e); } inBuffer.clear(); outBuffer.flip(); // write to output while (outBuffer.hasRemaining()) { output.write(outBuffer); } } /** * Overrides the {@link OutputStream#flush()}. To flush, we need to encrypt * the data in the buffer and write to the underlying stream, then do the * flush. * * @throws IOException if an I/O error occurs. */ @Override public void flush() throws IOException { checkStream(); encrypt(); output.flush(); super.flush(); } /** Forcibly free the direct buffers. */ protected void freeBuffers() { CryptoInputStream.freeDirectBuffer(inBuffer); CryptoInputStream.freeDirectBuffer(outBuffer); } /** * Gets the buffer size. * * @return the buffer size. */ protected int getBufferSize() { return bufferSize; } /** * Gets the internal Cipher. * * @return the cipher instance. */ protected CryptoCipher getCipher() { return cipher; } /** * Gets the inBuffer. * * @return the inBuffer. */ protected ByteBuffer getInBuffer() { return inBuffer; } /** * Gets the outBuffer. * * @return the outBuffer. */ protected ByteBuffer getOutBuffer() { return outBuffer; } /** * Initializes the cipher. * * @throws IOException if an I/O error occurs. */ protected void initCipher() throws IOException { try { cipher.init(Cipher.ENCRYPT_MODE, key, params); } catch (final GeneralSecurityException e) { throw new IOException(e); } } /** * Overrides the {@link java.nio.channels.Channel#isOpen()}. Tells whether or not this channel * is open. * * @return {@code true} if, and only if, this channel is open */ @Override public boolean isOpen() { return !closed; } /** * Overrides the {@link java.io.OutputStream#write(byte[], int, int)}. * Encryption is buffer based. If there is enough room in {@link #inBuffer}, * then write to this buffer. If {@link #inBuffer} is full, then do * encryption and write data to the underlying stream. * * @param array the data. * @param off the start offset in the data. * @param len the number of bytes to write. * @throws IOException if an I/O error occurs. */ @Override public void write(final byte[] array, int off, int len) throws IOException { checkStream(); Objects.requireNonNull(array, "array"); final int arrayLength = array.length; if (off < 0 || len < 0 || off > arrayLength || len > arrayLength - off) { throw new IndexOutOfBoundsException(); } while (len > 0) { final int remaining = inBuffer.remaining(); if (len < remaining) { inBuffer.put(array, off, len); len = 0; } else { inBuffer.put(array, off, remaining); off += remaining; len -= remaining; encrypt(); } } } /** * Overrides the * {@link java.nio.channels.WritableByteChannel#write(ByteBuffer)}. Writes a * sequence of bytes to this channel from the given buffer. * * @param src The buffer from which bytes are to be retrieved. * @return The number of bytes written, possibly zero. * @throws IOException if an I/O error occurs. */ @Override public int write(final ByteBuffer src) throws IOException { checkStream(); final int len = src.remaining(); int remaining = len; while (remaining > 0) { final int space = inBuffer.remaining(); if (remaining < space) { inBuffer.put(src); remaining = 0; } else { // to void copy twice, we set the limit to copy directly final int oldLimit = src.limit(); final int newLimit = src.position() + space; src.limit(newLimit); inBuffer.put(src); // restore the old limit src.limit(oldLimit); remaining -= space; encrypt(); } } return len; } /** * Overrides the {@link java.io.OutputStream#write(byte[])}. Writes the * specified byte to this output stream. * * @param b the data. * @throws IOException if an I/O error occurs. */ @Override public void write(final int b) throws IOException { oneByteBuf[0] = (byte) (b & 0xff); write(oneByteBuf, 0, oneByteBuf.length); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy