BaseWrapCipher.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
1package org.bouncycastle.jcajce.provider.symmetric.util;
2
3import java.security.AlgorithmParameters;
4import java.security.InvalidAlgorithmParameterException;
5import java.security.InvalidKeyException;
6import java.security.Key;
7import java.security.KeyFactory;
8import java.security.NoSuchAlgorithmException;
9import java.security.NoSuchProviderException;
10import java.security.PrivateKey;
11import java.security.SecureRandom;
12import java.security.spec.AlgorithmParameterSpec;
13import java.security.spec.InvalidKeySpecException;
14import java.security.spec.PKCS8EncodedKeySpec;
15import java.security.spec.X509EncodedKeySpec;
16
17import javax.crypto.BadPaddingException;
18import javax.crypto.Cipher;
19import javax.crypto.CipherSpi;
20import javax.crypto.IllegalBlockSizeException;
21import javax.crypto.NoSuchPaddingException;
22import javax.crypto.ShortBufferException;
23import javax.crypto.spec.IvParameterSpec;
24import javax.crypto.spec.PBEParameterSpec;
25// BEGIN android-removed
26// import javax.crypto.spec.RC2ParameterSpec;
27// import javax.crypto.spec.RC5ParameterSpec;
28// END android-removed
29import javax.crypto.spec.SecretKeySpec;
30
31import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
32import org.bouncycastle.crypto.CipherParameters;
33import org.bouncycastle.crypto.InvalidCipherTextException;
34import org.bouncycastle.crypto.Wrapper;
35import org.bouncycastle.crypto.params.KeyParameter;
36import org.bouncycastle.crypto.params.ParametersWithIV;
37import org.bouncycastle.jce.provider.BouncyCastleProvider;
38
39public abstract class BaseWrapCipher
40    extends CipherSpi
41    implements PBE
42{
43    //
44    // specs we can handle.
45    //
46    private Class[]                 availableSpecs =
47                                    {
48                                        IvParameterSpec.class,
49                                        PBEParameterSpec.class,
50                                        // BEGIN android-removed
51                                        // RC2ParameterSpec.class,
52                                        // RC5ParameterSpec.class
53                                        // END android-removed
54                                    };
55
56    protected int                     pbeType = PKCS12;
57    protected int                     pbeHash = SHA1;
58    protected int                     pbeKeySize;
59    protected int                     pbeIvSize;
60
61    protected AlgorithmParameters     engineParams = null;
62
63    protected Wrapper                 wrapEngine = null;
64
65    private int                       ivSize;
66    private byte[]                    iv;
67
68    protected BaseWrapCipher()
69    {
70    }
71
72    protected BaseWrapCipher(
73        Wrapper wrapEngine)
74    {
75        this(wrapEngine, 0);
76    }
77
78    protected BaseWrapCipher(
79        Wrapper wrapEngine,
80        int ivSize)
81    {
82        this.wrapEngine = wrapEngine;
83        this.ivSize = ivSize;
84    }
85
86    protected int engineGetBlockSize()
87    {
88        return 0;
89    }
90
91    protected byte[] engineGetIV()
92    {
93        return (byte[])iv.clone();
94    }
95
96    protected int engineGetKeySize(
97        Key     key)
98    {
99        return key.getEncoded().length;
100    }
101
102    protected int engineGetOutputSize(
103        int     inputLen)
104    {
105        return -1;
106    }
107
108    protected AlgorithmParameters engineGetParameters()
109    {
110        return null;
111    }
112
113    protected void engineSetMode(
114        String  mode)
115        throws NoSuchAlgorithmException
116    {
117        throw new NoSuchAlgorithmException("can't support mode " + mode);
118    }
119
120    protected void engineSetPadding(
121        String  padding)
122    throws NoSuchPaddingException
123    {
124        throw new NoSuchPaddingException("Padding " + padding + " unknown.");
125    }
126
127    protected void engineInit(
128        int                     opmode,
129        Key                     key,
130        AlgorithmParameterSpec  params,
131        SecureRandom            random)
132    throws InvalidKeyException, InvalidAlgorithmParameterException
133    {
134        CipherParameters        param;
135
136        if (key instanceof BCPBEKey)
137        {
138            BCPBEKey k = (BCPBEKey)key;
139
140            if (params instanceof PBEParameterSpec)
141            {
142                param = PBE.Util.makePBEParameters(k, params, wrapEngine.getAlgorithmName());
143            }
144            else if (k.getParam() != null)
145            {
146                param = k.getParam();
147            }
148            else
149            {
150                throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
151            }
152        }
153        else
154        {
155            param = new KeyParameter(key.getEncoded());
156        }
157
158        if (params instanceof IvParameterSpec)
159        {
160            IvParameterSpec iv = (IvParameterSpec) params;
161            param = new ParametersWithIV(param, iv.getIV());
162        }
163
164        if (param instanceof KeyParameter && ivSize != 0)
165        {
166            iv = new byte[ivSize];
167            random.nextBytes(iv);
168            param = new ParametersWithIV(param, iv);
169        }
170
171        switch (opmode)
172        {
173        case Cipher.WRAP_MODE:
174            wrapEngine.init(true, param);
175            break;
176        case Cipher.UNWRAP_MODE:
177            wrapEngine.init(false, param);
178            break;
179        case Cipher.ENCRYPT_MODE:
180        case Cipher.DECRYPT_MODE:
181            throw new IllegalArgumentException("engine only valid for wrapping");
182        default:
183            System.out.println("eeek!");
184        }
185    }
186
187    protected void engineInit(
188        int                 opmode,
189        Key                 key,
190        AlgorithmParameters params,
191        SecureRandom        random)
192    throws InvalidKeyException, InvalidAlgorithmParameterException
193    {
194        AlgorithmParameterSpec  paramSpec = null;
195
196        if (params != null)
197        {
198            for (int i = 0; i != availableSpecs.length; i++)
199            {
200                try
201                {
202                    paramSpec = params.getParameterSpec(availableSpecs[i]);
203                    break;
204                }
205                catch (Exception e)
206                {
207                    // try next spec
208                }
209            }
210
211            if (paramSpec == null)
212            {
213                throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
214            }
215        }
216
217        engineParams = params;
218        engineInit(opmode, key, paramSpec, random);
219    }
220
221    protected void engineInit(
222        int                 opmode,
223        Key                 key,
224        SecureRandom        random)
225        throws InvalidKeyException
226    {
227        try
228        {
229            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
230        }
231        catch (InvalidAlgorithmParameterException e)
232        {
233            throw new IllegalArgumentException(e.getMessage());
234        }
235    }
236
237    protected byte[] engineUpdate(
238        byte[]  input,
239        int     inputOffset,
240        int     inputLen)
241    {
242        throw new RuntimeException("not supported for wrapping");
243    }
244
245    protected int engineUpdate(
246        byte[]  input,
247        int     inputOffset,
248        int     inputLen,
249        byte[]  output,
250        int     outputOffset)
251        throws ShortBufferException
252    {
253        throw new RuntimeException("not supported for wrapping");
254    }
255
256    protected byte[] engineDoFinal(
257        byte[]  input,
258        int     inputOffset,
259        int     inputLen)
260        throws IllegalBlockSizeException, BadPaddingException
261    {
262        return null;
263    }
264
265    // BEGIN android-changed
266    // added ShortBufferException to throws statement
267    protected int engineDoFinal(
268        byte[]  input,
269        int     inputOffset,
270        int     inputLen,
271        byte[]  output,
272        int     outputOffset)
273        throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
274    {
275        return 0;
276    }
277    // END android-changed
278
279    protected byte[] engineWrap(
280        Key     key)
281    throws IllegalBlockSizeException, InvalidKeyException
282    {
283        byte[] encoded = key.getEncoded();
284        if (encoded == null)
285        {
286            throw new InvalidKeyException("Cannot wrap key, null encoding.");
287        }
288
289        try
290        {
291            if (wrapEngine == null)
292            {
293                return engineDoFinal(encoded, 0, encoded.length);
294            }
295            else
296            {
297                return wrapEngine.wrap(encoded, 0, encoded.length);
298            }
299        }
300        catch (BadPaddingException e)
301        {
302            throw new IllegalBlockSizeException(e.getMessage());
303        }
304    }
305
306    protected Key engineUnwrap(
307        byte[]  wrappedKey,
308        String  wrappedKeyAlgorithm,
309        int     wrappedKeyType)
310    // BEGIN android-removed
311    // throws InvalidKeyException
312    // END android-removed
313    // BEGIN android-added
314    throws InvalidKeyException, NoSuchAlgorithmException
315    // END android-added
316    {
317        byte[] encoded;
318        try
319        {
320            if (wrapEngine == null)
321            {
322                encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
323            }
324            else
325            {
326                encoded = wrapEngine.unwrap(wrappedKey, 0, wrappedKey.length);
327            }
328        }
329        catch (InvalidCipherTextException e)
330        {
331            throw new InvalidKeyException(e.getMessage());
332        }
333        catch (BadPaddingException e)
334        {
335            throw new InvalidKeyException(e.getMessage());
336        }
337        catch (IllegalBlockSizeException e2)
338        {
339            throw new InvalidKeyException(e2.getMessage());
340        }
341
342        if (wrappedKeyType == Cipher.SECRET_KEY)
343        {
344            return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
345        }
346        else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY)
347        {
348            /*
349                 * The caller doesn't know the algorithm as it is part of
350                 * the encrypted data.
351                 */
352            try
353            {
354                PrivateKeyInfo       in = PrivateKeyInfo.getInstance(encoded);
355
356                PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in);
357
358                if (privKey != null)
359                {
360                    return privKey;
361                }
362                else
363                {
364                    throw new InvalidKeyException("algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported");
365                }
366            }
367            catch (Exception e)
368            {
369                throw new InvalidKeyException("Invalid key encoding.");
370            }
371        }
372        else
373        {
374            try
375            {
376                KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
377
378                if (wrappedKeyType == Cipher.PUBLIC_KEY)
379                {
380                    return kf.generatePublic(new X509EncodedKeySpec(encoded));
381                }
382                else if (wrappedKeyType == Cipher.PRIVATE_KEY)
383                {
384                    return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
385                }
386            }
387            catch (NoSuchProviderException e)
388            {
389                throw new InvalidKeyException("Unknown key type " + e.getMessage());
390            }
391            // BEGIN android-removed
392            // catch (NoSuchAlgorithmException e)
393            // {
394            //     throw new InvalidKeyException("Unknown key type " + e.getMessage());
395            // }
396            // END android-removed
397            catch (InvalidKeySpecException e2)
398            {
399                throw new InvalidKeyException("Unknown key type " + e2.getMessage());
400            }
401
402            throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
403        }
404    }
405
406}
407