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/basic/CMSDemo.java 42    12.02.25 17:58 Dbratko $
059    // $Revision: 42 $
060    //
061    
062    package demo.cms.basic;
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.InvalidAlgorithmParameterException;
069    import java.security.InvalidKeyException;
070    import java.security.NoSuchAlgorithmException;
071    import java.security.PrivateKey;
072    import java.security.SignatureException;
073    import java.security.spec.InvalidParameterSpecException;
074    
075    import demo.DemoUtil;
076    import demo.keystore.CMSKeyStore;
077    import iaik.asn1.ObjectID;
078    import iaik.asn1.structures.AlgorithmID;
079    import iaik.asn1.structures.Attribute;
080    import iaik.cms.AuthenticatedData;
081    import iaik.cms.AuthenticatedDataStream;
082    import iaik.cms.CMSException;
083    import iaik.cms.ContentInfo;
084    import iaik.cms.ContentInfoStream;
085    import iaik.cms.Data;
086    import iaik.cms.DataStream;
087    import iaik.cms.DigestedData;
088    import iaik.cms.DigestedDataStream;
089    import iaik.cms.EncryptedContentInfo;
090    import iaik.cms.EncryptedContentInfoStream;
091    import iaik.cms.EncryptedData;
092    import iaik.cms.EncryptedDataStream;
093    import iaik.cms.EnvelopedData;
094    import iaik.cms.EnvelopedDataStream;
095    import iaik.cms.IssuerAndSerialNumber;
096    import iaik.cms.KeyTransRecipientInfo;
097    import iaik.cms.RecipientInfo;
098    import iaik.cms.SignedData;
099    import iaik.cms.SignedDataStream;
100    import iaik.cms.SignerInfo;
101    import iaik.cms.attributes.CMSContentType;
102    import iaik.cms.attributes.SigningTime;
103    import iaik.utils.Util;
104    import iaik.x509.X509Certificate;
105    
106    /**
107     * This class shows some CMS examples where the content types are
108     * wrapped into a ContentInfo.
109     * <p>
110     * All keys and certificates are read from a keystore created by the
111     * SetupCMSKeyStore program.
112     * <p>
113     * This class demonstrates how to wrap the several CMS types into ContentInfos:
114     * <p><ul>
115     * <li>Data
116     * <li>AuthenticatedData
117     * <li>EncryptedData for PBE encrypting the content
118     * <li>EnvelopedData
119     * <li>DigestedData including the message
120     * <li>DigestedData without message
121     * <li>SignedData including the message
122     * <li>SignedData without message
123     * </ul><p>
124     * Additionally, a <i>SignedAndEncryptedData</i> test is performed, which
125     * is a sequential combination of signed and enveloped data content types.
126     * <p>
127     * All sub-tests use the same proceeding: A test message is properly
128     * processed to give the requested content type object, which subsequently
129     * is encoded to be "sent" to some recipient, who parses it for the
130     * inherent structures.
131     */
132    public class CMSDemo {
133    
134      // signing certificate of user 1
135      X509Certificate user1_sign;
136      // signing private key of user 1
137      PrivateKey user1_sign_pk;
138      // signing certificate of user 2
139      X509Certificate user2_sign;
140      // signing private key of user 2
141      PrivateKey user2_sign_pk;
142      
143      // encryption certificate of user 1
144      X509Certificate user1_crypt;
145      // encryption private key of user 1
146      PrivateKey user1_crypt_pk;
147      // encryption certificate of user 2
148      X509Certificate user2_crypt;
149      // encryption private key of user 2
150      PrivateKey user2_crypt_pk;
151      // a certificate chain containing the user certs + CA
152      
153      X509Certificate[] certificates;
154    
155    
156      /**
157       * Setup the demo certificate chains.
158       *
159       * Keys and certificate are retrieved from the demo KeyStore.
160       *
161       * @throws IOException if an file read error occurs
162       */
163      public CMSDemo() throws IOException {
164        
165        System.out.println();
166        System.out.println("***************************************************************************************");
167        System.out.println("*                                 Basic CMS Demo                                      *");
168        System.out.println("*        (shows the usage of the several CMS content type implementations)            *");
169        System.out.println("***************************************************************************************");
170        System.out.println();
171        
172        
173        // signing certs
174        X509Certificate[] certs = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
175        user1_sign = certs[0];
176        user1_sign_pk = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
177        user2_sign = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1)[0];
178        user2_sign_pk = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
179        certificates = new X509Certificate[certs.length+1];
180        System.arraycopy(certs, 0, certificates, 0, certs.length);
181        certificates[certs.length] = user2_sign;
182        
183        // encryption certs
184        user1_crypt = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0];
185        user1_crypt_pk = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1);
186        user2_crypt = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0];
187        user2_crypt_pk = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2);
188    
189      }
190    
191      /**
192       * Creates a CMS <code>Data</code> object and wraps it into a ContentInfo.
193       * <p>
194       * @param message the message to be sent, as byte representation
195       * @return the encoded ContentInfo containing the <code>Data</code> object just created
196       * @throws CMSException if the <code>Data</code> object cannot
197       *                          be created
198       * @throws IOException if an I/O error occurs
199       */
200      public byte[] createDataStream(byte[] message) throws CMSException, IOException  {
201    
202        System.out.println("Create a new Data message:");
203    
204        // we are testing the stream interface
205        ByteArrayInputStream is = new ByteArrayInputStream(message);
206    
207        // create a new Data object which includes the data
208        DataStream data = new DataStream(is, 2048);
209    
210        ContentInfoStream cis = new ContentInfoStream(data);
211        // return the ContentInfo as BER encoded byte array where Data is encoded with block size 2048
212        ByteArrayOutputStream os = new ByteArrayOutputStream();
213        cis.writeTo(os);
214        return os.toByteArray();
215      }
216    
217      /**
218       * Parses a CMS <code>Data</code> object.
219       *
220       * @param data the encoded ContentInfo holding the <code>Data</code>
221       *
222       * @return the inherent message as byte array
223       * @throws CMSException if an parsing exception occurs
224       * @throws IOException if an I/O error occurs
225       */
226      public byte[] getDataStream(byte[] data) throws CMSException, IOException {
227    
228        // we are testing the stream interface
229        ByteArrayInputStream is = new ByteArrayInputStream(data);
230        ContentInfoStream cis = new ContentInfoStream(is);
231        System.out.println("This ContentInfo holds content of type " + cis.getContentType().getName());
232        // create the Data object
233        DataStream dataStream = (DataStream)cis.getContent();
234    
235        // get an InputStream for reading the signed content
236        InputStream content = dataStream.getInputStream();
237        ByteArrayOutputStream os = new ByteArrayOutputStream();
238        Util.copyStream(content, os, null);
239    
240        return os.toByteArray();
241      }
242    
243      /**
244       * Creates a CMS <code>EnvelopedData</code> and wraps it into a ContentInfo.
245       *
246       * @param message the message to be enveloped, as byte representation
247       * @return the encoded ContentInfo containing the EnvelopedData object just created
248       *
249       * @throws CMSException if the <code>EnvelopedData</code> object cannot
250       *                          be created
251       * @throws IOException if an I/O error occurs
252       */
253      public byte[] createEnvelopedDataStream(byte[] message) throws CMSException, IOException {
254    
255        EnvelopedDataStream enveloped_data;
256    
257        // we are testing the stream interface
258        ByteArrayInputStream is = new ByteArrayInputStream(message);
259        // create a new EnvelopedData object encrypted with TripleDES CBC
260        try {
261          enveloped_data = new EnvelopedDataStream(is, (AlgorithmID)AlgorithmID.aes256_CBC.clone());
262        } catch (NoSuchAlgorithmException ex) {
263          throw new CMSException(ex.toString());
264        }
265    
266        // create the recipient infos
267        RecipientInfo[] recipients = new RecipientInfo[2];
268        // user1 is the first receiver
269        recipients[0] = new KeyTransRecipientInfo(user1_crypt, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
270        // user2 is the second receiver
271        recipients[1] = new KeyTransRecipientInfo(user2_crypt, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
272    
273        // specify the recipients of the encrypted message
274        enveloped_data.setRecipientInfos(recipients);
275    
276        // return the EnvelopedDate as DER encoded byte array with block size 2048
277        ByteArrayOutputStream os = new ByteArrayOutputStream();
278        enveloped_data.setBlockSize(2048);
279        ContentInfoStream cis = new ContentInfoStream(enveloped_data);
280        cis.writeTo(os);
281        return os.toByteArray();
282      }
283    
284      /**
285       * Decrypts the encrypted content of the given EnvelopedData object for the
286       * specified recipient and returns the decrypted (= original) message.
287       *
288       * @param encoding the encoded ContentInfo containing an EnvelopedData object
289       * @param privateKey the private key to decrypt the message
290       * @param recipientInfoIndex the index into the <code>RecipientInfo</code> array
291       *                           to which the specified private key belongs
292       *
293       * @return the recovered message, as byte array
294       * @throws CMSException if the message cannot be recovered
295       * @throws IOException if an I/O error occurs
296       */
297      public byte[] getEnvelopedDataStream(byte[] encoding, PrivateKey privateKey, int recipientInfoIndex) throws CMSException, IOException {
298    
299        // create the EnvelopedData object from a DER encoded byte array
300        // we are testing the stream interface
301        ByteArrayInputStream is = new ByteArrayInputStream(encoding);
302        ContentInfoStream cis = new ContentInfoStream(is);
303        EnvelopedDataStream enveloped_data = (EnvelopedDataStream)cis.getContent();
304    
305        System.out.println("Information about the encrypted data:");
306        EncryptedContentInfoStream eci = (EncryptedContentInfoStream)enveloped_data.getEncryptedContentInfo();
307        System.out.println("Content type: "+eci.getContentType().getName());
308        System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
309    
310        System.out.println("\nThis message can be decrypted by the owners of the following certificates:");
311        RecipientInfo[] recipients = enveloped_data.getRecipientInfos();
312        for (int i=0; i<recipients.length; i++) {
313          System.out.println("Recipient "+(i+1)+":");
314          System.out.println(recipients[i].getRecipientIdentifiers()[0]);
315        }
316    
317        // decrypt the message
318        try {
319          enveloped_data.setupCipher(privateKey, recipientInfoIndex);
320          InputStream decrypted = enveloped_data.getInputStream();
321          ByteArrayOutputStream os = new ByteArrayOutputStream();
322          Util.copyStream(decrypted, os, null);
323    
324          return os.toByteArray();
325    
326        } catch (InvalidKeyException ex) {
327          throw new CMSException("Private key error: "+ex.toString());
328        } catch (NoSuchAlgorithmException ex) {
329          throw new CMSException("Content encryption algorithm not implemented: "+ex.toString());
330        }
331      }
332    
333      /**
334       * Creates a CMS <code>SignedData</code> object ans wraps it into a ContentInfo.
335       * <p>
336       *
337       * @param message the message to be signed, as byte representation
338       * @param mode the mode indicating whether to include the content 
339       *        (SignedDataStream.IMPLICIT) or not (SignedDataStream.EXPLICIT)
340       * @return the encoding of the ContentInfo holding the <code>SignedData</code> object just created
341       * @throws CMSException if the <code>SignedData</code> object cannot
342       *                          be created
343       * @throws IOException if an I/O error occurs
344       */
345      public byte[] createSignedDataStream(byte[] message, int mode) throws CMSException, IOException  {
346    
347        System.out.println("Create a new message signed by user 1:");
348    
349        // we are testing the stream interface
350        ByteArrayInputStream is = new ByteArrayInputStream(message);
351        // create a new SignedData object which includes the data
352        SignedDataStream signed_data = new SignedDataStream(is, mode);
353        // SignedData shall include the certificate chain for verifying
354        signed_data.setCertificates(certificates);
355    
356        // cert at index 0 is the user certificate
357        IssuerAndSerialNumber issuer = new IssuerAndSerialNumber(user1_sign);
358    
359        // create a new SignerInfo
360        SignerInfo signer_info = new SignerInfo(issuer, (AlgorithmID)AlgorithmID.sha256.clone(), AlgorithmID.sha256WithRSAEncryption, user1_sign_pk);
361        
362        // create some signed attributes
363        // the message digest attribute is automatically added
364        Attribute[] attributes = new Attribute[2];
365        try {
366          // content type is data
367          CMSContentType contentType = new CMSContentType(ObjectID.cms_data);
368          attributes[0] = new Attribute(contentType);
369          // signing time is now
370          SigningTime signingTime = new SigningTime();
371          attributes[1] = new Attribute(signingTime);
372        } catch (Exception ex) {
373          throw new CMSException("Error creating attribute: " + ex.toString());   
374        }    
375        
376        // set the attributes
377        signer_info.setSignedAttributes(attributes);
378        // finish the creation of SignerInfo by calling method addSigner
379        try {
380          signed_data.addSignerInfo(signer_info);
381    
382          // another SignerInfo without authenticated attributes 
383          signer_info = new SignerInfo(new IssuerAndSerialNumber(user2_sign),
384              (AlgorithmID)AlgorithmID.sha256.clone(), user2_sign_pk);
385          // the message digest itself is protected
386          signed_data.addSignerInfo(signer_info);
387    
388        } catch (NoSuchAlgorithmException ex) {
389          throw new CMSException("No implementation for signature algorithm: "+ex.getMessage());
390        }
391        // ensure block encoding
392        signed_data.setBlockSize(2048);
393    
394        // write the data through SignedData to any out-of-band place
395        if (mode == SignedDataStream.EXPLICIT) {
396          InputStream data_is = signed_data.getInputStream();
397          byte[] buf = new byte[1024];
398          int r;
399          while ((r = data_is.read(buf)) > 0) {
400            ;   // skip data
401          }   
402        }
403    
404        // create the ContentInfo
405        ContentInfoStream cis = new ContentInfoStream(signed_data);
406        // return the SignedData as encoded byte array with block size 2048
407        ByteArrayOutputStream os = new ByteArrayOutputStream();
408    
409        cis.writeTo(os);
410        return os.toByteArray();
411      }
412    
413      /**
414       * Parses a CMS <code>SignedData</code> object and verifies the signatures
415       * for all participated signers.
416       *
417       * @param signedData the ContentInfo with inherent SignedData, as BER encoded byte array
418       * @param message the the message which was transmitted out-of-band (explicit signed)
419       *
420       * @return the inherent message as byte array, or <code>null</code> if there
421       *         is no message included into the supplied <code>SignedData</code>
422       *         object
423       * @throws CMSException if any signature does not verify
424       * @throws IOException if an I/O error occurs
425       */
426      public byte[] getSignedDataStream(byte[] signedData, byte[] message) throws CMSException, IOException {
427    
428        // we are testing the stream interface
429        ByteArrayInputStream is = new ByteArrayInputStream(signedData);
430        // create the ContentInfo object
431        SignedDataStream signed_data = new SignedDataStream(is);
432    
433        if (signed_data.getMode() == SignedDataStream.EXPLICIT) {
434          // explicitly signed; set the content received by other means
435          signed_data.setInputStream(new ByteArrayInputStream(message));
436        }
437        
438        // get an InputStream for reading the signed content
439        InputStream data = signed_data.getInputStream();
440        ByteArrayOutputStream os = new ByteArrayOutputStream();
441        Util.copyStream(data, os, null);
442    
443        System.out.println("SignedData contains the following signer information:");
444        SignerInfo[] signer_infos = signed_data.getSignerInfos();
445        int numberOfSignerInfos = signer_infos.length;
446        if (numberOfSignerInfos == 0) {
447          String warning = "Warning: Unsigned message (no SignerInfo included)!";  
448          System.err.println(warning);
449          throw new CMSException(warning);
450        } else {
451          for (int i = 0; i < numberOfSignerInfos; i++) {
452            try {
453              // verify the signed data using the SignerInfo at index i
454              X509Certificate signer_cert = signed_data.verify(i);
455              // if the signature is OK the certificate of the signer is returned
456              System.out.println("Signature OK from signer: "+signer_cert.getSubjectDN());
457              // get signed attributes
458              SigningTime signingTime = (SigningTime)signer_infos[i].getSignedAttributeValue(ObjectID.signingTime);
459              if (signingTime != null) {
460                System.out.println("This message has been signed at " + signingTime.get());
461              } 
462              CMSContentType contentType = (CMSContentType)signer_infos[i].getSignedAttributeValue(ObjectID.contentType);
463              if (contentType != null) {
464                System.out.println("The content has CMS content type " + contentType.get().getName());
465              }
466      
467            } catch (SignatureException ex) {
468              // if the signature is not OK a SignatureException is thrown
469              System.out.println("Signature ERROR from signer: "+signed_data.getCertificate((signer_infos[i].getSignerIdentifier())).getSubjectDN());
470              throw new CMSException(ex.toString());
471            } 
472          }
473          // now check alternative signature verification
474          System.out.println("Now check the signature assuming that no certs have been included:");
475          try {
476             SignerInfo signer_info = signed_data.verify(user1_sign);
477              // if the signature is OK the certificate of the signer is returned
478              System.out.println("Signature OK from signer: "+signed_data.getCertificate(signer_info.getSignerIdentifier()).getSubjectDN());
479      
480          } catch (SignatureException ex) {
481              // if the signature is not OK a SignatureException is thrown
482              System.out.println("Signature ERROR from signer: "+user1_sign.getSubjectDN());
483              throw new CMSException(ex.toString());
484          }
485      
486          try {
487             SignerInfo signer_info = signed_data.verify(user2_sign);
488              // if the signature is OK the certificate of the signer is returned
489              System.out.println("Signature OK from signer: "+signed_data.getCertificate(signer_info.getSignerIdentifier()).getSubjectDN());
490      
491          } catch (SignatureException ex) {
492              // if the signature is not OK a SignatureException is thrown
493              System.out.println("Signature ERROR from signer: "+user2_sign.getSubjectDN());
494              throw new CMSException(ex.toString());
495          }
496          
497          // in practice we also would validate the signer certificate(s)
498        }
499    
500        return os.toByteArray();
501      }
502    
503      
504      /**
505       * Creates a <i>SignedAndEncrypted</i> (i.e. sequential combination of <code>
506       * SignedData</code> and <code>EnvelopedData</code>). 
507       *
508       * @param message the message to be signed and encrypted, as byte representation
509       * @return the encoded ContentInfo holding the signed and encrypted message object
510       *         just created
511       * @throws CMSException if the the <code>SignedData</code> or
512       *                          <code>EnvelopedData</code> object cannot be created
513       * @throws IOException if an I/O error occurs
514       */
515      public byte[] createSignedAndEncryptedDataStream(byte[] message) throws CMSException, IOException {
516    
517        System.out.println("Create a new message signed by user1 encrypted for user2:");
518    
519        byte[] signed = createSignedDataStream(message, SignedData.IMPLICIT);
520        return createEnvelopedDataStream(signed);
521      }
522    
523      /**
524       * Recovers the original message and verifies the signature.
525       *
526       * @param in the encoded CMS object
527       * @return the recovered message, as byte array
528       * @throws CMSException if the message cannot be recovered
529       * @throws IOException if an I/O error occurs
530       */
531      public byte[] getSignedAndEncryptedDataStream(byte[] in) throws CMSException, IOException {
532    
533        // user2 means index 2 (hardcoded for this demo)
534        byte[] signed = getEnvelopedDataStream(in, user2_crypt_pk, 1);
535        return getSignedDataStream(signed, null);
536      }
537    
538    
539       /**
540       * Creates a CMS <code>DigestedData</code> object.
541       * <p>
542       * @param message the message to be digested, as byte representation
543       * @return the encoded ContentInfo containing the DigestedData object just created
544       * @throws CMSException if the <code>DigestedData</code> object cannot
545       *                          be created
546       * @throws IOException if an I/O error occurs
547       */
548      public byte[] createDigestedDataStream(byte[] message, int mode) throws CMSException, IOException  {
549    
550        System.out.println("Create a new message to be digested:");
551    
552        // we are testing the stream interface
553        ByteArrayInputStream is = new ByteArrayInputStream(message);
554    
555        // create a new DigestedData object which includes the data
556        DigestedDataStream digested_data = null;
557    
558        digested_data = new DigestedDataStream(is, (AlgorithmID)AlgorithmID.sha256.clone(), mode);
559        digested_data.setBlockSize(2048);
560    
561        // write the data through DigestedData to any out-of-band place
562        if (mode == DigestedDataStream.EXPLICIT) {
563          InputStream data_is = digested_data.getInputStream();
564          byte[] buf = new byte[1024];
565          int r;
566          while ((r = data_is.read(buf)) > 0) {
567            ;   // skip data
568          }
569        }
570    
571        // wrap into ContentInfo and encode
572        ByteArrayOutputStream os = new ByteArrayOutputStream();
573        ContentInfoStream cis = new ContentInfoStream(digested_data);
574        cis.writeTo(os);
575        return os.toByteArray();
576      }
577    
578      /**
579       * Parses a CMS <code>DigestedData</code> object and verifies the hash.
580       *
581       * @param digestedData the encoded ContentInfo holding a DigestedData object
582       * @param message the the message which was transmitted out-of-band
583       *
584       * @return the inherent message as byte array, or <code>null</code> if there
585       *         is no message included into the supplied <code>DigestedData</code>
586       *         object
587       * @throws CMSException if any signature does not verify
588       * @throws IOException if an I/O error occurs
589       */
590      public byte[] getDigestedDataStream(byte[] digestedData, byte[] message) throws CMSException, IOException {
591    
592        // we are testing the stream interface
593        ByteArrayInputStream is = new ByteArrayInputStream(digestedData);
594        // create the DigestedData object
595        DigestedDataStream digested_data = new DigestedDataStream(is);
596        if (digested_data.getMode() == DigestedDataStream.EXPLICIT) {
597          digested_data.setInputStream(new ByteArrayInputStream(message));
598        }
599    
600        // get an InputStream for reading the signed content
601        InputStream data = digested_data.getInputStream();
602        ByteArrayOutputStream os = new ByteArrayOutputStream();
603        Util.copyStream(data, os, null);
604    
605        if (digested_data.verify()) {
606          System.out.println("Hash ok!");
607        } else {
608          throw new CMSException("Hash verification failed!");
609        }
610    
611        return os.toByteArray();
612      }
613    
614      /**
615       * Creates a CMS <code>EncryptedDataStream</code> message.
616       * <p>
617       * The supplied content is PBE-encrypted using the specified password.
618       *
619       * @param message the message to be encrypted, as byte representation
620       * @param pbeAlgorithm the PBE algorithm to be used
621       * @param password the password
622       * @return the DER encoding of the ContentInfo holding the <code>EncryptedData</code> object just created
623       * @throws CMSException if the <code>EncryptedData</code> object cannot
624       *                          be created
625       * @throws IOException if an I/O error occurs
626       */
627      public byte[] createEncryptedDataStream(byte[] message, AlgorithmID pbeAlgorithm, char[] password) throws CMSException, IOException {
628    
629        EncryptedDataStream encrypted_data;
630    
631        // we are testing the stream interface
632        ByteArrayInputStream is = new ByteArrayInputStream(message);
633       
634        try {
635          encrypted_data = new EncryptedDataStream(is, 2048);
636          encrypted_data.setupCipher(pbeAlgorithm, password);
637        } catch (InvalidKeyException ex) {
638          throw new CMSException("Key error: "+ex.toString());
639        } catch (NoSuchAlgorithmException ex) {
640          throw new CMSException("Content encryption algorithm not implemented: "+ex.toString());
641        }
642    
643        // wrap into ContentInfo and encode
644        ByteArrayOutputStream os = new ByteArrayOutputStream();
645        ContentInfoStream cis = new ContentInfoStream(encrypted_data);
646        cis.writeTo(os);
647        return os.toByteArray();
648      }
649    
650      /**
651       * Decrypts the PBE-encrypted content of the given <code>EncryptedData</code> object
652       * using the specified password and returns the decrypted (= original) message.
653       *
654       * @param encoding the encoded ContentInfo holding an <code>EncryptedData</code> object
655       * @param password the password to decrypt the message
656       *
657       * @return the recovered message, as byte array
658       * @throws CMSException if the message cannot be recovered
659       * @throws IOException if an I/O error occurs
660       */
661      public byte[] getEncryptedDataStream(byte[] encoding, char[] password) throws CMSException, IOException {
662    
663        // create the EncryptpedData object from a DER encoded byte array
664        // we are testing the stream interface
665        ByteArrayInputStream is = new ByteArrayInputStream(encoding);
666         // create the ContentInfo
667        ContentInfoStream cis = new ContentInfoStream(is);
668    
669        EncryptedDataStream encrypted_data = (EncryptedDataStream)cis.getContent();
670    
671        System.out.println("Information about the encrypted data:");
672        EncryptedContentInfoStream eci = encrypted_data.getEncryptedContentInfo();
673        System.out.println("Content type: "+eci.getContentType().getName());
674        System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
675    
676        // decrypt the message
677        try {
678          encrypted_data.setupCipher(password);
679          InputStream decrypted = encrypted_data.getInputStream();
680          ByteArrayOutputStream os = new ByteArrayOutputStream();
681          Util.copyStream(decrypted, os, null);
682    
683          return os.toByteArray();
684    
685        } catch (InvalidKeyException ex) {
686          throw new CMSException("Key error: "+ex.toString());
687        } catch (NoSuchAlgorithmException ex) {
688          throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
689        } catch (InvalidAlgorithmParameterException ex) {
690          throw new CMSException("Invalid Parameters: "+ex.getMessage());
691        } catch (InvalidParameterSpecException ex) {
692          throw new CMSException("Invalid Parameters: "+ex.getMessage());
693        }
694      }
695      
696      /**
697       * Creates a CMS <code>AuthenticatedDataStream</code> for the given message message.
698       * <p>
699       * <b>Attention:</b> This AuthenticatedData demo uses RSA as key management technique.
700       * In practice (see RFC 5652) a key management technique that provides data origin
701       * authentication should be used like, for instance, Static-Static Diffie-Hellman when
702       * both the originator and recipient public keys are bound to appropriate identities 
703       * in X.509 certificates, see, for instance, {@link demo.cms.authenticatedData.AuthenticatedDataDemo
704       * AuthenticatedDataDemo}.
705       *
706       * @param message the message to be authenticated, as byte representation
707       * @param includeAuthAttrs whether to include authenticated attributes
708       * @param mode the mode indicating whether to include the content 
709       *        (AuthenticatedDataStream.IMPLICIT) or not (AuthenticatedDataStream.EXPLICIT)
710       * @return the BER encoding of the <code>AuthenticatedData</code> object, wrapped in a ContentInfo
711       * @throws CMSException if the <code>AuthenticatedData</code> object cannot
712       *                         be created
713       * @throws IOException if an I/O error occurs
714       */
715      public byte[] createAuthenticatedDataStream(byte[] message,
716                                                  boolean includeAuthAttrs,
717                                                  int mode)
718        throws CMSException, IOException {
719        
720        AlgorithmID macAlgorithm = (AlgorithmID)AlgorithmID.hMAC_SHA256.clone();
721        int macKeyLength = 32;
722        AlgorithmID digestAlgorithm = null;
723        // we need a digest algorithm if authenticated attributes shall be included
724        if (includeAuthAttrs == true) {
725          digestAlgorithm = (AlgorithmID)AlgorithmID.sha256.clone();
726        }   
727        ObjectID contentType = ObjectID.cms_data;
728        
729        AuthenticatedDataStream authenticatedData;
730    
731        // we are testing the stream interface
732        ByteArrayInputStream is = new ByteArrayInputStream(message);
733        // create a new AuthenticatedData object 
734        try {
735          authenticatedData = new AuthenticatedDataStream(contentType,
736                                                          is, 
737                                                          macAlgorithm,
738                                                          macKeyLength,
739                                                          null,
740                                                          digestAlgorithm,
741                                                          mode);
742        } catch (NoSuchAlgorithmException ex) {
743          throw new CMSException(ex.toString());
744        }
745    
746        // create the recipient infos
747        RecipientInfo[] recipients = new RecipientInfo[2];
748        // user1 is the first receiver
749        recipients[0] = new KeyTransRecipientInfo(user1_crypt, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
750        // user2 is the second receiver
751        recipients[1] = new KeyTransRecipientInfo(user2_crypt, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
752        // specify the recipients of the authenticated message
753        authenticatedData.setRecipientInfos(recipients);
754        
755        if (includeAuthAttrs == true) {
756           // create some autheticated attributes
757           // (the message digest attribute is automatically added)
758           try {
759             Attribute[] attributes = { new Attribute(new CMSContentType(contentType)) };
760             authenticatedData.setAuthenticatedAttributes(attributes);
761           } catch (Exception ex) {
762             throw new CMSException("Error creating attribute: " + ex.toString());   
763           } 
764        }    
765        
766        // in explicit mode get the content and write it  to any out-of-band place
767        if (mode == AuthenticatedDataStream.EXPLICIT) {
768          InputStream data_is = authenticatedData.getInputStream();
769          byte[] buf = new byte[1024];
770          int r;
771          while ((r = data_is.read(buf)) > 0) {
772            ;   // skip data
773          }
774        }    
775        
776        // create the ContentInfo
777        ContentInfoStream cis = new ContentInfoStream(authenticatedData);
778        // return the AuthenticatedData as encoded byte array with block size 2048
779        ByteArrayOutputStream os = new ByteArrayOutputStream();
780    
781        cis.writeTo(os);
782        return os.toByteArray();  
783      }
784      
785      /**
786       * Decrypts the encrypted MAC key for the recipient identified by its index
787       * into the recipientInfos field and uses the MAC key to verify
788       * the authenticated data.
789       * <p>
790       * This way of decrypting the MAC key and verifying the content may be used for 
791       * any type of RecipientInfo (KeyTransRecipientInfo, KeyAgreeRecipientInfo, 
792       * KEKRecipientInfo), but requires to know at what index of the recipientInfos
793       * field the RecipientInfo for the particular recipient in mind can be found. 
794       * If the recipient in mind uses a RecipientInfo of type KeyAgreeRecipientInfo
795       * some processing overhead may take place because a KeyAgreeRecipientInfo may
796       * contain encrypted mac keys for more than only one recipient; since the
797       * recipientInfoIndex only specifies the RecipientInfo but not the encrypted
798       * mac key -- if there are more than only one -- repeated decryption runs may be
799       * required as long as the decryption process completes successfully.
800       * <p>
801       * <b>Attention:</b> This AuthenticatedData demo uses RSA as key management technique.
802       * In practice (see RFC 5652) a key management technique that provides data origin
803       * authentication should be used like, for instance, Static-Static Diffie-Hellman when
804       * both the originator and recipient public keys are bound to appropriate identities 
805       * in X.509 certificates, see, for instance, {@link demo.cms.authenticatedData.AuthenticatedDataDemo
806       * AuthenticatedDataDemo}.
807       *
808       * @param encoding the BER encoded ContentInfo holding the <code>AuthenticatedData</code> object
809       * @param message the content message, if transmitted by other means (explicit mode)
810       * @param key the key to decrypt the mac key 
811       * @param recipientInfoIndex the index of the right <code>RecipientInfo</code> to 
812       *                           which the given key belongs
813       *
814       * @return the verified message, as byte array
815       * @throws CMSException if the authenticated data cannot be verified
816       * @throws IOException if a stream read/write error occurs
817       */
818      public byte[] getAuthenticatedDataStream(byte[] encoding, 
819                                               byte[] message, 
820                                               PrivateKey key, 
821                                               int recipientInfoIndex)
822        throws CMSException, IOException {
823    
824        // create the AuthenticatedData object from a DER encoded byte array
825        // we are testing the stream interface
826        ByteArrayInputStream is = new ByteArrayInputStream(encoding);
827        // create the ContentInfo object
828        ContentInfoStream cis = new ContentInfoStream(is);
829        System.out.println("This ContentInfo holds content of type " + cis.getContentType().getName());
830        AuthenticatedDataStream authenticatedData = (AuthenticatedDataStream)cis.getContent();
831        
832        if (authenticatedData.getMode() == AuthenticatedDataStream.EXPLICIT) {
833          // in explicit mode explicitly supply the content for hash/mac computation  
834          authenticatedData.setInputStream(new ByteArrayInputStream(message));
835        }
836    
837        System.out.println("\nThis message can be verified by the following recipients:");
838        RecipientInfo[] recipients = authenticatedData.getRecipientInfos();
839        for (int i=0; i<recipients.length; i++) {
840          System.out.println("Recipient "+(i+1)+":");
841          System.out.println(recipients[i].getRecipientIdentifiers()[0]);
842        }
843    
844        // decrypt the mac key and verify the mac for indented recipient
845        try {
846          authenticatedData.setupMac(key, recipientInfoIndex);
847          InputStream contentStream = authenticatedData.getInputStream();
848          ByteArrayOutputStream os = new ByteArrayOutputStream();
849          Util.copyStream(contentStream, os, null);
850          
851          if (authenticatedData.verifyMac() == false) {
852            throw new CMSException("Mac verification error!");
853          }  
854          System.out.println("Mac successfully verified!");
855          
856          return os.toByteArray();
857    
858        } catch (InvalidKeyException ex) {
859          throw new CMSException("Key error: "+ex.getMessage());
860        } catch (NoSuchAlgorithmException ex) {
861          throw new CMSException(ex.toString());
862        }
863      }
864    
865    
866    
867      /**
868       * Creates a CMS <code>Data</code> object.
869       * <p>
870       * @param message the message to be sent, as byte representation
871       * @return the DER encoded ContentInfo holding the <code>Data</code> object just created
872       * @throws CMSException if the <code>Data</code> object cannot
873       *                          be created
874       */
875      public byte[] createData(byte[] message) throws CMSException  {
876    
877        System.out.println("Create a new Data message:");
878    
879        // create a new DigestedData object which includes the data
880        Data data = new Data(message);
881        ContentInfo ci = new ContentInfo(data);
882        // return the ASN.1 representation
883        return ci.toByteArray();
884      }
885    
886      /**
887       * Parses a CMS <code>Data</code> object.
888       *
889       * @param encoding the DER encoded ContentInfo holding with inherent <code>Data</code>
890       *
891       * @return the inherent message as byte array
892       *
893       * @throws CMSException if an parsing exception occurs
894       * @throws IOException if an I/O related error occurs
895       */
896      public byte[] getData(byte[] encoding) throws CMSException, IOException {
897        
898        ByteArrayInputStream encodedStream = new ByteArrayInputStream(encoding);
899        // create the ContentInfo
900        ContentInfo ci = new ContentInfo(encodedStream);
901        System.out.println("This ContentInfo holds content of type " + ci.getContentType().getName());
902        // create the Data object
903        Data data = (Data)ci.getContent();
904        
905        // get and return the content
906        return data.getData();
907      }
908    
909      /**
910       * Creates a CMS <code>EnvelopedData</code> message and wraps it into a ContentInfo.
911       * <p>
912       *
913       * @param message the message to be enveloped, as byte representation
914       * @return the DER encoded ContentInfo holding the EnvelopedData object just created
915       * @throws CMSException if the <code>EnvelopedData</code> object cannot
916       *                          be created
917       */
918      public byte[] createEnvelopedData(byte[] message) throws CMSException {
919    
920        EnvelopedData enveloped_data;
921    
922        // create a new EnvelopedData object encrypted with TripleDES CBC
923        try {
924          enveloped_data = new EnvelopedData(message, (AlgorithmID)AlgorithmID.aes256_CBC.clone());
925        } catch (NoSuchAlgorithmException ex) {
926          throw new CMSException(ex.toString());
927        }
928    
929        // create the recipient infos
930        RecipientInfo[] recipients = new RecipientInfo[2];
931        // user1 is the first receiver
932        recipients[0] = new KeyTransRecipientInfo(user1_crypt, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
933        // user2 is the second receiver
934        recipients[1] = new KeyTransRecipientInfo(user2_crypt, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
935        // specify the recipients of the encrypted message
936        enveloped_data.setRecipientInfos(recipients);
937        
938        // wrap into contentInfo
939        ContentInfo ci = new ContentInfo(enveloped_data);
940        // return the EnvelopedDate as DER encoded byte array
941        return ci.toByteArray();
942      }
943    
944      /**
945       * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for the
946       * specified recipient and returns the decrypted (= original) message.
947       *
948       * @param encoding the DER encoded ContentInfo holding an EnvelopedData
949       * @param privateKey the private key to decrypt the message
950       * @param recipientInfoIndex the index into the <code>RecipientInfo</code> array
951       *                           to which the specified private key belongs
952       *
953       * @return the recovered message, as byte array
954       * @throws CMSException if the message cannot be recovered
955       */
956      public byte[] getEnvelopedData(byte[] encoding, PrivateKey privateKey, int recipientInfoIndex) throws CMSException, IOException {
957        
958        ByteArrayInputStream encodedStream = new ByteArrayInputStream(encoding);
959        ContentInfo ci = new ContentInfo(encodedStream);
960        EnvelopedData enveloped_data = (EnvelopedData)ci.getContent();
961    
962        System.out.println("Information about the encrypted data:");
963        EncryptedContentInfo eci = (EncryptedContentInfo)enveloped_data.getEncryptedContentInfo();
964        System.out.println("Content type: "+eci.getContentType().getName());
965        System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
966    
967        System.out.println("\nThis message can be decrypted by the owners of the following certificates:");
968        RecipientInfo[] recipients = enveloped_data.getRecipientInfos();
969        for (int i=0; i<recipients.length; i++) {
970          System.out.println("Recipient "+(i+1)+":");
971          System.out.println(recipients[i].getRecipientIdentifiers()[0]);
972        }
973    
974        // decrypt the message
975        try {
976          enveloped_data.setupCipher(privateKey, recipientInfoIndex);
977          return enveloped_data.getContent();
978    
979        } catch (InvalidKeyException ex) {
980          throw new CMSException("Private key error: "+ex.toString());
981        } catch (NoSuchAlgorithmException ex) {
982          throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
983        }
984      }
985    
986      /**
987       * Creates a CMS <code>SignedData</code> object and wraps it into a ContentInfo.
988       *
989       * @param message the message to be signed, as byte representation
990       * @param mode the mode indicating whether to include the content 
991       *        (SignedDataStream.IMPLICIT) or not (SignedDataStream.EXPLICIT)
992       * @return the DER encoded ContentInfo holding the <code>SignedData</code> object just created
993       * @throws CMSException if the <code>SignedData</code> object cannot
994       *                          be created
995       */
996      public byte[] createSignedData(byte[] message, int mode) throws CMSException  {
997    
998        System.out.println("Create a new message signed by user 1:");
999    
1000        // create a new SignedData object which includes the data
1001        SignedData signed_data = new SignedData(message, mode);
1002        // SignedData shall include the certificate chain for verifying
1003        signed_data.setCertificates(certificates);
1004    
1005        // cert at index 0 is the user certificate
1006        IssuerAndSerialNumber issuer = new IssuerAndSerialNumber(user1_sign);
1007    
1008        // create a new SignerInfo
1009        SignerInfo signer_info = new SignerInfo(issuer, (AlgorithmID)AlgorithmID.sha256.clone(), user1_sign_pk);
1010        
1011        // create some signed attributes
1012        // the message digest attribute is automatically added
1013        Attribute[] attributes = new Attribute[2];
1014        try {
1015          // content type is data
1016          CMSContentType contentType = new CMSContentType(ObjectID.cms_data);
1017          attributes[0] = new Attribute(contentType);
1018          // signing time is now
1019          SigningTime signingTime = new SigningTime();
1020          attributes[1] = new Attribute(signingTime);
1021        } catch (Exception ex) {
1022          throw new CMSException("Error creating attribute: " + ex.toString());   
1023        }
1024        
1025        // set the attributes
1026        signer_info.setSignedAttributes(attributes);
1027        // finish the creation of SignerInfo by calling method addSigner
1028        try {
1029          signed_data.addSignerInfo(signer_info);
1030    
1031          // another SignerInfo without authenticated attributes 
1032          signer_info = new SignerInfo(new IssuerAndSerialNumber(user2_sign),
1033              (AlgorithmID)AlgorithmID.sha256.clone(), user2_sign_pk);
1034          // the message digest itself is protected
1035          signed_data.addSignerInfo(signer_info);
1036    
1037        } catch (NoSuchAlgorithmException ex) {
1038          throw new CMSException("No implementation for signature algorithm: "+ex.getMessage());
1039        }
1040    
1041        ContentInfo ci = new ContentInfo(signed_data);
1042        return ci.toByteArray();
1043      }
1044    
1045      /**
1046       * Parses a CMS <code>SignedData</code> object and verifies the signatures
1047       * for all participated signers.
1048       *
1049       * @param encoding the ContentInfo with inherent <code>SignedData</code> object, as DER encoding
1050       * @param message the the message which was transmitted out-of-band (explicit signed)
1051       *
1052       * @return the inherent message as byte array, or <code>null</code> if there
1053       *         is no message included into the supplied <code>SignedData</code>
1054       *         object
1055       * @throws CMSException if any signature does not verify
1056       * @throws IOException if an I/O error occurs
1057       */
1058      public byte[] getSignedData(byte[] encoding, byte[] message) throws CMSException, IOException {
1059        
1060        ByteArrayInputStream encodedStream = new ByteArrayInputStream(encoding);
1061        // create a content info from the ASN.1 object
1062        SignedData signed_data = new SignedData(encodedStream);
1063        
1064        if (signed_data.getMode() == SignedData.EXPLICIT) {
1065          // explicit mode: set content received by other means
1066          signed_data.setContent(message);
1067        }
1068    
1069        System.out.println("SignedData contains the following signer information:");
1070        SignerInfo[] signer_infos = signed_data.getSignerInfos();
1071    
1072        int numberOfSignerInfos = signer_infos.length;
1073        if (numberOfSignerInfos == 0) {
1074          String warning = "Warning: Unsigned message (no SignerInfo included)!";  
1075          System.err.println(warning);
1076          throw new CMSException(warning);
1077        } else {
1078          for (int i = 0; i < numberOfSignerInfos; i++) {
1079            try {
1080              // verify the signed data using the SignerInfo at index i
1081              X509Certificate signer_cert = signed_data.verify(i);
1082              // if the signature is OK the certificate of the signer is returned
1083              System.out.println("Signature OK from signer: "+signer_cert.getSubjectDN());
1084              // get signed attributes
1085              SigningTime signingTime = (SigningTime)signer_infos[i].getSignedAttributeValue(ObjectID.signingTime);
1086              if (signingTime != null) {
1087                System.out.println("This message has been signed at " + signingTime.get());
1088              } 
1089              CMSContentType contentType = (CMSContentType)signer_infos[i].getSignedAttributeValue(ObjectID.contentType);
1090              if (contentType != null) {
1091                System.out.println("The content has CMS content type " + contentType.get().getName());
1092              }
1093            } catch (SignatureException ex) {
1094               // if the signature is not OK a SignatureException is thrown
1095               System.out.println("Signature ERROR from signer: "+signed_data.getCertificate(signer_infos[i].getSignerIdentifier()).getSubjectDN());
1096               throw new CMSException(ex.toString());
1097            } 
1098          }
1099    
1100          // now check alternative signature verification
1101          System.out.println("Now check the signature assuming that no certs have been included:");
1102          try {
1103             SignerInfo signer_info = signed_data.verify(user1_sign);
1104              // if the signature is OK the certificate of the signer is returned
1105              System.out.println("Signature OK from signer: "+signed_data.getCertificate(signer_info.getSignerIdentifier()).getSubjectDN());
1106      
1107          } catch (SignatureException ex) {
1108              // if the signature is not OK a SignatureException is thrown
1109              System.out.println("Signature ERROR from signer: "+user1_sign.getSubjectDN());
1110              throw new CMSException(ex.toString());
1111          }
1112      
1113          try {
1114             SignerInfo signer_info = signed_data.verify(user2_sign);
1115              // if the signature is OK the certificate of the signer is returned
1116              System.out.println("Signature OK from signer: "+signed_data.getCertificate(signer_info.getSignerIdentifier()).getSubjectDN());
1117      
1118          } catch (SignatureException ex) {
1119              // if the signature is not OK a SignatureException is thrown
1120              System.out.println("Signature ERROR from signer: "+user2_sign.getSubjectDN());
1121              throw new CMSException(ex.toString());
1122          }
1123          
1124          // in practice we also would validate the signer certificate(s)  
1125        }
1126        return signed_data.getContent();
1127      }
1128    
1129    
1130      
1131      /**
1132       * Creates a <i>SignedAndEncrypted</i> (i.e. sequential combination of <code>
1133       * SignedData</code> and <code>EnvelopedData</code>) object.
1134       *
1135       * @param message the message to be signed and encrypted, as byte representation
1136       * @return the DER encoded ContentInfo holding the signed and encrypted message object
1137       *         just created
1138       * @throws CMSException if the the <code>SignedData</code> or
1139       *                          <code>EnvelopedData</code> object cannot be created
1140       */
1141      public byte[] createSignedAndEncryptedData(byte[] message) throws CMSException {
1142    
1143        System.out.println("Create a new message signed by user1 encrypted for user2:");
1144    
1145        byte[] signed = createSignedData(message, SignedData.IMPLICIT);
1146        return createEnvelopedData(signed);
1147      }
1148    
1149      /**
1150       * Recovers the original message and verifies the signature.
1151       *
1152       * @param encoding the DER encoded ContentInfo holding a SignedAndEnryptedData object
1153       * @return the recovered message, as byte array
1154       * @throws CMSException if the message cannot be recovered
1155       * @throws IOException if an I/O error occurs
1156       */
1157      public byte[] getSignedAndEncryptedData(byte[] encoding) throws CMSException, IOException {
1158        
1159        // user2 means index 2 (hardcoded for this demo)
1160        byte[] signed = getEnvelopedData(encoding, user2_crypt_pk, 1);
1161        return getSignedData(signed, null);
1162      }
1163    
1164    
1165      /**
1166       * Creates a CMS <code>DigestedData</code> object.
1167       * <p>
1168       *
1169       * @param message the message to be digested, as byte representation
1170       * @return the <code>DigestedData</code> wrapped into a ContentInfo, as DER encoding
1171       * @throws CMSException if the <code>DigestedData</code> object cannot
1172       *                          be created
1173       */
1174      public byte[] createDigestedData(byte[] message, int mode) throws CMSException  {
1175    
1176        System.out.println("Create a new digested message:");
1177    
1178        // create a new DigestedData object which includes the data
1179        DigestedData digested_data = new DigestedData(message, (AlgorithmID)AlgorithmID.sha256.clone(), mode);
1180        ContentInfo ci = new ContentInfo(digested_data);
1181        return ci.toByteArray();
1182      }
1183    
1184      /**
1185       * Parses a CMS <code>DigestedData</code> object and verifies the hash value.
1186       *
1187       * @param encoding the ContentInfo holding a <code>DigestedData</code>, as DER encoding
1188       * @param message the the message which was transmitted out-of-band (explicit digested)
1189       *
1190       * @return the message
1191       * @throws CMSException if some parsing exception occurs
1192       * @throws IOException if an I/O error occurs
1193       */
1194      public byte[] getDigestedData(byte[] encoding, byte[] message) throws CMSException, IOException {
1195        
1196        ByteArrayInputStream encodedStream = new ByteArrayInputStream(encoding);
1197        // create a content info from the ASN.1 object
1198        ContentInfo ci = new ContentInfo(encodedStream);
1199        System.out.println("This ContentInfo holds content of type " + ci.getContentType().getName());
1200    
1201        DigestedData digested_data = new DigestedData(encodedStream);
1202    
1203        if (digested_data.getMode() == DigestedData.EXPLICIT) {
1204          // set content transmitted by other means
1205          digested_data.setContent(message);
1206        }
1207    
1208        // now verify the digest
1209        if (digested_data.verify()) {
1210          System.out.println("Hash ok!");
1211        } else {
1212          throw new CMSException("Hash verification failed!");
1213        }
1214    
1215        return digested_data.getContent();
1216      }
1217    
1218    
1219      /**
1220       * Creates a CMS <code>EncryptedData</code> message.
1221       * <p>
1222       * The supplied content is PBE-encrypted using the specified password.
1223       *
1224       * @param message the message to be encrypted, as byte representation
1225       * @param pbeAlgorithm the PBE algorithm to be used
1226       * @param password the password
1227       * @return the <code>EncryptedData</code> object wrapped into a ContentInfo, as DER encoding
1228       * @throws CMSException if the <code>EncryptedData</code> object cannot
1229       *                          be created
1230       */
1231      public byte[] createEncryptedData(byte[] message, AlgorithmID pbeAlgorithm, char[] password) throws CMSException {
1232    
1233        EncryptedData encrypted_data;
1234    
1235        try {
1236          encrypted_data = new EncryptedData(message);
1237          // encrypt the message
1238          encrypted_data.setupCipher(pbeAlgorithm, password);
1239        } catch (InvalidKeyException ex) {
1240          throw new CMSException("Key error: "+ex.toString());
1241        } catch (NoSuchAlgorithmException ex) {
1242          throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
1243        }
1244        // create the ContentInfo
1245        ContentInfo ci = new ContentInfo(encrypted_data);
1246        return ci.toByteArray();
1247    
1248      }
1249    
1250      /**
1251       * Decrypts the PBE-encrypted content of the given <code>EncryptedData</code> object
1252       * using the specified password and returns the decrypted (= original) message.
1253       *
1254       * @param encoding the DER encoded ContentInfo holding the <code>EncryptedData</code> object
1255       * @param password the password to decrypt the message
1256       *
1257       * @return the recovered message, as byte array
1258       * @throws CMSException if the message cannot be recovered
1259       * @throws IOException if an I/O error occurs
1260       */
1261      public byte[] getEncryptedData(byte[] encoding, char[] password) throws CMSException, IOException {
1262        
1263        ByteArrayInputStream encodedStream = new ByteArrayInputStream(encoding);
1264        ContentInfo ci = new ContentInfo(encodedStream);
1265        System.out.println("This ContentInfo holds content of type " + ci.getContentType().getName());
1266    
1267        // get the EncryptedData
1268        EncryptedData encrypted_data = (EncryptedData)ci.getContent();
1269    
1270        System.out.println("Information about the encrypted data:");
1271        EncryptedContentInfo eci = (EncryptedContentInfo)encrypted_data.getEncryptedContentInfo();
1272        System.out.println("Content type: "+eci.getContentType().getName());
1273        System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
1274    
1275        // decrypt the message
1276        try {
1277          encrypted_data.setupCipher(password);
1278          return encrypted_data.getContent();
1279    
1280        } catch (InvalidKeyException ex) {
1281          throw new CMSException("Key error: "+ex.toString());
1282        } catch (NoSuchAlgorithmException ex) {
1283          throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
1284        } catch (InvalidAlgorithmParameterException ex) {
1285          throw new CMSException("Invalid Parameters: "+ex.toString());
1286        } catch (InvalidParameterSpecException ex) {
1287          throw new CMSException("Invalid Parameters: "+ex.toString());
1288        }
1289      }
1290      
1291      /**
1292       * Creates a CMS <code>AuthenticatedData</code> for the given message message.
1293       * <p>
1294       * <b>Attention:</b> This AuthenticatedData demo uses RSA as key management technique.
1295       * In practice (see RFC 5652) a key management technique that provides data origin
1296       * authentication should be used like, for instance, Static-Static Diffie-Hellman when
1297       * both the originator and recipient public keys are bound to appropriate identities 
1298       * in X.509 certificates, see, for instance, {@link demo.cms.authenticatedData.AuthenticatedDataDemo
1299       * AuthenticatedDataDemo}.
1300       *
1301       * @param message the message to be authenticated, as byte representation
1302       * @param includeAuthAttrs whether to include authenticated attributes
1303       * @param mode the mode indicating whether to include the content 
1304       *             (AuthenticatedData.IMPLICIT) or not (AuthenticatedDatam.EXPLICIT)
1305       * @return the BER encoding of the <code>AuthenticatedData</code> object, wrapped in a ContentInfo
1306       * @throws CMSException if the <code>AuthenticatedData</code> object cannot
1307       *                         be created
1308       * @throws IOException if an I/O error occurs
1309       */
1310      public byte[] createAuthenticatedData(byte[] message,
1311                                            boolean includeAuthAttrs,
1312                                            int mode)
1313        throws CMSException, IOException {
1314        
1315        AlgorithmID macAlgorithm = (AlgorithmID)AlgorithmID.hMAC_SHA256.clone();
1316        int macKeyLength = 32;
1317        AlgorithmID digestAlgorithm = null;
1318        // we need a digest algorithm if authenticated attributes shall be included
1319        if (includeAuthAttrs == true) {
1320          digestAlgorithm = (AlgorithmID)AlgorithmID.sha256.clone();
1321        }   
1322        ObjectID contentType = ObjectID.cms_data;
1323        
1324        AuthenticatedData authenticatedData;
1325    
1326        // create a new AuthenticatedData object 
1327        try {
1328          authenticatedData = new AuthenticatedData(contentType,
1329                                                    message, 
1330                                                    macAlgorithm,
1331                                                    macKeyLength,
1332                                                    null,
1333                                                    digestAlgorithm,
1334                                                    mode);
1335        } catch (NoSuchAlgorithmException ex) {
1336          throw new CMSException(ex.toString());
1337        }
1338    
1339    
1340        // create the recipient infos
1341        RecipientInfo[] recipients = new RecipientInfo[2];
1342        // user1 is the first receiver
1343        recipients[0] = new KeyTransRecipientInfo(user1_crypt, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
1344        // user2 is the second receiver
1345        recipients[1] = new KeyTransRecipientInfo(user2_crypt, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
1346        // specify the recipients of the authenticated message
1347        authenticatedData.setRecipientInfos(recipients);
1348        
1349        if (includeAuthAttrs == true) {
1350          // create some autheticated attributes
1351          // (the message digest attribute is automatically added)
1352          try {
1353            Attribute[] attributes = { new Attribute(new CMSContentType(contentType)) };
1354            authenticatedData.setAuthenticatedAttributes(attributes);
1355          } catch (Exception ex) {
1356            throw new CMSException("Error creating attribute: " + ex.toString());   
1357          } 
1358        }    
1359       
1360        // wrap the AuthenticatedData in a ContentInfo and encode it
1361        ContentInfo ci = new ContentInfo(authenticatedData);
1362        return ci.toByteArray();
1363      
1364      }
1365      
1366      /**
1367       * Decrypts the encrypted MAC key for the recipient identified by its index
1368       * into the recipientInfos field and uses the MAC key to verify
1369       * the authenticated data.
1370       * <p>
1371       * This way of decrypting the MAC key and verifying the content may be used for 
1372       * any type of RecipientInfo (KeyTransRecipientInfo, KeyAgreeRecipientInfo, 
1373       * KEKRecipientInfo), but requires to know at what index of the recipientInfos
1374       * field the RecipientInfo for the particular recipient in mind can be found. 
1375       * If the recipient in mind uses a RecipientInfo of type KeyAgreeRecipientInfo
1376       * some processing overhead may take place because a KeyAgreeRecipientInfo may
1377       * contain encrypted mac keys for more than only one recipient; since the
1378       * recipientInfoIndex only specifies the RecipientInfo but not the encrypted
1379       * mac key -- if there are more than only one -- repeated decryption runs may be
1380       * required as long as the decryption process completes successfully.
1381       * <p>
1382       * <b>Attention:</b> This AuthenticatedData demo uses RSA as key management technique.
1383       * In practice (see RFC 5652) a key management technique that provides data origin
1384       * authentication should be used like, for instance, Static-Static Diffie-Hellman when
1385       * both the originator and recipient public keys are bound to appropriate identities 
1386       * in X.509 certificates, see, for instance, {@link demo.cms.authenticatedData.AuthenticatedDataDemo
1387       * AuthenticatedDataDemo}.
1388       *
1389       * @param encoding the DER encoded ContentInfo holding the <code>AuthenticatedData</code> object
1390       * @param message the content message, if transmitted by other means (explicit mode)
1391       * @param key the key to decrypt the mac key
1392       * @param recipientInfoIndex the index of the right <code>RecipientInfo</code> to 
1393       *                           which the given key belongs
1394       *
1395       * @return the verified message, as byte array
1396       * @throws CMSException if the authenticated data cannot be verified
1397       * @throws IOException if a IO read/write error occurs
1398       */
1399      public byte[] getAuthenticatedData(byte[] encoding, 
1400                                         byte[] message,
1401                                         PrivateKey key,
1402                                         int recipientInfoIndex) 
1403        throws CMSException, IOException {
1404            
1405        // create the AuthenticatedData object from a DER encoded byte array
1406        ByteArrayInputStream is = new ByteArrayInputStream(encoding);
1407        ContentInfo ci = new ContentInfo(is);
1408        System.out.println("This ContentInfo holds content of type " + ci.getContentType().getName());
1409    
1410        AuthenticatedData authenticatedData = (AuthenticatedData)ci.getContent();
1411        
1412        if (authenticatedData.getMode() == AuthenticatedData.EXPLICIT) {
1413          // in explicit mode explicitly supply the content for hash/mac computation  
1414          authenticatedData.setContent(message);
1415        }
1416    
1417        System.out.println("\nThis message can be verified by the following recipients:");
1418        RecipientInfo[] recipients = authenticatedData.getRecipientInfos();
1419        for (int i=0; i<recipients.length; i++) {
1420          System.out.println("Recipient "+(i+1)+":");
1421          System.out.println(recipients[i].getRecipientIdentifiers()[0]);
1422        }
1423    
1424        // decrypt the mac key and verify the mac for the first recipient
1425        try {
1426          authenticatedData.setupMac(key, recipientInfoIndex);
1427          if (authenticatedData.verifyMac() == false) {
1428            throw new CMSException("Mac verification error!");
1429          }  
1430          System.out.println("Mac successfully verified!");
1431          
1432          return authenticatedData.getContent();
1433    
1434        } catch (InvalidKeyException ex) {
1435          throw new CMSException("Key error: "+ex.getMessage());
1436        } catch (NoSuchAlgorithmException ex) {
1437          throw new CMSException(ex.toString());
1438        }
1439      }
1440    
1441    
1442    
1443    
1444      /**
1445       * Tests the CMS content type implementations <code>Data</code>, <code>EnvelopedData</code>,
1446       * <code>SignedData</code>, <code>DigestedData</code>, <code>EncryptedData</code>.
1447       * An additional <i>SignedAndEncryptedData</i> test sequentially combines
1448       * signed and enveloped data.
1449       */
1450      public void start() {
1451         // the test message
1452        String m = "This is the test message.";
1453        System.out.println("Test message: \""+m+"\"");
1454        System.out.println();
1455        byte[] message = m.getBytes();
1456    
1457        try {
1458          byte[] encoding;
1459          byte[] received_message = null;
1460          System.out.println("Stream implementation demos");
1461          System.out.println("===========================");
1462    
1463          // the stream implementation
1464          //
1465          // test CMS DataStream
1466          //
1467          System.out.println("\nDataStream demo [create]:\n");
1468          encoding = createDataStream(message);
1469          // transmit data
1470          System.out.println("\nDataStream demo [parse]:\n");
1471          
1472          received_message = getDataStream(encoding);
1473          System.out.print("\nContent: ");
1474          System.out.println(new String(received_message));
1475    
1476    
1477          // the stream implementation
1478          //
1479          // test CMS EnvelopedDataStream
1480          //
1481          System.out.println("\nEnvelopedDataStream demo [create]:\n");
1482          encoding = createEnvelopedDataStream(message);
1483          // transmit data
1484          System.out.println("\nEnvelopedDataStream demo [parse]:\n");
1485          // user1 means index 0 (hardcoded for this demo)
1486          received_message = getEnvelopedDataStream(encoding, user1_crypt_pk, 0);
1487          System.out.print("\nDecrypted content: ");
1488          System.out.println(new String(received_message));
1489    
1490          //
1491          // test CMS Implicit SignedDataStream
1492          //
1493          System.out.println("\nImplicit SignedDataStream demo [create]:\n");
1494          encoding = createSignedDataStream(message, SignedDataStream.IMPLICIT);
1495          // transmit data
1496          System.out.println("\nImplicit SignedDataStream demo [parse]:\n");
1497          received_message = getSignedDataStream(encoding, null);
1498          System.out.print("\nSigned content: ");
1499          System.out.println(new String(received_message));
1500    
1501          //
1502          // test CMS Explicit SignedDataStream
1503          //
1504          System.out.println("\nExplicit SignedDataStream demo [create]:\n");
1505          encoding = createSignedDataStream(message, SignedDataStream.EXPLICIT);
1506          // transmit data
1507          System.out.println("\nExplicit SignedDataStream demo [parse]:\n");
1508          received_message = getSignedDataStream(encoding, message);
1509          System.out.print("\nSigned content: ");
1510          System.out.println(new String(received_message));
1511    
1512          // test CMS SignedAndEncryptedDataStream
1513          //
1514          System.out.println("\nSignedAndEncryptedDataStream demo [create]:\n");
1515          encoding = createSignedAndEncryptedDataStream(message);
1516          // transmit data
1517          System.out.println("\nSignedAndEncryptedDataStream demo [parse]:\n");
1518          received_message = getSignedAndEncryptedDataStream(encoding);
1519          System.out.print("\nSignedAndEncrypted content: ");
1520          System.out.println(new String(received_message));
1521    
1522    
1523          //
1524          // test CMS Implicit DigestedDataStream
1525          //
1526          System.out.println("\nImplicit DigestedDataStream demo [create]:\n");
1527          encoding = createDigestedDataStream(message, DigestedDataStream.IMPLICIT);
1528          // transmit data
1529          System.out.println("\nImplicit DigestedDataStream demo [parse]:\n");
1530          received_message = getDigestedDataStream(encoding, null);
1531          System.out.print("\nContent: ");
1532          System.out.println(new String(received_message));
1533    
1534          //
1535          // test CMS Explicit DigestedDataStream
1536          //
1537          System.out.println("\nExplicit DigestedDataStream demo [create]:\n");
1538          encoding = createDigestedDataStream(message, DigestedDataStream.EXPLICIT);
1539          // transmit data
1540          System.out.println("\nExplicit DigestedDataStream demo [parse]:\n");
1541          received_message = getDigestedDataStream(encoding, message);
1542          System.out.print("\nContent: ");
1543          System.out.println(new String(received_message));
1544    
1545          //
1546          // test CMS EncryptedDataStream
1547          //
1548          System.out.println("\nEncryptedDataStream demo [create]:\n");
1549          encoding = createEncryptedDataStream(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray());
1550          // transmit data
1551          System.out.println("\nEncryptedDataStream demo [parse]:\n");
1552          received_message = getEncryptedDataStream(encoding, "password".toCharArray());
1553          System.out.print("\nContent: ");
1554          System.out.println(new String(received_message));
1555          
1556                
1557          //
1558          // test CMS Implicit AuthenticatedDataStream with auth attributes
1559          //
1560          System.out.println("\nImplicit AuthenticatedDataStream demo with auth attributes [create]:\n");
1561          encoding = createAuthenticatedDataStream(message, true, AuthenticatedDataStream.IMPLICIT);
1562          // transmit data
1563          System.out.println("\nImplicit AuthenticatedDataStream demo with auth attributes [parse]:\n");
1564          received_message = getAuthenticatedDataStream(encoding, null, user1_crypt_pk, 0);
1565          System.out.print("\nVerified content: ");
1566          System.out.println(new String(received_message));
1567          
1568          System.out.println("\nImplicit AuthenticatedDataStream demo without auth attributes [create]:\n");
1569          encoding = createAuthenticatedDataStream(message, false, AuthenticatedDataStream.IMPLICIT);
1570          // transmit data
1571          System.out.println("\nImplicit AuthenticatedDataStream demo without auth attributes [parse]:\n");
1572          received_message = getAuthenticatedDataStream(encoding, null, user1_crypt_pk, 0);
1573          System.out.print("\nVerified content: ");
1574          System.out.println(new String(received_message));
1575    
1576          //
1577          // test CMS Explicit AuthenticatedDataStream
1578          //
1579          System.out.println("\nExplicit AuthenticatedDataStream demo with auth attributes [create]:\n");
1580          encoding = createAuthenticatedDataStream(message, true, AuthenticatedDataStream.EXPLICIT);
1581          // transmit data
1582          System.out.println("\nExplicit AuthenticatedDataStream demo with auth attributes [parse]:\n");
1583          received_message = getAuthenticatedDataStream(encoding, message, user1_crypt_pk, 0);
1584          System.out.print("\nVerified content: ");
1585          System.out.println(new String(received_message));
1586          
1587          System.out.println("\nExplicit AuthenticatedDataStream demo without auth attributes [create]:\n");
1588          encoding = createAuthenticatedDataStream(message, false, AuthenticatedDataStream.EXPLICIT);
1589          // transmit data
1590          System.out.println("\nExplicit AuthenticatedDataStream demo with auth attributes [parse]:\n");
1591          received_message = getAuthenticatedDataStream(encoding, message, user1_crypt_pk, 0);
1592          System.out.print("\nVerified content: ");
1593          System.out.println(new String(received_message));
1594    
1595    
1596          // the non-stream implementation
1597          System.out.println("\nNon-stream implementation demos");
1598          System.out.println("===============================");
1599          
1600          //
1601          // test CMS Data
1602          //
1603          System.out.println("\nData demo [create]:\n");
1604          encoding = createData(message);
1605          // transmit data
1606          System.out.println("\nData demo [parse]:\n");
1607    
1608          received_message = getData(encoding);
1609          System.out.print("\nContent: ");
1610          System.out.println(new String(received_message));
1611    
1612          //
1613          // test CMS EnvelopedData
1614          //
1615          System.out.println("\nEnvelopedData demo [create]:\n");
1616          encoding = createEnvelopedData(message);
1617          // transmit data
1618          System.out.println("\nEnvelopedData demo [parse]:\n");
1619          // user1 means index 0 (hardcoded for this demo)
1620          received_message = getEnvelopedData(encoding, user1_crypt_pk, 0);
1621          System.out.print("\nDecrypted content: ");
1622          System.out.println(new String(received_message));
1623    
1624          //
1625          // test CMS Implicit SignedData
1626          //
1627          System.out.println("\nImplicit SignedData demo [create]:\n");
1628          encoding = createSignedData(message, SignedDataStream.IMPLICIT);
1629          // transmit data
1630          System.out.println("\nImplicit SignedData demo [parse]:\n");
1631          received_message = getSignedData(encoding, null);
1632          System.out.print("\nSigned content: ");
1633          System.out.println(new String(received_message));
1634    
1635          //
1636          // test CMS Explicit SignedData
1637          //
1638          System.out.println("\nExplicit SignedData demo [create]:\n");
1639          encoding = createSignedData(message, SignedData.EXPLICIT);
1640          // transmit data
1641          System.out.println("\nExplicit SignedData demo [parse]:\n");
1642          received_message = getSignedData(encoding, message);
1643          System.out.print("\nSigned content: ");
1644          System.out.println(new String(received_message));
1645    
1646          //
1647          // test CMS SignedAndEncryptedData
1648          //
1649          System.out.println("\nSignedAndEncryptedData demo [create]:\n");
1650          encoding = createSignedAndEncryptedData(message);
1651          // transmit data
1652          System.out.println("\nSignedAndEncryptedData demo [parse]:\n");
1653          received_message = getSignedAndEncryptedData(encoding);
1654          System.out.print("\nSignedAndEncrypted content: ");
1655          System.out.println(new String(received_message));
1656    
1657    
1658          //
1659          // test CMS Implicit DigestedData
1660          //
1661          System.out.println("\nImplicit DigestedData demo [create]:\n");
1662          encoding = createDigestedData(message, DigestedData.IMPLICIT);
1663          // transmit data
1664          System.out.println("\nImplicit DigestedData demo [parse]:\n");
1665          received_message = getDigestedData(encoding, null);
1666          System.out.print("\nContent: ");
1667          System.out.println(new String(received_message));
1668    
1669          //
1670          // test CMS Explicit DigestedData
1671          //
1672          System.out.println("\nExplicit DigestedData demo [create]:\n");
1673          encoding = createDigestedData(message, DigestedData.EXPLICIT);
1674          // transmit data
1675          System.out.println("\nExplicit DigestedData demo [parse]:\n");
1676          received_message = getDigestedData(encoding, message);
1677          System.out.print("\nContent: ");
1678          System.out.println(new String(received_message));
1679    
1680          //
1681          // test CMS EncryptedData
1682          //
1683          System.out.println("\nEncryptedData demo [create]:\n");
1684          encoding = createEncryptedData(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray());
1685          // transmit data
1686          System.out.println("\nEncryptedData demo [parse]:\n");
1687          received_message = getEncryptedData(encoding, "password".toCharArray());
1688          System.out.print("\nContent: ");
1689          System.out.println(new String(received_message));
1690          
1691              //
1692          // test CMS Implicit AuthenticatedData 
1693          //
1694          System.out.println("\nImplicit AuthenticatedData demo with auth attributes [create]:\n");
1695          encoding = createAuthenticatedData(message, true, AuthenticatedData.IMPLICIT);
1696          // transmit data
1697          System.out.println("\nImplicit AuthenticatedData demo with auth attributes [parse]:\n");
1698          received_message = getAuthenticatedData(encoding, null, user1_crypt_pk, 0);
1699          System.out.print("\nVerified content: ");
1700          System.out.println(new String(received_message));
1701          
1702          System.out.println("\nImplicit AuthenticatedData demo without auth attributes [create]:\n");
1703          encoding = createAuthenticatedData(message, false, AuthenticatedData.IMPLICIT);
1704          // transmit data
1705          System.out.println("\nImplicit AuthenticatedData demo without auth attributes [parse]:\n");
1706          received_message = getAuthenticatedData(encoding, null, user1_crypt_pk, 0);
1707          System.out.print("\nVerified content: ");
1708          System.out.println(new String(received_message));
1709    
1710          //
1711          // test CMS Explicit AuthenticatedData
1712          //
1713          System.out.println("\nExplicit AuthenticatedData demo with auth attributes [create]:\n");
1714          encoding = createAuthenticatedData(message, true, AuthenticatedData.EXPLICIT);
1715          // transmit data
1716          System.out.println("\nExplicit AuthenticatedData demo with auth attributes [parse]:\n");
1717          received_message = getAuthenticatedData(encoding, message, user1_crypt_pk, 0);
1718          System.out.print("\nVerified content: ");
1719          System.out.println(new String(received_message));
1720          
1721          System.out.println("\nExplicit AuthenticatedData demo without auth attributes [create]:\n");
1722          encoding = createAuthenticatedData(message, false, AuthenticatedData.EXPLICIT);
1723          // transmit data
1724          System.out.println("\nExplicit AuthenticatedData demo with auth attributes [parse]:\n");
1725          received_message = getAuthenticatedData(encoding, message, user1_crypt_pk, 0);
1726          System.out.print("\nVerified content: ");
1727          System.out.println(new String(received_message));
1728    
1729    
1730          System.out.println("Ready!");
1731    
1732            } catch (Exception ex) {
1733              ex.printStackTrace();
1734              throw new RuntimeException(ex.toString());
1735            }
1736      }
1737    
1738    
1739      /**
1740       * Starts the CMS content type implementation tests.
1741       *
1742       * @throws Exception
1743       *            if some error occurs 
1744       */
1745      public static void main(String argv[]) throws Exception {
1746    
1747            demo.DemoUtil.initDemos();
1748        (new CMSDemo()).start();
1749    
1750        DemoUtil.waitKey();
1751      }
1752    }