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/ecc/ECDHEnvelopedDataDemo.java 27 12.02.25 17:58 Dbratko $ 029// $Revision: 27 $ 030// 031 032 033package demo.cms.ecc; 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; 044 045import javax.crypto.SecretKey; 046 047import demo.DemoUtil; 048import demo.cms.ecc.keystore.CMSEccKeyStore; 049import iaik.asn1.ObjectID; 050import iaik.asn1.structures.AlgorithmID; 051import iaik.cms.CMSAlgorithmID; 052import iaik.cms.CMSException; 053import iaik.cms.CertificateIdentifier; 054import iaik.cms.ContentInfo; 055import iaik.cms.ContentInfoOutputStream; 056import iaik.cms.ContentInfoStream; 057import iaik.cms.EncryptedContentInfo; 058import iaik.cms.EncryptedContentInfoStream; 059import iaik.cms.EnvelopedData; 060import iaik.cms.EnvelopedDataOutputStream; 061import iaik.cms.EnvelopedDataStream; 062import iaik.cms.IssuerAndSerialNumber; 063import iaik.cms.KeyAgreeRecipientInfo; 064import iaik.cms.KeyIdentifier; 065import iaik.cms.RecipientInfo; 066import iaik.cms.RecipientKeyIdentifier; 067import iaik.security.random.SecRandom; 068import iaik.utils.Util; 069import iaik.x509.X509Certificate; 070 071/** 072 * Demonstrates the usage of class {@link iaik.cms.EnvelopedDataStream} and 073 * {@link iaik.cms.EnvelopedData} for encrypting data using the CMS type 074 * EnvelopedData by using Ephemeral-Static ECDH according to <a href = 075 * "http://www.ietf.org/rfc/rfc3278.txt" target="_blank">3278</a> as 076 * key agreement method. 077 * <p> 078 * Any keys/certificates required for this demo are read from a keystore 079 * file "cmsecc.keystore" located in your current working directory. If 080 * the keystore file does not exist you can create it by running the 081 * {@link demo.cms.ecc.keystore.SetupCMSEccKeyStore SetupCMSEccKeyStore} 082 * program. 083 * <p> 084 * Additionally to <code>iaik_cms.jar</code> you also must have 085 * <code>iaik_jce_(full).jar</code> (IAIK-JCE, <a href = 086 * "https://sic.tech/products/core-crypto-toolkits/jca-jce/" target="_blank"> 087 * https://sic.tech/products/core-crypto-toolkits/jca-jce/</a>), 088 * and <code>iaik_eccelarate.jar</code> (IAIK-ECCelerate<sup><small>TM</small></sup>, <a href = 089 * "https://sic.tech/products/core-crypto-toolkits/eccelerate/" target="_blank"> 090 * https://sic.tech/products/core-crypto-toolkits/eccelerate/</a>) 091 * in your classpath. 092 * 093 * @see iaik.cms.EnvelopedDataStream 094 * @see iaik.cms.EnvelopedData 095 * @see iaik.cms.RecipientInfo 096 * @see iaik.cms.KeyAgreeRecipientInfo 097 * @see demo.cms.ecc.keystore.SetupCMSEccKeyStore 098 */ 099public class ECDHEnvelopedDataDemo { 100 101 // certificate of ecdhUser 1 102 X509Certificate ecdhUser1; 103 // private key of ecdhUser 1 104 PrivateKey ecdhUser1_pk; 105 // certificate of ecdhUser 2 106 X509Certificate ecdhUser2; 107 // private key of ecdhUser 2 108 PrivateKey ecdhUser2_pk; 109 110 // secure random number generator 111 SecureRandom random; 112 113 /** 114 * Setup the demo certificate chains. 115 * 116 * Keys and certificates are retrieved from the demo keyStore file 117 * "cmsecc.keystore" located in your current working directory. If 118 * the keystore file does not exist you can create it by running the 119 * {@link demo.cms.ecc.keystore.SetupCMSEccKeyStore SetupCMSEccKeyStore} 120 * program. 121 * 122 * @throws IOException if keys/certificates cannot be read from the keystore 123 */ 124 public ECDHEnvelopedDataDemo() throws IOException { 125 126 System.out.println(); 127 System.out.println("**********************************************************************************"); 128 System.out.println("* ECDHEnvelopedData demo *"); 129 System.out.println("* (shows the usage of the CMS EnvelopedData type implementation for ECDH) *"); 130 System.out.println("**********************************************************************************"); 131 System.out.println(); 132 133 // add all certificates to the list 134 135 ecdhUser1 = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_192_CRYPT_1)[0]; 136 ecdhUser1_pk = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_192_CRYPT_1); 137 ecdhUser2 = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_192_CRYPT_2)[0]; 138 ecdhUser2_pk = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_192_CRYPT_2); 139 140 random = SecRandom.getDefault(); 141 142 } 143 144 /** 145 * Creates a CMS <code>EnvelopedDataStream</code> message. 146 * 147 * @param message the message to be enveloped, as byte representation 148 * @return the DER encoding of the <code>EnvelopedData</code> object just created 149 * @throws CMSException if the <code>EnvelopedData</code> object cannot 150 * be created 151 * @throws IOException if an I/O error occurs 152 */ 153 public byte[] createEnvelopedDataStream(byte[] message) throws CMSException, IOException { 154 155 EnvelopedDataStream enveloped_data; 156 157 // we are testing the stream interface 158 ByteArrayInputStream is = new ByteArrayInputStream(message); 159 // create a new EnvelopedData object encrypted with AES 160 try { 161 enveloped_data = new EnvelopedDataStream(is, (AlgorithmID)AlgorithmID.aes256_CBC.clone()); 162 } catch (NoSuchAlgorithmException ex) { 163 throw new CMSException(ex.toString()); 164 } 165 166 167 // create the recipient infos 168 RecipientInfo[] recipients = createRecipients(); 169 // specify the recipients of the encrypted message 170 enveloped_data.setRecipientInfos(recipients); 171 172 // return the EnvelopedDate as DER encoded byte array with block size 4 173 // (just for testing; in real application we will use a proper blocksize, 174 // e.g. 2048, 4096,..) 175 enveloped_data.setBlockSize(4); 176 ByteArrayOutputStream os = new ByteArrayOutputStream(); 177 ContentInfoStream cis = new ContentInfoStream(enveloped_data); 178 cis.writeTo(os); 179 return os.toByteArray(); 180 } 181 182 /** 183 * Creates a CMS <code>EnvelopedData</code> message using the 184 * {@link iaik.cms.EnvelopedDataOutputStream EnvelopedDataOutputStream} 185 * class. 186 * 187 * @param message the message to be enveloped, as byte representation 188 * @return the DER encoding of the <code>EnvelopedData</code> object just created 189 * @throws CMSException if the <code>EnvelopedData</code> object cannot 190 * be created 191 * @throws IOException if an I/O error occurs 192 */ 193 public byte[] createEnvelopedDataOutputStream(byte[] message) throws CMSException, IOException { 194 195 EnvelopedDataStream enveloped_data; 196 197 // a stream from which to read the data to be encrypted 198 ByteArrayInputStream is = new ByteArrayInputStream(message); 199 200 // the stream to which to write the EnvelopedData 201 ByteArrayOutputStream resultStream = new ByteArrayOutputStream(); 202 EnvelopedDataOutputStream envelopedData; 203 204 // wrap EnvelopedData into a ContentInfo 205 ContentInfoOutputStream contentInfoStream = 206 new ContentInfoOutputStream(ObjectID.cms_envelopedData, resultStream); 207 // create a new EnvelopedData object encrypted with AES 208 try { 209 envelopedData = new EnvelopedDataOutputStream(contentInfoStream, 210 (AlgorithmID)AlgorithmID.aes256_CBC.clone()); 211 } catch (NoSuchAlgorithmException ex) { 212 throw new CMSException(ex.toString()); 213 } 214 215 216 // create the recipient infos 217 RecipientInfo[] recipients = createRecipients(); 218 /// specify the recipients of the encrypted message 219 envelopedData.setRecipientInfos(recipients); 220 221 int blockSize = 4; // in real world we would use a block size like 2048 222 // write in the data to be encrypted 223 byte[] buffer = new byte[blockSize]; 224 int bytesRead; 225 while ((bytesRead = is.read(buffer)) != -1) { 226 envelopedData.write(buffer, 0, bytesRead); 227 } 228 229 // closing the stream finishes encryption and closes the underlying stream 230 envelopedData.close(); 231 return resultStream.toByteArray(); 232 } 233 234 /** 235 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for 236 * the recipient identified by its index into the recipientInfos field. 237 * 238 * @param encoding the <code>EnvelopedData</code> object as DER encoded byte array 239 * @param key the key to decrypt the message 240 * @param recipientInfoIndex the index into the <code>RecipientInfo</code> array 241 * to which the specified key belongs 242 * 243 * @return the recovered message, as byte array 244 * @throws CMSException if the message cannot be recovered 245 * @throws IOException if a stream read/write error occurs 246 */ 247 public byte[] getEnvelopedDataStream(byte[] encoding, Key key, int recipientInfoIndex) 248 throws CMSException, IOException { 249 250 // create the EnvelopedData object from a DER encoded byte array 251 // we are testing the stream interface 252 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 253 EnvelopedDataStream enveloped_data = new EnvelopedDataStream(is); 254 255 System.out.println("Information about the encrypted data:"); 256 EncryptedContentInfoStream eci = (EncryptedContentInfoStream)enveloped_data.getEncryptedContentInfo(); 257 System.out.println("Content type: "+eci.getContentType().getName()); 258 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 259 260 System.out.println("\nThis message can be decrypted by the owners of the following certificates:"); 261 RecipientInfo[] recipients = enveloped_data.getRecipientInfos(); 262 263 // for demonstration purposes we only look one time for all recipients included: 264 if (recipientInfoIndex == 0) { 265 int k = 0; 266 for (int i=0; i<recipients.length; i++) { 267 KeyIdentifier[] recipientIDs = recipients[i].getRecipientIdentifiers(); 268 for (int j = 0; j < recipientIDs.length; j++) { 269 System.out.println("Recipient "+(++k)+":"); 270 System.out.println(recipientIDs[j]); 271 } 272 } 273 } 274 // decrypt the message for the first recipient 275 try { 276 enveloped_data.setupCipher(key, recipientInfoIndex); 277 InputStream decrypted = enveloped_data.getInputStream(); 278 ByteArrayOutputStream os = new ByteArrayOutputStream(); 279 Util.copyStream(decrypted, os, null); 280 281 return os.toByteArray(); 282 283 } catch (InvalidKeyException ex) { 284 throw new CMSException("Private key error: "+ex.getMessage()); 285 } catch (NoSuchAlgorithmException ex) { 286 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage()); 287 } 288 } 289 290 /** 291 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for 292 * the recipient identified by recipient identifier. 293 * 294 * @param encoding the <code>EnvelopedData</code> object as DER encoded byte array 295 * @param key the key to decrypt the message 296 * @param recipientID the recipient identifier uniquely identifying the key of the 297 * recipient 298 * 299 * @return the recovered message, as byte array 300 * @throws CMSException if the message cannot be recovered 301 * @throws IOException if a stream read/write error occurs 302 */ 303 public byte[] getEnvelopedDataStream(byte[] encoding, Key key, KeyIdentifier recipientID) 304 throws CMSException, IOException { 305 306 // create the EnvelopedData object from a DER encoded byte array 307 // we are testing the stream interface 308 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 309 EnvelopedDataStream enveloped_data = new EnvelopedDataStream(is); 310 311 System.out.println("Information about the encrypted data:"); 312 EncryptedContentInfoStream eci = (EncryptedContentInfoStream)enveloped_data.getEncryptedContentInfo(); 313 System.out.println("Content type: "+eci.getContentType().getName()); 314 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 315 316 // get the right RecipientInfo 317 System.out.println("\nSearch for RecipientInfo:"); 318 RecipientInfo recipient = enveloped_data.getRecipientInfo(recipientID); 319 if (recipient != null) { 320 System.out.println("RecipientInfo: " + recipient); 321 } else { 322 throw new CMSException("No recipient with ID: " + recipientID); 323 } 324 // decrypt the content encryption key and the content 325 try { 326 System.out.println("Decrypt encrypted content encryption key..."); 327 SecretKey cek = recipient.decryptKey(key, recipientID); 328 System.out.println("Decrypt content with decrypted content encryption key..."); 329 enveloped_data.setupCipher(cek); 330 InputStream decrypted = enveloped_data.getInputStream(); 331 ByteArrayOutputStream os = new ByteArrayOutputStream(); 332 Util.copyStream(decrypted, os, null); 333 334 return os.toByteArray(); 335 336 } catch (InvalidKeyException ex) { 337 throw new CMSException("Private key error: "+ex.getMessage()); 338 } catch (NoSuchAlgorithmException ex) { 339 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage()); 340 } 341 } 342 343 // non stream 344 345 /** 346 * Creates a CMS <code>EnvelopedData</code> message. 347 * 348 * @param message the message to be enveloped, as byte representation 349 * 350 * @return the encoded <code>EnvelopedData</code>, as byte array 351 * 352 * @throws CMSException if the <code>EnvelopedData</code> object cannot 353 * be created 354 */ 355 public byte[] createEnvelopedData(byte[] message) throws CMSException { 356 357 EnvelopedData enveloped_data; 358 359 // create a new EnvelopedData object encrypted with AES 360 try { 361 enveloped_data = new EnvelopedData(message, (AlgorithmID)AlgorithmID.aes256_CBC.clone()); 362 } catch (NoSuchAlgorithmException ex) { 363 throw new CMSException(ex.toString()); 364 } 365 366 // set the RecipientInfos 367 RecipientInfo[] recipients = createRecipients(); 368 enveloped_data.setRecipientInfos(recipients); 369 370 // return encoded EnvelopedData 371 // wrap into contentInfo 372 ContentInfo ci = new ContentInfo(enveloped_data); 373 return ci.getEncoded(); 374 } 375 376 377 /** 378 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for 379 * the recipient identified by its index into the recipientInfos field. 380 * 381 * @param enc the encoded <code>EnvelopedData</code> 382 * @param key the key to decrypt the message 383 * @param recipientInfoIndex the index into the <code>RecipientInfo</code> array 384 * to which the specified key belongs 385 * 386 * @return the recovered message, as byte array 387 * 388 * @throws CMSException if the message cannot be recovered 389 * @throws IOException if an I/O error occurs 390 */ 391 public byte[] getEnvelopedData(byte[] enc, Key key, int recipientInfoIndex) 392 throws CMSException, IOException { 393 ByteArrayInputStream bais = new ByteArrayInputStream(enc); 394 EnvelopedData enveloped_data = new EnvelopedData(bais); 395 396 System.out.println("Information about the encrypted data:"); 397 EncryptedContentInfo eci = (EncryptedContentInfo)enveloped_data.getEncryptedContentInfo(); 398 System.out.println("Content type: "+eci.getContentType().getName()); 399 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 400 401 System.out.println("\nThis message can be decrypted by the owners of the following certificates:"); 402 RecipientInfo[] recipients = enveloped_data.getRecipientInfos(); 403 404 // for demonstration purposes we only look one time for all recipients included: 405 if (recipientInfoIndex == 0) { 406 int k = 0; 407 for (int i=0; i<recipients.length; i++) { 408 KeyIdentifier[] recipientIDs = recipients[i].getRecipientIdentifiers(); 409 for (int j = 0; j < recipientIDs.length; j++) { 410 System.out.println("Recipient "+(++k)+":"); 411 System.out.println(recipientIDs[j]); 412 } 413 } 414 } 415 416 // decrypt the message 417 try { 418 enveloped_data.setupCipher(key, recipientInfoIndex); 419 return enveloped_data.getContent(); 420 421 } catch (InvalidKeyException ex) { 422 throw new CMSException("Private key error: "+ex.getMessage()); 423 } catch (NoSuchAlgorithmException ex) { 424 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage()); 425 } 426 } 427 428 /** 429 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for 430 * the recipient identified by recipient identifier. 431 * <p> 432 * This way of decrypting the content may be used for any type of RecipientInfo 433 * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo). The 434 * recipient in mind is identified by its recipient identifier. 435 * 436 * @param enc the encoded <code>AuthenticatedData</code> 437 * @param key the key to decrypt the message 438 * @param recipientID the recipient identifier uniquely identifying the key of the 439 * recipient 440 * 441 * @return the recovered message, as byte array 442 * @throws CMSException if the message cannot be recovered 443 * @throws IOException if an I/O error occurs 444 */ 445 public byte[] getEnvelopedData(byte[] enc, Key key, KeyIdentifier recipientID) 446 throws CMSException, IOException { 447 ByteArrayInputStream bais = new ByteArrayInputStream(enc); 448 EnvelopedData enveloped_data = new EnvelopedData(bais); 449 450 System.out.println("Information about the encrypted data:"); 451 EncryptedContentInfo eci = (EncryptedContentInfo)enveloped_data.getEncryptedContentInfo(); 452 System.out.println("Content type: "+eci.getContentType().getName()); 453 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 454 455 System.out.println("\nThis message can be decrypted by the owners of the following certificates:"); 456 457 // get the right RecipientInfo 458 System.out.println("\nSearch for RecipientInfo:"); 459 RecipientInfo recipient = enveloped_data.getRecipientInfo(recipientID); 460 if (recipient != null) { 461 System.out.println("RecipientInfo: " + recipient); 462 } else { 463 throw new CMSException("No recipient with ID: " + recipientID); 464 } 465 // decrypt the content encryption key and the content 466 try { 467 System.out.println("Decrypt encrypted content encryption key..."); 468 SecretKey cek = recipient.decryptKey(key, recipientID); 469 System.out.println("Decrypt content with decrypted content encryption key..."); 470 enveloped_data.setupCipher(cek); 471 return enveloped_data.getContent(); 472 473 } catch (InvalidKeyException ex) { 474 throw new CMSException("Private key error: "+ex.getMessage()); 475 } catch (NoSuchAlgorithmException ex) { 476 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage()); 477 } 478 } 479 480 /** 481 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for 482 * the recipient identified by its recipient certificate. 483 * 484 * @param enc the encoded <code>EnvelopedData</code> 485 * @param key the key to decrypt the message 486 * @param recipientCert the certificate of the recipient 487 * 488 * @return the recovered message, as byte array 489 * 490 * @throws CMSException if the message cannot be recovered 491 */ 492 public byte[] getEnvelopedData(byte[] enc, Key key, X509Certificate recipientCert) 493 throws CMSException, IOException { 494 ByteArrayInputStream bais = new ByteArrayInputStream(enc); 495 EnvelopedData enveloped_data = new EnvelopedData(bais); 496 497 System.out.println("Information about the encrypted data:"); 498 EncryptedContentInfo eci = (EncryptedContentInfo)enveloped_data.getEncryptedContentInfo(); 499 System.out.println("Content type: "+eci.getContentType().getName()); 500 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 501 502 System.out.println("\nThis message can be decrypted by the owners of the following certificates:"); 503 504 // decrypt the content encryption key and the content 505 try { 506 System.out.println("Decrypt the content..."); 507 enveloped_data.setupCipher(key, recipientCert); 508 return enveloped_data.getContent(); 509 510 } catch (InvalidKeyException ex) { 511 throw new CMSException("Private key error: "+ex.getMessage()); 512 } catch (NoSuchAlgorithmException ex) { 513 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage()); 514 } 515 } 516 517 /** 518 * Creates the RecipientInfos. 519 * 520 * @return the RecipientInfos created, two KeyAgreeRecipientInfos 521 * 522 * @throws CMSException if an error occurs when creating the recipient infos 523 */ 524 public RecipientInfo[] createRecipients() throws CMSException { 525 526 RecipientInfo[] recipients = new RecipientInfo[2]; 527 try { 528 // recipients use key agreement 529 // the key encryption (key agreement) algorithm to use: 530 AlgorithmID keyEA1 = (AlgorithmID)CMSAlgorithmID.dhSinglePass_stdDH_sha256kdf_scheme.clone(); 531 // the key wrap algorithm to use: 532 AlgorithmID keyWrapAlg1 = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone(); 533 // the length of the key encryption key to be generated: 534 int kekLength1 = 256; 535 recipients[0] = new KeyAgreeRecipientInfo(keyEA1, keyWrapAlg1, kekLength1); 536 // ecdhUser1 is the first receiver (cert identified by IssuerAndSerialNumber) 537 ((KeyAgreeRecipientInfo)recipients[0]).addRecipient(ecdhUser1, CertificateIdentifier.ISSUER_AND_SERIALNUMBER); 538 539 // ecdhUser2 is the second receiver (cert identified by RecipientKeyIdentifier) 540 // the key encryption (key agreement) algorithm to use (just for demonstration purposes we use a second KeyAgreeRecipeintInfo): 541 AlgorithmID keyEA2 = (AlgorithmID)CMSAlgorithmID.dhSinglePass_stdDH_sha256kdf_scheme.clone(); 542 // the key wrap algorithm to use: 543 AlgorithmID keyWrapAlg2 = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone(); 544 // the length of the key encryption key to be generated: 545 int kekLength2 = 256; 546 recipients[1] = new KeyAgreeRecipientInfo(keyEA2, keyWrapAlg2, kekLength2); 547 // ecdhUser1 is the first receiver (cert identified by RecipientKeyIdentifier) 548 ((KeyAgreeRecipientInfo)recipients[1]).addRecipient(ecdhUser2, CertificateIdentifier.RECIPIENT_KEY_IDENTIFIER); 549 550 } catch (Exception ex) { 551 throw new CMSException("Error adding recipients: " + ex.toString()); 552 } 553 return recipients; 554 } 555 556 /** 557 * Parses an EnvelopedData and decrypts the content for all test recipients 558 * using the index into the recipientInfos field for identifying the recipient. 559 * 560 * @param stream whether to use EnvelopedDataStream or EnvelopedData 561 * @param encodedEnvelopedData the encoded EnvelopedData object 562 * 563 * @throws Exception if some error occurs during decoding/decryption 564 */ 565 public void parseEnvelopedDataWithRecipientInfoIndex(boolean stream, byte[] encodedEnvelopedData) throws Exception { 566 byte[] receivedMessage; 567 if (stream) { 568 // ecdhUser1 569 System.out.println("\nDecrypt for ecdhUser1:"); 570 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, ecdhUser1_pk, 0); 571 System.out.print("\nDecrypted content: "); 572 System.out.println(new String(receivedMessage)); 573 // ecdhUser2 574 System.out.println("\nDecrypt for ecdhUser2:"); 575 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, ecdhUser2_pk, 1); 576 System.out.print("\nDecrypted content: "); 577 System.out.println(new String(receivedMessage)); 578 } else { 579 // ecdhUser1 580 System.out.println("\nDecrypt for ecdhUser1:"); 581 receivedMessage = getEnvelopedData(encodedEnvelopedData, ecdhUser1_pk, 0); 582 System.out.print("\nDecrypted content: "); 583 System.out.println(new String(receivedMessage)); 584 // ecdhUser2 585 System.out.println("\nDecrypt for ecdhUser2:"); 586 receivedMessage = getEnvelopedData(encodedEnvelopedData, ecdhUser2_pk, 1); 587 System.out.print("\nDecrypted content: "); 588 System.out.println(new String(receivedMessage)); 589 } 590 } 591 592 /** 593 * Parses an EnvelopedData and decrypts the content for all test recipients 594 * using their recipient identifiers for identifying the recipient. 595 * 596 * @param stream whether to use EnvelopedDataStream or EnvelopedData 597 * @param encodedEnvelopedData the encoded EnvelopedData object 598 * 599 * @throws Exception if some error occurs during decoding/decryption 600 */ 601 public void parseEnvelopedDataWithRecipientIdentifier(boolean stream, byte[] encodedEnvelopedData) throws Exception { 602 byte[] receivedMessage; 603 if (stream) { 604 // ecdhUser1 605 System.out.println("\nDecrypt for ecdhUser1:"); 606 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, ecdhUser1_pk, new IssuerAndSerialNumber(ecdhUser1)); 607 System.out.print("\nDecrypted content: "); 608 System.out.println(new String(receivedMessage)); 609 // ecdhUser2 610 System.out.println("\nDecrypt for ecdhUser2:"); 611 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, ecdhUser2_pk, new RecipientKeyIdentifier(ecdhUser2)); 612 System.out.print("\nDecrypted content: "); 613 System.out.println(new String(receivedMessage)); 614 } else { 615 // ecdhUser1 616 System.out.println("\nDecrypt for ecdhUser1:"); 617 receivedMessage = getEnvelopedData(encodedEnvelopedData, ecdhUser1_pk, new IssuerAndSerialNumber(ecdhUser1)); 618 System.out.print("\nDecrypted content: "); 619 System.out.println(new String(receivedMessage)); 620 // ecdhUser2 621 System.out.println("\nDecrypt for ecdhUser2:"); 622 receivedMessage = getEnvelopedData(encodedEnvelopedData, ecdhUser2_pk, new RecipientKeyIdentifier(ecdhUser2)); 623 System.out.print("\nDecrypted content: "); 624 System.out.println(new String(receivedMessage)); 625 } 626 } 627 628 629 630 /** 631 * Starts the test. 632 */ 633 public void start() { 634 // the test message 635 String m = "This is the test message."; 636 System.out.println("Test message: \""+m+"\""); 637 System.out.println(); 638 byte[] message = m.getBytes(); 639 640 try { 641 byte[] encoding; 642 System.out.println("Stream implementation demos"); 643 System.out.println("==========================="); 644 645 646 // the stream implementation 647 // 648 // test CMS EnvelopedDataStream 649 // 650 System.out.println("\nCMS EnvelopedDataStream demo [create]:\n"); 651 encoding = createEnvelopedDataStream(message); 652 // transmit data 653 System.out.println("\nCMS EnvelopedDataStream demo [parse]:\n"); 654 System.out.println("Decrypt for the several recipients using their index into the recipientInfos field."); 655 parseEnvelopedDataWithRecipientInfoIndex(true, encoding); 656 System.out.println("Decrypt for the several recipients using their RecipientIdentifier."); 657 parseEnvelopedDataWithRecipientIdentifier(true, encoding); 658 659 660 System.out.println("\nOutputStream implementation demos"); 661 System.out.println("================================="); 662 663 664 // the output stream implementation 665 // 666 // test CMS EnvelopedDataOutputStream 667 // 668 System.out.println("\nCMS EnvelopedDataOutputStream demo [create]:\n"); 669 encoding = createEnvelopedDataOutputStream(message); 670 // transmit data 671 System.out.println("\nCMS EnvelopedDataStream demo [parse]:\n"); 672 System.out.println("Decrypt for the several recipients using their index into the recipientInfos field."); 673 parseEnvelopedDataWithRecipientInfoIndex(true, encoding); 674 System.out.println("Decrypt for the several recipients using their RecipientIdentifier."); 675 parseEnvelopedDataWithRecipientIdentifier(true, encoding); 676 677 // the non-stream implementation 678 System.out.println("\nNon-stream implementation demos"); 679 System.out.println("==============================="); 680 681 682 // 683 // test CMS EnvelopedData 684 // 685 System.out.println("\nCMS EnvelopedData demo [create]:\n"); 686 encoding = createEnvelopedData(message); 687 // transmit data 688 System.out.println("\nCMS EnvelopedData demo [parse]:\n"); 689 System.out.println("Decrypt for the several recipients using their index into the recipientInfos field."); 690 parseEnvelopedDataWithRecipientInfoIndex(false, encoding); 691 System.out.println("Decrypt for the several recipients using their RecipientIdentifier."); 692 parseEnvelopedDataWithRecipientIdentifier(false, encoding); 693 694 695 696 } catch (Exception ex) { 697 ex.printStackTrace(); 698 throw new RuntimeException(ex.toString()); 699 } 700 } 701 702 /** 703 * Main method. 704 * 705 * @throws IOException 706 * if an I/O error occurs when reading required keys 707 * and certificates from the keystore file 708 */ 709 public static void main(String argv[]) throws Exception { 710 711 DemoUtil.initDemos(); 712 ECCDemoUtil.installIaikEccProvider(); 713 (new ECDHEnvelopedDataDemo()).start(); 714 System.out.println("\nReady!"); 715 System.in.read(); 716 } 717}