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/SMimeEnvelopedDemoAEAD.java 3 12.02.25 17:58 Dbratko $ 029// $Revision: 3 $ 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; 050 051import demo.DemoSMimeUtil; 052import demo.DemoUtil; 053import demo.keystore.CMSKeyStore; 054import demo.smime.DumpMessage; 055import iaik.asn1.structures.AlgorithmID; 056import iaik.smime.AuthEncryptedContent; 057import iaik.smime.EncryptedContent; 058import iaik.smime.SMimeBodyPart; 059import iaik.smime.SMimeMultipart; 060import iaik.smime.SignedContent; 061import iaik.x509.X509Certificate; 062 063/** 064 * This class demonstrates the usage of the IAIK S/MIME implementation. It shows how to create 065 * signed and/or encrypted S/MIME messages and how to parse them and verify the signatures 066 * and decrypt the content, respectively. This demos creates encrypted messages using an AEAD 067 * cipher mode (like GCM). Although CMS and S/MIME generally use AEAD cipher modes with the 068 * <code>AuthEnvelopedData</code> content type, it is technically possible to also use 069 * AEAD cipher modes with the <code>EnvelopedData</code> content type (when appending the mac value 070 * to the cipher text). This demo shows how to encrypt S/MIME messages with AEAD cipher modes when 071 * using the CMS <code>EnvelopedData</code> type. 072 073 * <p> 074 * To run this demo the following packages are required: 075 * <ul> 076 * <li> 077 * <code>iaik_cms.jar</code> (IAIK-CMS/SMIME) 078 * </li> 079 * <li> 080 * <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>). 081 * </li> 082 * <li> 083 * <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 084 * </li> 085 * <li> 086 * <a href="https://jakarta.ee/specifications/activation/" target="_blank">Jakarta Activation Framework</a> 087 * </li> 088 * </ul> 089 * 090 * This demo requires Java 7 or later. 091 * 092 */ 093public class SMimeEnvelopedDemoAEAD { 094 095 // whether to print dump all generates test messages to System.out 096 final static boolean PRINT_MESSAGES = false; 097 098 099 String firstName_ = "John"; 100 String lastName_ = "SMime"; 101 String to_ = "smimetest@iaik.tugraz.at"; // email recipient 102 String from_ = "smimetest@iaik.tugraz.at"; // email sender 103 String host_ = "mailhost"; // name of the mailhost 104 105 X509Certificate[] signerCertificates_; // list of certificates to include in the S/MIME message 106 X509Certificate signerCertificate_; // certificate of the signer/sender 107 PrivateKey signerPrivateKey_; // private key of the signer/sender 108 109 X509Certificate senderCryptCertificate_; // the encryption certificate of the signer/sender 110 111 X509Certificate rsaRecipientCertificate_; // RSA encryption cert and key of a recipient 112 113 /** 114 * Default constructor. Reads certificates and keys from the demo keystore. 115 */ 116 public SMimeEnvelopedDemoAEAD() { 117 118 System.out.println(); 119 System.out.println("********************************************************************************************"); 120 System.out.println("* SMimeEnvelopedDemoAEAD demo *"); 121 System.out.println("* (shows how to create and parse encrypted (enveloped) S/MIME messages with AEAD ciphers) *"); 122 System.out.println("********************************************************************************************"); 123 System.out.println(); 124 125 // get the certificates from the KeyStore 126 signerCertificates_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1); 127 signerPrivateKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1); 128 signerCertificate_ = signerCertificates_[0]; 129 senderCryptCertificate_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0]; 130 131 rsaRecipientCertificate_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0]; 132 133 } 134 135 /** 136 * Starts the demo. 137 * 138 * @throws IOException if an I/O related error occurs 139 */ 140 public void start() throws IOException { 141 142 // get the default Session 143 Session session = DemoSMimeUtil.getSession(); 144 145 try { 146 // Create a demo Multipart 147 MimeBodyPart mbp1 = new SMimeBodyPart(); 148 mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n"); 149 // attachment 150 MimeBodyPart attachment = new SMimeBodyPart(); 151 attachment.setDataHandler(new DataHandler(new FileDataSource("test.html"))); 152 attachment.setFileName("test.html"); 153 154 Multipart mp = new SMimeMultipart(); 155 mp.addBodyPart(mbp1); 156 mp.addBodyPart(attachment); 157 DataHandler multipart = new DataHandler(mp, mp.getContentType()); 158 159 Message msg; // the message to send 160 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream 161 ByteArrayInputStream bais; // we read from a stream 162 163 164 // Now create encrypted messages with different content encryption algorithms 165 if (DemoUtil.getIaikProviderVersion() >= 5.62) { 166 167 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), 128); 168 System.out.println("creating encrypted message [AES-GCM/128]..."); 169 baos.reset(); 170 msg.saveChanges(); 171 msg.writeTo(baos); 172 bais = new ByteArrayInputStream(baos.toByteArray()); 173 msg = new MimeMessage(session, bais); 174 if (PRINT_MESSAGES) { 175 printMessage(msg); 176 } 177 DumpMessage.dumpEncryptedMessage(msg); 178 179 System.out.println("\n\n*****************************************\n\n"); 180 181 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_GCM.clone(), 192); 182 System.out.println("creating encrypted message [AES-GCM/192]..."); 183 baos.reset(); 184 msg.saveChanges(); 185 msg.writeTo(baos); 186 bais = new ByteArrayInputStream(baos.toByteArray()); 187 msg = new MimeMessage(session, bais); 188 if (PRINT_MESSAGES) { 189 printMessage(msg); 190 } 191 DumpMessage.dumpEncryptedMessage(msg); 192 193 System.out.println("\n\n*****************************************\n\n"); 194 195 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_GCM.clone(), 256); 196 System.out.println("creating encrypted message [AES-GCM/256]..."); 197 baos.reset(); 198 msg.saveChanges(); 199 msg.writeTo(baos); 200 bais = new ByteArrayInputStream(baos.toByteArray()); 201 msg = new MimeMessage(session, bais); 202 if (PRINT_MESSAGES) { 203 printMessage(msg); 204 } 205 DumpMessage.dumpEncryptedMessage(msg); 206 207 System.out.println("\n\n*****************************************\n\n"); 208 209 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), 128); 210 System.out.println("creating encrypted message [AES-CCM/128]..."); 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.dumpEncryptedMessage(msg); 220 221 System.out.println("\n\n*****************************************\n\n"); 222 223 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CCM.clone(), 192); 224 System.out.println("creating encrypted message [AES-CCM/192]..."); 225 baos.reset(); 226 msg.saveChanges(); 227 msg.writeTo(baos); 228 bais = new ByteArrayInputStream(baos.toByteArray()); 229 msg = new MimeMessage(session, bais); 230 if (PRINT_MESSAGES) { 231 printMessage(msg); 232 } 233 DumpMessage.dumpEncryptedMessage(msg); 234 235 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CCM.clone(), 256); 236 System.out.println("creating encrypted message [AES-CCM/256]..."); 237 baos.reset(); 238 msg.saveChanges(); 239 msg.writeTo(baos); 240 bais = new ByteArrayInputStream(baos.toByteArray()); 241 msg = new MimeMessage(session, bais); 242 if (PRINT_MESSAGES) { 243 printMessage(msg); 244 } 245 DumpMessage.dumpEncryptedMessage(msg); 246 247 System.out.println("\n\n*****************************************\n\n"); 248 249 msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), 256); 250 System.out.println("creating encrypted message [ChaChaPoly1305]..."); 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.dumpEncryptedMessage(msg); 260 261 System.out.println("\n\n*****************************************\n\n"); 262 263 // Create an implicitly signed and encrypted message with attachment 264 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), 128, multipart, true, true); 265 System.out.println("creating implicitly signed and encrypted message [AES-GCM/128]..."); 266 baos.reset(); 267 msg.saveChanges(); 268 msg.writeTo(baos); 269 bais = new ByteArrayInputStream(baos.toByteArray()); 270 msg = new MimeMessage(session, bais); 271 if (PRINT_MESSAGES) { 272 printMessage(msg); 273 } 274 DumpMessage.dumpEncryptedMessage(msg); 275 276 System.out.println("\n\n*****************************************\n\n"); 277 278 // Create an explicitly signed and encrypted message with attachment 279 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), 128, multipart, true, true); 280 System.out.println("creating explicitly signed and encrypted message [AES-GCM/128]..."); 281 baos.reset(); 282 msg.saveChanges(); 283 msg.writeTo(baos); 284 bais = new ByteArrayInputStream(baos.toByteArray()); 285 msg = new MimeMessage(session, bais); 286 if (PRINT_MESSAGES) { 287 printMessage(msg); 288 } 289 DumpMessage.dumpEncryptedMessage(msg); 290 291 System.out.println("\n\n*****************************************\n\n"); 292 293 // Create an implicitly signed and encrypted message with attachment 294 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_GCM.clone(), 192, multipart, true, true); 295 System.out.println("creating implicitly signed and encrypted message [AES-GCM/192]..."); 296 baos.reset(); 297 msg.saveChanges(); 298 msg.writeTo(baos); 299 bais = new ByteArrayInputStream(baos.toByteArray()); 300 msg = new MimeMessage(session, bais); 301 if (PRINT_MESSAGES) { 302 printMessage(msg); 303 } 304 DumpMessage.dumpEncryptedMessage(msg); 305 306 System.out.println("\n\n*****************************************\n\n"); 307 308 // Create an explicitly signed and encrypted message with attachment 309 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_GCM.clone(), 192, multipart, true, true); 310 System.out.println("creating explicitly signed and encrypted message [AES-GCM/192]..."); 311 baos.reset(); 312 msg.saveChanges(); 313 msg.writeTo(baos); 314 bais = new ByteArrayInputStream(baos.toByteArray()); 315 msg = new MimeMessage(session, bais); 316 if (PRINT_MESSAGES) { 317 printMessage(msg); 318 } 319 DumpMessage.dumpEncryptedMessage(msg); 320 321 System.out.println("\n\n*****************************************\n\n"); 322 323 // Create an implicitly signed and encrypted message with attachment 324 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_GCM.clone(), 256, multipart, true, true); 325 System.out.println("creating implicitly signed and encrypted message [AES-GCM/256]..."); 326 baos.reset(); 327 msg.saveChanges(); 328 msg.writeTo(baos); 329 bais = new ByteArrayInputStream(baos.toByteArray()); 330 msg = new MimeMessage(session, bais); 331 if (PRINT_MESSAGES) { 332 printMessage(msg); 333 } 334 DumpMessage.dumpEncryptedMessage(msg); 335 336 System.out.println("\n\n*****************************************\n\n"); 337 338 // Create an explicitly signed and encrypted message with attachment 339 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_GCM.clone(), 256, multipart, true, true); 340 System.out.println("creating explicitly signed and encrypted message [AES-GCM/256]..."); 341 baos.reset(); 342 msg.saveChanges(); 343 msg.writeTo(baos); 344 bais = new ByteArrayInputStream(baos.toByteArray()); 345 msg = new MimeMessage(session, bais); 346 if (PRINT_MESSAGES) { 347 printMessage(msg); 348 } 349 DumpMessage.dumpEncryptedMessage(msg); 350 351 System.out.println("\n\n*****************************************\n\n"); 352 353 354 // Create an implicitly signed and encrypted message with attachment 355 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), 128, multipart, true, true); 356 System.out.println("creating implicitly signed and encrypted message [AES-CCM/128]..."); 357 baos.reset(); 358 msg.saveChanges(); 359 msg.writeTo(baos); 360 bais = new ByteArrayInputStream(baos.toByteArray()); 361 msg = new MimeMessage(session, bais); 362 if (PRINT_MESSAGES) { 363 printMessage(msg); 364 } 365 DumpMessage.dumpEncryptedMessage(msg); 366 367 System.out.println("\n\n*****************************************\n\n"); 368 369 // Create an explicitly signed and encrypted message with attachment 370 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), 128, multipart, true, true); 371 System.out.println("creating explicitly signed and encrypted message [AES-CCM/128]..."); 372 baos.reset(); 373 msg.saveChanges(); 374 msg.writeTo(baos); 375 bais = new ByteArrayInputStream(baos.toByteArray()); 376 msg = new MimeMessage(session, bais); 377 if (PRINT_MESSAGES) { 378 printMessage(msg); 379 } 380 DumpMessage.dumpEncryptedMessage(msg); 381 382 System.out.println("\n\n*****************************************\n\n"); 383 384 // Create an implicitly signed and encrypted message with attachment 385 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CCM.clone(), 192, multipart, true, true); 386 System.out.println("creating implicitly signed and encrypted message [AES-CCM/192]..."); 387 baos.reset(); 388 msg.saveChanges(); 389 msg.writeTo(baos); 390 bais = new ByteArrayInputStream(baos.toByteArray()); 391 msg = new MimeMessage(session, bais); 392 if (PRINT_MESSAGES) { 393 printMessage(msg); 394 } 395 DumpMessage.dumpEncryptedMessage(msg); 396 397 System.out.println("\n\n*****************************************\n\n"); 398 399 // Create an explicitly signed and encrypted message with attachment 400 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CCM.clone(), 192, multipart, true, true); 401 System.out.println("creating explicitly signed and encrypted message [AES-CCM/192]..."); 402 baos.reset(); 403 msg.saveChanges(); 404 msg.writeTo(baos); 405 bais = new ByteArrayInputStream(baos.toByteArray()); 406 msg = new MimeMessage(session, bais); 407 if (PRINT_MESSAGES) { 408 printMessage(msg); 409 } 410 DumpMessage.dumpEncryptedMessage(msg); 411 412 System.out.println("\n\n*****************************************\n\n"); 413 414 // Create an implicitly signed and encrypted message with attachment 415 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CCM.clone(), 256, multipart, true, true); 416 System.out.println("creating implicitly signed and encrypted message [AES-CCM/256]..."); 417 baos.reset(); 418 msg.saveChanges(); 419 msg.writeTo(baos); 420 bais = new ByteArrayInputStream(baos.toByteArray()); 421 msg = new MimeMessage(session, bais); 422 if (PRINT_MESSAGES) { 423 printMessage(msg); 424 } 425 DumpMessage.dumpEncryptedMessage(msg); 426 427 System.out.println("\n\n*****************************************\n\n"); 428 429 // Create an explicitly signed and encrypted message with attachment 430 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CCM.clone(), 256, multipart, true, true); 431 System.out.println("creating explicitly signed and encrypted message [AES-CCM/256]..."); 432 baos.reset(); 433 msg.saveChanges(); 434 msg.writeTo(baos); 435 bais = new ByteArrayInputStream(baos.toByteArray()); 436 msg = new MimeMessage(session, bais); 437 if (PRINT_MESSAGES) { 438 printMessage(msg); 439 } 440 DumpMessage.dumpEncryptedMessage(msg); 441 442 System.out.println("\n\n*****************************************\n\n"); 443 444 // Create an implicitly signed and encrypted message with attachment 445 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), 256, multipart, true, true); 446 System.out.println("creating implicitly signed and encrypted message [ChaCha20Poly1305]..."); 447 baos.reset(); 448 msg.saveChanges(); 449 msg.writeTo(baos); 450 bais = new ByteArrayInputStream(baos.toByteArray()); 451 msg = new MimeMessage(session, bais); 452 if (PRINT_MESSAGES) { 453 printMessage(msg); 454 } 455 DumpMessage.dumpEncryptedMessage(msg); 456 457 System.out.println("\n\n*****************************************\n\n"); 458 459 // Create an explicitly signed and encrypted message with attachment 460 msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), 256, multipart, true, true); 461 System.out.println("creating explicitly signed and encrypted message [ChaCha20Poly1305]..."); 462 baos.reset(); 463 msg.saveChanges(); 464 msg.writeTo(baos); 465 bais = new ByteArrayInputStream(baos.toByteArray()); 466 msg = new MimeMessage(session, bais); 467 if (PRINT_MESSAGES) { 468 printMessage(msg); 469 } 470 DumpMessage.dumpEncryptedMessage(msg); 471 472 System.out.println("\n\n*****************************************\n\n"); 473 474 } 475 476 477 478 } catch (Exception ex) { 479 ex.printStackTrace(); 480 throw new RuntimeException(ex.toString()); 481 } 482 } 483 484 /** 485 * Creates a MIME message container with the given subject for the given session. 486 * 487 * @param session the mail sesion 488 * @param subject the subject of the message 489 * 490 * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content) 491 * 492 * @throws MessagingException if the message cannot be created 493 */ 494 public Message createMessage(Session session, String subject) throws MessagingException { 495 MimeMessage msg = new MimeMessage(session); 496 msg.setFrom(new InternetAddress(from_)); 497 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to_, false)); 498 msg.setSentDate(new Date()); 499 msg.setSubject(subject); 500 return msg; 501 } 502 503 /** 504 * Creates a simple plain (neither signed nor encrypted) message. 505 * 506 * @param session the mail session 507 * @param dataHandler the content of the message 508 * 509 * @return the plain message 510 * 511 * @throws MessagingException if an error occurs when creating the message 512 */ 513 public Message createPlainMessage(Session session, DataHandler dataHandler) throws MessagingException { 514 515 Message msg = createMessage(session, "IAIK-S/MIME: Plain message"); 516 if (dataHandler != null) { 517 msg.setDataHandler(dataHandler); 518 } else { 519 msg.setText("This is a plain message!\nIt is wether signed nor encrypted!\n"); 520 } 521 return msg; 522 } 523 524 /** 525 * Creates a signed and encrypted message. 526 * 527 * @param session the mail session 528 * @param contentEA the content encryption algorithm to be used 529 * @param keyLength the length of the secret content encryption key to be created and used 530 * @param dataHandler the content of the message to be signed and encrypted 531 * @param implicit whether to use implicit (application/pkcs7-mime) or explicit 532 * (multipart/signed) signing 533 * @param authEncrypt whether to create an encrypted message 534 * 535 * @return the signed and encrypted message 536 * 537 * @throws MessagingException if an error occurs when creating the message 538 */ 539 public Message createSignedAndEncryptedMessage(Session session, 540 AlgorithmID contentEA, int keyLength, 541 DataHandler dataHandler, boolean implicit, boolean authEncrypt) 542 throws MessagingException { 543 544 String subject = null; 545 String text = null; 546 if (implicit) { 547 subject = "IAIK-S/MIME: Implicitly signed and " + (authEncrypt ? "authenticated " : "") + "encrypted"; 548 text = "This message is implicitly signed and " + (authEncrypt ? "authenticated " : "") + "encrypted!\n\n\n"; 549 } else { 550 subject = "IAIK-S/MIME: explicitly signed and " + (authEncrypt ? "authenticated " : "") + " encrypted"; 551 text = "This message is explicitly signed and " + (authEncrypt ? "authenticated " : "") + " encrypted!\n\n\n"; 552 } 553 Message msg = createMessage(session, subject); 554 555 SignedContent sc = new SignedContent(implicit); 556 if (dataHandler != null) { 557 sc.setDataHandler(dataHandler); 558 } else { 559 sc.setText(text); 560 } 561 sc.setCertificates(signerCertificates_); 562 try { 563 sc.addSigner(signerPrivateKey_, 564 signerCertificate_, 565 (AlgorithmID)AlgorithmID.sha256.clone(), 566 (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 567 } catch (NoSuchAlgorithmException ex) { 568 throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex); 569 } 570 571 EncryptedContent ec = null; 572 if (authEncrypt) { 573 ec = new AuthEncryptedContent(sc); 574 } else { 575 ec = new EncryptedContent(sc); 576 } 577 578 579 AlgorithmID algorithm = (AlgorithmID)contentEA.clone(); 580 581 // sender wants to be able to decrypt the message 582 ec.addRecipient(senderCryptCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 583 584 // add RSA recipient 585 ec.addRecipient(rsaRecipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 586 // set the encryption algorithm 587 try { 588 ec.setEncryptionAlgorithm(algorithm, keyLength); 589 } catch (NoSuchAlgorithmException ex) { 590 throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage()); 591 } 592 msg.setContent(ec, ec.getContentType()); 593 // let the EncryptedContent update some message headers 594 ec.setHeaders(msg); 595 596 return msg; 597 } 598 599 /** 600 * Creates a signed message. 601 * 602 * @param session the mail session 603 * @param dataHandler the content of the message to be signed 604 * @param implicit whether to use implicit (application/pkcs7-mime) or explicit 605 * (multipart/signed) signing 606 * @param digestAlgorithm the digest algorithm to be used 607 * @param signatureAlgorithm the signature algorithm to be used 608 * 609 * @return the signed message 610 * 611 * @throws MessagingException if an error occurs when creating the message 612 */ 613 public Message createSignedMessage(Session session, 614 DataHandler dataHandler, 615 boolean implicit, 616 AlgorithmID digestAlgorithm, 617 AlgorithmID signatureAlgorithm) 618 throws MessagingException { 619 620 String subject = null; 621 StringBuffer buf = new StringBuffer(); 622 623 if (implicit) { 624 subject = "IAIK-S/MIME: Implicitly Signed"; 625 buf.append("This message is implicitly signed!\n"); 626 buf.append("You need an S/MIME aware mail client to view this message.\n"); 627 buf.append("\n\n"); 628 } else { 629 subject = "IAIK-S/MIME: Explicitly Signed"; 630 buf.append("This message is explicitly signed!\n"); 631 buf.append("Every mail client can view this message.\n"); 632 buf.append("Non S/MIME mail clients will show the signature as attachment.\n"); 633 buf.append("\n\n"); 634 } 635 636 Message msg = createMessage(session, subject); 637 638 SignedContent sc = new SignedContent(implicit); 639 if (dataHandler != null) { 640 sc.setDataHandler(dataHandler); 641 } else { 642 sc.setText(buf.toString()); 643 } 644 sc.setCertificates(signerCertificates_); 645 646 try { 647 sc.addSigner(signerPrivateKey_, 648 signerCertificate_, 649 (AlgorithmID)digestAlgorithm.clone(), 650 (AlgorithmID)signatureAlgorithm.clone()); 651 } catch (NoSuchAlgorithmException ex) { 652 throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex); 653 } 654 655 msg.setContent(sc, sc.getContentType()); 656 // let the SignedContent update some message headers 657 sc.setHeaders(msg); 658 return msg; 659 } 660 661 /** 662 * Creates an encrypted message. 663 * 664 * @param session the mail session 665 * @param contentEA the content encryption algorithm to be used 666 * @param keyLength the length of the secret content encryption key to be created and used 667 * 668 * @return the encrypted message 669 * 670 * @throws MessagingException if an error occurs when creating the message 671 */ 672 public Message createEncryptedMessage(Session session, AlgorithmID contentEA, int keyLength) 673 throws MessagingException { 674 675 AlgorithmID algorithm = (AlgorithmID)contentEA.clone(); 676 677 StringBuffer subject = new StringBuffer(); 678 subject.append("IAIK-S/MIME: Encrypted ["+algorithm.getName()); 679 if (keyLength > 0) { 680 subject.append("/"+keyLength); 681 } 682 subject.append("]"); 683 Message msg = createMessage(session, subject.toString()); 684 685 EncryptedContent ec = new EncryptedContent(); 686 687 StringBuffer buf = new StringBuffer(); 688 buf.append("This is the encrypted content!\n"); 689 buf.append("Content encryption algorithm: "+algorithm.getName()); 690 buf.append("\n\n"); 691 692 ec.setText(buf.toString()); 693 694 // sender wants to be able to decrypt the message 695 ec.addRecipient(senderCryptCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 696 697 // add RSA recipient 698 ec.addRecipient(rsaRecipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 699 try { 700 ec.setEncryptionAlgorithm(algorithm, keyLength); 701 } catch (NoSuchAlgorithmException ex) { 702 throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage()); 703 } 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 * Prints a dump of the given message to System.out. 715 * 716 * @param msg the message to be dumped to System.out 717 * 718 * @throws IOException if an I/O error occurs 719 */ 720 static void printMessage(Message msg) throws IOException { 721 System.out.println("------------------------------------------------------------------"); 722 System.out.println("Message dump: \n"); 723 try { 724 msg.writeTo(System.out); 725 } catch (MessagingException ex) { 726 throw new IOException(ex.getMessage()); 727 } 728 System.out.println("\n------------------------------------------------------------------"); 729 } 730 731 /** 732 * The main method. 733 */ 734 public static void main(String[] argv) throws IOException { 735 String jdkVersion = (String) System.getProperty("java.version"); 736 if (jdkVersion.compareTo("1.7") >= 0) { 737 DemoSMimeUtil.initDemos(); 738 (new SMimeEnvelopedDemoAEAD()).start(); 739 System.out.println("\nReady!"); 740 DemoUtil.waitKey(); 741 } else { 742 System.err.println("This demo requires Java 7 or later!"); 743 } 744 } 745}