1 /* KeyWrappingAlgorithmAdapter.java -- Base Adapter for Key Wrapping algorithms
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu
.javax
.crypto
.jce
.cipher
;
41 import gnu
.java
.security
.Configuration
;
42 import gnu
.java
.security
.Registry
;
43 import gnu
.javax
.crypto
.jce
.spec
.BlockCipherParameterSpec
;
44 import gnu
.javax
.crypto
.kwa
.IKeyWrappingAlgorithm
;
45 import gnu
.javax
.crypto
.kwa
.KeyUnwrappingException
;
46 import gnu
.javax
.crypto
.kwa
.KeyWrappingAlgorithmFactory
;
48 import java
.security
.AlgorithmParameters
;
49 import java
.security
.InvalidAlgorithmParameterException
;
50 import java
.security
.InvalidKeyException
;
51 import java
.security
.Key
;
52 import java
.security
.KeyFactory
;
53 import java
.security
.NoSuchAlgorithmException
;
54 import java
.security
.SecureRandom
;
55 import java
.security
.spec
.AlgorithmParameterSpec
;
56 import java
.security
.spec
.InvalidKeySpecException
;
57 import java
.security
.spec
.InvalidParameterSpecException
;
58 import java
.security
.spec
.X509EncodedKeySpec
;
59 import java
.util
.HashMap
;
61 import java
.util
.logging
.Logger
;
63 import javax
.crypto
.BadPaddingException
;
64 import javax
.crypto
.Cipher
;
65 import javax
.crypto
.CipherSpi
;
66 import javax
.crypto
.IllegalBlockSizeException
;
67 import javax
.crypto
.NoSuchPaddingException
;
68 import javax
.crypto
.ShortBufferException
;
69 import javax
.crypto
.spec
.IvParameterSpec
;
70 import javax
.crypto
.spec
.SecretKeySpec
;
73 * An abstract base class to facilitate implementations of JCE Adapters for
74 * symmetric key block ciphers capable of providing key-wrapping functionality.
76 abstract class KeyWrappingAlgorithmAdapter
79 private static final Logger log
= Logger
.getLogger(KeyWrappingAlgorithmAdapter
.class.getName());
80 /** JCE canonical name of a null-padder. */
81 private static final String NO_PADDING
= "nopadding";
82 /** Concrete Key Wrapping Algorithm SPI. */
83 protected IKeyWrappingAlgorithm kwAlgorithm
;
84 /** Size in bytes of the padding block to be provided by external padders. */
85 protected int kwaBlockSize
;
86 /** KEK size in bytes. */
87 protected int kwaKeySize
;
88 /** Name of the supported mode. */
89 protected String supportedMode
;
90 /** Operational mode in which this instance was initialised. */
91 protected int opmode
= -1;
92 /** Initialisation Vector if/when user wants to override default one. */
96 * Creates a new JCE Adapter for the designated Key Wrapping Algorithm name.
98 * @param name the canonical name of the key-wrapping algorithm.
99 * @param blockSize the block size in bytes of the underlying symmetric-key
100 * block cipher algorithm.
101 * @param keySize the allowed size in bytes of the KEK bytes to initialise the
102 * underlying symmetric-key block cipher algorithm with.
103 * @param supportedMode canonical name of the block mode the underlying cipher
106 protected KeyWrappingAlgorithmAdapter(String name
, int blockSize
, int keySize
,
107 String supportedMode
)
111 this.kwAlgorithm
= KeyWrappingAlgorithmFactory
.getInstance(name
);
112 this.kwaBlockSize
= blockSize
;
113 this.kwaKeySize
= keySize
;
114 this.supportedMode
= supportedMode
;
118 * Wraps the encoded form of a designated {@link Key}.
120 * @param key the key-material to wrap.
121 * @return the wrapped key.
122 * @throws InvalidKeyException If the key cannot be wrapped.
124 protected byte[] engineWrap(Key key
)
125 throws InvalidKeyException
, IllegalBlockSizeException
127 byte[] keyMaterial
= key
.getEncoded();
128 byte[] result
= kwAlgorithm
.wrap(keyMaterial
, 0, keyMaterial
.length
);
133 * Unwraps a previously-wrapped key-material.
135 * @param wrappedKey the wrapped key-material to unwrap.
136 * @param wrappedKeyAlgorithm the canonical name of the algorithm, which the
137 * unwrapped key-material represents. This name is used to
138 * instantiate a concrete instance of a {@link Key} for that
139 * algorithm. For example, if the value of this parameter is
140 * <code>DSS</code> and the type (the next parameter) is
141 * {@link Cipher#PUBLIC_KEY} then an attempt to construct a concrete
142 * instance of a {@link java.security.interfaces.DSAPublicKey},
143 * using the unwrapped key material, shall be made.
144 * @param wrappedKeyType the type of wrapped key-material. MUST be one of
145 * {@link Cipher#PRIVATE_KEY}, {@link Cipher#PUBLIC_KEY}, or
146 * {@link Cipher#SECRET_KEY}.
147 * @return the unwrapped key-material as an instance of {@link Key} or one of
149 * @throws InvalidKeyException If the key cannot be unwrapped, or if
150 * <code>wrappedKeyType</code> is an inappropriate type for the
152 * @throws NoSuchAlgorithmException If the <code>wrappedKeyAlgorithm</code>
153 * is unknown to every currently installed Security Provider.
155 protected Key
engineUnwrap(byte[] wrappedKey
, String wrappedKeyAlgorithm
,
157 throws InvalidKeyException
, NoSuchAlgorithmException
162 keyBytes
= kwAlgorithm
.unwrap(wrappedKey
, 0, wrappedKey
.length
);
164 catch (KeyUnwrappingException x
)
166 InvalidKeyException y
= new InvalidKeyException("engineUnwrap()");
171 switch (wrappedKeyType
)
173 case Cipher
.SECRET_KEY
:
174 result
= new SecretKeySpec(keyBytes
, wrappedKeyAlgorithm
);
176 case Cipher
.PRIVATE_KEY
:
177 case Cipher
.PUBLIC_KEY
:
178 X509EncodedKeySpec keySpec
= new X509EncodedKeySpec(keyBytes
);
179 KeyFactory keyFactory
= KeyFactory
.getInstance(wrappedKeyAlgorithm
);
182 if (wrappedKeyType
== Cipher
.PRIVATE_KEY
)
183 result
= keyFactory
.generatePrivate(keySpec
);
185 result
= keyFactory
.generatePublic(keySpec
);
187 catch (InvalidKeySpecException x
)
189 InvalidKeyException y
= new InvalidKeyException("engineUnwrap()");
195 IllegalArgumentException x
= new IllegalArgumentException("Invalid 'wrappedKeyType': "
197 InvalidKeyException y
= new InvalidKeyException("engineUnwrap()");
204 protected int engineGetBlockSize()
209 protected byte[] engineGetIV()
211 return iv
== null ?
null : (byte[]) iv
.clone();
214 protected int engineGetOutputSize(int inputLength
)
218 case Cipher
.WRAP_MODE
:
219 return getOutputSizeForWrap(inputLength
);
220 case Cipher
.UNWRAP_MODE
:
221 return getOutputSizeForUnwrap(inputLength
);
223 throw new IllegalStateException();
227 protected AlgorithmParameters
engineGetParameters()
229 BlockCipherParameterSpec spec
= new BlockCipherParameterSpec(iv
,
232 AlgorithmParameters result
= null;
235 result
= AlgorithmParameters
.getInstance("BlockCipherParameters");
238 catch (NoSuchAlgorithmException x
)
240 if (Configuration
.DEBUG
)
241 log
.fine("Unable to find BlockCipherParameters. Return null");
243 catch (InvalidParameterSpecException x
)
245 if (Configuration
.DEBUG
)
246 log
.fine("Unable to initialise BlockCipherParameters. Return null");
251 protected void engineInit(int opmode
, Key key
, SecureRandom random
)
252 throws InvalidKeyException
255 byte[] kekBytes
= checkAndGetKekBytes(key
);
256 initAlgorithm(opmode
, kekBytes
, null, random
);
259 protected void engineInit(int opmode
, Key key
, AlgorithmParameters params
,
261 throws InvalidAlgorithmParameterException
, InvalidKeyException
263 AlgorithmParameterSpec spec
= null;
267 spec
= params
.getParameterSpec(BlockCipherParameterSpec
.class);
269 catch (InvalidParameterSpecException x
)
271 if (Configuration
.DEBUG
)
272 log
.fine("Unable to translate algorithm parameters into an instance "
273 + "of BlockCipherParameterSpec. Discard");
275 engineInit(opmode
, key
, spec
, random
);
278 protected void engineInit(int opmode
, Key key
, AlgorithmParameterSpec params
,
280 throws InvalidAlgorithmParameterException
, InvalidKeyException
283 byte[] kekBytes
= checkAndGetKekBytes(key
);
284 byte[] ivBytes
= null;
285 if (params
instanceof BlockCipherParameterSpec
)
286 ivBytes
= ((BlockCipherParameterSpec
) params
).getIV();
287 else if (params
instanceof IvParameterSpec
)
288 ivBytes
= ((IvParameterSpec
) params
).getIV();
290 initAlgorithm(opmode
, kekBytes
, ivBytes
, random
);
293 protected void engineSetMode(String mode
) throws NoSuchAlgorithmException
295 if (! supportedMode
.equalsIgnoreCase(mode
))
296 throw new UnsupportedOperationException("Only " + supportedMode
301 * NoPadding is the only padding algorithm supported by Key Wrapping Algorithm
302 * implementations in RI.
304 protected void engineSetPadding(String padding
) throws NoSuchPaddingException
306 if (! NO_PADDING
.equalsIgnoreCase(padding
))
307 throw new UnsupportedOperationException("Only NoPadding is supported");
310 protected byte[] engineUpdate(byte[] input
, int inputOffset
, int inputLength
)
312 throw new UnsupportedOperationException();
315 protected int engineUpdate(byte[] input
, int inputOffset
, int inputLength
,
316 byte[] output
, int outputOffset
)
317 throws ShortBufferException
319 throw new UnsupportedOperationException();
322 protected byte[] engineDoFinal(byte[] input
, int inputOffset
, int inputLength
)
323 throws IllegalBlockSizeException
, BadPaddingException
325 throw new UnsupportedOperationException();
328 protected int engineDoFinal(byte[] input
, int inputOffset
, int inputLength
,
329 byte[] output
, int outputOffset
)
330 throws IllegalBlockSizeException
, BadPaddingException
, ShortBufferException
332 throw new UnsupportedOperationException();
336 * Return the minimum size in bytes of a place holder large enough to receive
337 * the cipher text resulting from a wrap method with the designated size of
340 * This default implementation ALWAYS returns the smallest multiple of the
341 * <code>kwaBlockSize</code> --passed to this method through its
342 * constructor-- greater than or equal to the designated
343 * <code>inputLength</code>.
345 * @param inputLength the size of a plain text.
346 * @return an estimate of the size, in bytes, of the place holder to receive
347 * the resulting bytes of a wrap method.
349 protected int getOutputSizeForWrap(int inputLength
)
351 return kwaBlockSize
* (inputLength
+ kwaBlockSize
- 1) / kwaBlockSize
;
355 * Return the minimum size in bytes of a place holder large enough to receive
356 * the plain text resulting from an unwrap method with the designated size of
359 * This default implementation ALWAYS returns the smallest multiple of the
360 * <code>paddingBlockSize</code> --passed to this method through its
361 * constructor-- greater than or equal to the designated
362 * <code>inputLength</code>.
364 * @param inputLength the size of a cipher text.
365 * @return an estimate of the size, in bytes, of the place holder to receive
366 * the resulting bytes of an uwrap method.
368 protected int getOutputSizeForUnwrap(int inputLength
)
370 return kwaBlockSize
* (inputLength
+ kwaBlockSize
- 1) / kwaBlockSize
;
373 private void checkOpMode(int opmode
)
377 case Cipher
.WRAP_MODE
:
378 case Cipher
.UNWRAP_MODE
:
381 throw new IllegalArgumentException("Unsupported operational mode: " + opmode
);
385 * Returns the key bytes, iff it was in RAW format.
387 * @param key the opaque JCE secret key to use as the KEK.
388 * @return the bytes of the encoded form of the designated kek, iff it was in
390 * @throws InvalidKeyException if the designated key is not in the RAW format.
392 private byte[] checkAndGetKekBytes(Key key
) throws InvalidKeyException
394 if (! Registry
.RAW_ENCODING_SHORT_NAME
.equalsIgnoreCase(key
.getFormat()))
395 throw new InvalidKeyException("Only RAW key format is supported");
396 byte[] result
= key
.getEncoded();
397 int kekSize
= result
.length
;
398 if (kekSize
!= kwaKeySize
)
399 throw new InvalidKeyException("Invalid key material size. Expected "
400 + kwaKeySize
+ " but found " + kekSize
);
404 private void initAlgorithm(int opmode
, byte[] kek
, byte[] ivBytes
,
406 throws InvalidKeyException
408 this.opmode
= opmode
;
409 Map attributes
= new HashMap();
410 attributes
.put(IKeyWrappingAlgorithm
.KEY_ENCRYPTION_KEY_MATERIAL
, kek
);
413 this.iv
= (byte[]) ivBytes
.clone();
414 attributes
.put(IKeyWrappingAlgorithm
.INITIAL_VALUE
, this.iv
);
419 attributes
.put(IKeyWrappingAlgorithm
.SOURCE_OF_RANDOMNESS
, rnd
);
421 kwAlgorithm
.init(attributes
);