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