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