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 < 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 }