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 }