Home | History | Annotate | Download | only in crypto
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package javax.crypto;
     19 
     20 import java.io.FilterOutputStream;
     21 import java.io.IOException;
     22 import java.io.OutputStream;
     23 import libcore.io.Streams;
     24 
     25 /**
     26  * This class wraps an output stream and a cipher so that {@code write} methods
     27  * send the data through the cipher before writing them to the underlying output
     28  * stream.
     29  * <p>
     30  * The cipher must be initialized for the requested operation before being used
     31  * by a {@code CipherOutputStream}. For example, if a cipher initialized for
     32  * encryption is used with a {@code CipherOutputStream}, the {@code
     33  * CipherOutputStream} tries to encrypt the data writing it out.
     34  */
     35 public class CipherOutputStream extends FilterOutputStream {
     36 
     37     private final Cipher cipher;
     38 
     39     /**
     40      * Creates a new {@code CipherOutputStream} instance for an {@code
     41      * OutputStream} and a {@code Cipher}.
     42      *
     43      * @param os
     44      *            the output stream to write data to.
     45      * @param c
     46      *            the cipher to process the data with.
     47      */
     48     public CipherOutputStream(OutputStream os, Cipher c) {
     49         super(os);
     50         cipher = c;
     51     }
     52 
     53     /**
     54      * Creates a new {@code CipherOutputStream} instance for an {@code
     55      * OutputStream} without a cipher.
     56      * <p>
     57      * A {@code NullCipher} is created to process the data.
     58      *
     59      * @param os
     60      *            the output stream to write the data to.
     61      */
     62     protected CipherOutputStream(OutputStream os) {
     63         this(os, new NullCipher());
     64     }
     65 
     66     /**
     67      * Writes the single byte to this cipher output stream.
     68      *
     69      * @param b
     70      *            the byte to write.
     71      * @throws IOException
     72      *             if an error occurs.
     73      */
     74     @Override public void write(int b) throws IOException {
     75         Streams.writeSingleByte(this, b);
     76     }
     77 
     78     /**
     79      * Writes the {@code len} bytes from buffer {@code b} starting at offset
     80      * {@code off} to this cipher output stream.
     81      *
     82      * @param b
     83      *            the buffer.
     84      * @param off
     85      *            the offset to start at.
     86      * @param len
     87      *            the number of bytes.
     88      * @throws IOException
     89      *             if an error occurs.
     90      */
     91     @Override public void write(byte[] b, int off, int len) throws IOException {
     92         if (len == 0) {
     93             return;
     94         }
     95         byte[] result = cipher.update(b, off, len);
     96         if (result != null) {
     97             out.write(result);
     98         }
     99     }
    100 
    101     /**
    102      * Flushes this cipher output stream.
    103      *
    104      * @throws IOException
    105      *             if an error occurs
    106      */
    107     @Override
    108     public void flush() throws IOException {
    109         out.flush();
    110     }
    111 
    112     /**
    113      * Close this cipher output stream.
    114      * <p>
    115      * On the underlying cipher {@code doFinal} will be invoked, and any
    116      * buffered bytes from the cipher are also written out, and the cipher is
    117      * reset to its initial state. The underlying output stream is also closed.
    118      *
    119      * @throws IOException
    120      *             if an error occurs.
    121      */
    122     @Override
    123     public void close() throws IOException {
    124         byte[] result;
    125         try {
    126             if (cipher != null) {
    127                 result = cipher.doFinal();
    128                 if (result != null) {
    129                     out.write(result);
    130                 }
    131             }
    132             if (out != null) {
    133                 out.flush();
    134             }
    135         } catch (BadPaddingException e) {
    136             throw new IOException(e.getMessage());
    137         } catch (IllegalBlockSizeException e) {
    138             throw new IOException(e.getMessage());
    139         } finally {
    140             if (out != null) {
    141                 out.close();
    142             }
    143         }
    144     }
    145 }
    146