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