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