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