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/ecc/SMimeEccSuiteBDemo.java 18 12.02.25 17:59 Dbratko $ 029// $Revision: 18 $ 030// 031 032package demo.smime.ecc; 033 034import iaik.asn1.structures.AlgorithmID; 035import iaik.cms.CMSAlgorithmID; 036import iaik.smime.EncryptedContent; 037import iaik.smime.SMimeBodyPart; 038import iaik.smime.SMimeException; 039import iaik.smime.SMimeMultipart; 040import iaik.smime.SignedContent; 041import iaik.x509.X509Certificate; 042 043import java.io.ByteArrayInputStream; 044import java.io.ByteArrayOutputStream; 045import java.io.IOException; 046import java.security.NoSuchAlgorithmException; 047import java.security.PrivateKey; 048import java.util.Date; 049 050import jakarta.activation.DataHandler; 051import jakarta.activation.FileDataSource; 052import jakarta.mail.Message; 053import jakarta.mail.MessagingException; 054import jakarta.mail.Multipart; 055import jakarta.mail.Session; 056import jakarta.mail.internet.InternetAddress; 057import jakarta.mail.internet.MimeBodyPart; 058import jakarta.mail.internet.MimeMessage; 059 060import demo.DemoSMimeUtil; 061import demo.DemoUtil; 062import demo.cms.ecc.ECCDemoUtil; 063import demo.cms.ecc.keystore.CMSEccKeyStore; 064import demo.smime.DumpMessage; 065 066/** 067 * This class demonstrates the usage of the IAIK S/MIME implementation to create and 068 * parse ECDSA signed and/or ECDH based encrypted S/MIMEv3 messages according to 069 * RFC 5008 "Suite B in Secure/Multipurpose Internet Mail Extensions (S/MIME)". 070 * <br> 071 * The following algorithms are required by Suite B of the United States Security Agency 072 * (NSA) for use of ECC in S/MIME (see RFC 5008): 073 * <pre> 074 * Security Level 1 Security Level 2 075 * ---------------- ---------------- 076 * Message Digest: SHA-256 SHA-384 077 * Signature: ECDSA with P-256 ECDSA with P-384 078 * 079 * 080 * 081 * Security Level 1 Security Level 2 082 * ---------------- ---------------- 083 * Key Agreement: ECDH with P-256 ECDH with P-384 084 * Key Derivation: SHA-256 SHA-384 085 * Key Wrap: AES-128 Key Wrap AES-256 Key Wrap 086 * Content Encryption: AES-128 CBC AES-256 CBC 087 * </pre> 088 * <br> 089 * The key encryption algorithms used during ECDH are 090 * <code>dhSinglePass-stdDH-sha256kdf-scheme</code> for Security Level 1 and 091 * <code>dhSinglePass-stdDH-sha384kdf-scheme</code> for Security Level 2. 092 * <p> 093 * Any keys/certificates required for this demo are read from a keystore 094 * file "cmsecc.keystore" located in your current working directory. If 095 * the keystore file does not exist you can create it by running the 096 * {@link demo.cms.ecc.keystore.SetupCMSEccKeyStore SetupCMSEccKeyStore} 097 * program. 098 * <p> 099 * Additionally to <code>iaik_cms.jar</code> you also must have 100 * <code>iaik_jce_(full).jar</code> (IAIK-JCE, <a href = 101 * "https://sic.tech/products/core-crypto-toolkits/jca-jce/" target="_blank"> 102 * https://sic.tech/products/core-crypto-toolkits/jca-jce/</a>), 103 * and <code>iaik_eccelarate.jar</code> (IAIK-ECCelerate<sup><small>TM</small></sup>, <a href = 104 * "https://sic.tech/products/core-crypto-toolkits/eccelerate/" target="_blank"> 105 * https://sic.tech/products/core-crypto-toolkits/eccelerate/</a>) 106 * in your classpath. 107 * <p> 108 * To run this demo the following packages are required: 109 * <ul> 110 * <li> 111 * <code>iaik_cms.jar</code> 112 * </li> 113 * <li> 114 * <code>iaik_jce(_full).jar</code> (<a href="https://sic.tech/products/core-crypto-toolkits/jca-jce/" target="_blank">IAIK-JCE Core Crypto Library</a>). 115 * </li> 116 * <li> 117 * <code>iaik_eccelerate.jar</code> (<a href="https://sic.tech/products/core-crypto-toolkits/eccelerate/" target="_blank">IAIK ECC Library</a>). 118 * </li> 119 * <li> 120 * <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 121 * </li> 122 * <li> 123 * <a href="https://jakarta.ee/specifications/activation/" target="_blank">Jakarta Activation Framework</a> 124 * </li> 125 * </ul> 126 * 127 * @see demo.cms.ecc.keystore.SetupCMSEccKeyStore 128 * @see iaik.smime.SignedContent 129 * @see iaik.smime.EncryptedContent 130 */ 131public class SMimeEccSuiteBDemo { 132 133 // whether to print dump all generates test messages to System.out 134 final static boolean PRINT_MESSAGES = true; 135 136 String firstName = "John"; 137 String lastName = "SMime"; 138 String to = "smimetest@iaik.tugraz.at"; // email recipient 139 String from = "smimetest@iaik.tugraz.at"; // email sender 140 String host = "mailhost"; // name of the mailhost 141 142 // keys and certs for security level 1 demo (256 bit) 143 X509Certificate[] signerCertificates1_; // list of certificates to include in the S/MIME message 144 X509Certificate signerCertificate1_; // certificate of the signer/sender 145 X509Certificate recipientCertificate1_; // certificate of the recipient 146 X509Certificate encryptionCertOfSigner1_; // signer uses different certificate for encryption 147 PrivateKey signerPrivateKey1_; // private key of the signer/sender 148 PrivateKey recipientKey1_; // private key of recipient 149 150 // keys and certs for security level 2 demo (384 bit) 151 X509Certificate[] signerCertificates2_; // list of certificates to include in the S/MIME message 152 X509Certificate signerCertificate2_; // certificate of the signer/sender 153 X509Certificate recipientCertificate2_; // certificate of the recipient 154 X509Certificate encryptionCertOfSigner2_; // signer uses different certificate for encryption 155 PrivateKey signerPrivateKey2_; // private key of the signer/sender 156 PrivateKey recipientKey2_; // private key of recipient 157 158 /** 159 * Default constructor. Reads certificates and keys from the demo keystore. 160 */ 161 public SMimeEccSuiteBDemo() { 162 163 System.out.println(); 164 System.out.println("********************************************************************************************"); 165 System.out.println("* SMimeEccSuiteBDemo demo *"); 166 System.out.println("* (shows how to use NSA Suite B algorithms with ECDSA and ECDH *"); 167 System.out.println("* to sign and encrypt S/MIME messages) *"); 168 System.out.println("********************************************************************************************"); 169 System.out.println(); 170 171 // get keys and certificates for security level 1 demo from KeyStore 172 173 // signer 174 signerCertificates1_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_256_SIGN); 175 signerCertificate1_ = signerCertificates1_[0]; 176 signerPrivateKey1_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_256_SIGN); 177 // recipient 178 recipientCertificate1_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_256_CRYPT_1)[0]; 179 recipientKey1_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_256_CRYPT_1); 180 181 // encryption cert of signer 182 encryptionCertOfSigner1_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_256_CRYPT_2)[0]; 183 184 // get keys and certificates for security level 2 demo from KeyStore 185 186 // signer 187 signerCertificates2_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_384_SIGN); 188 signerCertificate2_ = signerCertificates2_[0]; 189 signerPrivateKey2_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_384_SIGN); 190 // recipient 191 recipientCertificate2_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_384_CRYPT_1)[0]; 192 recipientKey2_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_384_CRYPT_1); 193 // encryption cert of signer 194 encryptionCertOfSigner2_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_384_CRYPT_2)[0]; 195 196 } 197 198 /** 199 * Starts the demo. 200 * 201 * @throws IOException if an I/O related error occurs 202 */ 203 public void start() throws IOException { 204 205 // get the default Session 206 Session session = DemoSMimeUtil.getSession(); 207 208 try { 209 // Create a demo Multipart 210 MimeBodyPart mbp1 = new SMimeBodyPart(); 211 mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n"); 212 // attachment 213 MimeBodyPart attachment = new SMimeBodyPart(); 214 attachment.setDataHandler(new DataHandler(new FileDataSource("test.html"))); 215 attachment.setFileName("test.html"); 216 217 Multipart mp = new SMimeMultipart(); 218 mp.addBodyPart(mbp1); 219 mp.addBodyPart(attachment); 220 DataHandler multipart = new DataHandler(mp, mp.getContentType()); 221 222 Message msg; // the message to send 223 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream 224 ByteArrayInputStream bais; // we read from a stream 225 226 227 228 // Suite B Security Level 1 Signature: ECDSA with SHA-256 (ANSI X9.62) 229 230 // This is an explicitly signed message (ecdsa-sha256) 231 AlgorithmID hashAlgorithm = AlgorithmID.sha256; 232 AlgorithmID signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA256; 233 msg = createSignedMessage(session, 234 multipart, 235 false, 236 hashAlgorithm, 237 signatureAlgorithm, 238 signerPrivateKey1_, 239 signerCertificates1_, 240 encryptionCertOfSigner1_); 241 System.out.println("Suite B, Security Level 1: Creating explicitly signed message " + signatureAlgorithm.getName() + "..."); 242 baos.reset(); 243 msg.saveChanges(); 244 msg.writeTo(baos); 245 246 bais = new ByteArrayInputStream(baos.toByteArray()); 247 msg = new MimeMessage(session, bais); 248 if (PRINT_MESSAGES) { 249 printMessage(msg); 250 } 251 DumpMessage.dumpMsg(msg); 252 253 System.out.println("\n\n*****************************************\n\n"); 254 255 256 // This is an implicitly signed message (ecdsa-sha256) 257 msg = createSignedMessage(session, 258 multipart, 259 true, 260 hashAlgorithm, 261 signatureAlgorithm, 262 signerPrivateKey1_, 263 signerCertificates1_, 264 encryptionCertOfSigner1_); 265 System.out.println("Suite B, Security Level 1: Creating implicitly signed message " + signatureAlgorithm.getName() + "..."); 266 baos.reset(); 267 msg.saveChanges(); 268 msg.writeTo(baos); 269 270 bais = new ByteArrayInputStream(baos.toByteArray()); 271 msg = new MimeMessage(session, bais); 272 if (PRINT_MESSAGES) { 273 printMessage(msg); 274 } 275 DumpMessage.dumpMsg(msg); 276 277 System.out.println("\n\n*****************************************\n\n"); 278 279 280 // Suite B Security Level 2 Signature: ECDSA with SHA-384 (ANSI X9.62) 281 282 // This is an explicitly signed message (ecdsa-sha384) 283 hashAlgorithm = AlgorithmID.sha384; 284 signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA384; 285 msg = createSignedMessage(session, 286 multipart, 287 false, 288 hashAlgorithm, 289 signatureAlgorithm, 290 signerPrivateKey2_, 291 signerCertificates2_, 292 encryptionCertOfSigner2_); 293 System.out.println("Suite B, Security Level 2: Creating explicitly signed message " + signatureAlgorithm.getName() + "..."); 294 baos.reset(); 295 msg.saveChanges(); 296 msg.writeTo(baos); 297 bais = new ByteArrayInputStream(baos.toByteArray()); 298 msg = new MimeMessage(session, bais); 299 if (PRINT_MESSAGES) { 300 printMessage(msg); 301 } 302 DumpMessage.dumpMsg(msg); 303 304 System.out.println("\n\n*****************************************\n\n"); 305 306 307 // This is an implicitly signed message (ecdsa-sha384) 308 msg = createSignedMessage(session, 309 multipart, 310 true, 311 hashAlgorithm, 312 signatureAlgorithm, 313 signerPrivateKey2_, 314 signerCertificates2_, 315 encryptionCertOfSigner2_); 316 System.out.println("Suite B, Security Level 2: Creating implicitly signed message " + signatureAlgorithm.getName() + "..."); 317 baos.reset(); 318 msg.saveChanges(); 319 msg.writeTo(baos); 320 bais = new ByteArrayInputStream(baos.toByteArray()); 321 msg = new MimeMessage(session, bais); 322 if (PRINT_MESSAGES) { 323 printMessage(msg); 324 } 325 DumpMessage.dumpMsg(msg); 326 327 System.out.println("\n\n*****************************************\n\n"); 328 329 330 331 332 // Now create encrypted messages 333 334 // Suite B Security Level 1 Encryption: ECDH with P-256, AES-128 335 336 AlgorithmID contentEncAlg = AlgorithmID.aes128_CBC; 337 AlgorithmID keyEncAlg = CMSAlgorithmID.dhSinglePass_stdDH_sha256kdf_scheme; 338 AlgorithmID keyWrapAlg = CMSAlgorithmID.cms_aes128_wrap; 339 int contentEncKeyLength = 128; 340 int keyEncKeyLength = 128; 341 342 msg = createEncryptedMessage(session, 343 contentEncAlg, 344 contentEncKeyLength, 345 keyEncAlg, 346 keyWrapAlg, 347 keyEncKeyLength, 348 recipientCertificate1_, 349 encryptionCertOfSigner1_); 350 System.out.println("Suite B, Security Level 1: Creating encrypted message [ECDH P-256, AES-128]..."); 351 baos.reset(); 352 msg.saveChanges(); 353 msg.writeTo(baos); 354 355 bais = new ByteArrayInputStream(baos.toByteArray()); 356 msg = new MimeMessage(session, bais); 357 if (PRINT_MESSAGES) { 358 printMessage(msg); 359 } 360 DumpMessage dumpMsg = new DumpMessage(); 361 dumpMsg.setRecipientKey(recipientKey1_); 362 dumpMsg.dump(msg); 363 364 System.out.println("\n\n*****************************************\n\n"); 365 366 367 // Suite B Security Level 2 Encryption: ECDH with P-384, AES-256 368 369 contentEncAlg = AlgorithmID.aes256_CBC; 370 keyEncAlg = CMSAlgorithmID.dhSinglePass_stdDH_sha384kdf_scheme; 371 keyWrapAlg = CMSAlgorithmID.cms_aes256_wrap; 372 contentEncKeyLength = 256; 373 keyEncKeyLength = 256; 374 375 msg = createEncryptedMessage(session, 376 contentEncAlg, 377 contentEncKeyLength, 378 keyEncAlg, 379 keyWrapAlg, 380 keyEncKeyLength, 381 recipientCertificate2_, 382 encryptionCertOfSigner2_); 383 System.out.println("Suite B, Security Level 2: Creating encrypted message [ECDH P-384, AES-256]..."); 384 baos.reset(); 385 msg.saveChanges(); 386 msg.writeTo(baos); 387 bais = new ByteArrayInputStream(baos.toByteArray()); 388 msg = new MimeMessage(session, bais); 389 if (PRINT_MESSAGES) { 390 printMessage(msg); 391 } 392 dumpMsg.setRecipientKey(recipientKey2_); 393 dumpMsg.dump(msg); 394 395 System.out.println("\n\n*****************************************\n\n"); 396 397 398 399 400 // signed + encrypted 401 402 // Suite B Security Level 1: ECDSA with SHA-256; ECDH with P-256, AES-128 403 404 // Now create implicitly signed and encrypted message with attachment 405 hashAlgorithm = AlgorithmID.sha256; 406 signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA256; 407 contentEncAlg = AlgorithmID.aes128_CBC; 408 keyEncAlg = CMSAlgorithmID.dhSinglePass_stdDH_sha256kdf_scheme; 409 keyWrapAlg = CMSAlgorithmID.cms_aes128_wrap; 410 contentEncKeyLength = 128; 411 keyEncKeyLength = 128; 412 msg = createSignedAndEncryptedMessage(session, 413 multipart, 414 true, 415 hashAlgorithm, 416 signatureAlgorithm, 417 signerPrivateKey1_, 418 signerCertificates1_, 419 encryptionCertOfSigner1_, 420 contentEncAlg, 421 contentEncKeyLength, 422 keyEncAlg, 423 keyWrapAlg, 424 keyEncKeyLength, 425 recipientCertificate1_); 426 System.out.println("Suite B, Security Level 1: Creating implicitly signed " + signatureAlgorithm.getName() + " and encrypted message [ECDH P-256, AES-128]..."); 427 baos.reset(); 428 msg.saveChanges(); 429 msg.writeTo(baos); 430 431 bais = new ByteArrayInputStream(baos.toByteArray()); 432 msg = new MimeMessage(session, bais); 433 if (PRINT_MESSAGES) { 434 printMessage(msg); 435 } 436 dumpMsg.setRecipientKey(recipientKey1_); 437 dumpMsg.dump(msg); 438 439 System.out.println("\n\n*****************************************\n\n"); 440 441 // Now create a explicitly signed and encrypted message with attachment 442 msg = createSignedAndEncryptedMessage(session, 443 multipart, 444 false, 445 hashAlgorithm, 446 signatureAlgorithm, 447 signerPrivateKey1_, 448 signerCertificates1_, 449 encryptionCertOfSigner1_, 450 contentEncAlg, 451 contentEncKeyLength, 452 keyEncAlg, 453 keyWrapAlg, 454 keyEncKeyLength, 455 recipientCertificate1_); 456 System.out.println("Suite B, Security Level 1: Creating explicitly signed " + signatureAlgorithm.getName() + " and encrypted message [ECDH P-256, AES-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 System.out.println("\n\n*****************************************\n\n"); 467 468 469 // Suite B Security Level 2: ECDSA with SHA-384; ECDH with P-384, AES-256 470 471 // Now create implicitly signed and encrypted message with attachment 472 hashAlgorithm = AlgorithmID.sha384; 473 signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA384; 474 contentEncAlg = AlgorithmID.aes256_CBC; 475 keyEncAlg = CMSAlgorithmID.dhSinglePass_stdDH_sha384kdf_scheme; 476 keyWrapAlg = CMSAlgorithmID.cms_aes256_wrap; 477 contentEncKeyLength = 256; 478 keyEncKeyLength = 256; 479 msg = createSignedAndEncryptedMessage(session, 480 multipart, 481 true, 482 hashAlgorithm, 483 signatureAlgorithm, 484 signerPrivateKey2_, 485 signerCertificates2_, 486 encryptionCertOfSigner2_, 487 contentEncAlg, 488 contentEncKeyLength, 489 keyEncAlg, 490 keyWrapAlg, 491 keyEncKeyLength, 492 recipientCertificate2_); 493 System.out.println("Suite B, Security Level 1: Creating implicitly signed " + signatureAlgorithm.getName() + " and encrypted message [ECDH P-384, AES-256]..."); 494 baos.reset(); 495 msg.saveChanges(); 496 msg.writeTo(baos); 497 bais = new ByteArrayInputStream(baos.toByteArray()); 498 msg = new MimeMessage(session, bais); 499 if (PRINT_MESSAGES) { 500 printMessage(msg); 501 } 502 dumpMsg.setRecipientKey(recipientKey2_); 503 dumpMsg.dump(msg); 504 505 System.out.println("\n\n*****************************************\n\n"); 506 507 // Now create a explicitly signed and encrypted message with attachment 508 msg = createSignedAndEncryptedMessage(session, 509 multipart, 510 false, 511 hashAlgorithm, 512 signatureAlgorithm, 513 signerPrivateKey2_, 514 signerCertificates2_, 515 encryptionCertOfSigner2_, 516 contentEncAlg, 517 contentEncKeyLength, 518 keyEncAlg, 519 keyWrapAlg, 520 keyEncKeyLength, 521 recipientCertificate2_); 522 System.out.println("Suite B, Security Level 1: Creating explicitly signed " + signatureAlgorithm.getName() + " and encrypted message [ECDH P-384, AES-256]..."); 523 baos.reset(); 524 msg.saveChanges(); 525 msg.writeTo(baos); 526 bais = new ByteArrayInputStream(baos.toByteArray()); 527 msg = new MimeMessage(session, bais); 528 if (PRINT_MESSAGES) { 529 printMessage(msg); 530 } 531 DumpMessage.dumpMsg(msg); 532 System.out.println("\n\n*****************************************\n\n"); 533 534 535 } catch (Exception ex) { 536 ex.printStackTrace(); 537 throw new RuntimeException(ex.toString()); 538 } 539 540 System.out.println("OK!"); 541 542 } 543 544 /** 545 * Creates a MIME message container with the given subject for the given session. 546 * 547 * @param session the mail sesion 548 * @param subject the subject of the message 549 * 550 * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content) 551 * 552 * @throws MessagingException if the message cannot be created 553 */ 554 public Message createMessage(Session session, String subject) throws MessagingException { 555 MimeMessage msg = new MimeMessage(session); 556 msg.setFrom(new InternetAddress(from)); 557 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false)); 558 msg.setSentDate(new Date()); 559 msg.setSubject(subject); 560 return msg; 561 } 562 563 564 /** 565 * Creates a signed message. 566 * 567 * @param session the mail session 568 * @param dataHandler the content of the message to be signed 569 * @param implicit whether to use implicit (application/pkcs7-mime) or explicit 570 * (multipart/signed) signing 571 * @param hashAlgorithm the hash algorithm to be used 572 * @param signatureAlgorithm the signature algorithm to be used 573 * @param signerPrivateKey the private key of the signer 574 * @param signerCertificates the certificate chain of the signer 575 * @param encryptionCertOfSigner the encryption certificate of the signer 576 * (to be announced within the SignerInfo) 577 * 578 * @return the signed message 579 * 580 * @throws MessagingException if an error occurs when creating the message 581 */ 582 public Message createSignedMessage(Session session, 583 DataHandler dataHandler, 584 boolean implicit, 585 AlgorithmID hashAlgorithm, 586 AlgorithmID signatureAlgorithm, 587 PrivateKey signerPrivateKey, 588 X509Certificate[] signerCertificates, 589 X509Certificate encryptionCertOfSigner) 590 throws MessagingException { 591 592 String subject = null; 593 StringBuffer buf = new StringBuffer(); 594 595 if (implicit) { 596 subject = "IAIK-S/MIME: Implicitly Signed (" + signatureAlgorithm.getName() +")"; 597 buf.append("This message is implicitly signed with ! " + signatureAlgorithm.getName() + "\n"); 598 buf.append("You need an S/MIME aware mail client to view this message.\n"); 599 buf.append("\n\n"); 600 } else { 601 subject = "IAIK-S/MIME: Explicitly Signed (" + signatureAlgorithm.getName() +")"; 602 buf.append("This message is explicitly signed!\n"); 603 buf.append("Every mail client can view this message.\n"); 604 buf.append("Non S/MIME mail clients will show the signature as attachment.\n"); 605 buf.append("\n\n"); 606 } 607 608 Message msg = createMessage(session, subject); 609 610 SignedContent sc = new SignedContent(implicit); 611 if (dataHandler != null) { 612 sc.setDataHandler(dataHandler); 613 } else { 614 sc.setText(buf.toString()); 615 } 616 sc.setCertificates(signerCertificates); 617 618 AlgorithmID ecdsaSig = (AlgorithmID)signatureAlgorithm.clone(); 619 // CMS-ECDSA requires to encode the parameter field as NULL (see RFC 3278) 620 ecdsaSig.encodeAbsentParametersAsNull(true); 621 try { 622 sc.addSigner(signerPrivateKey, 623 signerCertificates[0], 624 (AlgorithmID)hashAlgorithm.clone(), 625 ecdsaSig, 626 encryptionCertOfSigner, 627 true); 628 } catch (NoSuchAlgorithmException ex) { 629 throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex); 630 } 631 632 msg.setContent(sc, sc.getContentType()); 633 // let the SignedContent update some message headers 634 sc.setHeaders(msg); 635 return msg; 636 } 637 638 /** 639 * Creates an encrypted message. 640 * 641 * @param session the mail session 642 * @param contentEA the content encryption algorithm to be used 643 * @param keyLength the length of the secret content encryption key to be created and used 644 * @param keyEA the key encryption algorithm to be used 645 * @param keyWrapAlg the key wrap algorithm to be used 646 * @param kekLength the length of the key encryption algorithm 647 * @param recipientCertificate the encryption certificate of the recipient 648 * @param encryptionCertOfSender the encryption certificate of the sender 649 * 650 * @return the encrypted message 651 * 652 * @throws MessagingException if an error occurs when creating the message 653 */ 654 public Message createEncryptedMessage(Session session, 655 AlgorithmID contentEA, 656 int keyLength, 657 AlgorithmID keyEA, 658 AlgorithmID keyWrapAlg, 659 int kekLength, 660 X509Certificate recipientCertificate, 661 X509Certificate encryptionCertOfSender) 662 throws MessagingException { 663 664 StringBuffer subject = new StringBuffer(); 665 subject.append("IAIK-S/MIME: Encrypted ["+contentEA.getName()); 666 if (keyLength > 0) { 667 subject.append("/"+keyLength); 668 } 669 subject.append("]"); 670 Message msg = createMessage(session, subject.toString()); 671 672 EncryptedContent ec = new EncryptedContent(); 673 674 StringBuffer buf = new StringBuffer(); 675 buf.append("This is the encrypted content!\n"); 676 buf.append("Content encryption algorithm: "+contentEA.getName()); 677 buf.append("\n\n"); 678 679 ec.setText(buf.toString()); 680 681 try { 682 ec.addRecipient(recipientCertificate, (AlgorithmID)keyEA.clone(), (AlgorithmID)keyWrapAlg.clone(), kekLength); 683 } catch (SMimeException ex) { 684 throw new MessagingException("Error adding ECDH recipient: " + ex.getMessage()); 685 } 686 // Sender want to be able to decrypt the message, too 687 try { 688 ec.addRecipient(encryptionCertOfSender, (AlgorithmID)keyEA.clone(), (AlgorithmID)keyWrapAlg.clone(), kekLength); 689 } catch (SMimeException ex) { 690 throw new MessagingException("Error adding ECDH recipient: " + ex.getMessage()); 691 } 692 try { 693 ec.setEncryptionAlgorithm((AlgorithmID)contentEA.clone(), keyLength); 694 } catch (NoSuchAlgorithmException ex) { 695 throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage()); 696 } 697 698 msg.setContent(ec, ec.getContentType()); 699 // let the EncryptedContent update some message headers 700 ec.setHeaders(msg); 701 702 return msg; 703 } 704 705 /** 706 * Creates a signed and encrypted message. 707 * 708 * @param session the mail session 709 * @param dataHandler the content of the message to be signed and encrypted 710 * @param implicit whether to use implicit (application/pkcs7-mime) or explicit 711 * (multipart/signed) signing 712 * @param hashAlgorithm the hash algorithm to be used 713 * @param signatureAlgorithm the signature algorithm to be used 714 * @param signerPrivateKey the private key of the signer 715 * @param signerCertificates the certificate chain of the signer 716 * @param encryptionCertOfSigner the encryption certificate of the signer 717 * (to be announced within the SignerInfo) 718 * @param contentEA the content encryption algorithm to be used 719 * @param keyLength the length of the secret content encryption key to be created and used 720 * @param keyEA the key encryption algorithm to be used 721 * @param keyWrapAlgorithm the key wrap algorithm to be used 722 * @param kekLength the length of the key encryption algorithm 723 * @param recipientCertificate the encryption certificate of the recipient 724 * 725 * @return the signed and encrypted message 726 * 727 * @throws MessagingException if an error occurs when creating the message 728 */ 729 public Message createSignedAndEncryptedMessage(Session session, 730 DataHandler dataHandler, 731 boolean implicit, 732 AlgorithmID hashAlgorithm, 733 AlgorithmID signatureAlgorithm, 734 PrivateKey signerPrivateKey, 735 X509Certificate[] signerCertificates, 736 X509Certificate encryptionCertOfSigner, 737 AlgorithmID contentEA, 738 int keyLength, 739 AlgorithmID keyEA, 740 AlgorithmID keyWrapAlgorithm, 741 int kekLength, 742 X509Certificate recipientCertificate) 743 throws MessagingException { 744 745 String subject = null; 746 String text = null; 747 if (implicit) { 748 subject = "IAIK-S/MIME: Implicitly Signed (" + signatureAlgorithm.getName() + ") and Encrypted (" + contentEA.getName() + ")"; 749 text = "This message is implicitly signed (" + signatureAlgorithm.getName() + ") and Encrypted (" + contentEA.getName() + ")!\n\n\n"; 750 } else { 751 subject = "IAIK-S/MIME: Explicitly Signed (" + signatureAlgorithm.getName() + ") and Encrypted (" + contentEA.getName() + ")"; 752 text = "This message is explicitly signed (" + signatureAlgorithm.getName() + ") and Encrypted (" + contentEA.getName() + ")!\n\n\n"; 753 } 754 Message msg = createMessage(session, subject); 755 756 SignedContent sc = new SignedContent(implicit); 757 if (dataHandler != null) { 758 sc.setDataHandler(dataHandler); 759 } else { 760 sc.setText(text); 761 } 762 sc.setCertificates(signerCertificates); 763 AlgorithmID ecdsaSig = (AlgorithmID)signatureAlgorithm.clone(); 764 // CMS-ECC requires that the parameters field is encoded as ASN.1 NULL object (see RFC 3278) 765 ecdsaSig.encodeAbsentParametersAsNull(true); 766 try { 767 sc.addSigner(signerPrivateKey, 768 signerCertificates[0], 769 (AlgorithmID)hashAlgorithm.clone(), 770 ecdsaSig, 771 encryptionCertOfSigner, 772 true); 773 } catch (NoSuchAlgorithmException ex) { 774 throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex); 775 } 776 777 EncryptedContent ec = new EncryptedContent(sc); 778 // encrypt for the recipient 779 try { 780 ec.addRecipient(recipientCertificate, (AlgorithmID)keyEA.clone(), (AlgorithmID)keyWrapAlgorithm.clone(), kekLength); 781 } catch (SMimeException ex) { 782 throw new MessagingException("Error adding ECDH recipient: " + ex.getMessage()); 783 } 784 try { 785 // I want to be able to decrypt the message, too 786 ec.addRecipient(encryptionCertOfSigner, (AlgorithmID)keyEA.clone(), (AlgorithmID)keyWrapAlgorithm.clone(), kekLength); 787 } catch (SMimeException ex) { 788 throw new MessagingException("Error adding ECDH recipient: " + ex.getMessage()); 789 } 790 // set the encryption algorithm 791 try { 792 ec.setEncryptionAlgorithm(contentEA, keyLength); 793 } catch (NoSuchAlgorithmException ex) { 794 throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage()); 795 } 796 msg.setContent(ec, ec.getContentType()); 797 // let the EncryptedContent update some message headers 798 ec.setHeaders(msg); 799 800 return msg; 801 } 802 803 804 /** 805 * Prints a dump of the given message to System.out. 806 * 807 * @param msg the message to be dumped to System.out 808 * 809 * @throws IOException if an I/O error occurs 810 */ 811 private static void printMessage(Message msg) throws IOException { 812 System.out.println("------------------------------------------------------------------"); 813 System.out.println("Message dump: \n"); 814 try { 815 msg.writeTo(System.out); 816 } catch (MessagingException ex) { 817 throw new IOException(ex.getMessage()); 818 } 819 System.out.println("\n------------------------------------------------------------------"); 820 } 821 822 823 /** 824 * The main method. 825 */ 826 public static void main(String[] argv) throws Exception { 827 828 DemoSMimeUtil.initDemos(); 829 // add ECC provider 830 ECCDemoUtil.installIaikEccProvider(); 831 (new SMimeEccSuiteBDemo()).start(); 832 System.out.println("\nReady!"); 833 DemoUtil.waitKey(); 834 } 835}