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/basic/SMimeDemo.java 53 12.02.25 17:58 Dbratko $
059 // $Revision: 53 $
060 //
061
062 package demo.smime.basic;
063
064 import java.io.ByteArrayInputStream;
065 import java.io.ByteArrayOutputStream;
066 import java.io.IOException;
067 import java.security.NoSuchAlgorithmException;
068 import java.security.PrivateKey;
069 import java.security.interfaces.RSAPrivateKey;
070 import java.util.Date;
071
072 import javax.activation.DataHandler;
073 import javax.activation.FileDataSource;
074 import javax.mail.Message;
075 import javax.mail.MessagingException;
076 import javax.mail.Multipart;
077 import javax.mail.Session;
078 import javax.mail.internet.InternetAddress;
079 import javax.mail.internet.MimeBodyPart;
080 import javax.mail.internet.MimeMessage;
081 import javax.mail.internet.MimeMultipart;
082
083 import demo.DemoSMimeUtil;
084 import demo.DemoUtil;
085 import demo.keystore.CMSKeyStore;
086 import demo.smime.DumpMessage;
087 import iaik.asn1.ObjectID;
088 import iaik.asn1.structures.AlgorithmID;
089 import iaik.asn1.structures.Name;
090 import iaik.cms.CMSAlgorithmID;
091 import iaik.pkcs.PKCSException;
092 import iaik.pkcs.pkcs10.CertificateRequest;
093 import iaik.smime.AuthEncryptedContent;
094 import iaik.smime.CompressedContent;
095 import iaik.smime.EncryptedContent;
096 import iaik.smime.PKCS10Content;
097 import iaik.smime.SMimeBodyPart;
098 import iaik.smime.SMimeMultipart;
099 import iaik.smime.SMimeParameters;
100 import iaik.smime.SignedContent;
101 import iaik.x509.X509Certificate;
102
103 /**
104 * This class demonstrates the usage of the IAIK S/MIME implementation. It shows how to create
105 * signed and/or encrypted S/MIME messages and how to parse them and verify the signatures
106 * and decrypt the content, respectively.
107 * <p>
108 * To run this demo the following packages are required:
109 * <ul>
110 * <li>
111 * <code>iaik_cms.jar</code>
112 * </li>
113 * <li>
114 * <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>).
115 * </li>
116 * <li>
117 * <code>mail.jar</code> (<a href="http://www.oracle.com/technetwork/java/javamail/index.html" target="_blank">JavaMail API</a>).
118 * </li>
119 * <li>
120 * <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).
121 * </li>
122 * </ul>
123 */
124 public class SMimeDemo {
125
126 // whether to print dump all generates test messages to System.out
127 final static boolean PRINT_MESSAGES = false;
128
129 String firstName_ = "John"; // name of sender
130 String lastName_ = "SMime";
131 String from_ = "smimetest@iaik.tugraz.at"; // email sender
132 String to_ = "smimetest@iaik.tugraz.at"; // email recipient
133 String host_ = "mailhost"; // name of the mailhost
134
135 X509Certificate[] signerCertificates_; // list of certificates to include in the S/MIME message
136 X509Certificate recipientCertificate_; // certificate of the recipient
137 X509Certificate signerCertificate_; // certificate of the signer/sender
138 X509Certificate encryptionCertOfSigner_; // signer uses different certificate for encryption
139 PrivateKey signerPrivateKey_; // private key of the signer/sender
140
141 /**
142 * Default constructor. Reads certificates and keys from the demo keystore.
143 */
144 public SMimeDemo() {
145
146 System.out.println();
147 System.out.println("******************************************************************************************");
148 System.out.println("* SMimeDemo demo *");
149 System.out.println("* (shows how to create and parse (verify, decrypt) signed and encrypted S/MIME messages) *");
150 System.out.println("******************************************************************************************");
151 System.out.println();
152
153 // get the certificates from the KeyStore
154 signerCertificates_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
155 signerPrivateKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
156 signerCertificate_ = signerCertificates_[0];
157
158 // recipient = signer for this test
159 recipientCertificate_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0];
160 encryptionCertOfSigner_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0];
161 }
162
163 /**
164 * Starts the demo.
165 *
166 * @throws IOException if an I/O related error occurs
167 */
168 public void start() throws IOException {
169
170 // get the default Session
171 Session session = DemoSMimeUtil.getSession();
172
173 try {
174 // Create a demo Multipart
175 MimeBodyPart mbp1 = new SMimeBodyPart();
176 mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n");
177 // attachment
178 MimeBodyPart attachment = new SMimeBodyPart();
179 attachment.setDataHandler(new DataHandler(new FileDataSource("test.html")));
180 attachment.setFileName("test.html");
181
182 Multipart mp = new SMimeMultipart();
183 mp.addBodyPart(mbp1);
184 mp.addBodyPart(attachment);
185 DataHandler multipart = new DataHandler(mp, mp.getContentType());
186
187 Message msg; // the message to send
188 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
189 ByteArrayInputStream bais; // we read from a stream
190
191 // 1. This is a plain message
192 msg = createPlainMessage(session, multipart);
193 System.out.println("creating plain message...");
194 msg.saveChanges();
195 msg.writeTo(baos);
196 bais = new ByteArrayInputStream(baos.toByteArray());
197 msg = new MimeMessage(session, bais);
198 if (PRINT_MESSAGES) {
199 printMessage(msg);
200 }
201 DumpMessage.dumpMsg(msg);
202
203 System.out.println("\n\n*****************************************\n\n");
204
205 // 2. This is an explicitly signed message
206 msg = createSignedMessage(session, multipart, false);
207 System.out.println("creating explicitly signed message...");
208 baos.reset();
209 msg.saveChanges();
210 msg.writeTo(baos);
211 bais = new ByteArrayInputStream(baos.toByteArray());
212 msg = new MimeMessage(session, bais);
213 if (PRINT_MESSAGES) {
214 printMessage(msg);
215 }
216 DumpMessage.dumpMsg(msg);
217
218 System.out.println("\n\n*****************************************\n\n");
219
220
221 // 3. This is an implicitly signed message
222 msg = createSignedMessage(session, multipart, true);
223 System.out.println("creating implicitly signed message...");
224 baos.reset();
225 msg.saveChanges();
226 msg.writeTo(baos);
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 // 4. Now create encrypted messages with different content encryption algorithms
237
238 // RC2 is deprecated; only demonstrated here
239 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 40);
240 System.out.println("creating encrypted message [RC2/40]...");
241 baos.reset();
242 msg.saveChanges();
243 msg.writeTo(baos);
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 // RC2 is deprecated; only demonstrated here
254 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 64);
255 System.out.println("creating encrypted message [RC2/64]...");
256 baos.reset();
257 msg.saveChanges();
258 msg.writeTo(baos);
259 bais = new ByteArrayInputStream(baos.toByteArray());
260 msg = new MimeMessage(session, bais);
261 if (PRINT_MESSAGES) {
262 printMessage(msg);
263 }
264 DumpMessage.dumpMsg(msg);
265
266 System.out.println("\n\n*****************************************\n\n");
267
268 // RC2 is deprecated; only demonstrated here
269 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 128);
270 System.out.println("creating encrypted message [RC2/128]...");
271 baos.reset();
272 msg.saveChanges();
273 msg.writeTo(baos);
274 bais = new ByteArrayInputStream(baos.toByteArray());
275 msg = new MimeMessage(session, bais);
276 if (PRINT_MESSAGES) {
277 printMessage(msg);
278 }
279 DumpMessage.dumpMsg(msg);
280
281 System.out.println("\n\n*****************************************\n\n");
282
283 // DES EDE is deprecated; only demonstrated here
284 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.des_EDE3_CBC.clone(), 192);
285 System.out.println("creating encrypted message [TripleDES]...");
286 baos.reset();
287 msg.saveChanges();
288 msg.writeTo(baos);
289 bais = new ByteArrayInputStream(baos.toByteArray());
290 msg = new MimeMessage(session, bais);
291 if (PRINT_MESSAGES) {
292 printMessage(msg);
293 }
294 DumpMessage.dumpMsg(msg);
295
296 System.out.println("\n\n*****************************************\n\n");
297
298 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CBC.clone(), 128);
299 System.out.println("creating encrypted message [AES/128]...");
300 baos.reset();
301 msg.saveChanges();
302 msg.writeTo(baos);
303 bais = new ByteArrayInputStream(baos.toByteArray());
304 msg = new MimeMessage(session, bais);
305 if (PRINT_MESSAGES) {
306 printMessage(msg);
307 }
308 DumpMessage.dumpMsg(msg);
309
310 System.out.println("\n\n*****************************************\n\n");
311
312 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CBC.clone(), 192);
313 System.out.println("creating encrypted message [AES/192]...");
314 baos.reset();
315 msg.saveChanges();
316 msg.writeTo(baos);
317 bais = new ByteArrayInputStream(baos.toByteArray());
318 msg = new MimeMessage(session, bais);
319 if (PRINT_MESSAGES) {
320 printMessage(msg);
321 }
322 DumpMessage.dumpMsg(msg);
323
324 System.out.println("\n\n*****************************************\n\n");
325
326 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), 256);
327 System.out.println("creating encrypted message [AES/256]...");
328 baos.reset();
329 msg.saveChanges();
330 msg.writeTo(baos);
331 bais = new ByteArrayInputStream(baos.toByteArray());
332 msg = new MimeMessage(session, bais);
333 if (PRINT_MESSAGES) {
334 printMessage(msg);
335 }
336 DumpMessage.dumpMsg(msg);
337
338 System.out.println("\n\n*****************************************\n\n");
339
340
341 // 5. Now create a implicitly signed and encrypted message with attachment
342 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), multipart, true);
343 System.out.println("creating implicitly signed and encrypted message [AES/256]...");
344 baos.reset();
345 msg.saveChanges();
346 msg.writeTo(baos);
347 bais = new ByteArrayInputStream(baos.toByteArray());
348 msg = new MimeMessage(session, bais);
349 if (PRINT_MESSAGES) {
350 printMessage(msg);
351 }
352 DumpMessage.dumpMsg(msg);
353
354 System.out.println("\n\n*****************************************\n\n");
355
356 // 6. Now create a explicitly signed and encrypted message with attachment
357 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), multipart, false);
358 System.out.println("creating explicitly signed and encrypted message [AES/256]...");
359 baos.reset();
360 msg.saveChanges();
361 msg.writeTo(baos);
362 bais = new ByteArrayInputStream(baos.toByteArray());
363 msg = new MimeMessage(session, bais);
364 if (PRINT_MESSAGES) {
365 printMessage(msg);
366 }
367 DumpMessage.dumpMsg(msg);
368
369 System.out.println("\n\n*****************************************\n\n");
370
371 // 7. Authenticated encrypted message with several algorithms
372 if (DemoUtil.getIaikProviderVersion() >= 5.62) {
373 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), 128);
374 System.out.println("creating encrypted message [AESGCM/128]...");
375 baos.reset();
376 msg.saveChanges();
377 msg.writeTo(baos);
378 bais = new ByteArrayInputStream(baos.toByteArray());
379 msg = new MimeMessage(session, bais);
380 if (PRINT_MESSAGES) {
381 printMessage(msg);
382 }
383 DumpMessage.dumpMsg(msg);
384
385 System.out.println("\n\n*****************************************\n\n");
386
387 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_GCM.clone(), 192);
388 System.out.println("creating encrypted message [AESGCM/192]...");
389 baos.reset();
390 msg.saveChanges();
391 msg.writeTo(baos);
392 bais = new ByteArrayInputStream(baos.toByteArray());
393 msg = new MimeMessage(session, bais);
394 if (PRINT_MESSAGES) {
395 printMessage(msg);
396 }
397 DumpMessage.dumpMsg(msg);
398
399 System.out.println("\n\n*****************************************\n\n");
400
401 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_GCM.clone(), 256);
402 System.out.println("creating encrypted message [AESGCM/256]...");
403 baos.reset();
404 msg.saveChanges();
405 msg.writeTo(baos);
406 bais = new ByteArrayInputStream(baos.toByteArray());
407 msg = new MimeMessage(session, bais);
408 if (PRINT_MESSAGES) {
409 printMessage(msg);
410 }
411 DumpMessage.dumpMsg(msg);
412
413 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), 256);
414 System.out.println("creating encrypted message [ChaCha20Poly1305]...");
415 baos.reset();
416 msg.saveChanges();
417 msg.writeTo(baos);
418 bais = new ByteArrayInputStream(baos.toByteArray());
419 msg = new MimeMessage(session, bais);
420 if (PRINT_MESSAGES) {
421 printMessage(msg);
422 }
423 DumpMessage.dumpMsg(msg);
424
425 System.out.println("\n\n*****************************************\n\n");
426
427 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), 128);
428 System.out.println("creating encrypted message [AESCCM/128]...");
429 baos.reset();
430 msg.saveChanges();
431 msg.writeTo(baos);
432 bais = new ByteArrayInputStream(baos.toByteArray());
433 msg = new MimeMessage(session, bais);
434 if (PRINT_MESSAGES) {
435 printMessage(msg);
436 }
437 DumpMessage.dumpMsg(msg);
438
439 System.out.println("\n\n*****************************************\n\n");
440
441 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CCM.clone(), 192);
442 System.out.println("creating encrypted message [AESCCM/192]...");
443 baos.reset();
444 msg.saveChanges();
445 msg.writeTo(baos);
446 bais = new ByteArrayInputStream(baos.toByteArray());
447 msg = new MimeMessage(session, bais);
448 if (PRINT_MESSAGES) {
449 printMessage(msg);
450 }
451 DumpMessage.dumpMsg(msg);
452
453 System.out.println("\n\n*****************************************\n\n");
454
455 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CCM.clone(), 256);
456 System.out.println("creating encrypted message [AESCCM/256]...");
457 baos.reset();
458 msg.saveChanges();
459 msg.writeTo(baos);
460 bais = new ByteArrayInputStream(baos.toByteArray());
461 msg = new MimeMessage(session, bais);
462 if (PRINT_MESSAGES) {
463 printMessage(msg);
464 }
465 DumpMessage.dumpMsg(msg);
466
467 System.out.println("\n\n*****************************************\n\n");
468
469 // Now create a implicitly signed and authenticated encrypted message with attachment
470 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), multipart, true);
471 System.out.println("creating implicitly signed and authenticated encrypted message [AES-GCM/128]...");
472 baos.reset();
473 msg.saveChanges();
474 msg.writeTo(baos);
475 bais = new ByteArrayInputStream(baos.toByteArray());
476 msg = new MimeMessage(session, bais);
477 if (PRINT_MESSAGES) {
478 printMessage(msg);
479 }
480 DumpMessage.dumpMsg(msg);
481
482 System.out.println("\n\n*****************************************\n\n");
483
484 // Now create a explicitly signed and authenticated encrypted message with attachment
485 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), multipart, false);
486 System.out.println("creating explicitly signed and authenticated encrypted message [AES-GCM/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
497 System.out.println("\n\n*****************************************\n\n");
498
499 // Now create a implicitly signed and authenticated encrypted message with attachment
500 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), multipart, true);
501 System.out.println("creating implicitly signed and authenticated encrypted message [ChaChaPoly1305]...");
502 baos.reset();
503 msg.saveChanges();
504 msg.writeTo(baos);
505 bais = new ByteArrayInputStream(baos.toByteArray());
506 msg = new MimeMessage(session, bais);
507 if (PRINT_MESSAGES) {
508 printMessage(msg);
509 }
510 DumpMessage.dumpMsg(msg);
511
512 System.out.println("\n\n*****************************************\n\n");
513
514 // Now create a explicitly signed and authenticated encrypted message with attachment
515 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), multipart, false);
516 System.out.println("creating explicitly signed and authenticated encrypted message [ChaChaPoly1305]...");
517 baos.reset();
518 msg.saveChanges();
519 msg.writeTo(baos);
520 bais = new ByteArrayInputStream(baos.toByteArray());
521 msg = new MimeMessage(session, bais);
522 if (PRINT_MESSAGES) {
523 printMessage(msg);
524 }
525 DumpMessage.dumpMsg(msg);
526
527 System.out.println("\n\n*****************************************\n\n");
528
529 // Now create a implicitly signed and authenticated encrypted message with attachment
530 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), multipart, true);
531 System.out.println("creating implicitly signed and authenticated encrypted message [AES-CCM/128]...");
532 baos.reset();
533 msg.saveChanges();
534 msg.writeTo(baos);
535 bais = new ByteArrayInputStream(baos.toByteArray());
536 msg = new MimeMessage(session, bais);
537 if (PRINT_MESSAGES) {
538 printMessage(msg);
539 }
540 DumpMessage.dumpMsg(msg);
541
542 System.out.println("\n\n*****************************************\n\n");
543
544 // Now create a explicitly signed and authenticated encrypted message with attachment
545 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), multipart, false);
546 System.out.println("creating explicitly signed and authenticated encrypted message [AES-CCM/128]...");
547 baos.reset();
548 msg.saveChanges();
549 msg.writeTo(baos);
550 bais = new ByteArrayInputStream(baos.toByteArray());
551 msg = new MimeMessage(session, bais);
552 if (PRINT_MESSAGES) {
553 printMessage(msg);
554 }
555 DumpMessage.dumpMsg(msg);
556
557 System.out.println("\n\n*****************************************\n\n");
558 }
559
560 // 8. certs only message
561 msg = createCertsOnlyMessage(session);
562 System.out.println("creating certs-only message");
563 baos.reset();
564 msg.saveChanges();
565 msg.writeTo(baos);
566 bais = new ByteArrayInputStream(baos.toByteArray());
567 msg = new MimeMessage(session, bais);
568 if (PRINT_MESSAGES) {
569 printMessage(msg);
570 }
571 DumpMessage.dumpMsg(msg);
572
573 System.out.println("\n\n*****************************************\n\n");
574
575 // 9. certs only message where the cert list is put into the second part
576 msg = createCertsOnlyMultiPartMessage(session);
577 System.out.println("creating message with certs-only part");
578 baos.reset();
579 msg.saveChanges();
580 msg.writeTo(baos);
581 bais = new ByteArrayInputStream(baos.toByteArray());
582 msg = new MimeMessage(session, bais);
583 if (PRINT_MESSAGES) {
584 printMessage(msg);
585 }
586 DumpMessage.dumpMsg(msg);
587
588 System.out.println("\n\n*****************************************\n\n");
589
590 // 10. application/pkcs10 cert request message
591 msg = createPKCS10Message(session);
592 System.out.println("creating application/pkcs10 message...");
593 baos.reset();
594 msg.saveChanges();
595 msg.writeTo(baos);
596 bais = new ByteArrayInputStream(baos.toByteArray());
597 msg = new MimeMessage(session, bais);
598 if (PRINT_MESSAGES) {
599 printMessage(msg);
600 }
601 DumpMessage.dumpMsg(msg);
602
603 System.out.println("\n\n*****************************************\n\n");
604
605 // 11. application/pkcs10 message where the request is in the second part
606 msg = createPKCS10MultiPartMessage(session);
607 System.out.println("creating message with pkcs10 part...");
608 baos.reset();
609 msg.saveChanges();
610 msg.writeTo(baos);
611 bais = new ByteArrayInputStream(baos.toByteArray());
612 msg = new MimeMessage(session, bais);
613 if (PRINT_MESSAGES) {
614 printMessage(msg);
615 }
616 DumpMessage.dumpMsg(msg);
617
618 System.out.println("\n\n*****************************************\n\n");
619
620 // 12. compressed message
621 msg = createCompressedMessage(session, multipart, (AlgorithmID)CMSAlgorithmID.zlib_compress.clone());
622 System.out.println("creating message with compressed data...");
623 baos.reset();
624 msg.saveChanges();
625 msg.writeTo(baos);
626 bais = new ByteArrayInputStream(baos.toByteArray());
627 msg = new MimeMessage(session, bais);
628 if (PRINT_MESSAGES) {
629 printMessage(msg);
630 }
631 DumpMessage.dumpMsg(msg);
632
633 } catch (Exception ex) {
634 ex.printStackTrace();
635 throw new RuntimeException(ex.toString());
636 }
637 }
638
639 /**
640 * Creates a MIME message container with the given subject for the given session.
641 *
642 * @param session the mail sesion
643 * @param subject the subject of the message
644 *
645 * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content)
646 *
647 * @throws MessagingException if the message cannot be created
648 */
649 public Message createMessage(Session session, String subject) throws MessagingException {
650 MimeMessage msg = new MimeMessage(session);
651 msg.setFrom(new InternetAddress(from_));
652 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to_, false));
653 msg.setSentDate(new Date());
654 msg.setSubject(subject);
655 return msg;
656 }
657
658 /**
659 * Creates a simple plain (neither signed nor encrypted) message.
660 *
661 * @param session the mail session
662 * @param dataHandler the content of the message
663 *
664 * @return the plain message
665 *
666 * @throws MessagingException if an error occurs when creating the message
667 */
668 public Message createPlainMessage(Session session, DataHandler dataHandler) throws MessagingException {
669
670 Message msg = createMessage(session, "IAIK-S/MIME: Plain message");
671 if (dataHandler != null) {
672 msg.setDataHandler(dataHandler);
673 } else {
674 msg.setText("This is a plain message!\nIt is wether signed nor encrypted!\n");
675 }
676 return msg;
677 }
678
679 /**
680 * Creates a signed and encrypted message.
681 *
682 * @param session the mail session
683 * @param algorithm the content encryption algorithm to be used
684 * @param dataHandler the content of the message to be signed and encrypted
685 * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
686 * (multipart/signed) signing
687 *
688 * @return the signed and encrypted message
689 *
690 * @throws MessagingException if an error occurs when creating the message
691 */
692 public Message createSignedAndEncryptedMessage(Session session, AlgorithmID algorithm, DataHandler dataHandler, boolean implicit)
693 throws MessagingException {
694
695 String subject = null;
696 String text = null;
697 if (implicit) {
698 subject = "IAIK-S/MIME: Implicitly Signed and Encrypted";
699 text = "This message is implicitly signed and encrypted!\n\n\n";
700 } else {
701 subject = "IAIK-S/MIME: Explicitly Signed and Encrypted";
702 text = "This message is explicitly signed and encrypted!\n\n\n";
703 }
704 Message msg = createMessage(session, subject);
705
706 SignedContent sc = new SignedContent(implicit);
707 if (dataHandler != null) {
708 sc.setDataHandler(dataHandler);
709 } else {
710 sc.setText(text);
711 }
712 sc.setCertificates(signerCertificates_);
713 try {
714 sc.addSigner((RSAPrivateKey)signerPrivateKey_, signerCertificate_);
715 } catch (NoSuchAlgorithmException ex) {
716 throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
717 }
718
719 EncryptedContent ec = null;
720 if (algorithm.equals(AlgorithmID.aes256_CBC)) {
721 ec = new EncryptedContent(sc);
722 } else {
723 ec = new AuthEncryptedContent(sc);
724 }
725 // encrypt for the recipient
726 ec.addRecipient(recipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
727 // I want to be able to decrypt the message, too
728 ec.addRecipient(encryptionCertOfSigner_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
729 // set the encryption algorithm
730 try {
731 ec.setEncryptionAlgorithm(algorithm, -1);
732 } catch (NoSuchAlgorithmException ex) {
733 throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());
734 }
735 msg.setContent(ec, ec.getContentType());
736 // let the EncryptedContent update some message headers
737 ec.setHeaders(msg);
738
739 return msg;
740 }
741
742
743
744 /**
745 * Creates a signed message.
746 *
747 * @param session the mail session
748 * @param dataHandler the content of the message to be signed
749 * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
750 * (multipart/signed) signing
751 *
752 * @return the signed message
753 *
754 * @throws MessagingException if an error occurs when creating the message
755 */
756 public Message createSignedMessage(Session session, DataHandler dataHandler, boolean implicit)
757 throws MessagingException {
758
759 String subject = null;
760 StringBuffer buf = new StringBuffer();
761
762 if (implicit) {
763 subject = "IAIK-S/MIME: Implicitly Signed";
764 buf.append("This message is implicitly signed!\n");
765 buf.append("You need an S/MIME aware mail client to view this message.\n");
766 buf.append("\n\n");
767 } else {
768 subject = "IAIK-S/MIME: Explicitly Signed";
769 buf.append("This message is explicitly signed!\n");
770 buf.append("Every mail client can view this message.\n");
771 buf.append("Non S/MIME mail clients will show the signature as attachment.\n");
772 buf.append("\n\n");
773 }
774
775 Message msg = createMessage(session, subject);
776
777 SignedContent sc = new SignedContent(implicit);
778
779 if (dataHandler != null) {
780 sc.setDataHandler(dataHandler);
781 } else {
782 sc.setText(buf.toString());
783 }
784 sc.setCertificates(signerCertificates_);
785
786 try {
787 sc.addSigner((RSAPrivateKey)signerPrivateKey_, signerCertificate_);
788 } catch (NoSuchAlgorithmException ex) {
789 throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
790 }
791
792 msg.setContent(sc, sc.getContentType());
793 // let the SignedContent update some message headers
794 sc.setHeaders(msg);
795 return msg;
796 }
797
798 /**
799 * Creates an encrypted message.
800 *
801 * @param session the mail session
802 * @param algorithm the content encryption algorithm to be used
803 * @param keyLength the length of the secret content encryption key to be created and used
804 *
805 * @return the encrypted message
806 *
807 * @throws MessagingException if an error occurs when creating the message
808 */
809 public Message createEncryptedMessage(Session session, AlgorithmID algorithm, int keyLength)
810 throws MessagingException {
811
812 StringBuffer subject = new StringBuffer();
813 subject.append("IAIK-S/MIME: Encrypted ["+algorithm.getName());
814 if (keyLength > 0) {
815 subject.append("/"+keyLength);
816 }
817 subject.append("]");
818 Message msg = createMessage(session, subject.toString());
819
820 EncryptedContent ec = new EncryptedContent();
821
822 StringBuffer buf = new StringBuffer();
823 buf.append("This is the encrypted content!\n");
824 buf.append("Content encryption algorithm: "+algorithm.getName());
825 buf.append("\n\n");
826
827 ec.setText(buf.toString());
828 // encrypt for the recipient
829 ec.addRecipient(recipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
830 // I want to be able to decrypt the message, too
831 ec.addRecipient(encryptionCertOfSigner_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
832 try {
833 ec.setEncryptionAlgorithm(algorithm, keyLength);
834 } catch (NoSuchAlgorithmException ex) {
835 throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());
836 }
837
838 msg.setContent(ec, ec.getContentType());
839 // let the EncryptedContent update some message headers
840 ec.setHeaders(msg);
841
842 return msg;
843 }
844
845 /**
846 * Creates an authenticated encrypted message.
847 *
848 * @param session the mail session
849 * @param algorithm the content encryption algorithm to be used
850 * @param keyLength the length of the secret content encryption key to be created and used
851 *
852 * @return the encrypted message
853 *
854 * @throws MessagingException if an error occurs when creating the message
855 */
856 public Message createAuthEncryptedMessage(Session session, AlgorithmID algorithm, int keyLength)
857 throws MessagingException {
858
859 StringBuffer subject = new StringBuffer();
860 subject.append("IAIK-S/MIME: AuthEncrypted ["+algorithm.getName());
861 if (keyLength > 0) {
862 subject.append("/"+keyLength);
863 }
864 subject.append("]");
865 Message msg = createMessage(session, subject.toString());
866
867 AuthEncryptedContent ec = new AuthEncryptedContent();
868
869 StringBuffer buf = new StringBuffer();
870 buf.append("This is the authenticated encrypted content!\n");
871 buf.append("Content encryption algorithm: "+algorithm.getName());
872 buf.append("\n\n");
873
874 ec.setText(buf.toString());
875 // encrypt for the recipient
876 ec.addRecipient(recipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
877 // I want to be able to decrypt the message, too
878 ec.addRecipient(encryptionCertOfSigner_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
879 try {
880 ec.setEncryptionAlgorithm(algorithm, keyLength);
881 } catch (NoSuchAlgorithmException ex) {
882 throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());
883 }
884
885 msg.setContent(ec, ec.getContentType());
886 // let the EncryptedContent update some message headers
887 ec.setHeaders(msg);
888
889 return msg;
890 }
891
892 /**
893 * Creates a certs-only message.
894 *
895 * @param session the mail session
896 *
897 * @return the certs-only message
898 *
899 * @throws MessagingException if an error occurs when creating the message
900 */
901 public Message createCertsOnlyMessage(Session session)
902 throws MessagingException {
903
904 Message msg = createMessage(session, "IAIK S/MIME: Certs-only message");
905 //use new content types
906 SMimeParameters.useNewContentTypes(true);
907 SignedContent sc = new SignedContent(true, SignedContent.CERTS_ONLY);
908 sc.setCertificates(signerCertificates_);
909 msg.setContent(sc, sc.getContentType());
910 //set filename and attachment parameters
911 sc.setHeaders(msg);
912
913
914 return msg;
915 }
916
917 /**
918 * Creates a certs-only message where the certificate list is transferred as attachment.
919 *
920 * @param session the mail session
921 *
922 * @return the certs-only message
923 *
924 * @throws MessagingException if an error occurs when creating the message
925 */
926 public Message createCertsOnlyMultiPartMessage(Session session) throws MessagingException {
927
928 MimeBodyPart mbp1 = new MimeBodyPart();
929 mbp1.setText("This is a test where the certs-only message is included in the second part!\n\n");
930
931 MimeBodyPart attachment = new MimeBodyPart();
932 //use new content types
933 SMimeParameters.useNewContentTypes(true);
934 SignedContent sc = new SignedContent(true, SignedContent.CERTS_ONLY);
935 sc.setCertificates(signerCertificates_);
936 attachment.setContent(sc, sc.getContentType());
937 // let the SignedContent update some headers
938 sc.setHeaders(attachment);
939 Multipart mp = new MimeMultipart();
940 mp.addBodyPart(mbp1);
941 mp.addBodyPart(attachment);
942
943 Message msg = createMessage(session, "IAIK S/MIME: Certs-only multipart message");
944 msg.setContent(mp, mp.getContentType());
945
946 return msg;
947 }
948
949 /**
950 * Creates a compressed message.
951 *
952 * @param session the mail session
953 * @param dataHandler the datahandler supplying the content to be compressed
954 * @param algorithm the compression algorithm to be used
955 *
956 * @return the compressed message
957 *
958 * @throws MessagingException if an error occurs when creating the message
959 */
960 public Message createCompressedMessage(Session session, DataHandler dataHandler, AlgorithmID algorithm)
961 throws MessagingException {
962
963 String subject = "IAIK-S/MIME: Compressed ["+algorithm.getName()+"]";
964 Message msg = createMessage(session, subject.toString());
965
966 CompressedContent compressedContent = new CompressedContent();
967
968 if (dataHandler == null) {
969 StringBuffer buf = new StringBuffer();
970 buf.append("This is the compressed content!\n");
971 buf.append("Compression algorithm: "+algorithm.getName());
972 buf.append("\n\n");
973 compressedContent.setText(buf.toString());
974 } else {
975 compressedContent.setDataHandler(dataHandler);
976 }
977
978 try {
979 compressedContent.setCompressionAlgorithm(algorithm);
980 } catch (NoSuchAlgorithmException ex) {
981 throw new MessagingException("Compression algorithm not supported: " + ex.getMessage());
982 }
983
984 msg.setContent(compressedContent, compressedContent.getContentType());
985 // let the CompressedContent update some message headers
986 compressedContent.setHeaders(msg);
987
988 return msg;
989 }
990
991 /**
992 * Creates a PKCS#10 certificate request message.
993 *
994 * @param session the mail session
995 *
996 * @return the PKCS#10 certificate request message
997 *
998 * @throws MessagingException if an error occurs when creating the message
999 */
1000 public Message createPKCS10Message(Session session)
1001 throws MessagingException {
1002
1003 Message msg = createMessage(session, "IAIK-S/MIME: Certificate Request");
1004
1005 PKCS10Content pc = new PKCS10Content();
1006 CertificateRequest request = null;
1007 try {
1008 request = createCertificateRequest();
1009 } catch (PKCSException ex) {
1010 throw new MessagingException(ex.getMessage());
1011 }
1012 pc.setCertRequest(request);
1013 msg.setContent(pc, pc.getContentType());
1014 // let the PKCS10Content update some message headers
1015 pc.setHeaders(msg);
1016
1017 return msg;
1018 }
1019
1020 /**
1021 * Creates a PKCS#10 message where the certificate request is transferred as attachment.
1022 *
1023 * @param session the mail session
1024 *
1025 * @return the PKCS#10 certificate request message
1026 *
1027 * @throws MessagingException if an error occurs when creating the message
1028 */
1029 public Message createPKCS10MultiPartMessage(Session session) throws MessagingException {
1030
1031 MimeBodyPart mbp1 = new MimeBodyPart();
1032 mbp1.setText("This is a test where the request message is included in the second part!\n\n");
1033 // try to test an attachment
1034 // this demo attaches our homepage
1035 MimeBodyPart attachment = new MimeBodyPart();
1036 //use new content types
1037 SMimeParameters.useNewContentTypes(true);
1038 PKCS10Content pc = new PKCS10Content();
1039 CertificateRequest request = null;
1040 try {
1041 request = createCertificateRequest();
1042 } catch (PKCSException ex) {
1043 throw new MessagingException(ex.getMessage());
1044 }
1045 pc.setCertRequest(request);
1046 DataHandler pkcs10Handler = new DataHandler(pc, pc.getContentType());
1047 attachment.setDataHandler(pkcs10Handler);
1048 attachment.setDisposition("attachment");
1049 attachment.setFileName("smime.p10");
1050 Multipart mp = new MimeMultipart();
1051 mp.addBodyPart(mbp1);
1052 mp.addBodyPart(attachment);
1053
1054 Message msg = createMessage(session, "IAIK-S/MIME: Certificate Request multipart message");
1055 msg.setContent(mp, mp.getContentType());
1056 return msg;
1057 }
1058
1059 /**
1060 * Creates a PKCS#10 certificate request.
1061 *
1062 * @return the certificate request
1063 *
1064 * @throws PKCSException if the request cannot be created
1065 */
1066 private CertificateRequest createCertificateRequest() throws PKCSException {
1067 try {
1068 Name subject = new Name();
1069 subject.addRDN(ObjectID.commonName, firstName_ + " " + lastName_);
1070 subject.addRDN(ObjectID.emailAddress, from_);
1071 CertificateRequest certRequest;
1072
1073 certRequest = new CertificateRequest(signerCertificate_.getPublicKey(), subject);
1074 certRequest.sign((AlgorithmID)AlgorithmID.sha256WithRSAEncryption.clone(), signerPrivateKey_);
1075 certRequest.verify();
1076 return certRequest;
1077 } catch (Exception ex) {
1078 throw new PKCSException("Cannot create cert request: " + ex.getMessage());
1079 }
1080 }
1081
1082
1083 /**
1084 * Prints a dump of the given message to System.out.
1085 *
1086 * @param msg the message to be dumped to System.out
1087 */
1088 static void printMessage(Message msg) throws IOException {
1089 System.out.println("------------------------------------------------------------------");
1090 System.out.println("Message dump: \n");
1091 try {
1092 msg.writeTo(System.out);
1093 } catch (MessagingException ex) {
1094 throw new IOException(ex.getMessage());
1095 }
1096 System.out.println("\n------------------------------------------------------------------");
1097 }
1098
1099
1100 /**
1101 * The main method.
1102 */
1103 public static void main(String[] argv) throws IOException {
1104
1105 DemoSMimeUtil.initDemos();
1106 (new SMimeDemo()).start();
1107 System.out.println("\nReady!");
1108 DemoUtil.waitKey();
1109 }
1110 }