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