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/authenticatedData/AuthenticatedDataDemo.java 25 12.02.25 17:58 Dbratko $ 029// $Revision: 25 $ 030 031package demo.cms.authenticatedData; 032 033 034import java.io.ByteArrayInputStream; 035import java.io.ByteArrayOutputStream; 036import java.io.IOException; 037import java.io.InputStream; 038import java.security.InvalidKeyException; 039import java.security.Key; 040import java.security.NoSuchAlgorithmException; 041import java.security.PrivateKey; 042import java.security.SecureRandom; 043 044import javax.crypto.KeyGenerator; 045import javax.crypto.SecretKey; 046 047import demo.DemoUtil; 048import demo.keystore.CMSKeyStore; 049import iaik.asn1.ObjectID; 050import iaik.asn1.structures.AlgorithmID; 051import iaik.asn1.structures.Attribute; 052import iaik.cms.AuthenticatedData; 053import iaik.cms.AuthenticatedDataStream; 054import iaik.cms.CMSAlgorithmID; 055import iaik.cms.CMSException; 056import iaik.cms.CertificateIdentifier; 057import iaik.cms.ContentInfo; 058import iaik.cms.ContentInfoStream; 059import iaik.cms.IssuerAndSerialNumber; 060import iaik.cms.KEKIdentifier; 061import iaik.cms.KEKRecipientInfo; 062import iaik.cms.KeyAgreeRecipientInfo; 063import iaik.cms.KeyIdentifier; 064import iaik.cms.KeyTransRecipientInfo; 065import iaik.cms.OriginatorInfo; 066import iaik.cms.RecipientInfo; 067import iaik.cms.RecipientKeyIdentifier; 068import iaik.cms.SecurityProvider; 069import iaik.cms.SubjectKeyID; 070import iaik.cms.attributes.CMSContentType; 071import iaik.security.random.SecRandom; 072import iaik.utils.Util; 073import iaik.x509.X509Certificate; 074 075/** 076 * Demonstrates the usage of class {@link iaik.cms.AuthenticatedDataStream} and 077 * {@link iaik.cms.AuthenticatedData} for recipient-specific protecting the 078 * integrity of a message using the CMS type AuthenticatedData. 079 * <p> 080 * This demo requires that you have <code>iaik_esdh.jar</code> 081 * (or <code>iaik_jce_full.jar</code>) in your classpath. 082 * You can download it from <a href="https://sic.tech/products/core-crypto-toolkits/jca-jce/" target="_blank"> 083 * https://sic.tech/products/core-crypto-toolkits/jca-jce/</a>. 084 * 085 * 086 * @see iaik.cms.AuthenticatedDataStream 087 * @see iaik.cms.AuthenticatedData 088 * 089 */ 090public class AuthenticatedDataDemo { 091 092 // certificate of rsaUser 1 093 X509Certificate rsaUser1Cert_; 094 // private key of rsaUser 1 095 PrivateKey rsaUser1PrivKey_; 096 // certificate of rsaUser 2 097 X509Certificate rsaUser2Cert_; 098 // private key of rsaUser 2 099 PrivateKey rsaUser2PrivKey_; 100 101 // certificate of (originator) User 1 (static-static Diffie-Hellman) 102 X509Certificate ssdhUser1Cert_; 103 X509Certificate[] originatorCerts_; 104 // private key of SSDH User 1 105 PrivateKey ssdhUser1PrivKey_; 106 // certificate of SSDH User 2 (static-static Diffie-Hellman) 107 X509Certificate ssdhUser2Cert_; 108 // private key of SSDH User 2 109 PrivateKey ssdhUser2PrivKey_; 110 111 // key wrap algorithm to be used 112 AlgorithmID keyWrapAlg_; 113 // kek length 114 int kekLength_; 115 // key encryption key for KEKRecipientInfo 116 SecretKey kek_; 117 byte[] kekID_; 118 119 120 // secure random number generator 121 SecureRandom random_; 122 123 /** 124 * Creates and AuthenticatedDataDemo object and setups the demo certificates. 125 * 126 * Keys and certificate are retrieved from the demo KeyStore which 127 * has to be located in your current working directory and may be 128 * created by running {@link demo.keystore.SetupCMSKeyStore 129 * SetupCMSKeyStore}. 130 * <p> 131 * CMS-AES256-Wrap is used as key wrap algorithm. 132 * 133 * @throws IOException if an file read error occurs 134 * @throws NoSuchAlgorithmException if no implementation for the requested key wrap algorithm is available 135 */ 136 public AuthenticatedDataDemo() throws IOException, NoSuchAlgorithmException { 137 this((AlgorithmID)CMSAlgorithmID.cms_aes256_wrap.clone(), 256); 138 } 139 140 /** 141 * Creates and AuthenticatedDataDemo object and setups the demo certificates. 142 * 143 * Keys and certificate are retrieved from the demo KeyStore which 144 * has to be located in your current working directory and may be 145 * created by running {@link demo.keystore.SetupCMSKeyStore 146 * SetupCMSKeyStore}. 147 * 148 * @param keyWrapAlg the key wrap algorithm to be used 149 * @param kekLength the length of the key encryption key 150 * 151 * @throws IOException if an file read error occurs 152 * @throws NoSuchAlgorithmException if no implementation for the requested key wrap algorithm is available 153 */ 154 public AuthenticatedDataDemo(AlgorithmID keyWrapAlg, int kekLength) throws IOException, NoSuchAlgorithmException { 155 156 System.out.println(); 157 System.out.println("**********************************************************************************"); 158 System.out.println("* AuthenticatedDataDemo *"); 159 System.out.println("* (shows the usage of the CMS AuthenticatedData type implementation) *"); 160 System.out.println("**********************************************************************************"); 161 System.out.println(); 162 163 // add all certificates to the list 164 rsaUser1Cert_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0]; 165 rsaUser1PrivKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1); 166 rsaUser2Cert_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0]; 167 rsaUser2PrivKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2); 168 169 originatorCerts_ = CMSKeyStore.getCertificateChain(CMSKeyStore.SSDH, CMSKeyStore.SZ_2048_CRYPT_1); 170 ssdhUser1Cert_ = originatorCerts_[0]; 171 ssdhUser1PrivKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.SSDH, CMSKeyStore.SZ_2048_CRYPT_1); 172 ssdhUser2Cert_ = CMSKeyStore.getCertificateChain(CMSKeyStore.SSDH, CMSKeyStore.SZ_2048_CRYPT_2)[0]; 173 ssdhUser2PrivKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.SSDH, CMSKeyStore.SZ_2048_CRYPT_2); 174 175 random_ = SecRandom.getDefault(); 176 keyWrapAlg_ = keyWrapAlg; 177 kekLength_ = kekLength; 178 // create a secret key encryption key for a KEKRecipientInfo 179 KeyGenerator kg = SecurityProvider.getSecurityProvider().getKeyGenerator(keyWrapAlg_, kekLength_); 180 kek_ = kg.generateKey(); 181 kekID_ = new byte[] { 00, 00, 00, 01 }; 182 183 } 184 185 186 /** 187 * Creates a CMS <code>AuthenticatedDataStream</code> for the given message message. 188 * 189 * @param message the message to be authenticated, as byte representation 190 * @param macAlgorithm the mac algorithm to be used 191 * @param macKeyLength the length of the temporary MAC key to be generated 192 * @param digestAlgorithm the digest algorithm to be used to calculate a digest 193 * from the content if authenticated attributes should 194 * be included 195 * @param mode whether to include the content into the AuthenticatedData ({@link 196 * AuthenticatedDataStream#IMPLICIT implicit}) or to not include it 197 * ({@link AuthenticatedDataStream#EXPLICIT explicit}) 198 * 199 * @return the BER encoding of the <code>AuthenticatedData</code> object just created 200 * 201 * @throws CMSException if the <code>AuthenticatedData</code> object cannot 202 * be created 203 * @throws IOException if an I/O error occurs 204 */ 205 public byte[] createAuthenticatedDataStream(byte[] message, 206 AlgorithmID macAlgorithm, 207 int macKeyLength, 208 AlgorithmID digestAlgorithm, 209 int mode) 210 throws CMSException, IOException { 211 212 AlgorithmID macAlg = (AlgorithmID)macAlgorithm.clone(); 213 AlgorithmID digestAlg = null; 214 if (digestAlgorithm != null) { 215 digestAlg = (AlgorithmID)digestAlgorithm.clone(); 216 } 217 ObjectID contentType = ObjectID.cms_data; 218 219 AuthenticatedDataStream authenticatedData; 220 221 // we are testing the stream interface 222 ByteArrayInputStream is = new ByteArrayInputStream(message); 223 // create a new AuthenticatedData object 224 try { 225 authenticatedData = new AuthenticatedDataStream(contentType, 226 is, 227 macAlg, 228 macKeyLength, 229 null, 230 digestAlg, 231 mode); 232 } catch (NoSuchAlgorithmException ex) { 233 throw new CMSException(ex.toString()); 234 } 235 236 // static-static mode: set OriginatorInfo 237 OriginatorInfo originator = new OriginatorInfo(); 238 originator.setCertificates(originatorCerts_); 239 authenticatedData.setOriginatorInfo(originator); 240 // create the recipient infos 241 RecipientInfo[] recipients = createRecipients(); 242 // specify the recipients of the authenticated message 243 authenticatedData.setRecipientInfos(recipients); 244 245 if (digestAlgorithm != null) { 246 // create some authenticated attributes 247 // (the message digest attribute is automatically added) 248 try { 249 Attribute[] attributes = { new Attribute(new CMSContentType(contentType)) }; 250 authenticatedData.setAuthenticatedAttributes(attributes); 251 } catch (Exception ex) { 252 throw new CMSException("Error creating attribute: " + ex.toString()); 253 } 254 } 255 256 // in explicit mode get the content and write it to any out-of-band place 257 if (mode == AuthenticatedDataStream.EXPLICIT) { 258 InputStream data_is = authenticatedData.getInputStream(); 259 byte[] buf = new byte[2048]; 260 int r; 261 while ((r = data_is.read(buf)) > 0) 262 ; // skip data 263 } 264 265 // return the AuthenticatedData as BER encoded byte array with block size 16 266 // (just for testing; in real application we will use a proper blocksize, 267 // e.g. 2048, 4096,..) 268 authenticatedData.setBlockSize(16); 269 // return the AuthenticatedDate as BER encoded byte array with block size 2048 270 ByteArrayOutputStream os = new ByteArrayOutputStream(); 271 // wrap into ContentInfo 272 ContentInfoStream contentInfo = new ContentInfoStream(authenticatedData); 273 contentInfo.writeTo(os); 274 return os.toByteArray(); 275 } 276 277 /** 278 * Decrypts the encrypted MAC key for the recipient identified by its index 279 * into the recipientInfos field and uses the MAC key to verify 280 * the authenticated data. 281 * <p> 282 * This way of decrypting the MAC key and verifying the content may be used for 283 * any type of RecipientInfo (KeyTransRecipientInfo, KeyAgreeRecipientInfo, 284 * KEKRecipientInfo, PasswordRecipeintInfo, OtherRecipientInfo), but requires to 285 * know at what index of the recipientInfos field the RecipientInfo for the 286 * particular recipient in mind can be found. 287 * If the recipient in mind uses a RecipientInfo of type KeyAgreeRecipientInfo 288 * some processing overhead may take place because a KeyAgreeRecipientInfo may 289 * contain encrypted mac keys for more than only one recipient; since the 290 * recipientInfoIndex only specifies the RecipientInfo but not the encrypted 291 * mac key -- if there are more than only one -- repeated decryption runs may be 292 * required as long as the decryption process completes successfully. 293 * 294 * @param encoding the <code>AuthenticatedData</code> object as BER encoded byte array 295 * @param message the content message, if transmitted by other means (explicit mode) 296 * @param key the key to decrypt the mac key 297 * @param recipientInfoIndex the index of the right <code>RecipientInfo</code> to 298 * which the given key belongs 299 * 300 * @return the verified message, as byte array 301 * 302 * @throws CMSException if the authenticated data cannot be verified 303 * @throws IOException if a stream read/write error occurs 304 */ 305 public byte[] getAuthenticatedDataStream(byte[] encoding, 306 byte[] message, 307 Key key, 308 int recipientInfoIndex) 309 throws CMSException, IOException { 310 311 // create the AuthenticatedData object from a DER encoded byte array 312 // we are testing the stream interface 313 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 314 AuthenticatedDataStream authenticatedData = new AuthenticatedDataStream(is); 315 316 if (authenticatedData.getMode() == AuthenticatedDataStream.EXPLICIT) { 317 // in explicit mode explicitly supply the content for hash/mac computation 318 authenticatedData.setInputStream(new ByteArrayInputStream(message)); 319 } 320 321 System.out.println("\nThis message can be verified by the following recipients:"); 322 RecipientInfo[] recipients = authenticatedData.getRecipientInfos(); 323 324 // for demonstration purposes we only look one time for all recipients included: 325 if (recipientInfoIndex == 0) { 326 int k = 0; 327 for (int i=0; i<recipients.length; i++) { 328 KeyIdentifier[] recipientIDs = recipients[i].getRecipientIdentifiers(); 329 for (int j = 0; j < recipientIDs.length; j++) { 330 System.out.println("Recipient "+(++k)+":"); 331 System.out.println(recipientIDs[j]); 332 } 333 } 334 } 335 // decrypt the mac key and verify the mac for the indented recipient 336 try { 337 authenticatedData.setupMac(key, recipientInfoIndex); 338 InputStream contentStream = authenticatedData.getInputStream(); 339 ByteArrayOutputStream os = new ByteArrayOutputStream(); 340 Util.copyStream(contentStream, os, null); 341 342 if (authenticatedData.verifyMac() == false) { 343 throw new CMSException("Mac verification error!"); 344 } 345 System.out.println("Mac successfully verified!"); 346 347 return os.toByteArray(); 348 349 } catch (InvalidKeyException ex) { 350 throw new CMSException("Key error: "+ex.getMessage()); 351 } catch (NoSuchAlgorithmException ex) { 352 throw new CMSException(ex.toString()); 353 } 354 } 355 356 /** 357 * Decrypts the encrypted MAC key for the recipient identified by recipient identifier 358 * and uses the MAC key to verify the authenticated data. 359 * <p> 360 * This way of decrypting the mac key may be used for any type of RecipientInfo 361 * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo). The 362 * recipient in mind is identified by its recipient identifier. 363 * 364 * @param encoding the <code>AuthenticatedData</code> object as BER encoded byte array 365 * @param message the content message, if transmitted by other means (explicit mode) 366 * @param key the key to decrypt the encrypted mac key 367 * @param recipientID the recipient identifier uniquely identifying the key of the 368 * recipient 369 * 370 * @return the verified message, as byte array 371 * 372 * @throws CMSException if the authenticated data cannot be verified 373 * @throws IOException if a stream read/write error occurs 374 */ 375 public byte[] getAuthenticatedDataStream(byte[] encoding, 376 byte[] message, 377 Key key, 378 KeyIdentifier recipientID) 379 throws CMSException, IOException { 380 381 // create the AuthenticatedData object from a BER encoded byte array 382 // we are testing the stream interface 383 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 384 AuthenticatedDataStream authenticatedData = new AuthenticatedDataStream(is); 385 386 if (authenticatedData.getMode() == AuthenticatedDataStream.EXPLICIT) { 387 // in explicit mode explicitly supply the content for hash/mac computation 388 authenticatedData.setInputStream(new ByteArrayInputStream(message)); 389 } 390 391 // get the right RecipientInfo 392 System.out.println("\nSearch for RecipientInfo:"); 393 RecipientInfo recipient = authenticatedData.getRecipientInfo(recipientID); 394 if (recipient != null) { 395 System.out.println("RecipientInfo: " + recipient); 396 } else { 397 throw new CMSException("No recipient with ID: " + recipientID); 398 } 399 // decrypt the mac key and verify the content mac 400 try { 401 System.out.println("Decrypt encrypted mac key..."); 402 SecretKey cek = recipient.decryptKey(key, recipientID); 403 System.out.println("Verify content mac with decrypted mac key..."); 404 authenticatedData.setupMac(cek); 405 InputStream contentStream = authenticatedData.getInputStream(); 406 ByteArrayOutputStream os = new ByteArrayOutputStream(); 407 Util.copyStream(contentStream, os, null); 408 409 if (authenticatedData.verifyMac() == false) { 410 throw new CMSException("Mac verification error!"); 411 } 412 System.out.println("Mac successfully verified!"); 413 414 return os.toByteArray(); 415 416 } catch (InvalidKeyException ex) { 417 throw new CMSException("Key error: "+ex.getMessage()); 418 } catch (NoSuchAlgorithmException ex) { 419 throw new CMSException(ex.toString()); 420 } 421 } 422 423 /** 424 * Decrypts the encrypted content of the given <code>AuthenticatedData</code> object for 425 * the recipient identified by its recipient certificate or kekID. 426 * <p> 427 * 428 * @param encoding the <code>AuthenticatedData</code> object as DER encoded byte array 429 * @param message the content message, if transmitted by other means (explicit mode) 430 * @param key the key to decrypt the message 431 * @param recipientCert the certificate of the recipient having a RecipientInfo of 432 * type KeyTransRecipientInfo or KeyAgreeRecipientInfo 433 * @param kekID the kekID identifying the recipient key when using a RecipientInfo 434 * of type KEKRecipientInfo 435 * 436 * @return the recovered message, as byte array 437 * @throws CMSException if the message cannot be recovered 438 * @throws IOException if a stream read/write error occurs 439 */ 440 public byte[] getAuthenticatedDataStream(byte[] encoding, 441 byte[] message, 442 Key key, 443 X509Certificate recipientCert, 444 byte[] kekID) 445 throws CMSException, IOException { 446 447 // create the AuthenticatedData object from a DER encoded byte array 448 // we are testing the stream interface 449 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 450 AuthenticatedDataStream authenticatedData = new AuthenticatedDataStream(is); 451 452 if (authenticatedData.getMode() == AuthenticatedDataStream.EXPLICIT) { 453 // in explicit mode explicitly supply the content for hash/mac computation 454 authenticatedData.setInputStream(new ByteArrayInputStream(message)); 455 } 456 457 458 // decrypt the mac key and verify the content mac 459 try { 460 System.out.println("Verify mac..."); 461 if (recipientCert != null) { 462 authenticatedData.setupMac(key, recipientCert); 463 } else { 464 // KEKRecipientInfo 465 authenticatedData.setupMac(key, new KEKIdentifier(kekID)); 466 } 467 InputStream contentStream = authenticatedData.getInputStream(); 468 ByteArrayOutputStream os = new ByteArrayOutputStream(); 469 Util.copyStream(contentStream, os, null); 470 471 if (authenticatedData.verifyMac() == false) { 472 throw new CMSException("Mac verification error!"); 473 } 474 System.out.println("Mac successfully verified!"); 475 476 return os.toByteArray(); 477 478 } catch (InvalidKeyException ex) { 479 throw new CMSException("Key error: "+ex.getMessage()); 480 } catch (NoSuchAlgorithmException ex) { 481 throw new CMSException(ex.toString()); 482 } 483 } 484 485 486 // non stream 487 488 /** 489 * Creates a CMS <code>AuthenticatedData</code> for the given message message. 490 * 491 * @param message the message to be authenticated, as byte representation 492 * @param macAlgorithm the mac algorithm to be used 493 * @param macKeyLength the length of the temporary MAC key to be generated 494 * @param digestAlgorithm the digest algorithm to be used to calculate a digest 495 * from the content if authenticated attributes should 496 * be included 497 * @param mode whether to include the content into the AuthenticatedData ({@link 498 * AuthenticatedDataStream#IMPLICIT implicit}) or to not include it 499 * ({@link AuthenticatedDataStream#EXPLICIT explicit}) 500 * 501 * @return the BER encoding of the <code>AuthenticatedData</code> object just created 502 * 503 * @throws CMSException if the <code>AuthenticatedData</code> object cannot 504 * be created 505 */ 506 public byte[] createAuthenticatedData(byte[] message, 507 AlgorithmID macAlgorithm, 508 int macKeyLength, 509 AlgorithmID digestAlgorithm, 510 int mode) 511 throws CMSException { 512 513 AlgorithmID macAlg = (AlgorithmID)macAlgorithm.clone(); 514 AlgorithmID digestAlg = null; 515 if (digestAlgorithm != null) { 516 digestAlg = (AlgorithmID)digestAlgorithm.clone(); 517 } 518 ObjectID contentType = ObjectID.cms_data; 519 520 AuthenticatedData authenticatedData; 521 522 // create a new AuthenticatedData object 523 try { 524 authenticatedData = new AuthenticatedData(contentType, 525 message, 526 macAlg, 527 macKeyLength, 528 null, 529 digestAlg, 530 mode); 531 } catch (NoSuchAlgorithmException ex) { 532 throw new CMSException(ex.toString()); 533 } 534 535 // static-static mode: set OriginatorInfo 536 OriginatorInfo originator = new OriginatorInfo(); 537 originator.setCertificates(originatorCerts_); 538 authenticatedData.setOriginatorInfo(originator); 539 // create the recipient infos 540 RecipientInfo[] recipients = createRecipients(); 541 // specify the recipients of the authenticated message 542 authenticatedData.setRecipientInfos(recipients); 543 544 if (digestAlgorithm != null) { 545 // create some authenticated attributes 546 // (the message digest attribute is automatically added) 547 try { 548 Attribute[] attributes = { new Attribute(new CMSContentType(contentType)) }; 549 authenticatedData.setAuthenticatedAttributes(attributes); 550 } catch (Exception ex) { 551 throw new CMSException("Error creating attribute: " + ex.toString()); 552 } 553 } 554 555 // wrap into ContentInfo 556 ContentInfo contentInfo = new ContentInfo(authenticatedData); 557 // return encoded EnvelopedData 558 return contentInfo.getEncoded(); 559 560 } 561 562 563 /** 564 * Gets the content of the given <code>AuthenticatedData</code> object and 565 * verifies the mac for the recipient identified by its index 566 * into the recipientInfos field and uses the MAC key to verify 567 * the authenticated data. 568 * <p> 569 * This way of decrypting the MAC key and verifying the content may be used for 570 * any type of RecipientInfo (KeyTransRecipientInfo, KeyAgreeRecipientInfo, 571 * KEKRecipientInfo), but requires to know at what index of the recipientInfos 572 * field the RecipientInfo for the particular recipient in mind can be found. 573 * If the recipient in mind uses a RecipientInfo of type KeyAgreeRecipientInfo 574 * some processing overhead may take place because a KeyAgreeRecipientInfo may 575 * contain encrypted mac keys for more than only one recipient; since the 576 * recipientInfoIndex only specifies the RecipientInfo but not the encrypted 577 * mac key -- if there are more than only one -- repeated decryption runs may be 578 * required as long as the decryption process completes successfully. 579 * 580 * @param encoding the <code>AuthenticatedData</code> object as BER encoded byte array 581 * @param message the content message, if transmitted by other means (explicit mode) 582 * @param key the key to decrypt the mac key 583 * @param recipientInfoIndex the index of the right <code>RecipientInfo</code> to 584 * which the given key belongs 585 * 586 * @return the verified message, as byte array 587 * @throws CMSException if the authenticated data cannot be verified 588 * @throws IOException if a IO read/write error occurs 589 */ 590 public byte[] getAuthenticatedData(byte[] encoding, 591 byte[] message, 592 Key key, 593 int recipientInfoIndex) 594 throws CMSException, IOException { 595 596 // create the AuthenticatedData object from a DER encoded byte array 597 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 598 AuthenticatedData authenticatedData = new AuthenticatedData(is); 599 600 if (authenticatedData.getMode() == AuthenticatedData.EXPLICIT) { 601 // in explicit mode explicitly supply the content for hash/mac computation 602 authenticatedData.setContent(message); 603 } 604 605 System.out.println("\nThis message can be verified by the owners of the following recipients:"); 606 RecipientInfo[] recipients = authenticatedData.getRecipientInfos(); 607 608 // for demonstration purposes we only look one time for all recipients included: 609 if (recipientInfoIndex == 0) { 610 int k = 0; 611 for (int i=0; i<recipients.length; i++) { 612 KeyIdentifier[] recipientIDs = recipients[i].getRecipientIdentifiers(); 613 for (int j = 0; j < recipientIDs.length; j++) { 614 System.out.println("Recipient "+(++k)+":"); 615 System.out.println(recipientIDs[j]); 616 } 617 } 618 } 619 // decrypt the mac key and verify the mac for the first recipient 620 try { 621 authenticatedData.setupMac(key, recipientInfoIndex); 622 if (authenticatedData.verifyMac() == false) { 623 throw new CMSException("Mac verification error!"); 624 } 625 System.out.println("Mac successfully verified!"); 626 627 return authenticatedData.getContent(); 628 629 } catch (InvalidKeyException ex) { 630 throw new CMSException("Key error: "+ex.getMessage()); 631 } catch (NoSuchAlgorithmException ex) { 632 throw new CMSException(ex.toString()); 633 } 634 } 635 636 /** 637 * Gets the content of the given <code>AuthenticatedData</code> object and 638 * verifies the mac for the recipient identified by recipient identifier. 639 * <p> 640 * This way of decrypting the content may be used for any type of RecipientInfo 641 * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo). The 642 * recipient in mind is identified by its recipient identifier. 643 * 644 * @param encoding the DER encoeded <code>AuthenticatedData</code> object# 645 * @param message the content message, if transmitted by other means (explicit mode) 646 * @param key the key to decrypt the message 647 * @param recipientID the recipient identifier uniquely identifying the key of the 648 * recipient 649 * 650 * @return the recovered message, as byte array 651 * @throws CMSException if the message cannot be recovered 652 * @throws IOException if an I/O error occurs 653 */ 654 public byte[] getAuthenticatedData(byte[] encoding, 655 byte[] message, 656 Key key, 657 KeyIdentifier recipientID) 658 throws CMSException, IOException { 659 660 // create the AuthenticatedData object from a DER encoded byte array 661 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 662 AuthenticatedData authenticatedData = new AuthenticatedData(is); 663 664 if (authenticatedData.getMode() == AuthenticatedData.EXPLICIT) { 665 // in explicit mode explicitly supply the content for hash/mac computation 666 authenticatedData.setContent(message); 667 } 668 669 // get the right RecipientInfo 670 System.out.println("\nSearch for RecipientInfo:"); 671 RecipientInfo recipient = authenticatedData.getRecipientInfo(recipientID); 672 if (recipient != null) { 673 System.out.println("RecipientInfo: " + recipient); 674 } else { 675 throw new CMSException("No recipient with ID " + recipientID); 676 } 677 // decrypt the mac key and verify the content mac 678 try { 679 System.out.println("Decrypt encrypted mac key..."); 680 SecretKey cek = recipient.decryptKey(key, recipientID); 681 System.out.println("Verify content mac with decrypted mac key..."); 682 authenticatedData.setupMac(cek); 683 684 if (authenticatedData.verifyMac() == false) { 685 throw new CMSException("Mac verification error!"); 686 } 687 System.out.println("Mac successfully verified!"); 688 689 return authenticatedData.getContent(); 690 691 } catch (InvalidKeyException ex) { 692 throw new CMSException("Key error: "+ex.getMessage()); 693 } 694 } 695 696 /** 697 * Gets the content of the given <code>AuthenticatedData</code> object and 698 * verifies the mac for the recipient identified by its recipient certificate or kekID. 699 * <p> 700 * 701 * @param encoding the DER encoded <code>AuthenticatedData</code> ASN.1 object 702 * @param message the content message, if transmitted by other means (explicit mode) 703 * @param key the key to decrypt the message 704 * @param recipientCert the certificate of the recipient having a RecipientInfo of 705 * type KeyTransRecipientInfo or KeyAgreeRecipientInfo 706 * @param kekID the kekID identifying the recipient key when using a RecipientInfo 707 * of type KEKRecipientInfo 708 * 709 * @return the recovered message, as byte array 710 * @throws CMSException if the message cannot be recovered 711 */ 712 public byte[] getAuthenticatedData(byte[] encoding, 713 byte[] message, 714 Key key, 715 X509Certificate recipientCert, 716 byte[] kekID) 717 throws CMSException, IOException { 718 719 // create the AuthenticatedData object from a DER encoded byte array 720 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 721 AuthenticatedData authenticatedData = new AuthenticatedData(is); 722 723 if (authenticatedData.getMode() == AuthenticatedData.EXPLICIT) { 724 // in explicit mode explicitly supply the content for hash/mac computation 725 authenticatedData.setContent(message); 726 } 727 728 // decrypt the mac key and verify the content mac 729 try { 730 System.out.println("Verify mac..."); 731 if (recipientCert != null) { 732 authenticatedData.setupMac(key, recipientCert); 733 } else { 734 // KEKRecipientInfo 735 authenticatedData.setupMac(key, new KEKIdentifier(kekID)); 736 } 737 738 if (authenticatedData.verifyMac() == false) { 739 throw new CMSException("Mac verification error!"); 740 } 741 System.out.println("Mac successfully verified!"); 742 743 return authenticatedData.getContent(); 744 745 } catch (InvalidKeyException ex) { 746 throw new CMSException("Key error: "+ex.getMessage()); 747 } catch (NoSuchAlgorithmException ex) { 748 throw new CMSException(ex.toString()); 749 } 750 } 751 752 /** 753 * Creates the RecipientInfos. 754 * 755 * @return the RecipientInfos created 756 * 757 * @throws CMSException if an error occurs when creating the recipient infos 758 */ 759 public RecipientInfo[] createRecipients() throws CMSException { 760 761 RecipientInfo[] recipients = new RecipientInfo[4]; 762 try { 763 764 // rsaUser1 is the first receiver (cert identified by IssuerAndSerialNumber) 765 recipients[0] = new KeyTransRecipientInfo(rsaUser1Cert_, 766 (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 767 // rsaUser2 is the second receiver (cert identifief by SubjectKeyIdentifier) 768 recipients[1] = new KeyTransRecipientInfo(rsaUser2Cert_, 769 CertificateIdentifier.SUBJECT_KEY_IDENTIFIER, 770 (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 771 772 // next recipients use key agreement (Static-Static Diffie-Hellman) 773 // the key encryption (key agreement) algorithm to use: 774 AlgorithmID keyEA = (AlgorithmID)AlgorithmID.ssdhKeyAgreement.clone(); 775 // the key wrap algorithm to use: 776 AlgorithmID keyWrapAlg = (AlgorithmID)keyWrapAlg_.clone(); 777 // the length of the key encryption key to be generated: 778 int kekLength = kekLength_; 779 // in static-static mode we may supply user keying material 780 byte[] ukm = new byte[64]; 781 random_.nextBytes(ukm); 782 // ssdhUser1 is originator 783 recipients[2] = new KeyAgreeRecipientInfo(ssdhUser1Cert_, 784 ssdhUser1PrivKey_, 785 KeyIdentifier.ISSUER_AND_SERIALNUMBER, 786 keyEA, 787 keyWrapAlg, 788 kekLength, 789 ukm); 790 // add ssdhUser1 (originator) as recipient, too 791 ((KeyAgreeRecipientInfo)recipients[2]).addRecipient(ssdhUser1Cert_, CertificateIdentifier.ISSUER_AND_SERIALNUMBER); 792 // ssdhUser2 is the recipient (cert identified by RecipientKeyIdentifier) 793 ((KeyAgreeRecipientInfo)recipients[2]).addRecipient(ssdhUser2Cert_, CertificateIdentifier.RECIPIENT_KEY_IDENTIFIER); 794 795 // last receiver uses a symmetric key encryption key 796 AlgorithmID kea = (AlgorithmID)keyWrapAlg_.clone(); 797 KEKIdentifier kekIdentifier = new KEKIdentifier(kekID_); 798 recipients[3] = new KEKRecipientInfo(kekIdentifier, kea, kek_); 799 800 } catch (Exception ex) { 801 throw new CMSException("Error adding recipients: " + ex.getMessage()); 802 } 803 return recipients; 804 } 805 806 /** 807 * Parses an AuthenticatedData and verifies the mac for all test recipients 808 * using the index into the recipientInfos field for identifying the recipient. 809 * 810 * @param stream whether to use AuthenticatedDataStream or AuthenticatedData 811 * @param encodedAuthenticatedData the encoded AuthenticatedData object 812 * @param message the content message, if transmitted by other means (explicit mode) 813 * 814 * @throws Exception if some error occurs during mac key decryption / mac verification 815 */ 816 public void parseAuthenticatedDataWithRecipientInfoIndex(boolean stream, 817 byte[] encodedAuthenticatedData, 818 byte[] message) 819 throws Exception { 820 821 byte[] receivedMessage; 822 if (stream) { 823 824 // rsaUser1 825 System.out.println("\nVerify MAC for rsaUser1:"); 826 827 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 828 message, 829 rsaUser1PrivKey_, 830 0); 831 System.out.print("\nContent: "); 832 System.out.println(new String(receivedMessage)); 833 834 // rsaUser2 835 System.out.println("\nVerify MAC for rsaUser2:"); 836 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 837 message, 838 rsaUser2PrivKey_, 839 1); 840 841 // ssdhUser1 842 System.out.println("\nVerify MAC for ssdhUser1:"); 843 844 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 845 message, 846 ssdhUser1PrivKey_, 847 2); 848 System.out.print("\nContent: "); 849 System.out.println(new String(receivedMessage)); 850 851 // ssdhUser2 852 System.out.println("\nVerify MAC for ssdhUser2:"); 853 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 854 message, 855 ssdhUser2PrivKey_, 856 2); 857 System.out.print("\nContent: "); 858 System.out.println(new String(receivedMessage)); 859 860 // kekUser 861 System.out.println("\nVerify MAC for kekUser:"); 862 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 863 message, 864 kek_, 865 3); 866 System.out.print("\nContent: "); 867 System.out.println(new String(receivedMessage)); 868 869 } else { 870 871 // rsaUser1 872 System.out.println("\nVerify MAC for rsaUser1:"); 873 874 receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 875 message, 876 rsaUser1PrivKey_, 877 0); 878 System.out.print("\nContent: "); 879 System.out.println(new String(receivedMessage)); 880 881 // rsaUser2 882 System.out.println("\nVerify MAC for rsaUser2:"); 883 receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 884 message, 885 rsaUser2PrivKey_, 886 1); 887 888 // ssdhUser1 889 System.out.println("\nVerify MAC for ssdhUser1:"); 890 receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 891 message, 892 ssdhUser1PrivKey_, 893 2); 894 System.out.print("\nContent: "); 895 System.out.println(new String(receivedMessage)); 896 // ssdhUser2 897 System.out.println("\nVerify MAC for ssdhUser2:"); 898 receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 899 message, 900 ssdhUser2PrivKey_, 901 2); 902 903 // kekUser 904 System.out.println("\nVerify MAC for kekUser:"); 905 receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 906 message, 907 kek_, 908 3); 909 910 System.out.print("\nContent: "); 911 System.out.println(new String(receivedMessage)); 912 } 913 } 914 915 /** 916 * Parses an AuthenticatedData and verifies the mac for all recipients 917 * identified by their recipient identifiers. 918 * 919 * @param stream whether to use AuthenticatedDataStream or AuthenticatedData 920 * @param encodedAuthenticatedData the encoded AuthenticatedData object 921 * @param message the content message, if transmitted by other means (explicit mode) 922 * 923 * @throws Exception if some error occurs during mac key decryption / mac verification 924 */ 925 public void parseAuthenticatedDataWithRecipientIdentifier(boolean stream, 926 byte[] encodedAuthenticatedData, 927 byte[] message) 928 throws Exception { 929 930 byte[] receivedMessage; 931 if (stream) { 932 933 // rsaUser1 934 System.out.println("\nVerify MAC for rsaUser1:"); 935 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 936 message, 937 rsaUser1PrivKey_, 938 new IssuerAndSerialNumber(rsaUser1Cert_)); 939 System.out.print("\nContent: "); 940 System.out.println(new String(receivedMessage)); 941 942 // rsaUser2 943 System.out.println("\nVerify MAC for rsaUser2:"); 944 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 945 message, 946 rsaUser2PrivKey_, 947 new SubjectKeyID(rsaUser2Cert_)); 948 949 // ssdhUser1 950 System.out.println("\nVerify MAC for ssdhUser1:"); 951 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 952 message, 953 ssdhUser1PrivKey_, 954 new IssuerAndSerialNumber(ssdhUser1Cert_)); 955 System.out.print("\nContent: "); 956 System.out.println(new String(receivedMessage)); 957 // ssdhUser2 958 System.out.println("\nVerify MAC for ssdhUser2:"); 959 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 960 message, 961 ssdhUser2PrivKey_, 962 new RecipientKeyIdentifier(ssdhUser2Cert_)); 963 // kekUser 964 System.out.println("\nVerify MAC for kekUser:"); 965 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 966 message, 967 kek_, 968 new KEKIdentifier(kekID_)); 969 970 System.out.print("\nContent: "); 971 System.out.println(new String(receivedMessage)); 972 973 } else { 974 975 // rsaUser1 976 System.out.println("\nVerify MAC for rsaUser1:"); 977 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 978 message, 979 rsaUser1PrivKey_, 980 new IssuerAndSerialNumber(rsaUser1Cert_)); 981 System.out.print("\nContent: "); 982 System.out.println(new String(receivedMessage)); 983 984 // rsaUser2 985 System.out.println("\nVerify MAC for rsaUser2:"); 986 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 987 message, 988 rsaUser2PrivKey_, 989 new SubjectKeyID(rsaUser2Cert_)); 990 991 // ssdhUser1 992 System.out.println("\nVerify MAC for ssdhUser1:"); 993 receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 994 message, 995 ssdhUser1PrivKey_, 996 new IssuerAndSerialNumber(ssdhUser1Cert_)); 997 System.out.print("\nContent: "); 998 System.out.println(new String(receivedMessage)); 999 // ssdhUser2 1000 System.out.println("\nVerify MAC for ssdhUser2:"); 1001 receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 1002 message, 1003 ssdhUser2PrivKey_, 1004 new RecipientKeyIdentifier(ssdhUser2Cert_)); 1005 // kekUser 1006 System.out.println("\nVerify MAC for kekUser:"); 1007 receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 1008 message, 1009 kek_, 1010 new KEKIdentifier(kekID_)); 1011 1012 System.out.print("\nContent: "); 1013 System.out.println(new String(receivedMessage)); 1014 } 1015 } 1016 1017 /** 1018 * Parses an AuthenticatedData and verifies the mac for all recipients 1019 * identified by their recipient certificate (or kek). 1020 * 1021 * @param stream whether to use AuthenticatedDataStream or AuthenticatedData 1022 * @param encodedAuthenticatedData the encoded AuthenticatedData object 1023 * @param message the content message, if transmitted by other means (explicit mode) 1024 * 1025 * @throws Exception if some error occurs during mac key decryption / mac verification 1026 */ 1027 public void parseAuthenticatedDataWithRecipientCertOrKEKId(boolean stream, 1028 byte[] encodedAuthenticatedData, 1029 byte[] message) 1030 throws Exception { 1031 1032 byte[] receivedMessage; 1033 if (stream) { 1034 1035 // rsaUser1 1036 System.out.println("\nVerify MAC for rsaUser1:"); 1037 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 1038 message, 1039 rsaUser1PrivKey_, 1040 rsaUser1Cert_, 1041 null); 1042 System.out.print("\nContent: "); 1043 System.out.println(new String(receivedMessage)); 1044 // rsaUser2 1045 System.out.println("\nVerify MAC for rsaUser2:"); 1046 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 1047 message, 1048 rsaUser2PrivKey_, 1049 rsaUser2Cert_, 1050 null); 1051 1052 // ssdhUser1 1053 System.out.println("\nVerify MAC for ssdhUser1:"); 1054 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 1055 message, 1056 ssdhUser1PrivKey_, 1057 ssdhUser1Cert_, 1058 null); 1059 System.out.print("\nContent: "); 1060 System.out.println(new String(receivedMessage)); 1061 // ssdhUser2 1062 System.out.println("\nVerify MAC for ssdhUser2:"); 1063 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 1064 message, 1065 ssdhUser2PrivKey_, 1066 ssdhUser2Cert_, 1067 null); 1068 // kekUser 1069 System.out.println("\nVerify MAC for kekUser:"); 1070 receivedMessage = getAuthenticatedDataStream(encodedAuthenticatedData, 1071 message, 1072 kek_, 1073 null, 1074 kekID_); 1075 1076 System.out.print("\nContent: "); 1077 System.out.println(new String(receivedMessage)); 1078 } else { 1079 // rsaUser1 1080 System.out.println("\nVerify MAC for rsaUser1:"); 1081 receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 1082 message, 1083 rsaUser1PrivKey_, 1084 rsaUser1Cert_, 1085 null); 1086 System.out.print("\nContent: "); 1087 System.out.println(new String(receivedMessage)); 1088 // rsaUser2 1089 System.out.println("\nVerify MAC for rsaUser2:"); 1090 receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 1091 message, 1092 rsaUser2PrivKey_, 1093 rsaUser2Cert_, 1094 null); 1095 1096 // ssdhUser1 1097 System.out.println("\nVerify MAC for ssdhUser1:"); 1098 receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 1099 message, 1100 ssdhUser1PrivKey_, 1101 ssdhUser1Cert_, 1102 null); 1103 System.out.print("\nContent: "); 1104 System.out.println(new String(receivedMessage)); 1105 // ssdhUser2 1106 System.out.println("\nVerify MAC for ssdhUser2:"); 1107 receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 1108 message, 1109 ssdhUser2PrivKey_, 1110 ssdhUser2Cert_, 1111 null); 1112 // kekUser 1113 System.out.println("\nVerify MAC for kekUser:"); 1114 receivedMessage = getAuthenticatedData(encodedAuthenticatedData, 1115 message, 1116 kek_, 1117 null, 1118 kekID_); 1119 1120 System.out.print("\nContent: "); 1121 System.out.println(new String(receivedMessage)); 1122 } 1123 } 1124 1125 /** 1126 * Starts the test. 1127 */ 1128 public void start() { 1129 // the test message 1130 String m = "This is the test message."; 1131 System.out.println("Test message: \""+m+"\""); 1132 System.out.println(); 1133 byte[] message = m.getBytes(); 1134 1135 try { 1136 byte[] encodedAuthenticatedData; 1137 1138 AlgorithmID macAlgorithm = (AlgorithmID)AlgorithmID.hMAC_SHA256.clone(); 1139 int macKeyLength = 32; 1140 AlgorithmID digestAlgorithm = (AlgorithmID)AlgorithmID.sha256.clone(); 1141 1142 System.out.println("Stream implementation demos"); 1143 System.out.println("==========================="); 1144 1145 1146 // the stream implementation 1147 // 1148 // test CMS AuthenticatedDataStream 1149 // 1150 1151 // implicit mode; with authenticated attributes 1152 System.out.println("\nCMS AuthenticatedDataStream demo with authenticated attributes [create, implicit mode]:\n"); 1153 encodedAuthenticatedData = createAuthenticatedDataStream(message, 1154 macAlgorithm, 1155 macKeyLength, 1156 digestAlgorithm, 1157 AuthenticatedDataStream.IMPLICIT); 1158 // transmit data 1159 System.out.println("\nCMS AuthenticatedDataStream demo [parse, implicit mode]:\n"); 1160 System.out.println("Decrypt and verify for the several recipients using their index into the recipientInfos field."); 1161 parseAuthenticatedDataWithRecipientInfoIndex(true, encodedAuthenticatedData, null); 1162 System.out.println("Decrypt and verify for the several recipients using their RecipientIdentifier."); 1163 parseAuthenticatedDataWithRecipientIdentifier(true, encodedAuthenticatedData, null); 1164 System.out.println("Decrypt and verify for the several recipients using their certificate or kek."); 1165 parseAuthenticatedDataWithRecipientCertOrKEKId(true, encodedAuthenticatedData, null); 1166 1167 // implicit mode; without authenticated attributes 1168 System.out.println("\nCMS AuthenticatedDataStream demo without authenticated attributes [create, implicit mode]:\n"); 1169 encodedAuthenticatedData = createAuthenticatedDataStream(message, 1170 macAlgorithm, 1171 macKeyLength, 1172 null, 1173 AuthenticatedDataStream.IMPLICIT); 1174 // transmit data 1175 System.out.println("\nCMS AuthenticatedDataStream demo [parse, implicit mode]:\n"); 1176 System.out.println("Decrypt and verify for the several recipients using their index into the recipientInfos field."); 1177 parseAuthenticatedDataWithRecipientInfoIndex(true, encodedAuthenticatedData, null); 1178 System.out.println("Decrypt and verify for the several recipients using their RecipientIdentifier."); 1179 parseAuthenticatedDataWithRecipientIdentifier(true, encodedAuthenticatedData, null); 1180 System.out.println("Decrypt and verify for the several recipients using their certificate or kek."); 1181 parseAuthenticatedDataWithRecipientCertOrKEKId(true, encodedAuthenticatedData, null); 1182 1183 1184 // explict mode; with authenticated attributes 1185 System.out.println("\nCMS AuthenticatedDataStream demo with authenticated attributes [create, explicit mode]:\n"); 1186 encodedAuthenticatedData = createAuthenticatedDataStream(message, 1187 macAlgorithm, 1188 macKeyLength, 1189 digestAlgorithm, 1190 AuthenticatedDataStream.EXPLICIT); 1191 // transmit data 1192 System.out.println("\nCMS AuthenticatedDataStream demo [parse, explicit mode]:\n"); 1193 System.out.println("Decrypt and verify for the several recipients using their index into the recipientInfos field."); 1194 parseAuthenticatedDataWithRecipientInfoIndex(true, encodedAuthenticatedData, message); 1195 System.out.println("Decrypt and verify for the several recipients using their RecipientIdentifier."); 1196 parseAuthenticatedDataWithRecipientIdentifier(true, encodedAuthenticatedData, message); 1197 System.out.println("Decrypt and verify for the several recipients using their certificate or kek."); 1198 parseAuthenticatedDataWithRecipientCertOrKEKId(true, encodedAuthenticatedData, message); 1199 1200 // explict mode; without authenticated attributes 1201 System.out.println("\nCMS AuthenticatedDataStream demo without authenticated attributes [create, explicit mode]:\n"); 1202 encodedAuthenticatedData = createAuthenticatedDataStream(message, 1203 macAlgorithm, 1204 macKeyLength, 1205 null, 1206 AuthenticatedDataStream.EXPLICIT); 1207 // transmit data 1208 System.out.println("\nCMS AuthenticatedDataStream demo [parse, explicit mode]:\n"); 1209 System.out.println("Decrypt and verify for the several recipients using their index into the recipientInfos field."); 1210 parseAuthenticatedDataWithRecipientInfoIndex(true, encodedAuthenticatedData, message); 1211 System.out.println("Decrypt and verify for the several recipients using their RecipientIdentifier."); 1212 parseAuthenticatedDataWithRecipientIdentifier(true, encodedAuthenticatedData, message); 1213 System.out.println("Decrypt and verify for the several recipients using their certificate or kek."); 1214 parseAuthenticatedDataWithRecipientCertOrKEKId(true, encodedAuthenticatedData, message); 1215 1216 1217 1218 // the non-stream implementation 1219 System.out.println("\nNon-stream implementation demos"); 1220 System.out.println("==============================="); 1221 1222 1223 // 1224 // test CMS AuthenticatedData 1225 // 1226 1227 // implict mode; with authenticated attributes 1228 System.out.println("\nCMS AuthenticatedData demo with authenticated attributes [create, implicit mode]:\n"); 1229 encodedAuthenticatedData = createAuthenticatedData(message, 1230 macAlgorithm, 1231 macKeyLength, 1232 digestAlgorithm, 1233 AuthenticatedDataStream.IMPLICIT); 1234 // transmit data 1235 System.out.println("\nCMS AuthenticatedData demo [parse]:\n"); 1236 System.out.println("Decrypt and verify for the several recipients using their index into the recipientInfos field."); 1237 parseAuthenticatedDataWithRecipientInfoIndex(false, encodedAuthenticatedData, null); 1238 System.out.println("Decrypt and verify for the several recipients using their RecipientIdentifier."); 1239 parseAuthenticatedDataWithRecipientIdentifier(false, encodedAuthenticatedData, null); 1240 System.out.println("Decrypt and verify for the several recipients using their certificate or kek."); 1241 parseAuthenticatedDataWithRecipientCertOrKEKId(false, encodedAuthenticatedData, null); 1242 1243 // implict mode; without authenticated attributes 1244 System.out.println("\nCMS AuthenticatedData demo without authenticated attributes [create, implicit mode]:\n"); 1245 encodedAuthenticatedData = createAuthenticatedData(message, 1246 macAlgorithm, 1247 macKeyLength, 1248 null, 1249 AuthenticatedDataStream.IMPLICIT); 1250 // transmit data 1251 System.out.println("\nCMS AuthenticatedData demo [parse]:\n"); 1252 System.out.println("Decrypt and verify for the several recipients using their index into the recipientInfos field."); 1253 parseAuthenticatedDataWithRecipientInfoIndex(false, encodedAuthenticatedData, null); 1254 System.out.println("Decrypt and verify for the several recipients using their RecipientIdentifier."); 1255 parseAuthenticatedDataWithRecipientIdentifier(false, encodedAuthenticatedData, null); 1256 System.out.println("Decrypt and verify for the several recipients using their certificate or kek."); 1257 parseAuthenticatedDataWithRecipientCertOrKEKId(false, encodedAuthenticatedData, null); 1258 1259 1260 // explict mode; with authenticated attributes 1261 System.out.println("\nCMS AuthenticatedData demo with authenticated attributes [create, explicit mode]:\n"); 1262 encodedAuthenticatedData = createAuthenticatedData(message, 1263 macAlgorithm, 1264 macKeyLength, 1265 digestAlgorithm, 1266 AuthenticatedDataStream.EXPLICIT); 1267 // transmit data 1268 System.out.println("\nCMS AuthenticatedData demo [parse]:\n"); 1269 System.out.println("Decrypt and verify for the several recipients using their index into the recipientInfos field."); 1270 parseAuthenticatedDataWithRecipientInfoIndex(false, encodedAuthenticatedData, message); 1271 System.out.println("Decrypt and verify for the several recipients using their RecipientIdentifier."); 1272 parseAuthenticatedDataWithRecipientIdentifier(false, encodedAuthenticatedData, message); 1273 System.out.println("Decrypt and verify for the several recipients using their certificate or kek."); 1274 parseAuthenticatedDataWithRecipientCertOrKEKId(false, encodedAuthenticatedData, message); 1275 1276 // explict mode; without authenticated attributes 1277 System.out.println("\nCMS AuthenticatedData demo without authenticated attributes [create, explicit mode]:\n"); 1278 encodedAuthenticatedData = createAuthenticatedData(message, 1279 macAlgorithm, 1280 macKeyLength, 1281 null, 1282 AuthenticatedDataStream.EXPLICIT); 1283 // transmit data 1284 System.out.println("\nCMS AuthenticatedData demo [parse]:\n"); 1285 System.out.println("Decrypt and verify for the several recipients using their index into the recipientInfos field."); 1286 parseAuthenticatedDataWithRecipientInfoIndex(false, encodedAuthenticatedData, message); 1287 System.out.println("Decrypt and verify for the several recipients using their RecipientIdentifier."); 1288 parseAuthenticatedDataWithRecipientIdentifier(false, encodedAuthenticatedData, message); 1289 System.out.println("Decrypt and verify for the several recipients using their certificate or kek."); 1290 parseAuthenticatedDataWithRecipientCertOrKEKId(false, encodedAuthenticatedData, message); 1291 1292 1293 } catch (Exception ex) { 1294 ex.printStackTrace(); 1295 throw new RuntimeException(ex.toString()); 1296 } 1297 } 1298 1299 /** 1300 * Main method. 1301 * 1302 * @throws IOException 1303 * if an I/O error occurs when reading required keys 1304 * and certificates from files 1305 */ 1306 public static void main(String argv[]) throws Exception { 1307 1308 DemoUtil.initDemos(); 1309 (new AuthenticatedDataDemo()).start(); 1310 System.out.println("\nReady!"); 1311 System.in.read(); 1312 } 1313 1314}