~brian-thomason/+junk/bouncycastle

« back to all changes in this revision

Viewing changes to src/org/bouncycastle/cert/crmf/jcajce/CRMFHelper.java

  • Committer: Brian Thomason
  • Date: 2011-12-20 17:20:32 UTC
  • Revision ID: brian.thomason@canonical.com-20111220172032-rdtm13jgdxtksacr
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package org.bouncycastle.cert.crmf.jcajce;
 
2
 
 
3
import java.io.IOException;
 
4
import java.security.AlgorithmParameterGenerator;
 
5
import java.security.AlgorithmParameters;
 
6
import java.security.GeneralSecurityException;
 
7
import java.security.InvalidAlgorithmParameterException;
 
8
import java.security.InvalidKeyException;
 
9
import java.security.Key;
 
10
import java.security.KeyFactory;
 
11
import java.security.MessageDigest;
 
12
import java.security.NoSuchAlgorithmException;
 
13
import java.security.NoSuchProviderException;
 
14
import java.security.PublicKey;
 
15
import java.security.SecureRandom;
 
16
import java.security.spec.InvalidKeySpecException;
 
17
import java.security.spec.InvalidParameterSpecException;
 
18
import java.security.spec.X509EncodedKeySpec;
 
19
import java.util.HashMap;
 
20
import java.util.Map;
 
21
 
 
22
import javax.crypto.Cipher;
 
23
import javax.crypto.KeyGenerator;
 
24
import javax.crypto.Mac;
 
25
import javax.crypto.NoSuchPaddingException;
 
26
import javax.crypto.SecretKey;
 
27
import javax.crypto.spec.IvParameterSpec;
 
28
import javax.crypto.spec.RC2ParameterSpec;
 
29
 
 
30
import org.bouncycastle.asn1.ASN1Null;
 
31
import org.bouncycastle.asn1.ASN1Object;
 
32
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
33
import org.bouncycastle.asn1.ASN1OctetString;
 
34
import org.bouncycastle.asn1.DERBitString;
 
35
import org.bouncycastle.asn1.DEREncodable;
 
36
import org.bouncycastle.asn1.DERNull;
 
37
import org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
 
38
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
 
39
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
 
40
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 
41
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
42
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
 
43
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 
44
import org.bouncycastle.cert.crmf.CRMFException;
 
45
import org.bouncycastle.cms.CMSAlgorithm;
 
46
import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
 
47
import org.bouncycastle.jcajce.JcaJceHelper;
 
48
 
 
49
class CRMFHelper
 
50
{
 
51
    protected static final Map BASE_CIPHER_NAMES = new HashMap();
 
52
    protected static final Map CIPHER_ALG_NAMES = new HashMap();
 
53
    protected static final Map DIGEST_ALG_NAMES = new HashMap();
 
54
    protected static final Map KEY_ALG_NAMES = new HashMap();
 
55
    protected static final Map MAC_ALG_NAMES = new HashMap();
 
56
 
 
57
    static
 
58
    {
 
59
        BASE_CIPHER_NAMES.put(PKCSObjectIdentifiers.des_EDE3_CBC,  "DESEDE");
 
60
        BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes128_CBC,  "AES");
 
61
        BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes192_CBC,  "AES");
 
62
        BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes256_CBC,  "AES");
 
63
        
 
64
        CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC,  "DESEDE/CBC/PKCS5Padding");
 
65
        CIPHER_ALG_NAMES.put(CMSAlgorithm.AES128_CBC,  "AES/CBC/PKCS5Padding");
 
66
        CIPHER_ALG_NAMES.put(CMSAlgorithm.AES192_CBC,  "AES/CBC/PKCS5Padding");
 
67
        CIPHER_ALG_NAMES.put(CMSAlgorithm.AES256_CBC,  "AES/CBC/PKCS5Padding");
 
68
        CIPHER_ALG_NAMES.put(new ASN1ObjectIdentifier(PKCSObjectIdentifiers.rsaEncryption.getId()), "RSA/ECB/PKCS1Padding");
 
69
        
 
70
        DIGEST_ALG_NAMES.put(OIWObjectIdentifiers.idSHA1, "SHA1");
 
71
        DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha224, "SHA224");
 
72
        DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha256, "SHA256");
 
73
        DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha384, "SHA384");
 
74
        DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha512, "SHA512");
 
75
 
 
76
        MAC_ALG_NAMES.put(IANAObjectIdentifiers.hmacSHA1, "HMACSHA1");
 
77
        MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA1, "HMACSHA1");
 
78
        MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA224, "HMACSHA224");
 
79
        MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA256, "HMACSHA256");
 
80
        MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA384, "HMACSHA384");
 
