001: package org.bouncycastle.cms;
002:
003: import org.bouncycastle.asn1.ASN1EncodableVector;
004: import org.bouncycastle.asn1.ASN1OctetString;
005: import org.bouncycastle.asn1.BERConstructedOctetString;
006: import org.bouncycastle.asn1.DERSet;
007: import org.bouncycastle.asn1.cms.ContentInfo;
008: import org.bouncycastle.asn1.cms.EncryptedContentInfo;
009: import org.bouncycastle.asn1.cms.EnvelopedData;
010: import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
011: import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
012:
013: import javax.crypto.Cipher;
014: import javax.crypto.CipherOutputStream;
015: import javax.crypto.KeyGenerator;
016: import javax.crypto.NoSuchPaddingException;
017: import javax.crypto.SecretKey;
018: import java.io.ByteArrayOutputStream;
019: import java.io.IOException;
020: import java.security.AlgorithmParameters;
021: import java.security.GeneralSecurityException;
022: import java.security.InvalidAlgorithmParameterException;
023: import java.security.InvalidKeyException;
024: import java.security.NoSuchAlgorithmException;
025: import java.security.NoSuchProviderException;
026: import java.util.Iterator;
027:
028: /**
029: * General class for generating a CMS enveloped-data message.
030: *
031: * A simple example of usage.
032: *
033: * <pre>
034: * CMSEnvelopedDataGenerator fact = new CMSEnvelopedDataGenerator();
035: *
036: * fact.addKeyTransRecipient(cert);
037: *
038: * CMSEnvelopedData data = fact.generate(content, algorithm, "BC");
039: * </pre>
040: */
041: public class CMSEnvelopedDataGenerator extends CMSEnvelopedGenerator {
042: /**
043: * base constructor
044: */
045: public CMSEnvelopedDataGenerator() {
046: }
047:
048: /**
049: * generate an enveloped object that contains an CMS Enveloped Data
050: * object using the given provider and the passed in key generator.
051: */
052: private CMSEnvelopedData generate(CMSProcessable content,
053: String encryptionOID, KeyGenerator keyGen, String provider)
054: throws NoSuchAlgorithmException, NoSuchProviderException,
055: CMSException {
056: String encProviderName = keyGen.getProvider().getName();
057: ASN1EncodableVector recipientInfos = new ASN1EncodableVector();
058: AlgorithmIdentifier encAlgId;
059: SecretKey encKey;
060: ASN1OctetString encContent;
061:
062: try {
063: Cipher cipher = CMSEnvelopedHelper.INSTANCE
064: .getSymmetricCipher(encryptionOID, encProviderName);
065:
066: AlgorithmParameters params;
067:
068: encKey = keyGen.generateKey();
069: params = generateParameters(encryptionOID, encKey,
070: encProviderName);
071:
072: cipher.init(Cipher.ENCRYPT_MODE, encKey, params);
073:
074: //
075: // If params are null we try and second guess on them as some providers don't provide
076: // algorithm parameter generation explicity but instead generate them under the hood.
077: //
078: if (params == null) {
079: params = cipher.getParameters();
080: }
081:
082: encAlgId = getAlgorithmIdentifier(encryptionOID, params);
083:
084: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
085: CipherOutputStream cOut = new CipherOutputStream(bOut,
086: cipher);
087:
088: content.write(cOut);
089:
090: cOut.close();
091:
092: encContent = new BERConstructedOctetString(bOut
093: .toByteArray());
094: } catch (NoSuchAlgorithmException e) {
095: throw new CMSException("can't find algorithm.", e);
096: } catch (InvalidKeyException e) {
097: throw new CMSException("key invalid in message.", e);
098: } catch (NoSuchPaddingException e) {
099: throw new CMSException("required padding not supported.", e);
100: } catch (InvalidAlgorithmParameterException e) {
101: throw new CMSException("algorithm parameters invalid.", e);
102: } catch (IOException e) {
103: throw new CMSException(
104: "exception decoding algorithm parameters.", e);
105: }
106:
107: Iterator it = recipientInfs.iterator();
108:
109: while (it.hasNext()) {
110: RecipientInf recipient = (RecipientInf) it.next();
111:
112: try {
113: recipientInfos.add(recipient.toRecipientInfo(encKey,
114: provider));
115: } catch (IOException e) {
116: throw new CMSException("encoding error.", e);
117: } catch (InvalidKeyException e) {
118: throw new CMSException(
119: "key inappropriate for algorithm.", e);
120: } catch (GeneralSecurityException e) {
121: throw new CMSException(
122: "error making encrypted content.", e);
123: }
124: }
125:
126: EncryptedContentInfo eci = new EncryptedContentInfo(
127: PKCSObjectIdentifiers.data, encAlgId, encContent);
128:
129: ContentInfo contentInfo = new ContentInfo(
130: PKCSObjectIdentifiers.envelopedData, new EnvelopedData(
131: null, new DERSet(recipientInfos), eci, null));
132:
133: return new CMSEnvelopedData(contentInfo);
134: }
135:
136: /**
137: * generate an enveloped object that contains an CMS Enveloped Data
138: * object using the given provider.
139: */
140: public CMSEnvelopedData generate(CMSProcessable content,
141: String encryptionOID, String provider)
142: throws NoSuchAlgorithmException, NoSuchProviderException,
143: CMSException {
144: KeyGenerator keyGen = CMSEnvelopedHelper.INSTANCE
145: .createSymmetricKeyGenerator(encryptionOID, provider);
146:
147: return generate(content, encryptionOID, keyGen, provider);
148: }
149:
150: /**
151: * generate an enveloped object that contains an CMS Enveloped Data
152: * object using the given provider.
153: */
154: public CMSEnvelopedData generate(CMSProcessable content,
155: String encryptionOID, int keySize, String provider)
156: throws NoSuchAlgorithmException, NoSuchProviderException,
157: CMSException {
158: KeyGenerator keyGen = CMSEnvelopedHelper.INSTANCE
159: .createSymmetricKeyGenerator(encryptionOID, provider);
160:
161: keyGen.init(keySize);
162:
163: return generate(content, encryptionOID, keyGen, provider);
164: }
165: }
|