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