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/smime/basic/ProcessMessageDemo.java 20    12.02.25 17:58 Dbratko $
059    // $Revision: 20 $
060    //
061    
062    package demo.smime.basic;
063    
064    import iaik.asn1.structures.AlgorithmID;
065    import iaik.cms.CMSAlgorithmID;
066    import iaik.smime.CompressedContent;
067    import iaik.smime.EncryptedContent;
068    import iaik.smime.SMimeBodyPart;
069    import iaik.smime.SMimeMultipart;
070    import iaik.smime.SMimeParameters;
071    import iaik.smime.SignedContent;
072    import iaik.x509.X509Certificate;
073    
074    import java.io.ByteArrayInputStream;
075    import java.io.ByteArrayOutputStream;
076    import java.io.IOException;
077    import java.security.NoSuchAlgorithmException;
078    import java.security.PrivateKey;
079    import java.security.interfaces.RSAPrivateKey;
080    import java.util.Date;
081    
082    import javax.activation.DataHandler;
083    import javax.activation.FileDataSource;
084    import javax.mail.Message;
085    import javax.mail.MessagingException;
086    import javax.mail.Multipart;
087    import javax.mail.Session;
088    import javax.mail.internet.InternetAddress;
089    import javax.mail.internet.MimeBodyPart;
090    import javax.mail.internet.MimeMessage;
091    
092    import demo.DemoSMimeUtil;
093    import demo.DemoUtil;
094    import demo.keystore.CMSKeyStore;
095    import demo.smime.DumpMessage;
096    
097    /**
098     * This class demonstrates the usage of the IAIK S/MIME implementation for 
099     * cryptographically processing (e.g. signing or encrypting) a received
100     * message. Since the message to be processed has a -- already canonicalized --
101     * multipart content, the SMimeMultipart/SMimeBodyPart control can be disabled
102     * either globally for the whole application:
103     * <pre>
104     * SMimeParameters.setCheckForSMimeParts(false);
105     * </pre>
106     * or only for the specific SignedContent object(s) in use:
107     * <pre>
108     * SignedContent sc = ...;
109     * sc.checkForSMimeParts(false);
110     * ...
111     * </pre>
112     * To run this demo the following packages are required:
113     * <ul>
114     *    <li>
115     *       <code>iaik_cms.jar</code> (IAIK-CMS/SMIME)
116     *    </li>
117     *    <li>
118     *       <code>iaik_jce(_full).jar</code> (<a href="https://sic.tech/products/core-crypto-toolkits/jca-jce/" target="_blank">IAIK-JCE Core Crypto Library</a>).
119     *    </li>
120     *    <li>
121     *       <code>mail.jar</code> (<a href="http://www.oracle.com/technetwork/java/javamail/index.html" target="_blank">JavaMail API</a>).
122     *    </li>   
123     *    <li>
124     *       <code>activation.jar</code> (<a href="http://www.oracle.com/technetwork/java/javase/downloads/index-135046.html" target="_blank">Java Activation Framework</a>; required for JDK versions &lt; 1.6).
125     *    </li> 
126     * </ul>
127     */
128    public class ProcessMessageDemo {
129        
130      // whether to print all generates test messages to System.out
131      final static boolean PRINT_MESSAGES = true;   
132    
133      String firstName = "John";
134      String lastName = "SMime";
135      String to = "smimetest@iaik.at";               // email recipient
136      String from = "smimetest@iaik.at";             // email sender
137      String host = "mailhost";                      // name of the mailhost
138    
139      X509Certificate[] signerCertificates;          // list of certificates to include in the S/MIME message
140      X509Certificate recipientCertificate;          // certificate of the recipient
141      X509Certificate signerCertificate;             // certificate of the signer/sender
142      X509Certificate encryptionCertOfSigner;        // signer uses different certificate for encryption
143      PrivateKey signerPrivateKey;                   // private key of the signer/sender
144      
145      /**
146       * Default constructor. Reads certificates and keys from the demo keystore.
147       */
148      public ProcessMessageDemo() {
149        
150        System.out.println();
151        System.out.println("******************************************************************************************");
152        System.out.println("*                                 ProcessMessageDemo                                     *");
153        System.out.println("*      (shows how to cryptographically process (sign, verify) an existing message)       *");
154        System.out.println("******************************************************************************************");
155        System.out.println();
156        
157        // get the certificates from the KeyStore
158        signerCertificates = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
159        signerPrivateKey = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
160        signerCertificate = signerCertificates[0];
161    
162        // recipient = signer for this test
163        recipientCertificate = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0];
164        encryptionCertOfSigner = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0];
165        
166        // we will cryptographically process an already existing (canonicalized)
167        // message and therefore can disable SMimeMultipart/SMimeBodyPart control
168        SMimeParameters.setCheckForSMimeParts(false);
169      }
170      
171      /**
172       * Starts the demo.
173       *
174       * @throws IOException if an I/O related error occurs
175       */
176      public void start() throws IOException {
177    
178            // get the default Session
179            Session session = DemoSMimeUtil.getSession();
180    
181            try {
182          // Create a demo Multipart
183          MimeBodyPart mbp1 = new SMimeBodyPart();
184          mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n");
185                // attachment
186          MimeBodyPart attachment = new SMimeBodyPart();
187          attachment.setDataHandler(new DataHandler(new FileDataSource("test.html")));
188          attachment.setFileName("test.html");
189            
190          Multipart mp = new SMimeMultipart();
191          mp.addBodyPart(mbp1);
192          mp.addBodyPart(attachment);
193          DataHandler multipart = new DataHandler(mp, mp.getContentType());
194    
195          Message msg;    // the message to send
196          ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
197          ByteArrayInputStream bais;  // we read from a stream
198    
199          // Create the plain test message
200          msg = createPlainMessage(session, multipart);
201          System.out.println("creating plain message...");
202                msg.saveChanges();
203                msg.writeTo(baos);
204                bais = new ByteArrayInputStream(baos.toByteArray());
205                msg = new MimeMessage(session, bais);
206                if (PRINT_MESSAGES) {
207            printMessage(msg);
208          }
209              DumpMessage.dumpMsg(msg);
210          // the plain message to be crytographically processed
211          MimeMessage plainMessage = (MimeMessage)msg;
212              
213                System.out.println("\n\n*****************************************\n\n");
214          
215          // include RFC822 headers of original message
216          boolean includeHeaders = true;
217          // This is an explicitly signed message
218          msg = createSignedMessage(session, plainMessage, false, includeHeaders);
219          System.out.println("creating explicitly signed message...");
220          baos.reset();
221                msg.saveChanges();
222                msg.writeTo(baos);
223                bais = new ByteArrayInputStream(baos.toByteArray());
224                msg = new MimeMessage(session, bais);
225                if (PRINT_MESSAGES) {
226            printMessage(msg);
227          }
228              DumpMessage.dumpMsg(msg);
229       
230          System.out.println("\n\n*****************************************\n\n");
231    
232          // This is an implicitly signed message
233          msg = createSignedMessage(session, plainMessage, true, includeHeaders);
234          System.out.println("creating implicitly signed message...");
235                baos.reset();
236                msg.saveChanges();
237                msg.writeTo(baos);
238                bais = new ByteArrayInputStream(baos.toByteArray());
239                msg = new MimeMessage(session, bais);
240                if (PRINT_MESSAGES) {
241            printMessage(msg);
242          }
243          DumpMessage.dumpMsg(msg);
244              
245              System.out.println("\n\n*****************************************\n\n");
246    
247          // Now create an encrypted message
248          msg = createEncryptedMessage(session, 
249                                       plainMessage,
250                                       (AlgorithmID)AlgorithmID.aes256_CBC.clone(),
251                                       256, 
252                                       includeHeaders);
253          System.out.println("creating encrypted message [AES]...");
254              baos.reset();
255              msg.saveChanges();
256              msg.writeTo(baos);
257              bais = new ByteArrayInputStream(baos.toByteArray());
258              msg = new MimeMessage(session, bais);
259              if (PRINT_MESSAGES) {
260              printMessage(msg);
261            }
262              DumpMessage.dumpMsg(msg);
263              
264              System.out.println("\n\n*****************************************\n\n");
265    
266          // Now create a implicitly signed and encrypted message with attachment
267              System.out.println("creating implicitly signed and encrypted message...");
268          msg = createSignedAndEncryptedMessage(session,
269                                                plainMessage,
270                                                true,
271                                                includeHeaders);
272        
273              baos.reset();
274              msg.saveChanges();
275              msg.writeTo(baos);
276              bais = new ByteArrayInputStream(baos.toByteArray());
277              msg = new MimeMessage(session, bais);
278              if (PRINT_MESSAGES) {
279              printMessage(msg);
280            }
281              DumpMessage.dumpMsg(msg);
282              
283              System.out.println("\n\n*****************************************\n\n");
284    
285          // Now create a explicitly signed and encrypted message with attachment
286              System.out.println("creating explicitly signed and encrypted message ...");
287          msg = createSignedAndEncryptedMessage(session, plainMessage, false, includeHeaders);
288          baos.reset();
289              msg.saveChanges();
290              msg.writeTo(baos);
291              bais = new ByteArrayInputStream(baos.toByteArray());
292              msg = new MimeMessage(session, bais);
293              if (PRINT_MESSAGES) {
294            printMessage(msg);
295          }
296              DumpMessage.dumpMsg(msg);
297              
298              System.out.println("\n\n*****************************************\n\n");
299      
300              // compressed message 
301              msg = createCompressedMessage(session, 
302                                        plainMessage, 
303                                        (AlgorithmID)CMSAlgorithmID.zlib_compress.clone(), 
304                                        includeHeaders);
305              System.out.println("creating message with compressed data...");
306              baos.reset();
307              msg.saveChanges();
308              msg.writeTo(baos);
309              bais = new ByteArrayInputStream(baos.toByteArray());
310              msg = new MimeMessage(session, bais);
311              if (PRINT_MESSAGES) {
312            printMessage(msg);
313          }
314              DumpMessage.dumpMsg(msg);
315          
316          
317          // now the same again but do not include RFC822 headers of original message
318          includeHeaders = false;
319          // This is an explicitly signed message
320          msg = createSignedMessage(session, plainMessage, false, includeHeaders);
321          System.out.println("creating explicitly signed message...");
322          baos.reset();
323          msg.saveChanges();
324          msg.writeTo(baos);
325          bais = new ByteArrayInputStream(baos.toByteArray());
326          msg = new MimeMessage(session, bais);
327          if (PRINT_MESSAGES) {
328            printMessage(msg);
329          }
330          DumpMessage.dumpMsg(msg);
331        
332          System.out.println("\n\n*****************************************\n\n");
333    
334    
335          // This is an implicitly signed message
336          msg = createSignedMessage(session, plainMessage, true, includeHeaders);
337          System.out.println("creating implicitly signed message...");
338          baos.reset();
339          msg.saveChanges();
340          msg.writeTo(baos);
341          bais = new ByteArrayInputStream(baos.toByteArray());
342          msg = new MimeMessage(session, bais);
343          if (PRINT_MESSAGES) {
344            printMessage(msg);
345          }
346          DumpMessage.dumpMsg(msg);
347        
348          System.out.println("\n\n*****************************************\n\n");
349    
350          // Now create an encrypted message
351          msg = createEncryptedMessage(session, 
352                                       plainMessage, 
353                                       (AlgorithmID)AlgorithmID.aes256_CBC.clone(),
354                                       256,
355                                       includeHeaders);
356          System.out.println("creating encrypted message [AES]...");
357          baos.reset();
358          msg.saveChanges();
359          msg.writeTo(baos);
360          bais = new ByteArrayInputStream(baos.toByteArray());
361          msg = new MimeMessage(session, bais);
362          if (PRINT_MESSAGES) {
363            printMessage(msg);
364          }
365          DumpMessage.dumpMsg(msg);
366          
367          System.out.println("\n\n*****************************************\n\n");
368    
369          // Now create a implicitly signed and encrypted message with attachment
370          System.out.println("creating implicitly signed and encrypted message ...");
371          msg = createSignedAndEncryptedMessage(session, plainMessage, true, includeHeaders);
372          baos.reset();
373          msg.saveChanges();
374          msg.writeTo(baos);
375          bais = new ByteArrayInputStream(baos.toByteArray());
376          msg = new MimeMessage(session, bais);
377          if (PRINT_MESSAGES) {
378            printMessage(msg);
379          }
380          DumpMessage.dumpMsg(msg);
381          
382          System.out.println("\n\n*****************************************\n\n");
383    
384          // Now create a explicitly signed and encrypted message with attachment
385          System.out.println("creating explicitly signed and encrypted message...");
386          msg = createSignedAndEncryptedMessage(session, plainMessage, false, includeHeaders);
387          baos.reset();
388          msg.saveChanges();
389          msg.writeTo(baos);
390          bais = new ByteArrayInputStream(baos.toByteArray());
391          msg = new MimeMessage(session, bais);
392          if (PRINT_MESSAGES) {
393            printMessage(msg);
394          }
395          DumpMessage.dumpMsg(msg);
396          
397          System.out.println("\n\n*****************************************\n\n");
398      
399          // compressed message 
400          msg = createCompressedMessage(session, 
401                                        plainMessage,
402                                        (AlgorithmID)CMSAlgorithmID.zlib_compress.clone(),
403                                        includeHeaders);
404          System.out.println("creating message with compressed data...");
405          baos.reset();
406          msg.saveChanges();
407          msg.writeTo(baos);
408          bais = new ByteArrayInputStream(baos.toByteArray());
409          msg = new MimeMessage(session, bais);
410          if (PRINT_MESSAGES) {
411            printMessage(msg);
412          }
413          DumpMessage.dumpMsg(msg);
414      
415        } catch (Exception ex) {
416              ex.printStackTrace();
417              throw new RuntimeException(ex.toString());
418        }
419      }
420      
421      /**
422       * Creates a MIME message container with the given subject for the given session.
423       * 
424       * @param session the mail sesion
425       * @param subject the subject of the message
426       *
427       * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content)
428       *
429       * @throws MessagingException if the message cannot be created
430       */
431      public Message createMessage(Session session, String subject) throws MessagingException {
432        MimeMessage msg = new MimeMessage(session);
433        msg.setFrom(new InternetAddress(from));
434            msg.setRecipients(Message.RecipientType.TO,     InternetAddress.parse(to, false));
435            msg.setSentDate(new Date());
436        msg.setSubject(subject);
437        return msg;
438      }
439      
440      /**
441       * Creates a simple plain (neither signed nor encrypted) message.
442       *
443       * @param session the mail session
444       * @param dataHandler the content of the message
445       * 
446       * @return the plain message
447       *
448       * @throws MessagingException if an error occurs when creating the message
449       */
450      public Message createPlainMessage(Session session, DataHandler dataHandler) throws MessagingException {
451    
452        Message msg = createMessage(session, "IAIK-S/MIME: Plain message");
453        if (dataHandler != null) {
454          msg.setDataHandler(dataHandler);
455        } else {
456          msg.setText("This is a plain message!\nIt is wether signed nor encrypted!\n");
457        }
458            return msg;
459      }
460      
461      /**
462       * Creates a signed and encrypted message.
463       *
464       * @param session the mail session
465       * @param message the message to be signed and encrypted
466       * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
467       *                 (multipart/signed) signing
468       * @param includeHeaders whether to inlcude the RFC822 headers of the original
469       *                       message   
470       *  
471       * @return the signed and encrypted message
472       *
473       * @throws MessagingException if an error occurs when creating the message
474       */
475      public Message createSignedAndEncryptedMessage(Session session, 
476                                                     MimeMessage message, 
477                                                     boolean implicit,
478                                                     boolean includeHeaders)
479        throws MessagingException {
480    
481        String subject = null;
482        String text = null;
483        if (implicit) {
484          subject = "IAIK-S/MIME: Implicitly Signed and Encrypted";
485          text = "This message is implicitly signed and encrypted!\n\n\n";
486        } else {
487          subject = "IAIK-S/MIME: Explicitly Signed and Encrypted";
488          text = "This message is explicitly signed and encrypted!\n\n\n";
489        }
490        Message msg = createMessage(session, subject);
491    
492        SignedContent sc = new SignedContent(implicit);
493        // set the message content
494        if (includeHeaders) {
495          sc.setContent(message, message.getContentType());
496        } else {
497          sc.setDataHandler(message.getDataHandler());
498        }
499        sc.setCertificates(signerCertificates);
500        try {
501          sc.addSigner((RSAPrivateKey)signerPrivateKey, signerCertificate);
502        } catch (NoSuchAlgorithmException ex) {
503          throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
504        }
505    
506        EncryptedContent ec = new EncryptedContent(sc);
507        // encrypt for the recipient
508        ec.addRecipient(recipientCertificate, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
509        // I want to be able to decrypt the message, too
510        ec.addRecipient(encryptionCertOfSigner, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
511        // set the encryption algorithm
512        try {
513          ec.setEncryptionAlgorithm((AlgorithmID)AlgorithmID.aes256_CBC.clone(), 256);
514        } catch (NoSuchAlgorithmException ex) {
515          throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
516        }   
517        msg.setContent(ec, ec.getContentType());
518        // let the EncryptedContent update some message headers
519        ec.setHeaders(msg);
520    
521        return msg;
522      }
523      
524      /**
525       * Creates a signed message.
526       *
527       * @param session the mail session
528       * @param message the message to be signed
529       * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
530       *                 (multipart/signed) signing
531       * @param includeHeaders whether to inlcude the RFC822 headers of the original
532       *                       message
533       * 
534       * @return the signed message
535       *
536       * @throws MessagingException if an error occurs when creating the message
537       */
538      public Message createSignedMessage(Session session, 
539                                         MimeMessage message,
540                                         boolean implicit,
541                                         boolean includeHeaders)
542        throws Exception {
543    
544        String subject = null;
545        
546        if (implicit) {
547          subject = "IAIK-S/MIME: Implicitly Signed";
548        } else {
549          subject = "IAIK-S/MIME: Explicitly Signed";
550        }
551        
552        Message msg = createMessage(session, subject);
553    
554        SignedContent sc = new SignedContent(implicit);
555        // set message content
556        if (includeHeaders) {
557          sc.setContent(message, message.getContentType());
558        } else {
559          sc.setDataHandler(message.getDataHandler());
560        }
561        sc.setCertificates(signerCertificates);
562    
563        try {
564          sc.addSigner((RSAPrivateKey)signerPrivateKey, signerCertificate);
565        } catch (NoSuchAlgorithmException ex) {
566          throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
567        }
568    
569        msg.setContent(sc, sc.getContentType());
570        // let the SignedContent update some message headers
571        sc.setHeaders(msg);
572        return msg;
573      }
574      
575      /**
576       * Creates an encrypted message.
577       *
578       * @param session the mail session
579       * @param message the message to be encrypted
580       * @param algorithm the content encryption algorithm to be used
581       * @param keyLength the length of the secret content encryption key to be created and used
582       * @param includeHeaders whether to inlcude the RFC822 headers of the original
583       *                       message 
584       * 
585       * @return the encrypted message
586       *
587       * @throws MessagingException if an error occurs when creating the message
588       */
589      public Message createEncryptedMessage(Session session, 
590                                            MimeMessage message, 
591                                            AlgorithmID algorithm, 
592                                            int keyLength,
593                                            boolean includeHeaders)
594        throws MessagingException {
595    
596        StringBuffer subject = new StringBuffer();
597        subject.append("IAIK-S/MIME: Encrypted ["+algorithm.getName());
598        if (keyLength > 0) {
599          subject.append("/"+keyLength);
600        }  
601        subject.append("]");
602        Message msg = createMessage(session, subject.toString());
603    
604        EncryptedContent ec = new EncryptedContent();
605        // set message content
606        if (includeHeaders) {
607          ec.setContent(message, message.getContentType());
608        } else {
609          ec.setDataHandler(message.getDataHandler());
610        }
611        
612        // encrypt for the recipient
613        ec.addRecipient(recipientCertificate, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
614        // I want to be able to decrypt the message, too
615        ec.addRecipient(encryptionCertOfSigner, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
616        try {
617          ec.setEncryptionAlgorithm(algorithm, keyLength);
618        } catch (NoSuchAlgorithmException ex) {
619          throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
620        }   
621    
622        msg.setContent(ec, ec.getContentType());
623        // let the EncryptedContent update some message headers
624        ec.setHeaders(msg);
625    
626        return msg;
627      }
628      
629        
630      /**
631       * Creates a compressed message.
632       *
633       * @param session the mail session
634       * @param message the message to be compressed
635       * @param algorithm the compression algorithm to be used
636       * @param includeHeaders whether to inlcude the RFC822 headers of the original
637       *                       message   
638       *  
639       * @return the compressed message
640       *
641       * @throws MessagingException if an error occurs when creating the message
642       */
643      public Message createCompressedMessage(Session session, 
644                                             MimeMessage message,
645                                             AlgorithmID algorithm,
646                                             boolean includeHeaders)
647        throws MessagingException {
648    
649        String subject = "IAIK-S/MIME: Compressed ["+algorithm.getName()+"]";
650        Message msg = createMessage(session, subject.toString());
651    
652        CompressedContent compressedContent = new CompressedContent();
653        // set message content
654        if (includeHeaders) {
655          compressedContent.setContent(message, message.getContentType());
656        } else {
657          compressedContent.setDataHandler(message.getDataHandler());
658        }
659        
660        try {
661          compressedContent.setCompressionAlgorithm(algorithm);
662        } catch (NoSuchAlgorithmException ex) {
663          throw new MessagingException("Compression algorithm not supported: " + ex.getMessage());   
664        }   
665    
666        msg.setContent(compressedContent, compressedContent.getContentType());
667        // let the CompressedContent update some message headers
668        compressedContent.setHeaders(msg);
669    
670        return msg;
671      }
672      
673        
674      
675      /** 
676       * Prints a dump of the given message to System.out.
677       *
678       * @param msg the message to be dumped to System.out
679       */
680      private static void printMessage(Message msg) throws IOException {
681        System.out.println("------------------------------------------------------------------");
682        System.out.println("Message dump: \n");
683        try {
684          msg.writeTo(System.out);
685        } catch (MessagingException ex) {
686          throw new IOException(ex.getMessage());   
687        }    
688        System.out.println("\n------------------------------------------------------------------");
689      }  
690    
691    
692      /**
693       * The main method.
694       */
695      public static void main(String[] argv) throws IOException {
696    
697        DemoSMimeUtil.initDemos();
698            (new ProcessMessageDemo()).start();
699        System.out.println("\nReady!");
700        DemoUtil.waitKey();
701      }
702    }