81
        MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA512, "HMACSHA512");
 
82
 
 
83
        KEY_ALG_NAMES.put(PKCSObjectIdentifiers.rsaEncryption, "RSA");
 
84
        KEY_ALG_NAMES.put(X9ObjectIdentifiers.id_dsa, "DSA");
 
85
    }
 
86
 
 
87
    private JcaJceHelper helper;
 
88
 
 
89
    CRMFHelper(JcaJceHelper helper)
 
90
    {
 
91
        this.helper = helper;
 
92
    }
 
93
 
 
94
    PublicKey toPublicKey(SubjectPublicKeyInfo subjectPublicKeyInfo)
 
95
        throws CRMFException
 
96
    {
 
97
        X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(subjectPublicKeyInfo).getBytes());
 
98
        AlgorithmIdentifier keyAlg = subjectPublicKeyInfo.getAlgorithmId();
 
99
 
 
100
        try
 
101
        {
 
102
            return createKeyFactory(keyAlg.getAlgorithm()).generatePublic(xspec);
 
103
        }
 
104
        catch (InvalidKeySpecException e)
 
105
        {
 
106
            throw new CRMFException("invalid key: " + e.getMessage(), e);
 
107
        }
 
108
    }
 
109
 
 
110
    Cipher createCipher(ASN1ObjectIdentifier algorithm)
 
111
        throws CRMFException
 
112
    {
 
113
        try
 
114
        {
 
115
            String cipherName = (String)CIPHER_ALG_NAMES.get(algorithm);
 
116
 
 
117
            if (cipherName != null)
 
118
            {
 
119
                try
 
120
                {
 
121
                    // this is reversed as the Sun policy files now allow unlimited strength RSA
 
122
                    return helper.createCipher(cipherName);
 
123
                }
 
124
                catch (NoSuchAlgorithmException e)
 
125
                {
 
126
                    // Ignore
 
127
                }
 
128
            }
 
129
            return helper.createCipher(algorithm.getId());
 
130
        }
 
131
        catch (GeneralSecurityException e)
 
132
        {
 
133
            throw new CRMFException("cannot create cipher: " + e.getMessage(), e);
 
134
        }
 
135
    }
 
136
    
 
137
    public KeyGenerator createKeyGenerator(ASN1ObjectIdentifier algorithm)
 
138
        throws CRMFException
 
139
    {
 
140
        try
 
141
        {
 
142
            String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm);
 
143
 
 
144
            if (cipherName != null)
 
145
            {
 
146
                try
 
147
                {
 
148
                    // this is reversed as the Sun policy files now allow unlimited strength RSA
 
149
                    return helper.createKeyGenerator(cipherName);
 
150
                }
 
151
                catch (NoSuchAlgorithmException e)
 
152
                {
 
153
                    // Ignore
 
154
                }
 
155
            }
 
156
            return helper.createKeyGenerator(algorithm.getId());
 
157
        }
 
158
        catch (GeneralSecurityException e)
 
159
        {
 
160
            throw new CRMFException("cannot create key generator: " + e.getMessage(), e);
 
161
        }
 
162
    }
 
163
    
 
164
    Cipher createContentCipher(final Key sKey, final AlgorithmIdentifier encryptionAlgID)
 
165
        throws CRMFException
 
166
    {
 
167
        return (Cipher)execute(new JCECallback()
 
168
        {
 
169
            public Object doInJCE()
 
170
                throws CRMFException, InvalidAlgorithmParameterException,
 
171
                InvalidKeyException, InvalidParameterSpecException, NoSuchAlgorithmException,
 
172
                NoSuchPaddingException, NoSuchProviderException
 
173
            {
 
174
                Cipher cipher = createCipher(encryptionAlgID.getAlgorithm());
 
175
                ASN1Object sParams = (ASN1Object)encryptionAlgID.getParameters();
 
176
                String encAlg = encryptionAlgID.getAlgorithm().getId();
 
177
 
 
178
                if (sParams != null && !(sParams instanceof ASN1Null))
 
179
                {
 
180
                    try
 
181
                    {
 
182
                        AlgorithmParameters params = createAlgorithmParameters(encryptionAlgID.getAlgorithm());
 
183
 
 
184
                        try
 
185
                        {
 
186
                            params.init(sParams.getEncoded(), "ASN.1");
 
187
                        }
 
188
                        catch (IOException e)
 
189
                        {
 
190
                            throw new CRMFException("error decoding algorithm parameters.", e);
 
191
                        }
 
192
 
 
193
                        cipher.init(Cipher.DECRYPT_MODE, sKey, params);
 
194
                    }
 
195
                    catch (NoSuchAlgorithmException e)
 
196
                    {
 
197
                        if (encAlg.equals(CMSEnvelopedDataGenerator.DES_EDE3_CBC)
 
198
                            || encAlg.equals(CMSEnvelopedDataGenerator.IDEA_CBC)
 
199
                            || encAlg.equals(CMSEnvelopedDataGenerator.AES128_CBC)
 
200
                            || encAlg.equals(CMSEnvelopedDataGenerator.AES192_CBC)
 
201
                            || encAlg.equals(CMSEnvelopedDataGenerator.AES256_CBC))
 
202
                        {
 
203
                            cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(
 
204
                                ASN1OctetString.getInstance(sParams).getOctets()));
 
205
                        }
 
206
                        else
 
207
                        {
 
208
                            throw e;
 
209
                        }
 
210
                    }
 
211
                }
 
212
                else
 
213
                {
 
214
                    if (encAlg.equals(CMSEnvelopedDataGenerator.DES_EDE3_CBC)
 
215
                        || encAlg.equals(CMSEnvelopedDataGenerator.IDEA_CBC)
 
216
                        || encAlg.equals(CMSEnvelopedDataGenerator.CAST5_CBC))
 
217
                    {
 
218
                        cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(new byte[8]));
 
219
                    }
 
220
                    else
 
221
                    {
 
222
                        cipher.init(Cipher.DECRYPT_MODE, sKey);
 
223
                    }
 
224
                }
 
225
 
 
226
                return cipher;
 
227
            }
 
228
        });
 
