View Javadoc
1    /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.commons.crypto.cipher;
19  
20  import java.nio.ByteBuffer;
21  import java.security.GeneralSecurityException;
22  import java.security.InvalidAlgorithmParameterException;
23  import java.security.InvalidKeyException;
24  import java.security.Key;
25  import java.security.spec.AlgorithmParameterSpec;
26  import java.util.Objects;
27  import java.util.Properties;
28  
29  import javax.crypto.BadPaddingException;
30  import javax.crypto.Cipher;
31  import javax.crypto.IllegalBlockSizeException;
32  import javax.crypto.ShortBufferException;
33  
34  /**
35   * Implements the {@link CryptoCipher} using JCE provider.
36   * <p>
37   * This class is not public/protected so does not appear in the main Javadoc. Please ensure that property use is documented in the enum
38   * CryptoRandomFactory.RandomProvider
39   * </p>
40   */
41  class JceCipher implements CryptoCipher {
42      private final Cipher cipher;
43  
44      /**
45       * Constructs a {@link CryptoCipher} based on JCE Cipher {@link Cipher}.
46       *
47       * @param props  properties for JCE cipher (only uses {@link CryptoCipherFactory#JCE_PROVIDER_KEY})
48       * @param transformation  transformation for JCE cipher (algorithm/mode/padding)
49       * @throws GeneralSecurityException if JCE cipher initialize failed
50       */
51      public JceCipher(final Properties props, final String transformation)
52              throws GeneralSecurityException {
53          final String provider = props.getProperty(CryptoCipherFactory.JCE_PROVIDER_KEY, "");
54          cipher = provider.isEmpty() ? Cipher.getInstance(transformation) : Cipher.getInstance(transformation, provider);
55      }
56  
57      /**
58       * Closes Jce cipher.
59       */
60      @Override
61      public void close() {
62          // Do nothing
63      }
64  
65      /**
66       * Encrypts or decrypts data in a single-part operation, or finishes a
67       * multiple-part operation.
68       *
69       * @param input the input byte array
70       * @param inputOffset the offset in input where the input starts
71       * @param inputLen the input length
72       * @param output the byte array for the result
73       * @param outputOffset the offset in output where the result is stored
74       * @return the number of bytes stored in output
75       * @throws ShortBufferException if the given output byte array is too small
76       *         to hold the result
77       * @throws BadPaddingException if this cipher is in decryption mode, and
78       *         (un)padding has been requested, but the decrypted data is not
79       *         bounded by the appropriate padding bytes
80       * @throws IllegalBlockSizeException if this cipher is a block cipher, no
81       *         padding has been requested (only in encryption mode), and the
82       *         total input length of the data processed by this cipher is not a
83       *         multiple of block size; or if this encryption algorithm is unable
84       *         to process the input data provided.
85       */
86      @Override
87      public int doFinal(final byte[] input, final int inputOffset, final int inputLen,
88              final byte[] output, final int outputOffset) throws ShortBufferException,
89              IllegalBlockSizeException, BadPaddingException {
90          return cipher.doFinal(input, inputOffset, inputLen, output,
91                  outputOffset);
92      }
93  
94      /**
95       * Encrypts or decrypts data in a single-part operation, or finishes a
96       * multiple-part operation. The data is encrypted or decrypted, depending on
97       * how this cipher was initialized.
98       *
99       * @param inBuffer the input ByteBuffer
100      * @param outBuffer the output ByteBuffer
101      * @return int number of bytes stored in {@code output}
102      * @throws BadPaddingException if this cipher is in decryption mode, and
103      *         (un)padding has been requested, but the decrypted data is not
104      *         bounded by the appropriate padding bytes
105      * @throws IllegalBlockSizeException if this cipher is a block cipher, no
106      *         padding has been requested (only in encryption mode), and the
107      *         total input length of the data processed by this cipher is not a
108      *         multiple of block size; or if this encryption algorithm is unable
109      *         to process the input data provided.
110      * @throws ShortBufferException if the given output buffer is too small to
111      *         hold the result
112      */
113     @Override
114     public int doFinal(final ByteBuffer inBuffer, final ByteBuffer outBuffer)
115             throws ShortBufferException, IllegalBlockSizeException,
116             BadPaddingException {
117         return cipher.doFinal(inBuffer, outBuffer);
118     }
119 
120     /**
121      * Returns the algorithm name of this {@code CryptoCipher} object.
122      *
123      * <p>
124      * This is the same name that was specified in one of the
125      * {@code CryptoCipherFactory#getInstance} calls that created this
126      * {@code CryptoCipher} object..
127      * </p>
128      *
129      * @return the algorithm name of this {@code CryptoCipher} object.
130      */
131     @Override
132     public String getAlgorithm() {
133         return cipher.getAlgorithm();
134     }
135 
136     /**
137      * Returns the block size (in bytes).
138      *
139      * @return the block size (in bytes), or 0 if the underlying algorithm is
140      * not a block cipher
141      */
142     @Override
143     public final int getBlockSize() {
144         return cipher.getBlockSize();
145     }
146 
147     /**
148      * Initializes the cipher with mode, key and iv.
149      *
150      * @param mode {@link Cipher#ENCRYPT_MODE} or {@link Cipher#DECRYPT_MODE}
151      * @param key crypto key for the cipher
152      * @param params the algorithm parameters
153      * @throws InvalidAlgorithmParameterException if the given algorithm
154      *         parameters are inappropriate for this cipher, or this cipher
155      *         requires algorithm parameters and {@code params} is null, or
156      *         the given algorithm parameters imply a cryptographic strength
157      *         that would exceed the legal limits (as determined from the
158      *         configured jurisdiction policy files).
159      */
160     @Override
161     public void init(final int mode, final Key key, final AlgorithmParameterSpec params)
162             throws InvalidKeyException, InvalidAlgorithmParameterException {
163         Objects.requireNonNull(key, "key");
164         Objects.requireNonNull(params, "params");
165 
166         // Jce uses the javax.crypto.Cipher modes; no need to convert the input
167         cipher.init(mode, key, params);
168     }
169 
170     /**
171      * Continues a multiple-part encryption/decryption operation. The data is
172      * encrypted or decrypted, depending on how this cipher was initialized.
173      *
174      * @param input the input byte array
175      * @param inputOffset the offset in input where the input starts
176      * @param inputLen the input length
177      * @param output the byte array for the result
178      * @param outputOffset the offset in output where the result is stored
179      * @return the number of bytes stored in output
180      * @throws ShortBufferException if there is insufficient space in the output
181      *         byte array
182      */
183     @Override
184     public int update(final byte[] input, final int inputOffset, final int inputLen,
185             final byte[] output, final int outputOffset) throws ShortBufferException {
186         return cipher
187                 .update(input, inputOffset, inputLen, output, outputOffset);
188     }
189 
190 
191     /**
192      * Continues a multiple-part encryption/decryption operation. The data is
193      * encrypted or decrypted, depending on how this cipher was initialized.
194      *
195      * @param inBuffer the input ByteBuffer
196      * @param outBuffer the output ByteBuffer
197      * @return int number of bytes stored in {@code output}
198      * @throws ShortBufferException if there is insufficient space in the output
199      *         buffer
200      */
201     @Override
202     public int update(final ByteBuffer inBuffer, final ByteBuffer outBuffer)
203             throws ShortBufferException {
204         return cipher.update(inBuffer, outBuffer);
205     }
206 
207     /**
208      * Continues a multi-part update of the Additional Authentication
209      * Data (AAD).
210      * <p>
211      * Calls to this method provide AAD to the cipher when operating in
212      * modes such as AEAD (GCM/CCM).  If this cipher is operating in
213      * either GCM or CCM mode, all AAD must be supplied before beginning
214      * operations on the ciphertext (via the {@code update} and
215      * {@code doFinal} methods).
216      * </p>
217      *
218      * @param aad the buffer containing the Additional Authentication Data
219      *
220      * @throws IllegalArgumentException if the {@code aad}
221      * byte array is null
222      * @throws IllegalStateException if this cipher is in a wrong state
223      * (e.g., has not been initialized), does not accept AAD, or if
224      * operating in either GCM or CCM mode and one of the {@code update}
225      * methods has already been called for the active
226      * encryption/decryption operation
227      * @throws UnsupportedOperationException if JCE's implementation does not
228      * support such operation
229      */
230     @Override
231     public void updateAAD(final byte[] aad) {
232         cipher.updateAAD(aad);
233     }
234 
235 
236     /**
237      * Continues a multi-part update of the Additional Authentication
238      * Data (AAD).
239      * <p>
240      * Calls to this method provide AAD to the cipher when operating in
241      * modes such as AEAD (GCM/CCM).  If this cipher is operating in
242      * either GCM or CCM mode, all AAD must be supplied before beginning
243      * operations on the ciphertext (via the {@code update} and
244      * {@code doFinal} methods).
245      * </p>
246      *
247      * @param aad the buffer containing the Additional Authentication Data
248      *
249      * @throws IllegalArgumentException if the {@code aad}
250      * byte array is null
251      * @throws IllegalStateException if this cipher is in a wrong state
252      * (e.g., has not been initialized), does not accept AAD, or if
253      * operating in either GCM or CCM mode and one of the {@code update}
254      * methods has already been called for the active
255      * encryption/decryption operation
256      * @throws UnsupportedOperationException if JCE's implementation does not
257      * support such operation
258      */
259     @Override
260     public void updateAAD(final ByteBuffer aad) {
261         cipher.updateAAD(aad);
262     }
263 }