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/ecc/SMimeEccSuiteBDemo.java 18    12.02.25 17:59 Dbratko $
029// $Revision: 18 $
030//
031
032package demo.smime.ecc;
033
034import iaik.asn1.structures.AlgorithmID;
035import iaik.cms.CMSAlgorithmID;
036import iaik.smime.EncryptedContent;
037import iaik.smime.SMimeBodyPart;
038import iaik.smime.SMimeException;
039import iaik.smime.SMimeMultipart;
040import iaik.smime.SignedContent;
041import iaik.x509.X509Certificate;
042
043import java.io.ByteArrayInputStream;
044import java.io.ByteArrayOutputStream;
045import java.io.IOException;
046import java.security.NoSuchAlgorithmException;
047import java.security.PrivateKey;
048import java.util.Date;
049
050import jakarta.activation.DataHandler;
051import jakarta.activation.FileDataSource;
052import jakarta.mail.Message;
053import jakarta.mail.MessagingException;
054import jakarta.mail.Multipart;
055import jakarta.mail.Session;
056import jakarta.mail.internet.InternetAddress;
057import jakarta.mail.internet.MimeBodyPart;
058import jakarta.mail.internet.MimeMessage;
059
060import demo.DemoSMimeUtil;
061import demo.DemoUtil;
062import demo.cms.ecc.ECCDemoUtil;
063import demo.cms.ecc.keystore.CMSEccKeyStore;
064import demo.smime.DumpMessage;
065
066/**
067 * This class demonstrates the usage of the IAIK S/MIME implementation to create and
068 * parse ECDSA signed and/or ECDH based encrypted S/MIMEv3 messages according to 
069 * RFC 5008 &quot;Suite B in Secure/Multipurpose Internet Mail Extensions (S/MIME)&quot;.
070 * <br>
071 * The following algorithms are required by Suite B of the United States Security Agency 
072 * (NSA) for use of ECC in S/MIME (see RFC 5008):
073 * <pre>
074 *                          Security Level 1   Security Level 2
075 *                          ----------------   ----------------
076 *    Message Digest:       SHA-256            SHA-384
077 *    Signature:            ECDSA with P-256   ECDSA with P-384
078 *    
079 *    
080 *
081 *                           Security Level 1   Security Level 2
082 *                          ----------------   ----------------
083 *    Key Agreement:        ECDH with P-256    ECDH with P-384
084 *    Key Derivation:       SHA-256            SHA-384
085 *    Key Wrap:             AES-128 Key Wrap   AES-256 Key Wrap
086 *    Content Encryption:   AES-128 CBC        AES-256 CBC
087 * </pre> 
088 * <br>
089 * The key encryption algorithms used during ECDH are 
090 * <code>dhSinglePass-stdDH-sha256kdf-scheme</code> for Security Level 1 and
091 * <code>dhSinglePass-stdDH-sha384kdf-scheme</code> for Security Level 2.
092 * <p> 
093 * Any keys/certificates required for this demo are read from a keystore
094 * file "cmsecc.keystore" located in your current working directory. If
095 * the keystore file does not exist you can create it by running the
096 * {@link demo.cms.ecc.keystore.SetupCMSEccKeyStore SetupCMSEccKeyStore}
097 * program. 
098 * <p>
099 * Additionally to <code>iaik_cms.jar</code> you also must have 
100 * <code>iaik_jce_(full).jar</code> (IAIK-JCE, <a href =
101 * "https://sic.tech/products/core-crypto-toolkits/jca-jce/" target="_blank">
102 * https://sic.tech/products/core-crypto-toolkits/jca-jce/</a>),
103 * and <code>iaik_eccelarate.jar</code> (IAIK-ECCelerate<sup><small>TM</small></sup>, <a href =
104 * "https://sic.tech/products/core-crypto-toolkits/eccelerate/" target="_blank">
105 * https://sic.tech/products/core-crypto-toolkits/eccelerate/</a>)
106 * in your classpath.
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>iaik_eccelerate.jar</code> (<a href="https://sic.tech/products/core-crypto-toolkits/eccelerate/" target="_blank">IAIK ECC Library</a>).
118 *    </li>   
119 *    <li>
120 *       <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
121 *    </li>   
122 *    <li>
123 *       <a href="https://jakarta.ee/specifications/activation/" target="_blank">Jakarta Activation Framework</a>
124 *    </li> 
125 * </ul>
126 * 
127 * @see demo.cms.ecc.keystore.SetupCMSEccKeyStore
128 * @see iaik.smime.SignedContent
129 * @see iaik.smime.EncryptedContent
130 */
131public class SMimeEccSuiteBDemo {
132    
133  // whether to print dump all generates test messages to System.out
134  final static boolean PRINT_MESSAGES = true;
135
136  String firstName = "John";
137  String lastName = "SMime";
138  String to = "smimetest@iaik.tugraz.at";     // email recipient
139  String from = "smimetest@iaik.tugraz.at";   // email sender
140  String host = "mailhost";                       // name of the mailhost
141
142  // keys and certs for security level 1 demo (256 bit)
143  X509Certificate[] signerCertificates1_;          // list of certificates to include in the S/MIME message
144  X509Certificate signerCertificate1_;             // certificate of the signer/sender
145  X509Certificate recipientCertificate1_;          // certificate of the recipient
146  X509Certificate encryptionCertOfSigner1_;        // signer uses different certificate for encryption
147  PrivateKey signerPrivateKey1_;                   // private key of the signer/sender
148  PrivateKey recipientKey1_;                       // private key of recipient
149  
150  // keys and certs for security level 2 demo (384 bit)
151  X509Certificate[] signerCertificates2_;          // list of certificates to include in the S/MIME message
152  X509Certificate signerCertificate2_;             // certificate of the signer/sender
153  X509Certificate recipientCertificate2_;          // certificate of the recipient
154  X509Certificate encryptionCertOfSigner2_;        // signer uses different certificate for encryption
155  PrivateKey signerPrivateKey2_;                   // private key of the signer/sender
156  PrivateKey recipientKey2_;                       // private key of recipient
157  
158  /**
159   * Default constructor. Reads certificates and keys from the demo keystore.
160   */
161  public SMimeEccSuiteBDemo() {
162    
163    System.out.println();
164    System.out.println("********************************************************************************************");
165    System.out.println("*                                SMimeEccSuiteBDemo demo                                   *");
166    System.out.println("*            (shows how to use NSA Suite B algorithms with ECDSA and ECDH                  *");
167    System.out.println("*                          to sign and encrypt S/MIME messages)                            *");
168    System.out.println("********************************************************************************************");
169    System.out.println();
170    
171    // get keys and certificates for security level 1 demo from KeyStore
172    
173    // signer
174    signerCertificates1_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_256_SIGN);
175    signerCertificate1_ = signerCertificates1_[0];
176    signerPrivateKey1_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_256_SIGN);
177    // recipient 
178    recipientCertificate1_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_256_CRYPT_1)[0];
179    recipientKey1_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_256_CRYPT_1);
180  
181    // encryption cert of signer 
182    encryptionCertOfSigner1_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_256_CRYPT_2)[0];
183    
184    // get keys and certificates for security level 2 demo from KeyStore
185    
186    // signer
187    signerCertificates2_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_384_SIGN);
188    signerCertificate2_ = signerCertificates2_[0];
189    signerPrivateKey2_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_384_SIGN);
190    // recipient 
191    recipientCertificate2_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_384_CRYPT_1)[0];
192    recipientKey2_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_384_CRYPT_1);
193    // encryption cert of signer 
194    encryptionCertOfSigner2_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_384_CRYPT_2)[0];
195
196  }
197  
198  /**
199   * Starts the demo.
200   *
201   * @throws IOException if an I/O related error occurs
202   */
203  public void start() throws IOException {
204    
205    // get the default Session
206        Session session = DemoSMimeUtil.getSession();
207
208        try {
209      // Create a demo Multipart
210      MimeBodyPart mbp1 = new SMimeBodyPart();
211          mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n");
212          // attachment
213      MimeBodyPart attachment = new SMimeBodyPart();
214      attachment.setDataHandler(new DataHandler(new FileDataSource("test.html")));
215      attachment.setFileName("test.html");
216
217      Multipart mp = new SMimeMultipart();
218      mp.addBodyPart(mbp1);
219      mp.addBodyPart(attachment);
220      DataHandler multipart = new DataHandler(mp, mp.getContentType());
221
222      Message msg;    // the message to send
223      ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
224      ByteArrayInputStream bais;  // we read from a stream
225
226        
227        
228      // Suite B Security Level 1 Signature: ECDSA with SHA-256 (ANSI X9.62)
229      
230      // This is an explicitly signed message (ecdsa-sha256)
231      AlgorithmID hashAlgorithm = AlgorithmID.sha256;
232      AlgorithmID signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA256;
233      msg = createSignedMessage(session, 
234                                multipart, 
235                                false, 
236                                hashAlgorithm, 
237                                signatureAlgorithm,
238                                signerPrivateKey1_,
239                                signerCertificates1_,
240                                encryptionCertOfSigner1_);
241      System.out.println("Suite B, Security Level 1: Creating explicitly signed message " + signatureAlgorithm.getName() + "...");
242      baos.reset();
243      msg.saveChanges(); 
244      msg.writeTo(baos);
245     
246      bais = new ByteArrayInputStream(baos.toByteArray());
247      msg = new MimeMessage(session, bais);
248      if (PRINT_MESSAGES) {
249        printMessage(msg);
250      }
251      DumpMessage.dumpMsg(msg);
252      
253      System.out.println("\n\n*****************************************\n\n");
254
255
256      // This is an implicitly signed message (ecdsa-sha256)
257      msg = createSignedMessage(session, 
258                                multipart, 
259                                true, 
260                                hashAlgorithm, 
261                                signatureAlgorithm,
262                                signerPrivateKey1_,
263                                signerCertificates1_,
264                                encryptionCertOfSigner1_);
265      System.out.println("Suite B, Security Level 1: Creating implicitly signed message " + signatureAlgorithm.getName() + "...");
266      baos.reset();
267      msg.saveChanges(); 
268      msg.writeTo(baos);
269      
270      bais = new ByteArrayInputStream(baos.toByteArray());
271      msg = new MimeMessage(session, bais);
272      if (PRINT_MESSAGES) {
273        printMessage(msg);
274      }
275      DumpMessage.dumpMsg(msg);
276      
277      System.out.println("\n\n*****************************************\n\n");
278
279      
280      // Suite B Security Level 2 Signature: ECDSA with SHA-384 (ANSI X9.62)
281      
282      // This is an explicitly signed message (ecdsa-sha384)
283      hashAlgorithm = AlgorithmID.sha384;
284      signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA384;
285      msg = createSignedMessage(session, 
286                                multipart, 
287                                false, 
288                                hashAlgorithm, 
289                                signatureAlgorithm,
290                                signerPrivateKey2_,
291                                signerCertificates2_,
292                                encryptionCertOfSigner2_);
293      System.out.println("Suite B, Security Level 2: Creating explicitly signed message " + signatureAlgorithm.getName() + "...");
294      baos.reset();
295      msg.saveChanges(); 
296      msg.writeTo(baos);
297      bais = new ByteArrayInputStream(baos.toByteArray());
298      msg = new MimeMessage(session, bais);
299      if (PRINT_MESSAGES) {
300        printMessage(msg);
301      }
302      DumpMessage.dumpMsg(msg);
303      
304      System.out.println("\n\n*****************************************\n\n");
305
306
307      // This is an implicitly signed message (ecdsa-sha384)
308      msg = createSignedMessage(session, 
309                                multipart, 
310                                true, 
311                                hashAlgorithm,
312                                signatureAlgorithm,
313                                signerPrivateKey2_,
314                                signerCertificates2_,
315                                encryptionCertOfSigner2_);
316      System.out.println("Suite B, Security Level 2: Creating implicitly signed message " + signatureAlgorithm.getName() + "...");
317      baos.reset();
318      msg.saveChanges(); 
319      msg.writeTo(baos);
320      bais = new ByteArrayInputStream(baos.toByteArray());
321      msg = new MimeMessage(session, bais);
322      if (PRINT_MESSAGES) {
323        printMessage(msg);
324      }
325      DumpMessage.dumpMsg(msg);
326      
327      System.out.println("\n\n*****************************************\n\n");
328        
329
330
331
332      // Now create encrypted messages 
333      
334      // Suite B Security Level 1 Encryption: ECDH with P-256, AES-128
335      
336      AlgorithmID contentEncAlg = AlgorithmID.aes128_CBC;
337      AlgorithmID keyEncAlg = CMSAlgorithmID.dhSinglePass_stdDH_sha256kdf_scheme;
338      AlgorithmID keyWrapAlg = CMSAlgorithmID.cms_aes128_wrap;
339      int contentEncKeyLength = 128;
340      int keyEncKeyLength = 128;
341          
342      msg = createEncryptedMessage(session, 
343                                   contentEncAlg, 
344                                   contentEncKeyLength,
345                                   keyEncAlg, 
346                                   keyWrapAlg, 
347                                   keyEncKeyLength,
348                                   recipientCertificate1_,
349                                   encryptionCertOfSigner1_);
350      System.out.println("Suite B, Security Level 1: Creating encrypted message [ECDH P-256, AES-128]...");
351      baos.reset();
352      msg.saveChanges(); 
353      msg.writeTo(baos);
354     
355      bais = new ByteArrayInputStream(baos.toByteArray());
356      msg = new MimeMessage(session, bais);
357      if (PRINT_MESSAGES) {
358        printMessage(msg);
359      }
360      DumpMessage dumpMsg = new DumpMessage();
361      dumpMsg.setRecipientKey(recipientKey1_);
362      dumpMsg.dump(msg);
363      
364      System.out.println("\n\n*****************************************\n\n");
365      
366      
367      // Suite B Security Level 2 Encryption: ECDH with P-384, AES-256
368      
369      contentEncAlg = AlgorithmID.aes256_CBC;
370      keyEncAlg = CMSAlgorithmID.dhSinglePass_stdDH_sha384kdf_scheme;
371      keyWrapAlg = CMSAlgorithmID.cms_aes256_wrap;
372      contentEncKeyLength = 256;
373      keyEncKeyLength = 256;
374      
375      msg = createEncryptedMessage(session, 
376                                   contentEncAlg, 
377                                   contentEncKeyLength,
378                                   keyEncAlg, 
379                                   keyWrapAlg, 
380                                   keyEncKeyLength,
381                                   recipientCertificate2_,
382                                   encryptionCertOfSigner2_);
383      System.out.println("Suite B, Security Level 2: Creating encrypted message [ECDH P-384, AES-256]...");
384      baos.reset();
385      msg.saveChanges(); 
386      msg.writeTo(baos);
387      bais = new ByteArrayInputStream(baos.toByteArray());
388      msg = new MimeMessage(session, bais);
389      if (PRINT_MESSAGES) {
390        printMessage(msg);
391      }
392      dumpMsg.setRecipientKey(recipientKey2_);
393      dumpMsg.dump(msg);
394      
395      System.out.println("\n\n*****************************************\n\n");
396      
397      
398        
399        
400      // signed + encrypted
401      
402      // Suite B Security Level 1: ECDSA with SHA-256; ECDH with P-256, AES-128
403      
404      // Now create implicitly signed and encrypted message with attachment
405      hashAlgorithm = AlgorithmID.sha256;
406      signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA256;
407      contentEncAlg = AlgorithmID.aes128_CBC;
408      keyEncAlg = CMSAlgorithmID.dhSinglePass_stdDH_sha256kdf_scheme;
409      keyWrapAlg = CMSAlgorithmID.cms_aes128_wrap;
410      contentEncKeyLength = 128;
411      keyEncKeyLength = 128;
412      msg = createSignedAndEncryptedMessage(session, 
413                                            multipart, 
414                                            true, 
415                                            hashAlgorithm, 
416                                            signatureAlgorithm,
417                                            signerPrivateKey1_,
418                                            signerCertificates1_,
419                                            encryptionCertOfSigner1_,
420                                            contentEncAlg, 
421                                            contentEncKeyLength,
422                                            keyEncAlg, 
423                                            keyWrapAlg, 
424                                            keyEncKeyLength,
425                                            recipientCertificate1_);
426      System.out.println("Suite B, Security Level 1: Creating implicitly signed " + signatureAlgorithm.getName() + " and encrypted message [ECDH P-256, AES-128]...");
427      baos.reset();
428      msg.saveChanges(); 
429      msg.writeTo(baos);
430     
431      bais = new ByteArrayInputStream(baos.toByteArray());
432      msg = new MimeMessage(session, bais);
433      if (PRINT_MESSAGES) {
434        printMessage(msg);
435      }
436      dumpMsg.setRecipientKey(recipientKey1_);
437      dumpMsg.dump(msg);
438      
439      System.out.println("\n\n*****************************************\n\n");
440
441      // Now create a explicitly signed and encrypted message with attachment
442      msg = createSignedAndEncryptedMessage(session, 
443                                            multipart, 
444                                            false, 
445                                            hashAlgorithm, 
446                                            signatureAlgorithm,
447                                            signerPrivateKey1_,
448                                            signerCertificates1_,
449                                            encryptionCertOfSigner1_,
450                                            contentEncAlg, 
451                                            contentEncKeyLength,
452                                            keyEncAlg, 
453                                            keyWrapAlg, 
454                                            keyEncKeyLength,
455                                            recipientCertificate1_);
456      System.out.println("Suite B, Security Level 1: Creating explicitly signed " + signatureAlgorithm.getName() + " and encrypted message [ECDH P-256, AES-128]...");
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      System.out.println("\n\n*****************************************\n\n");
467        
468        
469      // Suite B Security Level 2: ECDSA with SHA-384; ECDH with P-384, AES-256
470      
471      // Now create implicitly signed and encrypted message with attachment
472      hashAlgorithm = AlgorithmID.sha384;
473      signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA384;
474      contentEncAlg = AlgorithmID.aes256_CBC;
475      keyEncAlg = CMSAlgorithmID.dhSinglePass_stdDH_sha384kdf_scheme;
476      keyWrapAlg = CMSAlgorithmID.cms_aes256_wrap;
477      contentEncKeyLength = 256;
478      keyEncKeyLength = 256;
479      msg = createSignedAndEncryptedMessage(session, 
480                                            multipart, 
481                                            true, 
482                                            hashAlgorithm, 
483                                            signatureAlgorithm,
484                                            signerPrivateKey2_,
485                                            signerCertificates2_,
486                                            encryptionCertOfSigner2_,
487                                            contentEncAlg, 
488                                            contentEncKeyLength,
489                                            keyEncAlg, 
490                                            keyWrapAlg, 
491                                            keyEncKeyLength,
492                                            recipientCertificate2_);
493      System.out.println("Suite B, Security Level 1: Creating implicitly signed " + signatureAlgorithm.getName() + " and encrypted message [ECDH P-384, AES-256]...");
494      baos.reset();
495      msg.saveChanges();
496      msg.writeTo(baos);
497      bais = new ByteArrayInputStream(baos.toByteArray());
498      msg = new MimeMessage(session, bais);
499      if (PRINT_MESSAGES) {
500        printMessage(msg);
501      }
502      dumpMsg.setRecipientKey(recipientKey2_);
503      dumpMsg.dump(msg);
504      
505      System.out.println("\n\n*****************************************\n\n");
506
507      // Now create a explicitly signed and encrypted message with attachment
508      msg = createSignedAndEncryptedMessage(session, 
509                                            multipart, 
510                                            false, 
511                                            hashAlgorithm, 
512                                            signatureAlgorithm,
513                                            signerPrivateKey2_,
514                                            signerCertificates2_,
515                                            encryptionCertOfSigner2_,
516                                            contentEncAlg, 
517                                            contentEncKeyLength,
518                                            keyEncAlg, 
519                                            keyWrapAlg, 
520                                            keyEncKeyLength,
521                                            recipientCertificate2_);
522      System.out.println("Suite B, Security Level 1: Creating explicitly signed " + signatureAlgorithm.getName() + " and encrypted message [ECDH P-384, AES-256]...");
523      baos.reset();
524      msg.saveChanges(); 
525      msg.writeTo(baos);
526      bais = new ByteArrayInputStream(baos.toByteArray());
527      msg = new MimeMessage(session, bais);
528      if (PRINT_MESSAGES) {
529        printMessage(msg);
530      }
531      DumpMessage.dumpMsg(msg);
532      System.out.println("\n\n*****************************************\n\n");
533
534
535        } catch (Exception ex) {
536          ex.printStackTrace();
537          throw new RuntimeException(ex.toString());
538        }
539
540        System.out.println("OK!");
541        
542  }
543
544  /**
545   * Creates a MIME message container with the given subject for the given session.
546   * 
547   * @param session the mail sesion
548   * @param subject the subject of the message
549   *
550   * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content)
551   *
552   * @throws MessagingException if the message cannot be created
553   */
554  public Message createMessage(Session session, String subject) throws MessagingException {
555    MimeMessage msg = new MimeMessage(session);
556    msg.setFrom(new InternetAddress(from));
557        msg.setRecipients(Message.RecipientType.TO,     InternetAddress.parse(to, false));
558        msg.setSentDate(new Date());
559    msg.setSubject(subject);
560    return msg;
561  }
562  
563    
564  /**
565   * Creates a signed message.
566   *
567   * @param session the mail session
568   * @param dataHandler the content of the message to be signed
569   * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
570   *                 (multipart/signed) signing
571   * @param hashAlgorithm the hash algorithm to be used                
572   * @param signatureAlgorithm the signature algorithm to be used
573   * @param signerPrivateKey the private key of the signer
574   * @param signerCertificates the certificate chain of the signer
575   * @param encryptionCertOfSigner the encryption certificate of the signer
576   *                               (to be announced within the SignerInfo)
577   * 
578   * @return the signed message
579   *
580   * @throws MessagingException if an error occurs when creating the message
581   */
582  public Message createSignedMessage(Session session, 
583                                     DataHandler dataHandler,
584                                     boolean implicit,
585                                     AlgorithmID hashAlgorithm,
586                                     AlgorithmID signatureAlgorithm,
587                                     PrivateKey signerPrivateKey,
588                                     X509Certificate[] signerCertificates,
589                                     X509Certificate encryptionCertOfSigner)
590      throws MessagingException {
591
592    String subject = null;
593    StringBuffer buf = new StringBuffer();
594    
595    if (implicit) {
596      subject = "IAIK-S/MIME: Implicitly Signed (" + signatureAlgorithm.getName() +")";
597      buf.append("This message is implicitly signed with ! " + signatureAlgorithm.getName() + "\n");
598      buf.append("You need an S/MIME aware mail client to view this message.\n");
599      buf.append("\n\n");
600    } else {
601      subject = "IAIK-S/MIME: Explicitly Signed (" + signatureAlgorithm.getName() +")";
602      buf.append("This message is explicitly signed!\n");
603      buf.append("Every mail client can view this message.\n");
604      buf.append("Non S/MIME mail clients will show the signature as attachment.\n");
605      buf.append("\n\n");
606    }
607    
608    Message msg = createMessage(session, subject);
609    
610    SignedContent sc = new SignedContent(implicit);
611    if (dataHandler != null) {
612      sc.setDataHandler(dataHandler);
613    } else {
614      sc.setText(buf.toString());
615    }
616    sc.setCertificates(signerCertificates);
617
618    AlgorithmID ecdsaSig = (AlgorithmID)signatureAlgorithm.clone();
619    // CMS-ECDSA requires to encode the parameter field as NULL (see RFC 3278)
620    ecdsaSig.encodeAbsentParametersAsNull(true);
621    try {
622      sc.addSigner(signerPrivateKey, 
623                   signerCertificates[0], 
624                   (AlgorithmID)hashAlgorithm.clone(),
625                   ecdsaSig,
626                   encryptionCertOfSigner,
627                   true);
628    } catch (NoSuchAlgorithmException ex) {
629      throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
630    }
631
632    msg.setContent(sc, sc.getContentType());
633    // let the SignedContent update some message headers
634    sc.setHeaders(msg);
635    return msg;
636  }
637  
638  /**
639   * Creates an encrypted message.
640   *
641   * @param session the mail session
642   * @param contentEA the content encryption algorithm to be used
643   * @param keyLength the length of the secret content encryption key to be created and used
644   * @param keyEA the key encryption algorithm to be used
645   * @param keyWrapAlg the key wrap algorithm to be used
646   * @param kekLength the length of the key encryption algorithm
647   * @param recipientCertificate the encryption certificate of the recipient
648   * @param encryptionCertOfSender the encryption certificate of the sender
649   * 
650   * @return the encrypted message
651   *
652   * @throws MessagingException if an error occurs when creating the message
653   */
654  public Message createEncryptedMessage(Session session, 
655                                        AlgorithmID contentEA, 
656                                        int keyLength,
657                                        AlgorithmID keyEA, 
658                                        AlgorithmID keyWrapAlg,
659                                        int kekLength,
660                                        X509Certificate recipientCertificate,
661                                        X509Certificate encryptionCertOfSender)
662    throws MessagingException {
663    
664    StringBuffer subject = new StringBuffer();
665    subject.append("IAIK-S/MIME: Encrypted ["+contentEA.getName());
666    if (keyLength > 0) {
667      subject.append("/"+keyLength);
668    }  
669    subject.append("]");
670    Message msg = createMessage(session, subject.toString());
671
672    EncryptedContent ec = new EncryptedContent();
673
674    StringBuffer buf = new StringBuffer();
675    buf.append("This is the encrypted content!\n");
676    buf.append("Content encryption algorithm: "+contentEA.getName());
677    buf.append("\n\n");
678
679    ec.setText(buf.toString());
680    
681    try {  
682      ec.addRecipient(recipientCertificate, (AlgorithmID)keyEA.clone(), (AlgorithmID)keyWrapAlg.clone(), kekLength);
683    } catch (SMimeException ex) {
684      throw new MessagingException("Error adding ECDH recipient: " + ex.getMessage());   
685    }    
686    // Sender want to be able to decrypt the message, too
687    try {
688      ec.addRecipient(encryptionCertOfSender, (AlgorithmID)keyEA.clone(), (AlgorithmID)keyWrapAlg.clone(), kekLength);
689    } catch (SMimeException ex) {
690      throw new MessagingException("Error adding ECDH recipient: " + ex.getMessage());   
691    }
692    try {
693      ec.setEncryptionAlgorithm((AlgorithmID)contentEA.clone(), keyLength);
694    } catch (NoSuchAlgorithmException ex) {
695      throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
696    }    
697
698    msg.setContent(ec, ec.getContentType());
699    // let the EncryptedContent update some message headers
700    ec.setHeaders(msg);
701
702    return msg;
703  }
704  
705  /**
706   * Creates a signed and encrypted message.
707   *
708   * @param session the mail session
709   * @param dataHandler the content of the message to be signed and encrypted
710   * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
711   *                 (multipart/signed) signing
712   * @param hashAlgorithm the hash algorithm to be used
713   * @param signatureAlgorithm the signature algorithm to be used
714   * @param signerPrivateKey the private key of the signer
715   * @param signerCertificates the certificate chain of the signer
716   * @param encryptionCertOfSigner the encryption certificate of the signer
717   *                               (to be announced within the SignerInfo)
718   * @param contentEA the content encryption algorithm to be used
719   * @param keyLength the length of the secret content encryption key to be created and used
720   * @param keyEA the key encryption algorithm to be used
721   * @param keyWrapAlgorithm the key wrap algorithm to be used
722   * @param kekLength the length of the key encryption algorithm
723   * @param recipientCertificate the encryption certificate of the recipient
724   * 
725   * @return the signed and encrypted message
726   *
727   * @throws MessagingException if an error occurs when creating the message
728   */
729  public Message createSignedAndEncryptedMessage(Session session, 
730                                                 DataHandler dataHandler,
731                                                 boolean implicit,
732                                                 AlgorithmID hashAlgorithm,
733                                                 AlgorithmID signatureAlgorithm,
734                                                 PrivateKey signerPrivateKey,
735                                                 X509Certificate[] signerCertificates,
736                                                 X509Certificate encryptionCertOfSigner, 
737                                                 AlgorithmID contentEA, 
738                                                 int keyLength,
739                                                 AlgorithmID keyEA, 
740                                                 AlgorithmID keyWrapAlgorithm,
741                                                 int kekLength,
742                                                 X509Certificate recipientCertificate)
743    throws MessagingException {
744
745    String subject = null;
746    String text = null;
747    if (implicit) {
748      subject = "IAIK-S/MIME: Implicitly Signed (" + signatureAlgorithm.getName() + ") and Encrypted (" + contentEA.getName() + ")";
749      text = "This message is implicitly signed (" + signatureAlgorithm.getName() + ") and Encrypted (" + contentEA.getName() + ")!\n\n\n";
750    } else {
751      subject = "IAIK-S/MIME: Explicitly Signed (" + signatureAlgorithm.getName() + ") and Encrypted (" + contentEA.getName() + ")";
752      text = "This message is explicitly signed (" + signatureAlgorithm.getName() + ") and Encrypted (" + contentEA.getName() + ")!\n\n\n";
753    }
754    Message msg = createMessage(session, subject);
755
756    SignedContent sc = new SignedContent(implicit);
757    if (dataHandler != null) {
758      sc.setDataHandler(dataHandler);
759    } else {
760      sc.setText(text);
761    }
762    sc.setCertificates(signerCertificates);
763    AlgorithmID ecdsaSig = (AlgorithmID)signatureAlgorithm.clone();
764    // CMS-ECC requires that the parameters field is encoded as ASN.1 NULL object (see RFC 3278)
765    ecdsaSig.encodeAbsentParametersAsNull(true);
766    try {
767      sc.addSigner(signerPrivateKey, 
768                   signerCertificates[0], 
769                   (AlgorithmID)hashAlgorithm.clone(),
770                   ecdsaSig,
771                   encryptionCertOfSigner,
772                   true);
773    } catch (NoSuchAlgorithmException ex) {
774      throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
775    }
776
777    EncryptedContent ec = new EncryptedContent(sc);
778    // encrypt for the recipient
779    try {  
780      ec.addRecipient(recipientCertificate, (AlgorithmID)keyEA.clone(), (AlgorithmID)keyWrapAlgorithm.clone(), kekLength);
781    } catch (SMimeException ex) {
782      throw new MessagingException("Error adding ECDH recipient: " + ex.getMessage());   
783    } 
784    try {
785      // I want to be able to decrypt the message, too
786      ec.addRecipient(encryptionCertOfSigner, (AlgorithmID)keyEA.clone(), (AlgorithmID)keyWrapAlgorithm.clone(), kekLength);
787    } catch (SMimeException ex) {
788      throw new MessagingException("Error adding ECDH recipient: " + ex.getMessage());   
789    }
790    // set the encryption algorithm
791    try {
792      ec.setEncryptionAlgorithm(contentEA, keyLength);
793    } catch (NoSuchAlgorithmException ex) {
794      throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
795    }   
796    msg.setContent(ec, ec.getContentType());
797    // let the EncryptedContent update some message headers
798    ec.setHeaders(msg);
799
800    return msg;
801  }
802
803  
804  /** 
805   * Prints a dump of the given message to System.out.
806   *
807   * @param msg the message to be dumped to System.out
808   *
809   * @throws IOException if an I/O error occurs
810   */
811  private static void printMessage(Message msg) throws IOException {
812    System.out.println("------------------------------------------------------------------");
813    System.out.println("Message dump: \n");
814    try {
815      msg.writeTo(System.out);
816    } catch (MessagingException ex) {
817      throw new IOException(ex.getMessage());   
818    }    
819    System.out.println("\n------------------------------------------------------------------");
820  }  
821
822
823  /**
824   * The main method.
825   */
826  public static void main(String[] argv) throws Exception {
827     
828    DemoSMimeUtil.initDemos();
829    // add ECC provider    
830    ECCDemoUtil.installIaikEccProvider();
831        (new SMimeEccSuiteBDemo()).start();
832    System.out.println("\nReady!");
833    DemoUtil.waitKey();
834  }
835}