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