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