229
    }
 
230
    
 
231
    AlgorithmParameters createAlgorithmParameters(ASN1ObjectIdentifier algorithm)
 
232
        throws NoSuchAlgorithmException, NoSuchProviderException
 
233
    {
 
234
        String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm);
 
235
 
 
236
        if (algorithmName != null)
 
237
        {
 
238
            try
 
239
            {
 
240
                // this is reversed as the Sun policy files now allow unlimited strength RSA
 
241
                return helper.createAlgorithmParameters(algorithmName);
 
242
            }
 
243
            catch (NoSuchAlgorithmException e)
 
244
            {
 
245
                // Ignore
 
246
            }
 
247
        }
 
248
        return helper.createAlgorithmParameters(algorithm.getId());
 
249
    }
 
250
    
 
251
    KeyFactory createKeyFactory(ASN1ObjectIdentifier algorithm)
 
252
        throws CRMFException
 
253
    {
 
254
        try
 
255
        {
 
256
            String algName = (String)KEY_ALG_NAMES.get(algorithm);
 
257
 
 
258
            if (algName != null)
 
259
            {
 
260
                try
 
261
                {
 
262
                    // this is reversed as the Sun policy files now allow unlimited strength RSA
 
263
                    return helper.createKeyFactory(algName);
 
264
                }
 
265
                catch (NoSuchAlgorithmException e)
 
266
                {
 
267
                    // Ignore
 
268
                }
 
269
            }
 
270
            return helper.createKeyFactory(algorithm.getId());
 
271
        }
 
272
        catch (GeneralSecurityException e)
 
273
        {
 
274
            throw new CRMFException("cannot create cipher: " + e.getMessage(), e);
 
275
        }
 
276
    }
 
277
 
 
278
    MessageDigest createDigest(ASN1ObjectIdentifier algorithm)
 
279
        throws CRMFException
 
280
    {
 
281
        try
 
282
        {
 
283
            String digestName = (String)DIGEST_ALG_NAMES.get(algorithm);
 
284
 
 
285
            if (digestName != null)
 
286
            {
 
287
                try
 
288
                {
 
289
                    // this is reversed as the Sun policy files now allow unlimited strength RSA
 
290
                    return helper.createDigest(digestName);
 
291
                }
 
292
                catch (NoSuchAlgorithmException e)
 
293
                {
 
294
                    // Ignore
 
295
                }
 
296
            }
 
297
            return helper.createDigest(algorithm.getId());
 
298
        }
 
299
        catch (GeneralSecurityException e)
 
300
        {
 
301
            throw new CRMFException("cannot create cipher: " + e.getMessage(), e);
 
302
        }
 
303
    }
 
304
 
 
305
    Mac createMac(ASN1ObjectIdentifier algorithm)
 
306
        throws CRMFException
 
307
    {
 
308
        try
 
309
        {
 
310
            String macName = (String)MAC_ALG_NAMES.get(algorithm);
 
311
 
 
312
            if (macName != null)
 
313
            {
 
314
                try
 
315
                {
 
316
                    // this is reversed as the Sun policy files now allow unlimited strength RSA
 
317
                    return helper.createMac(macName);
 
318
                }
 
319
                catch (NoSuchAlgorithmException e)
 
320
                {
 
321
                    // Ignore
 
322
                }
 
323
            }
 
324
            return helper.createMac(algorithm.getId());
 
325
        }
 
326
        catch (GeneralSecurityException e)
 
327
        {
 
328
            throw new CRMFException("cannot create mac: " + e.getMessage(), e);
 
329
        }
 
330
    }
 
