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