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 }