BaseStreamCipher.java revision 5db505e1f6a68c8d5dfdb0fed0b8607dea7bed96
1package org.bouncycastle.jcajce.provider.symmetric.util;
2
3import java.security.AlgorithmParameters;
4import java.security.InvalidAlgorithmParameterException;
5import java.security.InvalidKeyException;
6import java.security.InvalidParameterException;
7import java.security.Key;
8import java.security.SecureRandom;
9import java.security.spec.AlgorithmParameterSpec;
10
11import javax.crypto.Cipher;
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;
27import org.bouncycastle.crypto.params.KeyParameter;
28import org.bouncycastle.crypto.params.ParametersWithIV;
29import org.bouncycastle.jce.provider.BouncyCastleProvider;
30
31public class BaseStreamCipher
32    extends BaseWrapCipher
33    implements PBE
34{
35    //
36    // specs we can handle.
37    //
38    private Class[]                 availableSpecs =
39                                    {
40                                        // BEGIN android-removed
41                                        // RC2ParameterSpec.class,
42                                        // RC5ParameterSpec.class,
43                                        // END android-removed
44                                        IvParameterSpec.class,
45                                        PBEParameterSpec.class
46                                    };
47
48    private StreamCipher       cipher;
49    private ParametersWithIV   ivParam;
50
51    private int                     ivLength = 0;
52
53    private PBEParameterSpec        pbeSpec = null;
54    private String                  pbeAlgorithm = null;
55
56    protected BaseStreamCipher(
57        StreamCipher engine,
58        int ivLength)
59    {
60        cipher = engine;
61        this.ivLength = ivLength;
62    }
63
64    protected BaseStreamCipher(
65        BlockCipher engine,
66        int ivLength)
67    {
68        this.ivLength = ivLength;
69
70        cipher = new StreamBlockCipher(engine);
71    }
72
73    protected int engineGetBlockSize()
74    {
75        return 0;
76    }
77
78    protected byte[] engineGetIV()
79    {
80        return (ivParam != null) ? ivParam.getIV() : null;
81    }
82
83    protected int engineGetKeySize(
84        Key     key)
85    {
86        return key.getEncoded().length * 8;
87    }
88
89    protected int engineGetOutputSize(
90        int     inputLen)
91    {
92        return inputLen;
93    }
94
95    protected AlgorithmParameters engineGetParameters()
96    {
97        if (engineParams == null)
98        {
99            if (pbeSpec != null)
100            {
101                try
102                {
103                    AlgorithmParameters engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
104                    engineParams.init(pbeSpec);
105
106                    return engineParams;
107                }
108                catch (Exception e)
109                {
110                    return null;
111                }
112            }
113        }
114
115        return engineParams;
116    }
117
118    /**
119     * should never be called.
120     */
121    protected void engineSetMode(
122        String  mode)
123    {
124        if (!mode.equalsIgnoreCase("ECB"))
125        {
126            throw new IllegalArgumentException("can't support mode " + mode);
127        }
128    }
129
130    /**
131     * should never be called.
132     */
133    protected void engineSetPadding(
134        String  padding)
135    throws NoSuchPaddingException
136    {
137        if (!padding.equalsIgnoreCase("NoPadding"))
138        {
139            throw new NoSuchPaddingException("Padding " + padding + " unknown.");
140        }
141    }
142
143    protected void engineInit(
144        int                     opmode,
145        Key                     key,
146        AlgorithmParameterSpec  params,
147        SecureRandom            random)
148        throws InvalidKeyException, InvalidAlgorithmParameterException
149    {
150        CipherParameters        param;
151
152        this.pbeSpec = null;
153        this.pbeAlgorithm = null;
154
155        this.engineParams = null;
156
157        //
158        // basic key check
159        //
160        if (!(key instanceof SecretKey))
161        {
162            throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
163        }
164
165        if (key instanceof BCPBEKey)
166        {
167            BCPBEKey k = (BCPBEKey)key;
168
169            if (k.getOID() != null)
170            {
171                pbeAlgorithm = k.getOID().getId();
172            }
173            else
174            {
175                pbeAlgorithm = k.getAlgorithm();
176            }
177
178            if (k.getParam() != null)
179            {
180                param = k.getParam();
181                pbeSpec = new PBEParameterSpec(k.getSalt(), k.getIterationCount());
182            }
183            else if (params instanceof PBEParameterSpec)
184            {
185                param = PBE.Util.makePBEParameters(k, params, cipher.getAlgorithmName());
186                pbeSpec = (PBEParameterSpec)params;
187            }
188            else
189            {
190                throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
191            }
192
193            if (k.getIvSize() != 0)
194            {
195                ivParam = (ParametersWithIV)param;
196            }
197        }
198        else if (params == null)
199        {
200            param = new KeyParameter(key.getEncoded());
201        }
202        else if (params instanceof IvParameterSpec)
203        {
204            param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
205            ivParam = (ParametersWithIV)param;
206        }
207        else
208        {
209            throw new InvalidAlgorithmParameterException("unknown parameter type.");
210        }
211
212        if ((ivLength != 0) && !(param instanceof ParametersWithIV))
213        {
214            SecureRandom    ivRandom = random;
215
216            if (ivRandom == null)
217            {
218                ivRandom = new SecureRandom();
219            }
220
221            if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
222            {
223                byte[]  iv = new byte[ivLength];
224
225                ivRandom.nextBytes(iv);
226                param = new ParametersWithIV(param, iv);
227                ivParam = (ParametersWithIV)param;
228            }
229            else
230            {
231                throw new InvalidAlgorithmParameterException("no IV set when one expected");
232            }
233        }
234
235        try
236        {
237            switch (opmode)
238            {
239            case Cipher.ENCRYPT_MODE:
240            case Cipher.WRAP_MODE:
241                cipher.init(true, param);
242                break;
243            case Cipher.DECRYPT_MODE:
244            case Cipher.UNWRAP_MODE:
245                cipher.init(false, param);
246                break;
247            default:
248                throw new InvalidParameterException("unknown opmode " + opmode + " passed");
249            }
250        }
251        catch (Exception e)
252        {
253            throw new InvalidKeyException(e.getMessage());
254        }
255    }
256
257    protected void engineInit(
258        int                 opmode,
259        Key                 key,
260        AlgorithmParameters params,
261        SecureRandom        random)
262        throws InvalidKeyException, InvalidAlgorithmParameterException
263    {
264        AlgorithmParameterSpec  paramSpec = null;
265
266        if (params != null)
267        {
268            for (int i = 0; i != availableSpecs.length; i++)
269            {
270                try
271                {
272                    paramSpec = params.getParameterSpec(availableSpecs[i]);
273                    break;
274                }
275                catch (Exception e)
276                {
277                    continue;
278                }
279            }
280
281            if (paramSpec == null)
282            {
283                throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
284            }
285        }
286
287        engineInit(opmode, key, paramSpec, random);
288        engineParams = params;
289    }
290
291    protected void engineInit(
292        int                 opmode,
293        Key                 key,
294        SecureRandom        random)
295        throws InvalidKeyException
296    {
297        try
298        {
299            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
300        }
301        catch (InvalidAlgorithmParameterException e)
302        {
303            throw new InvalidKeyException(e.getMessage());
304        }
305    }
306
307    protected byte[] engineUpdate(
308        byte[]  input,
309        int     inputOffset,
310        int     inputLen)
311    {
312        byte[]  out = new byte[inputLen];
313
314        cipher.processBytes(input, inputOffset, inputLen, out, 0);
315
316        return out;
317    }
318
319    protected int engineUpdate(
320        byte[]  input,
321        int     inputOffset,
322        int     inputLen,
323        byte[]  output,
324        int     outputOffset)
325        throws ShortBufferException
326    {
327        try
328        {
329        cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
330
331        return inputLen;
332        }
333        catch (DataLengthException e)
334        {
335            throw new ShortBufferException(e.getMessage());
336        }
337    }
338
339    protected byte[] engineDoFinal(
340        byte[]  input,
341        int     inputOffset,
342        int     inputLen)
343    {
344        if (inputLen != 0)
345        {
346            byte[] out = engineUpdate(input, inputOffset, inputLen);
347
348            cipher.reset();
349
350            return out;
351        }
352
353        cipher.reset();
354
355        return new byte[0];
356    }
357
358    protected int engineDoFinal(
359        byte[]  input,
360        int     inputOffset,
361        int     inputLen,
362        byte[]  output,
363        int     outputOffset)
364    {
365        if (inputLen != 0)
366        {
367            cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
368        }
369
370        cipher.reset();
371
372        return inputLen;
373    }
374}
375