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 }