• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
CipherOutputStream(OutputStream os, Cipher c)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      */
CipherOutputStream(OutputStream os)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      */
write(int b)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      */
write(byte[] b, int off, int len)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
flush()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
close()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