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