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