Reset branch to trunk.
[official-gcc.git] / trunk / libjava / classpath / gnu / javax / crypto / jce / cipher / KeyWrappingAlgorithmAdapter.java
blob03356a236f7abcf559395c3612fd2563f0a89b37
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)
9 any later version.
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
19 02110-1301 USA.
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
24 combination.
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;
60 import java.util.Map;
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;
72 /**
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
77 extends CipherSpi
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. */
93 byte[] iv;
95 /**
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
104 * is supporting.
106 protected KeyWrappingAlgorithmAdapter(String name, int blockSize, int keySize,
107 String supportedMode)
109 super();
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);
129 return result;
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
148 * its subclasses.
149 * @throws InvalidKeyException If the key cannot be unwrapped, or if
150 * <code>wrappedKeyType</code> is an inappropriate type for the
151 * unwrapped key.
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,
156 int wrappedKeyType)
157 throws InvalidKeyException, NoSuchAlgorithmException
159 byte[] keyBytes;
162 keyBytes = kwAlgorithm.unwrap(wrappedKey, 0, wrappedKey.length);
164 catch (KeyUnwrappingException x)
166 InvalidKeyException y = new InvalidKeyException("engineUnwrap()");
167 y.initCause(x);
168 throw y;
170 Key result;
171 switch (wrappedKeyType)
173 case Cipher.SECRET_KEY:
174 result = new SecretKeySpec(keyBytes, wrappedKeyAlgorithm);
175 break;
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);
184 else
185 result = keyFactory.generatePublic(keySpec);
187 catch (InvalidKeySpecException x)
189 InvalidKeyException y = new InvalidKeyException("engineUnwrap()");
190 y.initCause(x);
191 throw y;
193 break;
194 default:
195 IllegalArgumentException x = new IllegalArgumentException("Invalid 'wrappedKeyType': "
196 + wrappedKeyType);
197 InvalidKeyException y = new InvalidKeyException("engineUnwrap()");
198 y.initCause(x);
199 throw y;
201 return result;
204 protected int engineGetBlockSize()
206 return kwaBlockSize;
209 protected byte[] engineGetIV()
211 return iv == null ? null : (byte[]) iv.clone();
214 protected int engineGetOutputSize(int inputLength)
216 switch (opmode)
218 case Cipher.WRAP_MODE:
219 return getOutputSizeForWrap(inputLength);
220 case Cipher.UNWRAP_MODE:
221 return getOutputSizeForUnwrap(inputLength);
222 default:
223 throw new IllegalStateException();
227 protected AlgorithmParameters engineGetParameters()
229 BlockCipherParameterSpec spec = new BlockCipherParameterSpec(iv,
230 kwaBlockSize,
231 kwaKeySize);
232 AlgorithmParameters result = null;
235 result = AlgorithmParameters.getInstance("BlockCipherParameters");
236 result.init(spec);
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");
248 return result;
251 protected void engineInit(int opmode, Key key, SecureRandom random)
252 throws InvalidKeyException
254 checkOpMode(opmode);
255 byte[] kekBytes = checkAndGetKekBytes(key);
256 initAlgorithm(opmode, kekBytes, null, random);
259 protected void engineInit(int opmode, Key key, AlgorithmParameters params,
260 SecureRandom random)
261 throws InvalidAlgorithmParameterException, InvalidKeyException
263 AlgorithmParameterSpec spec = null;
266 if (params != 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,
279 SecureRandom random)
280 throws InvalidAlgorithmParameterException, InvalidKeyException
282 checkOpMode(opmode);
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
297 + " is supported");
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
338 * the plain text.
339 * <p>
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
357 * the cipher text.
358 * <p>
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)
375 switch (opmode)
377 case Cipher.WRAP_MODE:
378 case Cipher.UNWRAP_MODE:
379 return;
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
389 * RAW format.
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);
401 return result;
404 private void initAlgorithm(int opmode, byte[] kek, byte[] ivBytes,
405 SecureRandom rnd)
406 throws InvalidKeyException
408 this.opmode = opmode;
409 Map attributes = new HashMap();
410 attributes.put(IKeyWrappingAlgorithm.KEY_ENCRYPTION_KEY_MATERIAL, kek);
411 if (ivBytes != null)
413 this.iv = (byte[]) ivBytes.clone();
414 attributes.put(IKeyWrappingAlgorithm.INITIAL_VALUE, this.iv);
416 else
417 this.iv = null;
418 if (rnd != null)
419 attributes.put(IKeyWrappingAlgorithm.SOURCE_OF_RANDOMNESS, rnd);
421 kwAlgorithm.init(attributes);