001    // Copyright (C) 2002 IAIK
002    // https://jce.iaik.tugraz.at
003    //
004    // Copyright (C) 2003 - 2025 Stiftung Secure Information and
005    //                           Communication Technologies SIC
006    // https://sic.tech
007    //
008    // All rights reserved.
009    //
010    // Redistribution and use in source and binary forms, with or without
011    // modification, are permitted provided that the following conditions
012    // are met:
013    // 1. Redistributions of source code must retain the above copyright
014    //    notice, this list of conditions and the following disclaimer.
015    // 2. Redistributions in binary form must reproduce the above copyright
016    //    notice, this list of conditions and the following disclaimer in the
017    //    documentation and/or other materials provided with the distribution.
018    //
019    // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
020    // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
021    // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
022    // ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
023    // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
024    // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
025    // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
026    // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
027    // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
028    // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
029    // SUCH DAMAGE.
030    
031    // Copyright (C) 2002 IAIK
032    // https://sic.tech/
033    //
034    // Copyright (C) 2003 - 2025 Stiftung Secure Information and 
035    //                           Communication Technologies SIC
036    // https://sic.tech/
037    //
038    // All rights reserved.
039    //
040    // This source is provided for inspection purposes and recompilation only,
041    // unless specified differently in a contract with IAIK. This source has to
042    // be kept in strict confidence and must not be disclosed to any third party
043    // under any circumstances. Redistribution in source and binary forms, with
044    // or without modification, are <not> permitted in any case!
045    //
046    // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
047    // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
048    // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
049    // ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
050    // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
051    // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
052    // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
053    // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
054    // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
055    // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
056    // SUCH DAMAGE.
057    //
058    // $Header: /IAIK-CMS/current/src/demo/cms/envelopedData/EnvelopedDataDemo.java 40    12.02.25 17:58 Dbratko $
059    // $Revision: 40 $
060    //
061    
062    
063    package demo.cms.envelopedData;
064    
065    import java.io.ByteArrayInputStream;
066    import java.io.ByteArrayOutputStream;
067    import java.io.IOException;
068    import java.io.InputStream;
069    import java.security.InvalidKeyException;
070    import java.security.Key;
071    import java.security.NoSuchAlgorithmException;
072    import java.security.PrivateKey;
073    import java.security.SecureRandom;
074    import java.util.Arrays;
075    
076    import javax.crypto.KeyGenerator;
077    import javax.crypto.SecretKey;
078    
079    import demo.DemoUtil;
080    import demo.keystore.CMSKeyStore;
081    import iaik.asn1.structures.AlgorithmID;
082    import iaik.cms.CMSException;
083    import iaik.cms.CertificateIdentifier;
084    import iaik.cms.EncryptedContentInfo;
085    import iaik.cms.EncryptedContentInfoStream;
086    import iaik.cms.EnvelopedData;
087    import iaik.cms.EnvelopedDataStream;
088    import iaik.cms.IssuerAndSerialNumber;
089    import iaik.cms.KEKIdentifier;
090    import iaik.cms.KEKRecipientInfo;
091    import iaik.cms.KeyAgreeRecipientInfo;
092    import iaik.cms.KeyIdentifier;
093    import iaik.cms.KeyTransRecipientInfo;
094    import iaik.cms.RecipientInfo;
095    import iaik.cms.RecipientKeyIdentifier;
096    import iaik.cms.SecurityProvider;
097    import iaik.cms.SubjectKeyID;
098    import iaik.security.random.SecRandom;
099    import iaik.utils.Util;
100    import iaik.x509.X509Certificate;
101    
102    
103    /**
104     * Demonstrates the usage of class {@link iaik.cms.EnvelopedDataStream} and
105     * {@link iaik.cms.EnvelopedData} for encrypting data using the CMS type
106     * EnvelopedData.
107     * <p>
108     * This demo creates an EnvelopedData object and subsequently shows several
109     * ways that may be used for decrypting the content for some particular 
110     * recipient.
111     * <p>
112     * Keys and certificates are retrieved from the demo KeyStore ("cms.keystore") 
113     * which has to be located in your current working directory and may be
114     * created by running the {@link demo.keystore.SetupCMSKeyStore
115     * SetupCMSKeyStore} program.
116     * <p>
117     * This demo uses TripleDES which has been deprecated by S/MIMEv4 (RFC 8551),
118     * see {@link AESEnvelopedDataDemo AESEnvelopedDataDemo} for an AES based demo.
119     * 
120     * @see iaik.cms.EnvelopedDataStream
121     * @see iaik.cms.EnvelopedData
122     * @see iaik.cms.RecipientInfo
123     * @see iaik.cms.KeyTransRecipientInfo
124     * @see iaik.cms.KeyAgreeRecipientInfo
125     * @see iaik.cms.KEKRecipientInfo
126     */
127    public class EnvelopedDataDemo {
128    
129      // certificate of rsaUser 1
130      X509Certificate rsaUser1_;
131      // private key of rsaUser 1
132      PrivateKey rsaUser1Pk_;
133      // certificate of rsaUser 2
134      X509Certificate rsaUser2_;
135      // private key of rsaUser 2
136      PrivateKey rsaUser2Pk_;
137    
138      // certificate of esdhUser 1
139      X509Certificate esdhUser1_;
140      // private key of esdhUser 1
141      PrivateKey esdhUser1Pk_;
142      // certificate of esdhUser 2
143      X509Certificate esdhUser2_;
144      // private key of esdhUser 2
145      PrivateKey esdhUser2Pk_;
146      
147      // key encryption key for KEKRecipientInfo
148      SecretKey kek_;
149      byte[] kekID_;
150      
151      // content encryption algorithm to be used
152      AlgorithmID contentEncAlg_;
153      // cek algorithm
154      String cekAlg_;
155      // key wrap algorithm to be used
156      AlgorithmID keyWrapAlg_;
157      // key length (same for content encryption key and key encryption key
158      int keyLength_;
159    
160      // secure random number generator
161      SecureRandom random_;
162      
163      /**
164       * Creates an EnvelopedDataDemo and setups the demo certificates.
165       * <br>
166       * Keys and certificates are retrieved from the demo KeyStore ("cms.keystore")
167       * file which has to be located in your current working directory and may be
168       * created by running {@link demo.keystore.SetupCMSKeyStore
169       * SetupCMSKeyStore}.
170       * <br>
171       * TripleDES and TripleDES KeyWrap are used for content encryption and
172       * content encryption key wrapping.
173       *
174       * @throws IOException if an file read error occurs
175       * @throws NoSuchAlgorithmException if the requested TripleDES or TripleDES KeyWrap 
176       *                                     algorithms are not supported
177       */
178      public EnvelopedDataDemo() throws IOException, NoSuchAlgorithmException {
179        this((AlgorithmID)AlgorithmID.des_EDE3_CBC.clone(),
180             (AlgorithmID)AlgorithmID.cms_3DES_wrap.clone(),
181             (AlgorithmID)AlgorithmID.cms_3DES_wrap.clone(),
182             192);
183      }
184      
185      /**
186       * Creates an EnvelopedDataDemo and setups the demo certificates.
187       * <br>
188       * Keys and certificates are retrieved from the demo KeyStore ("cms.keystore")
189       * file which has to be located in your current working directory and may be
190       * created by running {@link demo.keystore.SetupCMSKeyStore
191       * SetupCMSKeyStore}.
192       *
193       * @param contentEncAlg the content encryption algorithm to be used
194       * @param keyWrapAlg the key wrap algorithm to be used for wrapping the content 
195       *                   encryption key (for KeyAgreeRecipientInfos)
196       * @param keyLength the key length to be used (same for content encryption key
197       *                  and key encryption key) (for KeyAgreeRecipientInfos and
198       *                  KEKRecipientInfos)
199       *                                    
200       * @throws IOException if an file read error occurs
201       * @throws NoSuchAlgorithmException if the requested algorithms are not supported
202       */
203      public EnvelopedDataDemo(AlgorithmID contentEncAlg,
204                               AlgorithmID keyWrapAlg,
205                               int keyLength) throws IOException, NoSuchAlgorithmException {
206        this(contentEncAlg, keyWrapAlg, keyWrapAlg, keyLength);
207        
208      }
209          
210    
211      /**
212       * Creates an EnvelopedDataDemo and setups the demo certificates.
213       * <br>
214       * Keys and certificates are retrieved from the demo KeyStore ("cms.keystore")
215       * file which has to be located in your current working directory and may be
216       * created by running {@link demo.keystore.SetupCMSKeyStore
217       * SetupCMSKeyStore}.
218       *
219       * @param contentEncAlg the content encryption algorithm to be used
220       * @param keyWrapAlg the key wrap algorithm to be used for wrapping the content 
221       *                   encryption key (for KeyAgreeRecipientInfos)
222       * @param kekAlg the name of the key encryption key algorithm to be used
223       *               (for KEKRecipientInfos)
224       * @param keyLength the key length to be used (same for content encryption key
225       *                  and key encryption key) (for KeyAgreeRecipientInfos and
226       *                  KEKRecipientInfos)
227       *                                    
228       * @throws IOException if an file read error occurs
229       * @throws NoSuchAlgorithmException if the requested algorithms are not supported
230       */
231      public EnvelopedDataDemo(AlgorithmID contentEncAlg,
232                               AlgorithmID keyWrapAlg,
233                               AlgorithmID kekAlg,
234                               int keyLength) throws IOException, NoSuchAlgorithmException {
235        
236        System.out.println();
237        System.out.println("**********************************************************************************");
238        System.out.println("                  EnvelopedDataDemo " + contentEncAlg.getName());
239        System.out.println("        (shows the usage of the CMS EnvelopedData type implementation)          ");
240        System.out.println("**********************************************************************************");
241        System.out.println();
242        
243        // add all certificates to the list
244        X509Certificate[] certs = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1);
245        rsaUser1_ = certs[0];
246        rsaUser1Pk_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1);
247        rsaUser2_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0];
248        rsaUser2Pk_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2);
249        
250        esdhUser1_ = CMSKeyStore.getCertificateChain(CMSKeyStore.ESDH, CMSKeyStore.SZ_2048_CRYPT_1)[0];
251        esdhUser1Pk_ = CMSKeyStore.getPrivateKey(CMSKeyStore.ESDH, CMSKeyStore.SZ_2048_CRYPT_1);
252        esdhUser2_ = CMSKeyStore.getCertificateChain(CMSKeyStore.ESDH, CMSKeyStore.SZ_2048_CRYPT_2)[0];
253        esdhUser2Pk_ = CMSKeyStore.getPrivateKey(CMSKeyStore.ESDH, CMSKeyStore.SZ_2048_CRYPT_2);
254        random_ = SecRandom.getDefault();
255        
256        contentEncAlg_ = contentEncAlg;
257        keyWrapAlg_ = keyWrapAlg;
258        keyLength_ = keyLength;
259        
260        // create a secret key encryption key for a KEKRecipientInfo
261        KeyGenerator kg = SecurityProvider.getSecurityProvider().getKeyGenerator(kekAlg, keyLength_);
262        kek_ = kg.generateKey();
263        kekID_ = new byte[] { 00, 00, 00, 01 };
264      }
265    
266    
267      /**
268       * Creates a CMS <code>EnvelopedDataStream</code> message.
269       *
270       * @param message the message to be enveloped, as byte representation
271       * @return the DER encoding of the <code>EnvelopedData</code> object just created
272       * @throws CMSException if the <code>EnvelopedData</code> object cannot
273       *                          be created
274       * @throws IOException if an I/O error occurs
275       */
276      public byte[] createEnvelopedDataStream(byte[] message) throws CMSException, IOException {
277    
278        EnvelopedDataStream enveloped_data;
279    
280        // we are testing the stream interface
281        ByteArrayInputStream is = new ByteArrayInputStream(message);
282        // create a new EnvelopedData object encrypted with TripleDES CBC
283        try {
284          enveloped_data = new EnvelopedDataStream(is, (AlgorithmID)contentEncAlg_.clone());
285        } catch (NoSuchAlgorithmException ex) {
286          throw new CMSException("No implementation for content encryption algorithm: " + ex.toString());
287        }
288    
289        // create the recipient infos
290        RecipientInfo[] recipients = createRecipients();
291        // specify the recipients of the encrypted message
292        enveloped_data.setRecipientInfos(recipients);
293    
294        // return the EnvelopedDate as DER encoded byte array with block size 2048
295        ByteArrayOutputStream os = new ByteArrayOutputStream();
296        enveloped_data.writeTo(os, 2048);
297        return os.toByteArray();
298      }
299    
300      /**
301       * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
302       * the recipient identified by its index into the recipientInfos field.
303       * <p>
304       * This way of decrypting the content may be used for any type of RecipientInfo
305       * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo), but requires to
306       * know at what index of the recipientInfo field the RecipientInfo for the 
307       * particular recipient in mind can be found. If the recipient in mind uses
308       * a RecipientInfo of type KeyAgreeRecipientInfo some processing overhead may
309       * take place because a KeyAgreeRecipientInfo may contain encrypted content-encryption
310       * keys for more than only one recipient; since the recipientInfoIndex only
311       * specifies the RecipientInfo but not the encrypted content encryption key 
312       * -- if there are more than only one -- repeated decryption runs may be
313       * required as long as the decryption process completes successfully.
314       *
315       * @param encoding the <code>EnvelopedData</code> object as DER encoded byte array
316       * @param key the key to decrypt the message
317       * @param recipientInfoIndex the index into the <code>RecipientInfo</code> array
318       *                        to which the specified key belongs
319       *
320       * @return the recovered message, as byte array
321       * @throws CMSException if the message cannot be recovered
322       * @throws IOException if a stream read/write error occurs
323       */
324      public byte[] getEnvelopedDataStream(byte[] encoding, Key key, int recipientInfoIndex)
325        throws CMSException, IOException {
326    
327        // create the EnvelopedData object from a DER encoded byte array
328        // we are testing the stream interface
329        ByteArrayInputStream is = new ByteArrayInputStream(encoding);
330        EnvelopedDataStream enveloped_data = new EnvelopedDataStream(is);
331    
332        System.out.println("Information about the encrypted data:");
333        EncryptedContentInfoStream eci = (EncryptedContentInfoStream)enveloped_data.getEncryptedContentInfo();
334        System.out.println("Content type: "+eci.getContentType().getName());
335        System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
336    
337        System.out.println("\nThis message can be decrypted by the owners of the following certificates:");
338        RecipientInfo[] recipients = enveloped_data.getRecipientInfos();
339        
340        // for demonstration purposes we only look one time for all recipients included:
341        if (recipientInfoIndex == 0) {
342          int k = 0;
343          for (int i=0; i<recipients.length; i++) {
344            KeyIdentifier[] recipientIDs = recipients[i].getRecipientIdentifiers();
345            for (int j = 0; j < recipientIDs.length; j++) {
346              System.out.println("Recipient "+(++k)+":");
347              System.out.println(recipientIDs[j]);
348            }   
349          }
350        }
351        // decrypt the message for the first recipient
352        try {
353          enveloped_data.setupCipher(key, recipientInfoIndex);
354          InputStream decrypted = enveloped_data.getInputStream();
355          ByteArrayOutputStream os = new ByteArrayOutputStream();
356          Util.copyStream(decrypted, os, null);
357    
358          return os.toByteArray();
359    
360        } catch (InvalidKeyException ex) {
361          throw new CMSException("Private key error: "+ex.getMessage());
362        } catch (NoSuchAlgorithmException ex) {
363          throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
364        }
365      }
366      
367      /**
368       * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
369       * the recipient identified by recipient identifier.
370       * <p>
371       * This way of decrypting the content may be used for any type of RecipientInfo
372       * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo). The 
373       * recipient in mind is identified by its recipient identifier.
374       *
375       * @param encoding the <code>EnvelopedData</code> object as DER encoded byte array
376       * @param key the key to decrypt the message
377       * @param recipientID the recipient identifier uniquely identifying the key of the
378       *        recipient
379       *
380       * @return the recovered message, as byte array
381       * @throws CMSException if the message cannot be recovered
382       * @throws IOException if a stream read/write error occurs
383       */
384      public byte[] getEnvelopedDataStream(byte[] encoding, Key key, KeyIdentifier recipientID)
385        throws CMSException, IOException {
386    
387        // create the EnvelopedData object from a DER encoded byte array
388        // we are testing the stream interface
389        ByteArrayInputStream is = new ByteArrayInputStream(encoding);
390        EnvelopedDataStream enveloped_data = new EnvelopedDataStream(is);
391    
392        System.out.println("Information about the encrypted data:");
393        EncryptedContentInfoStream eci = (EncryptedContentInfoStream)enveloped_data.getEncryptedContentInfo();
394        System.out.println("Content type: "+eci.getContentType().getName());
395        System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
396        
397        // get the right RecipientInfo
398        System.out.println("\nSearch for RecipientInfo:");
399        RecipientInfo recipient = enveloped_data.getRecipientInfo(recipientID);
400        if (recipient != null) {
401          System.out.println("RecipientInfo: " + recipient);   
402        } else {
403          throw new CMSException("No recipient with ID: " + recipientID);
404        }    
405        // decrypt the content encryption key and the content
406        try {
407          System.out.println("Decrypt encrypted content encryption key...");
408          SecretKey cek = recipient.decryptKey(key, recipientID);
409          System.out.println("Decrypt content with decrypted content encryption key...");
410          enveloped_data.setupCipher(cek);
411          InputStream decrypted = enveloped_data.getInputStream();
412          ByteArrayOutputStream os = new ByteArrayOutputStream();
413          Util.copyStream(decrypted, os, null);
414    
415          return os.toByteArray();
416    
417        } catch (InvalidKeyException ex) {
418          throw new CMSException("Private key error: "+ex.getMessage());
419        } catch (NoSuchAlgorithmException ex) {
420          throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
421        }
422      }
423      
424      /**
425       * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
426       * the recipient identified by its recipient certificate or kekID.
427       * <p>
428       * Since recipient certificates only may be used for for RecipientInfos of type
429       * KeyTransRecipientInfo or KeyAgreeRecipientInfo, a key id has to be supplied
430       * for decrypting the content for a recipient using a KEKRecipientInfo.
431       *
432       * @param encoding the <code>EnvelopedData</code> object as DER encoded byte array
433       * @param key the key to decrypt the message
434       * @param recipientCert the certificate of the recipient having a RecipientInfo of
435       *                      type KeyTransRecipientInfo or KeyAgreeRecipientInfo
436       * @param kekID the kekID identifying the recipient key when using a RecipientInfo
437       *              of type KEKRecipientInfo
438       *
439       * @return the recovered message, as byte array
440       * @throws CMSException if the message cannot be recovered
441       * @throws IOException if a stream read/write error occurs
442       */
443      public byte[] getEnvelopedDataStream(byte[] encoding, Key key, X509Certificate recipientCert, byte[] kekID)
444        throws CMSException, IOException {
445    
446        // create the EnvelopedData object from a DER encoded byte array
447        // we are testing the stream interface
448        ByteArrayInputStream is = new ByteArrayInputStream(encoding);
449        EnvelopedDataStream enveloped_data = new EnvelopedDataStream(is);
450    
451        System.out.println("Information about the encrypted data:");
452        EncryptedContentInfoStream eci = (EncryptedContentInfoStream)enveloped_data.getEncryptedContentInfo();
453        System.out.println("Content type: "+eci.getContentType().getName());
454        System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
455        
456        // decrypt the content encryption key and the content
457        try {
458          System.out.println("Decrypt the content...");
459          if (recipientCert != null) {
460            enveloped_data.setupCipher(key, recipientCert);
461          } else {
462            // KEKRecipientInfo
463            enveloped_data.setupCipher(key, new KEKIdentifier(kekID));
464          }  
465          InputStream decrypted = enveloped_data.getInputStream();
466          ByteArrayOutputStream os = new ByteArrayOutputStream();
467          Util.copyStream(decrypted, os, null);
468    
469          return os.toByteArray();
470    
471        } catch (InvalidKeyException ex) {
472          throw new CMSException("Private key error: "+ex.getMessage());
473        } catch (NoSuchAlgorithmException ex) {
474          throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
475        }
476      }
477    
478    
479      // non stream
480    
481      /**
482       * Creates a CMS <code>EnvelopedData</code> message.
483       * 
484       * @param message the message to be enveloped, as byte representation
485       * 
486       * @return the encoded <code>EnvelopedData</code>, as byte array
487       * 
488       * @throws CMSException if the <code>EnvelopedData</code> object cannot
489       *                          be created
490       */
491      public byte[] createEnvelopedData(byte[] message) throws CMSException {
492        
493        EnvelopedData enveloped_data;
494    
495        // create a new EnvelopedData object encrypted with TripleDES CBC
496        try {
497          enveloped_data = new EnvelopedData(message, (AlgorithmID)contentEncAlg_.clone());
498        } catch (NoSuchAlgorithmException ex) {
499          throw new CMSException("No implementation for content encryption algorithm: " + ex.toString());
500        }
501        
502        // set the RecipientInfos
503        RecipientInfo[] recipients = createRecipients();
504        enveloped_data.setRecipientInfos(recipients);
505    
506        // return encoded EnvelopedData
507        return enveloped_data.getEncoded();
508      }
509    
510    
511      /**
512       * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
513       * the recipient identified by its index into the recipientInfos field.
514       * <p>
515       * This way of decrypting the content may be used for any type of RecipientInfo
516       * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo), but requires to
517       * know at what index of the recipientInfo field the RecipientInfo for the 
518       * particular recipient in mind can be found. If the recipient in mind uses
519       * a RecipientInfo of type KeyAgreeRecipientInfo some processing overhead may
520       * take place because a KeyAgreeRecipientInfo may contain encrypted content-encryption
521       * keys for more than only one recipient; since the recipientInfoIndex only
522       * specifies the RecipientInfo but not the encrypted content encryption key 
523       * -- if there are more than only one -- repeated decryption runs may be
524       * required as long as the decryption process completes successfully.
525       *
526       * @param enc the encoded <code>EnvelopedData</code>
527       * 
528       * @param key the key to decrypt the message
529       * 
530       * @param recipientInfoIndex the index into the <code>RecipientInfo</code> array
531       *                    to which the specified key belongs
532       *
533       * @return the recovered message, as byte array
534       * 
535       * @throws CMSException if the message cannot be recovered
536       * @throws IOException if an I/O error occurs
537       */
538      public byte[] getEnvelopedData(byte[] enc, Key key, int recipientInfoIndex) 
539        throws CMSException, IOException {
540        ByteArrayInputStream bais = new ByteArrayInputStream(enc);
541        EnvelopedData enveloped_data = new EnvelopedData(bais);
542    
543        System.out.println("Information about the encrypted data:");
544        EncryptedContentInfo eci = (EncryptedContentInfo)enveloped_data.getEncryptedContentInfo();
545        System.out.println("Content type: "+eci.getContentType().getName());
546        System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
547    
548        System.out.println("\nThis message can be decrypted by the owners of the following certificates:");
549        RecipientInfo[] recipients = enveloped_data.getRecipientInfos();
550        
551        // for demonstration purposes we only look one time for all recipients included:
552        if (recipientInfoIndex == 0) {
553          int k = 0;
554          for (int i=0; i<recipients.length; i++) {
555            KeyIdentifier[] recipientIDs = recipients[i].getRecipientIdentifiers();
556            for (int j = 0; j < recipientIDs.length; j++) {
557              System.out.println("Recipient "+(++k)+":");
558              System.out.println(recipientIDs[j]);
559            }   
560          }
561        }
562        
563        // decrypt the message
564        try {
565          enveloped_data.setupCipher(key, recipientInfoIndex);
566          return enveloped_data.getContent();
567    
568        } catch (InvalidKeyException ex) {
569          throw new CMSException("Private key error: "+ex.getMessage());
570        } catch (NoSuchAlgorithmException ex) {
571          throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
572        }
573      }
574      
575      /**
576       * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
577       * the recipient identified by recipient identifier.
578       * <p>
579       * This way of decrypting the content may be used for any type of RecipientInfo
580       * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo). The 
581       * recipient in mind is identified by its recipient identifier.
582       *
583       * @param enc the DER encoded <code>EnvelopedData</code> ASN.1 object
584       * @param key the key to decrypt the message
585       * @param recipientID the recipient identifier uniquely identifying the key of the
586       *        recipient
587       *
588       * @return the recovered message, as byte array
589       * @throws CMSException if the message cannot be recovered
590       * @throws IOException if an I/O error occurs
591       */
592      public byte[] getEnvelopedData(byte[] enc, Key key, KeyIdentifier recipientID) 
593        throws CMSException, IOException {
594        ByteArrayInputStream bais = new ByteArrayInputStream(enc);
595        EnvelopedData enveloped_data = new EnvelopedData(bais);
596    
597        System.out.println("Information about the encrypted data:");
598        EncryptedContentInfo eci = (EncryptedContentInfo)enveloped_data.getEncryptedContentInfo();
599        System.out.println("Content type: "+eci.getContentType().getName());
600        System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
601    
602        System.out.println("\nThis message can be decrypted by the owners of the following certificates:");
603    
604        // get the right RecipientInfo
605        System.out.println("\nSearch for RecipientInfo:");
606        RecipientInfo recipient = enveloped_data.getRecipientInfo(recipientID);
607        if (recipient != null) {
608          System.out.println("RecipientInfo: " + recipient);   
609        } else {
610          throw new CMSException("No recipient with ID: " + recipientID);
611        }    
612        // decrypt the content encryption key and the content
613        try {
614          System.out.println("Decrypt encrypted content encryption key...");
615          SecretKey cek = recipient.decryptKey(key, recipientID);
616          System.out.println("Decrypt content with decrypted content encryption key...");
617          enveloped_data.setupCipher(cek);
618          return enveloped_data.getContent();
619    
620        } catch (InvalidKeyException ex) {
621          throw new CMSException("Private key error: "+ex.getMessage());
622        } catch (NoSuchAlgorithmException ex) {
623          throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
624        }
625      }
626      
627      /**
628       * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
629       * the recipient identified by its recipient certificate or keyID.
630       * <p>
631       * Since recipient certificates only may be used for for RecipientInfos of type
632       * KeyTransRecipientInfo or KeyAgreeRecipientInfo, a key id has to be supplied
633       * for decrypting the content for a recipient using a KEKRecipientInfo.
634       *
635       * @param enc the DER encoded <code>EnvelopedData</code> ASN.1 object
636       * @param key the key to decrypt the message
637       * @param recipientCert the certificate of the recipient having a RecipientInfo of
638       *                      type KeyTransRecipientInfo or KeyAgreeRecipientInfo
639       * @param kekID the kekID identifying the recipient key when using a RecipientInfo
640       *              of type KEKRecipientInfo
641       *
642       * @return the recovered message, as byte array
643       * @throws CMSException if the message cannot be recovered
644       */
645      public byte[] getEnvelopedData(byte[] enc, Key key, X509Certificate recipientCert, byte[] kekID) 
646        throws CMSException, IOException {
647        ByteArrayInputStream bais = new ByteArrayInputStream(enc);
648        EnvelopedData enveloped_data = new EnvelopedData(bais);
649    
650        System.out.println("Information about the encrypted data:");
651        EncryptedContentInfo eci = (EncryptedContentInfo)enveloped_data.getEncryptedContentInfo();
652        System.out.println("Content type: "+eci.getContentType().getName());
653        System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
654    
655        System.out.println("\nThis message can be decrypted by the owners of the following certificates:");
656    
657        // decrypt the content encryption key and the content
658        try {
659          System.out.println("Decrypt the content...");
660          if (recipientCert != null) {
661            enveloped_data.setupCipher(key, recipientCert);
662          } else {
663            // KEKRecipientInfo
664            enveloped_data.setupCipher(key, new KEKIdentifier(kekID));
665          }  
666          return enveloped_data.getContent();
667    
668        } catch (InvalidKeyException ex) {
669          throw new CMSException("Private key error: "+ex.getMessage());
670        } catch (NoSuchAlgorithmException ex) {
671          throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
672        }
673      }
674      
675      /**
676       * Creates the RecipientInfos.
677       *
678       * @return the RecipientInfos created, two KeyTransRecipientInfos, one
679       *         KeyAgreeRecipientInfo (for two recipients with same domain
680       *         parameters), and one KEKRecipientInfo
681       *
682       * @throws CMSException if an error occurs when creating the recipient infos
683       */
684      public RecipientInfo[] createRecipients() throws CMSException {
685        
686        RecipientInfo[] recipients = new RecipientInfo[4];
687        try {
688          // rsaUser1 is the first receiver (cert identified by IssuerAndSerialNumber)
689          recipients[0] = new KeyTransRecipientInfo(rsaUser1_, 
690                                                    (AlgorithmID)AlgorithmID.rsaEncryption.clone());
691          // rsaUser2 is the second receiver (cert identifief by SubjectKeyIdentifier)
692          recipients[1] = new KeyTransRecipientInfo(rsaUser2_, 
693                                                    CertificateIdentifier.SUBJECT_KEY_IDENTIFIER, 
694                                                    (AlgorithmID)AlgorithmID.rsaEncryption.clone());
695    
696          // next recipients use key agreement
697          // the key encryption (key agreement) algorithm to use:
698          AlgorithmID keyEA = (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone();
699          // the key wrap algorithm to use:
700          AlgorithmID keyWrapAlg = (AlgorithmID)keyWrapAlg_.clone();
701          // the length of the key encryption key to be generated:
702          int kekLength = keyLength_;
703          recipients[2] = new KeyAgreeRecipientInfo(keyEA, keyWrapAlg, kekLength);
704          // esdhUser1 is the third receiver  (cert identified by IssuerAndSerialNumber)
705          ((KeyAgreeRecipientInfo)recipients[2]).addRecipient(esdhUser1_, CertificateIdentifier.ISSUER_AND_SERIALNUMBER);
706          // esdhUser2 is the fourth receiver (cert identified by RecipientKeyIdentifier)
707          ((KeyAgreeRecipientInfo)recipients[2]).addRecipient(esdhUser2_, CertificateIdentifier.RECIPIENT_KEY_IDENTIFIER);
708          
709          // last receiver uses a symmetric key encryption key  
710          AlgorithmID kea = (AlgorithmID)keyWrapAlg_.clone();
711          KEKIdentifier kekIdentifier = new KEKIdentifier(kekID_);
712          recipients[3] = new KEKRecipientInfo(kekIdentifier, kea, kek_);
713        } catch (Exception ex) {
714          throw new CMSException("Error adding recipients: " + ex.getMessage()); 
715        }    
716        return recipients;
717      }  
718      
719      /**
720       * Parses an EnvelopedData and decrypts the content for all test recipients
721       * using the index into the recipientInfos field for identifying the recipient.
722       *
723       * @param stream whether to use EnvelopedDataStream or EnvelopedData
724       * @param message the original message (to be compared to the decryption result) 
725       * @param encodedEnvelopedData the encoded EnvelopedData object 
726       *
727       * @throws Exception if some error occurs during decoding/decryption
728       */ 
729      public void parseEnvelopedDataWithRecipientInfoIndex(boolean stream, 
730        byte[] message, byte[] encodedEnvelopedData) throws Exception {
731        byte[] receivedMessage;
732        if (stream) {
733          // rsaUser1
734          System.out.println("\nDecrypt for rsaUser1:");
735          receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, rsaUser1Pk_, 0);
736          if (!Arrays.equals(message, receivedMessage)) {
737            throw new IOException("Decryption error!");
738          }
739          System.out.print("\nDecrypted content: ");
740          System.out.println(new String(receivedMessage));
741          // rsaUser2
742          System.out.println("\nDecrypt for rsaUser2:");
743          receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, rsaUser2Pk_, 1);
744          if (!Arrays.equals(message, receivedMessage)) {
745            throw new IOException("Decryption error!");
746          }
747          System.out.print("\nDecrypted content: ");
748          System.out.println(new String(receivedMessage));
749          // esdhUser1
750          System.out.println("\nDecrypt for esdhUser1:");
751          receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, esdhUser1Pk_, 2);
752          if (!Arrays.equals(message, receivedMessage)) {
753            throw new IOException("Decryption error!");
754          }
755          System.out.print("\nDecrypted content: ");
756          System.out.println(new String(receivedMessage));
757          // esdhUser2
758          System.out.println("\nDecrypt for esdhUser2:");
759          receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, esdhUser2Pk_, 2);
760          if (!Arrays.equals(message, receivedMessage)) {
761            throw new IOException("Decryption error!");
762          }
763          System.out.print("\nDecrypted content: ");
764          System.out.println(new String(receivedMessage));
765          // kekUser
766          System.out.println("\nDecrypt for kekUser:");
767          receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, kek_, 3);
768          if (!Arrays.equals(message, receivedMessage)) {
769            throw new IOException("Decryption error!");
770          }
771          System.out.print("\nDecrypted content: ");
772          System.out.println(new String(receivedMessage));
773        } else {
774          // rsaUser1
775          System.out.println("\nDecrypt for rsaUser1:");
776          receivedMessage = getEnvelopedData(encodedEnvelopedData, rsaUser1Pk_, 0);
777          if (!Arrays.equals(message, receivedMessage)) {
778            throw new IOException("Decryption error!");
779          }
780          System.out.print("\nDecrypted content: ");
781          System.out.println(new String(receivedMessage));
782           // rsaUser2
783          System.out.println("\nDecrypt for rsaUser2:");
784          receivedMessage = getEnvelopedData(encodedEnvelopedData, rsaUser2Pk_, 1);
785          if (!Arrays.equals(message, receivedMessage)) {
786            throw new IOException("Decryption error!");
787          }
788          System.out.print("\nDecrypted content: ");
789          System.out.println(new String(receivedMessage));
790          // esdhUser1
791          System.out.println("\nDecrypt for esdhUser1:");
792          receivedMessage = getEnvelopedData(encodedEnvelopedData, esdhUser1Pk_, 2);
793          if (!Arrays.equals(message, receivedMessage)) {
794            throw new IOException("Decryption error!");
795          }
796          System.out.print("\nDecrypted content: ");
797          System.out.println(new String(receivedMessage));
798          // esdhUser2
799          System.out.println("\nDecrypt for esdhUser2:");
800          receivedMessage = getEnvelopedData(encodedEnvelopedData, esdhUser2Pk_, 2);
801          if (!Arrays.equals(message, receivedMessage)) {
802            throw new IOException("Decryption error!");
803          }
804          System.out.print("\nDecrypted content: ");
805          System.out.println(new String(receivedMessage));
806          // kekUser
807          System.out.println("\nDecrypt for kekUser:");
808          receivedMessage = getEnvelopedData(encodedEnvelopedData, kek_, 3);
809          if (!Arrays.equals(message, receivedMessage)) {
810            throw new IOException("Decryption error!");
811          }
812          System.out.print("\nDecrypted content: ");
813          System.out.println(new String(receivedMessage));
814        }    
815      }
816      
817      /**
818       * Parses an EnvelopedData and decrypts the content for all test recipients
819       * using their recipient identifiers for identifying the recipient.
820       *
821       * @param stream whether to use EnvelopedDataStream or EnvelopedData
822       * @param message the original message (to be compared to the decryption result) 
823       * @param encodedEnvelopedData the encoded EnvelopedData object 
824       *
825       * @throws Exception if some error occurs during decoding/decryption
826       */ 
827      public void parseEnvelopedDataWithRecipientIdentifier(boolean stream, 
828        byte[] message, byte[] encodedEnvelopedData) throws Exception {
829        byte[] receivedMessage;
830        if (stream) {
831          // rsaUser1
832          System.out.println("\nDecrypt for rsaUser1:");
833          receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, rsaUser1Pk_, new IssuerAndSerialNumber(rsaUser1_));
834          if (!Arrays.equals(message, receivedMessage)) {
835            throw new IOException("Decryption error!");
836          }
837          System.out.print("\nDecrypted content: ");
838          System.out.println(new String(receivedMessage));
839          // rsaUser2
840          System.out.println("\nDecrypt for rsaUser2:");
841          receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, rsaUser2Pk_, new SubjectKeyID(rsaUser2_));
842          if (!Arrays.equals(message, receivedMessage)) {
843            throw new IOException("Decryption error!");
844          }
845          System.out.print("\nDecrypted content: ");
846          System.out.println(new String(receivedMessage));
847          // esdhUser1
848          System.out.println("\nDecrypt for esdhUser1:");
849          receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, esdhUser1Pk_, new IssuerAndSerialNumber(esdhUser1_));
850          if (!Arrays.equals(message, receivedMessage)) {
851            throw new IOException("Decryption error!");
852          }
853          System.out.print("\nDecrypted content: ");
854          System.out.println(new String(receivedMessage));
855          // esdhUser2
856          System.out.println("\nDecrypt for esdhUser2:");
857          receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, esdhUser2Pk_, new RecipientKeyIdentifier(esdhUser2_));
858          if (!Arrays.equals(message, receivedMessage)) {
859            throw new IOException("Decryption error!");
860          }
861          System.out.print("\nDecrypted content: ");
862          System.out.println(new String(receivedMessage));
863          // kekUser
864          System.out.println("\nDecrypt for kekUser:");
865          receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, kek_, new KEKIdentifier(kekID_));
866          if (!Arrays.equals(message, receivedMessage)) {
867            throw new IOException("Decryption error!");
868          }
869          System.out.print("\nDecrypted content: ");
870          System.out.println(new String(receivedMessage));
871        } else {
872          // rsaUser1
873          System.out.println("\nDecrypt for rsaUser1:");
874          receivedMessage = getEnvelopedData(encodedEnvelopedData, rsaUser1Pk_, new IssuerAndSerialNumber(rsaUser1_));
875          if (!Arrays.equals(message, receivedMessage)) {
876            throw new IOException("Decryption error!");
877          }
878          System.out.print("\nDecrypted content: ");
879          System.out.println(new String(receivedMessage));
880           // rsaUser2
881          System.out.println("\nDecrypt for rsaUser2:");
882          receivedMessage = getEnvelopedData(encodedEnvelopedData, rsaUser2Pk_, new SubjectKeyID(rsaUser2_));
883          if (!Arrays.equals(message, receivedMessage)) {
884            throw new IOException("Decryption error!");
885          }
886          System.out.print("\nDecrypted content: ");
887          System.out.println(new String(receivedMessage));
888          // esdhUser1
889          System.out.println("\nDecrypt for esdhUser1:");
890          receivedMessage = getEnvelopedData(encodedEnvelopedData, esdhUser1Pk_, new IssuerAndSerialNumber(esdhUser1_));
891          if (!Arrays.equals(message, receivedMessage)) {
892            throw new IOException("Decryption error!");
893          }
894          System.out.print("\nDecrypted content: ");
895          System.out.println(new String(receivedMessage));
896          // esdhUser2
897          System.out.println("\nDecrypt for esdhUser2:");
898          receivedMessage = getEnvelopedData(encodedEnvelopedData, esdhUser2Pk_, new RecipientKeyIdentifier(esdhUser2_));
899          if (!Arrays.equals(message, receivedMessage)) {
900            throw new IOException("Decryption error!");
901          }
902          System.out.print("\nDecrypted content: ");
903          System.out.println(new String(receivedMessage));
904          // kekUser
905          System.out.println("\nDecrypt for kekUser:");
906          receivedMessage = getEnvelopedData(encodedEnvelopedData, kek_, new KEKIdentifier(kekID_));
907          if (!Arrays.equals(message, receivedMessage)) {
908            throw new IOException("Decryption error!");
909          }
910          System.out.print("\nDecrypted content: ");
911          System.out.println(new String(receivedMessage));
912        }    
913      }
914      
915      /**
916       * Parses an EnvelopedData and decrypts the content for all test recipients
917       * using their recipient certificate (for RecipientInfos of type KeyTransRecipientInfo
918       * or KeyAgreeRecipientInfo) or key id (for RecipientInfos of type KEKRecipientInfo)
919       * for identifying the recipient.
920       *
921       * @param stream whether to use EnvelopedDataStream or EnvelopedData
922       * @param message the original message (to be compared to the decryption result) 
923       * @param encodedEnvelopedData the encoded EnvelopedData object 
924       *
925       * @throws Exception if some error occurs during decoding/decryption
926       */ 
927      public void parseEnvelopedDataWithRecipientCertOrKEKId(boolean stream, 
928        byte[] message, byte[] encodedEnvelopedData) throws Exception {
929        byte[] receivedMessage;
930        if (stream) {
931          // rsaUser1
932          System.out.println("\nDecrypt for rsaUser1:");
933          receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, rsaUser1Pk_, rsaUser1_, null);
934          if (!Arrays.equals(message, receivedMessage)) {
935            throw new IOException("Decryption error!");
936          }
937          System.out.print("\nDecrypted content: ");
938          System.out.println(new String(receivedMessage));
939          // rsaUser2
940          System.out.println("\nDecrypt for rsaUser2:");
941          receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, rsaUser2Pk_, rsaUser2_, null);
942          if (!Arrays.equals(message, receivedMessage)) {
943            throw new IOException("Decryption error!");
944          }
945          System.out.print("\nDecrypted content: ");
946          System.out.println(new String(receivedMessage));
947          // esdhUser1
948          System.out.println("\nDecrypt for esdhUser1:");
949          receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, esdhUser1Pk_, esdhUser1_, null);
950          if (!Arrays.equals(message, receivedMessage)) {
951            throw new IOException("Decryption error!");
952          }
953          System.out.print("\nDecrypted content: ");
954          System.out.println(new String(receivedMessage));
955          // esdhUser2
956          System.out.println("\nDecrypt for esdhUser2:");
957          receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, esdhUser2Pk_, esdhUser2_, null);
958          if (!Arrays.equals(message, receivedMessage)) {
959            throw new IOException("Decryption error!");
960          }
961          System.out.print("\nDecrypted content: ");
962          System.out.println(new String(receivedMessage));
963          // kekUser
964          System.out.println("\nDecrypt for kekUser:");
965          receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, kek_, null, kekID_);
966          if (!Arrays.equals(message, receivedMessage)) {
967            throw new IOException("Decryption error!");
968          }
969          System.out.print("\nDecrypted content: ");
970          System.out.println(new String(receivedMessage));
971        } else {
972          // rsaUser1
973          System.out.println("\nDecrypt for rsaUser1:");
974          receivedMessage = getEnvelopedData(encodedEnvelopedData, rsaUser1Pk_, rsaUser1_, null);
975          if (!Arrays.equals(message, receivedMessage)) {
976            throw new IOException("Decryption error!");
977          }
978          System.out.print("\nDecrypted content: ");
979          System.out.println(new String(receivedMessage));
980           // rsaUser2
981          System.out.println("\nDecrypt for rsaUser2:");
982          receivedMessage = getEnvelopedData(encodedEnvelopedData, rsaUser2Pk_, rsaUser2_, null);
983          if (!Arrays.equals(message, receivedMessage)) {
984            throw new IOException("Decryption error!");
985          }
986          System.out.print("\nDecrypted content: ");
987          System.out.println(new String(receivedMessage));
988          // esdhUser1
989          System.out.println("\nDecrypt for esdhUser1:");
990          receivedMessage = getEnvelopedData(encodedEnvelopedData, esdhUser1Pk_, esdhUser1_, null);
991          if (!Arrays.equals(message, receivedMessage)) {
992            throw new IOException("Decryption error!");
993          }
994          System.out.print("\nDecrypted content: ");
995          System.out.println(new String(receivedMessage));
996          // esdhUser2
997          System.out.println("\nDecrypt for esdhUser2:");
998          receivedMessage = getEnvelopedData(encodedEnvelopedData, esdhUser2Pk_, esdhUser2_, null);
999          if (!Arrays.equals(message, receivedMessage)) {
1000            throw new IOException("Decryption error!");
1001          }
1002          System.out.print("\nDecrypted content: ");
1003          System.out.println(new String(receivedMessage));
1004          // kekUser
1005          System.out.println("\nDecrypt for kekUser:");
1006          receivedMessage = getEnvelopedData(encodedEnvelopedData, kek_, null, kekID_);
1007          if (!Arrays.equals(message, receivedMessage)) {
1008            throw new IOException("Decryption error!");
1009          }
1010          System.out.print("\nDecrypted content: ");
1011          System.out.println(new String(receivedMessage));
1012        }    
1013      }
1014      
1015      /**
1016       * Starts the test.
1017       */
1018      public void start() {
1019         // the test message
1020        String m = "This is the test message.";
1021        System.out.println("Test message: \""+m+"\"");
1022        System.out.println();
1023        byte[] message = m.getBytes();
1024    
1025        try {
1026          byte[] data;
1027          System.out.println("Stream implementation demos");
1028          System.out.println("===========================");
1029    
1030    
1031          // the stream implementation
1032          //
1033          // test CMS EnvelopedDataStream
1034          //
1035          System.out.println("\nCMS EnvelopedDataStream demo [create]:\n");
1036          data = createEnvelopedDataStream(message);
1037          // transmit data
1038          System.out.println("\nCMS EnvelopedDataStream demo [parse]:\n");
1039          System.out.println("Decrypt for the several recipients using their index into the recipientInfos field.");
1040          parseEnvelopedDataWithRecipientInfoIndex(true, message, data);
1041          System.out.println("Decrypt for the several recipients using their RecipientIdentifier.");
1042          parseEnvelopedDataWithRecipientIdentifier(true, message, data);
1043          System.out.println("Decrypt for the several recipients using their certificate or symmetric kek.");
1044          parseEnvelopedDataWithRecipientCertOrKEKId(true, message, data);
1045    
1046          // the non-stream implementation
1047          System.out.println("\nNon-stream implementation demos");
1048          System.out.println("===============================");
1049    
1050                
1051          //
1052          // test CMS EnvelopedData
1053          //
1054          System.out.println("\nCMS EnvelopedData demo [create]:\n");
1055          data = createEnvelopedData(message);
1056          // transmit data
1057          System.out.println("\nCMS EnvelopedData demo [parse]:\n");
1058          System.out.println("Decrypt for the several recipients using their index into the recipientInfos field.");
1059          parseEnvelopedDataWithRecipientInfoIndex(false, message, data);
1060          System.out.println("Decrypt for the several recipients using their RecipientIdentifier.");
1061          parseEnvelopedDataWithRecipientIdentifier(false, message, data);
1062          System.out.println("Decrypt for the several recipients using their certificate or symmetric kek.");
1063          parseEnvelopedDataWithRecipientCertOrKEKId(false, message, data);
1064          
1065    
1066            } catch (Exception ex) {
1067              ex.printStackTrace();
1068              throw new RuntimeException(ex.toString());
1069            }
1070      }
1071      
1072      /**
1073       * Main method.
1074       *
1075       * @throws IOException
1076       *            if an I/O error occurs when reading required keys
1077       *            and certificates from files
1078       */
1079      public static void main(String argv[]) throws Exception {
1080    
1081            DemoUtil.initDemos();
1082        (new EnvelopedDataDemo()).start();
1083        System.out.println("\nReady!");
1084        DemoUtil.waitKey();
1085      }
1086    }