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/SMimeDemo.java 53    12.02.25 17:58 Dbratko $
059    // $Revision: 53 $
060    //
061    
062    package demo.smime.basic;
063    
064    import java.io.ByteArrayInputStream;
065    import java.io.ByteArrayOutputStream;
066    import java.io.IOException;
067    import java.security.NoSuchAlgorithmException;
068    import java.security.PrivateKey;
069    import java.security.interfaces.RSAPrivateKey;
070    import java.util.Date;
071    
072    import javax.activation.DataHandler;
073    import javax.activation.FileDataSource;
074    import javax.mail.Message;
075    import javax.mail.MessagingException;
076    import javax.mail.Multipart;
077    import javax.mail.Session;
078    import javax.mail.internet.InternetAddress;
079    import javax.mail.internet.MimeBodyPart;
080    import javax.mail.internet.MimeMessage;
081    import javax.mail.internet.MimeMultipart;
082    
083    import demo.DemoSMimeUtil;
084    import demo.DemoUtil;
085    import demo.keystore.CMSKeyStore;
086    import demo.smime.DumpMessage;
087    import iaik.asn1.ObjectID;
088    import iaik.asn1.structures.AlgorithmID;
089    import iaik.asn1.structures.Name;
090    import iaik.cms.CMSAlgorithmID;
091    import iaik.pkcs.PKCSException;
092    import iaik.pkcs.pkcs10.CertificateRequest;
093    import iaik.smime.AuthEncryptedContent;
094    import iaik.smime.CompressedContent;
095    import iaik.smime.EncryptedContent;
096    import iaik.smime.PKCS10Content;
097    import iaik.smime.SMimeBodyPart;
098    import iaik.smime.SMimeMultipart;
099    import iaik.smime.SMimeParameters;
100    import iaik.smime.SignedContent;
101    import iaik.x509.X509Certificate;
102    
103    /**
104     * This class demonstrates the usage of the IAIK S/MIME implementation. It shows how to create
105     * signed and/or encrypted S/MIME messages and how to parse them and verify the signatures 
106     * and decrypt the content, respectively.
107     * <p>
108     * To run this demo the following packages are required:
109     * <ul>
110     *    <li>
111     *       <code>iaik_cms.jar</code>
112     *    </li>
113     *    <li>
114     *       <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>).
115     *    </li>
116     *    <li>
117     *       <code>mail.jar</code> (<a href="http://www.oracle.com/technetwork/java/javamail/index.html" target="_blank">JavaMail API</a>).
118     *    </li>   
119     *    <li>
120     *       <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).
121     *    </li> 
122     * </ul>
123     */
124    public class SMimeDemo {
125        
126      // whether to print dump all generates test messages to System.out
127      final static boolean PRINT_MESSAGES = false;   
128    
129      String firstName_ = "John";                     // name of sender
130      String lastName_ = "SMime";
131      String from_ = "smimetest@iaik.tugraz.at";      // email sender
132      String to_ = "smimetest@iaik.tugraz.at";        // email recipient
133      String host_ = "mailhost";                      // name of the mailhost
134    
135      X509Certificate[] signerCertificates_;          // list of certificates to include in the S/MIME message
136      X509Certificate recipientCertificate_;          // certificate of the recipient
137      X509Certificate signerCertificate_;             // certificate of the signer/sender
138      X509Certificate encryptionCertOfSigner_;        // signer uses different certificate for encryption
139      PrivateKey signerPrivateKey_;                   // private key of the signer/sender
140      
141      /**
142       * Default constructor. Reads certificates and keys from the demo keystore.
143       */
144      public SMimeDemo() {
145        
146        System.out.println();
147        System.out.println("******************************************************************************************");
148        System.out.println("*                                 SMimeDemo demo                                         *");
149        System.out.println("* (shows how to create and parse (verify, decrypt) signed and encrypted S/MIME messages) *");
150        System.out.println("******************************************************************************************");
151        System.out.println();
152        
153        // get the certificates from the KeyStore
154        signerCertificates_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
155        signerPrivateKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
156        signerCertificate_ = signerCertificates_[0];
157    
158        // recipient = signer for this test
159        recipientCertificate_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0];
160        encryptionCertOfSigner_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0];
161      }
162      
163      /**
164       * Starts the demo.
165       *
166       * @throws IOException if an I/O related error occurs
167       */
168      public void start() throws IOException {
169    
170            // get the default Session
171            Session session = DemoSMimeUtil.getSession();
172    
173            try {
174          // Create a demo Multipart
175          MimeBodyPart mbp1 = new SMimeBodyPart();
176          mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n");
177              // attachment
178          MimeBodyPart attachment = new SMimeBodyPart();
179          attachment.setDataHandler(new DataHandler(new FileDataSource("test.html")));
180          attachment.setFileName("test.html");
181            
182          Multipart mp = new SMimeMultipart();
183          mp.addBodyPart(mbp1);
184          mp.addBodyPart(attachment);
185          DataHandler multipart = new DataHandler(mp, mp.getContentType());
186    
187          Message msg;    // the message to send
188          ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
189          ByteArrayInputStream bais;  // we read from a stream
190    
191          // 1. This is a plain message
192          msg = createPlainMessage(session, multipart);
193          System.out.println("creating plain message...");
194              msg.saveChanges();
195              msg.writeTo(baos);
196              bais = new ByteArrayInputStream(baos.toByteArray());
197              msg = new MimeMessage(session, bais);
198              if (PRINT_MESSAGES) {
199            printMessage(msg);
200          }
201              DumpMessage.dumpMsg(msg);
202              
203              System.out.println("\n\n*****************************************\n\n");
204    
205          // 2. This is an explicitly signed message
206          msg = createSignedMessage(session, multipart, false);
207          System.out.println("creating explicitly signed message...");
208          baos.reset();
209              msg.saveChanges();
210              msg.writeTo(baos);
211              bais = new ByteArrayInputStream(baos.toByteArray());
212              msg = new MimeMessage(session, bais);
213              if (PRINT_MESSAGES) {
214            printMessage(msg);
215          }
216              DumpMessage.dumpMsg(msg);
217              
218              System.out.println("\n\n*****************************************\n\n");
219    
220    
221          // 3. This is an implicitly signed message
222          msg = createSignedMessage(session, multipart, true);
223          System.out.println("creating implicitly signed message...");
224              baos.reset();
225              msg.saveChanges();
226              msg.writeTo(baos);
227              bais = new ByteArrayInputStream(baos.toByteArray());
228              msg = new MimeMessage(session, bais);
229              if (PRINT_MESSAGES) {
230            printMessage(msg);
231          }
232              DumpMessage.dumpMsg(msg);
233              
234              System.out.println("\n\n*****************************************\n\n");
235    
236          // 4. Now create encrypted messages with different content encryption algorithms
237              
238          // RC2 is deprecated; only demonstrated here
239          msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 40);
240          System.out.println("creating encrypted message [RC2/40]...");
241              baos.reset();
242              msg.saveChanges();
243              msg.writeTo(baos);
244              bais = new ByteArrayInputStream(baos.toByteArray());
245              msg = new MimeMessage(session, bais);
246              if (PRINT_MESSAGES) {
247            printMessage(msg);
248          }
249              DumpMessage.dumpMsg(msg);
250              
251              System.out.println("\n\n*****************************************\n\n");
252              
253              // RC2 is deprecated; only demonstrated here
254          msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 64);
255          System.out.println("creating encrypted message [RC2/64]...");
256              baos.reset();
257              msg.saveChanges();
258              msg.writeTo(baos);
259              bais = new ByteArrayInputStream(baos.toByteArray());
260              msg = new MimeMessage(session, bais);
261              if (PRINT_MESSAGES) {
262            printMessage(msg);
263          }
264              DumpMessage.dumpMsg(msg);
265              
266              System.out.println("\n\n*****************************************\n\n");
267              
268              // RC2 is deprecated; only demonstrated here
269          msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 128);
270          System.out.println("creating encrypted message [RC2/128]...");
271              baos.reset();
272              msg.saveChanges();
273              msg.writeTo(baos);
274              bais = new ByteArrayInputStream(baos.toByteArray());
275              msg = new MimeMessage(session, bais);
276              if (PRINT_MESSAGES) {
277            printMessage(msg);
278          }
279              DumpMessage.dumpMsg(msg);
280              
281              System.out.println("\n\n*****************************************\n\n");
282              
283              // DES EDE is deprecated; only demonstrated here
284          msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.des_EDE3_CBC.clone(), 192);
285          System.out.println("creating encrypted message [TripleDES]...");
286              baos.reset();
287              msg.saveChanges();
288              msg.writeTo(baos);
289              bais = new ByteArrayInputStream(baos.toByteArray());
290              msg = new MimeMessage(session, bais);
291              if (PRINT_MESSAGES) {
292            printMessage(msg);
293          }
294              DumpMessage.dumpMsg(msg);
295              
296              System.out.println("\n\n*****************************************\n\n");
297          
298          msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CBC.clone(), 128);
299          System.out.println("creating encrypted message [AES/128]...");
300          baos.reset();
301          msg.saveChanges();
302          msg.writeTo(baos);
303          bais = new ByteArrayInputStream(baos.toByteArray());
304          msg = new MimeMessage(session, bais);
305          if (PRINT_MESSAGES) {
306            printMessage(msg);
307          }
308          DumpMessage.dumpMsg(msg);
309          
310          System.out.println("\n\n*****************************************\n\n");
311          
312          msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CBC.clone(), 192);
313          System.out.println("creating encrypted message [AES/192]...");
314          baos.reset();
315          msg.saveChanges();
316          msg.writeTo(baos);
317          bais = new ByteArrayInputStream(baos.toByteArray());
318          msg = new MimeMessage(session, bais);
319          if (PRINT_MESSAGES) {
320            printMessage(msg);
321          }
322          DumpMessage.dumpMsg(msg);
323          
324          System.out.println("\n\n*****************************************\n\n");
325          
326          msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), 256);
327          System.out.println("creating encrypted message [AES/256]...");
328          baos.reset();
329          msg.saveChanges();
330          msg.writeTo(baos);
331          bais = new ByteArrayInputStream(baos.toByteArray());
332          msg = new MimeMessage(session, bais);
333          if (PRINT_MESSAGES) {
334            printMessage(msg);
335          }
336          DumpMessage.dumpMsg(msg);
337          
338          System.out.println("\n\n*****************************************\n\n");
339        
340    
341          // 5. Now create a implicitly signed and encrypted message with attachment
342          msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), multipart, true);
343          System.out.println("creating implicitly signed and encrypted message [AES/256]...");
344              baos.reset();
345              msg.saveChanges();
346              msg.writeTo(baos);
347              bais = new ByteArrayInputStream(baos.toByteArray());
348              msg = new MimeMessage(session, bais);
349              if (PRINT_MESSAGES) {
350            printMessage(msg);
351          }
352              DumpMessage.dumpMsg(msg);
353              
354              System.out.println("\n\n*****************************************\n\n");
355    
356          // 6. Now create a explicitly signed and encrypted message with attachment
357          msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), multipart, false);
358          System.out.println("creating explicitly signed and encrypted message [AES/256]...");
359              baos.reset();
360              msg.saveChanges();
361              msg.writeTo(baos);
362              bais = new ByteArrayInputStream(baos.toByteArray());
363              msg = new MimeMessage(session, bais);
364              if (PRINT_MESSAGES) {
365            printMessage(msg);
366          }
367              DumpMessage.dumpMsg(msg);
368              
369              System.out.println("\n\n*****************************************\n\n");
370              
371              // 7. Authenticated encrypted message with several algorithms
372              if (DemoUtil.getIaikProviderVersion() >= 5.62) {
373            msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), 128);
374            System.out.println("creating encrypted message [AESGCM/128]...");
375            baos.reset();
376            msg.saveChanges();
377            msg.writeTo(baos);
378            bais = new ByteArrayInputStream(baos.toByteArray());
379            msg = new MimeMessage(session, bais);
380            if (PRINT_MESSAGES) {
381              printMessage(msg);
382            }
383            DumpMessage.dumpMsg(msg);
384            
385            System.out.println("\n\n*****************************************\n\n");
386            
387            msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_GCM.clone(), 192);
388            System.out.println("creating encrypted message [AESGCM/192]...");
389            baos.reset();
390            msg.saveChanges();
391            msg.writeTo(baos);
392            bais = new ByteArrayInputStream(baos.toByteArray());
393            msg = new MimeMessage(session, bais);
394            if (PRINT_MESSAGES) {
395              printMessage(msg);
396            }
397            DumpMessage.dumpMsg(msg);
398            
399            System.out.println("\n\n*****************************************\n\n");
400            
401            msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_GCM.clone(), 256);
402            System.out.println("creating encrypted message [AESGCM/256]...");
403            baos.reset();
404            msg.saveChanges();
405            msg.writeTo(baos);
406            bais = new ByteArrayInputStream(baos.toByteArray());
407            msg = new MimeMessage(session, bais);
408            if (PRINT_MESSAGES) {
409              printMessage(msg);
410            }
411            DumpMessage.dumpMsg(msg);
412            
413            msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), 256);
414            System.out.println("creating encrypted message [ChaCha20Poly1305]...");
415            baos.reset();
416            msg.saveChanges();
417            msg.writeTo(baos);
418            bais = new ByteArrayInputStream(baos.toByteArray());
419            msg = new MimeMessage(session, bais);
420            if (PRINT_MESSAGES) {
421              printMessage(msg);
422            }
423            DumpMessage.dumpMsg(msg);
424            
425            System.out.println("\n\n*****************************************\n\n");
426            
427            msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), 128);
428            System.out.println("creating encrypted message [AESCCM/128]...");
429            baos.reset();
430            msg.saveChanges();
431            msg.writeTo(baos);
432            bais = new ByteArrayInputStream(baos.toByteArray());
433            msg = new MimeMessage(session, bais);
434            if (PRINT_MESSAGES) {
435              printMessage(msg);
436            }
437            DumpMessage.dumpMsg(msg);
438            
439            System.out.println("\n\n*****************************************\n\n");
440            
441            msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CCM.clone(), 192);
442            System.out.println("creating encrypted message [AESCCM/192]...");
443            baos.reset();
444            msg.saveChanges();
445            msg.writeTo(baos);
446            bais = new ByteArrayInputStream(baos.toByteArray());
447            msg = new MimeMessage(session, bais);
448            if (PRINT_MESSAGES) {
449              printMessage(msg);
450            }
451            DumpMessage.dumpMsg(msg);
452            
453            System.out.println("\n\n*****************************************\n\n");
454            
455            msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CCM.clone(), 256);
456            System.out.println("creating encrypted message [AESCCM/256]...");
457            baos.reset();
458            msg.saveChanges();
459            msg.writeTo(baos);
460            bais = new ByteArrayInputStream(baos.toByteArray());
461            msg = new MimeMessage(session, bais);
462            if (PRINT_MESSAGES) {
463              printMessage(msg);
464            }
465            DumpMessage.dumpMsg(msg);
466            
467            System.out.println("\n\n*****************************************\n\n");
468            
469            // Now create a implicitly signed and authenticated encrypted message with attachment
470            msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), multipart, true);
471            System.out.println("creating implicitly signed and authenticated encrypted message [AES-GCM/128]...");
472            baos.reset();
473            msg.saveChanges();
474            msg.writeTo(baos);
475            bais = new ByteArrayInputStream(baos.toByteArray());
476            msg = new MimeMessage(session, bais);
477            if (PRINT_MESSAGES) {
478              printMessage(msg);
479            }
480            DumpMessage.dumpMsg(msg);
481            
482            System.out.println("\n\n*****************************************\n\n");
483    
484            // Now create a explicitly signed and authenticated encrypted message with attachment
485            msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), multipart, false);
486            System.out.println("creating explicitly signed and authenticated encrypted message [AES-GCM/128]...");
487            baos.reset();
488            msg.saveChanges();
489            msg.writeTo(baos);
490            bais = new ByteArrayInputStream(baos.toByteArray());
491            msg = new MimeMessage(session, bais);
492            if (PRINT_MESSAGES) {
493              printMessage(msg);
494            }
495            DumpMessage.dumpMsg(msg);
496            
497            System.out.println("\n\n*****************************************\n\n");
498            
499            // Now create a implicitly signed and authenticated encrypted message with attachment
500            msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), multipart, true);
501            System.out.println("creating implicitly signed and authenticated encrypted message [ChaChaPoly1305]...");
502            baos.reset();
503            msg.saveChanges();
504            msg.writeTo(baos);
505            bais = new ByteArrayInputStream(baos.toByteArray());
506            msg = new MimeMessage(session, bais);
507            if (PRINT_MESSAGES) {
508              printMessage(msg);
509            }
510            DumpMessage.dumpMsg(msg);
511            
512            System.out.println("\n\n*****************************************\n\n");
513    
514            // Now create a explicitly signed and authenticated encrypted message with attachment
515            msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), multipart, false);
516            System.out.println("creating explicitly signed and authenticated encrypted message [ChaChaPoly1305]...");
517            baos.reset();
518            msg.saveChanges();
519            msg.writeTo(baos);
520            bais = new ByteArrayInputStream(baos.toByteArray());
521            msg = new MimeMessage(session, bais);
522            if (PRINT_MESSAGES) {
523              printMessage(msg);
524            }
525            DumpMessage.dumpMsg(msg);
526            
527            System.out.println("\n\n*****************************************\n\n");
528            
529            // Now create a implicitly signed and authenticated encrypted message with attachment
530            msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), multipart, true);
531            System.out.println("creating implicitly signed and authenticated encrypted message [AES-CCM/128]...");
532            baos.reset();
533            msg.saveChanges();
534            msg.writeTo(baos);
535            bais = new ByteArrayInputStream(baos.toByteArray());
536            msg = new MimeMessage(session, bais);
537            if (PRINT_MESSAGES) {
538              printMessage(msg);
539            }
540            DumpMessage.dumpMsg(msg);
541            
542            System.out.println("\n\n*****************************************\n\n");
543    
544            // Now create a explicitly signed and authenticated encrypted message with attachment
545            msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), multipart, false);
546            System.out.println("creating explicitly signed and authenticated encrypted message [AES-CCM/128]...");
547            baos.reset();
548            msg.saveChanges();
549            msg.writeTo(baos);
550            bais = new ByteArrayInputStream(baos.toByteArray());
551            msg = new MimeMessage(session, bais);
552            if (PRINT_MESSAGES) {
553              printMessage(msg);
554            }
555            DumpMessage.dumpMsg(msg);
556            
557            System.out.println("\n\n*****************************************\n\n");
558              }  
559    
560              // 8. certs only message
561              msg = createCertsOnlyMessage(session);
562              System.out.println("creating certs-only message");
563              baos.reset();
564              msg.saveChanges();
565              msg.writeTo(baos);
566              bais = new ByteArrayInputStream(baos.toByteArray());
567              msg = new MimeMessage(session, bais);
568              if (PRINT_MESSAGES) {
569            printMessage(msg);
570          }
571              DumpMessage.dumpMsg(msg);
572              
573              System.out.println("\n\n*****************************************\n\n");
574    
575              // 9. certs only message where the cert list is put into the second part
576              msg = createCertsOnlyMultiPartMessage(session);
577              System.out.println("creating message with certs-only part");
578              baos.reset();
579              msg.saveChanges();
580              msg.writeTo(baos);
581              bais = new ByteArrayInputStream(baos.toByteArray());
582              msg = new MimeMessage(session, bais);
583              if (PRINT_MESSAGES) {
584            printMessage(msg);
585          }
586              DumpMessage.dumpMsg(msg);
587              
588              System.out.println("\n\n*****************************************\n\n");
589    
590              // 10. application/pkcs10 cert request message
591          msg = createPKCS10Message(session);
592          System.out.println("creating application/pkcs10 message...");
593              baos.reset();
594              msg.saveChanges();
595              msg.writeTo(baos);
596              bais = new ByteArrayInputStream(baos.toByteArray());
597              msg = new MimeMessage(session, bais);
598              if (PRINT_MESSAGES) {
599            printMessage(msg);
600          }
601              DumpMessage.dumpMsg(msg);
602              
603              System.out.println("\n\n*****************************************\n\n");
604    
605              // 11. application/pkcs10 message where the request is in the second part
606              msg = createPKCS10MultiPartMessage(session);
607              System.out.println("creating message with pkcs10 part...");
608              baos.reset();
609              msg.saveChanges();
610              msg.writeTo(baos);
611              bais = new ByteArrayInputStream(baos.toByteArray());
612              msg = new MimeMessage(session, bais);
613              if (PRINT_MESSAGES) {
614            printMessage(msg);
615          }
616              DumpMessage.dumpMsg(msg);
617              
618              System.out.println("\n\n*****************************************\n\n");
619    
620              // 12. compressed message 
621              msg = createCompressedMessage(session, multipart, (AlgorithmID)CMSAlgorithmID.zlib_compress.clone());
622              System.out.println("creating message with compressed data...");
623              baos.reset();
624              msg.saveChanges();
625              msg.writeTo(baos);
626              bais = new ByteArrayInputStream(baos.toByteArray());
627              msg = new MimeMessage(session, bais);
628              if (PRINT_MESSAGES) {
629            printMessage(msg);
630          }
631              DumpMessage.dumpMsg(msg);
632    
633            } catch (Exception ex) {
634                ex.printStackTrace();
635                throw new RuntimeException(ex.toString());
636            }
637      }
638      
639      /**
640       * Creates a MIME message container with the given subject for the given session.
641       * 
642       * @param session the mail sesion
643       * @param subject the subject of the message
644       *
645       * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content)
646       *
647       * @throws MessagingException if the message cannot be created
648       */
649      public Message createMessage(Session session, String subject) throws MessagingException {
650        MimeMessage msg = new MimeMessage(session);
651        msg.setFrom(new InternetAddress(from_));
652            msg.setRecipients(Message.RecipientType.TO,     InternetAddress.parse(to_, false));
653            msg.setSentDate(new Date());
654        msg.setSubject(subject);
655        return msg;
656      }
657      
658      /**
659       * Creates a simple plain (neither signed nor encrypted) message.
660       *
661       * @param session the mail session
662       * @param dataHandler the content of the message
663       * 
664       * @return the plain message
665       *
666       * @throws MessagingException if an error occurs when creating the message
667       */
668      public Message createPlainMessage(Session session, DataHandler dataHandler) throws MessagingException {
669    
670        Message msg = createMessage(session, "IAIK-S/MIME: Plain message");
671        if (dataHandler != null) {
672          msg.setDataHandler(dataHandler);
673        } else {
674          msg.setText("This is a plain message!\nIt is wether signed nor encrypted!\n");
675        }
676            return msg;
677      }
678      
679      /**
680       * Creates a signed and encrypted message.
681       *
682       * @param session the mail session
683       * @param algorithm the content encryption algorithm to be used
684       * @param dataHandler the content of the message to be signed and encrypted
685       * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
686       *                 (multipart/signed) signing
687       * 
688       * @return the signed and encrypted message
689       *
690       * @throws MessagingException if an error occurs when creating the message
691       */
692      public Message createSignedAndEncryptedMessage(Session session, AlgorithmID algorithm, DataHandler dataHandler, boolean implicit)
693        throws MessagingException {
694    
695        String subject = null;
696        String text = null;
697        if (implicit) {
698          subject = "IAIK-S/MIME: Implicitly Signed and Encrypted";
699          text = "This message is implicitly signed and encrypted!\n\n\n";
700        } else {
701          subject = "IAIK-S/MIME: Explicitly Signed and Encrypted";
702          text = "This message is explicitly signed and encrypted!\n\n\n";
703        }
704        Message msg = createMessage(session, subject);
705    
706        SignedContent sc = new SignedContent(implicit);
707        if (dataHandler != null) {
708          sc.setDataHandler(dataHandler);
709        } else {
710          sc.setText(text);
711        }
712        sc.setCertificates(signerCertificates_);
713        try {
714          sc.addSigner((RSAPrivateKey)signerPrivateKey_, signerCertificate_);
715        } catch (NoSuchAlgorithmException ex) {
716          throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
717        }
718    
719        EncryptedContent ec = null;
720        if (algorithm.equals(AlgorithmID.aes256_CBC)) {
721          ec = new EncryptedContent(sc);
722        } else {
723          ec = new AuthEncryptedContent(sc);
724        }
725        // encrypt for the recipient
726        ec.addRecipient(recipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
727        // I want to be able to decrypt the message, too
728        ec.addRecipient(encryptionCertOfSigner_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
729        // set the encryption algorithm
730        try {
731          ec.setEncryptionAlgorithm(algorithm, -1);
732        } catch (NoSuchAlgorithmException ex) {
733          throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
734        }   
735        msg.setContent(ec, ec.getContentType());
736        // let the EncryptedContent update some message headers
737        ec.setHeaders(msg);
738    
739        return msg;
740      }
741      
742      
743      
744      /**
745       * Creates a signed message.
746       *
747       * @param session the mail session
748       * @param dataHandler the content of the message to be signed
749       * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
750       *                 (multipart/signed) signing
751       * 
752       * @return the signed message
753       *
754       * @throws MessagingException if an error occurs when creating the message
755       */
756      public Message createSignedMessage(Session session, DataHandler dataHandler, boolean implicit)
757          throws MessagingException {
758    
759        String subject = null;
760        StringBuffer buf = new StringBuffer();
761        
762        if (implicit) {
763          subject = "IAIK-S/MIME: Implicitly Signed";
764          buf.append("This message is implicitly signed!\n");
765          buf.append("You need an S/MIME aware mail client to view this message.\n");
766          buf.append("\n\n");
767        } else {
768          subject = "IAIK-S/MIME: Explicitly Signed";
769          buf.append("This message is explicitly signed!\n");
770          buf.append("Every mail client can view this message.\n");
771          buf.append("Non S/MIME mail clients will show the signature as attachment.\n");
772          buf.append("\n\n");
773        }
774        
775        Message msg = createMessage(session, subject);
776    
777        SignedContent sc = new SignedContent(implicit);
778    
779        if (dataHandler != null) {
780          sc.setDataHandler(dataHandler);
781        } else {
782          sc.setText(buf.toString());
783        }
784        sc.setCertificates(signerCertificates_);
785    
786        try {
787          sc.addSigner((RSAPrivateKey)signerPrivateKey_, signerCertificate_);
788        } catch (NoSuchAlgorithmException ex) {
789          throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
790        }
791    
792        msg.setContent(sc, sc.getContentType());
793        // let the SignedContent update some message headers
794        sc.setHeaders(msg);
795        return msg;
796      }
797      
798      /**
799       * Creates an encrypted message.
800       *
801       * @param session the mail session
802       * @param algorithm the content encryption algorithm to be used
803       * @param keyLength the length of the secret content encryption key to be created and used
804       * 
805       * @return the encrypted message
806       *
807       * @throws MessagingException if an error occurs when creating the message
808       */
809      public Message createEncryptedMessage(Session session, AlgorithmID algorithm, int keyLength)
810          throws MessagingException {
811    
812        StringBuffer subject = new StringBuffer();
813        subject.append("IAIK-S/MIME: Encrypted ["+algorithm.getName());
814        if (keyLength > 0) {
815          subject.append("/"+keyLength);
816        }  
817        subject.append("]");
818        Message msg = createMessage(session, subject.toString());
819    
820        EncryptedContent ec = new EncryptedContent();
821    
822        StringBuffer buf = new StringBuffer();
823        buf.append("This is the encrypted content!\n");
824        buf.append("Content encryption algorithm: "+algorithm.getName());
825        buf.append("\n\n");
826    
827        ec.setText(buf.toString());
828        // encrypt for the recipient
829        ec.addRecipient(recipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
830        // I want to be able to decrypt the message, too
831        ec.addRecipient(encryptionCertOfSigner_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
832        try {
833          ec.setEncryptionAlgorithm(algorithm, keyLength);
834        } catch (NoSuchAlgorithmException ex) {
835          throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
836        }   
837    
838        msg.setContent(ec, ec.getContentType());
839        // let the EncryptedContent update some message headers
840        ec.setHeaders(msg);
841    
842        return msg;
843      }
844      
845      /**
846       * Creates an authenticated encrypted message.
847       *
848       * @param session the mail session
849       * @param algorithm the content encryption algorithm to be used
850       * @param keyLength the length of the secret content encryption key to be created and used
851       * 
852       * @return the encrypted message
853       *
854       * @throws MessagingException if an error occurs when creating the message
855       */
856      public Message createAuthEncryptedMessage(Session session, AlgorithmID algorithm, int keyLength)
857          throws MessagingException {
858    
859        StringBuffer subject = new StringBuffer();
860        subject.append("IAIK-S/MIME: AuthEncrypted ["+algorithm.getName());
861        if (keyLength > 0) {
862          subject.append("/"+keyLength);
863        }  
864        subject.append("]");
865        Message msg = createMessage(session, subject.toString());
866    
867        AuthEncryptedContent ec = new AuthEncryptedContent();
868    
869        StringBuffer buf = new StringBuffer();
870        buf.append("This is the authenticated encrypted content!\n");
871        buf.append("Content encryption algorithm: "+algorithm.getName());
872        buf.append("\n\n");
873    
874        ec.setText(buf.toString());
875        // encrypt for the recipient
876        ec.addRecipient(recipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
877        // I want to be able to decrypt the message, too
878        ec.addRecipient(encryptionCertOfSigner_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
879        try {
880          ec.setEncryptionAlgorithm(algorithm, keyLength);
881        } catch (NoSuchAlgorithmException ex) {
882          throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
883        }   
884    
885        msg.setContent(ec, ec.getContentType());
886        // let the EncryptedContent update some message headers
887        ec.setHeaders(msg);
888    
889        return msg;
890      }
891      
892      /**
893       * Creates a certs-only message.
894       *
895       * @param session the mail session
896       * 
897       * @return the certs-only message
898       *
899       * @throws MessagingException if an error occurs when creating the message
900       */
901      public Message createCertsOnlyMessage(Session session)
902          throws MessagingException {
903    
904        Message msg = createMessage(session, "IAIK S/MIME: Certs-only message");
905        //use new content types
906        SMimeParameters.useNewContentTypes(true);
907        SignedContent sc = new SignedContent(true, SignedContent.CERTS_ONLY);
908        sc.setCertificates(signerCertificates_);
909        msg.setContent(sc, sc.getContentType());
910        //set filename and attachment parameters
911        sc.setHeaders(msg);
912    
913    
914        return msg;
915      }
916      
917      /**
918       * Creates a certs-only message where the certificate list is transferred as attachment.
919       *
920       * @param session the mail session
921       * 
922       * @return the certs-only message
923       *
924       * @throws MessagingException if an error occurs when creating the message
925       */
926      public Message createCertsOnlyMultiPartMessage(Session session) throws MessagingException {
927    
928        MimeBodyPart mbp1 = new MimeBodyPart();
929            mbp1.setText("This is a test where the certs-only message is included in the second part!\n\n");
930    
931        MimeBodyPart attachment = new MimeBodyPart();
932        //use new content types
933        SMimeParameters.useNewContentTypes(true);
934        SignedContent sc = new SignedContent(true, SignedContent.CERTS_ONLY);
935        sc.setCertificates(signerCertificates_);
936        attachment.setContent(sc, sc.getContentType());
937        // let the SignedContent update some headers
938        sc.setHeaders(attachment);
939        Multipart mp = new MimeMultipart();
940        mp.addBodyPart(mbp1);
941        mp.addBodyPart(attachment);
942    
943        Message msg = createMessage(session, "IAIK S/MIME: Certs-only multipart message");
944        msg.setContent(mp, mp.getContentType());
945    
946        return msg;
947      }
948      
949      /**
950       * Creates a compressed message.
951       *
952       * @param session the mail session
953       * @param dataHandler the datahandler supplying the content to be compressed
954       * @param algorithm the compression algorithm to be used
955       * 
956       * @return the compressed message
957       *
958       * @throws MessagingException if an error occurs when creating the message
959       */
960      public Message createCompressedMessage(Session session, DataHandler dataHandler, AlgorithmID algorithm)
961          throws MessagingException {
962    
963        String subject = "IAIK-S/MIME: Compressed ["+algorithm.getName()+"]";
964        Message msg = createMessage(session, subject.toString());
965    
966        CompressedContent compressedContent = new CompressedContent();
967        
968        if (dataHandler == null) {
969          StringBuffer buf = new StringBuffer();
970          buf.append("This is the compressed content!\n");
971          buf.append("Compression algorithm: "+algorithm.getName());
972          buf.append("\n\n");
973          compressedContent.setText(buf.toString());
974        } else {
975          compressedContent.setDataHandler(dataHandler);   
976        }    
977        
978        try {
979          compressedContent.setCompressionAlgorithm(algorithm);
980        } catch (NoSuchAlgorithmException ex) {
981          throw new MessagingException("Compression algorithm not supported: " + ex.getMessage());   
982        }   
983    
984        msg.setContent(compressedContent, compressedContent.getContentType());
985        // let the CompressedContent update some message headers
986        compressedContent.setHeaders(msg);
987    
988        return msg;
989      }
990      
991      /**
992       * Creates a PKCS#10 certificate request message.
993       *
994       * @param session the mail session
995       * 
996       * @return the PKCS#10 certificate request message
997       *
998       * @throws MessagingException if an error occurs when creating the message
999       */
1000      public Message createPKCS10Message(Session session)
1001        throws MessagingException {
1002    
1003        Message msg = createMessage(session, "IAIK-S/MIME: Certificate Request");
1004    
1005        PKCS10Content pc = new PKCS10Content();
1006        CertificateRequest request = null;
1007        try {
1008           request = createCertificateRequest();
1009        } catch (PKCSException ex) {
1010           throw new MessagingException(ex.getMessage());
1011        }
1012        pc.setCertRequest(request);
1013        msg.setContent(pc, pc.getContentType());
1014        // let the PKCS10Content update some message headers
1015        pc.setHeaders(msg);
1016    
1017        return msg;
1018      }
1019      
1020        /**
1021       * Creates a PKCS#10 message where the certificate request is transferred as attachment.
1022       *
1023       * @param session the mail session
1024       * 
1025       * @return the PKCS#10 certificate request message
1026       *
1027       * @throws MessagingException if an error occurs when creating the message
1028       */
1029      public Message createPKCS10MultiPartMessage(Session session) throws MessagingException {
1030    
1031        MimeBodyPart mbp1 = new MimeBodyPart();
1032            mbp1.setText("This is a test where the request message is included in the second part!\n\n");
1033            // try to test an attachment
1034            // this demo attaches our homepage
1035        MimeBodyPart attachment = new MimeBodyPart();
1036        //use new content types
1037        SMimeParameters.useNewContentTypes(true);
1038        PKCS10Content pc = new PKCS10Content();
1039        CertificateRequest request = null;
1040        try {
1041           request = createCertificateRequest();
1042        } catch (PKCSException ex) {
1043           throw new MessagingException(ex.getMessage());
1044        }
1045        pc.setCertRequest(request);
1046        DataHandler pkcs10Handler = new DataHandler(pc, pc.getContentType());
1047        attachment.setDataHandler(pkcs10Handler);
1048        attachment.setDisposition("attachment");
1049        attachment.setFileName("smime.p10");
1050        Multipart mp = new MimeMultipart();
1051        mp.addBodyPart(mbp1);
1052        mp.addBodyPart(attachment);
1053    
1054        Message msg = createMessage(session, "IAIK-S/MIME: Certificate Request multipart message");
1055        msg.setContent(mp, mp.getContentType());
1056        return msg;
1057      }
1058      
1059      /**
1060       * Creates a PKCS#10 certificate request.
1061       *
1062       * @return the certificate request
1063       *
1064       * @throws PKCSException if the request cannot be created
1065       */
1066      private CertificateRequest createCertificateRequest() throws PKCSException {
1067        try {
1068          Name subject = new Name();
1069              subject.addRDN(ObjectID.commonName, firstName_ + " " + lastName_);
1070              subject.addRDN(ObjectID.emailAddress, from_);
1071              CertificateRequest certRequest;
1072    
1073          certRequest = new CertificateRequest(signerCertificate_.getPublicKey(), subject);
1074              certRequest.sign((AlgorithmID)AlgorithmID.sha256WithRSAEncryption.clone(), signerPrivateKey_);
1075              certRequest.verify();
1076              return certRequest;
1077            } catch (Exception ex) {
1078              throw new PKCSException("Cannot create cert request: " + ex.getMessage());
1079            }
1080      }
1081      
1082      
1083      /** 
1084       * Prints a dump of the given message to System.out.
1085       *
1086       * @param msg the message to be dumped to System.out
1087       */
1088      static void printMessage(Message msg) throws IOException {
1089        System.out.println("------------------------------------------------------------------");
1090        System.out.println("Message dump: \n");
1091        try {
1092          msg.writeTo(System.out);
1093        } catch (MessagingException ex) {
1094          throw new IOException(ex.getMessage());   
1095        }    
1096        System.out.println("\n------------------------------------------------------------------");
1097      }  
1098    
1099    
1100      /**
1101       * The main method.
1102       */
1103      public static void main(String[] argv) throws IOException {
1104    
1105        DemoSMimeUtil.initDemos();
1106            (new SMimeDemo()).start();
1107        System.out.println("\nReady!");
1108        DemoUtil.waitKey();
1109      }
1110    }