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