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/SMimeEccDemo.java 29 12.02.25 17:59 Dbratko $ 059 // $Revision: 29 $ 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 098 * ECDSA (with SHA1, SHA224, SHA256, SHA384, SHA512, RIPEMD160) signed and/or ECDH based 099 * encrypted S/MIMEv3 messages and how to parse them and verify the signatures 100 * and decrypt the content, respectively. 101 * <p> 102 * Any keys/certificates required for this demo are read from a keystore 103 * file "cmsecc.keystore" located in your current working directory. If 104 * the keystore file does not exist you can create it by running the 105 * {@link demo.cms.ecc.keystore.SetupCMSEccKeyStore SetupCMSEccKeyStore} 106 * program. 107 * <p> 108 * Additionally to <code>iaik_cms.jar</code> you also must have 109 * <code>iaik_jce_(full).jar</code> (IAIK-JCE, <a href = 110 * "https://sic.tech/products/core-crypto-toolkits/jca-jce/" target="_blank"> 111 * https://sic.tech/products/core-crypto-toolkits/jca-jce/</a>), 112 * and <code>iaik_eccelarate.jar</code> (IAIK-ECCelerate<sup><small>TM</small></sup>, <a href = 113 * "https://sic.tech/products/core-crypto-toolkits/eccelerate/" target="_blank"> 114 * https://sic.tech/products/core-crypto-toolkits/eccelerate/</a>) 115 * in your classpath. 116 * <p> 117 * To run this demo the following packages are required: 118 * <ul> 119 * <li> 120 * <code>iaik_cms.jar</code> 121 * </li> 122 * <li> 123 * <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>). 124 * </li> 125 * <li> 126 * <code>iaik_eccelerate.jar</code> (<a href="https://sic.tech/products/core-crypto-toolkits/eccelerate/" target="_blank">IAIK ECC Library</a>). 127 * </li> 128 * <li> 129 * <code>mail.jar</code> (<a href="http://www.oracle.com/technetwork/java/javamail/index.html" target="_blank">JavaMail API</a>). 130 * </li> 131 * <li> 132 * <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). 133 * </li> 134 * </ul> 135 * 136 * @see demo.cms.ecc.keystore.SetupCMSEccKeyStore 137 * @see iaik.smime.SignedContent 138 * @see iaik.smime.EncryptedContent 139 */ 140 public class SMimeEccDemo { 141 142 // whether to print dump all generates test messages to System.out 143 final static boolean PRINT_MESSAGES = false; 144 145 String firstName = "John"; 146 String lastName = "SMime"; 147 String to = "smimetest@iaik.tugraz.at"; // email recipient 148 String from = "smimetest@iaik.tugraz.at"; // email sender 149 String host = "mailhost"; // name of the mailhost 150 151 X509Certificate[] signerCertificates; // list of certificates to include in the S/MIME message 152 X509Certificate recipientCertificate; // certificate of the recipient 153 X509Certificate signerCertificate; // certificate of the signer/sender 154 X509Certificate encryptionCertOfSigner; // signer uses different certificate for encryption 155 // we use the same signer key for all demos here; in practice you should use a curve 156 // matching the security of the hash algorithm used by the signature algorithm 157 PrivateKey signerPrivateKey; // private key of the signer/sender 158 159 160 161 /** 162 * Default constructor. Reads certificates and keys from the demo keystore. 163 */ 164 public SMimeEccDemo() { 165 166 System.out.println(); 167 System.out.println("********************************************************************************************"); 168 System.out.println("* SMimeEccDemo demo *"); 169 System.out.println("* (shows how to create and parse (verify, decrypt) signed and encrypted S/MIMEv3 messages *"); 170 System.out.println("* using ECDSA for signing and ECDH for key agreement) *"); 171 System.out.println("********************************************************************************************"); 172 System.out.println(); 173 174 // get the certificates from the KeyStore 175 signerCertificates = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_256_SIGN); 176 signerCertificate = signerCertificates[0]; 177 signerPrivateKey = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_256_SIGN); 178 179 180 // recipient 181 recipientCertificate = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_256_CRYPT_1)[0]; 182 PrivateKey recipientKey = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_256_CRYPT_1); 183 184 // encryption cert of signer (in practice we will not use different key lenghts for recipients) 185 encryptionCertOfSigner = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_256_CRYPT_2)[0]; 186 } 187 188 /** 189 * Starts the demo. 190 * 191 * @throws IOException if an I/O related error occurs 192 */ 193 public void start() throws IOException { 194 195 // get the default Session 196 Session session = DemoSMimeUtil.getSession(); 197 198 try { 199 // Create a demo Multipart 200 MimeBodyPart mbp1 = new SMimeBodyPart(); 201 mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n"); 202 // attachment 203 MimeBodyPart attachment = new SMimeBodyPart(); 204 attachment.setDataHandler(new DataHandler(new FileDataSource("test.html"))); 205 attachment.setFileName("test.html"); 206 207 Multipart mp = new SMimeMultipart(); 208 mp.addBodyPart(mbp1); 209 mp.addBodyPart(attachment); 210 DataHandler multipart = new DataHandler(mp, mp.getContentType()); 211 212 Message msg; // the message to send 213 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream 214 ByteArrayInputStream bais; // we read from a stream 215 216 // ECDSA with SHA-1 (ANSI X9.62) 217 218 // This is an explicitly signed message (ecdsa-sha1) 219 AlgorithmID hashAlgorithm = AlgorithmID.sha1; 220 AlgorithmID signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA1; 221 msg = createSignedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm); 222 System.out.println("creating explicitly signed message " + signatureAlgorithm.getName() + "..."); 223 baos.reset(); 224 msg.saveChanges(); 225 msg.writeTo(baos); 226 227 bais = new ByteArrayInputStream(baos.toByteArray()); 228 msg = new MimeMessage(session, bais); 229 if (PRINT_MESSAGES) { 230 printMessage(msg); 231 } 232 DumpMessage.dumpMsg(msg); 233 234 System.out.println("\n\n*****************************************\n\n"); 235 236 237 // This is an implicitly signed message (ecdsa-sha1) 238 msg = createSignedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm); 239 System.out.println("creating implicitly signed message " + signatureAlgorithm.getName() + "..."); 240 baos.reset(); 241 msg.saveChanges(); 242 msg.writeTo(baos); 243 244 bais = new ByteArrayInputStream(baos.toByteArray()); 245 msg = new MimeMessage(session, bais); 246 if (PRINT_MESSAGES) { 247 printMessage(msg); 248 } 249 DumpMessage.dumpMsg(msg); 250 251 System.out.println("\n\n*****************************************\n\n"); 252 253 254 255 // ECDSA with SHA-224 (ANSI X9.62) 256 257 // This is an explicitly signed message (ecdsa-sha224) 258 hashAlgorithm = CMSAlgorithmID.sha224; 259 signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA224; 260 msg = createSignedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm); 261 System.out.println("creating explicitly signed message " + signatureAlgorithm.getName() + "..."); 262 baos.reset(); 263 msg.saveChanges(); 264 msg.writeTo(baos); 265 266 bais = new ByteArrayInputStream(baos.toByteArray()); 267 msg = new MimeMessage(session, bais); 268 if (PRINT_MESSAGES) { 269 printMessage(msg); 270 } 271 DumpMessage.dumpMsg(msg); 272 273 System.out.println("\n\n*****************************************\n\n"); 274 275 276 // This is an implicitly signed message (ecdsa-sha224) 277 msg = createSignedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm); 278 System.out.println("creating implicitly signed message " + signatureAlgorithm.getName() + "..."); 279 baos.reset(); 280 msg.saveChanges(); 281 msg.writeTo(baos); 282 283 bais = new ByteArrayInputStream(baos.toByteArray()); 284 msg = new MimeMessage(session, bais); 285 if (PRINT_MESSAGES) { 286 printMessage(msg); 287 } 288 DumpMessage.dumpMsg(msg); 289 290 System.out.println("\n\n*****************************************\n\n"); 291 292 293 // ECDSA with SHA-256 (ANSI X9.62) 294 295 // This is an explicitly signed message (ecdsa-sha256) 296 hashAlgorithm = AlgorithmID.sha256; 297 signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA256; 298 msg = createSignedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm); 299 System.out.println("creating explicitly signed message " + signatureAlgorithm.getName() + "..."); 300 baos.reset(); 301 msg.saveChanges(); 302 msg.writeTo(baos); 303 304 bais = new ByteArrayInputStream(baos.toByteArray()); 305 msg = new MimeMessage(session, bais); 306 if (PRINT_MESSAGES) { 307 printMessage(msg); 308 } 309 DumpMessage.dumpMsg(msg); 310 311 System.out.println("\n\n*****************************************\n\n"); 312 313 314 // This is an implicitly signed message (ecdsa-sha256) 315 msg = createSignedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm); 316 System.out.println("creating implicitly signed message " + signatureAlgorithm.getName() + "..."); 317 baos.reset(); 318 msg.saveChanges(); 319 msg.writeTo(baos); 320 321 bais = new ByteArrayInputStream(baos.toByteArray()); 322 msg = new MimeMessage(session, bais); 323 if (PRINT_MESSAGES) { 324 printMessage(msg); 325 } 326 DumpMessage.dumpMsg(msg); 327 328 System.out.println("\n\n*****************************************\n\n"); 329 330 331 // ECDSA with SHA-384 (ANSI X9.62) 332 333 // This is an explicitly signed message (ecdsa-sha384) 334 hashAlgorithm = AlgorithmID.sha384; 335 signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA384; 336 msg = createSignedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm); 337 System.out.println("creating explicitly signed message " + signatureAlgorithm.getName() + "..."); 338 baos.reset(); 339 msg.saveChanges(); 340 msg.writeTo(baos); 341 342 bais = new ByteArrayInputStream(baos.toByteArray()); 343 msg = new MimeMessage(session, bais); 344 if (PRINT_MESSAGES) { 345 printMessage(msg); 346 } 347 DumpMessage.dumpMsg(msg); 348 349 System.out.println("\n\n*****************************************\n\n"); 350 351 352 // This is an implicitly signed message (ecdsa-sha384) 353 msg = createSignedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm); 354 System.out.println("creating implicitly signed message " + signatureAlgorithm.getName() + "..."); 355 baos.reset(); 356 msg.saveChanges(); 357 msg.writeTo(baos); 358 359 bais = new ByteArrayInputStream(baos.toByteArray()); 360 msg = new MimeMessage(session, bais); 361 if (PRINT_MESSAGES) { 362 printMessage(msg); 363 } 364 DumpMessage.dumpMsg(msg); 365 366 System.out.println("\n\n*****************************************\n\n"); 367 368 369 // ECDSA with SHA-512 (ANSI X9.62) 370 371 // This is an explicitly signed message (ecdsa-sha512) 372 hashAlgorithm = AlgorithmID.sha512; 373 signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA512; 374 msg = createSignedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm); 375 System.out.println("creating explicitly signed message " + signatureAlgorithm.getName() + "..."); 376 baos.reset(); 377 msg.saveChanges(); 378 msg.writeTo(baos); 379 380 bais = new ByteArrayInputStream(baos.toByteArray()); 381 msg = new MimeMessage(session, bais); 382 if (PRINT_MESSAGES) { 383 printMessage(msg); 384 } 385 DumpMessage.dumpMsg(msg); 386 387 System.out.println("\n\n*****************************************\n\n"); 388 389 390 // This is an implicitly signed message (ecdsa-sha512) 391 msg = createSignedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm); 392 System.out.println("creating implicitly signed message " + signatureAlgorithm.getName() + "..."); 393 baos.reset(); 394 msg.saveChanges(); 395 msg.writeTo(baos); 396 397 bais = new ByteArrayInputStream(baos.toByteArray()); 398 msg = new MimeMessage(session, bais); 399 if (PRINT_MESSAGES) { 400 printMessage(msg); 401 } 402 DumpMessage.dumpMsg(msg); 403 404 System.out.println("\n\n*****************************************\n\n"); 405 406 407 408 // ECDSA with RIPEMD-160 (plain format, BSI) 409 410 // This is an explicitly signed message (ecdsa-plain-ripemd160) 411 hashAlgorithm = AlgorithmID.ripeMd160; 412 signatureAlgorithm = CMSAlgorithmID.ecdsa_plain_With_RIPEMD160; 413 msg = createSignedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm); 414 System.out.println("creating explicitly signed message " + signatureAlgorithm.getName() + "..."); 415 baos.reset(); 416 msg.saveChanges(); 417 msg.writeTo(baos); 418 419 bais = new ByteArrayInputStream(baos.toByteArray()); 420 msg = new MimeMessage(session, bais); 421 if (PRINT_MESSAGES) { 422 printMessage(msg); 423 } 424 DumpMessage.dumpMsg(msg); 425 426 System.out.println("\n\n*****************************************\n\n"); 427 428 429 // This is an implicitly signed message (ecdsa-plain-ripemd160) 430 msg = createSignedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm); 431 System.out.println("creating implicitly signed message " + signatureAlgorithm.getName() + "..."); 432 baos.reset(); 433 msg.saveChanges(); 434 msg.writeTo(baos); 435 436 bais = new ByteArrayInputStream(baos.toByteArray()); 437 msg = new MimeMessage(session, bais); 438 if (PRINT_MESSAGES) { 439 printMessage(msg); 440 } 441 DumpMessage.dumpMsg(msg); 442 443 System.out.println("\n\n*****************************************\n\n"); 444 445 446 447 // Now create encrypted messages with different content encryption algorithms 448 449 // RC2 is deprecated; only demonstrated here 450 msg = createEncryptedMessage(session, 451 (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 452 128, 453 (CMSAlgorithmID)CMSAlgorithmID.dhSinglePass_stdDH_sha1kdf_scheme.clone(), 454 (AlgorithmID)AlgorithmID.cms_rc2_wrap.clone(), 455 128); 456 System.out.println("creating encrypted message [RC2/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 DumpMessage.dumpMsg(msg); 467 468 469 System.out.println("\n\n*****************************************\n\n"); 470 471 // TripleDES is deprecated; only demonstrated here 472 msg = createEncryptedMessage(session, 473 (AlgorithmID)AlgorithmID.des_EDE3_CBC.clone(), 474 192, 475 (CMSAlgorithmID)CMSAlgorithmID.dhSinglePass_stdDH_sha1kdf_scheme.clone(), 476 (AlgorithmID)AlgorithmID.cms_3DES_wrap.clone(), 477 192); 478 System.out.println("creating encrypted message [TripleDES]..."); 479 baos.reset(); 480 msg.saveChanges(); 481 msg.writeTo(baos); 482 483 bais = new ByteArrayInputStream(baos.toByteArray()); 484 msg = new MimeMessage(session, bais); 485 if (PRINT_MESSAGES) { 486 printMessage(msg); 487 } 488 DumpMessage.dumpMsg(msg); 489 490 System.out.println("\n\n*****************************************\n\n"); 491 492 msg = createEncryptedMessage(session, 493 (AlgorithmID)AlgorithmID.aes128_CBC.clone(), 494 128, 495 (CMSAlgorithmID)CMSAlgorithmID.dhSinglePass_stdDH_sha1kdf_scheme.clone(), 496 (AlgorithmID)CMSAlgorithmID.cms_aes128_wrap.clone(), 497 128); 498 System.out.println("creating encrypted message [AES]..."); 499 baos.reset(); 500 msg.saveChanges(); 501 msg.writeTo(baos); 502 503 bais = new ByteArrayInputStream(baos.toByteArray()); 504 msg = new MimeMessage(session, bais); 505 if (PRINT_MESSAGES) { 506 printMessage(msg); 507 } 508 DumpMessage.dumpMsg(msg); 509 510 System.out.println("\n\n*****************************************\n\n"); 511 512 msg = createEncryptedMessage(session, 513 (AlgorithmID)AlgorithmID.aes256_CBC.clone(), 514 256, 515 (CMSAlgorithmID)CMSAlgorithmID.dhSinglePass_stdDH_sha256kdf_scheme.clone(), 516 (AlgorithmID)CMSAlgorithmID.cms_aes256_wrap.clone(), 517 256); 518 System.out.println("creating encrypted message [AES-256]..."); 519 baos.reset(); 520 msg.saveChanges(); 521 msg.writeTo(baos); 522 523 bais = new ByteArrayInputStream(baos.toByteArray()); 524 msg = new MimeMessage(session, bais); 525 if (PRINT_MESSAGES) { 526 printMessage(msg); 527 } 528 DumpMessage.dumpMsg(msg); 529 530 System.out.println("\n\n*****************************************\n\n"); 531 532 533 534 // signed (ecdsa-sha1) + encrypted 535 536 // Now create implicitly signed and encrypted message with attachment 537 hashAlgorithm = AlgorithmID.sha1; 538 signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA1; 539 msg = createSignedAndEncryptedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm); 540 System.out.println("creating implicitly signed " + signatureAlgorithm.getName() + " and encrypted message ..."); 541 baos.reset(); 542 msg.saveChanges(); 543 msg.writeTo(baos); 544 545 bais = new ByteArrayInputStream(baos.toByteArray()); 546 msg = new MimeMessage(session, bais); 547 if (PRINT_MESSAGES) { 548 printMessage(msg); 549 } 550 DumpMessage.dumpMsg(msg); 551 552 System.out.println("\n\n*****************************************\n\n"); 553 554 // Now create a explicitly signed and encrypted message with attachment 555 msg = createSignedAndEncryptedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm); 556 System.out.println("creating explicitly signed " + signatureAlgorithm.getName() + " and encrypted message ..."); 557 baos.reset(); 558 msg.saveChanges(); 559 msg.writeTo(baos); 560 561 bais = new ByteArrayInputStream(baos.toByteArray()); 562 msg = new MimeMessage(session, bais); 563 if (PRINT_MESSAGES) { 564 printMessage(msg); 565 } 566 DumpMessage.dumpMsg(msg); 567 System.out.println("\n\n*****************************************\n\n"); 568 569 570 // ECDSA with SHA-2 571 572 // signed (ecdsa-sha224) + encrypted 573 574 // Now create implicitly signed and encrypted message with attachment 575 hashAlgorithm = CMSAlgorithmID.sha224; 576 signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA224; 577 msg = createSignedAndEncryptedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm); 578 System.out.println("creating implicitly signed " + signatureAlgorithm.getName() + " and encrypted message ..."); 579 baos.reset(); 580 msg.saveChanges(); 581 msg.writeTo(baos); 582 583 bais = new ByteArrayInputStream(baos.toByteArray()); 584 msg = new MimeMessage(session, bais); 585 if (PRINT_MESSAGES) { 586 printMessage(msg); 587 } 588 DumpMessage.dumpMsg(msg); 589 590 System.out.println("\n\n*****************************************\n\n"); 591 592 // Now create a explicitly signed and encrypted message with attachment 593 msg = createSignedAndEncryptedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm); 594 System.out.println("creating explicitly signed " + signatureAlgorithm.getName() + " and encrypted message ..."); 595 baos.reset(); 596 msg.saveChanges(); 597 msg.writeTo(baos); 598 599 bais = new ByteArrayInputStream(baos.toByteArray()); 600 msg = new MimeMessage(session, bais); 601 if (PRINT_MESSAGES) { 602 printMessage(msg); 603 } 604 DumpMessage.dumpMsg(msg); 605 System.out.println("\n\n*****************************************\n\n"); 606 607 608 // signed (ecdsa-sha256) + encrypted 609 610 // Now create implicitly signed and encrypted message with attachment 611 hashAlgorithm = AlgorithmID.sha256; 612 signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA256; 613 msg = createSignedAndEncryptedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm); 614 System.out.println("creating implicitly signed " + signatureAlgorithm.getName() + " and encrypted message ..."); 615 baos.reset(); 616 msg.saveChanges(); 617 msg.writeTo(baos); 618 619 bais = new ByteArrayInputStream(baos.toByteArray()); 620 msg = new MimeMessage(session, bais); 621 if (PRINT_MESSAGES) { 622 printMessage(msg); 623 } 624 DumpMessage.dumpMsg(msg); 625 626 System.out.println("\n\n*****************************************\n\n"); 627 628 // Now create a explicitly signed and encrypted message with attachment 629 msg = createSignedAndEncryptedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm); 630 System.out.println("creating explicitly signed " + signatureAlgorithm.getName() + " and encrypted message ..."); 631 baos.reset(); 632 msg.saveChanges(); 633 msg.writeTo(baos); 634 635 bais = new ByteArrayInputStream(baos.toByteArray()); 636 msg = new MimeMessage(session, bais); 637 if (PRINT_MESSAGES) { 638 printMessage(msg); 639 } 640 DumpMessage.dumpMsg(msg); 641 System.out.println("\n\n*****************************************\n\n"); 642 643 644 // signed (ecdsa-sha384) + encrypted 645 646 // Now create implicitly signed and encrypted message with attachment 647 hashAlgorithm = AlgorithmID.sha384; 648 signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA384; 649 msg = createSignedAndEncryptedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm); 650 System.out.println("creating implicitly signed " + signatureAlgorithm.getName() + " and encrypted message ..."); 651 baos.reset(); 652 msg.saveChanges(); 653 msg.writeTo(baos); 654 655 bais = new ByteArrayInputStream(baos.toByteArray()); 656 msg = new MimeMessage(session, bais); 657 if (PRINT_MESSAGES) { 658 printMessage(msg); 659 } 660 DumpMessage.dumpMsg(msg); 661 662 System.out.println("\n\n*****************************************\n\n"); 663 664 // Now create a explicitly signed and encrypted message with attachment 665 msg = createSignedAndEncryptedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm); 666 System.out.println("creating explicitly signed " + signatureAlgorithm.getName() + " and encrypted message ..."); 667 baos.reset(); 668 msg.saveChanges(); 669 msg.writeTo(baos); 670 671 bais = new ByteArrayInputStream(baos.toByteArray()); 672 msg = new MimeMessage(session, bais); 673 if (PRINT_MESSAGES) { 674 printMessage(msg); 675 } 676 DumpMessage.dumpMsg(msg); 677 System.out.println("\n\n*****************************************\n\n"); 678 679 680 // signed (ecdsa-sha512) + encrypted 681 682 // Now create implicitly signed and encrypted message with attachment 683 hashAlgorithm = AlgorithmID.sha512; 684 signatureAlgorithm = CMSAlgorithmID.ecdsa_With_SHA512; 685 msg = createSignedAndEncryptedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm); 686 System.out.println("creating implicitly signed " + signatureAlgorithm.getName() + " and encrypted message ..."); 687 baos.reset(); 688 msg.saveChanges(); 689 msg.writeTo(baos); 690 691 bais = new ByteArrayInputStream(baos.toByteArray()); 692 msg = new MimeMessage(session, bais); 693 if (PRINT_MESSAGES) { 694 printMessage(msg); 695 } 696 DumpMessage.dumpMsg(msg); 697 698 System.out.println("\n\n*****************************************\n\n"); 699 700 // Now create a explicitly signed and encrypted message with attachment 701 msg = createSignedAndEncryptedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm); 702 System.out.println("creating explicitly signed " + signatureAlgorithm.getName() + " and encrypted message ..."); 703 baos.reset(); 704 msg.saveChanges(); 705 msg.writeTo(baos); 706 707 bais = new ByteArrayInputStream(baos.toByteArray()); 708 msg = new MimeMessage(session, bais); 709 if (PRINT_MESSAGES) { 710 printMessage(msg); 711 } 712 DumpMessage.dumpMsg(msg); 713 System.out.println("\n\n*****************************************\n\n"); 714 715 716 // signed (ecdsa-ripemd160) + encrypted 717 718 // Now create implicitly signed and encrypted message with attachment 719 hashAlgorithm = AlgorithmID.ripeMd160; 720 signatureAlgorithm = CMSAlgorithmID.ecdsa_plain_With_RIPEMD160; 721 msg = createSignedAndEncryptedMessage(session, multipart, true, hashAlgorithm, signatureAlgorithm); 722 System.out.println("creating implicitly signed " + signatureAlgorithm.getName() + " and encrypted message ..."); 723 baos.reset(); 724 msg.saveChanges(); 725 msg.writeTo(baos); 726 727 bais = new ByteArrayInputStream(baos.toByteArray()); 728 msg = new MimeMessage(session, bais); 729 if (PRINT_MESSAGES) { 730 printMessage(msg); 731 } 732 DumpMessage.dumpMsg(msg); 733 734 System.out.println("\n\n*****************************************\n\n"); 735 736 // Now create a explicitly signed and encrypted message with attachment 737 msg = createSignedAndEncryptedMessage(session, multipart, false, hashAlgorithm, signatureAlgorithm); 738 System.out.println("creating explicitly signed " + signatureAlgorithm.getName() + " and encrypted message ..."); 739 baos.reset(); 740 msg.saveChanges(); 741 msg.writeTo(baos); 742 743 bais = new ByteArrayInputStream(baos.toByteArray()); 744 msg = new MimeMessage(session, bais); 745 if (PRINT_MESSAGES) { 746 printMessage(msg); 747 } 748 DumpMessage.dumpMsg(msg); 749 System.out.println("\n\n*****************************************\n\n"); 750 751 752 753 754 } catch (Exception ex) { 755 ex.printStackTrace(); 756 throw new RuntimeException(ex.toString()); 757 } 758 759 System.out.println("OK!"); 760 761 } 762 763 /** 764 * Creates a MIME message container with the given subject for the given session. 765 * 766 * @param session the mail session 767 * @param subject the subject of the message 768 * 769 * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content) 770 * 771 * @throws MessagingException if the message cannot be created 772 */ 773 public Message createMessage(Session session, String subject) throws MessagingException { 774 MimeMessage msg = new MimeMessage(session); 775 msg.setFrom(new InternetAddress(from)); 776 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false)); 777 msg.setSentDate(new Date()); 778 msg.setSubject(subject); 779 return msg; 780 } 781 782 /** 783 * Creates a signed and encrypted message. 784 * 785 * @param session the mail session 786 * @param dataHandler the content of the message to be signed and encrypted 787 * @param implicit whether to use implicit (application/pkcs7-mime) or explicit 788 * (multipart/signed) signing 789 * @param hashAlgorithm the hash algorithm to be used 790 * @param signatureAlgorithm the signature algorithm to be used 791 * 792 * @return the signed and encrypted message 793 * 794 * @throws MessagingException if an error occurs when creating the message 795 */ 796 public Message createSignedAndEncryptedMessage(Session session, 797 DataHandler dataHandler, 798 boolean implicit, 799 AlgorithmID hashAlgorithm, 800 AlgorithmID signatureAlgorithm) 801 throws MessagingException { 802 803 String subject = null; 804 String text = null; 805 if (implicit) { 806 subject = "IAIK-S/MIME: Implicitly Signed and Encrypted"; 807 text = "This message is implicitly signed and encrypted!\n\n\n"; 808 } else { 809 subject = "IAIK-S/MIME: Explicitly Signed and Encrypted"; 810 text = "This message is explicitly signed and encrypted!\n\n\n"; 811 } 812 Message msg = createMessage(session, subject); 813 814 SignedContent sc = new SignedContent(implicit); 815 if (dataHandler != null) { 816 sc.setDataHandler(dataHandler); 817 } else { 818 sc.setText(text); 819 } 820 sc.setCertificates(signerCertificates); 821 AlgorithmID ecdsaSig = (AlgorithmID)signatureAlgorithm.clone(); 822 // CMS-ECC requires that the parameters field is encoded as ASN.1 NULL object (see RFC 3278) 823 ecdsaSig.encodeAbsentParametersAsNull(true); 824 try { 825 sc.addSigner(signerPrivateKey, 826 signerCertificate, 827 (AlgorithmID)hashAlgorithm.clone(), 828 ecdsaSig, 829 encryptionCertOfSigner, 830 true); 831 } catch (NoSuchAlgorithmException ex) { 832 throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex); 833 } 834 835 EncryptedContent ec = new EncryptedContent(sc); 836 // encrypt for the recipient 837 AlgorithmID keyEA = (CMSAlgorithmID)CMSAlgorithmID.dhSinglePass_stdDH_sha256kdf_scheme.clone(); 838 // the key wrap algorithm to use: 839 AlgorithmID keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone(); 840 // the length of the key encryption key to be generated: 841 int kekLength = 256; 842 try { 843 ec.addRecipient(recipientCertificate, (AlgorithmID)keyEA.clone(), (AlgorithmID)keyWrapAlg.clone(), kekLength); 844 } catch (SMimeException ex) { 845 throw new MessagingException("Error adding ECDH recipient: " + ex.getMessage()); 846 } 847 try { 848 // I want to be able to decrypt the message, too 849 ec.addRecipient(encryptionCertOfSigner, (AlgorithmID)keyEA.clone(), (AlgorithmID)keyWrapAlg.clone(), kekLength); 850 } catch (SMimeException ex) { 851 throw new MessagingException("Error adding ECDH recipient: " + ex.getMessage()); 852 } 853 // set the encryption algorithm 854 try { 855 ec.setEncryptionAlgorithm((AlgorithmID)AlgorithmID.aes256_CBC.clone(), 256); 856 } catch (NoSuchAlgorithmException ex) { 857 throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage()); 858 } 859 msg.setContent(ec, ec.getContentType()); 860 // let the EncryptedContent update some message headers 861 ec.setHeaders(msg); 862 863 return msg; 864 } 865 866 /** 867 * Creates a signed message. 868 * 869 * @param session the mail session 870 * @param dataHandler the content of the message to be signed 871 * @param implicit whether to use implicit (application/pkcs7-mime) or explicit 872 * (multipart/signed) signing 873 * @param hashAlgorithm the hash algorithm to be used 874 * @param signatureAlgorithm the signature algorithm to be used 875 * 876 * @return the signed message 877 * 878 * @throws MessagingException if an error occurs when creating the message 879 */ 880 public Message createSignedMessage(Session session, 881 DataHandler dataHandler, 882 boolean implicit, 883 AlgorithmID hashAlgorithm, 884 AlgorithmID signatureAlgorithm) 885 throws MessagingException { 886 887 String subject = null; 888 StringBuffer buf = new StringBuffer(); 889 890 if (implicit) { 891 subject = "IAIK-S/MIME: Implicitly Signed (" + signatureAlgorithm.getName() +")"; 892 buf.append("This message is implicitly signed with ! " + signatureAlgorithm.getName() + "\n"); 893 buf.append("You need an S/MIME aware mail client to view this message.\n"); 894 buf.append("\n\n"); 895 } else { 896 subject = "IAIK-S/MIME: Explicitly Signed (" + signatureAlgorithm.getName() +")"; 897 buf.append("This message is explicitly signed!\n"); 898 buf.append("Every mail client can view this message.\n"); 899 buf.append("Non S/MIME mail clients will show the signature as attachment.\n"); 900 buf.append("\n\n"); 901 } 902 903 Message msg = createMessage(session, subject); 904 905 SignedContent sc = new SignedContent(implicit); 906 if (dataHandler != null) { 907 sc.setDataHandler(dataHandler); 908 } else { 909 sc.setText(buf.toString()); 910 } 911 sc.setCertificates(signerCertificates); 912 913 AlgorithmID ecdsaSig = (AlgorithmID)signatureAlgorithm.clone(); 914 // CMS-ECDSA requires to encode the parameter field as NULL (see RFC 3278) 915 ecdsaSig.encodeAbsentParametersAsNull(true); 916 try { 917 sc.addSigner(signerPrivateKey, 918 signerCertificate, 919 (AlgorithmID)hashAlgorithm.clone(), 920 ecdsaSig, 921 encryptionCertOfSigner, 922 true); 923 } catch (NoSuchAlgorithmException ex) { 924 throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex); 925 } 926 927 msg.setContent(sc, sc.getContentType()); 928 // let the SignedContent update some message headers 929 sc.setHeaders(msg); 930 return msg; 931 } 932 933 /** 934 * Creates an encrypted message. 935 * 936 * @param session the mail session 937 * @param contentEA the content encryption algorithm to be used 938 * @param keyLength the length of the secret content encryption key to be created and used 939 * 940 * @return the encrypted message 941 * 942 * @throws MessagingException if an error occurs when creating the message 943 */ 944 public Message createEncryptedMessage(Session session, AlgorithmID contentEA, int keyLength, 945 AlgorithmID keyEA, AlgorithmID keyWrapAlgorithm, int kekLength) 946 throws MessagingException { 947 948 AlgorithmID algorithm = (AlgorithmID)contentEA.clone(); 949 AlgorithmID keyAgreeAlg = (AlgorithmID)keyEA.clone(); 950 AlgorithmID keyWrapAlg = (AlgorithmID)keyWrapAlgorithm.clone(); 951 952 StringBuffer subject = new StringBuffer(); 953 subject.append("IAIK-S/MIME: Encrypted ["+algorithm.getName()); 954 if (keyLength > 0) { 955 subject.append("/"+keyLength); 956 } 957 subject.append("]"); 958 Message msg = createMessage(session, subject.toString()); 959 960 EncryptedContent ec = new EncryptedContent(); 961 962 StringBuffer buf = new StringBuffer(); 963 buf.append("This is the encrypted content!\n"); 964 buf.append("Content encryption algorithm: "+algorithm.getName()); 965 buf.append("\n\n"); 966 967 ec.setText(buf.toString()); 968 969 try { 970 ec.addRecipient(recipientCertificate, (AlgorithmID)keyAgreeAlg.clone(), (AlgorithmID)keyWrapAlg.clone(), kekLength); 971 } catch (SMimeException ex) { 972 throw new MessagingException("Error adding ECDH recipient: " + ex.getMessage()); 973 } 974 // I want to be able to decrypt the message, too 975 try { 976 ec.addRecipient(encryptionCertOfSigner, (AlgorithmID)keyAgreeAlg.clone(), (AlgorithmID)keyWrapAlg.clone(), kekLength); 977 } catch (SMimeException ex) { 978 throw new MessagingException("Error adding ECDH recipient: " + ex.getMessage()); 979 } 980 try { 981 ec.setEncryptionAlgorithm(algorithm, keyLength); 982 } catch (NoSuchAlgorithmException ex) { 983 throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage()); 984 } 985 986 msg.setContent(ec, ec.getContentType()); 987 // let the EncryptedContent update some message headers 988 ec.setHeaders(msg); 989 990 return msg; 991 } 992 993 /** 994 * Prints a dump of the given message to System.out. 995 * 996 * @param msg the message to be dumped to System.out 997 * 998 * @throws IOException if an I/O error occurs 999 */ 1000 private static void printMessage(Message msg) throws IOException { 1001 System.out.println("------------------------------------------------------------------"); 1002 System.out.println("Message dump: \n"); 1003 try { 1004 msg.writeTo(System.out); 1005 } catch (MessagingException ex) { 1006 throw new IOException(ex.getMessage()); 1007 } 1008 System.out.println("\n------------------------------------------------------------------"); 1009 } 1010 1011 1012 /** 1013 * The main method. 1014 */ 1015 public static void main(String[] argv) throws Exception { 1016 1017 DemoSMimeUtil.initDemos(); 1018 // add ECC provider 1019 ECCDemoUtil.installIaikEccProvider(); 1020 1021 (new SMimeEccDemo()).start(); 1022 System.out.println("\nReady!"); 1023 DemoUtil.waitKey(); 1024 } 1025 }