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