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/SMimeEccDemo.java 29    12.02.25 17:59 Dbratko $
029// $Revision: 29 $
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
068 * ECDSA (with SHA1, SHA224, SHA256, SHA384, SHA512, RIPEMD160) signed and/or ECDH based 
069 * encrypted S/MIMEv3 messages and how to parse them and verify the signatures 
070 * and decrypt the content, respectively.
071 * <p>
072 * Any keys/certificates required for this demo are read from a keystore
073 * file "cmsecc.keystore" located in your current working directory. If
074 * the keystore file does not exist you can create it by running the
075 * {@link demo.cms.ecc.keystore.SetupCMSEccKeyStore SetupCMSEccKeyStore}
076 * program. 
077 * <p>
078 * Additionally to <code>iaik_cms.jar</code> you also must have 
079 * <code>iaik_jce_(full).jar</code> (IAIK-JCE, <a href =
080 * "https://sic.tech/products/core-crypto-toolkits/jca-jce/" target="_blank">
081 * https://sic.tech/products/core-crypto-toolkits/jca-jce/</a>),
082 * and <code>iaik_eccelarate.jar</code> (IAIK-ECCelerate<sup><small>TM</small></sup>, <a href =
083 * "https://sic.tech/products/core-crypto-toolkits/eccelerate/" target="_blank">
084 * https://sic.tech/products/core-crypto-toolkits/eccelerate/</a>)
085 * in your classpath.
086 * <p>
087 * To run this demo the following packages are required:
088 * <ul>
089 *    <li>
090 *       <code>iaik_cms.jar</code>
091 *    </li>
092 *    <li>
093 *       <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>).
094 *    </li>
095 *    <li>
096 *       <code>iaik_eccelerate.jar</code> (<a href="https://sic.tech/products/core-crypto-toolkits/eccelerate/" target="_blank">IAIK ECC Library</a>).
097 *    </li>   
098 *    <li>
099 *       <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
100 *    </li>   
101 *    <li>
102 *       <a href="https://jakarta.ee/specifications/activation/" target="_blank">Jakarta Activation Framework</a>
103 *    </li> 
104 * </ul>
105 * 
106 * @see demo.cms.ecc.keystore.SetupCMSEccKeyStore
107 * @see iaik.smime.SignedContent
108 * @see iaik.smime.EncryptedContent
109 */
110public class SMimeEccDemo {
111    
112  // whether to print dump all generates test messages to System.out
113  final static boolean PRINT_MESSAGES = false;   
114
115  String firstName = "John";
116  String lastName = "SMime";
117  String to = "smimetest@iaik.tugraz.at";     // email recipient
118  String from = "smimetest@iaik.tugraz.at";   // email sender
119  String host = "mailhost";                       // name of the mailhost
120
121  X509Certificate[] signerCertificates;          // list of certificates to include in the S/MIME message
122  X509Certificate recipientCertificate;          // certificate of the recipient
123  X509Certificate signerCertificate;             // certificate of the signer/sender
124  X509Certificate encryptionCertOfSigner;        // signer uses different certificate for encryption
125  // we use the same signer key for all demos here; in practice you should use a curve
126  // matching the security of the hash algorithm used by the signature algorithm
127  PrivateKey signerPrivateKey;                   // private key of the signer/sender
128  
129  
130  
131  /**
132   * Default constructor. Reads certificates and keys from the demo keystore.
133   */
134  public SMimeEccDemo() {
135    
136    System.out.println();
137    System.out.println("********************************************************************************************");
138    System.out.println("*                                SMimeEccDemo demo                                         *");
139    System.out.println("* (shows how to create and parse (verify, decrypt) signed and encrypted S/MIMEv3 messages  *");
140    System.out.println("*                 using ECDSA for signing and ECDH for key agreement)                      *");
141    System.out.println("********************************************************************************************");
142    System.out.println();
143    
144    // get the certificates from the KeyStore
145    signerCertificates = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_256_SIGN);
146    signerCertificate = signerCertificates[0];
147    signerPrivateKey = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_256_SIGN);
148    
149
150    // recipient 
151    recipientCertificate = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_256_CRYPT_1)[0];
152    PrivateKey recipientKey = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_256_CRYPT_1);
153    
154    // encryption cert of signer (in practice we will not use different key lenghts for recipients)
155    encryptionCertOfSigner = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_256_CRYPT_2)[0];
156  }
157  
158  /**
159   * Starts the demo.
160   *
161   * @throws IOException if an I/O related error occurs
162   */
163  public void start() throws IOException {
164    
165    // get the default Session
166        Session session = DemoSMimeUtil.getSession();
167
168        try {
169      // Create a demo Multipart
170      MimeBodyPart mbp1 = new SMimeBodyPart();
171          mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n");
172          // attachment
173      MimeBodyPart attachment = new SMimeBodyPart();
174      attachment.setDataHandler(new DataHandler(new FileDataSource("test.html")));
175      attachment.setFileName("test.html");
176
177      Multipart mp = new SMimeMultipart();
178      mp.addBodyPart(mbp1);
179      mp.addBodyPart(attachment);
180      DataHandler multipart = new DataHandler(mp, mp.getContentType());
181
182      Message msg;    // the message to send
183      ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
184      ByteArrayInputStream bais;  // we read from a stream
185
186      // ECDSA with SHA-1 (ANSI X9.62)
187      
188      // This is an explicitly signed message (ecdsa-sha1)
189      AlgorithmID hashAlgorithm = AlgorithmID.sha1;
190      AlgorithmID signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA1;
191      msg = createSignedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm);
192      System.out.println("creating explicitly signed message " + signatureAlgorithm.getName() + "...");
193      baos.reset();
194          msg.saveChanges(); 
195          msg.writeTo(baos);
196
197          bais = new ByteArrayInputStream(baos.toByteArray());
198          msg = new MimeMessage(session, bais);
199          if (PRINT_MESSAGES) {
200        printMessage(msg);
201      }
202          DumpMessage.dumpMsg(msg);
203          
204          System.out.println("\n\n*****************************************\n\n");
205
206
207      // This is an implicitly signed message (ecdsa-sha1)
208      msg = createSignedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm);
209      System.out.println("creating implicitly signed message " + signatureAlgorithm.getName() + "...");
210          baos.reset();
211          msg.saveChanges(); 
212          msg.writeTo(baos);
213     
214          bais = new ByteArrayInputStream(baos.toByteArray());
215          msg = new MimeMessage(session, bais);
216          if (PRINT_MESSAGES) {
217        printMessage(msg);
218      }
219          DumpMessage.dumpMsg(msg);
220          
221          System.out.println("\n\n*****************************************\n\n");
222      
223      
224      
225      // ECDSA with SHA-224 (ANSI X9.62)
226      
227      // This is an explicitly signed message (ecdsa-sha224)
228      hashAlgorithm = CMSAlgorithmID.sha224;
229      signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA224;
230      msg = createSignedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm);
231      System.out.println("creating explicitly signed message " + signatureAlgorithm.getName() + "...");
232      baos.reset();
233      msg.saveChanges(); 
234      msg.writeTo(baos);
235   
236      bais = new ByteArrayInputStream(baos.toByteArray());
237      msg = new MimeMessage(session, bais);
238      if (PRINT_MESSAGES) {
239        printMessage(msg);
240      }
241      DumpMessage.dumpMsg(msg);
242      
243      System.out.println("\n\n*****************************************\n\n");
244
245
246      // This is an implicitly signed message (ecdsa-sha224)
247      msg = createSignedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm);
248      System.out.println("creating implicitly signed message " + signatureAlgorithm.getName() + "...");
249      baos.reset();
250      msg.saveChanges(); 
251      msg.writeTo(baos);
252      
253      bais = new ByteArrayInputStream(baos.toByteArray());
254      msg = new MimeMessage(session, bais);
255      if (PRINT_MESSAGES) {
256        printMessage(msg);
257      }
258      DumpMessage.dumpMsg(msg);
259      
260      System.out.println("\n\n*****************************************\n\n");
261      
262      
263      // ECDSA with SHA-256 (ANSI X9.62)
264      
265      // This is an explicitly signed message (ecdsa-sha256)
266      hashAlgorithm = AlgorithmID.sha256;
267      signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA256;
268      msg = createSignedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm);
269      System.out.println("creating explicitly signed message " + signatureAlgorithm.getName() + "...");
270      baos.reset();
271      msg.saveChanges(); 
272      msg.writeTo(baos);
273    
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
284      // This is an implicitly signed message (ecdsa-sha256)
285      msg = createSignedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm);
286      System.out.println("creating implicitly signed message " + signatureAlgorithm.getName() + "...");
287      baos.reset();
288      msg.saveChanges(); 
289      msg.writeTo(baos);
290     
291      bais = new ByteArrayInputStream(baos.toByteArray());
292      msg = new MimeMessage(session, bais);
293      if (PRINT_MESSAGES) {
294        printMessage(msg);
295      }
296      DumpMessage.dumpMsg(msg);
297      
298      System.out.println("\n\n*****************************************\n\n");
299
300      
301      // ECDSA with SHA-384 (ANSI X9.62)
302      
303      // This is an explicitly signed message (ecdsa-sha384)
304      hashAlgorithm = AlgorithmID.sha384;
305      signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA384;
306      msg = createSignedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm);
307      System.out.println("creating explicitly signed message " + signatureAlgorithm.getName() + "...");
308      baos.reset();
309      msg.saveChanges(); 
310      msg.writeTo(baos);
311 
312      bais = new ByteArrayInputStream(baos.toByteArray());
313      msg = new MimeMessage(session, bais);
314      if (PRINT_MESSAGES) {
315        printMessage(msg);
316      }
317      DumpMessage.dumpMsg(msg);
318      
319      System.out.println("\n\n*****************************************\n\n");
320
321
322      // This is an implicitly signed message (ecdsa-sha384)
323      msg = createSignedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm);
324      System.out.println("creating implicitly signed message " + signatureAlgorithm.getName() + "...");
325      baos.reset();
326      msg.saveChanges(); 
327      msg.writeTo(baos);
328      
329      bais = new ByteArrayInputStream(baos.toByteArray());
330      msg = new MimeMessage(session, bais);
331      if (PRINT_MESSAGES) {
332        printMessage(msg);
333      }
334      DumpMessage.dumpMsg(msg);
335      
336      System.out.println("\n\n*****************************************\n\n");
337      
338      
339      // ECDSA with SHA-512 (ANSI X9.62)
340      
341      // This is an explicitly signed message (ecdsa-sha512)
342      hashAlgorithm = AlgorithmID.sha512;
343      signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA512;
344      msg = createSignedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm);
345      System.out.println("creating explicitly signed message " + signatureAlgorithm.getName() + "...");
346      baos.reset();
347      msg.saveChanges(); 
348      msg.writeTo(baos);
349     
350      bais = new ByteArrayInputStream(baos.toByteArray());
351      msg = new MimeMessage(session, bais);
352      if (PRINT_MESSAGES) {
353        printMessage(msg);
354      }
355      DumpMessage.dumpMsg(msg);
356      
357      System.out.println("\n\n*****************************************\n\n");
358
359
360      // This is an implicitly signed message (ecdsa-sha512)
361      msg = createSignedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm);
362      System.out.println("creating implicitly signed message " + signatureAlgorithm.getName() + "...");
363      baos.reset();
364      msg.saveChanges(); 
365      msg.writeTo(baos);
366      
367      bais = new ByteArrayInputStream(baos.toByteArray());
368      msg = new MimeMessage(session, bais);
369      if (PRINT_MESSAGES) {
370        printMessage(msg);
371      }
372      DumpMessage.dumpMsg(msg);
373      
374      System.out.println("\n\n*****************************************\n\n");
375      
376      
377      
378      // ECDSA with RIPEMD-160 (plain format, BSI)
379      
380      // This is an explicitly signed message (ecdsa-plain-ripemd160)
381      hashAlgorithm = AlgorithmID.ripeMd160;
382      signatureAlgorithm = CMSAlgorithmID.ecdsa_plain_With_RIPEMD160;
383      msg = createSignedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm);
384      System.out.println("creating explicitly signed message " + signatureAlgorithm.getName() + "...");
385      baos.reset();
386      msg.saveChanges(); 
387      msg.writeTo(baos);
388    
389      bais = new ByteArrayInputStream(baos.toByteArray());
390      msg = new MimeMessage(session, bais);
391      if (PRINT_MESSAGES) {
392        printMessage(msg);
393      }
394      DumpMessage.dumpMsg(msg);
395      
396      System.out.println("\n\n*****************************************\n\n");
397
398
399      // This is an implicitly signed message (ecdsa-plain-ripemd160)
400      msg = createSignedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm);
401      System.out.println("creating implicitly signed message " + signatureAlgorithm.getName() + "...");
402      baos.reset();
403      msg.saveChanges(); 
404      msg.writeTo(baos);
405      
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      System.out.println("\n\n*****************************************\n\n");
414     
415
416
417      // Now create encrypted messages with different content encryption algorithms
418   
419      // RC2 is deprecated; only demonstrated here
420      msg = createEncryptedMessage(session, 
421                                   (AlgorithmID)AlgorithmID.rc2_CBC.clone(),
422                                   128,
423                                   (CMSAlgorithmID)CMSAlgorithmID.dhSinglePass_stdDH_sha1kdf_scheme.clone(),
424                                   (AlgorithmID)AlgorithmID.cms_rc2_wrap.clone(),
425                                   128);
426      System.out.println("creating encrypted message [RC2/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          DumpMessage.dumpMsg(msg);
437          
438          
439          System.out.println("\n\n*****************************************\n\n");
440          
441          // TripleDES is deprecated; only demonstrated here
442      msg = createEncryptedMessage(session, 
443                                   (AlgorithmID)AlgorithmID.des_EDE3_CBC.clone(), 
444                                   192,
445                                   (CMSAlgorithmID)CMSAlgorithmID.dhSinglePass_stdDH_sha1kdf_scheme.clone(), 
446                                   (AlgorithmID)AlgorithmID.cms_3DES_wrap.clone(), 
447                                   192);
448      System.out.println("creating encrypted message [TripleDES]...");
449          baos.reset();
450          msg.saveChanges(); 
451          msg.writeTo(baos);
452      
453          bais = new ByteArrayInputStream(baos.toByteArray());
454          msg = new MimeMessage(session, bais);
455          if (PRINT_MESSAGES) {
456        printMessage(msg);
457      }
458          DumpMessage.dumpMsg(msg);
459          
460          System.out.println("\n\n*****************************************\n\n");
461   
462      msg = createEncryptedMessage(session, 
463                                   (AlgorithmID)AlgorithmID.aes128_CBC.clone(), 
464                                   128,
465                                   (CMSAlgorithmID)CMSAlgorithmID.dhSinglePass_stdDH_sha1kdf_scheme.clone(),  
466                                   (AlgorithmID)CMSAlgorithmID.cms_aes128_wrap.clone(), 
467                                   128);
468      System.out.println("creating encrypted message [AES]...");
469      baos.reset();
470      msg.saveChanges(); 
471      msg.writeTo(baos);
472     
473      bais = new ByteArrayInputStream(baos.toByteArray());
474      msg = new MimeMessage(session, bais);
475      if (PRINT_MESSAGES) {
476        printMessage(msg);
477      }
478      DumpMessage.dumpMsg(msg);
479      
480      System.out.println("\n\n*****************************************\n\n");
481      
482      msg = createEncryptedMessage(session, 
483                                   (AlgorithmID)AlgorithmID.aes256_CBC.clone(), 
484                                   256,
485                                   (CMSAlgorithmID)CMSAlgorithmID.dhSinglePass_stdDH_sha256kdf_scheme.clone(),  
486                                   (AlgorithmID)CMSAlgorithmID.cms_aes256_wrap.clone(), 
487                                   256);
488      System.out.println("creating encrypted message [AES-256]...");
489      baos.reset();
490      msg.saveChanges();
491      msg.writeTo(baos);
492
493      bais = new ByteArrayInputStream(baos.toByteArray());
494      msg = new MimeMessage(session, bais);
495      if (PRINT_MESSAGES) {
496        printMessage(msg);
497      }
498      DumpMessage.dumpMsg(msg);
499
500      System.out.println("\n\n*****************************************\n\n");
501      
502      
503      
504      // signed (ecdsa-sha1) + encrypted 
505      
506      // Now create implicitly signed and encrypted message with attachment
507      hashAlgorithm = AlgorithmID.sha1;
508      signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA1;
509      msg = createSignedAndEncryptedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm);
510      System.out.println("creating implicitly signed " + signatureAlgorithm.getName() + " and encrypted message ...");
511          baos.reset();
512          msg.saveChanges(); 
513          msg.writeTo(baos);
514     
515          bais = new ByteArrayInputStream(baos.toByteArray());
516          msg = new MimeMessage(session, bais);
517          if (PRINT_MESSAGES) {
518        printMessage(msg);
519      }
520          DumpMessage.dumpMsg(msg);
521          
522          System.out.println("\n\n*****************************************\n\n");
523
524      // Now create a explicitly signed and encrypted message with attachment
525      msg = createSignedAndEncryptedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm);
526      System.out.println("creating explicitly signed " + signatureAlgorithm.getName() + " and encrypted message ...");
527          baos.reset();
528          msg.saveChanges();
529          msg.writeTo(baos);
530     
531          bais = new ByteArrayInputStream(baos.toByteArray());
532          msg = new MimeMessage(session, bais);
533          if (PRINT_MESSAGES) {
534        printMessage(msg);
535      }
536          DumpMessage.dumpMsg(msg);
537          System.out.println("\n\n*****************************************\n\n");
538      
539     
540      // ECDSA with SHA-2 
541    
542      // signed (ecdsa-sha224) + encrypted 
543      
544      // Now create implicitly signed and encrypted message with attachment
545      hashAlgorithm = CMSAlgorithmID.sha224;
546      signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA224;
547      msg = createSignedAndEncryptedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm);
548      System.out.println("creating implicitly signed " + signatureAlgorithm.getName() + " and encrypted message ...");
549      baos.reset();
550      msg.saveChanges();
551      msg.writeTo(baos);
552      
553      bais = new ByteArrayInputStream(baos.toByteArray());
554      msg = new MimeMessage(session, bais);
555      if (PRINT_MESSAGES) {
556        printMessage(msg);
557      }
558      DumpMessage.dumpMsg(msg);
559      
560      System.out.println("\n\n*****************************************\n\n");
561
562      // Now create a explicitly signed and encrypted message with attachment
563      msg = createSignedAndEncryptedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm);
564      System.out.println("creating explicitly signed " + signatureAlgorithm.getName() + " and encrypted message ...");
565      baos.reset();
566      msg.saveChanges(); 
567      msg.writeTo(baos);
568  
569      bais = new ByteArrayInputStream(baos.toByteArray());
570      msg = new MimeMessage(session, bais);
571      if (PRINT_MESSAGES) {
572        printMessage(msg);
573      }
574      DumpMessage.dumpMsg(msg);
575      System.out.println("\n\n*****************************************\n\n");
576      
577      
578      // signed (ecdsa-sha256) + encrypted 
579      
580      // Now create implicitly signed and encrypted message with attachment
581      hashAlgorithm = AlgorithmID.sha256;
582      signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA256;
583      msg = createSignedAndEncryptedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm);
584      System.out.println("creating implicitly signed " + signatureAlgorithm.getName() + " and encrypted message ...");
585      baos.reset();
586      msg.saveChanges();  
587      msg.writeTo(baos);
588      
589      bais = new ByteArrayInputStream(baos.toByteArray());
590      msg = new MimeMessage(session, bais);
591      if (PRINT_MESSAGES) {
592        printMessage(msg);
593      }
594      DumpMessage.dumpMsg(msg);
595      
596      System.out.println("\n\n*****************************************\n\n");
597
598      // Now create a explicitly signed and encrypted message with attachment
599      msg = createSignedAndEncryptedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm);
600      System.out.println("creating explicitly signed " + signatureAlgorithm.getName() + " and encrypted message ...");
601      baos.reset();
602      msg.saveChanges();  
603      msg.writeTo(baos);
604     
605      bais = new ByteArrayInputStream(baos.toByteArray());
606      msg = new MimeMessage(session, bais);
607      if (PRINT_MESSAGES) {
608        printMessage(msg);
609      }
610      DumpMessage.dumpMsg(msg);
611      System.out.println("\n\n*****************************************\n\n");
612      
613      
614      // signed (ecdsa-sha384) + encrypted 
615      
616      // Now create implicitly signed and encrypted message with attachment
617      hashAlgorithm = AlgorithmID.sha384;
618      signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA384;
619      msg = createSignedAndEncryptedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm);
620      System.out.println("creating implicitly signed " + signatureAlgorithm.getName() + " and encrypted message ...");
621      baos.reset();
622      msg.saveChanges();  
623      msg.writeTo(baos);
624    
625      bais = new ByteArrayInputStream(baos.toByteArray());
626      msg = new MimeMessage(session, bais);
627      if (PRINT_MESSAGES) {
628        printMessage(msg);
629      }
630      DumpMessage.dumpMsg(msg);
631      
632      System.out.println("\n\n*****************************************\n\n");
633
634      // Now create a explicitly signed and encrypted message with attachment
635      msg = createSignedAndEncryptedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm);
636      System.out.println("creating explicitly signed " + signatureAlgorithm.getName() + " and encrypted message ...");
637      baos.reset();
638      msg.saveChanges();  
639      msg.writeTo(baos);
640    
641      bais = new ByteArrayInputStream(baos.toByteArray());
642      msg = new MimeMessage(session, bais);
643      if (PRINT_MESSAGES) {
644        printMessage(msg);
645      }
646      DumpMessage.dumpMsg(msg);
647      System.out.println("\n\n*****************************************\n\n");
648      
649      
650      // signed (ecdsa-sha512) + encrypted 
651      
652      // Now create implicitly signed and encrypted message with attachment
653      hashAlgorithm = AlgorithmID.sha512;
654      signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA512;
655      msg = createSignedAndEncryptedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm);
656      System.out.println("creating implicitly signed " + signatureAlgorithm.getName() + " and encrypted message ...");
657      baos.reset();
658      msg.saveChanges();  
659      msg.writeTo(baos);
660   
661      bais = new ByteArrayInputStream(baos.toByteArray());
662      msg = new MimeMessage(session, bais);
663      if (PRINT_MESSAGES) {
664        printMessage(msg);
665      }
666      DumpMessage.dumpMsg(msg);
667      
668      System.out.println("\n\n*****************************************\n\n");
669
670      // Now create a explicitly signed and encrypted message with attachment
671      msg = createSignedAndEncryptedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm);
672      System.out.println("creating explicitly signed " + signatureAlgorithm.getName() + " and encrypted message ...");
673      baos.reset();
674      msg.saveChanges();  
675      msg.writeTo(baos);
676  
677      bais = new ByteArrayInputStream(baos.toByteArray());
678      msg = new MimeMessage(session, bais);
679      if (PRINT_MESSAGES) {
680        printMessage(msg);
681      }
682      DumpMessage.dumpMsg(msg);
683      System.out.println("\n\n*****************************************\n\n");
684      
685      
686      // signed (ecdsa-ripemd160) + encrypted 
687      
688      // Now create implicitly signed and encrypted message with attachment
689      hashAlgorithm = AlgorithmID.ripeMd160;
690      signatureAlgorithm = CMSAlgorithmID.ecdsa_plain_With_RIPEMD160;
691      msg = createSignedAndEncryptedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm);
692      System.out.println("creating implicitly signed " + signatureAlgorithm.getName() + " and encrypted message ...");
693      baos.reset();
694      msg.saveChanges();  
695      msg.writeTo(baos);
696   
697      bais = new ByteArrayInputStream(baos.toByteArray());
698      msg = new MimeMessage(session, bais);
699      if (PRINT_MESSAGES) {
700        printMessage(msg);
701      }
702      DumpMessage.dumpMsg(msg);
703      
704      System.out.println("\n\n*****************************************\n\n");
705
706      // Now create a explicitly signed and encrypted message with attachment
707      msg = createSignedAndEncryptedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm);
708      System.out.println("creating explicitly signed " + signatureAlgorithm.getName() + " and encrypted message ...");
709      baos.reset();
710      msg.saveChanges();  
711      msg.writeTo(baos);
712      
713      bais = new ByteArrayInputStream(baos.toByteArray());
714      msg = new MimeMessage(session, bais);
715      if (PRINT_MESSAGES) {
716        printMessage(msg);
717      }
718      DumpMessage.dumpMsg(msg);
719      System.out.println("\n\n*****************************************\n\n");
720   
721
722
723
724        } catch (Exception ex) {
725          ex.printStackTrace();
726          throw new RuntimeException(ex.toString());
727        }
728
729        System.out.println("OK!");
730        
731  }
732
733  /**
734   * Creates a MIME message container with the given subject for the given session.
735   * 
736   * @param session the mail session
737   * @param subject the subject of the message
738   *
739   * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content)
740   *
741   * @throws MessagingException if the message cannot be created
742   */
743  public Message createMessage(Session session, String subject) throws MessagingException {
744    MimeMessage msg = new MimeMessage(session);
745    msg.setFrom(new InternetAddress(from));
746        msg.setRecipients(Message.RecipientType.TO,     InternetAddress.parse(to, false));
747        msg.setSentDate(new Date());
748    msg.setSubject(subject);
749    return msg;
750  }
751  
752  /**
753   * Creates a signed and encrypted message.
754   *
755   * @param session the mail session
756   * @param dataHandler the content of the message to be signed and encrypted
757   * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
758   *                 (multipart/signed) signing
759   * @param hashAlgorithm the hash algorithm to be used
760   * @param signatureAlgorithm the signature algorithm to be used                
761   * 
762   * @return the signed and encrypted message
763   *
764   * @throws MessagingException if an error occurs when creating the message
765   */
766  public Message createSignedAndEncryptedMessage(Session session, 
767                                                 DataHandler dataHandler,
768                                                 boolean implicit,
769                                                 AlgorithmID hashAlgorithm,
770                                                 AlgorithmID signatureAlgorithm)
771    throws MessagingException {
772
773    String subject = null;
774    String text = null;
775    if (implicit) {
776      subject = "IAIK-S/MIME: Implicitly Signed and Encrypted";
777      text = "This message is implicitly signed and encrypted!\n\n\n";
778    } else {
779      subject = "IAIK-S/MIME: Explicitly Signed and Encrypted";
780      text = "This message is explicitly signed and encrypted!\n\n\n";
781    }
782    Message msg = createMessage(session, subject);
783
784    SignedContent sc = new SignedContent(implicit);
785    if (dataHandler != null) {
786      sc.setDataHandler(dataHandler);
787    } else {
788      sc.setText(text);
789    }
790    sc.setCertificates(signerCertificates);
791    AlgorithmID ecdsaSig = (AlgorithmID)signatureAlgorithm.clone();
792    // CMS-ECC requires that the parameters field is encoded as ASN.1 NULL object (see RFC 3278)
793    ecdsaSig.encodeAbsentParametersAsNull(true);
794    try {
795      sc.addSigner(signerPrivateKey, 
796                   signerCertificate, 
797                   (AlgorithmID)hashAlgorithm.clone(),
798                   ecdsaSig,
799                   encryptionCertOfSigner,
800                   true);
801    } catch (NoSuchAlgorithmException ex) {
802      throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
803    }
804
805    EncryptedContent ec = new EncryptedContent(sc);
806    // encrypt for the recipient
807    AlgorithmID keyEA = (CMSAlgorithmID)CMSAlgorithmID.dhSinglePass_stdDH_sha256kdf_scheme.clone();
808    // the key wrap algorithm to use:
809    AlgorithmID keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone();
810    // the length of the key encryption key to be generated:
811    int kekLength = 256;
812    try {  
813      ec.addRecipient(recipientCertificate, (AlgorithmID)keyEA.clone(), (AlgorithmID)keyWrapAlg.clone(), kekLength);
814    } catch (SMimeException ex) {
815      throw new MessagingException("Error adding ECDH recipient: " + ex.getMessage());   
816    } 
817    try {
818      // I want to be able to decrypt the message, too
819      ec.addRecipient(encryptionCertOfSigner, (AlgorithmID)keyEA.clone(), (AlgorithmID)keyWrapAlg.clone(), kekLength);
820    } catch (SMimeException ex) {
821      throw new MessagingException("Error adding ECDH recipient: " + ex.getMessage());   
822    }
823    // set the encryption algorithm
824    try {
825      ec.setEncryptionAlgorithm((AlgorithmID)AlgorithmID.aes256_CBC.clone(), 256);
826    } catch (NoSuchAlgorithmException ex) {
827      throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
828    }   
829    msg.setContent(ec, ec.getContentType());
830    // let the EncryptedContent update some message headers
831    ec.setHeaders(msg);
832
833    return msg;
834  }
835  
836  /**
837   * Creates a signed message.
838   *
839   * @param session the mail session
840   * @param dataHandler the content of the message to be signed
841   * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
842   *                 (multipart/signed) signing
843   * @param hashAlgorithm the hash algorithm to be used                
844   * @param signatureAlgorithm the signature algorithm to be used
845   * 
846   * @return the signed message
847   *
848   * @throws MessagingException if an error occurs when creating the message
849   */
850  public Message createSignedMessage(Session session, 
851                                     DataHandler dataHandler,
852                                     boolean implicit,
853                                     AlgorithmID hashAlgorithm,
854                                     AlgorithmID signatureAlgorithm)
855      throws MessagingException {
856
857    String subject = null;
858    StringBuffer buf = new StringBuffer();
859    
860    if (implicit) {
861      subject = "IAIK-S/MIME: Implicitly Signed (" + signatureAlgorithm.getName() +")";
862      buf.append("This message is implicitly signed with ! " + signatureAlgorithm.getName() + "\n");
863      buf.append("You need an S/MIME aware mail client to view this message.\n");
864      buf.append("\n\n");
865    } else {
866      subject = "IAIK-S/MIME: Explicitly Signed (" + signatureAlgorithm.getName() +")";
867      buf.append("This message is explicitly signed!\n");
868      buf.append("Every mail client can view this message.\n");
869      buf.append("Non S/MIME mail clients will show the signature as attachment.\n");
870      buf.append("\n\n");
871    }
872    
873    Message msg = createMessage(session, subject);
874    
875    SignedContent sc = new SignedContent(implicit);
876    if (dataHandler != null) {
877      sc.setDataHandler(dataHandler);
878    } else {
879      sc.setText(buf.toString());
880    }
881    sc.setCertificates(signerCertificates);
882
883    AlgorithmID ecdsaSig = (AlgorithmID)signatureAlgorithm.clone();
884    // CMS-ECDSA requires to encode the parameter field as NULL (see RFC 3278)
885    ecdsaSig.encodeAbsentParametersAsNull(true);
886    try {
887      sc.addSigner(signerPrivateKey, 
888                   signerCertificate, 
889                   (AlgorithmID)hashAlgorithm.clone(),
890                   ecdsaSig,
891                   encryptionCertOfSigner,
892                   true);
893    } catch (NoSuchAlgorithmException ex) {
894      throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
895    }
896
897    msg.setContent(sc, sc.getContentType());
898    // let the SignedContent update some message headers
899    sc.setHeaders(msg);
900    return msg;
901  }
902  
903  /**
904   * Creates an encrypted message.
905   *
906   * @param session the mail session
907   * @param contentEA the content encryption algorithm to be used
908   * @param keyLength the length of the secret content encryption key to be created and used
909   * 
910   * @return the encrypted message
911   *
912   * @throws MessagingException if an error occurs when creating the message
913   */
914  public Message createEncryptedMessage(Session session, AlgorithmID contentEA, int keyLength,
915    AlgorithmID keyEA, AlgorithmID keyWrapAlgorithm, int kekLength)
916      throws MessagingException {
917    
918    AlgorithmID algorithm = (AlgorithmID)contentEA.clone();
919    AlgorithmID keyAgreeAlg = (AlgorithmID)keyEA.clone();
920    AlgorithmID keyWrapAlg = (AlgorithmID)keyWrapAlgorithm.clone();
921    
922    StringBuffer subject = new StringBuffer();
923    subject.append("IAIK-S/MIME: Encrypted ["+algorithm.getName());
924    if (keyLength > 0) {
925      subject.append("/"+keyLength);
926    }  
927    subject.append("]");
928    Message msg = createMessage(session, subject.toString());
929
930    EncryptedContent ec = new EncryptedContent();
931
932    StringBuffer buf = new StringBuffer();
933    buf.append("This is the encrypted content!\n");
934    buf.append("Content encryption algorithm: "+algorithm.getName());
935    buf.append("\n\n");
936
937    ec.setText(buf.toString());
938    
939    try {  
940      ec.addRecipient(recipientCertificate, (AlgorithmID)keyAgreeAlg.clone(), (AlgorithmID)keyWrapAlg.clone(), kekLength);
941    } catch (SMimeException ex) {
942      throw new MessagingException("Error adding ECDH recipient: " + ex.getMessage());   
943    }    
944    // I want to be able to decrypt the message, too
945    try {
946      ec.addRecipient(encryptionCertOfSigner, (AlgorithmID)keyAgreeAlg.clone(), (AlgorithmID)keyWrapAlg.clone(), kekLength);
947    } catch (SMimeException ex) {
948      throw new MessagingException("Error adding ECDH recipient: " + ex.getMessage());   
949    }
950    try {
951      ec.setEncryptionAlgorithm(algorithm, keyLength);
952    } catch (NoSuchAlgorithmException ex) {
953      throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
954    }    
955
956    msg.setContent(ec, ec.getContentType());
957    // let the EncryptedContent update some message headers
958    ec.setHeaders(msg);
959
960    return msg;
961  }
962  
963  /** 
964   * Prints a dump of the given message to System.out.
965   *
966   * @param msg the message to be dumped to System.out
967   *
968   * @throws IOException if an I/O error occurs
969   */
970  private static void printMessage(Message msg) throws IOException {
971    System.out.println("------------------------------------------------------------------");
972    System.out.println("Message dump: \n");
973    try {
974      msg.writeTo(System.out);
975    } catch (MessagingException ex) {
976      throw new IOException(ex.getMessage());   
977    }    
978    System.out.println("\n------------------------------------------------------------------");
979  }  
980
981
982  /**
983   * The main method.
984   */
985  public static void main(String[] argv) throws Exception {
986     
987    DemoSMimeUtil.initDemos();
988    //  add ECC provider    
989    ECCDemoUtil.installIaikEccProvider();
990    
991        (new SMimeEccDemo()).start();
992    System.out.println("\nReady!");
993    DemoUtil.waitKey();
994  }
995}