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