331
 
 
332
    AlgorithmParameterGenerator createAlgorithmParameterGenerator(ASN1ObjectIdentifier algorithm)
 
333
        throws GeneralSecurityException
 
334
    {
 
335
        String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm);
 
336
 
 
337
        if (algorithmName != null)
 
338
        {
 
339
            try
 
340
            {
 
341
                // this is reversed as the Sun policy files now allow unlimited strength RSA
 
342
                return helper.createAlgorithmParameterGenerator(algorithmName);
 
343
            }
 
344
            catch (NoSuchAlgorithmException e)
 
345
            {
 
346
                // Ignore
 
347
            }
 
348
        }
 
349
        return helper.createAlgorithmParameterGenerator(algorithm.getId());
 
350
    }
 
351
 
 
352
    AlgorithmParameters generateParameters(ASN1ObjectIdentifier encryptionOID, SecretKey encKey, SecureRandom rand)
 
353
        throws CRMFException
 
354
    {
 
355
        try
 
356
        {
 
357
            AlgorithmParameterGenerator pGen = createAlgorithmParameterGenerator(encryptionOID);
 
358
 
 
359
            if (encryptionOID.equals(CMSEnvelopedDataGenerator.RC2_CBC))
 
360
            {
 
361
                byte[]  iv = new byte[8];
 
362
 
 
363
                rand.nextBytes(iv);
 
364
 
 
365
                try
 
366
                {
 
367
                    pGen.init(new RC2ParameterSpec(encKey.getEncoded().length * 8, iv), rand);
 
368
                }
 
369
                catch (InvalidAlgorithmParameterException e)
 
370
                {
 
371
                    throw new CRMFException("parameters generation error: " + e, e);
 
372
                }
 
373
            }
 
374
 
 
375
            return pGen.generateParameters();
 
376
        }
 
377
        catch (NoSuchAlgorithmException e)
 
378
        {
 
379
            return null;
 
380
        }
 
381
        catch (GeneralSecurityException e)
 
382
        {
 
383
            throw new CRMFException("exception creating algorithm parameter generator: " + e, e);
 
384
        }
 
385
    }
 
386
 
 
387
    AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier encryptionOID, AlgorithmParameters params)
 
388
        throws CRMFException
 
389
    {
 
390
        DEREncodable asn1Params;
 
391
        if (params != null)
 
392
        {
 
393
            try
 
394
            {
 
395
                asn1Params = ASN1Object.fromByteArray(params.getEncoded("ASN.1"));
 
396
            }
 
397
            catch (IOException e)
 
398
            {
 
399
                throw new CRMFException("cannot encode parameters: " + e.getMessage(), e);
 
400
            }
 
401
        }
 
402
        else
 
403
        {
 
404
            asn1Params = DERNull.INSTANCE;
 
405
        }
 
406
 
 
407
        return new AlgorithmIdentifier(
 
408
            encryptionOID,
 
409
            asn1Params);
 
410
    }
 
411
    
 
412
    static Object execute(JCECallback callback) throws CRMFException
 
413
    {
 
414
        try
 
415
        {
 
416
            return callback.doInJCE();
 
417
        }
 
418
        catch (NoSuchAlgorithmException e)
 
419
        {
 
420
            throw new CRMFException("can't find algorithm.", e);
 
421
        }
 
422
        catch (InvalidKeyException e)
 
423
        {
 
424
            throw new CRMFException("key invalid in message.", e);
 
425
        }
 
426
        catch (NoSuchProviderException e)
 
427
        {
 
428
            throw new CRMFException("can't find provider.", e);
 
429
        }
 
430
        catch (NoSuchPaddingException e)
 
431
        {
 
432
            throw new CRMFException("required padding not supported.", e);
 
433
        }
 
434
        catch (InvalidAlgorithmParameterException e)
 
435
        {
 
436
            throw new CRMFException("algorithm parameters invalid.", e);
 
437
        }
 
438
        catch (InvalidParameterSpecException e)
 
439
        {
 
440
            throw new CRMFException("MAC algorithm parameter spec invalid.", e);
 
441
        }
 
442
    }
 
443
    
 
444
    static interface JCECallback
 
445
    {
 
446
        Object doInJCE()
 
447
            throws CRMFException, InvalidAlgorithmParameterException, InvalidKeyException, InvalidParameterSpecException,
 
448
            NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException;
 
449
    }
 
450
}