public class HMACwith3DESwrap
extends javax.crypto.CipherSpi
RFC 3537 specifies the HMACwith3DESwrap key wrap algorithm for wrapping a HMAC message authentication code key with a 3DES key encryption key. This algorithm may be used for wrapping HMAC keys as required by the CMS (Cryptographic Message Syntax) AuthenticatedData type.
Since this class only can be used for wrapping/unwrapping HMAC keys an
application only can call methods wrap
and unwrap
of the corresponding Cipher object. Any attempt to call an
update
or doFinal
method will cause a
RuntimeException to be thrown. A CMS key wrap (unwrap) procedure involves two
encryption (decryption) operations, both run in CBC mode. The first
encryption step uses a random IV and the second encryption step uses a fixed
IV of 0x4adda22c79e82105. Correspondingly the first decryption step uses a
fixed IV (0x4adda22c79e82105) and the second decryption step uses the random
IV recovered from the first decryption. When calling an
engineInit
method any parameters supplied are ignored; this CMS
HMACwith3DESwrap key wrap cipher implementation itself takes care for using
the right IV for the right en/decryption step. When calling method
getIV
or getParameters
this class always returns
null
since a CMS HMACwith3DESwrap key wrap cipher does not
include parameters in its algorithm id.
When creating a new CMS HMACwith3DESwrap Cipher object you only may provide the name of the key wrap cipher ("3DESWrapHMAC"). Any cipher mode (always uses CBC) or padding (does the padding itself) specification is ignored.
For example, wrapping a HMAC key using a Triple-DES key encryption key typically may be done as follows:
// the HMAC key to be wrapped: SecretKey hmacKey = ...; // the key encryption key to be used: SecretKey kek = ...; // get a HMACwith3DESwrap cipher: Cipher c = Cipher.getInstance("3DESWrapHMAC"); // init with the key encryption key c.init(Cipher.WRAP_MODE, kek); // wrap the HMAC key: byte[] wrappedHmacKey = c.wrap(hmacKey);For unwrapping the key init the Cipher in unwrap mode:
Cipher c = Cipher.getInstance("3DESWrapHMAC"); // init with the key encryption key c.init(Cipher.UNWRAP_MODE, kek); // unwrap the wrapped HMAC key: Key unwrappedHmacKey = c.unwrap(wrappedHmacKey, "HmacSHA1", Cipher.SECRET_KEY);
Modifier and Type | Field and Description |
---|---|
protected int |
cipherTextLength
The expected cipher text length, may be required to be checked.
|
static byte[] |
CMS_KEY_WRAP_IV
The IV for the last encryption step of CMS key wrap.
|
protected java.security.Key |
kek
The key encryption key (used for en/decrypting the content encryption key).
|
protected byte[] |
keyWrapIV
The IV to be used for the second encryption step.
|
protected java.security.SecureRandom |
random
The SecureRandom.
|
Constructor and Description |
---|
HMACwith3DESwrap()
Creates a HMACwith3DESwrap object.
|
Modifier and Type | Method and Description |
---|---|
protected byte[] |
computeLCEKPAD(java.security.Key contentEncryptionKey)
Calculates the LCEKPAD value (RFC 2630, Section 12.6.4) from the given
content encryption key.
|
protected byte[] |
decomposeLCEKPAD(byte[] LCEKPAD)
Decomposes the LCEKPAD value (RFC 2630, Section 12.6.5, 8.) into LENGTH CEK
and PAD and returns the CEK
|
byte[] |
engineDoFinal(byte[] in,
int inOff,
int inLen)
Throws a RuntimeException since not supported by this key wrap cipher.
|
int |
engineDoFinal(byte[] in,
int inOff,
int inLen,
byte[] out,
int outOff)
Throws a RuntimeException since not supported by this key wrap cipher.
|
int |
engineGetBlockSize()
Returns the block size corresponding to this cipher.
|
byte[] |
engineGetIV()
Returns null.
|
protected int |
engineGetKeySize(java.security.Key key) |
int |
engineGetOutputSize(int inLen)
Returns the output buffer size necessary for capturing the data resulting
from the next
update or doFinal operation
including any data currently being buffered. |
java.security.AlgorithmParameters |
engineGetParameters()
Returns null.
|
void |
engineInit(int opmode,
java.security.Key key,
java.security.spec.AlgorithmParameterSpec params,
java.security.SecureRandom random)
Initializes this cipher object.
|
void |
engineInit(int opmode,
java.security.Key key,
java.security.AlgorithmParameters params,
java.security.SecureRandom random)
Initializes this cipher object.
|
protected void |
engineInit(int opmode,
java.security.Key key,
byte[] iv,
java.security.SecureRandom random)
Internal inits the underlying TripleDES cipher for the second en/decryption
step.
|
void |
engineInit(int opmode,
java.security.Key key,
java.security.SecureRandom random)
Initializes this cipher object.
|
void |
engineSetMode(java.lang.String mode)
Sets the mode of this cipher to "CBC".
|
void |
engineSetPadding(java.lang.String paddingName)
Sets the padding scheme of this cipher.
|
protected java.security.Key |
engineUnwrap(byte[] wrappedKey,
java.lang.String wrappedKeyAlgorithm,
int wrappedKeyType)
Unwraps the given wrapped key to recover the content encryption key.
|
byte[] |
engineUpdate(byte[] in,
int inOff,
int inLen)
Throws a RuntimeException since not supported by this key wrap cipher.
|
int |
engineUpdate(byte[] in,
int inOff,
int inLen,
byte[] out,
int outOff)
Throws a RuntimeException since not supported by this key wrap cipher.
|
protected void |
engineUpdateAAD(byte[] src,
int offset,
int len) |
protected byte[] |
engineWrap(java.security.Key key) |
protected java.security.Key |
finishUnWrap(byte[] lKeyPad,
java.lang.String wrappedKeyAlgorithm,
int wrappedKeyType)
Finishes the unwrapping process by decomposing the LKEYPAD value (RFC 3537,
Section 3.2, 8.) into LENGTH, KEY and PAD and returns the HMAC KEY.
|
int |
getModeBlockSize()
Returns the block size corresponding to the actual cipher mode.
|
protected java.security.SecureRandom |
getRandom()
Gets the SecureRandom.
|
protected byte[] |
prepareWrap(java.security.Key hMacKey)
Prepares the given HMAC key for being wrapped.
|
java.lang.String |
toString()
Returns a string representation of this Cipher.
|
protected java.security.Key kek
protected int cipherTextLength
protected java.security.SecureRandom random
protected byte[] keyWrapIV
public static final byte[] CMS_KEY_WRAP_IV
IV = 0x4adda22c79e82105.
public HMACwith3DESwrap()
Cipher.getInstance
factory methods instead, e.g.:
Cipher HMACwith3DESwrap = Cipher.getInstance("3DESWrapHMAC");Since the HMACwith3DESwrap cipher only runs in CBC mode and itself takes care for padding, any mode or padding specification as part of the transformation string supplied when creating the Cipher object is ignored.
public void engineInit(int opmode, java.security.Key key, java.security.spec.AlgorithmParameterSpec params, java.security.SecureRandom random) throws java.security.InvalidKeyException, java.security.InvalidAlgorithmParameterException
If parameters are supplied they are ignored. If the cipher has to be initialized for key wrap, a random IV is used. If the cipher has to be initialized for key unwrap, a fixed CMS key wrap IV is used.
opmode
- the operation mode for which this cipher is used (WRAP_MODE or
UNWRAP_MODE)key
- the key encryption key to be usedparams
- the algorithm parameters, ignoredrandom
- the random seedjava.security.InvalidKeyException
- if the given key cannot be used for initializing this cipherjava.security.InvalidAlgorithmParameterException
- if the given algorithm parameters don't match to this cipherCipher.init(int, java.security.Key)
,
CipherSpi.engineInit(int, java.security.Key, java.security.SecureRandom)
public void engineInit(int opmode, java.security.Key key, java.security.AlgorithmParameters params, java.security.SecureRandom random) throws java.security.InvalidKeyException, java.security.InvalidAlgorithmParameterException
If parameters are supplied they are ignored. If the cipher has to be initialized for key wrap, a random IV is used. If the cipher has to be initialized for key unwrap, a fixed CMS key wrap IV is used.
opmode
- the operation mode for which this cipher is used (WRAP_MODE or
UNWRAP_MODE)key
- the key encryption keyparams
- the algorithm parameters; ignoredrandom
- the random seedjava.security.InvalidKeyException
- if the given key cannot be used for initializing this cipherjava.security.InvalidAlgorithmParameterException
- if the given algorithm parameters don't match to this cipherCipher.init(int, java.security.Key)
,
CipherSpi.engineInit(int, java.security.Key, java.security.SecureRandom)
protected void engineInit(int opmode, java.security.Key key, byte[] iv, java.security.SecureRandom random) throws java.security.InvalidKeyException, java.security.InvalidAlgorithmParameterException
A CMS key wrap (unwrap) procedure involves two encryption (decryption) operations, both run in CBC mode. The first encryption step uses a random IV and the second encryption step uses a fixed IV of default 0x4adda22c79e82105. Correspondingly the first decryption step uses a fixed IV (default 0x4adda22c79e82105) and the second decryption step uses the random IV recovered from the first decryption. This method is called during the wrapping/unwrapping procedure to init the underlying TripleDES cipher for the second en/decryption step with the given key and iv.
opmode
- the operation modekey
- the key encryption keyiv
- the initialization vector, either fixed (for second encryption
step) or recovered random (for second decryption step)random
- the random seedjava.security.InvalidKeyException
- if something is wrong with the keyjava.security.InvalidAlgorithmParameterException
- if an error occurs when creating the parameters from the ivprotected byte[] prepareWrap(java.security.Key hMacKey) throws java.security.InvalidKeyException
This method calculates the LKEYPAD value (RFC 3537, Section 3.1) from the given HMAC key.
As first step of the HMACwith3DESwrap algorithm described in RFC3537, the HMAC key is concatenated with its length and padded to a multiple of 8, if required:
hMacKey
- the HMAC key for which to calculate the LKEYPAD valuejava.security.InvalidKeyException
- if the cek cannot be prepared for some reasonprotected java.security.Key finishUnWrap(byte[] lKeyPad, java.lang.String wrappedKeyAlgorithm, int wrappedKeyType) throws java.security.InvalidKeyException
As last step of the HMACwith3DESwrap Key UnWrap algorithm described in RFC3537, the LKEYPAD (composed of HMAC key-length, decrypted HMAC key and optional padding) has to be decomposed for getting the original HMAC key.
lKeyPad
- the recovered LKEYPAD value resulting from step 6 (section 3.2 of
RFC 3537); the key checksum check already has been performed when
calling this method.wrappedKeyAlgorithm
- the algorithm of the wrapped key, e.g. "HmacSHA1"wrappedKeyType
- (ignored) only Cipher.SECRET_KEY allowed for this key wrap cipherjava.security.InvalidKeyException
- if the key cannot be unwrapped because the PAD value of the
LKEYPAD is invalid (has a length not shorter than 8)public void engineInit(int opmode, java.security.Key key, java.security.SecureRandom random) throws java.security.InvalidKeyException
If the cipher has to be initialized for key wrap, a random IV is used. If the cipher has to be initialized for key unwrap, a fixed CMS key wrap IV is used.
opmode
- the operation mode for which this cipher is used (WRAP_MODE or
UNWRAP_MODE)key
- the key encryption key to be usedrandom
- the random seedjava.security.InvalidKeyException
- if the given key cannot be used for initializing this cipherCipher.init(int, java.security.Key)
,
CipherSpi.engineInit(int, java.security.Key, java.security.SecureRandom)
public void engineSetPadding(java.lang.String paddingName) throws javax.crypto.NoSuchPaddingException
This method only overrides engineSetPadding
for not allowing
an application to request a specific padding scheme (this key wrap cipher
itself takes care for padding).
paddingName
- the name of the padding scheme; ignoredjavax.crypto.NoSuchPaddingException
- if this padding scheme is not supportedCipherSpi.engineSetPadding(java.lang.String)
public void engineSetMode(java.lang.String mode) throws java.security.NoSuchAlgorithmException
This method only overrides engineSetMode
for not allowing an
application to request a specific cipher mode (this key wrap cipher always
uses "CBC").
mode
- the cipher modejava.security.NoSuchAlgorithmException
- if this cipher mode is not supportedCipherSpi.engineSetMode(java.lang.String)
public byte[] engineUpdate(byte[] in, int inOff, int inLen)
wrap
/unwrap
for wrapping/unwrapping a key.in
- the input data.inOff
- the offset indicating where the subarray starts in the
in
array.inLen
- the length of the subarray.BufferedCipher.engineDoFinal(byte[], int, int, byte[], int)
,
Cipher.doFinal()
,
Cipher.update(byte[])
,
CipherSpi.engineUpdate(byte[], int, int)
public int engineUpdate(byte[] in, int inOff, int inLen, byte[] out, int outOff) throws javax.crypto.ShortBufferException
wrap
/unwrap
for wrapping/unwrapping a key.in
- the input data.inOff
- the offset indicating where the subarray starts in the
in
array.inLen
- the length of the subarray.out
- the output buffer.outOff
- the offset indicating where to start writing the result into the
output buffer.out
array.javax.crypto.ShortBufferException
- if the buffer size is to shortBufferedCipher.engineDoFinal(byte[], int, int, byte[], int)
,
Cipher.doFinal()
,
Cipher.update(byte[])
,
CipherSpi.engineUpdate(byte[], int, int)
public int engineDoFinal(byte[] in, int inOff, int inLen, byte[] out, int outOff) throws javax.crypto.ShortBufferException, javax.crypto.IllegalBlockSizeException, javax.crypto.BadPaddingException
wrap
/unwrap
for wrapping/unwrapping a key.in
- the byte array holding the data to be processedinOff
- the offset indicating the start position within the input byte
arrayinLen
- the number of bytes to be processedout
- the byte array for holding the resultoutOff
- the offset indicating the start position within the output byte
array to which the en/decrypted data is writtenjavax.crypto.ShortBufferException
- if the given output buffer is too small for holding the resultjavax.crypto.IllegalBlockSizeException
- if the total length of the processed data is not a multiple of
the block size for a (no padding performing) block cipherjavax.crypto.BadPaddingException
- if the decrypted data is not bounded by the proper padding
bytes after data decryption including (un)paddingCipher.doFinal()
,
CipherSpi.engineDoFinal(byte[], int, int)
public byte[] engineDoFinal(byte[] in, int inOff, int inLen) throws javax.crypto.IllegalBlockSizeException, javax.crypto.BadPaddingException
wrap
/unwrap
for wrapping/unwrapping a key.in
- the byte array holding the data to be processedinOff
- the offset indicating the start position within the input byte
arrayinLen
- the number of bytes to be processedjavax.crypto.IllegalBlockSizeException
- if the total length of the processed data is not a multiple of
the block size for a (no padding performing) block cipherjavax.crypto.BadPaddingException
- if the decrypted data is not bounded by the proper padding
bytes after data decryption including (un)paddingCipher.doFinal()
,
CipherSpi.engineDoFinal(byte[], int, int)
public java.security.AlgorithmParameters engineGetParameters()
public byte[] engineGetIV()
Cipher.getIV()
,
CipherSpi.engineGetIV()
public java.lang.String toString()
protected byte[] engineWrap(java.security.Key key) throws javax.crypto.IllegalBlockSizeException, java.security.InvalidKeyException
javax.crypto.IllegalBlockSizeException
java.security.InvalidKeyException
protected java.security.Key engineUnwrap(byte[] wrappedKey, java.lang.String wrappedKeyAlgorithm, int wrappedKeyType) throws java.security.InvalidKeyException, java.security.NoSuchAlgorithmException
This method implements the core operations common to the Triple-DES and RC2
Key Wrap algorithms of RFC 2630, in particular the equivalent steps 1 to 7
of Triple-DES Key Unwrap (section 12.6.3 of RFC 2630) respectively steps 1
to 7 of RC2 Key Unwrap (section 12.6.5 of RFC 2630). Any key wrap algorithm
specific operations required to finish the unwrap procedure may be done by
implementing the abstract method finishUnWrap
for the specific key wrap algorithm in mind. Triple-DES Key
wrap, for instance, requires the content encryption key to be (odd) parity
adjusted before being wrapped. Triple-DES Key Wrap is implemented by class
TripleDESKeyWrap
which
implements method finishUnWrap
to check odd parity at the end of the unwrapping procedure.
wrappedKey
- the wrapped content encryption key to be unwrappedwrappedKeyAlgorithm
- the content encryption key algorithmwrappedKeyType
- the key type, Cipher.SECRET_KEYjava.security.InvalidKeyException
- if an error occurs while unwrapping the keyjava.security.NoSuchAlgorithmException
- if the algorithm used is not supported by the installed
providersprotected java.security.SecureRandom getRandom()
If no SecureRandom has been set, a new one is created.
protected byte[] computeLCEKPAD(java.security.Key contentEncryptionKey)
As first step of the RC2 Key Wrap algorithm described in RFC2630, the content-encryption key is concatenated with its length and padded to a multiple of 8, if required:
preparing
the content
encryption key for the wrapping procedure.contentEncryptionKey
- the content encryption key for which to calculate the LCEKPAD
valueprotected byte[] decomposeLCEKPAD(byte[] LCEKPAD) throws javax.crypto.BadPaddingException
As last step of the RC2 Key UnWrap algorithm described in RFC2630, the
LCEKPAD (composed of cek-length, decrypted content-encryption key and
optional padding) has to be decomposed for getting the cek. Since LCEKPAD
also may be used by other key wrap algorithms than RC2 (e.g. CAST-128 Key
Wrap; RFC2984) this method may be used for decomposing the LCEKPAD value
when finishing
the unwrapping
procedure.
LCEKPAD
- the LCEKPAD value (LENGTH || CEK || PAD)javax.crypto.BadPaddingException
- if the PAD value of the LCEKPAD has a length not shorter than
8protected void engineUpdateAAD(byte[] src, int offset, int len)
engineUpdateAAD
in class javax.crypto.CipherSpi
public int engineGetOutputSize(int inLen)
update
or doFinal
operation
including any data currently being buffered.engineGetOutputSize
in class javax.crypto.CipherSpi
inLen
- the number of bytes to processCipher.getOutputSize(int)
,
CipherSpi.engineGetOutputSize(int)
public int getModeBlockSize()
public int engineGetBlockSize()
engineGetBlockSize
in class javax.crypto.CipherSpi
Cipher.getBlockSize()
,
CipherSpi.engineGetBlockSize()
protected int engineGetKeySize(java.security.Key key) throws java.security.InvalidKeyException
engineGetKeySize
in class javax.crypto.CipherSpi
java.security.InvalidKeyException