Base abstract class for block cipher algorithms.
Usage
Note that this class exists mostly to simplify algorithm-specific subclasses. Unless you understand the concepts of
cipher modes of operation, block sizes, and padding schemes, and you want direct control of these things, you should
typically not uses instances of this class directly. Instead, algorithm-specific subclasses, such as
AesCipherService,
BlowfishCipherService, and others are usually better suited for regular use.
However, if you have the need to create a custom block cipher service where no sufficient algorithm-specific subclass
exists in Shiro, this class would be very useful.
Configuration
Block ciphers can accept configuration parameters that direct how they operate. These parameters concatenated
together in a single String comprise what the JDK JCA documentation calls a
transformation
string. We think that it is better for Shiro to construct this transformation string automatically based on its
constituent parts instead of having the end-user construct the string manually, which may be error prone or
confusing. To that end, Shiro
DefaultBlockCipherServices have attributes that can be set individually in
a type-safe manner based on your configuration needs, and Shiro will build the transformation string for you.
The following sections typically document the configuration options for block (byte array)
#encrypt(byte[],byte[]) and
#decrypt(byte[],byte[]) method invocations. Streaming configuration
for those same attributes are done via mirrored
streaming* attributes, and their purpose is identical, but
they're only used during streaming
#encrypt(java.io.InputStream,java.io.OutputStream,byte[]) and
#decrypt(java.io.InputStream,java.io.OutputStream,byte[]) methods. See the "Streaming"
section below for more.
Block Size
The block size specifies the number of bits (not bytes) that the cipher operates on when performing an operation.
It can be specified explicitly via the
#setBlockSize attribute. If not set, the JCA Provider
default will be used based on the cipher algorithm. Block sizes are usually very algorithm specific, so set this
value only if you know you don't want the JCA Provider's default for the desired algorithm. For example, the
AES algorithm's Rijndael implementation
only supports a 128 bit block size and will not work with any other
size.
Also note that the
#setInitializationVectorSize is usually the same as the
#setBlockSize in block ciphers. If you change either attribute, you should ensure that the other
attribute is correct for the target cipher algorithm.
Operation Mode
You may set the block cipher's
mode of
operation via the
#setMode(OperationMode) attribute, which accepts a type-safe
OperationMode enum instance. This type safety helps avoid typos when specifying the mode and
guarantees that the mode name will be recognized by the underlying JCA Provider.
*If no operation mode is specified, Shiro defaults all of its block
CipherService instances to the
OperationMode#CBC mode, specifically to support auto-generation of initialization vectors during
encryption. This is different than the JDK's default
OperationMode#ECB mode because
ECB does
not support initialization vectors, which are necessary for strong encryption. See the
org.apache.shiro.crypto.JcaCipherService class JavaDoc for an extensive
explanation on why we do this and why we do not use the Sun
ECB default. You also might also want read
the Wikipedia
section on ECB and look at the encrypted image to see an example of why
ECB should not be used in
security-sensitive environments.
In the rare case that you need to override the default with a mode not represented
by the
OperationMode enum, you may specify the raw mode name string that will be recognized by your JCA
provider via the
#setModeName attribute. Because this is not type-safe, it is recommended only to
use this attribute if the
OperationMode enum does not represent your desired mode.
NOTE: If you change the mode to one that does not support initialization vectors (such as
OperationMode#ECB or
OperationMode#NONE), you must turn off auto-generated
initialization vectors by setting
#setGenerateInitializationVectors(boolean)to
false. Abandoning initialization vectors significantly weakens encryption, so think twice before
disabling this feature.
Padding Scheme
Because block ciphers process messages in fixed-length blocks, if the final block in a message is not equal to the
block length, padding is applied to match that
size to maintain the total length of the message. This is good because it protects data patterns from being
identified - when all chunks look the same length, it is much harder to infer what that data might be.
You may set a padding scheme via the
#setPaddingScheme(PaddingScheme) attribute, which
accepts a type-safe
PaddingScheme enum instance. Like the
OperationMode enum,
this enum offers type safety to help avoid typos and guarantees that the mode will be recongized by the underlying
JCA provider.
*If no padding scheme is specified, this class defaults to the
PaddingScheme#PKCS5 scheme, specifically
to be compliant with the default behavior of auto-generating initialization vectors during encryption (see the
org.apache.shiro.crypto.JcaCipherService class JavaDoc for why).
In the rare case that you need to override the default with a scheme not represented by the
PaddingSchemeenum, you may specify the raw padding scheme name string that will be recognized by your JCA provider via the
#setPaddingScheme attribute. Because this is not type-safe, it is recommended only to
use this attribute if the
PaddingScheme enum does not represent your desired scheme.
Streaming
Most people don't think of using block ciphers as stream ciphers, since their name implies working
with block data (i.e. byte arrays) only. However, block ciphers can be turned into byte-oriented stream ciphers by
using an appropriate
OperationMode with a
#getStreamingBlockSize()of 8 bits. This is why the
CipherService interface provides both block and streaming operations.
Because this streaming 8-bit block size rarely changes across block-cipher algorithms, default values have been set
for all three streaming configuration parameters. The defaults are:
-
#setStreamingBlockSize(int) =
8 (bits)
-
#setStreamingMode =
OperationMode#CBC
-
#setStreamingPaddingScheme(PaddingScheme) =
PaddingScheme#PKCS5
These attributes have the same meaning as the
mode,
blockSize, and
paddingScheme attributes
described above, but they are applied during streaming method invocations only (
#encrypt(java.io.InputStream,java.io.OutputStream,byte[])and
#decrypt(java.io.InputStream,java.io.OutputStream,byte[])).