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/basic/CMSStreamDemo.java 31 12.02.25 17:58 Dbratko $ 059 // $Revision: 31 $ 060 // 061 062 package demo.smime.basic; 063 064 import java.io.ByteArrayInputStream; 065 import java.io.ByteArrayOutputStream; 066 import java.io.IOException; 067 import java.io.InputStream; 068 import java.io.OutputStream; 069 import java.io.PipedInputStream; 070 import java.io.PipedOutputStream; 071 import java.security.PrivateKey; 072 import java.util.Random; 073 074 import demo.DemoSMimeUtil; 075 import demo.DemoUtil; 076 import demo.keystore.CMSKeyStore; 077 import iaik.asn1.structures.AlgorithmID; 078 import iaik.cms.IssuerAndSerialNumber; 079 import iaik.smime.SMimeAuthEncrypted; 080 import iaik.smime.SMimeEncrypted; 081 import iaik.smime.SMimeSigned; 082 import iaik.utils.CryptoUtils; 083 import iaik.utils.Util; 084 import iaik.x509.X509Certificate; 085 086 /** 087 * This class shows the usage of the SMimeSigned and SMimeEncrypted classes. 088 * These classes can be used to create/parse signed and/or encrypted CMS messages. 089 * This demo does not use the JavaMail API. 090 * 091 * @see iaik.smime.SMimeSigned 092 * @see iaik.smime.SMimeEncrypted 093 */ 094 public class CMSStreamDemo { 095 096 // the signer private key 097 PrivateKey[] signerPrivateKeys; 098 // the signer certificate 099 X509Certificate rsaSignerCertificate; 100 // the signer certificate 101 X509Certificate dsaSignerCertificate; 102 // the recipient private key 103 PrivateKey[] recipientPrivateKeys; 104 // the recipient certificate 105 X509Certificate[] recipientCertificates; 106 // the certificate chain 107 X509Certificate[] signerCertificates; 108 // buffer with test data to sign and/or encrypt 109 byte[] buffer; 110 // size of the buffer 111 final static int BUF_SIZE = 10000; 112 113 /** 114 * Empty default constructor. 115 */ 116 public CMSStreamDemo() { 117 118 System.out.println(); 119 System.out.println("******************************************************************************************"); 120 System.out.println("* CMSStreamDemo *"); 121 System.out.println("* (shows the usage of the IAIK-CMS SMimeSigned and SMimeEncrypted classes) *"); 122 System.out.println("******************************************************************************************"); 123 System.out.println(); 124 125 // create some random data for the test 126 buffer = new byte[BUF_SIZE]; 127 Random rnd = new Random(); 128 rnd.nextBytes(buffer); 129 } 130 131 /** 132 * Reads the required keys and certificates from the demo keystore. 133 * 134 * @throws Exception if some error occurs when reading from the keystore 135 */ 136 public void setupCertificates() throws Exception { 137 // get the certificates from the KeyStore 138 // we use two signers just for demonstration 139 signerPrivateKeys = new PrivateKey[2]; 140 // RSA signer 141 X509Certificate[] rsaCerts = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1); 142 rsaSignerCertificate = rsaCerts[0]; 143 signerPrivateKeys[0] = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1); 144 // DSA signer 145 X509Certificate[] dsaCerts = CMSKeyStore.getCertificateChain(CMSKeyStore.DSA, CMSKeyStore.SZ_2048_SIGN_1); 146 dsaSignerCertificate = dsaCerts[0]; 147 signerPrivateKeys[1] = CMSKeyStore.getPrivateKey(CMSKeyStore.DSA, CMSKeyStore.SZ_2048_SIGN_1); 148 signerCertificates = new X509Certificate[rsaCerts.length + dsaCerts.length]; 149 System.arraycopy(rsaCerts, 0, signerCertificates, 0, dsaCerts.length); 150 System.arraycopy(dsaCerts, 0, signerCertificates, rsaCerts.length, dsaCerts.length); 151 152 // get the recipients keys and certificates 153 recipientPrivateKeys = new PrivateKey[2]; 154 recipientPrivateKeys[0] = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1); 155 recipientPrivateKeys[1] = CMSKeyStore.getPrivateKey(CMSKeyStore.ESDH, CMSKeyStore.SZ_2048_CRYPT_1); 156 recipientCertificates = new X509Certificate[2]; 157 recipientCertificates[0] = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0]; 158 recipientCertificates[1] = CMSKeyStore.getCertificateChain(CMSKeyStore.ESDH, CMSKeyStore.SZ_2048_CRYPT_1)[0]; 159 } 160 161 /** 162 * Uses class {@link iaik.smime.SMimeEncrypted SMimeEncrypted} to encrypt some data, encode it, 163 * and finally parses the encoding to decrypt and recover the original content. 164 * 165 * @param contentEA the content encryption algorithm to be used 166 * @param keyWrapAlg the key wrap algorithm to be used for encrypting the temporary content encryption key 167 * @param keyLength the length of the content encryption key to be created and used 168 * @param recipientIndex the index into the recipientInfos field indicating for which recipient the message 169 * shall be decrypted 170 * 171 * @throws Exception if some error occurs 172 */ 173 public void testSMimeEncrypted(AlgorithmID contentEA, AlgorithmID keyWrapAlg, int keyLength, int recipientIndex) throws Exception { 174 175 // repository for the encrypted message 176 byte[] encrypted_message; 177 // the InputStream containing the data to encrypt 178 InputStream is = new ByteArrayInputStream(buffer); 179 // the OutputStream where the data shall be written to 180 ByteArrayOutputStream os = new ByteArrayOutputStream(); 181 182 // encrypt with DES/CBC and default key length 183 SMimeEncrypted encrypted = new SMimeEncrypted(is, contentEA, keyLength); 184 // add one RSA recipient 185 encrypted.addRecipient(recipientCertificates[0], (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 186 // add one ESDH recipient 187 encrypted.addRecipient(recipientCertificates[1], (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), keyWrapAlg, keyLength); 188 189 // encrypt and write the data to the output stream 190 encrypted.writeTo(os); 191 // finished 192 os.close(); 193 // get the encrypted message from the ByteArrayOutputStream 194 encrypted_message = os.toByteArray(); 195 196 // and now decrypt the data 197 is = new ByteArrayInputStream(encrypted_message); 198 encrypted = new SMimeEncrypted(is); 199 // use this private key to decrypt the symmetric key of recipient 0 200 encrypted.decryptSymmetricKey(recipientPrivateKeys[recipientIndex], recipientIndex); 201 // get the InputStream with the decrypted data 202 InputStream data = encrypted.getInputStream(); 203 204 // reset our output stream 205 os.reset(); 206 // write the decrypted data to an output stream 207 // copy the data 208 Util.copyStream(data, os, null); 209 os.close(); 210 211 // original and 'received' message must be the same 212 if (!CryptoUtils.equalsBlock(buffer, os.toByteArray())) 213 throw new RuntimeException("Error: messages are not equal!"); 214 } 215 216 /** 217 * Uses class {@link iaik.smime.SMimeSigned SMimeSigned} to sign some data, encode it, 218 * and finally parses the encoding to verify the signature. 219 * 220 * @param mode either {@link iaik.smime.SMimeSigned#IMPLICIT implicit} or 221 * {@link iaik.smime.SMimeSigned#EXPLICIT explicit} to indicate 222 * whether the content shall be included in the signature or 223 * transmitted out-of-band 224 * 225 * @throws Exception if some error occurs 226 */ 227 public void testSMimeSigned(int mode) throws Exception { 228 229 // repository for the signed message 230 byte[] signed_message = null; 231 // repository for the signature 232 byte[] signature; 233 // the InputStream containing the data to sign 234 InputStream is = new ByteArrayInputStream(buffer); 235 // the OutputStream where the data shall be written to 236 ByteArrayOutputStream os = new ByteArrayOutputStream(); 237 238 // create an implicitly/explicitly signed message 239 SMimeSigned signed = new SMimeSigned(is, mode); 240 // these certificates are sent within the signature 241 signed.setCertificates(signerCertificates); 242 // add two signers for testing 243 signed.addSigner(signerPrivateKeys[0], 244 new IssuerAndSerialNumber(rsaSignerCertificate)); 245 signed.addSigner(signerPrivateKeys[1], 246 new IssuerAndSerialNumber(dsaSignerCertificate), 247 (AlgorithmID)AlgorithmID.sha256.clone(), 248 (AlgorithmID)AlgorithmID.dsaWithSHA256.clone()); 249 250 251 if (mode == SMimeSigned.EXPLICIT) { 252 // write the data to the out-of-band file 253 ByteArrayOutputStream out_data = new ByteArrayOutputStream(); 254 Util.copyStream(signed.getInputStream(), out_data, null); 255 out_data.close(); 256 signed_message = out_data.toByteArray(); 257 } 258 259 // write the signature or the data+signature to the output stream 260 signed.writeTo(os); 261 os.close(); 262 signature = os.toByteArray(); 263 264 // and now verify the signature 265 is = new ByteArrayInputStream(signature); 266 signed = new SMimeSigned(is); 267 if (mode == SMimeSigned.EXPLICIT) { 268 // content data has been not included 269 signed.setInputStream(new ByteArrayInputStream(signed_message)); 270 } 271 272 // get the InputStream with the signed, plain data 273 InputStream data = signed.getInputStream(); 274 275 // reset our output stream 276 os.reset(); 277 // write the verified data to the output stream 278 // copy the data 279 Util.copyStream(data, os, null); 280 os.close(); 281 282 // now verify the signed data and print the certificate of the signer 283 // (verify() verifies signer at index 0) 284 X509Certificate cert = signed.verify(); 285 System.out.println("Signature OK from: "+cert.getSubjectDN()); 286 // verify our second test signer 287 cert = signed.verify(1); 288 System.out.println("Signature OK from: "+cert.getSubjectDN()); 289 290 // original and 'received' message must be the same 291 if (!CryptoUtils.equalsBlock(buffer, os.toByteArray())) 292 throw new RuntimeException("Error: messages are not equal!"); 293 } 294 295 /** 296 * Uses class {@link iaik.smime.SMimeAuthEncrypted SMimeAuthEncrypted} to 297 * authenticated encrypt some data, encode it, 298 * and finally parses the encoding to decrypt and recover the original content. 299 * 300 * @param contentEA the content-authenticated encryption algorithm to be used 301 * @param keyWrapAlg the key wrap algorithm to be used for encrypting the temporary content encryption key 302 * @param keyLength the length of the content encryption key to be created and used 303 * @param recipientIndex the index into the recipientInfos field indicating for which recipient the message 304 * shall be decrypted 305 * 306 * @throws Exception if some error occurs 307 */ 308 public void testSMimeAuthEncrypted(AlgorithmID contentEA, AlgorithmID keyWrapAlg, int keyLength, int recipientIndex) throws Exception { 309 310 // repository for the encrypted message 311 byte[] encrypted_message; 312 // the InputStream containing the data to encrypt 313 InputStream is = new ByteArrayInputStream(buffer); 314 // the OutputStream where the data shall be written to 315 ByteArrayOutputStream os = new ByteArrayOutputStream(); 316 317 // encrypt with DES/CBC and default key length 318 SMimeAuthEncrypted encrypted = new SMimeAuthEncrypted(is, contentEA, keyLength); 319 if (contentEA.equals(AlgorithmID.aes128_CCM) || 320 contentEA.equals(AlgorithmID.aes192_CCM) || 321 contentEA.equals(AlgorithmID.aes256_CCM)) { 322 // for aes-ccm we need to know the data input length in advance 323 encrypted.setInputLength(buffer.length); 324 } 325 326 // add one RSA recipient 327 encrypted.addRecipient(recipientCertificates[0], (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 328 // add one ESDH recipient 329 encrypted.addRecipient(recipientCertificates[1], (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), keyWrapAlg, keyLength); 330 331 // encrypt and write the data to the output stream 332 encrypted.writeTo(os); 333 // finished 334 os.close(); 335 // get the encrypted message from the ByteArrayOutputStream 336 encrypted_message = os.toByteArray(); 337 338 // and now decrypt the data 339 is = new ByteArrayInputStream(encrypted_message); 340 encrypted = new SMimeAuthEncrypted(is, (byte[])null, buffer.length); 341 // use this private key to decrypt the symmetric key of recipient 0 342 encrypted.decryptSymmetricKey(recipientPrivateKeys[recipientIndex], recipientIndex); 343 // get the InputStream with the decrypted data 344 InputStream data = encrypted.getInputStream(); 345 346 // reset our output stream 347 os.reset(); 348 // write the decrypted data to an output stream 349 // copy the data 350 Util.copyStream(data, os, null); 351 os.close(); 352 353 // original and 'received' message must be the same 354 if (!CryptoUtils.equalsBlock(buffer, os.toByteArray())) 355 throw new RuntimeException("Error: messages are not equal!"); 356 } 357 358 /** 359 * Uses class {@link iaik.smime.SMimeSigned SMimeSigned} and class {@link iaik.smime.SMimeEncrypted SMimeEncrypted} 360 * to sign and encrypt some data, encode it, and finally parses the encoding to decrypt and recover the original content 361 * and verify the signature. 362 * 363 * @param contentEA the content encryption algorithm to be used 364 * @param keyWrapAlg the key wrap algorithm to be used for encrypting the temporary content encryption key 365 * @param keyLength the length of the content encryption key to be created and used 366 * @param recipientIndex the index into the recipientInfos field indicating for which recipient the message 367 * shall be decrypted 368 * 369 * @throws Exception if some error occurs 370 */ 371 public void testSMimeSignedAndEncrypted(AlgorithmID contentEA, AlgorithmID keyWrapAlg, int keyLength, int recipientIndex) throws Exception { 372 373 // repository for the signed and encrypted message 374 byte[] signed_encrpyted_message; 375 // the InputStream containing the data to sign and encrypt 376 InputStream is = new ByteArrayInputStream(buffer); 377 // the OutputStream where the data shall be written to 378 ByteArrayOutputStream os = new ByteArrayOutputStream(); 379 380 // we have to sign and encrypt => connect 2 streams 381 PipedOutputStream piped_out = new PipedOutputStream(); 382 PipedInputStream piped_in = new PipedInputStream(piped_out); 383 384 // create an implicit signed message (signature contains message) 385 SMimeSigned signed = new SMimeSigned(is, SMimeSigned.IMPLICIT); 386 // these certificates are sent within the signature 387 signed.setCertificates(signerCertificates); 388 // add two signers for testing 389 signed.addSigner(signerPrivateKeys[0], 390 new IssuerAndSerialNumber(rsaSignerCertificate)); 391 signed.addSigner(signerPrivateKeys[1], new IssuerAndSerialNumber(dsaSignerCertificate), 392 (AlgorithmID)AlgorithmID.sha256.clone(), 393 (AlgorithmID)AlgorithmID.dsaWithSHA256.clone()); 394 395 396 // a new Thread between the 2 streams 397 Writer writer = new Writer(signed, piped_out); 398 writer.start(); 399 400 // encrypt with DES/CBC and default key length 401 SMimeEncrypted encrypted = new SMimeEncrypted(piped_in, contentEA, keyLength); 402 403 // add one RSA recipient 404 encrypted.addRecipient(recipientCertificates[0], 405 (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 406 // add one ESDH recipient 407 encrypted.addRecipient(recipientCertificates[1], 408 (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), 409 keyWrapAlg, 410 keyLength); 411 // encrypt and write the data to the output stream 412 encrypted.writeTo(os); 413 // finished 414 os.close(); 415 // get the signed and encrypted message from the ByteArrayOutputStream 416 signed_encrpyted_message = os.toByteArray(); 417 418 // and now decrypt the data and verify the signature 419 is = new ByteArrayInputStream(signed_encrpyted_message); 420 encrypted = new SMimeEncrypted(is); 421 // use this private key to decrypt the symmetric key 422 encrypted.decryptSymmetricKey(recipientPrivateKeys[recipientIndex], recipientIndex); 423 // get the InputStream with the decrypted data 424 InputStream data_dec = encrypted.getInputStream(); 425 426 // read the signed data from the derypted InputStream 427 signed = new SMimeSigned(data_dec); 428 429 // get the InputStream with the signed, plain data 430 InputStream data = signed.getInputStream(); 431 432 // reset our output stream 433 os.reset(); 434 // write the decrypted and verified data to the output stream 435 // copy the data 436 Util.copyStream(data, os, null); 437 os.close(); 438 439 // now verify the signed data and print the certificate of the signer 440 // (verify() verifies signer at index 0) 441 X509Certificate cert = signed.verify(); 442 System.out.println("Signature OK from: "+cert.getSubjectDN()); 443 // verify our second test signer 444 cert = signed.verify(1); 445 System.out.println("Signature OK from: "+cert.getSubjectDN()); 446 447 // original and 'received' message must be the same 448 if (!CryptoUtils.equalsBlock(buffer, os.toByteArray())) 449 throw new RuntimeException("Error: messages are not equal!"); 450 } 451 452 /** 453 * Uses class {@link iaik.smime.SMimeSigned SMimeSigned} and class {@link iaik.smime.SMimeAuthEncrypted SMimeAuthEncrypted} 454 * to sign and authenticated encrypt some data, encode it, and finally parses the encoding to decrypt and recover the original content 455 * and verify the signature. 456 * 457 * @param contentEA the content-authenticated encryption algorithm to be used 458 * @param keyWrapAlg the key wrap algorithm to be used for encrypting the temporary content encryption key 459 * @param keyLength the length of the content encryption key to be created and used 460 * @param recipientIndex the index into the recipientInfos field indicating for which recipient the message 461 * shall be decrypted 462 * 463 * @throws Exception if some error occurs 464 */ 465 public void testSMimeSignedAndAuthEncrypted(AlgorithmID contentEA, AlgorithmID keyWrapAlg, int keyLength, int recipientIndex) throws Exception { 466 467 // repository for the signed and encrypted message 468 byte[] signed_encrpyted_message; 469 // the InputStream containing the data to sign and encrypt 470 InputStream is = new ByteArrayInputStream(buffer); 471 // the OutputStream where the data shall be written to 472 ByteArrayOutputStream os = new ByteArrayOutputStream(); 473 474 // we have to sign and encrypt => connect 2 streams 475 PipedOutputStream piped_out = new PipedOutputStream(); 476 PipedInputStream piped_in = new PipedInputStream(piped_out); 477 478 // create an implicit signed message (signature contains message) 479 SMimeSigned signed = new SMimeSigned(is, SMimeSigned.IMPLICIT); 480 // these certificates are sent within the signature 481 signed.setCertificates(signerCertificates); 482 // add two signers for testing 483 signed.addSigner(signerPrivateKeys[0], 484 new IssuerAndSerialNumber(rsaSignerCertificate)); 485 signed.addSigner(signerPrivateKeys[1], new IssuerAndSerialNumber(dsaSignerCertificate), 486 (AlgorithmID)AlgorithmID.sha256.clone(), 487 (AlgorithmID)AlgorithmID.dsaWithSHA256.clone()); 488 489 490 // a new Thread between the 2 streams 491 Writer writer = new Writer(signed, piped_out); 492 writer.start(); 493 494 // encrypt with default key length 495 SMimeAuthEncrypted encrypted = new SMimeAuthEncrypted(piped_in, contentEA, keyLength); 496 497 // add one RSA recipient 498 encrypted.addRecipient(recipientCertificates[0], 499 (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 500 // add one ESDH recipient 501 encrypted.addRecipient(recipientCertificates[1], 502 (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), 503 keyWrapAlg, 504 keyLength); 505 // encrypt and write the data to the output stream 506 encrypted.writeTo(os); 507 // finished 508 os.close(); 509 // get the signed and encrypted message from the ByteArrayOutputStream 510 signed_encrpyted_message = os.toByteArray(); 511 512 // and now decrypt the data and verify the signature 513 is = new ByteArrayInputStream(signed_encrpyted_message); 514 encrypted = new SMimeAuthEncrypted(is, (byte[])null, -1); 515 516 // use this private key to decrypt the symmetric key 517 encrypted.decryptSymmetricKey(recipientPrivateKeys[recipientIndex], recipientIndex); 518 // get the InputStream with the decrypted data 519 InputStream decryptedIs = encrypted.getInputStream(); 520 521 // read the signed data from the derypted InputStream 522 signed = new SMimeSigned(decryptedIs); 523 524 // get the InputStream with the signed, plain data 525 InputStream data = signed.getInputStream(); 526 527 // reset our output stream 528 os.reset(); 529 // write the decrypted and verified data to the output stream 530 // copy the data 531 Util.copyStream(data, os, null); 532 os.close(); 533 534 // now verify the signed data and print the certificate of the signer 535 // (verify() verifies signer at index 0) 536 X509Certificate cert = signed.verify(); 537 System.out.println("Signature OK from: "+cert.getSubjectDN()); 538 // verify our second test signer 539 cert = signed.verify(1); 540 System.out.println("Signature OK from: "+cert.getSubjectDN()); 541 542 // original and 'received' message must be the same 543 if (!CryptoUtils.equalsBlock(buffer, os.toByteArray())) 544 throw new RuntimeException("Error: messages are not equal!"); 545 } 546 547 /** 548 * Starts the demo. 549 */ 550 public void start() { 551 try { 552 // read keys and certificates from demo keystore 553 setupCertificates(); 554 555 System.out.println("testing an implicit S/MIME signed message..."); 556 testSMimeSigned(SMimeSigned.IMPLICIT); 557 558 System.out.println("testing an explicit S/MIME signed message..."); 559 testSMimeSigned(SMimeSigned.EXPLICIT); 560 561 // DES EDE is deprecated; only demonstrated here 562 AlgorithmID contentEA = (AlgorithmID)AlgorithmID.des_EDE3_CBC.clone(); 563 AlgorithmID keyWrapAlg = (AlgorithmID)AlgorithmID.cms_3DES_wrap.clone(); 564 System.out.println("testing a S/MIME encrypted message for 3DES CBC; decrypting for RSA user..."); 565 testSMimeEncrypted(contentEA, keyWrapAlg, -1, 0); 566 System.out.println("testing a S/MIME encrypted message for 3DES CBC; decrypting for ESDH user..."); 567 testSMimeEncrypted(contentEA, keyWrapAlg, -1, 1); 568 569 // RC2 is deprecated; only demonstrated here 570 contentEA = (AlgorithmID)AlgorithmID.rc2_CBC.clone(); 571 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_rc2_wrap.clone(); 572 System.out.println("testing a S/MIME encrypted message for RC2 CBC; decrypting for RSA user..."); 573 testSMimeEncrypted(contentEA, keyWrapAlg, 128, 0); 574 System.out.println("testing a S/MIME encrypted message for RC2 CBC; decrypting for ESDH user..."); 575 testSMimeEncrypted(contentEA, keyWrapAlg, 128, 1); 576 577 // DES EDE is deprecated; only demonstrated here 578 contentEA = (AlgorithmID)AlgorithmID.des_EDE3_CBC.clone(); 579 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_3DES_wrap.clone(); 580 System.out.println("testing a S/MIME signed and encrypted message for 3DES CBC; decrypting for RSA user..."); 581 testSMimeSignedAndEncrypted(contentEA, keyWrapAlg, -1, 0); 582 System.out.println("testing a S/MIME signed and encrypted message for 3DES CBC; decrypting for ESDH user..."); 583 testSMimeSignedAndEncrypted(contentEA, keyWrapAlg, -1, 1); 584 585 // RC2 is deprecated; only demonstrated here 586 contentEA = (AlgorithmID)AlgorithmID.rc2_CBC.clone(); 587 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_rc2_wrap.clone(); 588 System.out.println("testing a S/MIME signed and encrypted message for RC2 CBC; decrypting for RSA user..."); 589 testSMimeSignedAndEncrypted(contentEA, keyWrapAlg, 128, 0); 590 System.out.println("testing a S/MIME signed and encrypted message for RC2 CBC; decrypting for ESDH user..."); 591 testSMimeSignedAndEncrypted(contentEA, keyWrapAlg, 128, 1); 592 593 contentEA = (AlgorithmID)AlgorithmID.aes128_CBC.clone(); 594 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes128_wrap.clone(); 595 System.out.println("testing a S/MIME encrypted message for AES-128-CBC; decrypting for RSA user..."); 596 testSMimeEncrypted(contentEA, keyWrapAlg, -1, 0); 597 System.out.println("testing a S/MIME encrypted message for AES-128-CBC; decrypting for ESDH user..."); 598 testSMimeEncrypted(contentEA, keyWrapAlg, -1, 1); 599 600 contentEA = (AlgorithmID)AlgorithmID.aes128_CBC.clone(); 601 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes128_wrap.clone(); 602 System.out.println("testing a S/MIME signed and encrypted message for AES-128-CBC; decrypting for RSA user..."); 603 testSMimeSignedAndEncrypted(contentEA, keyWrapAlg, -1, 0); 604 System.out.println("testing a S/MIME signed and encrypted message for AES-128-CBC; decrypting for ESDH user..."); 605 testSMimeSignedAndEncrypted(contentEA, keyWrapAlg, -1, 1); 606 607 contentEA = (AlgorithmID)AlgorithmID.aes192_CBC.clone(); 608 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes192_wrap.clone(); 609 System.out.println("testing a S/MIME encrypted message for AES-192-CBC; decrypting for RSA user..."); 610 testSMimeEncrypted(contentEA, keyWrapAlg, -1, 0); 611 System.out.println("testing a S/MIME encrypted message for AES-192-CBC; decrypting for ESDH user..."); 612 testSMimeEncrypted(contentEA, keyWrapAlg, -1, 1); 613 614 contentEA = (AlgorithmID)AlgorithmID.aes192_CBC.clone(); 615 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes192_wrap.clone(); 616 System.out.println("testing a S/MIME signed and encrypted message for AES-192-CBC; decrypting for RSA user..."); 617 testSMimeSignedAndEncrypted(contentEA, keyWrapAlg, -1, 0); 618 System.out.println("testing a S/MIME signed and encrypted message for AES-192-CBC; decrypting for ESDH user..."); 619 testSMimeSignedAndEncrypted(contentEA, keyWrapAlg, -1, 1); 620 621 contentEA = (AlgorithmID)AlgorithmID.aes256_CBC.clone(); 622 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone(); 623 System.out.println("testing a S/MIME encrypted message for AES-256-CBC; decrypting for RSA user..."); 624 testSMimeEncrypted(contentEA, keyWrapAlg, -1, 0); 625 System.out.println("testing a S/MIME encrypted message for AES-256-CBC; decrypting for ESDH user..."); 626 testSMimeEncrypted(contentEA, keyWrapAlg, -1, 1); 627 contentEA = (AlgorithmID)AlgorithmID.aes256_CBC.clone(); 628 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone(); 629 System.out.println("testing a S/MIME signed and encrypted message for AES-256-CBC; decrypting for RSA user..."); 630 testSMimeSignedAndEncrypted(contentEA, keyWrapAlg, -1, 0); 631 System.out.println("testing a S/MIME signed and encrypted message for AES-256-CBC; decrypting for ESDH user..."); 632 testSMimeSignedAndEncrypted(contentEA, keyWrapAlg, -1, 1); 633 634 contentEA = (AlgorithmID)AlgorithmID.aes128_GCM.clone(); 635 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes128_wrap.clone(); 636 System.out.println("testing a S/MIME auth encrypted message for AES-128-GCM; decrypting for RSA user..."); 637 testSMimeAuthEncrypted(contentEA, keyWrapAlg, -1, 0); 638 System.out.println("testing a S/MIME auth encrypted message for AES-128-GCM; decrypting for ESDH user..."); 639 testSMimeAuthEncrypted(contentEA, keyWrapAlg, -1, 1); 640 641 contentEA = (AlgorithmID)AlgorithmID.aes192_GCM.clone(); 642 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes192_wrap.clone(); 643 System.out.println("testing a S/MIME auth encrypted message for AES-192-GCM; decrypting for RSA user..."); 644 testSMimeAuthEncrypted(contentEA, keyWrapAlg, -1, 0); 645 System.out.println("testing a S/MIME auth encrypted message for AES-192-GCM; decrypting for ESDH user..."); 646 testSMimeAuthEncrypted(contentEA, keyWrapAlg, -1, 1); 647 648 contentEA = (AlgorithmID)AlgorithmID.aes256_GCM.clone(); 649 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone(); 650 System.out.println("testing a S/MIME auth encrypted message for AES-256-GCM; decrypting for RSA user..."); 651 testSMimeAuthEncrypted(contentEA, keyWrapAlg, -1, 0); 652 System.out.println("testing a S/MIME auth encrypted message for AES-256-GCM; decrypting for ESDH user..."); 653 testSMimeAuthEncrypted(contentEA, keyWrapAlg, -1, 1); 654 655 contentEA = (AlgorithmID)AlgorithmID.aes128_CCM.clone(); 656 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes128_wrap.clone(); 657 System.out.println("testing a S/MIME auth encrypted message for AES-128-CCM; decrypting for RSA user..."); 658 testSMimeAuthEncrypted(contentEA, keyWrapAlg, -1, 0); 659 System.out.println("testing a S/MIME auth encrypted message for AES-128-CCM; decrypting for ESDH user..."); 660 testSMimeAuthEncrypted(contentEA, keyWrapAlg, -1, 1); 661 662 contentEA = (AlgorithmID)AlgorithmID.aes192_CCM.clone(); 663 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes192_wrap.clone(); 664 System.out.println("testing a S/MIME auth encrypted message for AES-192-CCM; decrypting for RSA user..."); 665 testSMimeAuthEncrypted(contentEA, keyWrapAlg, -1, 0); 666 System.out.println("testing a S/MIME auth encrypted message for AES-192-CCM; decrypting for ESDH user..."); 667 testSMimeAuthEncrypted(contentEA, keyWrapAlg, -1, 1); 668 669 contentEA = (AlgorithmID)AlgorithmID.aes256_CCM.clone(); 670 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone(); 671 System.out.println("testing a S/MIME auth encrypted message for AES-256-CCM; decrypting for RSA user..."); 672 testSMimeAuthEncrypted(contentEA, keyWrapAlg, -1, 0); 673 System.out.println("testing a S/MIME auth encrypted message for AES-256-CCM; decrypting for ESDH user..."); 674 testSMimeAuthEncrypted(contentEA, keyWrapAlg, -1, 1); 675 676 contentEA = (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(); 677 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone(); 678 System.out.println("testing a S/MIME auth encrypted message for ChaChaPoly1305; decrypting for RSA user..."); 679 testSMimeAuthEncrypted(contentEA, keyWrapAlg, -1, 0); 680 System.out.println("testing a S/MIME auth encrypted message for ChaChaPoly1305; decrypting for ESDH user..."); 681 testSMimeAuthEncrypted(contentEA, keyWrapAlg, -1, 1); 682 683 contentEA = (AlgorithmID)AlgorithmID.aes128_GCM.clone(); 684 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes128_wrap.clone(); 685 System.out.println("testing a S/MIME signed and auth encrypted message for AES-128-GCM; decrypting for RSA user..."); 686 testSMimeSignedAndAuthEncrypted(contentEA, keyWrapAlg, -1, 0); 687 System.out.println("testing a S/MIME signed and auth encrypted message for AES-128-GCM; decrypting for ESDH user..."); 688 testSMimeSignedAndAuthEncrypted(contentEA, keyWrapAlg, -1, 1); 689 690 contentEA = (AlgorithmID)AlgorithmID.aes192_GCM.clone(); 691 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes192_wrap.clone(); 692 System.out.println("testing a S/MIME signed and auth encrypted message for AES-192-GCM; decrypting for RSA user..."); 693 testSMimeSignedAndAuthEncrypted(contentEA, keyWrapAlg, -1, 0); 694 System.out.println("testing a S/MIME signed and auth encrypted message for AES-192-GCM; decrypting for ESDH user..."); 695 testSMimeSignedAndAuthEncrypted(contentEA, keyWrapAlg, -1, 1); 696 697 contentEA = (AlgorithmID)AlgorithmID.aes256_GCM.clone(); 698 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone(); 699 System.out.println("testing a S/MIME signed and auth encrypted message for AES-256-GCM; decrypting for RSA user..."); 700 testSMimeSignedAndAuthEncrypted(contentEA, keyWrapAlg, -1, 0); 701 System.out.println("testing a S/MIME signed and auth encrypted message for AES-256-GCM; decrypting for ESDH user..."); 702 testSMimeSignedAndAuthEncrypted(contentEA, keyWrapAlg, -1, 1); 703 704 contentEA = (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(); 705 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone(); 706 System.out.println("testing a S/MIME signed and auth encrypted message for ChaChaPoly1305; decrypting for RSA user..."); 707 testSMimeSignedAndAuthEncrypted(contentEA, keyWrapAlg, -1, 0); 708 System.out.println("testing a S/MIME signed and auth encrypted message for ChaChaPoly1305; decrypting for ESDH user..."); 709 testSMimeSignedAndAuthEncrypted(contentEA, keyWrapAlg, -1, 1); 710 711 712 } catch (Exception ex) { 713 ex.printStackTrace(); 714 throw new RuntimeException(ex.toString()); 715 } 716 } 717 718 /** 719 * The main method. 720 * Reads the certificates and the private key and then starts the demos. 721 */ 722 public static void main(String[] argv) throws IOException { 723 724 DemoSMimeUtil.initDemos(); 725 (new CMSStreamDemo()).start(); 726 727 System.out.println("\nReady!"); 728 DemoUtil.waitKey(); 729 } 730 731 /** 732 * Inner class for copying data between the 2 streams. 733 */ 734 static class Writer extends Thread { 735 736 SMimeSigned signed; 737 OutputStream os; 738 Exception exception; 739 740 public Writer(SMimeSigned signed, OutputStream os) { 741 super("Writer"); 742 this.signed = signed; 743 this.os = os; 744 } 745 746 /** 747 * Writes the SMimeSinged to the OutputStream. 748 */ 749 public void run() { 750 try { 751 signed.writeTo(os); 752 os.close(); 753 } catch (Exception ex) { 754 exception = ex; 755 System.out.println("Writer exception: "+exception); 756 } 757 } 758 759 /** 760 * Returns a possible exception. 761 */ 762 public Exception getException() { 763 return exception; 764 } 765 } 766 }