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 }