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/cms/envelopedData/EnvelopedDataDemoAEAD.java 5 12.02.25 17:58 Dbratko $
059 // $Revision: 5 $
060 //
061
062
063 package demo.cms.envelopedData;
064
065 import java.io.ByteArrayInputStream;
066 import java.io.ByteArrayOutputStream;
067 import java.io.IOException;
068 import java.io.InputStream;
069 import java.security.InvalidKeyException;
070 import java.security.Key;
071 import java.security.NoSuchAlgorithmException;
072 import java.security.PrivateKey;
073 import java.security.SecureRandom;
074
075 import javax.crypto.KeyGenerator;
076 import javax.crypto.SecretKey;
077
078 import demo.DemoUtil;
079 import demo.keystore.CMSKeyStore;
080 import iaik.asn1.ObjectID;
081 import iaik.asn1.structures.AlgorithmID;
082 import iaik.cms.CMSException;
083 import iaik.cms.CertificateIdentifier;
084 import iaik.cms.ContentInfo;
085 import iaik.cms.ContentInfoOutputStream;
086 import iaik.cms.ContentInfoStream;
087 import iaik.cms.EncryptedContentInfo;
088 import iaik.cms.EncryptedContentInfoStream;
089 import iaik.cms.EnvelopedData;
090 import iaik.cms.EnvelopedDataOutputStream;
091 import iaik.cms.EnvelopedDataStream;
092 import iaik.cms.IssuerAndSerialNumber;
093 import iaik.cms.KEKIdentifier;
094 import iaik.cms.KEKRecipientInfo;
095 import iaik.cms.KeyAgreeRecipientInfo;
096 import iaik.cms.KeyIdentifier;
097 import iaik.cms.KeyTransRecipientInfo;
098 import iaik.cms.RecipientInfo;
099 import iaik.cms.RecipientKeyIdentifier;
100 import iaik.cms.SubjectKeyID;
101 import iaik.security.random.SecRandom;
102 import iaik.utils.CryptoUtils;
103 import iaik.utils.Util;
104 import iaik.x509.X509Certificate;
105
106
107 /**
108 * Demonstrates the usage of class {@link iaik.cms.EnvelopedDataStream},
109 * {@link iaik.cms.EnvelopedData} and {@link iaik.cms.EnvelopedDataOutputStream} for
110 * AEAD encrypting data using the CMS type EnvelopedData according to
111 * <a href = "http://www.ietf.org/rfc/rfc5652.txt" target="_blank">RFC 5652</a>.
112 * <p>
113 * Usually CMS uses AEAD cipher modes like GCM with the <code>AuthEnvelopedData</code> type. However,
114 * technically -- when appending the mac value to the cipher text -- it is also possible to use
115 * AEAD ciphers with the <code>EnvelopedData</code> type as shown in this demo.
116 * <br>
117 * Since AES-CCM and AES-GCM are not implemented by IAIK-JCE versions prior 3.17, this demo
118 * at least may require IAIK-JCE 3.17 as cryptographic service provider.
119 * ChaCha20-Poly1305 for CMS requires IAIK-JCE version 5.62 or later.
120 * <p>
121 * Keys and certificates are retrieved from the demo KeyStore ("cms.keystore")
122 * which has to be located in your current working directory and may be
123 * created by running the {@link demo.keystore.SetupCMSKeyStore
124 * SetupCMSKeyStore} program.
125 * <p>
126 * This demo requires Java 7 or later.
127 *
128 * @see iaik.cms.EnvelopedDataStream
129 * @see iaik.cms.EnvelopedData
130 * @see iaik.cms.RecipientInfo
131 * @see iaik.cms.KeyTransRecipientInfo
132 * @see iaik.cms.KeyAgreeRecipientInfo
133 * @see iaik.cms.KEKRecipientInfo
134 */
135 public class EnvelopedDataDemoAEAD {
136
137 // certificate of rsaUser 1
138 X509Certificate rsaUser1;
139 // private key of rsaUser 1
140 PrivateKey rsaUser1_pk;
141 // certificate of rsaUser 2
142 X509Certificate rsaUser2;
143 // private key of rsaUser 2
144 PrivateKey rsaUser2_pk;
145
146 // certificate of esdhUser 1
147 X509Certificate esdhUser1;
148 // private key of esdhUser 1
149 PrivateKey esdhUser1_pk;
150 // certificate of esdhUser 2
151 X509Certificate esdhUser2;
152 // private key of esdhUser 2
153 PrivateKey esdhUser2_pk;
154
155 // key encryption key for KEKRecipientInfo
156 SecretKey kek;
157 byte[] kekID;
158
159 // secure random number generator
160 SecureRandom random;
161
162 // the test message
163 byte[] test_message;
164
165 /**
166 * Setup the demo certificate chains.
167 *
168 * Keys and certificates are retrieved from the demo KeyStore ("cms.keystore")
169 * file which has to be located in your current working directory and may be
170 * created by running {@link demo.keystore.SetupCMSKeyStore
171 * SetupCMSKeyStore}.
172 *
173 * @throws IOException if an file read error occurs
174 */
175 public EnvelopedDataDemoAEAD() throws IOException {
176
177 System.out.println();
178 System.out.println("*************************************************************************************");
179 System.out.println("* EnvelopedDataDemoAEAD *");
180 System.out.println("* (shows the usage of the CMS EnvelopedData type implementation with AEAD ciphers) *");
181 System.out.println("*************************************************************************************");
182 System.out.println();
183
184 // add all certificates to the list
185 X509Certificate[] certs = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1);
186 rsaUser1 = certs[0];
187 rsaUser1_pk = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1);
188 rsaUser2 = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0];
189 rsaUser2_pk = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2);
190
191 esdhUser1 = CMSKeyStore.getCertificateChain(CMSKeyStore.ESDH, CMSKeyStore.SZ_2048_CRYPT_1)[0];
192 esdhUser1_pk = CMSKeyStore.getPrivateKey(CMSKeyStore.ESDH, CMSKeyStore.SZ_2048_CRYPT_1);
193 esdhUser2 = CMSKeyStore.getCertificateChain(CMSKeyStore.ESDH, CMSKeyStore.SZ_2048_CRYPT_2)[0];
194 esdhUser2_pk = CMSKeyStore.getPrivateKey(CMSKeyStore.ESDH, CMSKeyStore.SZ_2048_CRYPT_2);
195 random = SecRandom.getDefault();
196 // create a secret key encryption key for a KEKRecipientInfo
197 KeyGenerator kg;
198 try {
199 kg = KeyGenerator.getInstance("AES");
200 } catch (NoSuchAlgorithmException ex) {
201 throw new IOException("KeyGenerator for AES not avcailable!");
202 }
203 kg.init(random);
204 kek = kg.generateKey();
205 kekID = new byte[] { 00, 00, 00, 01 };
206
207 test_message = "This is the test message.".getBytes();
208 }
209
210
211 /**
212 * Creates a CMS <code>EnvelopedDataStream</code> message.
213 *
214 * @param message the message to be authenticated-enveloped, as byte representation
215 * @param contentAuthEncAlg the id of the content-authenticated encryption algorithm
216 *
217 * @return the BER encoding of the <code>EnvelopedData</code> object just created
218 *
219 * @throws CMSException if the <code>EnvelopedData</code> object cannot
220 * be created
221 * @throws IOException if an I/O error occurs
222 */
223 public byte[] createEnvelopedDataStream(byte[] message,
224 AlgorithmID contentAuthEncAlg)
225 throws CMSException, IOException {
226
227 // we are testing the stream interface
228 ByteArrayInputStream is = new ByteArrayInputStream(message);
229 // create a new EnvelopedData object
230 EnvelopedDataStream enveleopedData;
231 try {
232 enveleopedData = new EnvelopedDataStream(is, contentAuthEncAlg);
233 } catch (NoSuchAlgorithmException e) {
234 throw new CMSException(e.getMessage());
235 }
236
237 // create the recipient infos
238 RecipientInfo[] recipients = createRecipients();
239 // specify the recipients of the encrypted message
240 enveleopedData.setRecipientInfos(recipients);
241
242 // wrap into ContentInfo
243 ContentInfoStream contentInfo = new ContentInfoStream(enveleopedData);
244 ByteArrayOutputStream os = new ByteArrayOutputStream();
245 contentInfo.writeTo(os);
246 return os.toByteArray();
247 }
248
249 /**
250 * Uses the <code>EnvelopedDataOutputStream</code> implementation to create an
251 * EnvelopedData message.
252 *
253 * @param message the message to be authenticated-enveloped, as byte representation
254 * @param contentAuthEncAlg the id of the content-authenticated encryption algorithm
255 *
256 * @return the BER encoding of the <code>EnvelopedData</code> object just created
257 *
258 * @throws CMSException if the <code>EnvelopedData</code> object cannot
259 * be created
260 * @throws IOException if an I/O error occurs
261 */
262 public byte[] createEnvelopedDataOutputStream(byte[] message,
263 AlgorithmID contentAuthEncAlg)
264 throws CMSException, IOException {
265
266 // a stream from which to read the data to be encrypted
267 ByteArrayInputStream is = new ByteArrayInputStream(message);
268
269 // the stream to which to write the EnvelopedData
270 ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
271 EnvelopedDataOutputStream envelopedData;
272
273 // wrap EnvelopedData into a ContentInfo
274 ContentInfoOutputStream contentInfoStream =
275 new ContentInfoOutputStream(ObjectID.cms_envelopedData, resultStream);
276 // create a new EnvelopedData object encrypted with AES
277 try {
278 envelopedData = new EnvelopedDataOutputStream(contentInfoStream,
279 contentAuthEncAlg);
280 } catch (NoSuchAlgorithmException ex) {
281 throw new CMSException("No implementation for AES.");
282 }
283
284 // create the recipient infos
285 RecipientInfo[] recipients = createRecipients();
286 // specify the recipients of the encrypted message
287 envelopedData.setRecipientInfos(recipients);
288
289 int blockSize = 16; // in real world we would use a block size like 2048
290 // write in the data to be encrypted
291 byte[] buffer = new byte[blockSize];
292 int bytesRead;
293 while ((bytesRead = is.read(buffer)) != -1) {
294 envelopedData.write(buffer, 0, bytesRead);
295 }
296
297 // closing the stream finishes encryption and closes the underlying stream
298 envelopedData.close();
299 return resultStream.toByteArray();
300 }
301
302
303 /**
304 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
305 * the recipient identified by its index into the recipientInfos field and verifies
306 * the message authentication code.
307 * <p>
308 * This way of decrypting the content may be used for any type of RecipientInfo
309 * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo), but requires to
310 * know at what index of the recipientInfo field the RecipientInfo for the
311 * particular recipient in mind can be found. If the recipient in mind uses
312 * a RecipientInfo of type KeyAgreeRecipientInfo some processing overhead may
313 * take place because a KeyAgreeRecipientInfo may contain encrypted content-encryption
314 * keys for more than only one recipient; since the recipientInfoIndex only
315 * specifies the RecipientInfo but not the encrypted content encryption key
316 * -- if there are more than only one -- repeated decryption runs may be
317 * required as long as the decryption process completes successfully.
318 *
319 * @param encoding the <code>EnvelopedData</code> object as DER encoded byte array
320 * @param key the key to decrypt the message
321 * @param recipientInfoIndex the index into the <code>RecipientInfo</code> array
322 * to which the specified key belongs
323 *
324 * @return the recovered message, as byte array
325 * @throws CMSException if the message cannot be recovered or MAC verification fails
326 * @throws IOException if a stream read/write error occurs
327 */
328 public byte[] getEnvelopedDataStream(byte[] encoding, Key key, int recipientInfoIndex)
329 throws CMSException, IOException {
330
331 // create the EnvelopedData object from a BER encoded byte array
332 ByteArrayInputStream is = new ByteArrayInputStream(encoding);
333 EnvelopedDataStream enveleopedData = new EnvelopedDataStream(is);
334
335 System.out.println("Information about the authenticated encrypted data:");
336 EncryptedContentInfoStream eci = enveleopedData.getEncryptedContentInfo();
337 System.out.println("Content type: "+eci.getContentType().getName());
338 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
339
340 System.out.println("\nThis message can be decrypted by the owners of the following certificates:");
341 RecipientInfo[] recipients = enveleopedData.getRecipientInfos();
342
343 // for demonstration purposes we only look one time for all recipients included:
344 if (recipientInfoIndex == 0) {
345 int k = 0;
346 for (int i=0; i<recipients.length; i++) {
347 KeyIdentifier[] recipientIDs = recipients[i].getRecipientIdentifiers();
348 for (int j = 0; j < recipientIDs.length; j++) {
349 System.out.println("Recipient "+(++k)+":");
350 System.out.println(recipientIDs[j]);
351 }
352 }
353 }
354 // decrypt the message for the first recipient and verify mac
355 try {
356 enveleopedData.setupCipher(key, recipientInfoIndex);
357 InputStream decrypted = enveleopedData.getInputStream();
358 ByteArrayOutputStream os = new ByteArrayOutputStream();
359 Util.copyStream(decrypted, os, null);
360 byte[] content = os.toByteArray();
361
362 checkDecryptedMessage(content, test_message);
363 return content;
364 } catch (InvalidKeyException ex) {
365 throw new CMSException("Private key error: "+ex.toString());
366 } catch (NoSuchAlgorithmException ex) {
367 throw new CMSException("Content encryption algorithm not implemented: "+ex.toString());
368 }
369 }
370
371 /**
372 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
373 * the recipient identified by recipient identifier and verifies the message
374 * authentication code.
375 * <p>
376 * This way of decrypting the content may be used for any type of RecipientInfo
377 * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo). The
378 * recipient in mind is identified by its recipient identifier.
379 *
380 * @param encoding the <code>EnvelopedData</code> object as BER encoded byte array
381 * @param key the key to decrypt the message
382 * @param recipientID the recipient identifier uniquely identifying the key of the
383 * recipient
384 *
385 * @return the recovered message, as byte array
386 * @throws CMSException if the message cannot be recovered
387 * @throws IOException if a stream read/write error occurs
388 */
389 public byte[] getEnvelopedDataStream(byte[] encoding, Key key, KeyIdentifier recipientID)
390 throws CMSException, IOException {
391
392 // create the EnvelopedData object from a DER encoded byte array
393 ByteArrayInputStream is = new ByteArrayInputStream(encoding);
394 EnvelopedDataStream enveleopedData = new EnvelopedDataStream(is);
395
396 System.out.println("Information about the encrypted data:");
397 EncryptedContentInfoStream eci = enveleopedData.getEncryptedContentInfo();
398 System.out.println("Content type: "+eci.getContentType().getName());
399 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
400
401 // get the right RecipientInfo
402 System.out.println("\nSearch for RecipientInfo:");
403 RecipientInfo recipient = enveleopedData.getRecipientInfo(recipientID);
404 if (recipient != null) {
405 System.out.println("RecipientInfo: " + recipient);
406 } else {
407 throw new CMSException("No recipient with ID: " + recipientID);
408 }
409 // decrypt the content encryption key and the content; verify mac
410 try {
411 System.out.println("Decrypt encrypted content encryption key...");
412 SecretKey cek = recipient.decryptKey(key, recipientID);
413 System.out.println("Decrypt content with decrypted content encryption key...");
414 enveleopedData.setupCipher(cek);
415 InputStream decrypted = enveleopedData.getInputStream();
416 ByteArrayOutputStream os = new ByteArrayOutputStream();
417 Util.copyStream(decrypted, os, null);
418 byte[] content = os.toByteArray();
419 checkDecryptedMessage(content, test_message);
420 return content;
421 } catch (InvalidKeyException ex) {
422 throw new CMSException("Private key error: "+ex.toString());
423 } catch (NoSuchAlgorithmException ex) {
424 throw new CMSException("Content encryption algorithm not implemented: "+ex.toString());
425 }
426 }
427
428 /**
429 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
430 * the recipient identified by its recipient certificate or kekID and verifies the message
431 * authentication code.
432 * <p>
433 * Since recipient certificates only may be used for for RecipientInfos of type
434 * KeyTransRecipientInfo or KeyAgreeRecipientInfo, a key id has to be supplied
435 * for decrypting the content for a recipient using a KEKRecipientInfo.
436 *
437 * @param encoding the <code>EnvelopedData</code> object as BER encoded byte array
438 * @param key the key to decrypt the message
439 * @param recipientCert the certificate of the recipient having a RecipientInfo of
440 * type KeyTransRecipientInfo or KeyAgreeRecipientInfo
441 * @param kekID the kekID identifying the recipient key when using a RecipientInfo
442 * of type KEKRecipientInfo
443 *
444 * @return the recovered message, as byte array
445 * @throws CMSException if the message cannot be recovered
446 * @throws IOException if a stream read/write error occurs
447 */
448 public byte[] getEnvelopedDataStream(byte[] encoding, Key key, X509Certificate recipientCert, byte[] kekID)
449 throws CMSException, IOException {
450
451 // create the EnvelopedData object from a BER encoded byte array
452 ByteArrayInputStream is = new ByteArrayInputStream(encoding);
453 EnvelopedDataStream enveleopedData = new EnvelopedDataStream(is);
454
455 System.out.println("Information about the encrypted data:");
456 EncryptedContentInfoStream eci = (EncryptedContentInfoStream)enveleopedData.getEncryptedContentInfo();
457 System.out.println("Content type: "+eci.getContentType().getName());
458 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
459
460 // decrypt the content encryption key and the content; verify mac
461 try {
462 System.out.println("Decrypt the content...");
463 if (recipientCert != null) {
464 enveleopedData.setupCipher(key, recipientCert);
465 } else {
466 // KEKRecipientInfo
467 enveleopedData.setupCipher(key, new KEKIdentifier(kekID));
468 }
469 InputStream decrypted = enveleopedData.getInputStream();
470 ByteArrayOutputStream os = new ByteArrayOutputStream();
471 Util.copyStream(decrypted, os, null);
472 byte[] content = os.toByteArray();
473 checkDecryptedMessage(content, test_message);
474 return content;
475 } catch (InvalidKeyException ex) {
476 throw new CMSException("Private key error: "+ex.toString());
477 } catch (NoSuchAlgorithmException ex) {
478 throw new CMSException("Content encryption algorithm not implemented: "+ex.toString());
479 }
480 }
481
482
483 // non stream
484
485 /**
486 * Creates a CMS <code>EnvelopedData</code> message.
487 *
488 * @param message the message to be enveloped, as byte representation
489 * @param contentAuthEncAlg the id of the content-authenticated encryption algorithm
490 *
491 *
492 * @return the encoded <code>EnvelopedData</code>, as byte array
493 *
494 * @throws CMSException if the <code>EnvelopedData</code> object cannot
495 * be created
496 */
497 public byte[] createEnvelopedData(byte[] message, AlgorithmID contentAuthEncAlg)
498 throws CMSException {
499
500 EnvelopedData enveleopedData;
501
502 // create a new EnvelopedData object
503 try {
504 enveleopedData = new EnvelopedData(message, contentAuthEncAlg);
505 } catch (NoSuchAlgorithmException e) {
506 throw new CMSException(e.getMessage());
507 }
508
509 // set the RecipientInfos
510 RecipientInfo[] recipients = createRecipients();
511 enveleopedData.setRecipientInfos(recipients);
512
513 // wrap into ContentInfo
514 ContentInfo contentInfo = new ContentInfo(enveleopedData);
515 // return encoded EnvelopedData
516 return contentInfo.getEncoded();
517 }
518
519
520 /**
521 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
522 * the recipient identified by its index into the recipientInfos field and verifies
523 * the message authentication code.
524 * <p>
525 * This way of decrypting the content may be used for any type of RecipientInfo
526 * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo), but requires to
527 * know at what index of the recipientInfo field the RecipientInfo for the
528 * particular recipient in mind can be found. If the recipient in mind uses
529 * a RecipientInfo of type KeyAgreeRecipientInfo some processing overhead may
530 * take place because a KeyAgreeRecipientInfo may contain encrypted content-encryption
531 * keys for more than only one recipient; since the recipientInfoIndex only
532 * specifies the RecipientInfo but not the encrypted content encryption key
533 * -- if there are more than only one -- repeated decryption runs may be
534 * required as long as the decryption process completes successfully.
535 *
536 * @param enc the encoded <code>EnvelopedData</code>
537 *
538 * @param key the key to decrypt the message
539 *
540 * @param recipientInfoIndex the index into the <code>RecipientInfo</code> array
541 * to which the specified key belongs
542 *
543 * @return the recovered message, as byte array
544 *
545 * @throws CMSException if the message cannot be recovered
546 * @throws IOException if an I/O error occurs
547 */
548 public byte[] getEnvelopedData(byte[] enc, Key key, int recipientInfoIndex)
549 throws CMSException, IOException {
550 ByteArrayInputStream bais = new ByteArrayInputStream(enc);
551 EnvelopedData enveleopedData = new EnvelopedData(bais);
552
553 System.out.println("Information about the encrypted data:");
554 EncryptedContentInfo eci = (EncryptedContentInfo)enveleopedData.getEncryptedContentInfo();
555 System.out.println("Content type: "+eci.getContentType().getName());
556 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
557
558 System.out.println("\nThis message can be decrypted by the owners of the following certificates:");
559 RecipientInfo[] recipients = enveleopedData.getRecipientInfos();
560
561 // for demonstration purposes we only look one time for all recipients included:
562 if (recipientInfoIndex == 0) {
563 int k = 0;
564 for (int i=0; i<recipients.length; i++) {
565 KeyIdentifier[] recipientIDs = recipients[i].getRecipientIdentifiers();
566 for (int j = 0; j < recipientIDs.length; j++) {
567 System.out.println("Recipient "+(++k)+":");
568 System.out.println(recipientIDs[j]);
569 }
570 }
571 }
572
573 // decrypt the message and verify the mac
574 try {
575 enveleopedData.setupCipher(key, recipientInfoIndex);
576 byte[] content = enveleopedData.getContent();
577 checkDecryptedMessage(content, test_message);
578 return content;
579 } catch (InvalidKeyException ex) {
580 throw new CMSException("Private key error: "+ex.toString());
581 } catch (NoSuchAlgorithmException ex) {
582 throw new CMSException("Content encryption algorithm not implemented: "+ex.toString());
583 }
584 }
585 /**
586 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
587 * the recipient identified by recipient identifier.
588 * <p>
589 * This way of decrypting the content may be used for any type of RecipientInfo
590 * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo). The
591 * recipient in mind is identified by its recipient identifier.
592 *
593 * @param enc the BER encoded <code>EnvelopedData</code> ASN.1 object
594 * @param key the key to decrypt the message
595 * @param recipientID the recipient identifier uniquely identifying the key of the
596 * recipient
597 *
598 * @return the recovered message, as byte array
599 * @throws CMSException if the message cannot be recovered
600 * @throws IOException if an I/O error occurs
601 */
602 public byte[] getEnvelopedData(byte[] enc, Key key, KeyIdentifier recipientID)
603 throws CMSException, IOException {
604 ByteArrayInputStream bais = new ByteArrayInputStream(enc);
605 EnvelopedData enveleopedData = new EnvelopedData(bais);
606
607 System.out.println("Information about the encrypted data:");
608 EncryptedContentInfo eci = (EncryptedContentInfo)enveleopedData.getEncryptedContentInfo();
609 System.out.println("Content type: "+eci.getContentType().getName());
610 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
611
612 // get the right RecipientInfo
613 System.out.println("\nSearch for RecipientInfo:");
614 RecipientInfo recipient = enveleopedData.getRecipientInfo(recipientID);
615 if (recipient != null) {
616 System.out.println("RecipientInfo: " + recipient);
617 } else {
618 throw new CMSException("No recipient with ID: " + recipientID);
619 }
620 // decrypt the content encryption key and the content
621 try {
622 System.out.println("Decrypt encrypted content encryption key...");
623 SecretKey cek = recipient.decryptKey(key, recipientID);
624 System.out.println("Decrypt content with decrypted content encryption key...");
625 // decrypt content and verify mac
626 enveleopedData.setupCipher(cek);
627 byte[] content = enveleopedData.getContent();
628 checkDecryptedMessage(content, test_message);
629 return content;
630 } catch (InvalidKeyException ex) {
631 throw new CMSException("Private key error: "+ex.toString());
632 } catch (NoSuchAlgorithmException ex) {
633 throw new CMSException("Content encryption algorithm not implemented: "+ex.toString());
634 }
635 }
636
637 /**
638 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
639 * the recipient identified by its recipient certificate or keyID.
640 * <p>
641 * Since recipient certificates only may be used for for RecipientInfos of type
642 * KeyTransRecipientInfo or KeyAgreeRecipientInfo, a key id has to be supplied
643 * for decrypting the content for a recipient using a KEKRecipientInfo.
644 *
645 * @param enc the BER encoded <code>EnvelopedData</code> ASN.1 object
646 * @param key the key to decrypt the message
647 * @param recipientCert the certificate of the recipient having a RecipientInfo of
648 * type KeyTransRecipientInfo or KeyAgreeRecipientInfo
649 * @param kekID the kekID identifying the recipient key when using a RecipientInfo
650 * of type KEKRecipientInfo
651 *
652 * @return the recovered message, as byte array
653 * @throws CMSException if the message cannot be recovered
654 */
655 public byte[] getEnvelopedData(byte[] enc, Key key, X509Certificate recipientCert, byte[] kekID)
656 throws CMSException, IOException {
657 ByteArrayInputStream bais = new ByteArrayInputStream(enc);
658 EnvelopedData enveleopedData = new EnvelopedData(bais);
659
660 System.out.println("Information about the encrypted data:");
661 EncryptedContentInfo eci = (EncryptedContentInfo)enveleopedData.getEncryptedContentInfo();
662 System.out.println("Content type: "+eci.getContentType().getName());
663 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
664
665 // decrypt the content encryption key and the content
666 try {
667 System.out.println("Decrypt the content and verify mac...");
668 // decrypt content and verify mac
669 if (recipientCert != null) {
670 enveleopedData.setupCipher(key, recipientCert);
671 } else {
672 // KEKRecipientInfo
673 enveleopedData.setupCipher(key, new KEKIdentifier(kekID));
674 }
675 byte[] content = enveleopedData.getContent();
676 checkDecryptedMessage(content, test_message);
677 return content;
678 } catch (InvalidKeyException ex) {
679 throw new CMSException("Private key error: "+ex.toString());
680 } catch (NoSuchAlgorithmException ex) {
681 throw new CMSException("Content encryption algorithm not implemented: "+ex.toString());
682 }
683
684 }
685
686 /**
687 * Creates the RecipientInfos.
688 *
689 * @return the RecipientInfos created, two KeyTransRecipientInfos, one
690 * KeyAgreeRecipientInfo (for two recipients with same domain
691 * parameters), and one KEKRecipientInfo
692 *
693 * @throws CMSException if an error occurs when creating the recipient infos
694 */
695 public RecipientInfo[] createRecipients() throws CMSException {
696
697 RecipientInfo[] recipients = new RecipientInfo[4];
698 try {
699 // rsaUser1 is the first receiver (cert identified by IssuerAndSerialNumber)
700 recipients[0] = new KeyTransRecipientInfo(rsaUser1,
701 (AlgorithmID)AlgorithmID.rsaEncryption.clone());
702 // rsaUser2 is the second receiver (cert identifief by SubjectKeyIdentifier)
703 recipients[1] = new KeyTransRecipientInfo(rsaUser2,
704 CertificateIdentifier.SUBJECT_KEY_IDENTIFIER,
705 (AlgorithmID)AlgorithmID.rsaEncryption.clone());
706
707 // next recipients use key agreement
708 // the key encryption (key agreement) algorithm to use:
709 AlgorithmID keyEA = (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone();
710 // the key wrap algorithm to use:
711 AlgorithmID keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone();
712 // the length of the key encryption key to be generated:
713 int kekLength = 256;
714 recipients[2] = new KeyAgreeRecipientInfo(keyEA, keyWrapAlg, kekLength);
715 // esdhUser1 is the third receiver (cert identified by IssuerAndSerialNumber)
716 ((KeyAgreeRecipientInfo)recipients[2]).addRecipient(esdhUser1, CertificateIdentifier.ISSUER_AND_SERIALNUMBER);
717 // esdhUser2 is the fourth receiver (cert identified by RecipientKeyIdentifier)
718 ((KeyAgreeRecipientInfo)recipients[2]).addRecipient(esdhUser2, CertificateIdentifier.RECIPIENT_KEY_IDENTIFIER);
719
720 // last receiver uses a symmetric key encryption key
721 AlgorithmID kea = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone();
722 KEKIdentifier kekIdentifier = new KEKIdentifier(kekID);
723 recipients[3] = new KEKRecipientInfo(kekIdentifier, kea, kek);
724 } catch (Exception ex) {
725 throw new CMSException("Error adding recipients: " + ex.getMessage());
726 }
727 return recipients;
728 }
729
730 /**
731 * Parses an EnvelopedData and decrypts the content for all test recipients
732 * using the index into the recipientInfos field for identifying the recipient.
733 *
734 * @param stream whether to use EnvelopedDataStream or EnvelopedData
735 * @param encodedEnvelopedData the encoded EnvelopedData object
736 *
737 * @throws Exception if some error occurs during decoding/decryption
738 */
739 public void parseEnvelopedDataWithRecipientInfoIndex(boolean stream, byte[] encodedEnvelopedData) throws Exception {
740 byte[] receivedMessage;
741 if (stream) {
742 // rsaUser1
743 System.out.println("\nDecrypt for rsaUser1:");
744 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, rsaUser1_pk, 0);
745 System.out.print("\nDecrypted content: ");
746 System.out.println(new String(receivedMessage));
747 // rsaUser2
748 System.out.println("\nDecrypt for rsaUser2:");
749 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, rsaUser2_pk, 1);
750 System.out.print("\nDecrypted content: ");
751 System.out.println(new String(receivedMessage));
752 // esdhUser1
753 System.out.println("\nDecrypt for esdhUser1:");
754 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, esdhUser1_pk, 2);
755 System.out.print("\nDecrypted content: ");
756 System.out.println(new String(receivedMessage));
757 // esdhUser2
758 System.out.println("\nDecrypt for esdhUser2:");
759 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, esdhUser2_pk, 2);
760 System.out.print("\nDecrypted content: ");
761 System.out.println(new String(receivedMessage));
762 // kekUser
763 System.out.println("\nDecrypt for kekUser:");
764 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, kek, 3);
765 System.out.print("\nDecrypted content: ");
766 System.out.println(new String(receivedMessage));
767 } else {
768 // rsaUser1
769 System.out.println("\nDecrypt for rsaUser1:");
770 receivedMessage = getEnvelopedData(encodedEnvelopedData, rsaUser1_pk, 0);
771 System.out.print("\nDecrypted content: ");
772 System.out.println(new String(receivedMessage));
773 // rsaUser2
774 System.out.println("\nDecrypt for rsaUser2:");
775 receivedMessage = getEnvelopedData(encodedEnvelopedData, rsaUser2_pk, 1);
776 System.out.print("\nDecrypted content: ");
777 System.out.println(new String(receivedMessage));
778 // esdhUser1
779 System.out.println("\nDecrypt for esdhUser1:");
780 receivedMessage = getEnvelopedData(encodedEnvelopedData, esdhUser1_pk, 2);
781 System.out.print("\nDecrypted content: ");
782 System.out.println(new String(receivedMessage));
783 // esdhUser2
784 System.out.println("\nDecrypt for esdhUser2:");
785 receivedMessage = getEnvelopedData(encodedEnvelopedData, esdhUser2_pk, 2);
786 System.out.print("\nDecrypted content: ");
787 System.out.println(new String(receivedMessage));
788 // kekUser
789 System.out.println("\nDecrypt for kekUser:");
790 receivedMessage = getEnvelopedData(encodedEnvelopedData, kek, 3);
791 System.out.print("\nDecrypted content: ");
792 System.out.println(new String(receivedMessage));
793 }
794 }
795
796 /**
797 * Parses an EnvelopedData and decrypts the content for all test recipients
798 * using their recipient identifiers for identifying the recipient.
799 *
800 * @param stream whether to use EnvelopedDataStream or EnvelopedData
801 * @param encodedEnvelopedData the encoded EnvelopedData object
802 *
803 * @throws Exception if some error occurs during decoding/decryption
804 */
805 public void parseEnvelopedDataWithRecipientIdentifier(boolean stream, byte[] encodedEnvelopedData) throws Exception {
806 byte[] receivedMessage;
807 if (stream) {
808 // rsaUser1
809 System.out.println("\nDecrypt for rsaUser1:");
810 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, rsaUser1_pk, new IssuerAndSerialNumber(rsaUser1));
811 System.out.print("\nDecrypted content: ");
812 System.out.println(new String(receivedMessage));
813 // rsaUser2
814 System.out.println("\nDecrypt for rsaUser2:");
815 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, rsaUser2_pk, new SubjectKeyID(rsaUser2));
816 System.out.print("\nDecrypted content: ");
817 System.out.println(new String(receivedMessage));
818 // esdhUser1
819 System.out.println("\nDecrypt for esdhUser1:");
820 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, esdhUser1_pk, new IssuerAndSerialNumber(esdhUser1));
821 System.out.print("\nDecrypted content: ");
822 System.out.println(new String(receivedMessage));
823 // esdhUser2
824 System.out.println("\nDecrypt for esdhUser2:");
825 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, esdhUser2_pk, new RecipientKeyIdentifier(esdhUser2));
826 System.out.print("\nDecrypted content: ");
827 System.out.println(new String(receivedMessage));
828 // kekUser
829 System.out.println("\nDecrypt for kekUser:");
830 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, kek, new KEKIdentifier(kekID));
831 System.out.print("\nDecrypted content: ");
832 System.out.println(new String(receivedMessage));
833 } else {
834 // rsaUser1
835 System.out.println("\nDecrypt for rsaUser1:");
836 receivedMessage = getEnvelopedData(encodedEnvelopedData, rsaUser1_pk, new IssuerAndSerialNumber(rsaUser1));
837 System.out.print("\nDecrypted content: ");
838 System.out.println(new String(receivedMessage));
839 // rsaUser2
840 System.out.println("\nDecrypt for rsaUser2:");
841 receivedMessage = getEnvelopedData(encodedEnvelopedData, rsaUser2_pk, new SubjectKeyID(rsaUser2));
842 System.out.print("\nDecrypted content: ");
843 System.out.println(new String(receivedMessage));
844 // esdhUser1
845 System.out.println("\nDecrypt for esdhUser1:");
846 receivedMessage = getEnvelopedData(encodedEnvelopedData, esdhUser1_pk, new IssuerAndSerialNumber(esdhUser1));
847 System.out.print("\nDecrypted content: ");
848 System.out.println(new String(receivedMessage));
849 // esdhUser2
850 System.out.println("\nDecrypt for esdhUser2:");
851 receivedMessage = getEnvelopedData(encodedEnvelopedData, esdhUser2_pk, new RecipientKeyIdentifier(esdhUser2));
852 System.out.print("\nDecrypted content: ");
853 System.out.println(new String(receivedMessage));
854 // kekUser
855 System.out.println("\nDecrypt for kekUser:");
856 receivedMessage = getEnvelopedData(encodedEnvelopedData, kek, new KEKIdentifier(kekID));
857 System.out.print("\nDecrypted content: ");
858 System.out.println(new String(receivedMessage));
859 }
860 }
861
862 /**
863 * Parses an EnvelopedData and decrypts the content for all test recipients
864 * using their recipient certificate (for RecipientInfos of type KeyTransRecipientInfo
865 * or KeyAgreeRecipientInfo) or key id (for RecipientInfos of type KEKRecipientInfo)
866 * for identifying the recipient.
867 *
868 * @param stream whether to use EnvelopedDataStream or EnvelopedData
869 * @param encodedEnvelopedData the encoded EnvelopedData object
870 *
871 * @throws Exception if some error occurs during decoding/decryption
872 */
873 public void parseEnvelopedDataWithRecipientCertOrKEKId(boolean stream, byte[] encodedEnvelopedData) throws Exception {
874 byte[] receivedMessage;
875 if (stream) {
876 // rsaUser1
877 System.out.println("\nDecrypt for rsaUser1:");
878 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, rsaUser1_pk, rsaUser1, null);
879 System.out.print("\nDecrypted content: ");
880 System.out.println(new String(receivedMessage));
881 // rsaUser2
882 System.out.println("\nDecrypt for rsaUser2:");
883 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, rsaUser2_pk, rsaUser2, null);
884 System.out.print("\nDecrypted content: ");
885 System.out.println(new String(receivedMessage));
886 // esdhUser1
887 System.out.println("\nDecrypt for esdhUser1:");
888 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, esdhUser1_pk, esdhUser1, null);
889 System.out.print("\nDecrypted content: ");
890 System.out.println(new String(receivedMessage));
891 // esdhUser2
892 System.out.println("\nDecrypt for esdhUser2:");
893 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, esdhUser2_pk, esdhUser2, null);
894 System.out.print("\nDecrypted content: ");
895 System.out.println(new String(receivedMessage));
896 // kekUser
897 System.out.println("\nDecrypt for kekUser:");
898 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, kek, null, kekID);
899 System.out.print("\nDecrypted content: ");
900 System.out.println(new String(receivedMessage));
901 } else {
902 // rsaUser1
903 System.out.println("\nDecrypt for rsaUser1:");
904 receivedMessage = getEnvelopedData(encodedEnvelopedData, rsaUser1_pk, rsaUser1, null);
905 System.out.print("\nDecrypted content: ");
906 System.out.println(new String(receivedMessage));
907 // rsaUser2
908 System.out.println("\nDecrypt for rsaUser2:");
909 receivedMessage = getEnvelopedData(encodedEnvelopedData, rsaUser2_pk, rsaUser2, null);
910 System.out.print("\nDecrypted content: ");
911 System.out.println(new String(receivedMessage));
912 // esdhUser1
913 System.out.println("\nDecrypt for esdhUser1:");
914 receivedMessage = getEnvelopedData(encodedEnvelopedData, esdhUser1_pk, esdhUser1, null);
915 System.out.print("\nDecrypted content: ");
916 System.out.println(new String(receivedMessage));
917 // esdhUser2
918 System.out.println("\nDecrypt for esdhUser2:");
919 receivedMessage = getEnvelopedData(encodedEnvelopedData, esdhUser2_pk, esdhUser2, null);
920 System.out.print("\nDecrypted content: ");
921 System.out.println(new String(receivedMessage));
922 // kekUser
923 System.out.println("\nDecrypt for kekUser:");
924 receivedMessage = getEnvelopedData(encodedEnvelopedData, kek, null, kekID);
925 System.out.print("\nDecrypted content: ");
926 System.out.println(new String(receivedMessage));
927 }
928 }
929
930 /**
931 * Checks the decrypted message.
932 *
933 * @param decryptedMessage the decrypted message
934 * @param testMessage the original message
935 *
936 * @throws CMSException if decrypted and original message do not match
937 */
938 private void checkDecryptedMessage(byte[] decryptedMessage, byte[] testMessage) throws CMSException {
939 if (CryptoUtils.equalsBlock(decryptedMessage, testMessage) == false) {
940 throw new CMSException("Decrypted content not equal to original one!");
941 }
942 }
943
944 /**
945 * Starts the test.
946 */
947 public void start() {
948
949 // AES-GCM
950 AlgorithmID contentAuthEncAlg = (AlgorithmID)AlgorithmID.aes256_GCM.clone();
951 start(contentAuthEncAlg);
952
953 // AES-CCM
954 contentAuthEncAlg = (AlgorithmID)AlgorithmID.aes256_CCM.clone();
955 start(contentAuthEncAlg);
956
957 // ChaCha20Poly1305
958 contentAuthEncAlg = (AlgorithmID)AlgorithmID.chacha20Poly1305.clone();
959 start(contentAuthEncAlg);
960 }
961
962 /**
963 * Starts the test for the given content-authenticated encryption algorithm.
964 *
965 * @param contentAuthEncAlg the id of the content-authenticated encryption algorithm
966 */
967 public void start(AlgorithmID contentAuthEncAlg) {
968 // the test message
969 byte[] message = test_message;
970
971 try {
972 byte[] encodedEnvelopedData;
973
974 // the stream implementation
975 System.out.println("Stream implementation demos");
976 System.out.println("===========================");
977
978 //
979 // test CMS EnvelopedDataStream
980 //
981 System.out.println("\nCMS EnvelopedDataStream demo [create]:\n");
982 encodedEnvelopedData = createEnvelopedDataStream(message, (AlgorithmID)contentAuthEncAlg.clone());
983 // transmit data
984 System.out.println("\nCMS EnvelopedDataStream demo [parse]:\n");
985 System.out.println("Decrypt for the several recipients using their index into the recipientInfos field.");
986 parseEnvelopedDataWithRecipientInfoIndex(true, encodedEnvelopedData);
987 System.out.println("Decrypt for the several recipients using their RecipientIdentifier.");
988 parseEnvelopedDataWithRecipientIdentifier(true, encodedEnvelopedData);
989 System.out.println("Decrypt for the several recipients using their certificate or symmetric kek.");
990 parseEnvelopedDataWithRecipientCertOrKEKId(true, encodedEnvelopedData);
991
992 // the output stream implementation
993 System.out.println("Output Stream implementation demos");
994 System.out.println("==================================");
995
996 //
997 // test CMS EnvelopedDataOutputStream
998 //
999 System.out.println("\nCMS EnvelopedDataOutputStream demo [create]:\n");
1000 encodedEnvelopedData = createEnvelopedDataOutputStream(message, (AlgorithmID)contentAuthEncAlg.clone());
1001 // transmit data
1002 System.out.println("\nCMS EnvelopedDataOutputStream demo [parse]:\n");
1003 System.out.println("Decrypt for the several recipients using their index into the recipientInfos field.");
1004 parseEnvelopedDataWithRecipientInfoIndex(true, encodedEnvelopedData);
1005 System.out.println("Decrypt for the several recipients using their RecipientIdentifier.");
1006 parseEnvelopedDataWithRecipientIdentifier(true, encodedEnvelopedData);
1007 System.out.println("Decrypt for the several recipients using their certificate or symmetric kek.");
1008 parseEnvelopedDataWithRecipientCertOrKEKId(true, encodedEnvelopedData);
1009
1010
1011 // the non-stream implementation
1012 System.out.println("\nNon-stream implementation demos");
1013 System.out.println("===============================");
1014
1015
1016 //
1017 // test CMS EnvelopedData
1018 //
1019 System.out.println("\nCMS EnvelopedData demo [create]:\n");
1020 encodedEnvelopedData = createEnvelopedData(message, (AlgorithmID)contentAuthEncAlg.clone());
1021 // transmit data
1022 System.out.println("\nCMS EnvelopedData demo [parse]:\n");
1023 System.out.println("Decrypt for the several recipients using their index into the recipientInfos field.");
1024 parseEnvelopedDataWithRecipientInfoIndex(false, encodedEnvelopedData);
1025 System.out.println("Decrypt for the several recipients using their RecipientIdentifier.");
1026 parseEnvelopedDataWithRecipientIdentifier(false, encodedEnvelopedData);
1027 System.out.println("Decrypt for the several recipients using their certificate or symmetric kek.");
1028 parseEnvelopedDataWithRecipientCertOrKEKId(false, encodedEnvelopedData);
1029
1030
1031 } catch (Exception ex) {
1032 ex.printStackTrace();
1033 throw new RuntimeException(ex.toString());
1034 }
1035 }
1036
1037 /**
1038 * Main method.
1039 *
1040 * @throws IOException
1041 * if an I/O error occurs when reading required keys
1042 * and certificates from files
1043 */
1044 public static void main(String argv[]) throws Exception {
1045
1046 DemoUtil.initDemos();
1047
1048 (new EnvelopedDataDemoAEAD()).start();
1049 System.out.println("\nReady!");
1050 DemoUtil.waitKey();
1051 }
1052 }