JCEStreamCipher.java revision aea1f1224e7ad62991b68c485f086abcb289f82b
1package org.bouncycastle.jce.provider;
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.SecretKey;
23import javax.crypto.ShortBufferException;
24import javax.crypto.spec.IvParameterSpec;
25import javax.crypto.spec.PBEParameterSpec;
26// BEGIN android-removed
27// import javax.crypto.spec.RC2ParameterSpec;
28// import javax.crypto.spec.RC5ParameterSpec;
29// END android-removed
30import javax.crypto.spec.SecretKeySpec;
31
32import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
33import org.bouncycastle.crypto.BlockCipher;
34import org.bouncycastle.crypto.CipherParameters;
35import org.bouncycastle.crypto.DataLengthException;
36import org.bouncycastle.crypto.StreamBlockCipher;
37import org.bouncycastle.crypto.StreamCipher;
38// BEGIN android-removed
39// import org.bouncycastle.crypto.engines.BlowfishEngine;
40// import org.bouncycastle.crypto.engines.DESEngine;
41// import org.bouncycastle.crypto.engines.DESedeEngine;
42// END android-removed
43import org.bouncycastle.crypto.engines.RC4Engine;
44// BEGIN android-removed
45// import org.bouncycastle.crypto.engines.SkipjackEngine;
46// import org.bouncycastle.crypto.engines.TwofishEngine;
47// END android-removed
48import org.bouncycastle.crypto.modes.CFBBlockCipher;
49import org.bouncycastle.crypto.modes.OFBBlockCipher;
50import org.bouncycastle.crypto.params.KeyParameter;
51import org.bouncycastle.crypto.params.ParametersWithIV;
52import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
53import org.bouncycastle.jcajce.provider.symmetric.util.PBE;
54
55public class JCEStreamCipher
56    extends CipherSpi
57    implements PBE
58{
59    //
60    // specs we can handle.
61    //
62    private Class[]                 availableSpecs =
63                                    {
64                                        // BEGIN android-removed
65                                        // RC2ParameterSpec.class,
66                                        // RC5ParameterSpec.class,
67                                        // END android-removed
68                                        IvParameterSpec.class,
69                                        PBEParameterSpec.class
70                                    };
71
72    private StreamCipher       cipher;
73    private ParametersWithIV   ivParam;
74
75    private int                     ivLength = 0;
76
77    private PBEParameterSpec        pbeSpec = null;
78    private String                  pbeAlgorithm = null;
79
80    private AlgorithmParameters engineParams;
81
82    protected JCEStreamCipher(
83        StreamCipher engine,
84        int          ivLength)
85    {
86        cipher = engine;
87        this.ivLength = ivLength;
88    }
89
90    protected JCEStreamCipher(
91        BlockCipher engine,
92        int         ivLength)
93    {
94        this.ivLength = ivLength;
95
96        cipher = new StreamBlockCipher(engine);
97    }
98
99    protected int engineGetBlockSize()
100    {
101        return 0;
102    }
103
104    protected byte[] engineGetIV()
105    {
106        return (ivParam != null) ? ivParam.getIV() : null;
107    }
108
109    protected int engineGetKeySize(
110        Key     key)
111    {
112        return key.getEncoded().length * 8;
113    }
114
115    protected int engineGetOutputSize(
116        int     inputLen)
117    {
118        return inputLen;
119    }
120
121    protected AlgorithmParameters engineGetParameters()
122    {
123        if (engineParams == null)
124        {
125            if (pbeSpec != null)
126            {
127                try
128                {
129                    AlgorithmParameters engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
130                    engineParams.init(pbeSpec);
131
132                    return engineParams;
133                }
134                catch (Exception e)
135                {
136                    return null;
137                }
138            }
139        }
140
141        return engineParams;
142    }
143
144    /**
145     * should never be called.
146     */
147    protected void engineSetMode(
148        String  mode)
149    {
150        if (!mode.equalsIgnoreCase("ECB"))
151        {
152            throw new IllegalArgumentException("can't support mode " + mode);
153        }
154    }
155
156    /**
157     * should never be called.
158     */
159    protected void engineSetPadding(
160        String  padding)
161    throws NoSuchPaddingException
162    {
163        if (!padding.equalsIgnoreCase("NoPadding"))
164        {
165            throw new NoSuchPaddingException("Padding " + padding + " unknown.");
166        }
167    }
168
169    protected void engineInit(
170        int                     opmode,
171        Key                     key,
172        AlgorithmParameterSpec  params,
173        SecureRandom            random)
174        throws InvalidKeyException, InvalidAlgorithmParameterException
175    {
176        CipherParameters        param;
177
178        this.pbeSpec = null;
179        this.pbeAlgorithm = null;
180
181        this.engineParams = null;
182
183        //
184        // basic key check
185        //
186        if (!(key instanceof SecretKey))
187        {
188            throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
189        }
190
191        if (key instanceof BCPBEKey)
192        {
193            BCPBEKey k = (BCPBEKey)key;
194
195            if (k.getOID() != null)
196            {
197                pbeAlgorithm = k.getOID().getId();
198            }
199            else
200            {
201                pbeAlgorithm = k.getAlgorithm();
202            }
203
204            if (k.getParam() != null)
205            {
206                param = k.getParam();
207                pbeSpec = new PBEParameterSpec(k.getSalt(), k.getIterationCount());
208            }
209            else if (params instanceof PBEParameterSpec)
210            {
211                param = PBE.Util.makePBEParameters(k, params, cipher.getAlgorithmName());
212                pbeSpec = (PBEParameterSpec)params;
213            }
214            else
215            {
216                throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
217            }
218
219            if (k.getIvSize() != 0)
220            {
221                ivParam = (ParametersWithIV)param;
222            }
223        }
224        else if (params == null)
225        {
226            param = new KeyParameter(key.getEncoded());
227        }
228        else if (params instanceof IvParameterSpec)
229        {
230            param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
231            ivParam = (ParametersWithIV)param;
232        }
233        else
234        {
235            throw new IllegalArgumentException("unknown parameter type.");
236        }
237
238        if ((ivLength != 0) && !(param instanceof ParametersWithIV))
239        {
240            SecureRandom    ivRandom = random;
241
242            if (ivRandom == null)
243            {
244                ivRandom = new SecureRandom();
245            }
246
247            if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
248            {
249                byte[]  iv = new byte[ivLength];
250
251                ivRandom.nextBytes(iv);
252                param = new ParametersWithIV(param, iv);
253                ivParam = (ParametersWithIV)param;
254            }
255            else
256            {
257                throw new InvalidAlgorithmParameterException("no IV set when one expected");
258            }
259        }
260
261        switch (opmode)
262        {
263        case Cipher.ENCRYPT_MODE:
264        case Cipher.WRAP_MODE:
265            cipher.init(true, param);
266            break;
267        case Cipher.DECRYPT_MODE:
268        case Cipher.UNWRAP_MODE:
269            cipher.init(false, param);
270            break;
271        default:
272            System.out.println("eeek!");
273        }
274    }
275
276    protected void engineInit(
277        int                 opmode,
278        Key                 key,
279        AlgorithmParameters params,
280        SecureRandom        random)
281        throws InvalidKeyException, InvalidAlgorithmParameterException
282    {
283        AlgorithmParameterSpec  paramSpec = null;
284
285        if (params != null)
286        {
287            for (int i = 0; i != availableSpecs.length; i++)
288            {
289                try
290                {
291                    paramSpec = params.getParameterSpec(availableSpecs[i]);
292                    break;
293                }
294                catch (Exception e)
295                {
296                    continue;
297                }
298            }
299
300            if (paramSpec == null)
301            {
302                throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
303            }
304        }
305
306        engineInit(opmode, key, paramSpec, random);
307        engineParams = params;
308    }
309
310    protected void engineInit(
311        int                 opmode,
312        Key                 key,
313        SecureRandom        random)
314        throws InvalidKeyException
315    {
316        try
317        {
318            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
319        }
320        catch (InvalidAlgorithmParameterException e)
321        {
322            throw new InvalidKeyException(e.getMessage());
323        }
324    }
325
326    protected byte[] engineUpdate(
327        byte[]  input,
328        int     inputOffset,
329        int     inputLen)
330    {
331        byte[]  out = new byte[inputLen];
332
333        cipher.processBytes(input, inputOffset, inputLen, out, 0);
334
335        return out;
336    }
337
338    protected int engineUpdate(
339        byte[]  input,
340        int     inputOffset,
341        int     inputLen,
342        byte[]  output,
343        int     outputOffset)
344        throws ShortBufferException
345    {
346        try
347        {
348        cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
349
350        return inputLen;
351        }
352        catch (DataLengthException e)
353        {
354            throw new ShortBufferException(e.getMessage());
355        }
356    }
357
358    protected byte[] engineDoFinal(
359        byte[]  input,
360        int     inputOffset,
361        int     inputLen)
362        throws BadPaddingException, IllegalBlockSizeException
363    {
364        if (inputLen != 0)
365        {
366            byte[] out = engineUpdate(input, inputOffset, inputLen);
367
368            cipher.reset();
369
370            return out;
371        }
372
373        cipher.reset();
374
375        return new byte[0];
376    }
377
378    protected int engineDoFinal(
379        byte[]  input,
380        int     inputOffset,
381        int     inputLen,
382        byte[]  output,
383        int     outputOffset)
384        throws BadPaddingException
385    {
386        if (inputLen != 0)
387        {
388            cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
389        }
390
391        cipher.reset();
392
393        return inputLen;
394    }
395
396    protected byte[] engineWrap(
397         Key     key)
398     throws IllegalBlockSizeException, InvalidKeyException
399     {
400         byte[] encoded = key.getEncoded();
401         if (encoded == null)
402         {
403             throw new InvalidKeyException("Cannot wrap key, null encoding.");
404         }
405
406         try
407         {
408             return engineDoFinal(encoded, 0, encoded.length);
409         }
410         catch (BadPaddingException e)
411         {
412             throw new IllegalBlockSizeException(e.getMessage());
413         }
414     }
415
416     protected Key engineUnwrap(
417         byte[] wrappedKey,
418         String wrappedKeyAlgorithm,
419         int wrappedKeyType)
420         throws InvalidKeyException
421     {
422         byte[] encoded;
423         try
424         {
425             encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
426         }
427         catch (BadPaddingException e)
428         {
429             throw new InvalidKeyException(e.getMessage());
430         }
431         catch (IllegalBlockSizeException e2)
432         {
433             throw new InvalidKeyException(e2.getMessage());
434         }
435
436         if (wrappedKeyType == Cipher.SECRET_KEY)
437         {
438             return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
439         }
440         else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY)
441         {
442             /*
443              * The caller doesn't know the algorithm as it is part of
444              * the encrypted data.
445              */
446             try
447             {
448                 PrivateKeyInfo in = PrivateKeyInfo.getInstance(encoded);
449
450                 PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in);
451
452                 if (privKey != null)
453                 {
454                     return privKey;
455                 }
456                 else
457                 {
458                     throw new InvalidKeyException("algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported");
459                 }
460             }
461             catch (Exception e)
462             {
463                 throw new InvalidKeyException("Invalid key encoding.");
464             }
465         }
466         else
467         {
468             try
469             {
470                 KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
471
472                 if (wrappedKeyType == Cipher.PUBLIC_KEY)
473                 {
474                     return kf.generatePublic(new X509EncodedKeySpec(encoded));
475                 }
476                 else if (wrappedKeyType == Cipher.PRIVATE_KEY)
477                 {
478                     return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
479                 }
480             }
481             catch (NoSuchProviderException e)
482             {
483                 throw new InvalidKeyException("Unknown key type " + e.getMessage());
484             }
485             catch (NoSuchAlgorithmException e)
486             {
487                 throw new InvalidKeyException("Unknown key type " + e.getMessage());
488             }
489             catch (InvalidKeySpecException e2)
490             {
491                 throw new InvalidKeyException("Unknown key type " + e2.getMessage());
492             }
493
494             throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
495         }
496     }
497
498    /*
499     * The ciphers that inherit from us.
500     */
501
502    // BEGIN android-removed
503    // /**
504    //  * DES
505    //  */
506    // static public class DES_CFB8
507    //     extends JCEStreamCipher
508    // {
509    //     public DES_CFB8()
510    //     {
511    //         super(new CFBBlockCipher(new DESEngine(), 8), 64);
512    //     }
513    // }
514    //
515    // /**
516    //  * DESede
517    //  */
518    // static public class DESede_CFB8
519    //     extends JCEStreamCipher
520    // {
521    //     public DESede_CFB8()
522    //     {
523    //         super(new CFBBlockCipher(new DESedeEngine(), 8), 64);
524    //     }
525    // }
526    //
527    // /**
528    //  * SKIPJACK
529    //  */
530    // static public class Skipjack_CFB8
531    //     extends JCEStreamCipher
532    // {
533    //     public Skipjack_CFB8()
534    //     {
535    //         super(new CFBBlockCipher(new SkipjackEngine(), 8), 64);
536    //     }
537    // }
538    //
539    // /**
540    //  * Blowfish
541    //  */
542    // static public class Blowfish_CFB8
543    //     extends JCEStreamCipher
544    // {
545    //     public Blowfish_CFB8()
546    //     {
547    //         super(new CFBBlockCipher(new BlowfishEngine(), 8), 64);
548    //     }
549    // }
550    //
551    // /**
552    //  * Twofish
553    //  */
554    // static public class Twofish_CFB8
555    //     extends JCEStreamCipher
556    // {
557    //     public Twofish_CFB8()
558    //     {
559    //         super(new CFBBlockCipher(new TwofishEngine(), 8), 128);
560    //     }
561    // }
562    //
563    // /**
564    //  * DES
565    //  */
566    // static public class DES_OFB8
567    //     extends JCEStreamCipher
568    // {
569    //     public DES_OFB8()
570    //     {
571    //         super(new OFBBlockCipher(new DESEngine(), 8), 64);
572    //     }
573    // }
574    //
575    // /**
576    //  * DESede
577    //  */
578    // static public class DESede_OFB8
579    //     extends JCEStreamCipher
580    // {
581    //     public DESede_OFB8()
582    //     {
583    //         super(new OFBBlockCipher(new DESedeEngine(), 8), 64);
584    //     }
585    // }
586    //
587    // /**
588    //  * SKIPJACK
589    //  */
590    // static public class Skipjack_OFB8
591    //     extends JCEStreamCipher
592    // {
593    //     public Skipjack_OFB8()
594    //     {
595    //         super(new OFBBlockCipher(new SkipjackEngine(), 8), 64);
596    //     }
597    // }
598    //
599    // /**
600    //  * Blowfish
601    //  */
602    // static public class Blowfish_OFB8
603    //     extends JCEStreamCipher
604    // {
605    //     public Blowfish_OFB8()
606    //     {
607    //         super(new OFBBlockCipher(new BlowfishEngine(), 8), 64);
608    //     }
609    // }
610    //
611    // /**
612    //  * Twofish
613    //  */
614    // static public class Twofish_OFB8
615    //     extends JCEStreamCipher
616    // {
617    //     public Twofish_OFB8()
618    //     {
619    //         super(new OFBBlockCipher(new TwofishEngine(), 8), 128);
620    //     }
621    // }
622    // END android-removed
623
624    /**
625     * PBEWithSHAAnd128BitRC4
626     */
627    static public class PBEWithSHAAnd128BitRC4
628        extends JCEStreamCipher
629    {
630        public PBEWithSHAAnd128BitRC4()
631        {
632            super(new RC4Engine(), 0);
633        }
634    }
635
636    /**
637     * PBEWithSHAAnd40BitRC4
638     */
639    static public class PBEWithSHAAnd40BitRC4
640        extends JCEStreamCipher
641    {
642        public PBEWithSHAAnd40BitRC4()
643        {
644            super(new RC4Engine(), 0);
645        }
646    }
647}
648