PageRenderTime 61ms CodeModel.GetById 31ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 1ms

/extern/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/IESCipher.java

https://gitlab.com/vizilo/fdroidclient
Java | 507 lines | 424 code | 70 blank | 13 comment | 76 complexity | 5e8495b304d60f793c0f0a58720f2a67 MD5 | raw file
  1package org.spongycastle.jcajce.provider.asymmetric.dh;
  2
  3import java.io.ByteArrayOutputStream;
  4import java.security.AlgorithmParameters;
  5import java.security.InvalidAlgorithmParameterException;
  6import java.security.InvalidKeyException;
  7import java.security.Key;
  8import java.security.NoSuchAlgorithmException;
  9import java.security.PrivateKey;
 10import java.security.PublicKey;
 11import java.security.SecureRandom;
 12import java.security.spec.AlgorithmParameterSpec;
 13
 14import javax.crypto.BadPaddingException;
 15import javax.crypto.Cipher;
 16import javax.crypto.CipherSpi;
 17import javax.crypto.IllegalBlockSizeException;
 18import javax.crypto.NoSuchPaddingException;
 19import javax.crypto.ShortBufferException;
 20import javax.crypto.interfaces.DHKey;
 21import javax.crypto.interfaces.DHPrivateKey;
 22import javax.crypto.interfaces.DHPublicKey;
 23
 24import org.spongycastle.crypto.InvalidCipherTextException;
 25import org.spongycastle.crypto.KeyEncoder;
 26import org.spongycastle.crypto.agreement.DHBasicAgreement;
 27import org.spongycastle.crypto.digests.SHA1Digest;
 28import org.spongycastle.crypto.engines.AESEngine;
 29import org.spongycastle.crypto.engines.DESedeEngine;
 30import org.spongycastle.crypto.engines.IESEngine;
 31import org.spongycastle.crypto.generators.DHKeyPairGenerator;
 32import org.spongycastle.crypto.generators.EphemeralKeyPairGenerator;
 33import org.spongycastle.crypto.generators.KDF2BytesGenerator;
 34import org.spongycastle.crypto.macs.HMac;
 35import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
 36import org.spongycastle.crypto.params.AsymmetricKeyParameter;
 37import org.spongycastle.crypto.params.DHKeyGenerationParameters;
 38import org.spongycastle.crypto.params.DHKeyParameters;
 39import org.spongycastle.crypto.params.DHParameters;
 40import org.spongycastle.crypto.params.DHPublicKeyParameters;
 41import org.spongycastle.crypto.params.IESParameters;
 42import org.spongycastle.crypto.params.IESWithCipherParameters;
 43import org.spongycastle.crypto.parsers.DHIESPublicKeyParser;
 44import org.spongycastle.jcajce.provider.asymmetric.util.DHUtil;
 45import org.spongycastle.jcajce.provider.asymmetric.util.IESUtil;
 46import org.spongycastle.jce.interfaces.IESKey;
 47import org.spongycastle.jce.provider.BouncyCastleProvider;
 48import org.spongycastle.jce.spec.IESParameterSpec;
 49import org.spongycastle.util.BigIntegers;
 50import org.spongycastle.util.Strings;
 51
 52
 53public class IESCipher
 54    extends CipherSpi
 55{
 56    private IESEngine engine;
 57    private int state = -1;
 58    private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
 59    private AlgorithmParameters engineParam = null;
 60    private IESParameterSpec engineSpec = null;
 61    private AsymmetricKeyParameter key;
 62    private SecureRandom random;
 63    private boolean dhaesMode = false;
 64    private AsymmetricKeyParameter otherKeyParameter = null;
 65
 66    public IESCipher(IESEngine engine)
 67    {
 68        this.engine = engine;
 69    }
 70
 71
 72    public int engineGetBlockSize()
 73    {
 74        if (engine.getCipher() != null)
 75        {
 76            return engine.getCipher().getBlockSize();
 77        }
 78        else
 79        {
 80            return 0;
 81        }
 82    }
 83
 84
 85    public int engineGetKeySize(Key key)
 86    {
 87        if (key instanceof DHKey)
 88        {
 89            return ((DHKey)key).getParams().getP().bitLength();
 90        }
 91        else
 92        {
 93            throw new IllegalArgumentException("not a DH key");
 94        }
 95    }
 96
 97
 98    public byte[] engineGetIV()
 99    {
100        return null;
101    }
102
103    public AlgorithmParameters engineGetParameters()
104    {
105        if (engineParam == null && engineSpec != null)
106        {
107            try
108            {
109                engineParam = AlgorithmParameters.getInstance("IES", BouncyCastleProvider.PROVIDER_NAME);
110                engineParam.init(engineSpec);
111            }
112            catch (Exception e)
113            {
114                throw new RuntimeException(e.toString());
115            }
116        }
117
118        return engineParam;
119    }
120
121
122    public void engineSetMode(String mode)
123        throws NoSuchAlgorithmException
124    {
125        String modeName = Strings.toUpperCase(mode);
126
127        if (modeName.equals("NONE"))
128        {
129            dhaesMode = false;
130        }
131        else if (modeName.equals("DHAES"))
132        {
133            dhaesMode = true;
134        }
135        else
136        {
137            throw new IllegalArgumentException("can't support mode " + mode);
138        }
139    }
140
141    public int engineGetOutputSize(int inputLen)
142    {
143        int len1, len2, len3;
144
145        len1 = engine.getMac().getMacSize();
146
147        if (key != null)
148        {
149            len2 = ((DHKey)key).getParams().getP().bitLength() / 8 + 1;
150        }
151        else
152        {
153            throw new IllegalStateException("cipher not initialised");
154        }
155
156        if (engine.getCipher() == null)
157        {
158            len3 = inputLen;
159        }
160        else if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
161        {
162            len3 = engine.getCipher().getOutputSize(inputLen);
163        }
164        else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
165        {
166            len3 = engine.getCipher().getOutputSize(inputLen - len1 - len2);
167        }
168        else
169        {
170            throw new IllegalStateException("cipher not initialised");
171        }
172
173        if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
174        {
175            return buffer.size() + len1 + len2 + len3;
176        }
177        else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
178        {
179            return buffer.size() - len1 - len2 + len3;
180        }
181        else
182        {
183            throw new IllegalStateException("IESCipher not initialised");
184        }
185
186    }
187
188    public void engineSetPadding(String padding)
189        throws NoSuchPaddingException
190    {
191        String paddingName = Strings.toUpperCase(padding);
192
193        // TDOD: make this meaningful...
194        if (paddingName.equals("NOPADDING"))
195        {
196
197        }
198        else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING"))
199        {
200
201        }
202        else
203        {
204            throw new NoSuchPaddingException("padding not available with IESCipher");
205        }
206    }
207
208    // Initialisation methods
209
210    public void engineInit(
211        int opmode,
212        Key key,
213        AlgorithmParameters params,
214        SecureRandom random)
215        throws InvalidKeyException, InvalidAlgorithmParameterException
216    {
217        AlgorithmParameterSpec paramSpec = null;
218
219        if (params != null)
220        {
221            try
222            {
223                paramSpec = params.getParameterSpec(IESParameterSpec.class);
224            }
225            catch (Exception e)
226            {
227                throw new InvalidAlgorithmParameterException("cannot recognise parameters: " + e.toString());
228            }
229        }
230
231        engineParam = params;
232        engineInit(opmode, key, paramSpec, random);
233    }
234
235
236    public void engineInit(
237        int opmode,
238        Key key,
239        AlgorithmParameterSpec engineSpec,
240        SecureRandom random)
241        throws InvalidAlgorithmParameterException, InvalidKeyException
242    {
243        // Use default parameters (including cipher key size) if none are specified
244        if (engineSpec == null)
245        {
246            this.engineSpec = IESUtil.guessParameterSpec(engine);
247        }
248        else if (engineSpec instanceof IESParameterSpec)
249        {
250            this.engineSpec = (IESParameterSpec)engineSpec;
251        }
252        else
253        {
254            throw new InvalidAlgorithmParameterException("must be passed IES parameters");
255        }
256
257        // Parse the recipient's key
258        if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE)
259        {
260            if (key instanceof DHPublicKey)
261            {
262                this.key = DHUtil.generatePublicKeyParameter((PublicKey)key);
263            }
264            else if (key instanceof IESKey)
265            {
266                IESKey ieKey = (IESKey)key;
267
268                this.key = DHUtil.generatePublicKeyParameter(ieKey.getPublic());
269                this.otherKeyParameter = DHUtil.generatePrivateKeyParameter(ieKey.getPrivate());
270            }
271            else
272            {
273                throw new InvalidKeyException("must be passed recipient's public DH key for encryption");
274            }
275        }
276        else if (opmode == Cipher.DECRYPT_MODE || opmode == Cipher.UNWRAP_MODE)
277        {
278            if (key instanceof DHPrivateKey)
279            {
280                this.key = DHUtil.generatePrivateKeyParameter((PrivateKey)key);
281            }
282            else if (key instanceof IESKey)
283            {
284                IESKey ieKey = (IESKey)key;
285
286                this.otherKeyParameter = DHUtil.generatePublicKeyParameter(ieKey.getPublic());
287                this.key = DHUtil.generatePrivateKeyParameter(ieKey.getPrivate());
288            }
289            else
290            {
291                throw new InvalidKeyException("must be passed recipient's private DH key for decryption");
292            }
293        }
294        else
295        {
296            throw new InvalidKeyException("must be passed EC key");
297        }
298
299        this.random = random;
300        this.state = opmode;
301        buffer.reset();
302
303    }
304
305
306    public void engineInit(
307        int opmode,
308        Key key,
309        SecureRandom random)
310        throws InvalidKeyException
311    {
312        try
313        {
314            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
315        }
316        catch (InvalidAlgorithmParameterException e)
317        {
318            throw new IllegalArgumentException("can't handle supplied parameter spec");
319        }
320
321    }
322
323
324    // Update methods - buffer the input
325
326    public byte[] engineUpdate(
327        byte[] input,
328        int inputOffset,
329        int inputLen)
330    {
331        buffer.write(input, inputOffset, inputLen);
332        return null;
333    }
334
335
336    public int engineUpdate(
337        byte[] input,
338        int inputOffset,
339        int inputLen,
340        byte[] output,
341        int outputOffset)
342    {
343        buffer.write(input, inputOffset, inputLen);
344        return 0;
345    }
346
347
348    // Finalisation methods
349
350    public byte[] engineDoFinal(
351        byte[] input,
352        int inputOffset,
353        int inputLen)
354        throws IllegalBlockSizeException, BadPaddingException
355    {
356        if (inputLen != 0)
357        {
358            buffer.write(input, inputOffset, inputLen);
359        }
360
361        byte[] in = buffer.toByteArray();
362        buffer.reset();
363
364        // Convert parameters for use in IESEngine
365        IESParameters params = new IESWithCipherParameters(engineSpec.getDerivationV(),
366            engineSpec.getEncodingV(),
367            engineSpec.getMacKeySize(),
368            engineSpec.getCipherKeySize());
369
370        DHParameters dhParams = ((DHKeyParameters)key).getParameters();
371
372        byte[] V;
373        if (otherKeyParameter != null)
374        {
375            try
376            {
377                if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
378                {
379                    engine.init(true, otherKeyParameter, key, params);
380                }
381                else
382                {
383                    engine.init(false, key, otherKeyParameter, params);
384                }
385                return engine.processBlock(in, 0, in.length);
386            }
387            catch (Exception e)
388            {
389                throw new BadPaddingException(e.getMessage());
390            }
391        }
392
393        if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
394        {
395            // Generate the ephemeral key pair
396            DHKeyPairGenerator gen = new DHKeyPairGenerator();
397            gen.init(new DHKeyGenerationParameters(random, dhParams));
398
399            EphemeralKeyPairGenerator kGen = new EphemeralKeyPairGenerator(gen, new KeyEncoder()
400            {
401                public byte[] getEncoded(AsymmetricKeyParameter keyParameter)
402                {
403                    byte[] Vloc = new byte[(((DHKeyParameters)keyParameter).getParameters().getP().bitLength() + 7) / 8];
404                    byte[] Vtmp = BigIntegers.asUnsignedByteArray(((DHPublicKeyParameters)keyParameter).getY());
405
406                    if (Vtmp.length > Vloc.length)
407                    {
408                        throw new IllegalArgumentException("Senders's public key longer than expected.");
409                    }
410                    else
411                    {
412                        System.arraycopy(Vtmp, 0, Vloc, Vloc.length - Vtmp.length, Vtmp.length);
413                    }
414
415                    return Vloc;
416                }
417            });
418
419            // Encrypt the buffer
420            try
421            {
422                engine.init(key, params, kGen);
423
424                return engine.processBlock(in, 0, in.length);
425            }
426            catch (Exception e)
427            {
428                throw new BadPaddingException(e.getMessage());
429            }
430        }
431        else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
432        {
433            // Decrypt the buffer
434            try
435            {
436                engine.init(key, params, new DHIESPublicKeyParser(((DHKeyParameters)key).getParameters()));
437
438                return engine.processBlock(in, 0, in.length);
439            }
440            catch (InvalidCipherTextException e)
441            {
442                throw new BadPaddingException(e.getMessage());
443            }
444        }
445        else
446        {
447            throw new IllegalStateException("IESCipher not initialised");
448        }
449
450    }
451
452
453    public int engineDoFinal(
454        byte[] input,
455        int inputOffset,
456        int inputLength,
457        byte[] output,
458        int outputOffset)
459        throws ShortBufferException, IllegalBlockSizeException, BadPaddingException
460    {
461
462        byte[] buf = engineDoFinal(input, inputOffset, inputLength);
463        System.arraycopy(buf, 0, output, outputOffset, buf.length);
464        return buf.length;
465
466    }
467
468
469    /**
470     * Classes that inherit from us
471     */
472
473    static public class IES
474        extends IESCipher
475    {
476        public IES()
477        {
478            super(new IESEngine(new DHBasicAgreement(),
479                new KDF2BytesGenerator(new SHA1Digest()),
480                new HMac(new SHA1Digest())));
481        }
482    }
483
484    static public class IESwithDESede
485        extends IESCipher
486    {
487        public IESwithDESede()
488        {
489            super(new IESEngine(new DHBasicAgreement(),
490                new KDF2BytesGenerator(new SHA1Digest()),
491                new HMac(new SHA1Digest()),
492                new PaddedBufferedBlockCipher(new DESedeEngine())));
493        }
494    }
495
496    static public class IESwithAES
497        extends IESCipher
498    {
499        public IESwithAES()
500        {
501            super(new IESEngine(new DHBasicAgreement(),
502                new KDF2BytesGenerator(new SHA1Digest()),
503                new HMac(new SHA1Digest()),
504                new PaddedBufferedBlockCipher(new AESEngine())));
505        }
506    }
507}