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