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