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