001// Copyright (C) 2002 IAIK
002// https://sic.tech/
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// This source is provided for inspection purposes and recompilation only,
011// unless specified differently in a contract with IAIK. This source has to
012// be kept in strict confidence and must not be disclosed to any third party
013// under any circumstances. Redistribution in source and binary forms, with
014// or without modification, are <not> permitted in any case!
015//
016// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
017// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
018// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
019// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
020// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
021// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
022// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
023// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
024// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
025// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
026// SUCH DAMAGE.
027//
028// $Header: /IAIK-CMS/current/src/demo/smime/basic/SMimeEnvelopedDemoAEAD.java 3     12.02.25 17:58 Dbratko $
029// $Revision: 3 $
030//
031
032package demo.smime.basic;
033
034import java.io.ByteArrayInputStream;
035import java.io.ByteArrayOutputStream;
036import java.io.IOException;
037import java.security.NoSuchAlgorithmException;
038import java.security.PrivateKey;
039import java.util.Date;
040
041import jakarta.activation.DataHandler;
042import jakarta.activation.FileDataSource;
043import jakarta.mail.Message;
044import jakarta.mail.MessagingException;
045import jakarta.mail.Multipart;
046import jakarta.mail.Session;
047import jakarta.mail.internet.InternetAddress;
048import jakarta.mail.internet.MimeBodyPart;
049import jakarta.mail.internet.MimeMessage;
050
051import demo.DemoSMimeUtil;
052import demo.DemoUtil;
053import demo.keystore.CMSKeyStore;
054import demo.smime.DumpMessage;
055import iaik.asn1.structures.AlgorithmID;
056import iaik.smime.AuthEncryptedContent;
057import iaik.smime.EncryptedContent;
058import iaik.smime.SMimeBodyPart;
059import iaik.smime.SMimeMultipart;
060import iaik.smime.SignedContent;
061import iaik.x509.X509Certificate;
062
063/**
064 * This class demonstrates the usage of the IAIK S/MIME implementation. It shows how to create
065 * signed and/or encrypted S/MIME messages and how to parse them and verify the signatures 
066 * and decrypt the content, respectively. This demos creates encrypted messages using an AEAD
067 * cipher mode (like GCM). Although CMS and S/MIME generally use AEAD cipher modes with the 
068 * <code>AuthEnvelopedData</code> content type, it is technically possible to also use
069 * AEAD cipher modes with the <code>EnvelopedData</code> content type (when appending the mac value
070 * to the cipher text). This demo shows how to encrypt S/MIME messages with AEAD cipher modes when
071 * using the CMS <code>EnvelopedData</code> type.
072
073 * <p>
074 * To run this demo the following packages are required:
075 * <ul>
076 *    <li>
077 *       <code>iaik_cms.jar</code> (IAIK-CMS/SMIME)
078 *    </li>
079 *    <li>
080 *       <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>).
081 *    </li>
082 *    <li>
083 *       <a href="https://jakarta.ee/specifications/mail/" target="_blank">Jakarta</a>/<a href="https://eclipse-ee4j.github.io/angus-mail/" target="_blank">Angus</a> Mail
084 *    </li>   
085 *    <li>
086 *       <a href="https://jakarta.ee/specifications/activation/" target="_blank">Jakarta Activation Framework</a>
087 *    </li> 
088 * </ul>
089 * 
090 * This demo requires Java 7 or later.
091 * 
092 */
093public class SMimeEnvelopedDemoAEAD {
094    
095  // whether to print dump all generates test messages to System.out
096  final static boolean PRINT_MESSAGES = false;   
097  
098
099  String firstName_ = "John";
100  String lastName_ = "SMime";
101  String to_ = "smimetest@iaik.tugraz.at";     // email recipient
102  String from_ = "smimetest@iaik.tugraz.at";   // email sender
103  String host_ = "mailhost";                   // name of the mailhost
104
105  X509Certificate[] signerCertificates_;       // list of certificates to include in the S/MIME message
106  X509Certificate signerCertificate_;          // certificate of the signer/sender
107  PrivateKey signerPrivateKey_;                // private key of the signer/sender
108  
109  X509Certificate senderCryptCertificate_;     // the encryption certificate of the signer/sender
110  
111  X509Certificate rsaRecipientCertificate_;    // RSA encryption cert and key of a recipient
112  
113  /**
114   * Default constructor. Reads certificates and keys from the demo keystore.
115   */
116  public SMimeEnvelopedDemoAEAD() {
117    
118    System.out.println();
119    System.out.println("********************************************************************************************");
120    System.out.println("*                        SMimeEnvelopedDemoAEAD demo                                       *");
121    System.out.println("* (shows how to create and parse encrypted (enveloped) S/MIME messages with AEAD ciphers)  *");
122    System.out.println("********************************************************************************************");
123    System.out.println();
124    
125    // get the certificates from the KeyStore
126    signerCertificates_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
127    signerPrivateKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
128    signerCertificate_ = signerCertificates_[0];
129    senderCryptCertificate_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0];
130
131    rsaRecipientCertificate_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0];
132
133  }
134  
135  /**
136   * Starts the demo.
137   *
138   * @throws IOException if an I/O related error occurs
139   */
140  public void start() throws IOException {
141
142    // get the default Session
143        Session session = DemoSMimeUtil.getSession();
144
145        try {
146      // Create a demo Multipart
147      MimeBodyPart mbp1 = new SMimeBodyPart();
148          mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n");
149          // attachment
150      MimeBodyPart attachment = new SMimeBodyPart();
151      attachment.setDataHandler(new DataHandler(new FileDataSource("test.html")));
152      attachment.setFileName("test.html");
153
154      Multipart mp = new SMimeMultipart();
155      mp.addBodyPart(mbp1);
156      mp.addBodyPart(attachment);
157      DataHandler multipart = new DataHandler(mp, mp.getContentType());
158
159      Message msg;    // the message to send
160      ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
161      ByteArrayInputStream bais;  // we read from a stream
162
163          
164          // Now create encrypted messages with different content encryption algorithms
165          if (DemoUtil.getIaikProviderVersion() >= 5.62) {
166            
167            msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), 128);
168        System.out.println("creating encrypted message [AES-GCM/128]...");
169        baos.reset();
170        msg.saveChanges();
171        msg.writeTo(baos);
172        bais = new ByteArrayInputStream(baos.toByteArray());
173        msg = new MimeMessage(session, bais);
174        if (PRINT_MESSAGES) {
175          printMessage(msg);
176        }
177        DumpMessage.dumpEncryptedMessage(msg);
178         
179        System.out.println("\n\n*****************************************\n\n");
180        
181        msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_GCM.clone(), 192);
182        System.out.println("creating encrypted message [AES-GCM/192]...");
183        baos.reset();
184        msg.saveChanges();
185        msg.writeTo(baos);
186        bais = new ByteArrayInputStream(baos.toByteArray());
187        msg = new MimeMessage(session, bais);
188        if (PRINT_MESSAGES) {
189          printMessage(msg);
190        }
191        DumpMessage.dumpEncryptedMessage(msg); 
192         
193        System.out.println("\n\n*****************************************\n\n");
194            
195            msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_GCM.clone(), 256);
196            System.out.println("creating encrypted message [AES-GCM/256]...");
197            baos.reset();
198            msg.saveChanges();
199            msg.writeTo(baos);
200            bais = new ByteArrayInputStream(baos.toByteArray());
201            msg = new MimeMessage(session, bais);
202            if (PRINT_MESSAGES) {
203              printMessage(msg);
204            }
205            DumpMessage.dumpEncryptedMessage(msg);
206             
207            System.out.println("\n\n*****************************************\n\n");
208            
209            msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), 128);
210        System.out.println("creating encrypted message [AES-CCM/128]...");
211        baos.reset();
212        msg.saveChanges();
213        msg.writeTo(baos);
214        bais = new ByteArrayInputStream(baos.toByteArray());
215        msg = new MimeMessage(session, bais);
216        if (PRINT_MESSAGES) {
217          printMessage(msg);
218        }
219        DumpMessage.dumpEncryptedMessage(msg);
220         
221        System.out.println("\n\n*****************************************\n\n");
222        
223        msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CCM.clone(), 192);
224        System.out.println("creating encrypted message [AES-CCM/192]...");
225        baos.reset();
226        msg.saveChanges();
227        msg.writeTo(baos);
228        bais = new ByteArrayInputStream(baos.toByteArray());
229        msg = new MimeMessage(session, bais);
230        if (PRINT_MESSAGES) {
231          printMessage(msg);
232        }
233        DumpMessage.dumpEncryptedMessage(msg); 
234        
235        msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CCM.clone(), 256);
236        System.out.println("creating encrypted message [AES-CCM/256]...");
237        baos.reset();
238        msg.saveChanges();
239        msg.writeTo(baos);
240        bais = new ByteArrayInputStream(baos.toByteArray());
241        msg = new MimeMessage(session, bais);
242        if (PRINT_MESSAGES) {
243          printMessage(msg);
244        }
245        DumpMessage.dumpEncryptedMessage(msg);
246         
247        System.out.println("\n\n*****************************************\n\n");
248        
249        msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), 256);
250        System.out.println("creating encrypted message [ChaChaPoly1305]...");
251        baos.reset();
252        msg.saveChanges();
253        msg.writeTo(baos);
254        bais = new ByteArrayInputStream(baos.toByteArray());
255        msg = new MimeMessage(session, bais);
256        if (PRINT_MESSAGES) {
257          printMessage(msg);
258        }
259        DumpMessage.dumpEncryptedMessage(msg);  
260         
261        System.out.println("\n\n*****************************************\n\n");
262        
263       // Create an implicitly signed and encrypted message with attachment
264        msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), 128, multipart, true, true);
265        System.out.println("creating implicitly signed and encrypted message [AES-GCM/128]...");
266        baos.reset();
267        msg.saveChanges();
268        msg.writeTo(baos);
269        bais = new ByteArrayInputStream(baos.toByteArray());
270        msg = new MimeMessage(session, bais);
271        if (PRINT_MESSAGES) {
272          printMessage(msg);
273        }
274        DumpMessage.dumpEncryptedMessage(msg);
275        
276        System.out.println("\n\n*****************************************\n\n");
277
278        // Create an explicitly signed and encrypted message with attachment
279        msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), 128, multipart, true, true);
280        System.out.println("creating explicitly signed and encrypted message [AES-GCM/128]...");
281        baos.reset();
282        msg.saveChanges();
283        msg.writeTo(baos);
284        bais = new ByteArrayInputStream(baos.toByteArray());
285        msg = new MimeMessage(session, bais);
286        if (PRINT_MESSAGES) {
287          printMessage(msg);
288        }
289        DumpMessage.dumpEncryptedMessage(msg);
290        
291        System.out.println("\n\n*****************************************\n\n");
292        
293        // Create an implicitly signed and encrypted message with attachment
294        msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_GCM.clone(), 192, multipart, true, true);
295        System.out.println("creating implicitly signed and encrypted message [AES-GCM/192]...");
296        baos.reset();
297        msg.saveChanges();
298        msg.writeTo(baos);
299        bais = new ByteArrayInputStream(baos.toByteArray());
300        msg = new MimeMessage(session, bais);
301        if (PRINT_MESSAGES) {
302          printMessage(msg);
303        }
304        DumpMessage.dumpEncryptedMessage(msg);
305        
306        System.out.println("\n\n*****************************************\n\n");
307
308        // Create an explicitly signed and encrypted message with attachment
309        msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_GCM.clone(), 192, multipart, true, true);
310        System.out.println("creating explicitly signed and encrypted message [AES-GCM/192]...");
311        baos.reset();
312        msg.saveChanges();
313        msg.writeTo(baos);
314        bais = new ByteArrayInputStream(baos.toByteArray());
315        msg = new MimeMessage(session, bais);
316        if (PRINT_MESSAGES) {
317          printMessage(msg);
318        }
319        DumpMessage.dumpEncryptedMessage(msg);
320        
321        System.out.println("\n\n*****************************************\n\n");
322            
323        // Create an implicitly signed and encrypted message with attachment
324        msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_GCM.clone(), 256, multipart, true, true);
325        System.out.println("creating implicitly signed and encrypted message [AES-GCM/256]...");
326        baos.reset();
327        msg.saveChanges();
328        msg.writeTo(baos);
329        bais = new ByteArrayInputStream(baos.toByteArray());
330        msg = new MimeMessage(session, bais);
331        if (PRINT_MESSAGES) {
332          printMessage(msg);
333        }
334        DumpMessage.dumpEncryptedMessage(msg);
335        
336        System.out.println("\n\n*****************************************\n\n");
337
338        // Create an explicitly signed and encrypted message with attachment
339        msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_GCM.clone(), 256, multipart, true, true);
340        System.out.println("creating explicitly signed and encrypted message [AES-GCM/256]...");
341        baos.reset();
342        msg.saveChanges();
343        msg.writeTo(baos);
344        bais = new ByteArrayInputStream(baos.toByteArray());
345        msg = new MimeMessage(session, bais);
346        if (PRINT_MESSAGES) {
347          printMessage(msg);
348        }
349        DumpMessage.dumpEncryptedMessage(msg);
350        
351        System.out.println("\n\n*****************************************\n\n");
352        
353        
354        // Create an implicitly signed and encrypted message with attachment
355         msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), 128, multipart, true, true);
356         System.out.println("creating implicitly signed and encrypted message [AES-CCM/128]...");
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.dumpEncryptedMessage(msg);
366         
367         System.out.println("\n\n*****************************************\n\n");
368
369         // Create an explicitly signed and encrypted message with attachment
370         msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), 128, multipart, true, true);
371         System.out.println("creating explicitly signed and encrypted message [AES-CCM/128]...");
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.dumpEncryptedMessage(msg);
381         
382         System.out.println("\n\n*****************************************\n\n");
383         
384         // Create an implicitly signed and encrypted message with attachment
385         msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CCM.clone(), 192, multipart, true, true);
386         System.out.println("creating implicitly signed and encrypted message [AES-CCM/192]...");
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.dumpEncryptedMessage(msg);
396         
397         System.out.println("\n\n*****************************************\n\n");
398
399         // Create an explicitly signed and encrypted message with attachment
400         msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CCM.clone(), 192, multipart, true, true);
401         System.out.println("creating explicitly signed and encrypted message [AES-CCM/192]...");
402         baos.reset();
403         msg.saveChanges();
404         msg.writeTo(baos);
405         bais = new ByteArrayInputStream(baos.toByteArray());
406         msg = new MimeMessage(session, bais);
407         if (PRINT_MESSAGES) {
408           printMessage(msg);
409         }
410         DumpMessage.dumpEncryptedMessage(msg);
411         
412         System.out.println("\n\n*****************************************\n\n");
413         
414         // Create an implicitly signed and encrypted message with attachment
415         msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CCM.clone(), 256, multipart, true, true);
416         System.out.println("creating implicitly signed and encrypted message [AES-CCM/256]...");
417         baos.reset();
418         msg.saveChanges();
419         msg.writeTo(baos);
420         bais = new ByteArrayInputStream(baos.toByteArray());
421         msg = new MimeMessage(session, bais);
422         if (PRINT_MESSAGES) {
423           printMessage(msg);
424         }
425         DumpMessage.dumpEncryptedMessage(msg);
426         
427         System.out.println("\n\n*****************************************\n\n");
428
429         // Create an explicitly signed and encrypted message with attachment
430         msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CCM.clone(), 256, multipart, true, true);
431         System.out.println("creating explicitly signed and encrypted message [AES-CCM/256]...");
432         baos.reset();
433         msg.saveChanges();
434         msg.writeTo(baos);
435         bais = new ByteArrayInputStream(baos.toByteArray());
436         msg = new MimeMessage(session, bais);
437         if (PRINT_MESSAGES) {
438           printMessage(msg);
439         }
440         DumpMessage.dumpEncryptedMessage(msg);
441         
442         System.out.println("\n\n*****************************************\n\n");
443        
444         // Create an implicitly signed and encrypted message with attachment
445         msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), 256, multipart, true, true);
446         System.out.println("creating implicitly signed and encrypted message [ChaCha20Poly1305]...");
447         baos.reset();
448         msg.saveChanges();
449         msg.writeTo(baos);
450         bais = new ByteArrayInputStream(baos.toByteArray());
451         msg = new MimeMessage(session, bais);
452         if (PRINT_MESSAGES) {
453           printMessage(msg);
454         }
455         DumpMessage.dumpEncryptedMessage(msg);
456         
457         System.out.println("\n\n*****************************************\n\n");
458
459         // Create an explicitly signed and encrypted message with attachment
460         msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), 256, multipart, true, true);
461         System.out.println("creating explicitly signed and encrypted message [ChaCha20Poly1305]...");
462         baos.reset();
463         msg.saveChanges();
464         msg.writeTo(baos);
465         bais = new ByteArrayInputStream(baos.toByteArray());
466         msg = new MimeMessage(session, bais);
467         if (PRINT_MESSAGES) {
468           printMessage(msg);
469         }
470         DumpMessage.dumpEncryptedMessage(msg);
471         
472         System.out.println("\n\n*****************************************\n\n");
473            
474          }
475         
476         
477
478        } catch (Exception ex) {
479            ex.printStackTrace();
480            throw new RuntimeException(ex.toString());
481        }
482  }
483
484  /**
485   * Creates a MIME message container with the given subject for the given session.
486   * 
487   * @param session the mail sesion
488   * @param subject the subject of the message
489   *
490   * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content)
491   *
492   * @throws MessagingException if the message cannot be created
493   */
494  public Message createMessage(Session session, String subject) throws MessagingException {
495    MimeMessage msg = new MimeMessage(session);
496    msg.setFrom(new InternetAddress(from_));
497        msg.setRecipients(Message.RecipientType.TO,     InternetAddress.parse(to_, false));
498        msg.setSentDate(new Date());
499    msg.setSubject(subject);
500    return msg;
501  }
502  
503  /**
504   * Creates a simple plain (neither signed nor encrypted) message.
505   *
506   * @param session the mail session
507   * @param dataHandler the content of the message
508   * 
509   * @return the plain message
510   *
511   * @throws MessagingException if an error occurs when creating the message
512   */
513  public Message createPlainMessage(Session session, DataHandler dataHandler) throws MessagingException {
514
515    Message msg = createMessage(session, "IAIK-S/MIME: Plain message");
516    if (dataHandler != null) {
517      msg.setDataHandler(dataHandler);
518    } else {
519      msg.setText("This is a plain message!\nIt is wether signed nor encrypted!\n");
520    }
521    return msg;
522  }
523  
524  /**
525   * Creates a signed and encrypted message.
526   *
527   * @param session the mail session
528   * @param contentEA the content encryption algorithm to be used
529   * @param keyLength the length of the secret content encryption key to be created and used
530   * @param dataHandler the content of the message to be signed and encrypted
531   * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
532   *                 (multipart/signed) signing
533   * @param authEncrypt whether to create an encrypted message                
534   * 
535   * @return the signed and encrypted message
536   *
537   * @throws MessagingException if an error occurs when creating the message
538   */
539  public Message createSignedAndEncryptedMessage(Session session, 
540    AlgorithmID contentEA, int keyLength,
541    DataHandler dataHandler, boolean implicit, boolean authEncrypt)
542    throws MessagingException {
543
544    String subject = null;
545    String text = null;
546    if (implicit) {
547      subject = "IAIK-S/MIME: Implicitly signed and " + (authEncrypt ? "authenticated " : "") + "encrypted";
548      text = "This message is implicitly signed and " + (authEncrypt ? "authenticated " : "") + "encrypted!\n\n\n";
549    } else {
550      subject = "IAIK-S/MIME: explicitly signed and " + (authEncrypt ? "authenticated " : "") + " encrypted";
551      text = "This message is explicitly signed and " + (authEncrypt ? "authenticated " : "") + " encrypted!\n\n\n";
552    }
553    Message msg = createMessage(session, subject);
554
555    SignedContent sc = new SignedContent(implicit);
556    if (dataHandler != null) {
557      sc.setDataHandler(dataHandler);
558    } else {
559      sc.setText(text);
560    }
561    sc.setCertificates(signerCertificates_);
562    try {
563      sc.addSigner(signerPrivateKey_, 
564                   signerCertificate_,
565                   (AlgorithmID)AlgorithmID.sha256.clone(),
566                   (AlgorithmID)AlgorithmID.rsaEncryption.clone());
567    } catch (NoSuchAlgorithmException ex) {
568      throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
569    }
570
571    EncryptedContent ec = null;
572    if (authEncrypt) {
573      ec = new AuthEncryptedContent(sc);
574    } else {
575      ec = new EncryptedContent(sc);
576    }
577
578    
579    AlgorithmID algorithm = (AlgorithmID)contentEA.clone();
580    
581    // sender wants to be able to decrypt the message
582    ec.addRecipient(senderCryptCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());  
583     
584    // add RSA recipient
585    ec.addRecipient(rsaRecipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
586    // set the encryption algorithm
587    try {
588      ec.setEncryptionAlgorithm(algorithm, keyLength);
589    } catch (NoSuchAlgorithmException ex) {
590      throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
591    }   
592    msg.setContent(ec, ec.getContentType());
593    // let the EncryptedContent update some message headers
594    ec.setHeaders(msg);
595
596    return msg;
597  }
598  
599  /**
600   * Creates a signed message.
601   *
602   * @param session the mail session
603   * @param dataHandler the content of the message to be signed
604   * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
605   *                 (multipart/signed) signing
606   * @param digestAlgorithm the digest algorithm to be used
607   * @param signatureAlgorithm the signature algorithm to be used                
608   * 
609   * @return the signed message
610   *
611   * @throws MessagingException if an error occurs when creating the message
612   */
613  public Message createSignedMessage(Session session, 
614                                     DataHandler dataHandler,
615                                     boolean implicit,
616                                     AlgorithmID digestAlgorithm,
617                                     AlgorithmID signatureAlgorithm)
618      throws MessagingException {
619
620    String subject = null;
621    StringBuffer buf = new StringBuffer();
622    
623    if (implicit) {
624      subject = "IAIK-S/MIME: Implicitly Signed";
625      buf.append("This message is implicitly signed!\n");
626      buf.append("You need an S/MIME aware mail client to view this message.\n");
627      buf.append("\n\n");
628    } else {
629      subject = "IAIK-S/MIME: Explicitly Signed";
630      buf.append("This message is explicitly signed!\n");
631      buf.append("Every mail client can view this message.\n");
632      buf.append("Non S/MIME mail clients will show the signature as attachment.\n");
633      buf.append("\n\n");
634    }
635    
636    Message msg = createMessage(session, subject);
637    
638    SignedContent sc = new SignedContent(implicit);
639    if (dataHandler != null) {
640      sc.setDataHandler(dataHandler);
641    } else {
642      sc.setText(buf.toString());
643    }
644    sc.setCertificates(signerCertificates_);
645
646    try {
647      sc.addSigner(signerPrivateKey_, 
648                   signerCertificate_,
649                   (AlgorithmID)digestAlgorithm.clone(),
650                   (AlgorithmID)signatureAlgorithm.clone());
651    } catch (NoSuchAlgorithmException ex) {
652      throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
653    }
654
655    msg.setContent(sc, sc.getContentType());
656    // let the SignedContent update some message headers
657    sc.setHeaders(msg);
658    return msg;
659  }
660  
661  /**
662   * Creates an encrypted message.
663   *
664   * @param session the mail session
665   * @param contentEA the content encryption algorithm to be used
666   * @param keyLength the length of the secret content encryption key to be created and used
667   * 
668   * @return the encrypted message
669   *
670   * @throws MessagingException if an error occurs when creating the message
671   */
672  public Message createEncryptedMessage(Session session, AlgorithmID contentEA, int keyLength)
673    throws MessagingException {
674    
675    AlgorithmID algorithm = (AlgorithmID)contentEA.clone();
676    
677    StringBuffer subject = new StringBuffer();
678    subject.append("IAIK-S/MIME: Encrypted ["+algorithm.getName());
679    if (keyLength > 0) {
680      subject.append("/"+keyLength);
681    }  
682    subject.append("]");
683    Message msg = createMessage(session, subject.toString());
684
685    EncryptedContent ec = new EncryptedContent();
686
687    StringBuffer buf = new StringBuffer();
688    buf.append("This is the encrypted content!\n");
689    buf.append("Content encryption algorithm: "+algorithm.getName());
690    buf.append("\n\n");
691
692    ec.setText(buf.toString());
693    
694    // sender wants to be able to decrypt the message
695    ec.addRecipient(senderCryptCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());  
696   
697    // add RSA recipient
698    ec.addRecipient(rsaRecipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
699    try {
700      ec.setEncryptionAlgorithm(algorithm, keyLength);
701    } catch (NoSuchAlgorithmException ex) {
702      throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
703    }    
704
705    msg.setContent(ec, ec.getContentType());
706    // let the EncryptedContent update some message headers
707    ec.setHeaders(msg);
708
709    return msg;
710  }
711  
712  
713  /** 
714   * Prints a dump of the given message to System.out.
715   *
716   * @param msg the message to be dumped to System.out
717   *
718   * @throws IOException if an I/O error occurs
719   */
720  static void printMessage(Message msg) throws IOException {
721    System.out.println("------------------------------------------------------------------");
722    System.out.println("Message dump: \n");
723    try {
724      msg.writeTo(System.out);
725    } catch (MessagingException ex) {
726      throw new IOException(ex.getMessage());   
727    }    
728    System.out.println("\n------------------------------------------------------------------");
729  }  
730  
731  /**
732   * The main method.
733   */
734  public static void main(String[] argv) throws IOException {
735    String jdkVersion = (String) System.getProperty("java.version");
736    if (jdkVersion.compareTo("1.7") >= 0) { 
737      DemoSMimeUtil.initDemos();
738        (new SMimeEnvelopedDemoAEAD()).start();
739      System.out.println("\nReady!");
740      DemoUtil.waitKey();
741    } else {
742      System.err.println("This demo requires Java 7 or later!");
743    }  
744  }
745}