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