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/SMimeV3Demo.java 49 12.02.25 17:58 Dbratko $ 029// $Revision: 49 $ 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.util.Date; 040 041import jakarta.activation.DataHandler; 042import jakarta.activation.FileDataSource; 043import jakarta.mail.Message; 044import jakarta.mail.MessagingException; 045import jakarta.mail.Multipart; 046import jakarta.mail.Session; 047import jakarta.mail.internet.InternetAddress; 048import jakarta.mail.internet.MimeBodyPart; 049import jakarta.mail.internet.MimeMessage; 050import jakarta.mail.internet.MimeMultipart; 051 052import demo.DemoSMimeUtil; 053import demo.DemoUtil; 054import demo.keystore.CMSKeyStore; 055import demo.smime.DumpMessage; 056import iaik.asn1.ObjectID; 057import iaik.asn1.structures.AlgorithmID; 058import iaik.asn1.structures.Name; 059import iaik.cms.CMSAlgorithmID; 060import iaik.pkcs.PKCSException; 061import iaik.pkcs.pkcs10.CertificateRequest; 062import iaik.smime.AuthEncryptedContent; 063import iaik.smime.CompressedContent; 064import iaik.smime.EncryptedContent; 065import iaik.smime.PKCS10Content; 066import iaik.smime.SMimeBodyPart; 067import iaik.smime.SMimeException; 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/MIMEv3 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> (IAIK-CMS/SMIME) 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 * You also will need the ESDH implementation of IAIK-JCE contained in <code>iaik_esdh.jar</code> or 094 * <code>iaik_jce_full.jar</code>; the first may be used in addition to <code>iaik_jce.jar</code>, 095 * the second instead of <code>iaik_jce.jar</code>. 096 */ 097public class SMimeV3Demo { 098 099 // whether to print dump all generates test messages to System.out 100 final static boolean PRINT_MESSAGES = false; 101 102 103 String firstName = "John"; 104 String lastName = "SMime"; 105 String to = "smimetest@iaik.tugraz.at"; // email recipient 106 String from = "smimetest@iaik.tugraz.at"; // email sender 107 String host = "mailhost"; // name of the mailhost 108 109 X509Certificate[] signerCertificates; // list of certificates to include in the S/MIME message 110 X509Certificate recipientCertificate; // certificate of the recipient 111 X509Certificate signerCertificate; // certificate of the signer/sender 112 X509Certificate encryptionCertOfSigner; // signer uses different certificate for encryption 113 PrivateKey signerPrivateKey; // private key of the signer/sender 114 115 /** 116 * Default constructor. Reads certificates and keys from the demo keystore. 117 */ 118 public SMimeV3Demo() { 119 120 System.out.println(); 121 System.out.println("********************************************************************************************"); 122 System.out.println("* SMimeV3Demo demo *"); 123 System.out.println("* (shows how to create and parse (verify, decrypt) signed and encrypted S/MIMEv3 messages) *"); 124 System.out.println("********************************************************************************************"); 125 System.out.println(); 126 127 // get the certificates from the KeyStore 128 signerCertificates = CMSKeyStore.getCertificateChain(CMSKeyStore.DSA, CMSKeyStore.SZ_2048_SIGN_1); 129 signerPrivateKey = CMSKeyStore.getPrivateKey(CMSKeyStore.DSA, CMSKeyStore.SZ_2048_SIGN_1); 130 signerCertificate = signerCertificates[0]; 131 132 // recipient = signer for this test 133 recipientCertificate = CMSKeyStore.getCertificateChain(CMSKeyStore.ESDH, CMSKeyStore.SZ_2048_CRYPT_1)[0]; 134 if (recipientCertificate == null) { 135 throw new NullPointerException("ESDH certificate not available! Add iaik_esdh.jar to your classpath!"); 136 } 137 encryptionCertOfSigner = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0]; 138 } 139 140 /** 141 * Starts the demo. 142 * 143 * @throws IOException if an I/O related error occurs 144 */ 145 public void start() throws IOException { 146 147 // get the default Session 148 Session session = DemoSMimeUtil.getSession(); 149 150 try { 151 // Create a demo Multipart 152 MimeBodyPart mbp1 = new SMimeBodyPart(); 153 mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n"); 154 // attachment 155 MimeBodyPart attachment = new SMimeBodyPart(); 156 attachment.setDataHandler(new DataHandler(new FileDataSource("test.html"))); 157 attachment.setFileName("test.html"); 158 159 Multipart mp = new SMimeMultipart(); 160 mp.addBodyPart(mbp1); 161 mp.addBodyPart(attachment); 162 DataHandler multipart = new DataHandler(mp, mp.getContentType()); 163 164 Message msg; // the message to send 165 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream 166 ByteArrayInputStream bais; // we read from a stream 167 168 // 1. This is a plain message 169 msg = createPlainMessage(session, multipart); 170 System.out.println("creating plain message..."); 171 msg.saveChanges(); 172 msg.writeTo(baos); 173 bais = new ByteArrayInputStream(baos.toByteArray()); 174 msg = new MimeMessage(session, bais); 175 if (PRINT_MESSAGES) { 176 printMessage(msg); 177 } 178 DumpMessage.dumpMsg(msg); 179 180 System.out.println("\n\n*****************************************\n\n"); 181 182 // 2. This is an explicitly signed message 183 msg = createSignedMessage(session, multipart, false, AlgorithmID.sha256, AlgorithmID.dsaWithSHA256); 184 System.out.println("creating explicitly signed message..."); 185 baos.reset(); 186 msg.saveChanges(); 187 msg.writeTo(baos); 188 bais = new ByteArrayInputStream(baos.toByteArray()); 189 msg = new MimeMessage(session, bais); 190 if (PRINT_MESSAGES) { 191 printMessage(msg); 192 } 193 DumpMessage.dumpMsg(msg); 194 195 System.out.println("\n\n*****************************************\n\n"); 196 197 198 // 3. This is an implicitly signed message 199 msg = createSignedMessage(session, multipart, true, AlgorithmID.sha256, AlgorithmID.dsaWithSHA256); 200 System.out.println("creating implicitly signed message..."); 201 baos.reset(); 202 msg.saveChanges(); 203 msg.writeTo(baos); 204 bais = new ByteArrayInputStream(baos.toByteArray()); 205 msg = new MimeMessage(session, bais); 206 if (PRINT_MESSAGES) { 207 printMessage(msg); 208 } 209 DumpMessage.dumpMsg(msg); 210 211 System.out.println("\n\n*****************************************\n\n"); 212 213 // 4. Now create encrypted messages with different content encryption algorithms 214 215 // RC2 is deprecated; only demonstrated here 216 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 40, 217 (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)AlgorithmID.cms_rc2_wrap.clone(), 128); 218 System.out.println("creating encrypted message [RC2/40]..."); 219 baos.reset(); 220 msg.saveChanges(); 221 msg.writeTo(baos); 222 bais = new ByteArrayInputStream(baos.toByteArray()); 223 msg = new MimeMessage(session, bais); 224 if (PRINT_MESSAGES) { 225 printMessage(msg); 226 } 227 DumpMessage.dumpMsg(msg); 228 229 System.out.println("\n\n*****************************************\n\n"); 230 231 // RC2 is deprecated; only demonstrated here 232 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 64, 233 (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)AlgorithmID.cms_rc2_wrap.clone(), 128); 234 System.out.println("creating encrypted message [RC2/64]..."); 235 baos.reset(); 236 msg.saveChanges(); 237 msg.writeTo(baos); 238 bais = new ByteArrayInputStream(baos.toByteArray()); 239 msg = new MimeMessage(session, bais); 240 if (PRINT_MESSAGES) { 241 printMessage(msg); 242 } 243 DumpMessage.dumpMsg(msg); 244 245 System.out.println("\n\n*****************************************\n\n"); 246 247 // RC2 is deprecated; only demonstrated here 248 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 128, 249 (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)AlgorithmID.cms_rc2_wrap.clone(), 128); 250 System.out.println("creating encrypted message [RC2/128]..."); 251 baos.reset(); 252 msg.saveChanges(); 253 msg.writeTo(baos); 254 bais = new ByteArrayInputStream(baos.toByteArray()); 255 msg = new MimeMessage(session, bais); 256 if (PRINT_MESSAGES) { 257 printMessage(msg); 258 } 259 DumpMessage.dumpMsg(msg); 260 261 262 System.out.println("\n\n*****************************************\n\n"); 263 264 // DES EDE is deprecated; only demonstrated here 265 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.des_EDE3_CBC.clone(), 192, 266 (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)AlgorithmID.cms_3DES_wrap.clone(), 192); 267 System.out.println("creating encrypted message [TripleDES]..."); 268 baos.reset(); 269 msg.saveChanges(); 270 msg.writeTo(baos); 271 bais = new ByteArrayInputStream(baos.toByteArray()); 272 msg = new MimeMessage(session, bais); 273 if (PRINT_MESSAGES) { 274 printMessage(msg); 275 } 276 DumpMessage.dumpMsg(msg); 277 278 System.out.println("\n\n*****************************************\n\n"); 279 280 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CBC.clone(), 128, 281 (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes128_wrap.clone(), 128); 282 System.out.println("creating encrypted message [AES/128]..."); 283 baos.reset(); 284 msg.saveChanges(); 285 msg.writeTo(baos); 286 bais = new ByteArrayInputStream(baos.toByteArray()); 287 msg = new MimeMessage(session, bais); 288 if (PRINT_MESSAGES) { 289 printMessage(msg); 290 } 291 DumpMessage.dumpMsg(msg); 292 293 System.out.println("\n\n*****************************************\n\n"); 294 295 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CBC.clone(), 192, 296 (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes192_wrap.clone(), 192); 297 System.out.println("creating encrypted message [AES/192]..."); 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.aes256_CBC.clone(), 256, 311 (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes256_wrap.clone(), 256); 312 System.out.println("creating encrypted message [AES/256]..."); 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 324 System.out.println("\n\n*****************************************\n\n"); 325 326 // 5. Now create an implicitly signed and encrypted message with attachment 327 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), multipart, true); 328 System.out.println("creating implicitly 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 // 6. Now create an explicitly signed and encrypted message with attachment 342 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), multipart, false); 343 System.out.println("creating explicitly 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 // 7. Now create authenticated encrypted messages with different content encryption algorithms 357 if (DemoUtil.getIaikProviderVersion() >= 5.62) { 358 359 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), 128, 360 (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes128_wrap.clone(), 128); 361 System.out.println("creating authenticated encrypted message [AES-GCM/128]..."); 362 baos.reset(); 363 msg.saveChanges(); 364 msg.writeTo(baos); 365 bais = new ByteArrayInputStream(baos.toByteArray()); 366 msg = new MimeMessage(session, bais); 367 if (PRINT_MESSAGES) { 368 printMessage(msg); 369 } 370 DumpMessage.dumpMsg(msg); 371 372 System.out.println("\n\n*****************************************\n\n"); 373 374 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_GCM.clone(), 192, 375 (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes192_wrap.clone(), 192); 376 System.out.println("creating authenticated encrypted message [AES-GCM/192]..."); 377 baos.reset(); 378 msg.saveChanges(); 379 msg.writeTo(baos); 380 bais = new ByteArrayInputStream(baos.toByteArray()); 381 msg = new MimeMessage(session, bais); 382 if (PRINT_MESSAGES) { 383 printMessage(msg); 384 } 385 DumpMessage.dumpMsg(msg); 386 387 System.out.println("\n\n*****************************************\n\n"); 388 389 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_GCM.clone(), 256, 390 (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes256_wrap.clone(), 256); 391 System.out.println("creating authenticated encrypted message [AES-GCM/256]..."); 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.aes128_CCM.clone(), 128, 405 (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes128_wrap.clone(), 128); 406 System.out.println("creating authenticated encrypted message [AES-CCM/128]..."); 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.aes192_CCM.clone(), 192, 420 (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes192_wrap.clone(), 192); 421 System.out.println("creating authenticated encrypted message [AES-CCM/192]..."); 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 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CCM.clone(), 256, 433 (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes256_wrap.clone(), 256); 434 System.out.println("creating authenticated encrypted message [AES-CCM/256]..."); 435 baos.reset(); 436 msg.saveChanges(); 437 msg.writeTo(baos); 438 bais = new ByteArrayInputStream(baos.toByteArray()); 439 msg = new MimeMessage(session, bais); 440 if (PRINT_MESSAGES) { 441 printMessage(msg); 442 } 443 DumpMessage.dumpMsg(msg); 444 445 System.out.println("\n\n*****************************************\n\n"); 446 447 msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), 256, 448 (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes256_wrap.clone(), 256); 449 System.out.println("creating authenticated encrypted message [ChaChaPoly1305]..."); 450 baos.reset(); 451 msg.saveChanges(); 452 msg.writeTo(baos); 453 bais = new ByteArrayInputStream(baos.toByteArray()); 454 msg = new MimeMessage(session, bais); 455 if (PRINT_MESSAGES) { 456 printMessage(msg); 457 } 458 DumpMessage.dumpMsg(msg); 459 460 System.out.println("\n\n*****************************************\n\n"); 461 462 // Create an implicitly signed and authenticated encrypted message with attachment 463 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_GCM.clone(), multipart, true); 464 System.out.println("creating implicitly signed and encrypted message [AES-GCM/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 // Create an explicitly signed and encrypted message with attachment 478 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_GCM.clone(), multipart, false); 479 System.out.println("creating explicitly signed and encrypted message [AES-GCM/256]..."); 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_CCM.clone(), multipart, true); 494 System.out.println("creating implicitly signed and encrypted message [AES-CCM/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_CCM.clone(), multipart, false); 509 System.out.println("creating explicitly signed and encrypted message [AES-CCM/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.chacha20Poly1305.clone(), multipart, true); 524 System.out.println("creating implicitly signed and encrypted message [ChaCha20Poly1305]..."); 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.chacha20Poly1305.clone(), multipart, false); 539 System.out.println("creating explicitly signed and encrypted message [ChaCha20Poly1305]..."); 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 } 553 554 // 8. certs only message 555 msg = createCertsOnlyMessage(session); 556 System.out.println("creating certs-only message"); 557 baos.reset(); 558 msg.saveChanges(); 559 msg.writeTo(baos); 560 bais = new ByteArrayInputStream(baos.toByteArray()); 561 msg = new MimeMessage(session, bais); 562 if (PRINT_MESSAGES) { 563 printMessage(msg); 564 } 565 DumpMessage.dumpMsg(msg); 566 567 System.out.println("\n\n*****************************************\n\n"); 568 569 // 9. second certs only message 570 msg = createCertsOnlyMultiPartMessage(session); 571 System.out.println("creating message with certs-only part"); 572 baos.reset(); 573 msg.saveChanges(); 574 msg.writeTo(baos); 575 bais = new ByteArrayInputStream(baos.toByteArray()); 576 msg = new MimeMessage(session, bais); 577 if (PRINT_MESSAGES) { 578 printMessage(msg); 579 } 580 DumpMessage.dumpMsg(msg); 581 582 System.out.println("\n\n*****************************************\n\n"); 583 584 // 10. application/pkcs10 cert request message 585 msg = createPKCS10Message(session); 586 System.out.println("creating application/pkcs10 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 // 11. ending application/pkcs10 message where the request is in the second part 600 msg = createPKCS10MultiPartMessage(session); 601 System.out.println("creating message with pkcs10 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 // 12. compressed message 615 msg = createCompressedMessage(session, multipart, (AlgorithmID)CMSAlgorithmID.zlib_compress.clone()); 616 System.out.println("creating message with compressed data..."); 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 } catch (Exception ex) { 628 ex.printStackTrace(); 629 throw new RuntimeException(ex.toString()); 630 } 631 } 632 633 /** 634 * Creates a MIME message container with the given subject for the given session. 635 * 636 * @param session the mail sesion 637 * @param subject the subject of the message 638 * 639 * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content) 640 * 641 * @throws MessagingException if the message cannot be created 642 */ 643 public Message createMessage(Session session, String subject) throws MessagingException { 644 MimeMessage msg = new MimeMessage(session); 645 msg.setFrom(new InternetAddress(from)); 646 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false)); 647 msg.setSentDate(new Date()); 648 msg.setSubject(subject); 649 return msg; 650 } 651 652 /** 653 * Creates a simple plain (neither signed nor encrypted) message. 654 * 655 * @param session the mail session 656 * @param dataHandler the content of the message 657 * 658 * @return the plain message 659 * 660 * @throws MessagingException if an error occurs when creating the message 661 */ 662 public Message createPlainMessage(Session session, DataHandler dataHandler) throws MessagingException { 663 664 Message msg = createMessage(session, "IAIK-S/MIME: Plain message"); 665 if (dataHandler != null) { 666 msg.setDataHandler(dataHandler); 667 } else { 668 msg.setText("This is a plain message!\nIt is wether signed nor encrypted!\n"); 669 } 670 return msg; 671 } 672 673 /** 674 * Creates a signed and encrypted message. 675 * 676 * @param session the mail session 677 * @param algorithm the content encryption algorithm to be used 678 * @param dataHandler the content of the message to be signed and encrypted 679 * @param implicit whether to use implicit (application/pkcs7-mime) or explicit 680 * (multipart/signed) signing 681 * 682 * @return the signed and encrypted message 683 * 684 * @throws MessagingException if an error occurs when creating the message 685 */ 686 public Message createSignedAndEncryptedMessage(Session session, AlgorithmID algorithm, DataHandler dataHandler, boolean implicit) 687 throws MessagingException { 688 689 String subject = null; 690 String text = null; 691 if (implicit) { 692 subject = "IAIK-S/MIME: Implicitly Signed and Encrypted"; 693 text = "This message is implicitly signed and encrypted!\n\n\n"; 694 } else { 695 subject = "IAIK-S/MIME: Explicitly Signed and Encrypted"; 696 text = "This message is explicitly signed and encrypted!\n\n\n"; 697 } 698 Message msg = createMessage(session, subject); 699 700 SignedContent sc = new SignedContent(implicit); 701 if (dataHandler != null) { 702 sc.setDataHandler(dataHandler); 703 } else { 704 sc.setText(text); 705 } 706 sc.setCertificates(signerCertificates); 707 try { 708 sc.addSigner(signerPrivateKey, 709 signerCertificate, 710 (AlgorithmID)AlgorithmID.sha256.clone(), 711 (AlgorithmID)AlgorithmID.dsaWithSHA256.clone()); 712 } catch (NoSuchAlgorithmException ex) { 713 throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex); 714 } 715 716 EncryptedContent ec = null; 717 if (algorithm.equals(AlgorithmID.aes256_CBC)) { 718 ec = new EncryptedContent(sc); 719 } else { 720 ec = new AuthEncryptedContent(sc); 721 } 722 // encrypt for the recipient 723 AlgorithmID keyEA = (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(); 724 // the key wrap algorithm to use: 725 AlgorithmID keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone(); 726 // the length of the key encryption key to be generated: 727 int kekLength = 256; 728 try { 729 ec.addRecipient(recipientCertificate, keyEA, keyWrapAlg, kekLength); 730 } catch (SMimeException ex) { 731 throw new MessagingException("Error adding ESDH recipient: " + ex.getMessage()); 732 } 733 // I want to be able to decrypt the message, too 734 ec.addRecipient(encryptionCertOfSigner, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 735 // set the encryption algorithm 736 try { 737 ec.setEncryptionAlgorithm(algorithm, -1); 738 } catch (NoSuchAlgorithmException ex) { 739 throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage()); 740 } 741 msg.setContent(ec, ec.getContentType()); 742 // let the EncryptedContent update some message headers 743 ec.setHeaders(msg); 744 745 return msg; 746 } 747 748 /** 749 * Creates a signed message. 750 * 751 * @param session the mail session 752 * @param dataHandler the content of the message to be signed 753 * @param implicit whether to use implicit (application/pkcs7-mime) or explicit 754 * (multipart/signed) signing 755 * @param digestAlgorithm the digest algorithm to be used 756 * @param signatureAlgorithm the signature algorithm to be used 757 * 758 * @return the signed message 759 * 760 * @throws MessagingException if an error occurs when creating the message 761 */ 762 public Message createSignedMessage(Session session, 763 DataHandler dataHandler, 764 boolean implicit, 765 AlgorithmID digestAlgorithm, 766 AlgorithmID signatureAlgorithm) 767 throws MessagingException { 768 769 String subject = null; 770 StringBuffer buf = new StringBuffer(); 771 772 if (implicit) { 773 subject = "IAIK-S/MIME: Implicitly Signed"; 774 buf.append("This message is implicitly signed!\n"); 775 buf.append("You need an S/MIME aware mail client to view this message.\n"); 776 buf.append("\n\n"); 777 } else { 778 subject = "IAIK-S/MIME: Explicitly Signed"; 779 buf.append("This message is explicitly signed!\n"); 780 buf.append("Every mail client can view this message.\n"); 781 buf.append("Non S/MIME mail clients will show the signature as attachment.\n"); 782 buf.append("\n\n"); 783 } 784 785 Message msg = createMessage(session, subject); 786 787 SignedContent sc = new SignedContent(implicit); 788 if (dataHandler != null) { 789 sc.setDataHandler(dataHandler); 790 } else { 791 sc.setText(buf.toString()); 792 } 793 sc.setCertificates(signerCertificates); 794 795 try { 796 sc.addSigner(signerPrivateKey, 797 signerCertificate, 798 (AlgorithmID)digestAlgorithm.clone(), 799 (AlgorithmID)signatureAlgorithm.clone()); 800 } catch (NoSuchAlgorithmException ex) { 801 throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex); 802 } 803 804 msg.setContent(sc, sc.getContentType()); 805 // let the SignedContent update some message headers 806 sc.setHeaders(msg); 807 return msg; 808 } 809 810 /** 811 * Creates an encrypted message. 812 * 813 * @param session the mail session 814 * @param contentEA the content encryption algorithm to be used 815 * @param keyLength the length of the secret content encryption key to be created and used 816 * @param keyEA the key encryption algorithm to be used 817 * @param keyWrapAlgorithm the key wrap algorithm to be used 818 * @param kekLength the length of the key encryption algorithm 819 * 820 * @return the encrypted message 821 * 822 * @throws MessagingException if an error occurs when creating the message 823 */ 824 public Message createEncryptedMessage(Session session, AlgorithmID contentEA, int keyLength, 825 AlgorithmID keyEA, AlgorithmID keyWrapAlgorithm, int kekLength) 826 throws MessagingException { 827 828 AlgorithmID algorithm = (AlgorithmID)contentEA.clone(); 829 AlgorithmID keyAgreeAlg = (AlgorithmID)keyEA.clone(); 830 AlgorithmID keyWrapAlg = (AlgorithmID)keyWrapAlgorithm.clone(); 831 832 StringBuffer subject = new StringBuffer(); 833 subject.append("IAIK-S/MIME: Encrypted ["+algorithm.getName()); 834 if (keyLength > 0) { 835 subject.append("/"+keyLength); 836 } 837 subject.append("]"); 838 Message msg = createMessage(session, subject.toString()); 839 840 EncryptedContent ec = new EncryptedContent(); 841 842 StringBuffer buf = new StringBuffer(); 843 buf.append("This is the encrypted content!\n"); 844 buf.append("Content encryption algorithm: "+algorithm.getName()); 845 buf.append("\n\n"); 846 847 ec.setText(buf.toString()); 848 849 try { 850 ec.addRecipient(recipientCertificate, keyAgreeAlg, keyWrapAlg, kekLength); 851 } catch (SMimeException ex) { 852 throw new MessagingException("Error adding ESDH recipient: " + ex.getMessage()); 853 } 854 // I want to be able to decrypt the message, too 855 ec.addRecipient(encryptionCertOfSigner, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 856 try { 857 ec.setEncryptionAlgorithm(algorithm, keyLength); 858 } catch (NoSuchAlgorithmException ex) { 859 throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage()); 860 } 861 862 msg.setContent(ec, ec.getContentType()); 863 // let the EncryptedContent update some message headers 864 ec.setHeaders(msg); 865 866 return msg; 867 } 868 869 /** 870 * Creates an authenticated encrypted message. 871 * 872 * @param session the mail session 873 * @param contentEA the content encryption algorithm to be used 874 * @param keyLength the length of the secret content encryption key to be created and used 875 * @param keyEA the key encryption algorithm to be used 876 * @param keyWrapAlgorithm the key wrap algorithm to be used 877 * @param kekLength the length of the key encryption algorithm 878 * @return the encrypted message 879 * 880 * @throws MessagingException if an error occurs when creating the message 881 */ 882 public Message createAuthEncryptedMessage(Session session, AlgorithmID contentEA, int keyLength, 883 AlgorithmID keyEA, AlgorithmID keyWrapAlgorithm, int kekLength) 884 throws MessagingException { 885 886 AlgorithmID algorithm = (AlgorithmID)contentEA.clone(); 887 AlgorithmID keyAgreeAlg = (AlgorithmID)keyEA.clone(); 888 AlgorithmID keyWrapAlg = (AlgorithmID)keyWrapAlgorithm.clone(); 889 890 StringBuffer subject = new StringBuffer(); 891 subject.append("IAIK-S/MIME: Authenticated Encrypted ["+algorithm.getName()); 892 if (keyLength > 0) { 893 subject.append("/"+keyLength); 894 } 895 subject.append("]"); 896 Message msg = createMessage(session, subject.toString()); 897 898 AuthEncryptedContent ec = new AuthEncryptedContent(); 899 900 StringBuffer buf = new StringBuffer(); 901 buf.append("This is the authenticated encrypted content!\n"); 902 buf.append("Content encryption algorithm: "+algorithm.getName()); 903 buf.append("\n\n"); 904 905 ec.setText(buf.toString()); 906 907 try { 908 ec.addRecipient(recipientCertificate, keyAgreeAlg, keyWrapAlg, kekLength); 909 } catch (SMimeException ex) { 910 throw new MessagingException("Error adding ESDH recipient: " + ex.getMessage()); 911 } 912 // I want to be able to decrypt the message, too 913 ec.addRecipient(encryptionCertOfSigner, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 914 try { 915 ec.setEncryptionAlgorithm(algorithm, keyLength); 916 } catch (NoSuchAlgorithmException ex) { 917 throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage()); 918 } 919 920 msg.setContent(ec, ec.getContentType()); 921 // let the EncryptedContent update some message headers 922 ec.setHeaders(msg); 923 924 return msg; 925 } 926 927 /** 928 * Creates a certs-only message. 929 * 930 * @param session the mail session 931 * 932 * @return the certs-only message 933 * 934 * @throws MessagingException if an error occurs when creating the message 935 */ 936 public Message createCertsOnlyMessage(Session session) 937 throws MessagingException { 938 939 Message msg = createMessage(session, "IAIK S/MIME: Certs-only message"); 940 //use new content types 941 SMimeParameters.useNewContentTypes(true); 942 SignedContent sc = new SignedContent(true, SignedContent.CERTS_ONLY); 943 sc.setCertificates(signerCertificates); 944 msg.setContent(sc, sc.getContentType()); 945 //set filename and attachment parameters 946 sc.setHeaders(msg); 947 948 return msg; 949 } 950 951 952 /** 953 * Creates a certs-only message where the certificate list is transferred as attachment. 954 * 955 * @param session the mail session 956 * 957 * @return the certs-only message 958 * 959 * @throws MessagingException if an error occurs when creating the message 960 */ 961 public Message createCertsOnlyMultiPartMessage(Session session) throws MessagingException { 962 963 MimeBodyPart mbp1 = new MimeBodyPart(); 964 mbp1.setText("This is a test where the certs-only message is included in the second part!\n\n"); 965 966 MimeBodyPart attachment = new MimeBodyPart(); 967 //use new content types 968 SMimeParameters.useNewContentTypes(true); 969 SignedContent sc = new SignedContent(true, SignedContent.CERTS_ONLY); 970 sc.setCertificates(signerCertificates); 971 attachment.setContent(sc, sc.getContentType()); 972 // let the SignedContent update some headers 973 sc.setHeaders(attachment); 974 Multipart mp = new MimeMultipart(); 975 mp.addBodyPart(mbp1); 976 mp.addBodyPart(attachment); 977 978 Message msg = createMessage(session, "IAIK S/MIME: Certs-only multipart message"); 979 msg.setContent(mp, mp.getContentType()); 980 return msg; 981 } 982 983 /** 984 * Creates a compressed message. 985 * 986 * @param session the mail session 987 * @param dataHandler the datahandler supplying the content to be compressed 988 * @param algorithm the compression algorithm to be used 989 * 990 * @return the compressed message 991 * 992 * @throws MessagingException if an error occurs when creating the message 993 */ 994 public Message createCompressedMessage(Session session, DataHandler dataHandler, AlgorithmID algorithm) 995 throws MessagingException { 996 997 String subject = "IAIK-S/MIME: Compressed ["+algorithm.getName()+"]"; 998 Message msg = createMessage(session, subject.toString()); 999 1000 CompressedContent compressedContent = new CompressedContent(); 1001 1002 if (dataHandler == null) { 1003 StringBuffer buf = new StringBuffer(); 1004 buf.append("This is the compressed content!\n"); 1005 buf.append("Compression algorithm: "+algorithm.getName()); 1006 buf.append("\n\n"); 1007 compressedContent.setText(buf.toString()); 1008 } else { 1009 compressedContent.setDataHandler(dataHandler); 1010 } 1011 1012 try { 1013 compressedContent.setCompressionAlgorithm(algorithm); 1014 } catch (NoSuchAlgorithmException ex) { 1015 throw new MessagingException("Compression algorithm not supported: " + ex.getMessage()); 1016 } 1017 1018 msg.setContent(compressedContent, compressedContent.getContentType()); 1019 // let the CompressedContent update some message headers 1020 compressedContent.setHeaders(msg); 1021 1022 return msg; 1023 } 1024 1025 /** 1026 * Creates a PKCS#10 certificate request message. 1027 * 1028 * @param session the mail session 1029 * 1030 * @return the PKCS#10 certificate request message 1031 * 1032 * @throws MessagingException if an error occurs when creating the message 1033 */ 1034 public Message createPKCS10Message(Session session) 1035 throws MessagingException { 1036 1037 Message msg = createMessage(session, "IAIK-S/MIME: Certificate Request"); 1038 1039 PKCS10Content pc = new PKCS10Content(); 1040 CertificateRequest request = null; 1041 try { 1042 request = createCertificateRequest(); 1043 } catch (PKCSException ex) { 1044 throw new MessagingException(ex.getMessage()); 1045 } 1046 pc.setCertRequest(request); 1047 msg.setContent(pc, pc.getContentType()); 1048 // let the PKCS10Content update some message headers 1049 pc.setHeaders(msg); 1050 1051 return msg; 1052 } 1053 1054 1055 private CertificateRequest createCertificateRequest() throws PKCSException { 1056 try { 1057 Name subject = new Name(); 1058 subject.addRDN(ObjectID.commonName, firstName + " " + lastName); 1059 subject.addRDN(ObjectID.emailAddress, from); 1060 CertificateRequest certRequest; 1061 certRequest = new CertificateRequest(signerCertificate.getPublicKey(), subject); 1062 certRequest.sign((AlgorithmID)AlgorithmID.dsaWithSHA256.clone(), signerPrivateKey); 1063 certRequest.verify(); 1064 return certRequest; 1065 } catch (Exception ex) { 1066 throw new PKCSException("Cannot create cert request: " + ex.getMessage()); 1067 } 1068 1069 } 1070 1071 /** 1072 * Creates a PKCS#10 message where the certificate request is transferred as attachment. 1073 * 1074 * @param session the mail session 1075 * 1076 * @return the PKCS#10 certificate request message 1077 * 1078 * @throws MessagingException if an error occurs when creating the message 1079 */ 1080 public Message createPKCS10MultiPartMessage(Session session) throws MessagingException { 1081 1082 MimeBodyPart mbp1 = new MimeBodyPart(); 1083 mbp1.setText("This is a test where the request message is included in the second part!\n\n"); 1084 // try to test an attachment 1085 // this demo attaches our homepage 1086 MimeBodyPart attachment = new MimeBodyPart(); 1087 //use new content types 1088 SMimeParameters.useNewContentTypes(true); 1089 PKCS10Content pc = new PKCS10Content(); 1090 CertificateRequest request = null; 1091 try { 1092 request = createCertificateRequest(); 1093 } catch (PKCSException ex) { 1094 throw new MessagingException(ex.getMessage()); 1095 } 1096 pc.setCertRequest(request); 1097 DataHandler pkcs10Handler = new DataHandler(pc, pc.getContentType()); 1098 attachment.setDataHandler(pkcs10Handler); 1099 attachment.setDisposition("attachment"); 1100 attachment.setFileName("smime.p10"); 1101 Multipart mp = new MimeMultipart(); 1102 mp.addBodyPart(mbp1); 1103 mp.addBodyPart(attachment); 1104 1105 Message msg = createMessage(session, "IAIK-S/MIME: Certificate Request multipart message"); 1106 msg.setContent(mp, mp.getContentType()); 1107 return msg; 1108 } 1109 1110 /** 1111 * Prints a dump of the given message to System.out. 1112 * 1113 * @param msg the message to be dumped to System.out 1114 * 1115 * @throws IOException if an I/O error occurs 1116 */ 1117 static void printMessage(Message msg) throws IOException { 1118 System.out.println("------------------------------------------------------------------"); 1119 System.out.println("Message dump: \n"); 1120 try { 1121 msg.writeTo(System.out); 1122 } catch (MessagingException ex) { 1123 throw new IOException(ex.getMessage()); 1124 } 1125 System.out.println("\n------------------------------------------------------------------"); 1126 } 1127 1128 1129 /** 1130 * The main method. 1131 */ 1132 public static void main(String[] argv) throws IOException { 1133 1134 DemoSMimeUtil.initDemos(); 1135 (new SMimeV3Demo()).start(); 1136 System.out.println("\nReady!"); 1137 DemoUtil.waitKey(); 1138 } 1139}