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/pkcs7cms/PKCS7CMSEncryptedContentInfoDemo.java 25    12.02.25 17:58 Dbratko $
059    // $Revision: 25 $
060    //
061    
062    package demo.cms.pkcs7cms;
063    
064    import iaik.asn1.ASN;
065    import iaik.asn1.ASN1Object;
066    import iaik.asn1.INTEGER;
067    import iaik.asn1.OCTET_STRING;
068    import iaik.asn1.ObjectID;
069    import iaik.asn1.SEQUENCE;
070    import iaik.asn1.structures.AlgorithmID;
071    import iaik.cms.EncryptedContentInfoStream;
072    import iaik.cms.EnvelopedDataStream;
073    import iaik.cms.KeyTransRecipientInfo;
074    import iaik.cms.RecipientInfo;
075    import iaik.cms.SecurityProvider;
076    import iaik.security.random.SecRandom;
077    import iaik.utils.Util;
078    import iaik.x509.X509Certificate;
079    
080    import java.io.ByteArrayInputStream;
081    import java.io.ByteArrayOutputStream;
082    import java.io.IOException;
083    import java.io.InputStream;
084    import java.math.BigInteger;
085    import java.security.PrivateKey;
086    import java.security.SecureRandom;
087    import java.security.spec.AlgorithmParameterSpec;
088    
089    import javax.crypto.KeyGenerator;
090    import javax.crypto.SecretKey;
091    import javax.crypto.spec.IvParameterSpec;
092    import javax.crypto.spec.RC2ParameterSpec;
093    
094    import demo.DemoUtil;
095    import demo.keystore.CMSKeyStore;
096    
097    /**
098     * This class demonstrates the EnvelopedDataStream/EncryptedContentInfoStream usages
099     * for algorithms that may require a specific parameter handling.
100     * <p>
101     * This class shows the compatibility to PKCS#7.
102     * <p>
103     * All keys and certificates are read from a keystore created by the
104     * SetupCMSKeyStore program.
105     * <p>
106     * The following algorithms are demonstrated:
107     * <ul>
108     * <li>ARCFOUR: Variable-key-size stream cipher; no parameters to be sent
109     * <li>RC2_CBC: Variable-key-size block cipher; parameters as used by S/MIME:
110     *              rc2ParamterVersion and IV; encoded as SEQUENCE:
111     *              <pre>
112     *               RC2-CBC parameter ::=  SEQUENCE {
113     *                 rc2ParameterVersion  INTEGER,
114     *                 iv                   OCTET STRING (8)}
115     *
116     *               For the effective-key-bits of 40, 64, and 128, the
117     *                rc2ParameterVersion values are 160, 120, 58 respectively.
118     *              </pre>
119     * <li>CAST5_CBC: Feistel type block cipher with key sizes of 40-128 bit in 8 bit
120     *              increments; parameters (RFC 2144):
121     *              <pre>
122     *               Parameters ::=  SEQUENCE {
123     *                 iv         OCTET STRING DEFAULT 0,
124     *                 keyLength  INTEGER }
125     *
126     *              </pre>
127     * </ul>
128     * This class shows how an EncryptedContentInfo is explicit created for encrypt�ng
129     * the content and supplying it to an EnvelopedDataStream object. Note that IAIK-CMS
130     * also allows to use EnvelopedData(Stream) for algorithms like RC2, ARCFOUR or CAST in
131     * without having the necessity of explicit key/parameter handling, see {@link 
132     * demo.cms.envelopedData.RC2EnvelopedDataDemo RC2EnvelopedDataDemo} for an example.
133     * <p>
134     * Note that the usage of algorithms like RC2 is deprecated but used here for this
135     * demo since it requires a specific parameter handling.
136     */
137    public class PKCS7CMSEncryptedContentInfoDemo {
138    
139      // certificate of user 1
140      X509Certificate user1;
141      // private key of user 1
142      PrivateKey user1_pk;
143      // certificate of user 2
144      X509Certificate user2;
145      // private key of user 2
146      PrivateKey user2_pk;
147      // secure random number generator
148      SecureRandom random;
149    
150      /**
151       * Setup the demo certificate chains.
152       *
153       * Keys and certificate are retrieved from the demo KeyStore.
154       *
155       * @throws IOException if an file read error occurs
156       */
157      public PKCS7CMSEncryptedContentInfoDemo() throws IOException {
158        
159        System.out.println();
160        System.out.println("********************************************************************************************************");
161        System.out.println("*                               PKCS7CMSEncryptedContentInfoDemo                                       *");
162        System.out.println("* (tests the CMS EncryptedContentInfo against the IAIK-JCE PKCS#7 EncryptedContentInfo implementation) *");
163        System.out.println("********************************************************************************************************");
164        System.out.println();
165        
166        // add all certificates to the list
167        X509Certificate[] certs = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1);
168        user1 = certs[0];
169        user1_pk = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1);
170        user2 = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0];
171        user2_pk = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2);
172    
173        random = SecRandom.getDefault();
174    
175    
176    
177      }
178    
179    
180      /**
181       * Creates a CMS <code>EnvelopedDataStream</code> message.
182       *
183       * @param message the message to be enveloped, as byte representation
184       * @param contentEA the content encryption algorithm
185       * @param keyLength the key length for the symmetric key
186       * @return the DER encoding of the <code>EnvelopedData</code> object just created
187       * @throws Exception if the <code>EnvelopedData</code> object cannot be created
188       */
189      public byte[] createEnvelopedDataStream(byte[] message, AlgorithmID contentEA, int keyLength) throws Exception {
190    
191          SecurityProvider provider = SecurityProvider.getSecurityProvider();
192          ByteArrayInputStream is = new ByteArrayInputStream(message);
193    
194          AlgorithmParameterSpec params = null;
195          SecretKey secretKey = null;
196    
197          // create iv
198          byte[] iv = new byte[8];
199          random.nextBytes(iv);
200    
201          int rc2_param = 58;
202          if (contentEA.equals(AlgorithmID.rc2_CBC)) {
203            
204             switch (keyLength) {
205               case 40:
206                 rc2_param = 160;
207                 break;
208               case 64:
209                 rc2_param = 120;
210                 break;
211               default:    // 128
212                 rc2_param = 58;
213                 keyLength = 128;
214             }
215             // create the paramters (SEQUENCE) to be sent
216             SEQUENCE parameter = new SEQUENCE();
217             parameter.addComponent(new INTEGER(rc2_param));
218             parameter.addComponent(new OCTET_STRING(iv));
219             contentEA.setParameter(parameter);
220             params = new RC2ParameterSpec(keyLength,iv);
221          }  else if (contentEA.equals(AlgorithmID.arcfour)){
222             // no params for ARCFOUR
223             params = null;
224          } else if (contentEA.equals(AlgorithmID.cast5_CBC)) {
225             SEQUENCE parameter = new SEQUENCE();
226             parameter.addComponent(new OCTET_STRING(iv));
227             parameter.addComponent(new INTEGER(keyLength));
228             contentEA.setParameter(parameter);
229             params = new IvParameterSpec(iv);
230    
231          } else {
232             throw new Exception("Algorithm " + contentEA + " not supportted for this test!");
233          }
234    
235          KeyGenerator keyGen = provider.getKeyGenerator(contentEA, keyLength);
236          // generate a new key
237          secretKey = keyGen.generateKey();
238    
239          // create the EncryptedContentInfo for the content to be encrypted
240          EncryptedContentInfoStream eci = new EncryptedContentInfoStream(ObjectID.pkcs7_data, is);
241          // setup the cipher for encryption
242          eci.setupCipher(contentEA, secretKey, params);
243    
244           // create the recipient infos
245          RecipientInfo[] recipients = new RecipientInfo[2];
246          // user1 is the first receiver
247          recipients[0] = new KeyTransRecipientInfo(user1, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
248          // encrypt the secret key for recipient 1
249          recipients[0].encryptKey(secretKey);
250          // user2 is the second receiver
251          recipients[1] = new KeyTransRecipientInfo(user2, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
252          // encrypt the secret key for recipient 2
253          recipients[1].encryptKey(secretKey);
254          // now create the EnvelopedDataStream
255          EnvelopedDataStream enveloped_data = new EnvelopedDataStream(recipients, eci);
256    
257          // return the EnvelopedDate as DER encoded byte array with block size 2048
258          ByteArrayOutputStream os = new ByteArrayOutputStream();
259          enveloped_data.writeTo(os, 2048);
260          byte[] enc = os.toByteArray();
261          return enc;
262    
263      }
264    
265      /**
266       * Decrypts the encrypted content of the given CMS <code>EnvelopedData</code> object for the
267       * specified recipient and returns the decrypted (= original) message.
268       *
269       * @param encoding the <code>EnvelopedData</code> object as DER encoded byte array
270       * @param privateKey the private key to decrypt the message
271       * @param recipientInfoIndex the index into the <code>RecipientInfo</code> array
272       *                           to which the specified private key belongs
273       *
274       * @return the recovered message, as byte array
275       * @throws Exception if the message cannot be recovered
276       */
277      public byte[] getEnvelopedDataStream(byte[] encoding, PrivateKey privateKey, int recipientInfoIndex) throws Exception {
278    
279        // create the EnvelopedData object from a DER encoded byte array
280        // we are testing the stream interface
281        ByteArrayInputStream is = new ByteArrayInputStream(encoding);
282        EnvelopedDataStream enveloped_data = new EnvelopedDataStream(is);
283    
284        AlgorithmParameterSpec params = null;
285        // get the recipient infos
286        RecipientInfo[]  recipients = enveloped_data.getRecipientInfos();
287    
288        System.out.println("\nThis message can be decrypted by the owners of the following certificates:");
289    
290        for (int i=0; i<recipients.length; i++) {
291          System.out.println("Recipient "+(i+1)+":");
292          System.out.println(recipients[i].getRecipientIdentifiers()[0]);
293        }
294        // decrypt symmetric content encryption key, e.g.:
295        SecretKey secretKey = recipients[recipientInfoIndex].decryptKey(user1_pk);
296    
297        //get the ECI from the enveloped data:
298        EncryptedContentInfoStream eci = (EncryptedContentInfoStream)enveloped_data.getEncryptedContentInfo();
299        //get the content encryption algorithm:
300        AlgorithmID contentEA = eci.getContentEncryptionAlgorithm();
301        System.out.println("Content Encryption Algorithm: " + contentEA);
302        if (contentEA.equals(AlgorithmID.rc2_CBC)) {
303            // get the parameters as SEQUENCE
304            SEQUENCE seq = (SEQUENCE)contentEA.getParameter();
305            // the iv is the second component
306            OCTET_STRING oct = (OCTET_STRING)seq.getComponentAt(1);
307            // create an IvParameterSpec:
308            //params = new IvParameterSpec((byte[])oct.getValue());
309            int rc2ParameterVersion = ((BigInteger)seq.getComponentAt(0).getValue()).intValue();
310            int effective_key_bits = 32;
311            switch (rc2ParameterVersion) {
312                  case 160:
313                    effective_key_bits = 40;
314                    break;
315                  case 120:
316                    effective_key_bits = 64;
317                    break;
318                  case 58:
319                    effective_key_bits = 128;
320                    break;
321                  default:
322                    throw new Exception("Invalid rc2ParameterVersion " + rc2ParameterVersion + "!");
323    
324                 }
325                 params = new RC2ParameterSpec(effective_key_bits,(byte[])seq.getComponentAt(1).getValue());
326    
327          }
328          else if (contentEA.equals(AlgorithmID.rc5_CBC)) {
329             OCTET_STRING oct = (OCTET_STRING)contentEA.getParameter();
330             // create an IvParameterSpec:
331             params = new IvParameterSpec((byte[])oct.getValue());
332          } else if (contentEA.equals(AlgorithmID.arcfour)) {
333             params = null;
334          } else if (contentEA.equals(AlgorithmID.cast5_CBC)) {
335             // get the parameters
336             ASN1Object asn1Params = contentEA.getParameter();
337             if (asn1Params.isA(ASN.SEQUENCE)) {
338               // the iv is the first component
339               params = new IvParameterSpec((byte[])asn1Params.getComponentAt(0).getValue());
340             } else {
341               // to be compatible with (invalid) CAST AlgorithmIDs only using the IV as parameters
342               params = new IvParameterSpec((byte[])asn1Params.getValue());
343             }  
344          } else {
345             throw new Exception("Algorithm " + contentEA + " not supportted for this test!");
346          }
347    
348    
349          //now setup the cipher with previously decrypted recipient key amd params
350          eci.setupCipher(secretKey, params);
351          //get and read the data thereby actually performing the decryption
352          InputStream data_is = eci.getInputStream();
353          ByteArrayOutputStream baos = new ByteArrayOutputStream();
354          Util.copyStream(data_is, baos, null);
355          byte[] decrypted = baos.toByteArray();
356          return decrypted;
357    
358      }
359      
360      // PKCS#7
361      
362      
363      /**
364       * Creates a PKCS#7 <code>EnvelopedDataStream</code> message.
365       * <p>
366       * The enveloped-data content type consists of encrypted content of any
367       * type and encrypted content-encryption keys for one or more recipients.
368       * The combination of encrypted content and encrypted content-encryption
369       * key for a recipient is a "digital envelope" for that recipient. Any type
370       * of content can be enveloped for any number of recipients in parallel.
371       *
372       * @param message the message to be enveloped, as byte representation
373       * @param cea the content encryption algorithm
374       * @param keyLength the key length for the symmetric key
375       * @return the DER encoding of the <code>EnvelopedData</code> object just created
376       * @throws Exception if the <code>EnvelopedData</code> object cannot
377       *                          be created
378       */
379      public byte[] createPKCS7EnvelopedDataStream(byte[] message, AlgorithmID cea, int keyLength) throws Exception {
380    
381          SecurityProvider provider = SecurityProvider.getSecurityProvider();
382          ByteArrayInputStream is = new ByteArrayInputStream(message);
383          AlgorithmID contentEA = (AlgorithmID)cea.clone(); 
384          AlgorithmParameterSpec params = null;
385          KeyGenerator key_gen = null;
386          SecretKey secretKey = null;
387    
388          // create iv
389          byte[] iv = new byte[8];
390          random.nextBytes(iv);
391    
392          int rc2_param = 58;
393          if (contentEA.equals(AlgorithmID.rc2_CBC)) {
394             switch (keyLength) {
395               case 40:
396                 rc2_param = 160;
397                 break;
398               case 64:
399                 rc2_param = 120;
400                 break;
401               default:    // 128
402                 rc2_param = 58;
403                 keyLength = 128;
404             }
405             // create the paramters (SEQUENCE) to be sent
406             SEQUENCE parameter = new SEQUENCE();
407             parameter.addComponent(new INTEGER(rc2_param));
408             parameter.addComponent(new OCTET_STRING(iv));
409             contentEA.setParameter(parameter);
410             params = new RC2ParameterSpec(keyLength,iv);
411          }  else if (contentEA.equals(AlgorithmID.arcfour)){
412             // no params for ARCFOUR
413             params = null;
414          } else if (contentEA.equals(AlgorithmID.cast5_CBC)) {
415      
416             SEQUENCE parameter = new SEQUENCE();
417             parameter.addComponent(new OCTET_STRING(iv));
418             parameter.addComponent(new INTEGER(keyLength));
419             contentEA.setParameter(parameter);
420             params = new IvParameterSpec(iv);
421    
422          } else {
423             throw new Exception("Algorithm " + contentEA + " not supportted for this test!");
424          }
425    
426          KeyGenerator keyGen = provider.getKeyGenerator(contentEA, keyLength);
427          // generate a new key
428          secretKey = keyGen.generateKey();
429      
430          // create the EncryptedContentInfo for the content to be encrypted
431          iaik.pkcs.pkcs7.EncryptedContentInfoStream eci = new iaik.pkcs.pkcs7.EncryptedContentInfoStream(ObjectID.pkcs7_data, is);
432          // setup the cipher for encryption
433          eci.setupCipher(contentEA, secretKey, params);
434    
435           // create the recipient infos
436          iaik.pkcs.pkcs7.RecipientInfo[] recipients = new iaik.pkcs.pkcs7.RecipientInfo[2];
437          // user1 is the first receiver
438          recipients[0] = new iaik.pkcs.pkcs7.RecipientInfo(user1, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
439          // encrypt the secret key for recipient 1
440          recipients[0].encryptKey(secretKey);
441          // user2 is the second receiver
442          recipients[1] = new iaik.pkcs.pkcs7.RecipientInfo(user2, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
443          // encrypt the secret key for recipient 2
444          recipients[1].encryptKey(secretKey);
445          // now create the EnvelopedDataStream
446          iaik.pkcs.pkcs7.EnvelopedDataStream enveloped_data = 
447            new iaik.pkcs.pkcs7.EnvelopedDataStream(recipients, eci);
448    
449          // return the EnvelopedDate as DER encoded byte array with block size 2048
450          ByteArrayOutputStream os = new ByteArrayOutputStream();
451          enveloped_data.writeTo(os, 2048);
452          byte[] enc = os.toByteArray();
453          return enc;
454    
455      }
456    
457      /**
458       * Decrypts the encrypted content of the given PKCS#7 <code>EnvelopedData</code> object for the
459       * specified recipient and returns the decrypted (= original) message.
460       *
461       * @param encoding the <code>EnvelopedData</code> object as DER encoded byte array
462       * @param privateKey the private key to decrypt the message
463       * @param recipientInfoIndex the index into the <code>RecipientInfo</code> array
464       *                           to which the specified private key belongs
465       *
466       * @return the recovered message, as byte array
467       * @throws Exception if the message cannot be recovered
468       */
469      public byte[] getPKCS7EnvelopedDataStream(byte[] encoding, PrivateKey privateKey, int recipientInfoIndex) throws Exception {
470    
471        // create the EnvelopedData object from a DER encoded byte array
472        // we are testing the stream interface
473        ByteArrayInputStream is = new ByteArrayInputStream(encoding);
474        iaik.pkcs.pkcs7.EnvelopedDataStream enveloped_data = new iaik.pkcs.pkcs7.EnvelopedDataStream(is);
475    
476        AlgorithmParameterSpec params = null;
477        // get the recipient infos
478        iaik.pkcs.pkcs7.RecipientInfo[]  recipients = enveloped_data.getRecipientInfos();
479    
480        System.out.println("\nThis message can be decrypted by the owners of the following certificates:");
481    
482        for (int i=0; i<recipients.length; i++) {
483          System.out.println("Recipient "+(i+1)+":");
484          System.out.println(recipients[i].getIssuerAndSerialNumber());
485        }
486        // decrypt symmetric content encryption key, e.g.:
487        SecretKey secretKey = recipients[recipientInfoIndex].decryptKey(user1_pk);
488    
489        //get the ECI from the enveloped data:
490        iaik.pkcs.pkcs7.EncryptedContentInfoStream eci = (iaik.pkcs.pkcs7.EncryptedContentInfoStream)enveloped_data.getEncryptedContentInfo();
491        //get the content encryption algorithm:
492        AlgorithmID contentEA = eci.getContentEncryptionAlgorithm();
493        System.out.println("Content Encryption Algorithm: " + contentEA);
494        if (contentEA.equals(AlgorithmID.rc2_CBC)) {
495            // get the parameters as SEQUENCE
496            SEQUENCE seq = (SEQUENCE)contentEA.getParameter();
497            // the iv is the second component
498            OCTET_STRING oct = (OCTET_STRING)seq.getComponentAt(1);
499            // create an IvParameterSpec:
500            //params = new IvParameterSpec((byte[])oct.getValue());
501            int rc2ParameterVersion = ((BigInteger)seq.getComponentAt(0).getValue()).intValue();
502            int effective_key_bits = 32;
503            switch (rc2ParameterVersion) {
504                  case 160:
505                    effective_key_bits = 40;
506                    break;
507                  case 120:
508                    effective_key_bits = 64;
509                    break;
510                  case 58:
511                    effective_key_bits = 128;
512                    break;
513                  default:
514                    throw new Exception("Invalid rc2ParameterVersion " + rc2ParameterVersion + "!");
515    
516                 }
517                 params = new RC2ParameterSpec(effective_key_bits,(byte[])seq.getComponentAt(1).getValue());
518    
519          }
520          else if (contentEA.equals(AlgorithmID.rc5_CBC)) {
521             OCTET_STRING oct = (OCTET_STRING)contentEA.getParameter();
522             // create an IvParameterSpec:
523             params = new IvParameterSpec((byte[])oct.getValue());
524          } else if (contentEA.equals(AlgorithmID.arcfour)) {
525             params = null;
526          } else if (contentEA.equals(AlgorithmID.cast5_CBC)) {
527             // get the parameters
528             ASN1Object asn1Params = contentEA.getParameter();
529             if (asn1Params.isA(ASN.SEQUENCE)) {
530               // the iv is the first component
531               params = new IvParameterSpec((byte[])asn1Params.getComponentAt(0).getValue());
532             } else {
533               // to be compatible with (invalid) CAST AlgorithmIDs only using the IV as parameters
534               params = new IvParameterSpec((byte[])asn1Params.getValue());
535             }  
536          } else {
537             throw new Exception("Algorithm " + contentEA + " not supportted for this test!");
538          }
539    
540    
541          //now setup the cipher with previously decrypted recipient key amd params
542          eci.setupCipher(secretKey, params);
543          //get and read the data thereby actually performing the decryption
544          InputStream data_is = eci.getInputStream();
545          ByteArrayOutputStream baos = new ByteArrayOutputStream();
546          Util.copyStream(data_is, baos, null);
547          byte[] decrypted = baos.toByteArray();
548          return decrypted;
549    
550      }
551    
552    
553    
554      /**
555       * Starts the test.
556       */
557      public void start() {
558         // the test message
559        String m = "This is the test message.";
560        System.out.println("Test message: \""+m+"\"");
561        System.out.println();
562        byte[] message = m.getBytes();
563    
564        try {
565          byte[] data;
566          byte[] received_message = null;
567    
568    
569          // the stream implementation
570          //
571          // test CMS EnvelopedDataStream
572          //
573    
574          // ARCFOUR
575          System.out.println("\nEnvelopedDataStream demo for algorithm ARCFOUR [create]:\n");
576          data = createEnvelopedDataStream(message, (AlgorithmID)AlgorithmID.arcfour.clone(), 128);
577          // transmit data
578          System.out.println("\nEnvelopedDataStream demo [parse]:\n");
579          // user1 means index 0 (hardcoded for this demo)
580          received_message = getEnvelopedDataStream(data, user1_pk, 0);
581          System.out.print("\nDecrypted content: ");
582          System.out.println(new String(received_message));
583    
584          // RC2
585          System.out.println("\nEnvelopedDataStream demo for algorithm RC2 [create]:\n");
586          data = createEnvelopedDataStream(message, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 128);
587          // transmit data
588          System.out.println("\nEnvelopedDataStream demo [parse]:\n");
589          // user1 means index 0 (hardcoded for this demo)
590          received_message = getEnvelopedDataStream(data, user1_pk, 0);
591          System.out.print("\nDecrypted content: ");
592          System.out.println(new String(received_message));
593    
594          // CAST5_CBC
595          System.out.println("\nEnvelopedDataStream demo for algorithm CAST5_CBC [create]:\n");
596          data = createEnvelopedDataStream(message, (AlgorithmID)AlgorithmID.cast5_CBC.clone(), 128);
597          // transmit data
598          System.out.println("\nEnvelopedDataStream demo [parse]:\n");
599          // user1 means index 0 (hardcoded for this demo)
600          received_message = getEnvelopedDataStream(data, user1_pk, 0);
601          System.out.print("\nDecrypted content: ");
602          System.out.println(new String(received_message));
603          
604          // CMS <---> PKCS#7
605          
606          System.out.println("Test compatibility to PKCS#7....");
607          
608          // ARCFOUR
609          System.out.println("\nCMS EnvelopedDataStream demo for algorithm ARCFOUR [create]:\n");
610          data = createEnvelopedDataStream(message, (AlgorithmID)AlgorithmID.arcfour.clone(), 128);
611          // transmit data
612          System.out.println("\nPKCS#7 EnvelopedDataStream demo [parse]:\n");
613          // user1 means index 0 (hardcoded for this demo)
614          received_message = getPKCS7EnvelopedDataStream(data, user1_pk, 0);
615          System.out.print("\nDecrypted content: ");
616          System.out.println(new String(received_message));
617          
618          System.out.println("\nPKCS#7 EnvelopedDataStream demo for algorithm ARCFOUR [create]:\n");
619          data = createPKCS7EnvelopedDataStream(message, (AlgorithmID)AlgorithmID.arcfour.clone(), 128);
620          // transmit data
621          System.out.println("\nCMS EnvelopedDataStream demo [parse]:\n");
622          // user1 means index 0 (hardcoded for this demo)
623          received_message = getEnvelopedDataStream(data, user1_pk, 0);
624          System.out.print("\nDecrypted content: ");
625          System.out.println(new String(received_message));
626    
627    
628          // RC2
629          System.out.println("\nCMS EnvelopedDataStream demo for algorithm RC2 [create]:\n");
630          data = createEnvelopedDataStream(message, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 128);
631          // transmit data
632          System.out.println("\nPKCS#7 EnvelopedDataStream demo [parse]:\n");
633          // user1 means index 0 (hardcoded for this demo)
634          received_message = getPKCS7EnvelopedDataStream(data, user1_pk, 0);
635          System.out.print("\nDecrypted content: ");
636          System.out.println(new String(received_message));
637          
638          System.out.println("\nPKCS#7 EnvelopedDataStream demo for algorithm RC2 [create]:\n");
639          data = createPKCS7EnvelopedDataStream(message, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 128);
640          // transmit data
641          System.out.println("\nCMS EnvelopedDataStream demo [parse]:\n");
642          // user1 means index 0 (hardcoded for this demo)
643          received_message = getEnvelopedDataStream(data, user1_pk, 0);
644          System.out.print("\nDecrypted content: ");
645          System.out.println(new String(received_message));
646    
647          // CAST5_CBC
648          System.out.println("\nCMS EnvelopedDataStream demo for algorithm CAST5_CBC [create]:\n");
649          data = createEnvelopedDataStream(message, (AlgorithmID)AlgorithmID.cast5_CBC.clone(), 128);
650          // transmit data
651          System.out.println("\nPKCS#7 EnvelopedDataStream demo [parse]:\n");
652          // user1 means index 0 (hardcoded for this demo)
653          received_message = getPKCS7EnvelopedDataStream(data, user1_pk, 0);
654          System.out.print("\nDecrypted content: ");
655          System.out.println(new String(received_message));
656          
657          System.out.println("\nPKCS#7 EnvelopedDataStream demo for algorithm CAST5_CBC [create]:\n");
658          data = createPKCS7EnvelopedDataStream(message, (AlgorithmID)AlgorithmID.cast5_CBC.clone(), 128);
659          // transmit data
660          System.out.println("\nCMS EnvelopedDataStream demo [parse]:\n");
661          // user1 means index 0 (hardcoded for this demo)
662          received_message = getEnvelopedDataStream(data, user1_pk, 0);
663          System.out.print("\nDecrypted content: ");
664          System.out.println(new String(received_message));
665    
666            } catch (Exception ex) {
667              ex.printStackTrace();
668              throw new RuntimeException(ex.toString());
669            }
670      }
671    
672      /**
673       * The main method.
674       *
675       * @throws IOException
676       *            if an I/O error occurs when reading required keys
677       *            and certificates from files
678       */
679      public static void main(String argv[]) throws Exception {
680    
681            DemoUtil.initDemos();
682    
683        (new PKCS7CMSEncryptedContentInfoDemo()).start();
684        System.out.println("\nReady!");
685        DemoUtil.waitKey();
686      }
687    }