Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
DefaultBlockCipherService |
|
| 1.8;1.8 |
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, | |
13 | * software distributed under the License is distributed on an | |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
15 | * KIND, either express or implied. See the License for the | |
16 | * specific language governing permissions and limitations | |
17 | * under the License. | |
18 | */ | |
19 | package org.apache.shiro.crypto; | |
20 | ||
21 | import org.apache.shiro.util.StringUtils; | |
22 | ||
23 | /** | |
24 | * Base abstract class for block cipher algorithms. | |
25 | * | |
26 | * <h2>Usage</h2> | |
27 | * Note that this class exists mostly to simplify algorithm-specific subclasses. Unless you understand the concepts of | |
28 | * cipher modes of operation, block sizes, and padding schemes, and you want direct control of these things, you should | |
29 | * typically not uses instances of this class directly. Instead, algorithm-specific subclasses, such as | |
30 | * {@link AesCipherService}, {@link BlowfishCipherService}, and others are usually better suited for regular use. | |
31 | * <p/> | |
32 | * However, if you have the need to create a custom block cipher service where no sufficient algorithm-specific subclass | |
33 | * exists in Shiro, this class would be very useful. | |
34 | * | |
35 | * <h2>Configuration</h2> | |
36 | * Block ciphers can accept configuration parameters that direct how they operate. These parameters concatenated | |
37 | * together in a single String comprise what the JDK JCA documentation calls a | |
38 | * <a href="http://java.sun.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#trans">transformation | |
39 | * string</a>. We think that it is better for Shiro to construct this transformation string automatically based on its | |
40 | * constituent parts instead of having the end-user construct the string manually, which may be error prone or | |
41 | * confusing. To that end, Shiro {@link DefaultBlockCipherService}s have attributes that can be set individually in | |
42 | * a type-safe manner based on your configuration needs, and Shiro will build the transformation string for you. | |
43 | * <p/> | |
44 | * The following sections typically document the configuration options for block (byte array) | |
45 | * {@link #encrypt(byte[], byte[])} and {@link #decrypt(byte[], byte[])} method invocations. Streaming configuration | |
46 | * for those same attributes are done via mirrored {@code streaming}* attributes, and their purpose is identical, but | |
47 | * they're only used during streaming {@link #encrypt(java.io.InputStream, java.io.OutputStream, byte[])} and | |
48 | * {@link #decrypt(java.io.InputStream, java.io.OutputStream, byte[])} methods. See the "Streaming" | |
49 | * section below for more. | |
50 | * | |
51 | * <h3>Block Size</h3> | |
52 | * The block size specifies the number of bits (not bytes) that the cipher operates on when performing an operation. | |
53 | * It can be specified explicitly via the {@link #setBlockSize blockSize} attribute. If not set, the JCA Provider | |
54 | * default will be used based on the cipher algorithm. Block sizes are usually very algorithm specific, so set this | |
55 | * value only if you know you don't want the JCA Provider's default for the desired algorithm. For example, the | |
56 | * AES algorithm's Rijndael implementation <em>only</em> supports a 128 bit block size and will not work with any other | |
57 | * size. | |
58 | * <p/> | |
59 | * Also note that the {@link #setInitializationVectorSize initializationVectorSize} is usually the same as the | |
60 | * {@link #setBlockSize blockSize} in block ciphers. If you change either attribute, you should ensure that the other | |
61 | * attribute is correct for the target cipher algorithm. | |
62 | * | |
63 | * <h3>Operation Mode</h3> | |
64 | * You may set the block cipher's<a href="http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation">mode of | |
65 | * operation</a> via the {@link #setMode(OperationMode) mode} attribute, which accepts a type-safe | |
66 | * {@link OperationMode OperationMode} enum instance. This type safety helps avoid typos when specifying the mode and | |
67 | * guarantees that the mode name will be recognized by the underlying JCA Provider. | |
68 | * <p/> | |
69 | * <b>*</b>If no operation mode is specified, Shiro defaults all of its block {@code CipherService} instances to the | |
70 | * {@link OperationMode#CBC CBC} mode, specifically to support auto-generation of initialization vectors during | |
71 | * encryption. This is different than the JDK's default {@link OperationMode#ECB ECB} mode because {@code ECB} does | |
72 | * not support initialization vectors, which are necessary for strong encryption. See the | |
73 | * {@link org.apache.shiro.crypto.JcaCipherService JcaCipherService parent class} class JavaDoc for an extensive | |
74 | * explanation on why we do this and why we do not use the Sun {@code ECB} default. You also might also want read | |
75 | * the <a href="http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29">Wikipedia | |
76 | * section on ECB<a/> and look at the encrypted image to see an example of why {@code ECB} should not be used in | |
77 | * security-sensitive environments. | |
78 | * <p/> | |
79 | * In the rare case that you need to override the default with a mode not represented | |
80 | * by the {@link OperationMode} enum, you may specify the raw mode name string that will be recognized by your JCA | |
81 | * provider via the {@link #setModeName modeName} attribute. Because this is not type-safe, it is recommended only to | |
82 | * use this attribute if the {@link OperationMode} enum does not represent your desired mode. | |
83 | * <p/> | |
84 | * <b>NOTE:</b> If you change the mode to one that does not support initialization vectors (such as | |
85 | * {@link OperationMode#ECB ECB} or {@link OperationMode#NONE NONE}), you <em>must</em> turn off auto-generated | |
86 | * initialization vectors by setting {@link #setGenerateInitializationVectors(boolean) generateInitializationVectors} | |
87 | * to {@code false}. Abandoning initialization vectors significantly weakens encryption, so think twice before | |
88 | * disabling this feature. | |
89 | * | |
90 | * <h3>Padding Scheme</h3> | |
91 | * Because block ciphers process messages in fixed-length blocks, if the final block in a message is not equal to the | |
92 | * block length, <a href="http://en.wikipedia.org/wiki/Padding_(cryptography)">padding</a> is applied to match that | |
93 | * size to maintain the total length of the message. This is good because it protects data patterns from being | |
94 | * identified - when all chunks look the same length, it is much harder to infer what that data might be. | |
95 | * <p/> | |
96 | * You may set a padding scheme via the {@link #setPaddingScheme(PaddingScheme) paddingScheme} attribute, which | |
97 | * accepts a type-safe {@link PaddingScheme PaddingScheme} enum instance. Like the {@link OperationMode} enum, | |
98 | * this enum offers type safety to help avoid typos and guarantees that the mode will be recongized by the underlying | |
99 | * JCA provider. | |
100 | * <p/> | |
101 | * <b>*</b>If no padding scheme is specified, this class defaults to the {@link PaddingScheme#PKCS5} scheme, specifically | |
102 | * to be compliant with the default behavior of auto-generating initialization vectors during encryption (see the | |
103 | * {@link org.apache.shiro.crypto.JcaCipherService JcaCipherService parent class} class JavaDoc for why). | |
104 | * <p/> | |
105 | * In the rare case that you need to override the default with a scheme not represented by the {@link PaddingScheme} | |
106 | * enum, you may specify the raw padding scheme name string that will be recognized by your JCA provider via the | |
107 | * {@link #setPaddingScheme paddingSchemeName} attribute. Because this is not type-safe, it is recommended only to | |
108 | * use this attribute if the {@link PaddingScheme} enum does not represent your desired scheme. | |
109 | * | |
110 | * <h2>Streaming</h2> | |
111 | * Most people don't think of using block ciphers as stream ciphers, since their name implies working | |
112 | * with block data (i.e. byte arrays) only. However, block ciphers can be turned into byte-oriented stream ciphers by | |
113 | * using an appropriate {@link OperationMode operation mode} with a {@link #getStreamingBlockSize() streaming block size} | |
114 | * of 8 bits. This is why the {@link CipherService} interface provides both block and streaming operations. | |
115 | * <p/> | |
116 | * Because this streaming 8-bit block size rarely changes across block-cipher algorithms, default values have been set | |
117 | * for all three streaming configuration parameters. The defaults are: | |
118 | * <ul> | |
119 | * <li>{@link #setStreamingBlockSize(int) streamingBlockSize} = {@code 8} (bits)</li> | |
120 | * <li>{@link #setStreamingMode streamingMode} = {@link OperationMode#CBC CBC}</li> | |
121 | * <li>{@link #setStreamingPaddingScheme(PaddingScheme) streamingPaddingScheme} = {@link PaddingScheme#PKCS5 PKCS5}</li> | |
122 | * </ul> | |
123 | * <p/> | |
124 | * These attributes have the same meaning as the {@code mode}, {@code blockSize}, and {@code paddingScheme} attributes | |
125 | * described above, but they are applied during streaming method invocations only ({@link #encrypt(java.io.InputStream, java.io.OutputStream, byte[])} | |
126 | * and {@link #decrypt(java.io.InputStream, java.io.OutputStream, byte[])}). | |
127 | * | |
128 | * @see BlowfishCipherService | |
129 | * @see AesCipherService | |
130 | * @see <a href="http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation">Wikipedia: Block Cipher Modes of Operation</a> | |
131 | * @since 1.0 | |
132 | */ | |
133 | public class DefaultBlockCipherService extends AbstractSymmetricCipherService { | |
134 | ||
135 | private static final int DEFAULT_BLOCK_SIZE = 0; | |
136 | ||
137 | private static final String TRANSFORMATION_STRING_DELIMITER = "/"; | |
138 | private static final int DEFAULT_STREAMING_BLOCK_SIZE = 8; //8 bits (1 byte) | |
139 | ||
140 | private String modeName; | |
141 | private int blockSize; //size in bits (not bytes) - i.e. a blockSize of 8 equals 1 byte. negative or zero value = use system default | |
142 | private String paddingSchemeName; | |
143 | ||
144 | private String streamingModeName; | |
145 | private int streamingBlockSize; | |
146 | private String streamingPaddingSchemeName; | |
147 | ||
148 | private String transformationString; //cached value - rebuilt whenever any of its constituent parts change | |
149 | private String streamingTransformationString; //cached value - rebuilt whenever any of its constituent parts change | |
150 | ||
151 | ||
152 | /** | |
153 | * Creates a new {@link DefaultBlockCipherService} using the specified block cipher {@code algorithmName}. Per this | |
154 | * class's JavaDoc, this constructor also sets the following defaults: | |
155 | * <ul> | |
156 | * <li>{@code streamingMode} = {@link OperationMode#CBC CBC}</li> | |
157 | * <li>{@code streamingPaddingScheme} = {@link PaddingScheme#NONE none}</li> | |
158 | * <li>{@code streamingBlockSize} = 8</li> | |
159 | * </ul> | |
160 | * All other attributes are null/unset, indicating the JCA Provider defaults will be used. | |
161 | * | |
162 | * @param algorithmName the block cipher algorithm to use when encrypting and decrypting | |
163 | */ | |
164 | public DefaultBlockCipherService(String algorithmName) { | |
165 | 6 | super(algorithmName); |
166 | ||
167 | 6 | this.modeName = OperationMode.CBC.name(); |
168 | 6 | this.paddingSchemeName = PaddingScheme.PKCS5.getTransformationName(); |
169 | 6 | this.blockSize = DEFAULT_BLOCK_SIZE; //0 = use the JCA provider's default |
170 | ||
171 | 6 | this.streamingModeName = OperationMode.CBC.name(); |
172 | 6 | this.streamingPaddingSchemeName = PaddingScheme.PKCS5.getTransformationName(); |
173 | 6 | this.streamingBlockSize = DEFAULT_STREAMING_BLOCK_SIZE; |
174 | 6 | } |
175 | ||
176 | /** | |
177 | * Returns the cipher operation mode name (as a String) to be used when constructing | |
178 | * {@link javax.crypto.Cipher Cipher} transformation string or {@code null} if the JCA Provider default mode for | |
179 | * the specified {@link #getAlgorithmName() algorithm} should be used. | |
180 | * <p/> | |
181 | * This attribute is used <em>only</em> when constructing the transformation string for block (byte array) | |
182 | * operations ({@link #encrypt(byte[], byte[])} and {@link #decrypt(byte[], byte[])}). The | |
183 | * {@link #getStreamingModeName() streamingModeName} attribute is used when the block cipher is used for | |
184 | * streaming operations. | |
185 | * <p/> | |
186 | * The default value is {@code null} to retain the JCA Provider default. | |
187 | * | |
188 | * @return the cipher operation mode name (as a String) to be used when constructing the | |
189 | * {@link javax.crypto.Cipher Cipher} transformation string, or {@code null} if the JCA Provider default | |
190 | * mode for the specified {@link #getAlgorithmName() algorithm} should be used. | |
191 | */ | |
192 | public String getModeName() { | |
193 | 14 | return modeName; |
194 | } | |
195 | ||
196 | /** | |
197 | * Sets the cipher operation mode name to be used when constructing the | |
198 | * {@link javax.crypto.Cipher Cipher} transformation string. A {@code null} value indicates that the JCA Provider | |
199 | * default mode for the specified {@link #getAlgorithmName() algorithm} should be used. | |
200 | * <p/> | |
201 | * This attribute is used <em>only</em> when constructing the transformation string for block (byte array) | |
202 | * operations ({@link #encrypt(byte[], byte[])} and {@link #decrypt(byte[], byte[])}). The | |
203 | * {@link #getStreamingModeName() streamingModeName} attribute is used when the block cipher is used for | |
204 | * streaming operations. | |
205 | * <p/> | |
206 | * The default value is {@code null} to retain the JCA Provider default. | |
207 | * <p/> | |
208 | * <b>NOTE:</b> most standard mode names are represented by the {@link OperationMode OperationMode} enum. That enum | |
209 | * should be used with the {@link #setMode mode} attribute when possible to retain type-safety and reduce the | |
210 | * possibility of errors. This method is better used if the {@link OperationMode} enum does not represent the | |
211 | * necessary mode. | |
212 | * | |
213 | * @param modeName the cipher operation mode name to be used when constructing | |
214 | * {@link javax.crypto.Cipher Cipher} transformation string, or {@code null} if the JCA Provider | |
215 | * default mode for the specified {@link #getAlgorithmName() algorithm} should be used. | |
216 | * @see #setMode | |
217 | */ | |
218 | public void setModeName(String modeName) { | |
219 | 0 | this.modeName = modeName; |
220 | //clear out the transformation string so the next invocation will rebuild it with the new mode: | |
221 | 0 | this.transformationString = null; |
222 | 0 | } |
223 | ||
224 | /** | |
225 | * Sets the cipher operation mode of operation to be used when constructing the | |
226 | * {@link javax.crypto.Cipher Cipher} transformation string. A {@code null} value indicates that the JCA Provider | |
227 | * default mode for the specified {@link #getAlgorithmName() algorithm} should be used. | |
228 | * <p/> | |
229 | * This attribute is used <em>only</em> when constructing the transformation string for block (byte array) | |
230 | * operations ({@link #encrypt(byte[], byte[])} and {@link #decrypt(byte[], byte[])}). The | |
231 | * {@link #setStreamingMode streamingMode} attribute is used when the block cipher is used for | |
232 | * streaming operations. | |
233 | * <p/> | |
234 | * If the {@link OperationMode} enum cannot represent your desired mode, you can set the name explicitly | |
235 | * via the {@link #setModeName modeName} attribute directly. However, because {@link OperationMode} represents all | |
236 | * standard JDK mode names already, ensure that your underlying JCA Provider supports the non-standard name first. | |
237 | * | |
238 | * @param mode the cipher operation mode to be used when constructing | |
239 | * {@link javax.crypto.Cipher Cipher} transformation string, or {@code null} if the JCA Provider | |
240 | * default mode for the specified {@link #getAlgorithmName() algorithm} should be used. | |
241 | */ | |
242 | public void setMode(OperationMode mode) { | |
243 | 0 | setModeName(mode.name()); |
244 | 0 | } |
245 | ||
246 | /** | |
247 | * Returns the cipher algorithm padding scheme name (as a String) to be used when constructing | |
248 | * {@link javax.crypto.Cipher Cipher} transformation string or {@code null} if the JCA Provider default mode for | |
249 | * the specified {@link #getAlgorithmName() algorithm} should be used. | |
250 | * <p/> | |
251 | * This attribute is used <em>only</em> when constructing the transformation string for block (byte array) | |
252 | * operations ({@link #encrypt(byte[], byte[])} and {@link #decrypt(byte[], byte[])}). The | |
253 | * {@link #getStreamingPaddingSchemeName() streamingPaddingSchemeName} attribute is used when the block cipher is | |
254 | * used for streaming operations. | |
255 | * <p/> | |
256 | * The default value is {@code null} to retain the JCA Provider default. | |
257 | * | |
258 | * @return the padding scheme name (as a String) to be used when constructing the | |
259 | * {@link javax.crypto.Cipher Cipher} transformation string, or {@code null} if the JCA Provider default | |
260 | * padding scheme for the specified {@link #getAlgorithmName() algorithm} should be used. | |
261 | */ | |
262 | public String getPaddingSchemeName() { | |
263 | 2 | return paddingSchemeName; |
264 | } | |
265 | ||
266 | /** | |
267 | * Sets the padding scheme name to be used when constructing the | |
268 | * {@link javax.crypto.Cipher Cipher} transformation string, or {@code null} if the JCA Provider default mode for | |
269 | * the specified {@link #getAlgorithmName() algorithm} should be used. | |
270 | * <p/> | |
271 | * This attribute is used <em>only</em> when constructing the transformation string for block (byte array) | |
272 | * operations ({@link #encrypt(byte[], byte[])} and {@link #decrypt(byte[], byte[])}). The | |
273 | * {@link #getStreamingPaddingSchemeName() streamingPaddingSchemeName} attribute is used when the block cipher is | |
274 | * used for streaming operations. | |
275 | * <p/> | |
276 | * The default value is {@code null} to retain the JCA Provider default. | |
277 | * <p/> | |
278 | * <b>NOTE:</b> most standard padding schemes are represented by the {@link PaddingScheme PaddingScheme} enum. | |
279 | * That enum should be used with the {@link #setPaddingScheme paddingScheme} attribute when possible to retain | |
280 | * type-safety and reduce the possibility of errors. Calling this method however is suitable if the | |
281 | * {@code PaddingScheme} enum does not represent the desired scheme. | |
282 | * | |
283 | * @param paddingSchemeName the padding scheme name to be used when constructing | |
284 | * {@link javax.crypto.Cipher Cipher} transformation string, or {@code null} if the JCA | |
285 | * Provider default padding scheme for the specified {@link #getAlgorithmName() algorithm} | |
286 | * should be used. | |
287 | * @see #setPaddingScheme | |
288 | */ | |
289 | public void setPaddingSchemeName(String paddingSchemeName) { | |
290 | 0 | this.paddingSchemeName = paddingSchemeName; |
291 | //clear out the transformation string so the next invocation will rebuild it with the new padding scheme: | |
292 | 0 | this.transformationString = null; |
293 | 0 | } |
294 | ||
295 | /** | |
296 | * Sets the padding scheme to be used when constructing the | |
297 | * {@link javax.crypto.Cipher Cipher} transformation string. A {@code null} value indicates that the JCA Provider | |
298 | * default padding scheme for the specified {@link #getAlgorithmName() algorithm} should be used. | |
299 | * <p/> | |
300 | * This attribute is used <em>only</em> when constructing the transformation string for block (byte array) | |
301 | * operations ({@link #encrypt(byte[], byte[])} and {@link #decrypt(byte[], byte[])}). The | |
302 | * {@link #setStreamingPaddingScheme streamingPaddingScheme} attribute is used when the block cipher is used for | |
303 | * streaming operations. | |
304 | * <p/> | |
305 | * If the {@link PaddingScheme PaddingScheme} enum does represent your desired scheme, you can set the name explicitly | |
306 | * via the {@link #setPaddingSchemeName paddingSchemeName} attribute directly. However, because | |
307 | * {@code PaddingScheme} represents all standard JDK scheme names already, ensure that your underlying JCA Provider | |
308 | * supports the non-standard name first. | |
309 | * | |
310 | * @param paddingScheme the padding scheme to be used when constructing | |
311 | * {@link javax.crypto.Cipher Cipher} transformation string, or {@code null} if the JCA Provider | |
312 | * default padding scheme for the specified {@link #getAlgorithmName() algorithm} should be used. | |
313 | */ | |
314 | public void setPaddingScheme(PaddingScheme paddingScheme) { | |
315 | 0 | setPaddingSchemeName(paddingScheme.getTransformationName()); |
316 | 0 | } |
317 | ||
318 | /** | |
319 | * Returns the block cipher's block size to be used when constructing | |
320 | * {@link javax.crypto.Cipher Cipher} transformation string or {@code 0} if the JCA Provider default block size | |
321 | * for the specified {@link #getAlgorithmName() algorithm} should be used. | |
322 | * <p/> | |
323 | * This attribute is used <em>only</em> when constructing the transformation string for block (byte array) | |
324 | * operations ({@link #encrypt(byte[], byte[])} and {@link #decrypt(byte[], byte[])}). The | |
325 | * {@link #getStreamingBlockSize() streamingBlockSize} attribute is used when the block cipher is used for | |
326 | * streaming operations. | |
327 | * <p/> | |
328 | * The default value is {@code 0} which retains the JCA Provider default. | |
329 | * | |
330 | * @return the block cipher block size to be used when constructing the | |
331 | * {@link javax.crypto.Cipher Cipher} transformation string, or {@code 0} if the JCA Provider default | |
332 | * block size for the specified {@link #getAlgorithmName() algorithm} should be used. | |
333 | */ | |
334 | public int getBlockSize() { | |
335 | 2 | return blockSize; |
336 | } | |
337 | ||
338 | /** | |
339 | * Sets the block cipher's block size to be used when constructing | |
340 | * {@link javax.crypto.Cipher Cipher} transformation string. {@code 0} indicates that the JCA Provider default | |
341 | * block size for the specified {@link #getAlgorithmName() algorithm} should be used. | |
342 | * <p/> | |
343 | * This attribute is used <em>only</em> when constructing the transformation string for block (byte array) | |
344 | * operations ({@link #encrypt(byte[], byte[])} and {@link #decrypt(byte[], byte[])}). The | |
345 | * {@link #getStreamingBlockSize() streamingBlockSize} attribute is used when the block cipher is used for | |
346 | * streaming operations. | |
347 | * <p/> | |
348 | * The default value is {@code 0} which retains the JCA Provider default. | |
349 | * <p/> | |
350 | * <b>NOTE:</b> block cipher block sizes are very algorithm-specific. If you change this value, ensure that it | |
351 | * will work with the specified {@link #getAlgorithmName() algorithm}. | |
352 | * | |
353 | * @param blockSize the block cipher block size to be used when constructing the | |
354 | * {@link javax.crypto.Cipher Cipher} transformation string, or {@code 0} if the JCA Provider | |
355 | * default block size for the specified {@link #getAlgorithmName() algorithm} should be used. | |
356 | */ | |
357 | public void setBlockSize(int blockSize) { | |
358 | 0 | this.blockSize = Math.max(DEFAULT_BLOCK_SIZE, blockSize); |
359 | //clear out the transformation string so the next invocation will rebuild it with the new block size: | |
360 | 0 | this.transformationString = null; |
361 | 0 | } |
362 | ||
363 | /** | |
364 | * Same purpose as the {@link #getModeName modeName} attribute, but is used instead only for for streaming | |
365 | * operations ({@link #encrypt(java.io.InputStream, java.io.OutputStream, byte[])} and | |
366 | * {@link #decrypt(java.io.InputStream, java.io.OutputStream, byte[])}). | |
367 | * <p/> | |
368 | * Note that unlike the {@link #getModeName modeName} attribute, the default value of this attribute is not | |
369 | * {@code null} - it is {@link OperationMode#CBC CBC} for reasons described in the class-level JavaDoc in the | |
370 | * {@code Streaming} section. | |
371 | * | |
372 | * @return the transformation string mode name to be used for streaming operations only. | |
373 | */ | |
374 | public String getStreamingModeName() { | |
375 | 6 | return streamingModeName; |
376 | } | |
377 | ||
378 | private boolean isModeStreamingCompatible(String modeName) { | |
379 | 0 | return modeName != null && |
380 | !modeName.equalsIgnoreCase(OperationMode.ECB.name()) && | |
381 | !modeName.equalsIgnoreCase(OperationMode.NONE.name()); | |
382 | } | |
383 | ||
384 | /** | |
385 | * Sets the transformation string mode name to be used for streaming operations only. The default value is | |
386 | * {@link OperationMode#CBC CBC} for reasons described in the class-level JavaDoc in the {@code Streaming} section. | |
387 | * | |
388 | * @param streamingModeName transformation string mode name to be used for streaming operations only | |
389 | */ | |
390 | public void setStreamingModeName(String streamingModeName) { | |
391 | 0 | if (!isModeStreamingCompatible(streamingModeName)) { |
392 | 0 | String msg = "mode [" + streamingModeName + "] is not a valid operation mode for block cipher streaming."; |
393 | 0 | throw new IllegalArgumentException(msg); |
394 | } | |
395 | 0 | this.streamingModeName = streamingModeName; |
396 | //clear out the streaming transformation string so the next invocation will rebuild it with the new mode: | |
397 | 0 | this.streamingTransformationString = null; |
398 | 0 | } |
399 | ||
400 | /** | |
401 | * Sets the transformation string mode to be used for streaming operations only. The default value is | |
402 | * {@link OperationMode#CBC CBC} for reasons described in the class-level JavaDoc in the {@code Streaming} section. | |
403 | * | |
404 | * @param mode the transformation string mode to be used for streaming operations only | |
405 | */ | |
406 | public void setStreamingMode(OperationMode mode) { | |
407 | 0 | setStreamingModeName(mode.name()); |
408 | 0 | } |
409 | ||
410 | public String getStreamingPaddingSchemeName() { | |
411 | 2 | return streamingPaddingSchemeName; |
412 | } | |
413 | ||
414 | public void setStreamingPaddingSchemeName(String streamingPaddingSchemeName) { | |
415 | 0 | this.streamingPaddingSchemeName = streamingPaddingSchemeName; |
416 | //clear out the streaming transformation string so the next invocation will rebuild it with the new scheme: | |
417 | 0 | this.streamingTransformationString = null; |
418 | 0 | } |
419 | ||
420 | public void setStreamingPaddingScheme(PaddingScheme scheme) { | |
421 | 0 | setStreamingPaddingSchemeName(scheme.getTransformationName()); |
422 | 0 | } |
423 | ||
424 | public int getStreamingBlockSize() { | |
425 | 0 | return streamingBlockSize; |
426 | } | |
427 | ||
428 | public void setStreamingBlockSize(int streamingBlockSize) { | |
429 | 0 | this.streamingBlockSize = Math.max(DEFAULT_BLOCK_SIZE, streamingBlockSize); |
430 | //clear out the streaming transformation string so the next invocation will rebuild it with the new block size: | |
431 | 0 | this.streamingTransformationString = null; |
432 | 0 | } |
433 | ||
434 | /** | |
435 | * Returns the transformation string to use with the {@link javax.crypto.Cipher#getInstance} call. If | |
436 | * {@code streaming} is {@code true}, a block-cipher transformation string compatible with streaming operations will | |
437 | * be constructed and cached for re-use later (see the class-level JavaDoc for more on using block ciphers | |
438 | * for streaming). If {@code streaming} is {@code false} a normal block-cipher transformation string will | |
439 | * be constructed and cached for later re-use. | |
440 | * | |
441 | * @param streaming if the transformation string is going to be used for a Cipher performing stream-based encryption or not. | |
442 | * @return the transformation string | |
443 | */ | |
444 | protected String getTransformationString(boolean streaming) { | |
445 | 16 | if (streaming) { |
446 | 8 | if (this.streamingTransformationString == null) { |
447 | 2 | this.streamingTransformationString = buildStreamingTransformationString(); |
448 | } | |
449 | 8 | return this.streamingTransformationString; |
450 | } else { | |
451 | 8 | if (this.transformationString == null) { |
452 | 2 | this.transformationString = buildTransformationString(); |
453 | } | |
454 | 8 | return this.transformationString; |
455 | } | |
456 | } | |
457 | ||
458 | private String buildTransformationString() { | |
459 | 2 | return buildTransformationString(getModeName(), getPaddingSchemeName(), getBlockSize()); |
460 | } | |
461 | ||
462 | private String buildStreamingTransformationString() { | |
463 | 2 | return buildTransformationString(getStreamingModeName(), getStreamingPaddingSchemeName(), 0); |
464 | } | |
465 | ||
466 | private String buildTransformationString(String modeName, String paddingSchemeName, int blockSize) { | |
467 | 4 | StringBuilder sb = new StringBuilder(getAlgorithmName()); |
468 | 4 | if (StringUtils.hasText(modeName)) { |
469 | 4 | sb.append(TRANSFORMATION_STRING_DELIMITER).append(modeName); |
470 | } | |
471 | 4 | if (blockSize > 0) { |
472 | 0 | sb.append(blockSize); |
473 | } | |
474 | 4 | if (StringUtils.hasText(paddingSchemeName)) { |
475 | 4 | sb.append(TRANSFORMATION_STRING_DELIMITER).append(paddingSchemeName); |
476 | } | |
477 | 4 | return sb.toString(); |
478 | } | |
479 | ||
480 | /** | |
481 | * Returns {@code true} if the specified cipher operation mode name supports initialization vectors, | |
482 | * {@code false} otherwise. | |
483 | * | |
484 | * @param modeName the raw text name of the mode of operation | |
485 | * @return {@code true} if the specified cipher operation mode name supports initialization vectors, | |
486 | * {@code false} otherwise. | |
487 | */ | |
488 | private boolean isModeInitializationVectorCompatible(String modeName) { | |
489 | 16 | return modeName != null && |
490 | !modeName.equalsIgnoreCase(OperationMode.ECB.name()) && | |
491 | !modeName.equalsIgnoreCase(OperationMode.NONE.name()); | |
492 | } | |
493 | ||
494 | /** | |
495 | * Overrides the parent implementation to ensure initialization vectors are always generated if streaming is | |
496 | * enabled (block ciphers <em>must</em> use initialization vectors if they are to be used as a stream cipher). If | |
497 | * not being used as a stream cipher, then the value is computed based on whether or not the currently configured | |
498 | * {@link #getModeName modeName} is compatible with initialization vectors as well as the result of the configured | |
499 | * {@link #setGenerateInitializationVectors(boolean) generateInitializationVectors} value. | |
500 | * | |
501 | * @param streaming whether or not streaming is being performed | |
502 | * @return {@code true} if streaming or a value computed based on if the currently configured mode is compatible | |
503 | * with initialization vectors. | |
504 | */ | |
505 | @Override | |
506 | protected boolean isGenerateInitializationVectors(boolean streaming) { | |
507 | 16 | return streaming || super.isGenerateInitializationVectors() && isModeInitializationVectorCompatible(getModeName()); |
508 | } | |
509 | ||
510 | @Override | |
511 | protected byte[] generateInitializationVector(boolean streaming) { | |
512 | 8 | if (streaming) { |
513 | 4 | String streamingModeName = getStreamingModeName(); |
514 | 4 | if (!isModeInitializationVectorCompatible(streamingModeName)) { |
515 | 0 | String msg = "streamingMode attribute value [" + streamingModeName + "] does not support " + |
516 | "Initialization Vectors. Ensure the streamingMode value represents an operation mode " + | |
517 | "that is compatible with initialization vectors."; | |
518 | 0 | throw new IllegalStateException(msg); |
519 | } | |
520 | 4 | } else { |
521 | 4 | String modeName = getModeName(); |
522 | 4 | if (!isModeInitializationVectorCompatible(modeName)) { |
523 | 0 | String msg = "mode attribute value [" + modeName + "] does not support " + |
524 | "Initialization Vectors. Ensure the mode value represents an operation mode " + | |
525 | "that is compatible with initialization vectors."; | |
526 | 0 | throw new IllegalStateException(msg); |
527 | } | |
528 | } | |
529 | 8 | return super.generateInitializationVector(streaming); |
530 | } | |
531 | } |