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