001// Copyright (C) 2002 IAIK 002// https://sic.tech/ 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// This source is provided for inspection purposes and recompilation only, 011// unless specified differently in a contract with IAIK. This source has to 012// be kept in strict confidence and must not be disclosed to any third party 013// under any circumstances. Redistribution in source and binary forms, with 014// or without modification, are <not> permitted in any case! 015// 016// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 017// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 018// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 019// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 020// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 021// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 022// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 023// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 024// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 025// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 026// SUCH DAMAGE. 027// 028// $Header: /IAIK-CMS/current/src/demo/smime/basic/SMimeDemo.java 53 12.02.25 17:58 Dbratko $ 029// $Revision: 53 $ 030// 031 032package demo.smime.basic; 033 034import java.io.ByteArrayInputStream; 035import java.io.ByteArrayOutputStream; 036import java.io.IOException; 037import java.security.NoSuchAlgorithmException; 038import java.security.PrivateKey; 039import java.security.interfaces.RSAPrivateKey; 040import java.util.Date; 041 042import jakarta.activation.DataHandler; 043import jakarta.activation.FileDataSource; 044import jakarta.mail.Message; 045import jakarta.mail.MessagingException; 046import jakarta.mail.Multipart; 047import jakarta.mail.Session; 048import jakarta.mail.internet.InternetAddress; 049import jakarta.mail.internet.MimeBodyPart; 050import jakarta.mail.internet.MimeMessage; 051import jakarta.mail.internet.MimeMultipart; 052 053import demo.DemoSMimeUtil; 054import demo.DemoUtil; 055import demo.keystore.CMSKeyStore; 056import demo.smime.DumpMessage; 057import iaik.asn1.ObjectID; 058import iaik.asn1.structures.AlgorithmID; 059import iaik.asn1.structures.Name; 060import iaik.cms.CMSAlgorithmID; 061import iaik.pkcs.PKCSException; 062import iaik.pkcs.pkcs10.CertificateRequest; 063import iaik.smime.AuthEncryptedContent; 064import iaik.smime.CompressedContent; 065import iaik.smime.EncryptedContent; 066import iaik.smime.PKCS10Content; 067import iaik.smime.SMimeBodyPart; 068import iaik.smime.SMimeMultipart; 069import iaik.smime.SMimeParameters; 070import iaik.smime.SignedContent; 071import iaik.x509.X509Certificate; 072 073/** 074 * This class demonstrates the usage of the IAIK S/MIME implementation. It shows how to create 075 * signed and/or encrypted S/MIME messages and how to parse them and verify the signatures 076 * and decrypt the content, respectively. 077 * <p> 078 * To run this demo the following packages are required: 079 * <ul> 080 * <li> 081 * <code>iaik_cms.jar</code> 082 * </li> 083 * <li> 084 * <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>). 085 * </li> 086 * <li> 087 * <a href="https://jakarta.ee/specifications/mail/" target="_blank">Jakarta</a>/<a href="https://eclipse-ee4j.github.io/angus-mail/" target="_blank">Angus</a> Mail 088 * </li> 089 * <li> 090 * <a href="https://jakarta.ee/specifications/activation/" target="_blank">Jakarta Activation Framework</a> 091 * </li> 092 * </ul> 093 */ 094public class SMimeDemo { 095 096 // whether to print dump all generates test messages to System.out 097 final static boolean PRINT_MESSAGES = false; 098 099 String firstName_ = "John"; // name of sender 100 String lastName_ = "SMime"; 101 String from_ = "smimetest@iaik.tugraz.at"; // email sender 102 String to_ = "smimetest@iaik.tugraz.at"; // email recipient 103 String host_ = "mailhost"; // name of the mailhost 104 105 X509Certificate[] signerCertificates_; // list of certificates to include in the S/MIME message 106 X509Certificate recipientCertificate_; // certificate of the recipient 107 X509Certificate signerCertificate_; // certificate of the signer/sender 108 X509Certificate encryptionCertOfSigner_; // signer uses different certificate for encryption 109 PrivateKey signerPrivateKey_; // private key of the signer/sender 110 111 /** 112 * Default constructor. Reads certificates and keys from the demo keystore. 113 */ 114 public SMimeDemo() { 115 116 System.out.println(); 117 System.out.println("******************************************************************************************"); 118 System.out.println("* SMimeDemo demo *"); 119 System.out.println("* (shows how to create and parse (verify, decrypt) signed and encrypted S/MIME messages) *"); 120 System.out.println("******************************************************************************************"); 121 System.out.println(); 122 123 // get the certificates from the KeyStore 124 signerCertificates_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1); 125 signerPrivateKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1); 126 signerCertificate_ = signerCertificates_[0]; 127 128 // recipient = signer for this test 129 recipientCertificate_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0]; 130 encryptionCertOfSigner_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0]; 131 } 132 133 /** 134 * Starts the demo. 135 * 136 * @throws IOException if an I/O related error occurs 137 */ 138 public void start() throws IOException { 139 140 // get the default Session 141 Session session = DemoSMimeUtil.getSession(); 142 143 try { 144 // Create a demo Multipart 145 MimeBodyPart mbp1 = new SMimeBodyPart(); 146 mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n"); 147 // attachment 148 MimeBodyPart attachment = new SMimeBodyPart(); 149 attachment.setDataHandler(new DataHandler(new FileDataSource("test.html"))); 150 attachment.setFileName("test.html"); 151 152 Multipart mp = new SMimeMultipart(); 153 mp.addBodyPart(mbp1); 154 mp.addBodyPart(attachment); 155 DataHandler multipart = new DataHandler(mp, mp.getContentType()); 156 157 Message msg; // the message to send 158 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream 159 ByteArrayInputStream bais; // we read from a stream 160 161 // 1. This is a plain message 162 msg = createPlainMessage(session, multipart); 163 System.out.println("creating plain message..."); 164 msg.saveChanges(); 165 msg.writeTo(baos); 166 bais = new ByteArrayInputStream(baos.toByteArray()); 167 msg = new MimeMessage(session, bais); 168 if (PRINT_MESSAGES) { 169 printMessage(msg); 170 } 171 DumpMessage.dumpMsg(msg); 172 173 System.out.println("\n\n*****************************************\n\n"); 174 175 // 2. This is an explicitly signed message 176 msg = createSignedMessage(session, multipart, false); 177 System.out.println("creating explicitly signed message..."); 178 baos.reset(); 179 msg.saveChanges(); 180 msg.writeTo(baos); 181 bais = new ByteArrayInputStream(baos.toByteArray()); 182 msg = new MimeMessage(session, bais); 183 if (PRINT_MESSAGES) { 184 printMessage(msg); 185 } 186 DumpMessage.dumpMsg(msg); 187 188 System.out.println("\n\n*****************************************\n\n"); 189 190 191 // 3. This is an implicitly signed message 192 msg = createSignedMessage(session, multipart, true); 193 System.out.println("creating implicitly signed message..."); 194 baos.reset(); 195 msg.saveChanges(); 196 msg.writeTo(baos); 197 bais = new ByteArrayInputStream(baos.toByteArray()); 198 msg = new MimeMessage(session, bais); 199 if (PRINT_MESSAGES) { 200 printMessage(msg); 201 } 202 DumpMessage.dumpMsg(msg); 203 204 System.out.println("\n\n*****************************************\n\n"); 205 206 // 4. Now create encrypted messages with different content encryption algorithms 207 208 // RC2 is deprecated; only demonstrated here 209 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 40); 210 System.out.println("creating encrypted message [RC2/40]..."); 211 baos.reset(); 212 msg.saveChanges(); 213 msg.writeTo(baos); 214 bais = new ByteArrayInputStream(baos.toByteArray()); 215 msg = new MimeMessage(session, bais); 216 if (PRINT_MESSAGES) { 217 printMessage(msg); 218 } 219 DumpMessage.dumpMsg(msg); 220 221 System.out.println("\n\n*****************************************\n\n"); 222 223 // RC2 is deprecated; only demonstrated here 224 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 64); 225 System.out.println("creating encrypted message [RC2/64]..."); 226 baos.reset(); 227 msg.saveChanges(); 228 msg.writeTo(baos); 229 bais = new ByteArrayInputStream(baos.toByteArray()); 230 msg = new MimeMessage(session, bais); 231 if (PRINT_MESSAGES) { 232 printMessage(msg); 233 } 234 DumpMessage.dumpMsg(msg); 235 236 System.out.println("\n\n*****************************************\n\n"); 237 238 // RC2 is deprecated; only demonstrated here 239 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 128); 240 System.out.println("creating encrypted message [RC2/128]..."); 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 // DES EDE is deprecated; only demonstrated here 254 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.des_EDE3_CBC.clone(), 192); 255 System.out.println("creating encrypted message [TripleDES]..."); 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 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CBC.clone(), 128); 269 System.out.println("creating encrypted message [AES/128]..."); 270 baos.reset(); 271 msg.saveChanges(); 272 msg.writeTo(baos); 273 bais = new ByteArrayInputStream(baos.toByteArray()); 274 msg = new MimeMessage(session, bais); 275 if (PRINT_MESSAGES) { 276 printMessage(msg); 277 } 278 DumpMessage.dumpMsg(msg); 279 280 System.out.println("\n\n*****************************************\n\n"); 281 282 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CBC.clone(), 192); 283 System.out.println("creating encrypted message [AES/192]..."); 284 baos.reset(); 285 msg.saveChanges(); 286 msg.writeTo(baos); 287 bais = new ByteArrayInputStream(baos.toByteArray()); 288 msg = new MimeMessage(session, bais); 289 if (PRINT_MESSAGES) { 290 printMessage(msg); 291 } 292 DumpMessage.dumpMsg(msg); 293 294 System.out.println("\n\n*****************************************\n\n"); 295 296 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), 256); 297 System.out.println("creating encrypted message [AES/256]..."); 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 311 // 5. Now create a implicitly signed and encrypted message with attachment 312 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), multipart, true); 313 System.out.println("creating implicitly signed and encrypted message [AES/256]..."); 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 // 6. Now create a explicitly signed and encrypted message with attachment 327 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), multipart, false); 328 System.out.println("creating explicitly signed and encrypted message [AES/256]..."); 329 baos.reset(); 330 msg.saveChanges(); 331 msg.writeTo(baos); 332 bais = new ByteArrayInputStream(baos.toByteArray()); 333 msg = new MimeMessage(session, bais); 334 if (PRINT_MESSAGES) { 335 printMessage(msg); 336 } 337 DumpMessage.dumpMsg(msg); 338 339 System.out.println("\n\n*****************************************\n\n"); 340 341 // 7. Authenticated encrypted message with several algorithms 342 if (DemoUtil.getIaikProviderVersion() >= 5.62) { 343 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), 128); 344 System.out.println("creating encrypted message [AESGCM/128]..."); 345 baos.reset(); 346 msg.saveChanges(); 347 msg.writeTo(baos); 348 bais = new ByteArrayInputStream(baos.toByteArray()); 349 msg = new MimeMessage(session, bais); 350 if (PRINT_MESSAGES) { 351 printMessage(msg); 352 } 353 DumpMessage.dumpMsg(msg); 354 355 System.out.println("\n\n*****************************************\n\n"); 356 357 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_GCM.clone(), 192); 358 System.out.println("creating encrypted message [AESGCM/192]..."); 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 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_GCM.clone(), 256); 372 System.out.println("creating encrypted message [AESGCM/256]..."); 373 baos.reset(); 374 msg.saveChanges(); 375 msg.writeTo(baos); 376 bais = new ByteArrayInputStream(baos.toByteArray()); 377 msg = new MimeMessage(session, bais); 378 if (PRINT_MESSAGES) { 379 printMessage(msg); 380 } 381 DumpMessage.dumpMsg(msg); 382 383 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), 256); 384 System.out.println("creating encrypted message [ChaCha20Poly1305]..."); 385 baos.reset(); 386 msg.saveChanges(); 387 msg.writeTo(baos); 388 bais = new ByteArrayInputStream(baos.toByteArray()); 389 msg = new MimeMessage(session, bais); 390 if (PRINT_MESSAGES) { 391 printMessage(msg); 392 } 393 DumpMessage.dumpMsg(msg); 394 395 System.out.println("\n\n*****************************************\n\n"); 396 397 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), 128); 398 System.out.println("creating encrypted message [AESCCM/128]..."); 399 baos.reset(); 400 msg.saveChanges(); 401 msg.writeTo(baos); 402 bais = new ByteArrayInputStream(baos.toByteArray()); 403 msg = new MimeMessage(session, bais); 404 if (PRINT_MESSAGES) { 405 printMessage(msg); 406 } 407 DumpMessage.dumpMsg(msg); 408 409 System.out.println("\n\n*****************************************\n\n"); 410 411 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CCM.clone(), 192); 412 System.out.println("creating encrypted message [AESCCM/192]..."); 413 baos.reset(); 414 msg.saveChanges(); 415 msg.writeTo(baos); 416 bais = new ByteArrayInputStream(baos.toByteArray()); 417 msg = new MimeMessage(session, bais); 418 if (PRINT_MESSAGES) { 419 printMessage(msg); 420 } 421 DumpMessage.dumpMsg(msg); 422 423 System.out.println("\n\n*****************************************\n\n"); 424 425 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CCM.clone(), 256); 426 System.out.println("creating encrypted message [AESCCM/256]..."); 427 baos.reset(); 428 msg.saveChanges(); 429 msg.writeTo(baos); 430 bais = new ByteArrayInputStream(baos.toByteArray()); 431 msg = new MimeMessage(session, bais); 432 if (PRINT_MESSAGES) { 433 printMessage(msg); 434 } 435 DumpMessage.dumpMsg(msg); 436 437 System.out.println("\n\n*****************************************\n\n"); 438 439 // Now create a implicitly signed and authenticated encrypted message with attachment 440 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), multipart, true); 441 System.out.println("creating implicitly signed and authenticated encrypted message [AES-GCM/128]..."); 442 baos.reset(); 443 msg.saveChanges(); 444 msg.writeTo(baos); 445 bais = new ByteArrayInputStream(baos.toByteArray()); 446 msg = new MimeMessage(session, bais); 447 if (PRINT_MESSAGES) { 448 printMessage(msg); 449 } 450 DumpMessage.dumpMsg(msg); 451 452 System.out.println("\n\n*****************************************\n\n"); 453 454 // Now create a explicitly signed and authenticated encrypted message with attachment 455 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), multipart, false); 456 System.out.println("creating explicitly signed and authenticated encrypted message [AES-GCM/128]..."); 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.chacha20Poly1305.clone(), multipart, true); 471 System.out.println("creating implicitly signed and authenticated encrypted message [ChaChaPoly1305]..."); 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.chacha20Poly1305.clone(), multipart, false); 486 System.out.println("creating explicitly signed and authenticated encrypted message [ChaChaPoly1305]..."); 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.aes128_CCM.clone(), multipart, true); 501 System.out.println("creating implicitly signed and authenticated encrypted message [AES-CCM/128]..."); 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.aes128_CCM.clone(), multipart, false); 516 System.out.println("creating explicitly signed and authenticated encrypted message [AES-CCM/128]..."); 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 530 // 8. certs only message 531 msg = createCertsOnlyMessage(session); 532 System.out.println("creating certs-only message"); 533 baos.reset(); 534 msg.saveChanges(); 535 msg.writeTo(baos); 536 bais = new ByteArrayInputStream(baos.toByteArray()); 537 msg = new MimeMessage(session, bais); 538 if (PRINT_MESSAGES) { 539 printMessage(msg); 540 } 541 DumpMessage.dumpMsg(msg); 542 543 System.out.println("\n\n*****************************************\n\n"); 544 545 // 9. certs only message where the cert list is put into the second part 546 msg = createCertsOnlyMultiPartMessage(session); 547 System.out.println("creating message with certs-only part"); 548 baos.reset(); 549 msg.saveChanges(); 550 msg.writeTo(baos); 551 bais = new ByteArrayInputStream(baos.toByteArray()); 552 msg = new MimeMessage(session, bais); 553 if (PRINT_MESSAGES) { 554 printMessage(msg); 555 } 556 DumpMessage.dumpMsg(msg); 557 558 System.out.println("\n\n*****************************************\n\n"); 559 560 // 10. application/pkcs10 cert request message 561 msg = createPKCS10Message(session); 562 System.out.println("creating application/pkcs10 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 // 11. application/pkcs10 message where the request is in the second part 576 msg = createPKCS10MultiPartMessage(session); 577 System.out.println("creating message with pkcs10 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 // 12. compressed message 591 msg = createCompressedMessage(session, multipart, (AlgorithmID)CMSAlgorithmID.zlib_compress.clone()); 592 System.out.println("creating message with compressed data..."); 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 } catch (Exception ex) { 604 ex.printStackTrace(); 605 throw new RuntimeException(ex.toString()); 606 } 607 } 608 609 /** 610 * Creates a MIME message container with the given subject for the given session. 611 * 612 * @param session the mail sesion 613 * @param subject the subject of the message 614 * 615 * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content) 616 * 617 * @throws MessagingException if the message cannot be created 618 */ 619 public Message createMessage(Session session, String subject) throws MessagingException { 620 MimeMessage msg = new MimeMessage(session); 621 msg.setFrom(new InternetAddress(from_)); 622 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to_, false)); 623 msg.setSentDate(new Date()); 624 msg.setSubject(subject); 625 return msg; 626 } 627 628 /** 629 * Creates a simple plain (neither signed nor encrypted) message. 630 * 631 * @param session the mail session 632 * @param dataHandler the content of the message 633 * 634 * @return the plain message 635 * 636 * @throws MessagingException if an error occurs when creating the message 637 */ 638 public Message createPlainMessage(Session session, DataHandler dataHandler) throws MessagingException { 639 640 Message msg = createMessage(session, "IAIK-S/MIME: Plain message"); 641 if (dataHandler != null) { 642 msg.setDataHandler(dataHandler); 643 } else { 644 msg.setText("This is a plain message!\nIt is wether signed nor encrypted!\n"); 645 } 646 return msg; 647 } 648 649 /** 650 * Creates a signed and encrypted message. 651 * 652 * @param session the mail session 653 * @param algorithm the content encryption algorithm to be used 654 * @param dataHandler the content of the message to be signed and encrypted 655 * @param implicit whether to use implicit (application/pkcs7-mime) or explicit 656 * (multipart/signed) signing 657 * 658 * @return the signed and encrypted message 659 * 660 * @throws MessagingException if an error occurs when creating the message 661 */ 662 public Message createSignedAndEncryptedMessage(Session session, AlgorithmID algorithm, DataHandler dataHandler, boolean implicit) 663 throws MessagingException { 664 665 String subject = null; 666 String text = null; 667 if (implicit) { 668 subject = "IAIK-S/MIME: Implicitly Signed and Encrypted"; 669 text = "This message is implicitly signed and encrypted!\n\n\n"; 670 } else { 671 subject = "IAIK-S/MIME: Explicitly Signed and Encrypted"; 672 text = "This message is explicitly signed and encrypted!\n\n\n"; 673 } 674 Message msg = createMessage(session, subject); 675 676 SignedContent sc = new SignedContent(implicit); 677 if (dataHandler != null) { 678 sc.setDataHandler(dataHandler); 679 } else { 680 sc.setText(text); 681 } 682 sc.setCertificates(signerCertificates_); 683 try { 684 sc.addSigner((RSAPrivateKey)signerPrivateKey_, signerCertificate_); 685 } catch (NoSuchAlgorithmException ex) { 686 throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex); 687 } 688 689 EncryptedContent ec = null; 690 if (algorithm.equals(AlgorithmID.aes256_CBC)) { 691 ec = new EncryptedContent(sc); 692 } else { 693 ec = new AuthEncryptedContent(sc); 694 } 695 // encrypt for the recipient 696 ec.addRecipient(recipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 697 // I want to be able to decrypt the message, too 698 ec.addRecipient(encryptionCertOfSigner_, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 699 // set the encryption algorithm 700 try { 701 ec.setEncryptionAlgorithm(algorithm, -1); 702 } catch (NoSuchAlgorithmException ex) { 703 throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage()); 704 } 705 msg.setContent(ec, ec.getContentType()); 706 // let the EncryptedContent update some message headers 707 ec.setHeaders(msg); 708 709 return msg; 710 } 711 712 713 714 /** 715 * Creates a signed message. 716 * 717 * @param session the mail session 718 * @param dataHandler the content of the message to be signed 719 * @param implicit whether to use implicit (application/pkcs7-mime) or explicit 720 * (multipart/signed) signing 721 * 722 * @return the signed message 723 * 724 * @throws MessagingException if an error occurs when creating the message 725 */ 726 public Message createSignedMessage(Session session, DataHandler dataHandler, boolean implicit) 727 throws MessagingException { 728 729 String subject = null; 730 StringBuffer buf = new StringBuffer(); 731 732 if (implicit) { 733 subject = "IAIK-S/MIME: Implicitly Signed"; 734 buf.append("This message is implicitly signed!\n"); 735 buf.append("You need an S/MIME aware mail client to view this message.\n"); 736 buf.append("\n\n"); 737 } else { 738 subject = "IAIK-S/MIME: Explicitly Signed"; 739 buf.append("This message is explicitly signed!\n"); 740 buf.append("Every mail client can view this message.\n"); 741 buf.append("Non S/MIME mail clients will show the signature as attachment.\n"); 742 buf.append("\n\n"); 743 } 744 745 Message msg = createMessage(session, subject); 746 747 SignedContent sc = new SignedContent(implicit); 748 749 if (dataHandler != null) { 750 sc.setDataHandler(dataHandler); 751 } else { 752 sc.setText(buf.toString()); 753 } 754 sc.setCertificates(signerCertificates_); 755 756 try { 757 sc.addSigner((RSAPrivateKey)signerPrivateKey_, signerCertificate_); 758 } catch (NoSuchAlgorithmException ex) { 759 throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex); 760 } 761 762 msg.setContent(sc, sc.getContentType()); 763 // let the SignedContent update some message headers 764 sc.setHeaders(msg); 765 return msg; 766 } 767 768 /** 769 * Creates an encrypted message. 770 * 771 * @param session the mail session 772 * @param algorithm the content encryption algorithm to be used 773 * @param keyLength the length of the secret content encryption key to be created and used 774 * 775 * @return the encrypted message 776 * 777 * @throws MessagingException if an error occurs when creating the message 778 */ 779 public Message createEncryptedMessage(Session session, AlgorithmID algorithm, int keyLength) 780 throws MessagingException { 781 782 StringBuffer subject = new StringBuffer(); 783 subject.append("IAIK-S/MIME: Encrypted ["+algorithm.getName()); 784 if (keyLength > 0) { 785 subject.append("/"+keyLength); 786 } 787 subject.append("]"); 788 Message msg = createMessage(session, subject.toString()); 789 790 EncryptedContent ec = new EncryptedContent(); 791 792 StringBuffer buf = new StringBuffer(); 793 buf.append("This is the encrypted content!\n"); 794 buf.append("Content encryption algorithm: "+algorithm.getName()); 795 buf.append("\n\n"); 796 797 ec.setText(buf.toString()); 798 // encrypt for the recipient 799 ec.addRecipient(recipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 800 // I want to be able to decrypt the message, too 801 ec.addRecipient(encryptionCertOfSigner_, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 802 try { 803 ec.setEncryptionAlgorithm(algorithm, keyLength); 804 } catch (NoSuchAlgorithmException ex) { 805 throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage()); 806 } 807 808 msg.setContent(ec, ec.getContentType()); 809 // let the EncryptedContent update some message headers 810 ec.setHeaders(msg); 811 812 return msg; 813 } 814 815 /** 816 * Creates an authenticated encrypted message. 817 * 818 * @param session the mail session 819 * @param algorithm the content encryption algorithm to be used 820 * @param keyLength the length of the secret content encryption key to be created and used 821 * 822 * @return the encrypted message 823 * 824 * @throws MessagingException if an error occurs when creating the message 825 */ 826 public Message createAuthEncryptedMessage(Session session, AlgorithmID algorithm, int keyLength) 827 throws MessagingException { 828 829 StringBuffer subject = new StringBuffer(); 830 subject.append("IAIK-S/MIME: AuthEncrypted ["+algorithm.getName()); 831 if (keyLength > 0) { 832 subject.append("/"+keyLength); 833 } 834 subject.append("]"); 835 Message msg = createMessage(session, subject.toString()); 836 837 AuthEncryptedContent ec = new AuthEncryptedContent(); 838 839 StringBuffer buf = new StringBuffer(); 840 buf.append("This is the authenticated encrypted content!\n"); 841 buf.append("Content encryption algorithm: "+algorithm.getName()); 842 buf.append("\n\n"); 843 844 ec.setText(buf.toString()); 845 // encrypt for the recipient 846 ec.addRecipient(recipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 847 // I want to be able to decrypt the message, too 848 ec.addRecipient(encryptionCertOfSigner_, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 849 try { 850 ec.setEncryptionAlgorithm(algorithm, keyLength); 851 } catch (NoSuchAlgorithmException ex) { 852 throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage()); 853 } 854 855 msg.setContent(ec, ec.getContentType()); 856 // let the EncryptedContent update some message headers 857 ec.setHeaders(msg); 858 859 return msg; 860 } 861 862 /** 863 * Creates a certs-only message. 864 * 865 * @param session the mail session 866 * 867 * @return the certs-only message 868 * 869 * @throws MessagingException if an error occurs when creating the message 870 */ 871 public Message createCertsOnlyMessage(Session session) 872 throws MessagingException { 873 874 Message msg = createMessage(session, "IAIK S/MIME: Certs-only message"); 875 //use new content types 876 SMimeParameters.useNewContentTypes(true); 877 SignedContent sc = new SignedContent(true, SignedContent.CERTS_ONLY); 878 sc.setCertificates(signerCertificates_); 879 msg.setContent(sc, sc.getContentType()); 880 //set filename and attachment parameters 881 sc.setHeaders(msg); 882 883 884 return msg; 885 } 886 887 /** 888 * Creates a certs-only message where the certificate list is transferred as attachment. 889 * 890 * @param session the mail session 891 * 892 * @return the certs-only message 893 * 894 * @throws MessagingException if an error occurs when creating the message 895 */ 896 public Message createCertsOnlyMultiPartMessage(Session session) throws MessagingException { 897 898 MimeBodyPart mbp1 = new MimeBodyPart(); 899 mbp1.setText("This is a test where the certs-only message is included in the second part!\n\n"); 900 901 MimeBodyPart attachment = new MimeBodyPart(); 902 //use new content types 903 SMimeParameters.useNewContentTypes(true); 904 SignedContent sc = new SignedContent(true, SignedContent.CERTS_ONLY); 905 sc.setCertificates(signerCertificates_); 906 attachment.setContent(sc, sc.getContentType()); 907 // let the SignedContent update some headers 908 sc.setHeaders(attachment); 909 Multipart mp = new MimeMultipart(); 910 mp.addBodyPart(mbp1); 911 mp.addBodyPart(attachment); 912 913 Message msg = createMessage(session, "IAIK S/MIME: Certs-only multipart message"); 914 msg.setContent(mp, mp.getContentType()); 915 916 return msg; 917 } 918 919 /** 920 * Creates a compressed message. 921 * 922 * @param session the mail session 923 * @param dataHandler the datahandler supplying the content to be compressed 924 * @param algorithm the compression algorithm to be used 925 * 926 * @return the compressed message 927 * 928 * @throws MessagingException if an error occurs when creating the message 929 */ 930 public Message createCompressedMessage(Session session, DataHandler dataHandler, AlgorithmID algorithm) 931 throws MessagingException { 932 933 String subject = "IAIK-S/MIME: Compressed ["+algorithm.getName()+"]"; 934 Message msg = createMessage(session, subject.toString()); 935 936 CompressedContent compressedContent = new CompressedContent(); 937 938 if (dataHandler == null) { 939 StringBuffer buf = new StringBuffer(); 940 buf.append("This is the compressed content!\n"); 941 buf.append("Compression algorithm: "+algorithm.getName()); 942 buf.append("\n\n"); 943 compressedContent.setText(buf.toString()); 944 } else { 945 compressedContent.setDataHandler(dataHandler); 946 } 947 948 try { 949 compressedContent.setCompressionAlgorithm(algorithm); 950 } catch (NoSuchAlgorithmException ex) { 951 throw new MessagingException("Compression algorithm not supported: " + ex.getMessage()); 952 } 953 954 msg.setContent(compressedContent, compressedContent.getContentType()); 955 // let the CompressedContent update some message headers 956 compressedContent.setHeaders(msg); 957 958 return msg; 959 } 960 961 /** 962 * Creates a PKCS#10 certificate request message. 963 * 964 * @param session the mail session 965 * 966 * @return the PKCS#10 certificate request message 967 * 968 * @throws MessagingException if an error occurs when creating the message 969 */ 970 public Message createPKCS10Message(Session session) 971 throws MessagingException { 972 973 Message msg = createMessage(session, "IAIK-S/MIME: Certificate Request"); 974 975 PKCS10Content pc = new PKCS10Content(); 976 CertificateRequest request = null; 977 try { 978 request = createCertificateRequest(); 979 } catch (PKCSException ex) { 980 throw new MessagingException(ex.getMessage()); 981 } 982 pc.setCertRequest(request); 983 msg.setContent(pc, pc.getContentType()); 984 // let the PKCS10Content update some message headers 985 pc.setHeaders(msg); 986 987 return msg; 988 } 989 990 /** 991 * Creates a PKCS#10 message where the certificate request is transferred as attachment. 992 * 993 * @param session the mail session 994 * 995 * @return the PKCS#10 certificate request message 996 * 997 * @throws MessagingException if an error occurs when creating the message 998 */ 999 public Message createPKCS10MultiPartMessage(Session session) throws MessagingException { 1000 1001 MimeBodyPart mbp1 = new MimeBodyPart(); 1002 mbp1.setText("This is a test where the request message is included in the second part!\n\n"); 1003 // try to test an attachment 1004 // this demo attaches our homepage 1005 MimeBodyPart attachment = new MimeBodyPart(); 1006 //use new content types 1007 SMimeParameters.useNewContentTypes(true); 1008 PKCS10Content pc = new PKCS10Content(); 1009 CertificateRequest request = null; 1010 try { 1011 request = createCertificateRequest(); 1012 } catch (PKCSException ex) { 1013 throw new MessagingException(ex.getMessage()); 1014 } 1015 pc.setCertRequest(request); 1016 DataHandler pkcs10Handler = new DataHandler(pc, pc.getContentType()); 1017 attachment.setDataHandler(pkcs10Handler); 1018 attachment.setDisposition("attachment"); 1019 attachment.setFileName("smime.p10"); 1020 Multipart mp = new MimeMultipart(); 1021 mp.addBodyPart(mbp1); 1022 mp.addBodyPart(attachment); 1023 1024 Message msg = createMessage(session, "IAIK-S/MIME: Certificate Request multipart message"); 1025 msg.setContent(mp, mp.getContentType()); 1026 return msg; 1027 } 1028 1029 /** 1030 * Creates a PKCS#10 certificate request. 1031 * 1032 * @return the certificate request 1033 * 1034 * @throws PKCSException if the request cannot be created 1035 */ 1036 private CertificateRequest createCertificateRequest() throws PKCSException { 1037 try { 1038 Name subject = new Name(); 1039 subject.addRDN(ObjectID.commonName, firstName_ + " " + lastName_); 1040 subject.addRDN(ObjectID.emailAddress, from_); 1041 CertificateRequest certRequest; 1042 1043 certRequest = new CertificateRequest(signerCertificate_.getPublicKey(), subject); 1044 certRequest.sign((AlgorithmID)AlgorithmID.sha256WithRSAEncryption.clone(), signerPrivateKey_); 1045 certRequest.verify(); 1046 return certRequest; 1047 } catch (Exception ex) { 1048 throw new PKCSException("Cannot create cert request: " + ex.getMessage()); 1049 } 1050 } 1051 1052 1053 /** 1054 * Prints a dump of the given message to System.out. 1055 * 1056 * @param msg the message to be dumped to System.out 1057 */ 1058 static void printMessage(Message msg) throws IOException { 1059 System.out.println("------------------------------------------------------------------"); 1060 System.out.println("Message dump: \n"); 1061 try { 1062 msg.writeTo(System.out); 1063 } catch (MessagingException ex) { 1064 throw new IOException(ex.getMessage()); 1065 } 1066 System.out.println("\n------------------------------------------------------------------"); 1067 } 1068 1069 1070 /** 1071 * The main method. 1072 */ 1073 public static void main(String[] argv) throws IOException { 1074 1075 DemoSMimeUtil.initDemos(); 1076 (new SMimeDemo()).start(); 1077 System.out.println("\nReady!"); 1078 DemoUtil.waitKey(); 1079 } 1080}