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 "Suite B in Secure/Multipurpose Internet Mail Extensions (S/MIME)".
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 < 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 }