001// Copyright (C) 2002 IAIK
002// https://sic.tech/
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// This source is provided for inspection purposes and recompilation only,
011// unless specified differently in a contract with IAIK. This source has to
012// be kept in strict confidence and must not be disclosed to any third party
013// under any circumstances. Redistribution in source and binary forms, with
014// or without modification, are <not> permitted in any case!
015//
016// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
017// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
018// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
019// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
020// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
021// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
022// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
023// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
024// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
025// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
026// SUCH DAMAGE.
027//
028// $Header: /IAIK-CMS/current/src/demo/cms/authenticatedData/AuthenticatedDataDemo.java 25    12.02.25 17:58 Dbratko $
029// $Revision: 25 $
030
031package demo.cms.authenticatedData;
032
033
034import java.io.ByteArrayInputStream;
035import java.io.ByteArrayOutputStream;
036import java.io.IOException;
037import java.io.InputStream;
038import java.security.InvalidKeyException;
039import java.security.Key;
040import java.security.NoSuchAlgorithmException;
041import java.security.PrivateKey;
042import java.security.SecureRandom;
043
044import javax.crypto.KeyGenerator;
045import javax.crypto.SecretKey;
046
047import demo.DemoUtil;
048import demo.keystore.CMSKeyStore;
049import iaik.asn1.ObjectID;
050import iaik.asn1.structures.AlgorithmID;
051import iaik.asn1.structures.Attribute;
052import iaik.cms.AuthenticatedData;
053import iaik.cms.AuthenticatedDataStream;
054import iaik.cms.CMSAlgorithmID;
055import iaik.cms.CMSException;
056import iaik.cms.CertificateIdentifier;
057import iaik.cms.ContentInfo;
058import iaik.cms.ContentInfoStream;
059import iaik.cms.IssuerAndSerialNumber;
060import iaik.cms.KEKIdentifier;
061import iaik.cms.KEKRecipientInfo;
062import iaik.cms.KeyAgreeRecipientInfo;
063import iaik.cms.KeyIdentifier;
064import iaik.cms.KeyTransRecipientInfo;
065import iaik.cms.OriginatorInfo;
066import iaik.cms.RecipientInfo;
067import iaik.cms.RecipientKeyIdentifier;
068import iaik.cms.SecurityProvider;
069import iaik.cms.SubjectKeyID;
070import iaik.cms.attributes.CMSContentType;
071import iaik.security.random.SecRandom;
072import iaik.utils.Util;
073import iaik.x509.X509Certificate;
074
075/**
076 * Demonstrates the usage of class {@link iaik.cms.AuthenticatedDataStream} and
077 * {@link iaik.cms.AuthenticatedData} for recipient-specific protecting the 
078 * integrity of a message using the CMS type AuthenticatedData.
079 * <p>
080 * This demo requires that you have <code>iaik_esdh.jar</code>
081 * (or <code>iaik_jce_full.jar</code>) in your classpath.
082 * You can download it from <a href="https://sic.tech/products/core-crypto-toolkits/jca-jce/" target="_blank">
083 * https://sic.tech/products/core-crypto-toolkits/jca-jce/</a>.
084 * 
085 *
086 * @see iaik.cms.AuthenticatedDataStream
087 * @see iaik.cms.AuthenticatedData
088 * 
089 */
090public class AuthenticatedDataDemo {
091  
092  // certificate of rsaUser 1
093  X509Certificate rsaUser1Cert_;
094  // private key of rsaUser 1
095  PrivateKey rsaUser1PrivKey_;
096  // certificate of rsaUser 2
097  X509Certificate rsaUser2Cert_;
098  // private key of rsaUser 2
099  PrivateKey rsaUser2PrivKey_;
100
101  // certificate of (originator) User 1 (static-static Diffie-Hellman)
102  X509Certificate ssdhUser1Cert_;
103  X509Certificate[] originatorCerts_;
104  // private key of SSDH User 1
105  PrivateKey ssdhUser1PrivKey_;
106  // certificate of SSDH User 2 (static-static Diffie-Hellman)
107  X509Certificate ssdhUser2Cert_;
108  // private key of SSDH User 2
109  PrivateKey ssdhUser2PrivKey_;
110  
111  // key wrap algorithm to be used
112  AlgorithmID keyWrapAlg_;
113  // kek length
114  int kekLength_;
115  // key encryption key for KEKRecipientInfo
116  SecretKey kek_;
117  byte[] kekID_;
118
119  
120  // secure random number generator
121  SecureRandom random_;
122  
123  /**
124   * Creates and AuthenticatedDataDemo object and setups the demo certificates.
125   *
126   * Keys and certificate are retrieved from the demo KeyStore which
127   * has to be located in your current working directory and may be
128   * created by running {@link demo.keystore.SetupCMSKeyStore
129   * SetupCMSKeyStore}.
130   * <p>
131   * CMS-AES256-Wrap is used as key wrap algorithm.
132   *
133   * @throws IOException if an file read error occurs
134   * @throws NoSuchAlgorithmException if no implementation for the requested key wrap algorithm is available
135   */
136  public AuthenticatedDataDemo() throws IOException, NoSuchAlgorithmException {
137    this((AlgorithmID)CMSAlgorithmID.cms_aes256_wrap.clone(), 256);
138  }
139  
140  /**
141   * Creates and AuthenticatedDataDemo object and setups the demo certificates.
142   *
143   * Keys and certificate are retrieved from the demo KeyStore which
144   * has to be located in your current working directory and may be
145   * created by running {@link demo.keystore.SetupCMSKeyStore
146   * SetupCMSKeyStore}.
147   * 
148   * @param keyWrapAlg the key wrap algorithm to be used
149   * @param kekLength the length of the key encryption key
150   *
151   * @throws IOException if an file read error occurs
152   * @throws NoSuchAlgorithmException if no implementation for the requested key wrap algorithm is available
153   */
154  public AuthenticatedDataDemo(AlgorithmID keyWrapAlg, int kekLength) throws IOException, NoSuchAlgorithmException {
155    
156    System.out.println();
157    System.out.println("**********************************************************************************");
158    System.out.println("*                           AuthenticatedDataDemo                                *");
159    System.out.println("*        (shows the usage of the CMS AuthenticatedData type implementation)      *");
160    System.out.println("**********************************************************************************");
161    System.out.println();
162    
163    // add all certificates to the list
164    rsaUser1Cert_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0];
165    rsaUser1PrivKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1);
166    rsaUser2Cert_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0];
167    rsaUser2PrivKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2);
168    
169    originatorCerts_ = CMSKeyStore.getCertificateChain(CMSKeyStore.SSDH, CMSKeyStore.SZ_2048_CRYPT_1);
170    ssdhUser1Cert_ = originatorCerts_[0];
171    ssdhUser1PrivKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.SSDH, CMSKeyStore.SZ_2048_CRYPT_1);
172    ssdhUser2Cert_ = CMSKeyStore.getCertificateChain(CMSKeyStore.SSDH, CMSKeyStore.SZ_2048_CRYPT_2)[0];
173    ssdhUser2PrivKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.SSDH, CMSKeyStore.SZ_2048_CRYPT_2);
174    
175    random_ = SecRandom.getDefault();
176    keyWrapAlg_ = keyWrapAlg;
177    kekLength_ = kekLength;
178    //  create a secret key encryption key for a KEKRecipientInfo
179    KeyGenerator kg = SecurityProvider.getSecurityProvider().getKeyGenerator(keyWrapAlg_, kekLength_);
180    kek_ = kg.generateKey();
181    kekID_ = new byte[] { 00, 00, 00, 01 };
182    
183  }
184
185
186  /**
187   * Creates a CMS <code>AuthenticatedDataStream</code> for the given message message.
188   *
189   * @param message the message to be authenticated, as byte representation
190   * @param macAlgorithm the mac algorithm to be used
191   * @param macKeyLength the length of the temporary MAC key to be generated
192   * @param digestAlgorithm the digest algorithm to be used to calculate a digest
193   *                        from the content if authenticated attributes should
194   *                        be included
195   * @param mode whether to include the content into the AuthenticatedData ({@link
196   *             AuthenticatedDataStream#IMPLICIT implicit}) or to not include it
197   *             ({@link AuthenticatedDataStream#EXPLICIT explicit})
198   *                                    
199   * @return the BER encoding of the <code>AuthenticatedData</code> object just created
200   * 
201   * @throws CMSException if the <code>AuthenticatedData</code> object cannot
202   *                          be created
203   * @throws IOException if an I/O error occurs
204   */
205  public byte[] createAuthenticatedDataStream(byte[] message,
206                                              AlgorithmID macAlgorithm,
207                                              int macKeyLength,
208                                              AlgorithmID digestAlgorithm,
209                                              int mode)
210    throws CMSException, IOException {
211    
212    AlgorithmID macAlg = (AlgorithmID)macAlgorithm.clone();
213    AlgorithmID digestAlg = null;
214    if (digestAlgorithm != null) {
215       digestAlg = (AlgorithmID)digestAlgorithm.clone();
216    }   
217    ObjectID contentType = ObjectID.cms_data;
218    
219    AuthenticatedDataStream authenticatedData;
220
221    // we are testing the stream interface
222    ByteArrayInputStream is = new ByteArrayInputStream(message);
223    // create a new AuthenticatedData object 
224    try {
225      authenticatedData = new AuthenticatedDataStream(contentType,
226                                                      is, 
227                                                      macAlg,
228                                                      macKeyLength,
229                                                      null,
230                                                      digestAlg,
231                                                      mode);
232    } catch (NoSuchAlgorithmException ex) {
233      throw new CMSException(ex.toString());
234    }
235
236    // static-static mode: set OriginatorInfo
237    OriginatorInfo originator = new OriginatorInfo();
238    originator.setCertificates(originatorCerts_);
239    authenticatedData.setOriginatorInfo(originator);
240    // create the recipient infos
241    RecipientInfo[] recipients = createRecipients();
242    // specify the recipients of the authenticated message
243    authenticatedData.setRecipientInfos(recipients);
244    
245    if (digestAlgorithm != null) {
246       // create some authenticated attributes
247       // (the message digest attribute is automatically added)
248       try {
249         Attribute[] attributes = { new Attribute(new CMSContentType(contentType)) };
250         authenticatedData.setAuthenticatedAttributes(attributes);
251       } catch (Exception ex) {
252         throw new CMSException("Error creating attribute: " + ex.toString());   
253       } 
254    }    
255    
256    // in explicit mode get the content and write it  to any out-of-band place
257    if (mode == AuthenticatedDataStream.EXPLICIT) {
258      InputStream data_is = authenticatedData.getInputStream();
259      byte[] buf = new byte[2048];
260      int r;
261      while ((r = data_is.read(buf)) > 0)
262        ;   // skip data
263    }    
264      
265    // return the AuthenticatedData as BER encoded byte array with block size 16
266    // (just for testing; in real application we will use a proper blocksize,
267    //  e.g. 2048, 4096,..)
268    authenticatedData.setBlockSize(16);
269    // return the AuthenticatedDate as BER encoded byte array with block size 2048
270    ByteArrayOutputStream os = new ByteArrayOutputStream();
271    // wrap into ContentInfo
272    ContentInfoStream contentInfo = new ContentInfoStream(authenticatedData);
273    contentInfo.writeTo(os);
274    return os.toByteArray();
275  }
276
277  /**
278   * Decrypts the encrypted MAC key for the recipient identified by its index
279   * into the recipientInfos field and uses the MAC key to verify
280   * the authenticated data.
281   * <p>
282   * This way of decrypting the MAC key and verifying the content may be used for 
283   * any type of RecipientInfo (KeyTransRecipientInfo, KeyAgreeRecipientInfo, 
284   * KEKRecipientInfo, PasswordRecipeintInfo, OtherRecipientInfo), but requires to 
285   * know at what index of the recipientInfos field the RecipientInfo for the 
286   * particular recipient in mind can be found. 
287   * If the recipient in mind uses a RecipientInfo of type KeyAgreeRecipientInfo
288   * some processing overhead may take place because a KeyAgreeRecipientInfo may
289   * contain encrypted mac keys for more than only one recipient; since the
290   * recipientInfoIndex only specifies the RecipientInfo but not the encrypted
291   * mac key -- if there are more than only one -- repeated decryption runs may be
292   * required as long as the decryption process completes successfully.
293   *
294   * @param encoding the <code>AuthenticatedData</code> object as BER encoded byte array
295   * @param message the content message, if transmitted by other means (explicit mode)
296   * @param key the key to decrypt the mac key 
297   * @param recipientInfoIndex the index of the right <code>RecipientInfo</code> to 
298   *                           which the given key belongs
299   *
300   * @return the verified message, as byte array
301   * 
302   * @throws CMSException if the authenticated data cannot be verified
303   * @throws IOException if a stream read/write error occurs
304   */
305  public byte[] getAuthenticatedDataStream(byte[] encoding, 
306                                           byte[] message, 
307                                           Key key, 
308                                           int recipientInfoIndex)
309    throws CMSException, IOException {
310
311    // create the AuthenticatedData object from a DER encoded byte array
312    // we are testing the stream interface
313    ByteArrayInputStream is = new ByteArrayInputStream(encoding);
314    AuthenticatedDataStream authenticatedData = new AuthenticatedDataStream(is);
315    
316    if (authenticatedData.getMode() == AuthenticatedDataStream.EXPLICIT) {
317      // in explicit mode explicitly supply the content for hash/mac computation  
318      authenticatedData.setInputStream(new ByteArrayInputStream(message));
319    }
320
321    System.out.println("\nThis message can be verified by the following recipients:");
322    RecipientInfo[] recipients = authenticatedData.getRecipientInfos();
323    
324    // for demonstration purposes we only look one time for all recipients included:
325    if (recipientInfoIndex == 0) {
326      int k = 0;
327      for (int i=0; i<recipients.length; i++) {
328        KeyIdentifier[] recipientIDs = recipients[i].getRecipientIdentifiers();
329        for (int j = 0; j < recipientIDs.length; j++) {
330          System.out.println("Recipient "+(++k)+":");
331          System.out.println(recipientIDs[j]);
332        }   
333      }
334    }
335    // decrypt the mac key and verify the mac for the indented recipient
336    try {
337      authenticatedData.setupMac(key, recipientInfoIndex);
338      InputStream contentStream = authenticatedData.getInputStream();
339      ByteArrayOutputStream os = new ByteArrayOutputStream();
340      Util.copyStream(contentStream, os, null);
341      
342      if (authenticatedData.verifyMac() == false) {
343        throw new CMSException("Mac verification error!");
344      }  
345      System.out.println("Mac successfully verified!");
346      
347      return os.toByteArray();
348
349    } catch (InvalidKeyException ex) {
350      throw new CMSException("Key error: "+ex.getMessage());
351    } catch (NoSuchAlgorithmException ex) {
352      throw new CMSException(ex.toString());
353    }
354  }
355  
356  /**
357   * Decrypts the encrypted MAC key for the recipient identified by recipient identifier
358   * and uses the MAC key to verify the authenticated data.
359   * <p>
360   * This way of decrypting the mac key may be used for any type of RecipientInfo
361   * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo). The 
362   * recipient in mind is identified by its recipient identifier.
363   *
364   * @param encoding the <code>AuthenticatedData</code> object as BER encoded byte array
365   * @param message the content message, if transmitted by other means (explicit mode)
366   * @param key the key to decrypt the encrypted mac key
367   * @param recipientID the recipient identifier uniquely identifying the key of the
368   *        recipient
369   *
370   * @return the verified message, as byte array
371   * 
372   * @throws CMSException if the authenticated data cannot be verified
373   * @throws IOException if a stream read/write error occurs
374   */
375  public byte[] getAuthenticatedDataStream(byte[] encoding, 
376                                           byte[] message,
377                                           Key key, 
378                                           KeyIdentifier recipientID)
379    throws CMSException, IOException {
380
381    // create the AuthenticatedData object from a BER encoded byte array
382    // we are testing the stream interface
383    ByteArrayInputStream is = new ByteArrayInputStream(encoding);
384    AuthenticatedDataStream authenticatedData = new AuthenticatedDataStream(is);
385    
386    if (authenticatedData.getMode() == AuthenticatedDataStream.EXPLICIT) {
387      // in explicit mode explicitly supply the content for hash/mac computation  
388      authenticatedData.setInputStream(new ByteArrayInputStream(message));
389    }
390   
391    // get the right RecipientInfo
392    System.out.println("\nSearch for RecipientInfo:");
393    RecipientInfo recipient = authenticatedData.getRecipientInfo(recipientID);
394    if (recipient != null) {
395      System.out.println("RecipientInfo: " + recipient);   
396    } else {
397      throw new CMSException("No recipient with ID: " + recipientID);
398    }
399    // decrypt the mac key and verify the content mac
400    try {
401      System.out.println("Decrypt encrypted mac key...");
402      SecretKey cek = recipient.decryptKey(key, recipientID);
403      System.out.println("Verify content mac with decrypted mac key...");
404      authenticatedData.setupMac(cek);
405      InputStream contentStream = authenticatedData.getInputStream();
406      ByteArrayOutputStream os = new ByteArrayOutputStream();
407      Util.copyStream(contentStream, os, null);
408      
409      if (authenticatedData.verifyMac() == false) {
410        throw new CMSException("Mac verification error!");
411      } 
412      System.out.println("Mac successfully verified!");
413
414      return os.toByteArray();
415
416    } catch (InvalidKeyException ex) {
417      throw new CMSException("Key error: "+ex.getMessage());
418    } catch (NoSuchAlgorithmException ex) {
419      throw new CMSException(ex.toString());
420    }
421  }
422  
423  /**
424   * Decrypts the encrypted content of the given <code>AuthenticatedData</code> object for
425   * the recipient identified by its recipient certificate or kekID.
426   * <p>
427   *
428   * @param encoding the <code>AuthenticatedData</code> object as DER encoded byte array
429   * @param message the content message, if transmitted by other means (explicit mode) 
430   * @param key the key to decrypt the message
431   * @param recipientCert the certificate of the recipient having a RecipientInfo of
432   *                      type KeyTransRecipientInfo or KeyAgreeRecipientInfo
433   * @param kekID the kekID identifying the recipient key when using a RecipientInfo
434   *              of type KEKRecipientInfo                     
435   *
436   * @return the recovered message, as byte array
437   * @throws CMSException if the message cannot be recovered
438   * @throws IOException if a stream read/write error occurs
439   */
440  public byte[] getAuthenticatedDataStream(byte[] encoding, 
441                                           byte[] message,
442                                           Key key, 
443                                           X509Certificate recipientCert,
444                                           byte[] kekID)
445    throws CMSException, IOException {
446
447    // create the AuthenticatedData object from a DER encoded byte array
448    // we are testing the stream interface
449    ByteArrayInputStream is = new ByteArrayInputStream(encoding);
450    AuthenticatedDataStream authenticatedData = new AuthenticatedDataStream(is);
451    
452    if (authenticatedData.getMode() == AuthenticatedDataStream.EXPLICIT) {
453      // in explicit mode explicitly supply the content for hash/mac computation  
454      authenticatedData.setInputStream(new ByteArrayInputStream(message));
455    }
456
457   
458    // decrypt the mac key and verify the content mac
459    try {
460      System.out.println("Verify mac...");
461      if (recipientCert != null) {
462        authenticatedData.setupMac(key, recipientCert);
463      } else {
464        // KEKRecipientInfo
465        authenticatedData.setupMac(key, new KEKIdentifier(kekID));
466      }
467      InputStream contentStream = authenticatedData.getInputStream();
468      ByteArrayOutputStream os = new ByteArrayOutputStream();
469      Util.copyStream(contentStream, os, null);
470      
471      if (authenticatedData.verifyMac() == false) {
472        throw new CMSException("Mac verification error!");
473      }
474      System.out.println("Mac successfully verified!");
475
476      return os.toByteArray();
477
478    } catch (InvalidKeyException ex) {
479      throw new CMSException("Key error: "+ex.getMessage());
480    } catch (NoSuchAlgorithmException ex) {
481      throw new CMSException(ex.toString());
482    }
483  }
484
485
486  // non stream
487
488  /**
489   * Creates a CMS <code>AuthenticatedData</code> for the given message message.
490   *
491   * @param message the message to be authenticated, as byte representation
492   * @param macAlgorithm the mac algorithm to be used
493   * @param macKeyLength the length of the temporary MAC key to be generated
494   * @param digestAlgorithm the digest algorithm to be used to calculate a digest
495   *                        from the content if authenticated attributes should
496   *                        be included
497   * @param mode whether to include the content into the AuthenticatedData ({@link
498   *             AuthenticatedDataStream#IMPLICIT implicit}) or to not include it
499   *             ({@link AuthenticatedDataStream#EXPLICIT explicit}) 
500   *                                    
501   * @return the BER encoding of the <code>AuthenticatedData</code> object just created
502   * 
503   * @throws CMSException if the <code>AuthenticatedData</code> object cannot
504   *                          be created
505   */
506  public byte[] createAuthenticatedData(byte[] message,
507                                        AlgorithmID macAlgorithm,
508                                        int macKeyLength,
509                                        AlgorithmID digestAlgorithm,
510                                        int mode)
511    throws CMSException {
512        
513    AlgorithmID macAlg = (AlgorithmID)macAlgorithm.clone();
514    AlgorithmID digestAlg = null;
515    if (digestAlgorithm != null) {
516       digestAlg = (AlgorithmID)digestAlgorithm.clone();
517    }   
518    ObjectID contentType = ObjectID.cms_data;
519    
520    AuthenticatedData authenticatedData;
521
522    // create a new AuthenticatedData object 
523    try {
524      authenticatedData = new AuthenticatedData(contentType,
525                                                message, 
526                                                macAlg,
527                                                macKeyLength,
528                                                null,
529                                                digestAlg,
530                                                mode);
531    } catch (NoSuchAlgorithmException ex) {
532      throw new CMSException(ex.toString());
533    }
534
535    // static-static mode: set OriginatorInfo
536    OriginatorInfo originator = new OriginatorInfo();
537    originator.setCertificates(originatorCerts_);
538    authenticatedData.setOriginatorInfo(originator);
539    // create the recipient infos
540    RecipientInfo[] recipients = createRecipients();
541    // specify the recipients of the authenticated message
542    authenticatedData.setRecipientInfos(recipients);
543    
544    if (digestAlgorithm != null) {
545       // create some authenticated attributes
546       // (the message digest attribute is automatically added)
547       try {
548         Attribute[] attributes = { new Attribute(new CMSContentType(contentType)) };
549         authenticatedData.setAuthenticatedAttributes(attributes);
550       } catch (Exception ex) {
551         throw new CMSException("Error creating attribute: " + ex.toString());   
552       } 
553    }    
554   
555    // wrap into ContentInfo
556    ContentInfo contentInfo = new ContentInfo(authenticatedData);
557    // return encoded EnvelopedData
558    return contentInfo.getEncoded();
559  
560  }
561
562
563  /**
564   * Gets the content of the given <code>AuthenticatedData</code> object and 
565   * verifies the mac for the recipient identified by its index
566   * into the recipientInfos field and uses the MAC key to verify
567   * the authenticated data.
568   * <p>
569   * This way of decrypting the MAC key and verifying the content may be used for 
570   * any type of RecipientInfo (KeyTransRecipientInfo, KeyAgreeRecipientInfo, 
571   * KEKRecipientInfo), but requires to know at what index of the recipientInfos
572   * field the RecipientInfo for the particular recipient in mind can be found. 
573   * If the recipient in mind uses a RecipientInfo of type KeyAgreeRecipientInfo
574   * some processing overhead may take place because a KeyAgreeRecipientInfo may
575   * contain encrypted mac keys for more than only one recipient; since the
576   * recipientInfoIndex only specifies the RecipientInfo but not the encrypted
577   * mac key -- if there are more than only one -- repeated decryption runs may be
578   * required as long as the decryption process completes successfully.
579   *
580   * @param encoding the <code>AuthenticatedData</code> object as BER encoded byte array
581   * @param message the content message, if transmitted by other means (explicit mode)
582   * @param key the key to decrypt the mac key
583   * @param recipientInfoIndex the index of the right <code>RecipientInfo</code> to 
584   *                           which the given key belongs
585   *
586   * @return the verified message, as byte array
587   * @throws CMSException if the authenticated data cannot be verified
588   * @throws IOException if a IO read/write error occurs
589   */
590  public byte[] getAuthenticatedData(byte[] encoding, 
591                                     byte[] message,
592                                     Key key,
593                                     int recipientInfoIndex) 
594    throws CMSException, IOException {
595        
596    // create the AuthenticatedData object from a DER encoded byte array
597    ByteArrayInputStream is = new ByteArrayInputStream(encoding);
598    AuthenticatedData authenticatedData = new AuthenticatedData(is);
599    
600    if (authenticatedData.getMode() == AuthenticatedData.EXPLICIT) {
601      // in explicit mode explicitly supply the content for hash/mac computation  
602      authenticatedData.setContent(message);
603    }
604
605    System.out.println("\nThis message can be verified by the owners of the following recipients:");
606    RecipientInfo[] recipients = authenticatedData.getRecipientInfos();
607    
608    // for demonstration purposes we only look one time for all recipients included:
609    if (recipientInfoIndex == 0) {
610      int k = 0;
611      for (int i=0; i<recipients.length; i++) {
612        KeyIdentifier[] recipientIDs = recipients[i].getRecipientIdentifiers();
613        for (int j = 0; j < recipientIDs.length; j++) {
614          System.out.println("Recipient "+(++k)+":");
615          System.out.println(recipientIDs[j]);
616        }   
617      }
618    }
619    // decrypt the mac key and verify the mac for the first recipient
620    try {
621      authenticatedData.setupMac(key, recipientInfoIndex);
622      if (authenticatedData.verifyMac() == false) {
623        throw new CMSException("Mac verification error!");
624      }  
625      System.out.println("Mac successfully verified!");
626      
627      return authenticatedData.getContent();
628
629    } catch (InvalidKeyException ex) {
630      throw new CMSException("Key error: "+ex.getMessage());
631    } catch (NoSuchAlgorithmException ex) {
632      throw new CMSException(ex.toString());
633    }
634  }
635  
636  /**
637   * Gets the content of the given <code>AuthenticatedData</code> object and 
638   * verifies the mac for the recipient identified by recipient identifier.
639   * <p>
640   * This way of decrypting the content may be used for any type of RecipientInfo
641   * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo). The 
642   * recipient in mind is identified by its recipient identifier.
643   *
644   * @param encoding the DER encoeded <code>AuthenticatedData</code> object#
645   * @param message the content message, if transmitted by other means (explicit mode)
646   * @param key the key to decrypt the message
647   * @param recipientID the recipient identifier uniquely identifying the key of the
648   *        recipient
649   *
650   * @return the recovered message, as byte array
651   * @throws CMSException if the message cannot be recovered
652   * @throws IOException if an I/O error occurs
653   */
654  public byte[] getAuthenticatedData(byte[] encoding, 
655                                     byte[] message,
656                                     Key key, 
657                                     KeyIdentifier recipientID) 
658    throws CMSException, IOException {
659        
660    // create the AuthenticatedData object from a DER encoded byte array
661    ByteArrayInputStream is = new ByteArrayInputStream(encoding);
662    AuthenticatedData authenticatedData = new AuthenticatedData(is);
663    
664    if (authenticatedData.getMode() == AuthenticatedData.EXPLICIT) {
665      // in explicit mode explicitly supply the content for hash/mac computation  
666      authenticatedData.setContent(message);
667    }
668   
669    // get the right RecipientInfo
670    System.out.println("\nSearch for RecipientInfo:");
671    RecipientInfo recipient = authenticatedData.getRecipientInfo(recipientID);
672    if (recipient != null) {
673      System.out.println("RecipientInfo: " + recipient);   
674    } else {
675      throw new CMSException("No recipient with ID " + recipientID);
676    }
677    // decrypt the mac key and verify the content mac
678    try {
679      System.out.println("Decrypt encrypted mac key...");
680      SecretKey cek = recipient.decryptKey(key, recipientID);
681      System.out.println("Verify content mac with decrypted mac key...");
682      authenticatedData.setupMac(cek);
683      
684      if (authenticatedData.verifyMac() == false) {
685        throw new CMSException("Mac verification error!");
686      } 
687      System.out.println("Mac successfully verified!");
688
689      return authenticatedData.getContent();
690
691    } catch (InvalidKeyException ex) {
692      throw new CMSException("Key error: "+ex.getMessage());
693    } 
694  }
695  
696  /**
697   * Gets the content of the given <code>AuthenticatedData</code> object and 
698   * verifies the mac for the recipient identified by its recipient certificate or kekID.
699   * <p>
700   *
701   * @param encoding the DER encoded <code>AuthenticatedData</code> ASN.1 object
702   * @param message the content message, if transmitted by other means (explicit mode) 
703   * @param key the key to decrypt the message
704   * @param recipientCert the certificate of the recipient having a RecipientInfo of
705   *                      type KeyTransRecipientInfo or KeyAgreeRecipientInfo
706   * @param kekID the kekID identifying the recipient key when using a RecipientInfo
707   *              of type KEKRecipientInfo                      
708   *
709   * @return the recovered message, as byte array
710   * @throws CMSException if the message cannot be recovered
711   */
712  public byte[] getAuthenticatedData(byte[] encoding, 
713                                     byte[] message,
714                                     Key key,
715                                     X509Certificate recipientCert,
716                                     byte[] kekID) 
717    throws CMSException, IOException {
718
719    // create the AuthenticatedData object from a DER encoded byte array
720    ByteArrayInputStream is = new ByteArrayInputStream(encoding);
721    AuthenticatedData authenticatedData = new AuthenticatedData(is);
722    
723    if (authenticatedData.getMode() == AuthenticatedData.EXPLICIT) {
724      // in explicit mode explicitly supply the content for hash/mac computation  
725      authenticatedData.setContent(message);
726    }
727
728    // decrypt the mac key and verify the content mac
729    try {
730      System.out.println("Verify mac...");
731      if (recipientCert != null) {
732        authenticatedData.setupMac(key, recipientCert);
733      } else {
734        // KEKRecipientInfo
735        authenticatedData.setupMac(key, new KEKIdentifier(kekID));
736      }
737    
738      if (authenticatedData.verifyMac() == false) {
739        throw new CMSException("Mac verification error!");
740      }
741      System.out.println("Mac successfully verified!");
742
743      return authenticatedData.getContent();
744      
745    } catch (InvalidKeyException ex) {
746      throw new CMSException("Key error: "+ex.getMessage());
747    } catch (NoSuchAlgorithmException ex) {
748      throw new CMSException(ex.toString());
749    } 
750  }
751  
752  /**
753   * Creates the RecipientInfos.
754   *
755   * @return the RecipientInfos created
756   *
757   * @throws CMSException if an error occurs when creating the recipient infos
758   */
759  public RecipientInfo[] createRecipients() throws CMSException {
760    
761    RecipientInfo[] recipients = new RecipientInfo[4];
762    try {
763      
764      // rsaUser1 is the first receiver (cert identified by IssuerAndSerialNumber)
765      recipients[0] = new KeyTransRecipientInfo(rsaUser1Cert_, 
766                                                (AlgorithmID)AlgorithmID.rsaEncryption.clone());
767      // rsaUser2 is the second receiver (cert identifief by SubjectKeyIdentifier)
768      recipients[1] = new KeyTransRecipientInfo(rsaUser2Cert_,
769                                                CertificateIdentifier.SUBJECT_KEY_IDENTIFIER, 
770                                                (AlgorithmID)AlgorithmID.rsaEncryption.clone());
771      
772      // next recipients use key agreement (Static-Static Diffie-Hellman)
773      // the key encryption (key agreement) algorithm to use:
774      AlgorithmID keyEA = (AlgorithmID)AlgorithmID.ssdhKeyAgreement.clone();
775      // the key wrap algorithm to use:
776      AlgorithmID keyWrapAlg = (AlgorithmID)keyWrapAlg_.clone();
777      // the length of the key encryption key to be generated:
778      int kekLength = kekLength_;
779      // in static-static mode we may supply user keying material
780      byte[] ukm = new byte[64];
781      random_.nextBytes(ukm);
782      // ssdhUser1 is originator
783      recipients[2] = new KeyAgreeRecipientInfo(ssdhUser1Cert_, 
784                                                ssdhUser1PrivKey_,
785                                                KeyIdentifier.ISSUER_AND_SERIALNUMBER,
786                                                keyEA, 
787                                                keyWrapAlg, 
788                                                kekLength, 
789                                                ukm);
790      // add ssdhUser1 (originator) as recipient, too
791      ((KeyAgreeRecipientInfo)recipients[2]).addRecipient(ssdhUser1Cert_, CertificateIdentifier.ISSUER_AND_SERIALNUMBER);
792      // ssdhUser2 is the recipient (cert identified by RecipientKeyIdentifier)
793      ((KeyAgreeRecipientInfo)recipients[2]).addRecipient(ssdhUser2Cert_, CertificateIdentifier.RECIPIENT_KEY_IDENTIFIER);
794
795      // last receiver uses a symmetric key encryption key  
796      AlgorithmID kea = (AlgorithmID)keyWrapAlg_.clone();
797      KEKIdentifier kekIdentifier = new KEKIdentifier(kekID_);
798      recipients[3] = new KEKRecipientInfo(kekIdentifier, kea, kek_);
799      
800    } catch (Exception ex) {
801      throw new CMSException("Error adding recipients: " + ex.getMessage()); 
802    }    
803    return recipients;
804  }  
805  
806  /**
807   * Parses an AuthenticatedData and verifies the mac for all test recipients
808   * using the index into the recipientInfos field for identifying the recipient.
809   *
810   * @param stream whether to use AuthenticatedDataStream or AuthenticatedData
811   * @param encodedAuthenticatedData the encoded AuthenticatedData object 
812   * @param message the content message, if transmitted by other means (explicit mode) 
813   *
814   * @throws Exception if some error occurs during mac key decryption / mac verification
815   */ 
816  public void parseAuthenticatedDataWithRecipientInfoIndex(boolean stream, 
817                                                           byte[] encodedAuthenticatedData,
818                                                           byte[] message) 
819    throws Exception {
820    
821    byte[] receivedMessage;
822    if (stream) {
823      
824      // rsaUser1
825      System.out.println("\nVerify MAC for rsaUser1:");
826      
827      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 
828                                                    message,
829                                                    rsaUser1PrivKey_,
830                                                    0);
831      System.out.print("\nContent: ");
832      System.out.println(new String(receivedMessage));
833        
834      // rsaUser2
835      System.out.println("\nVerify MAC for rsaUser2:");
836      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 
837                                                    message,
838                                                    rsaUser2PrivKey_,
839                                                    1);
840      
841      // ssdhUser1
842      System.out.println("\nVerify MAC for ssdhUser1:");
843    
844      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 
845                                                    message,
846                                                    ssdhUser1PrivKey_,
847                                                    2);
848      System.out.print("\nContent: ");
849      System.out.println(new String(receivedMessage));
850      
851      // ssdhUser2
852      System.out.println("\nVerify MAC for ssdhUser2:");
853      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 
854                                                    message,
855                                                    ssdhUser2PrivKey_,
856                                                    2);
857      System.out.print("\nContent: ");
858      System.out.println(new String(receivedMessage));
859      
860      // kekUser
861      System.out.println("\nVerify MAC for kekUser:");
862      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData,
863                                                    message,
864                                                    kek_,
865                                                    3);
866      System.out.print("\nContent: ");
867      System.out.println(new String(receivedMessage));
868      
869    } else {
870      
871      // rsaUser1
872      System.out.println("\nVerify MAC for rsaUser1:");
873      
874      receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 
875                                              message,
876                                              rsaUser1PrivKey_,
877                                              0);
878      System.out.print("\nContent: ");
879      System.out.println(new String(receivedMessage));
880        
881      // rsaUser2
882      System.out.println("\nVerify MAC for rsaUser2:");
883      receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 
884                                              message,
885                                              rsaUser2PrivKey_,
886                                              1); 
887      
888      // ssdhUser1
889      System.out.println("\nVerify MAC for ssdhUser1:");
890      receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 
891                                              message, 
892                                              ssdhUser1PrivKey_,
893                                              2);
894      System.out.print("\nContent: ");
895      System.out.println(new String(receivedMessage));
896       // ssdhUser2
897      System.out.println("\nVerify MAC for ssdhUser2:");
898      receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 
899                                              message, 
900                                              ssdhUser2PrivKey_, 
901                                              2);
902      
903      // kekUser
904      System.out.println("\nVerify MAC for kekUser:");
905      receivedMessage = getAuthenticatedData(encodedAuthenticatedData,
906                                              message,
907                                              kek_,
908                                              3);
909      
910      System.out.print("\nContent: ");
911      System.out.println(new String(receivedMessage));
912    }    
913  }
914  
915  /**
916   * Parses an AuthenticatedData and verifies the mac for all recipients
917   * identified by their recipient identifiers.
918   *
919   * @param stream whether to use AuthenticatedDataStream or AuthenticatedData
920   * @param encodedAuthenticatedData the encoded AuthenticatedData object 
921   * @param message the content message, if transmitted by other means (explicit mode)  
922   *
923   * @throws Exception if some error occurs during mac key decryption / mac verification
924   */ 
925  public void parseAuthenticatedDataWithRecipientIdentifier(boolean stream, 
926                                                            byte[] encodedAuthenticatedData,
927                                                            byte[] message) 
928    throws Exception {
929        
930    byte[] receivedMessage;
931    if (stream) {
932      
933      // rsaUser1
934      System.out.println("\nVerify MAC for rsaUser1:");
935      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 
936                                                    message, 
937                                                    rsaUser1PrivKey_, 
938                                                    new IssuerAndSerialNumber(rsaUser1Cert_));
939      System.out.print("\nContent: ");
940      System.out.println(new String(receivedMessage));
941      
942      // rsaUser2
943      System.out.println("\nVerify MAC for rsaUser2:");
944      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData,
945                                                    message,
946                                                    rsaUser2PrivKey_, 
947                                                    new SubjectKeyID(rsaUser2Cert_));
948
949      // ssdhUser1
950      System.out.println("\nVerify MAC for ssdhUser1:");
951      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 
952                                                    message, 
953                                                    ssdhUser1PrivKey_, 
954                                                    new IssuerAndSerialNumber(ssdhUser1Cert_));
955      System.out.print("\nContent: ");
956      System.out.println(new String(receivedMessage));
957      // ssdhUser2
958      System.out.println("\nVerify MAC for ssdhUser2:");
959      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData,
960                                                    message,
961                                                    ssdhUser2PrivKey_, 
962                                                    new RecipientKeyIdentifier(ssdhUser2Cert_));
963      // kekUser
964      System.out.println("\nVerify MAC for kekUser:");
965      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData,
966                                                    message,
967                                                    kek_,
968                                                    new KEKIdentifier(kekID_));
969      
970      System.out.print("\nContent: ");
971      System.out.println(new String(receivedMessage));
972    
973    } else {
974      
975      // rsaUser1
976      System.out.println("\nVerify MAC for rsaUser1:");
977      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 
978                                                    message, 
979                                                    rsaUser1PrivKey_, 
980                                                    new IssuerAndSerialNumber(rsaUser1Cert_));
981      System.out.print("\nContent: ");
982      System.out.println(new String(receivedMessage));
983      
984      // rsaUser2
985      System.out.println("\nVerify MAC for rsaUser2:");
986      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData,
987                                                    message,
988                                                    rsaUser2PrivKey_, 
989                                                    new SubjectKeyID(rsaUser2Cert_));
990      
991      // ssdhUser1
992      System.out.println("\nVerify MAC for ssdhUser1:");
993      receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 
994                                              message, 
995                                              ssdhUser1PrivKey_, 
996                                              new IssuerAndSerialNumber(ssdhUser1Cert_));
997      System.out.print("\nContent: ");
998      System.out.println(new String(receivedMessage));
999       // ssdhUser2
1000      System.out.println("\nVerify MAC for ssdhUser2:");
1001      receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 
1002                                              message, 
1003                                              ssdhUser2PrivKey_, 
1004                                              new RecipientKeyIdentifier(ssdhUser2Cert_));
1005      // kekUser
1006      System.out.println("\nVerify MAC for kekUser:");
1007      receivedMessage = getAuthenticatedData(encodedAuthenticatedData,
1008                                              message,
1009                                              kek_,
1010                                              new KEKIdentifier(kekID_));
1011      
1012      System.out.print("\nContent: ");
1013      System.out.println(new String(receivedMessage));
1014    }    
1015  }
1016  
1017  /**
1018   * Parses an AuthenticatedData and verifies the mac for all recipients
1019   * identified by their recipient certificate (or kek).
1020   *
1021   * @param stream whether to use AuthenticatedDataStream or AuthenticatedData
1022   * @param encodedAuthenticatedData the encoded AuthenticatedData object
1023   * @param message the content message, if transmitted by other means (explicit mode)  
1024   *
1025   * @throws Exception if some error occurs during mac key decryption / mac verification
1026   */ 
1027  public void parseAuthenticatedDataWithRecipientCertOrKEKId(boolean stream, 
1028                                                             byte[] encodedAuthenticatedData,
1029                                                             byte[] message)
1030    throws Exception {
1031    
1032    byte[] receivedMessage;
1033    if (stream) {
1034      
1035      // rsaUser1
1036      System.out.println("\nVerify MAC for rsaUser1:");
1037      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 
1038                                                    message, 
1039                                                    rsaUser1PrivKey_, 
1040                                                    rsaUser1Cert_,
1041                                                    null);
1042      System.out.print("\nContent: ");
1043      System.out.println(new String(receivedMessage));
1044      // rsaUser2
1045      System.out.println("\nVerify MAC for rsaUser2:");
1046      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData,
1047                                                    message,
1048                                                    rsaUser2PrivKey_, 
1049                                                    rsaUser2Cert_,
1050                                                    null);
1051      
1052      // ssdhUser1
1053      System.out.println("\nVerify MAC for ssdhUser1:");
1054      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 
1055                                                    message, 
1056                                                    ssdhUser1PrivKey_, 
1057                                                    ssdhUser1Cert_,
1058                                                    null);
1059      System.out.print("\nContent: ");
1060      System.out.println(new String(receivedMessage));
1061      // ssdhUser2
1062      System.out.println("\nVerify MAC for ssdhUser2:");
1063      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData,
1064                                                    message,
1065                                                    ssdhUser2PrivKey_, 
1066                                                    ssdhUser2Cert_,
1067                                                    null);
1068      // kekUser
1069      System.out.println("\nVerify MAC for kekUser:");
1070      receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData,
1071                                                    message,
1072                                                    kek_, 
1073                                                    null,
1074                                                    kekID_);
1075      
1076      System.out.print("\nContent: ");
1077      System.out.println(new String(receivedMessage));
1078    } else {
1079      // rsaUser1
1080      System.out.println("\nVerify MAC for rsaUser1:");
1081      receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 
1082                                              message, 
1083                                              rsaUser1PrivKey_, 
1084                                              rsaUser1Cert_,
1085                                              null);
1086      System.out.print("\nContent: ");
1087      System.out.println(new String(receivedMessage));
1088      // rsaUser2
1089      System.out.println("\nVerify MAC for rsaUser2:");
1090      receivedMessage = getAuthenticatedData(encodedAuthenticatedData,
1091                                              message,
1092                                              rsaUser2PrivKey_, 
1093                                              rsaUser2Cert_,
1094                                              null);
1095      
1096      // ssdhUser1
1097      System.out.println("\nVerify MAC for ssdhUser1:");
1098      receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 
1099                                              message, 
1100                                              ssdhUser1PrivKey_, 
1101                                              ssdhUser1Cert_,
1102                                              null);
1103      System.out.print("\nContent: ");
1104      System.out.println(new String(receivedMessage));
1105       // ssdhUser2
1106      System.out.println("\nVerify MAC for ssdhUser2:");
1107      receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 
1108                                              message, 
1109                                              ssdhUser2PrivKey_, 
1110                                              ssdhUser2Cert_,
1111                                              null);
1112      // kekUser
1113      System.out.println("\nVerify MAC for kekUser:");
1114      receivedMessage = getAuthenticatedData(encodedAuthenticatedData,
1115                                              message,
1116                                              kek_, 
1117                                              null,
1118                                              kekID_);
1119      
1120      System.out.print("\nContent: ");
1121      System.out.println(new String(receivedMessage));
1122    }    
1123  }
1124  
1125  /**
1126   * Starts the test.
1127   */
1128  public void start() {
1129     // the test message
1130    String m = "This is the test message.";
1131    System.out.println("Test message: \""+m+"\"");
1132    System.out.println();
1133    byte[] message = m.getBytes();
1134
1135    try {
1136      byte[] encodedAuthenticatedData;
1137      
1138      AlgorithmID macAlgorithm = (AlgorithmID)AlgorithmID.hMAC_SHA256.clone();
1139      int macKeyLength = 32;
1140      AlgorithmID digestAlgorithm = (AlgorithmID)AlgorithmID.sha256.clone();
1141      
1142      System.out.println("Stream implementation demos");
1143      System.out.println("===========================");
1144
1145
1146      // the stream implementation
1147      //
1148      // test CMS AuthenticatedDataStream
1149      //
1150      
1151      // implicit mode; with authenticated attributes
1152      System.out.println("\nCMS AuthenticatedDataStream demo with authenticated attributes [create, implicit mode]:\n");
1153      encodedAuthenticatedData = createAuthenticatedDataStream(message,
1154                                                               macAlgorithm,
1155                                                               macKeyLength,
1156                                                               digestAlgorithm,
1157                                                               AuthenticatedDataStream.IMPLICIT);
1158      // transmit data
1159      System.out.println("\nCMS AuthenticatedDataStream demo [parse, implicit mode]:\n");
1160      System.out.println("Decrypt and verify for the several recipients using their index into the recipientInfos field.");
1161      parseAuthenticatedDataWithRecipientInfoIndex(true, encodedAuthenticatedData, null);
1162      System.out.println("Decrypt and verify for the several recipients using their RecipientIdentifier.");
1163      parseAuthenticatedDataWithRecipientIdentifier(true, encodedAuthenticatedData, null);
1164      System.out.println("Decrypt and verify for the several recipients using their certificate or kek.");
1165      parseAuthenticatedDataWithRecipientCertOrKEKId(true, encodedAuthenticatedData, null);
1166      
1167      // implicit mode; without authenticated attributes
1168      System.out.println("\nCMS AuthenticatedDataStream demo without authenticated attributes [create, implicit mode]:\n");
1169      encodedAuthenticatedData = createAuthenticatedDataStream(message,
1170                                                               macAlgorithm,
1171                                                               macKeyLength,
1172                                                               null,
1173                                                               AuthenticatedDataStream.IMPLICIT);
1174      // transmit data
1175      System.out.println("\nCMS AuthenticatedDataStream demo [parse, implicit mode]:\n");
1176      System.out.println("Decrypt and verify for the several recipients using their index into the recipientInfos field.");
1177      parseAuthenticatedDataWithRecipientInfoIndex(true, encodedAuthenticatedData, null);
1178      System.out.println("Decrypt and verify for the several recipients using their RecipientIdentifier.");
1179      parseAuthenticatedDataWithRecipientIdentifier(true, encodedAuthenticatedData, null);
1180      System.out.println("Decrypt and verify for the several recipients using their certificate or kek.");
1181      parseAuthenticatedDataWithRecipientCertOrKEKId(true, encodedAuthenticatedData, null);
1182      
1183  
1184      // explict mode; with authenticated attributes
1185      System.out.println("\nCMS AuthenticatedDataStream demo with authenticated attributes [create, explicit mode]:\n");
1186      encodedAuthenticatedData = createAuthenticatedDataStream(message,
1187                                                               macAlgorithm,
1188                                                               macKeyLength,
1189                                                               digestAlgorithm,
1190                                                               AuthenticatedDataStream.EXPLICIT);
1191      // transmit data
1192      System.out.println("\nCMS AuthenticatedDataStream demo [parse, explicit mode]:\n");
1193      System.out.println("Decrypt and verify for the several recipients using their index into the recipientInfos field.");
1194      parseAuthenticatedDataWithRecipientInfoIndex(true, encodedAuthenticatedData, message);
1195      System.out.println("Decrypt and verify for the several recipients using their RecipientIdentifier.");
1196      parseAuthenticatedDataWithRecipientIdentifier(true, encodedAuthenticatedData, message);
1197      System.out.println("Decrypt and verify for the several recipients using their certificate or kek.");
1198      parseAuthenticatedDataWithRecipientCertOrKEKId(true, encodedAuthenticatedData, message);
1199      
1200      // explict mode; without authenticated attributes
1201      System.out.println("\nCMS AuthenticatedDataStream demo without authenticated attributes [create, explicit mode]:\n");
1202      encodedAuthenticatedData = createAuthenticatedDataStream(message,
1203                                                               macAlgorithm,
1204                                                               macKeyLength,
1205                                                               null,
1206                                                               AuthenticatedDataStream.EXPLICIT);
1207      // transmit data
1208      System.out.println("\nCMS AuthenticatedDataStream demo [parse, explicit mode]:\n");
1209      System.out.println("Decrypt and verify for the several recipients using their index into the recipientInfos field.");
1210      parseAuthenticatedDataWithRecipientInfoIndex(true, encodedAuthenticatedData, message);
1211      System.out.println("Decrypt and verify for the several recipients using their RecipientIdentifier.");
1212      parseAuthenticatedDataWithRecipientIdentifier(true, encodedAuthenticatedData, message);
1213      System.out.println("Decrypt and verify for the several recipients using their certificate or kek.");
1214      parseAuthenticatedDataWithRecipientCertOrKEKId(true, encodedAuthenticatedData, message);
1215      
1216      
1217
1218      // the non-stream implementation
1219      System.out.println("\nNon-stream implementation demos");
1220      System.out.println("===============================");
1221
1222            
1223      //
1224      // test CMS AuthenticatedData
1225      //
1226      
1227      // implict mode; with authenticated attributes
1228      System.out.println("\nCMS AuthenticatedData demo with authenticated attributes [create, implicit mode]:\n");
1229      encodedAuthenticatedData = createAuthenticatedData(message,
1230                                                         macAlgorithm,
1231                                                         macKeyLength,
1232                                                         digestAlgorithm,
1233                                                         AuthenticatedDataStream.IMPLICIT);
1234      // transmit data
1235      System.out.println("\nCMS AuthenticatedData demo [parse]:\n");
1236      System.out.println("Decrypt and verify for the several recipients using their index into the recipientInfos field.");
1237      parseAuthenticatedDataWithRecipientInfoIndex(false, encodedAuthenticatedData, null);
1238      System.out.println("Decrypt and verify for the several recipients using their RecipientIdentifier.");
1239      parseAuthenticatedDataWithRecipientIdentifier(false, encodedAuthenticatedData, null);
1240      System.out.println("Decrypt and verify for the several recipients using their certificate or kek.");
1241      parseAuthenticatedDataWithRecipientCertOrKEKId(false, encodedAuthenticatedData, null);
1242      
1243      // implict mode; without authenticated attributes
1244      System.out.println("\nCMS AuthenticatedData demo without authenticated attributes [create, implicit mode]:\n");
1245      encodedAuthenticatedData = createAuthenticatedData(message,
1246                                                         macAlgorithm,
1247                                                         macKeyLength,
1248                                                         null,
1249                                                         AuthenticatedDataStream.IMPLICIT);
1250      // transmit data
1251      System.out.println("\nCMS AuthenticatedData demo [parse]:\n");
1252      System.out.println("Decrypt and verify for the several recipients using their index into the recipientInfos field.");
1253      parseAuthenticatedDataWithRecipientInfoIndex(false, encodedAuthenticatedData, null);
1254      System.out.println("Decrypt and verify for the several recipients using their RecipientIdentifier.");
1255      parseAuthenticatedDataWithRecipientIdentifier(false, encodedAuthenticatedData, null);
1256      System.out.println("Decrypt and verify for the several recipients using their certificate or kek.");
1257      parseAuthenticatedDataWithRecipientCertOrKEKId(false, encodedAuthenticatedData, null);
1258      
1259      
1260      // explict mode; with authenticated attributes
1261      System.out.println("\nCMS AuthenticatedData demo with authenticated attributes [create, explicit mode]:\n");
1262      encodedAuthenticatedData = createAuthenticatedData(message,
1263                                                         macAlgorithm,
1264                                                         macKeyLength,
1265                                                         digestAlgorithm,
1266                                                         AuthenticatedDataStream.EXPLICIT);
1267      // transmit data
1268      System.out.println("\nCMS AuthenticatedData demo [parse]:\n");
1269      System.out.println("Decrypt and verify for the several recipients using their index into the recipientInfos field.");
1270      parseAuthenticatedDataWithRecipientInfoIndex(false, encodedAuthenticatedData, message);
1271      System.out.println("Decrypt and verify for the several recipients using their RecipientIdentifier.");
1272      parseAuthenticatedDataWithRecipientIdentifier(false, encodedAuthenticatedData, message);
1273      System.out.println("Decrypt and verify for the several recipients using their certificate or kek.");
1274      parseAuthenticatedDataWithRecipientCertOrKEKId(false, encodedAuthenticatedData, message);
1275      
1276      // explict mode; without authenticated attributes
1277      System.out.println("\nCMS AuthenticatedData demo without authenticated attributes [create, explicit mode]:\n");
1278      encodedAuthenticatedData = createAuthenticatedData(message,
1279                                                         macAlgorithm,
1280                                                         macKeyLength,
1281                                                         null,
1282                                                         AuthenticatedDataStream.EXPLICIT);
1283      // transmit data
1284      System.out.println("\nCMS AuthenticatedData demo [parse]:\n");
1285      System.out.println("Decrypt and verify for the several recipients using their index into the recipientInfos field.");
1286      parseAuthenticatedDataWithRecipientInfoIndex(false, encodedAuthenticatedData, message);
1287      System.out.println("Decrypt and verify for the several recipients using their RecipientIdentifier.");
1288      parseAuthenticatedDataWithRecipientIdentifier(false, encodedAuthenticatedData, message);
1289      System.out.println("Decrypt and verify for the several recipients using their certificate or kek.");
1290      parseAuthenticatedDataWithRecipientCertOrKEKId(false, encodedAuthenticatedData, message);
1291      
1292
1293        } catch (Exception ex) {
1294          ex.printStackTrace();
1295          throw new RuntimeException(ex.toString());
1296        }
1297  }
1298  
1299  /**
1300   * Main method.
1301   *
1302   * @throws IOException
1303   *            if an I/O error occurs when reading required keys
1304   *            and certificates from files
1305   */
1306  public static void main(String argv[]) throws Exception {
1307
1308        DemoUtil.initDemos();
1309        (new AuthenticatedDataDemo()).start();
1310    System.out.println("\nReady!");
1311    System.in.read();
1312  }  
1313
1314}