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