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/EckaEGAuthEnvelopedDataDemo.java 12 12.02.25 17:58 Dbratko $ 059 // $Revision: 12 $ 060 // 061 062 063 package demo.cms.ecc; 064 065 import iaik.asn1.CodingException; 066 import iaik.asn1.ObjectID; 067 import iaik.asn1.structures.AlgorithmID; 068 import iaik.asn1.structures.Attribute; 069 import iaik.cms.AuthEnvelopedData; 070 import iaik.cms.AuthEnvelopedDataOutputStream; 071 import iaik.cms.AuthEnvelopedDataStream; 072 import iaik.cms.CMSAlgorithmID; 073 import iaik.cms.CMSException; 074 import iaik.cms.CertificateIdentifier; 075 import iaik.cms.CompressedData; 076 import iaik.cms.CompressedDataOutputStream; 077 import iaik.cms.CompressedDataStream; 078 import iaik.cms.ContentInfo; 079 import iaik.cms.ContentInfoOutputStream; 080 import iaik.cms.ContentInfoStream; 081 import iaik.cms.EncryptedContentInfo; 082 import iaik.cms.EncryptedContentInfoStream; 083 import iaik.cms.IssuerAndSerialNumber; 084 import iaik.cms.KeyAgreeRecipientInfo; 085 import iaik.cms.KeyIdentifier; 086 import iaik.cms.RecipientInfo; 087 import iaik.cms.RecipientKeyIdentifier; 088 import iaik.cms.SignedData; 089 import iaik.cms.SignedDataStream; 090 import iaik.cms.SignerInfo; 091 import iaik.cms.attributes.CMSContentType; 092 import iaik.cms.attributes.SigningTime; 093 import iaik.security.random.SecRandom; 094 import iaik.utils.Util; 095 import iaik.x509.X509Certificate; 096 097 import java.io.ByteArrayInputStream; 098 import java.io.ByteArrayOutputStream; 099 import java.io.IOException; 100 import java.io.InputStream; 101 import java.security.InvalidKeyException; 102 import java.security.Key; 103 import java.security.NoSuchAlgorithmException; 104 import java.security.PrivateKey; 105 import java.security.SecureRandom; 106 import java.security.SignatureException; 107 108 import javax.crypto.SecretKey; 109 110 import demo.DemoUtil; 111 import demo.cms.ecc.keystore.CMSEccKeyStore; 112 113 114 /** 115 * Demonstrates the usage of class {@link iaik.cms.SignedDataStream} and 116 * {@link iaik.cms.SignedData}, and {@link iaik.cms.AuthEnvelopedDataStream} and 117 * {@link iaik.cms.AuthEnvelopedData} according to the BSI Technical 118 * Recommendation <a href = 119 * "https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Publikationen/TechnischeRichtlinien/TR03109/TR-03109-1_Anlage_CMS.pdf;jsessionid=3DD6E4FBAC90766F8E2AB3F79BB003C5.1_cid341?__blob=publicationFile&v=1" target="_blank"> 120 * BSI TR-03109-1</a> for transmitting signed authenticated encrypted 121 * data between Smart-Meter-Gateways and external market participants and the 122 * Smart Meter Gateway Administrator. 123 * <p> 124 * This demo uses AES-GCM as specified by <a href = "http://www.ietf.org/rfc/rfc5084.txt" target="_blank">RFC 5084</a> 125 * and AES-CBC-CMAC as specified by BSI TR-03109-1 for authenticated encryption. 126 * The demo compressed the data, creates an AuthEnvelopedData object, packs it into a SignedData and 127 * subsequently shows several ways that may be used for decrypting the content 128 * for some particular recipient. 129 * <p> 130 * Any keys/certificates required for this demo are read from a keystore 131 * file "cmsecc.keystore" located in your current working directory. If 132 * the keystore file does not exist you can create it by running the 133 * {@link demo.cms.ecc.keystore.SetupCMSEccKeyStore SetupCMSEccKeyStore} 134 * program. 135 * <p> 136 * Additionally to <code>iaik_cms.jar</code> you also must have 137 * <code>iaik_jce_(full).jar</code> (IAIK-JCE, <a href = 138 * "https://sic.tech/products/core-crypto-toolkits/jca-jce/" target="_blank"> 139 * https://sic.tech/products/core-crypto-toolkits/jca-jce/</a>), 140 * and <code>iaik_eccelarate.jar</code> (IAIK-ECCelerate<sup><small>TM</small></sup>, <a href = 141 * "https://sic.tech/products/core-crypto-toolkits/eccelerate/" target="_blank"> 142 * https://sic.tech/products/core-crypto-toolkits/eccelerate/</a>) 143 * in your classpath. 144 * 145 * @see iaik.cms.AuthEnvelopedDataStream 146 * @see iaik.cms.AuthEnvelopedData 147 * @see iaik.cms.SignedDataStream 148 * @see iaik.cms.SignedData 149 * @see iaik.cms.RecipientInfo 150 * @see iaik.cms.KeyAgreeRecipientInfo 151 * 152 */ 153 public class EckaEGAuthEnvelopedDataDemo { 154 155 // certificate of signer 156 X509Certificate[] ecdsa256bitSignerCertChain_; 157 // private key of signer 158 PrivateKey ecdsa256bitSignerPrivateKey_; 159 160 // certificate of signer 161 X509Certificate[] ecdsa384bitSignerCertChain_; 162 // private key of signer 163 PrivateKey ecdsa384bitSignerPrivateKey_; 164 165 //certificate of signer 166 X509Certificate[] ecdsa521bitSignerCertChain_; 167 // private key of signer 168 PrivateKey ecdsa521bitSignerPrivateKey_; 169 170 171 // certificate of recipient 1 (recipient 1 is signer) 172 X509Certificate ecdh256bitRecipient1Cert_; 173 // private key of recipient 1 174 PrivateKey ecdh256bitRecipient1PrivateKey_; 175 // certificate of recipient 2 176 X509Certificate ecdh256bitRecipient2Cert_; 177 // private key of recipient 2 178 PrivateKey ecdh256bitRecipient2PrivateKey_; 179 180 //certificate of recipient 1 (recipient 1 is signer) 181 X509Certificate ecdh384bitRecipient1Cert_; 182 // private key of recipient 1 183 PrivateKey ecdh384bitRecipient1PrivateKey_; 184 // certificate of recipient 2 185 X509Certificate ecdh384bitRecipient2Cert_; 186 // private key of recipient 2 187 PrivateKey ecdh384bitRecipient2PrivateKey_; 188 189 //certificate of recipient 1 (recipient 1 is signer) 190 X509Certificate ecdh521bitRecipient1Cert_; 191 // private key of recipient 1 192 PrivateKey ecdh521bitRecipient1PrivateKey_; 193 // certificate of recipient 2 194 X509Certificate ecdh521bitRecipient2Cert_; 195 // private key of recipient 2 196 PrivateKey ecdh521bitRecipient2PrivateKey_; 197 198 // secure random number generator 199 SecureRandom random; 200 201 /** 202 * Setup the demo certificate chains. 203 * 204 * Keys and certificates are retrieved from the demo KeyStore ("cmsecc.keystore") 205 * file which has to be located in your current working directory and may be 206 * created by running {@link demo.cms.ecc.keystore.SetupCMSEccKeyStore 207 * SetupCMSEccKeyStore}. 208 * 209 * @throws IOException if an file read error occurs 210 */ 211 public EckaEGAuthEnvelopedDataDemo() throws IOException { 212 213 System.out.println(); 214 System.out.println("**********************************************************************************"); 215 System.out.println("* EckaEGAuthEnvelopedDataDemo *"); 216 System.out.println("* (CMS AuthEnvelopedData/SignedData for type implementation for BSI TR-03109-1) *"); 217 System.out.println("**********************************************************************************"); 218 System.out.println(); 219 220 ecdsa256bitSignerCertChain_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_256_SIGN); 221 ecdsa256bitSignerPrivateKey_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_256_SIGN); 222 ecdsa384bitSignerCertChain_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_384_SIGN); 223 ecdsa384bitSignerPrivateKey_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_384_SIGN); 224 ecdsa521bitSignerCertChain_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_521_SIGN); 225 ecdsa521bitSignerPrivateKey_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDSA, CMSEccKeyStore.SZ_521_SIGN); 226 227 228 ecdh256bitRecipient1Cert_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_256_CRYPT_1)[0]; 229 ecdh256bitRecipient1PrivateKey_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_256_CRYPT_1); 230 ecdh256bitRecipient2Cert_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_256_CRYPT_2)[0]; 231 ecdh256bitRecipient2PrivateKey_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_256_CRYPT_2); 232 233 ecdh384bitRecipient1Cert_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_384_CRYPT_1)[0]; 234 ecdh384bitRecipient1PrivateKey_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_384_CRYPT_1); 235 ecdh384bitRecipient2Cert_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_384_CRYPT_2)[0]; 236 ecdh384bitRecipient2PrivateKey_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_384_CRYPT_2); 237 238 ecdh521bitRecipient1Cert_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_521_CRYPT_1)[0]; 239 ecdh521bitRecipient1PrivateKey_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_521_CRYPT_1); 240 ecdh521bitRecipient2Cert_ = CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_521_CRYPT_2)[0]; 241 ecdh521bitRecipient2PrivateKey_ = CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDH, CMSEccKeyStore.SZ_521_CRYPT_2); 242 random = SecRandom.getDefault(); 243 244 } 245 246 247 /** 248 * Creates a CMS <code>AuthEnvelopedData</code> message using class <code>AuthEnvelopedDataStream</code>. 249 * 250 * @param message the message to be authenticated-enveloped, as byte representation 251 * @param contentAuthEncAlg the id of the content-authenticated encryption algorithm 252 * @param recipient1Cert the certificate of the first recipient (sender) 253 * @param recipient2Cert the certificate of the second recipient * 254 * 255 * @return the BER encoding of the <code>AuthEnvelopedData</code> object just created 256 * 257 * @throws CMSException if the <code>AuthEnvelopedData</code> object cannot 258 * be created 259 * @throws IOException if an I/O error occurs 260 */ 261 public byte[] createAuthEnvelopedDataStream(byte[] message, 262 AlgorithmID contentAuthEncAlg, 263 X509Certificate recipient1Cert, 264 X509Certificate recipient2Cert) 265 throws CMSException, IOException { 266 267 System.out.println("Create a new AuthEnvelopedData message using " + contentAuthEncAlg); 268 269 // we are testing the stream interface 270 ByteArrayInputStream is = new ByteArrayInputStream(message); 271 // create a new AuthEnvelopedData object 272 AuthEnvelopedDataStream authEnvelopedData = new AuthEnvelopedDataStream(ObjectID.cms_compressedData, is, contentAuthEncAlg); 273 274 // create some authenticated attributes 275 try { 276 Attribute[] attributes = { new Attribute(new CMSContentType(ObjectID.cms_data)) }; 277 authEnvelopedData.setAuthenticatedAttributes(attributes); 278 } catch (Exception ex) { 279 throw new CMSException("Error creating attribute: " + ex.toString()); 280 } 281 282 // create the recipient infos 283 RecipientInfo[] recipients = createRecipients(contentAuthEncAlg, recipient1Cert, recipient2Cert); 284 // specify the recipients of the encrypted message 285 authEnvelopedData.setRecipientInfos(recipients); 286 287 // wrap into ContentInfo 288 ContentInfoStream contentInfo = new ContentInfoStream(authEnvelopedData); 289 ByteArrayOutputStream os = new ByteArrayOutputStream(); 290 contentInfo.writeTo(os); 291 return os.toByteArray(); 292 } 293 294 /** 295 * Creates a CMS <code>AuthEnvelopedData</code> message using class 296 * <code>AuthEnvelopedDataOutputStream</code>. The content data is 297 * compressed inside this method. 298 * 299 * @param message the message to be authenticated-enveloped, as byte representation 300 * @param contentAuthEncAlg the id of the content-authenticated encryption algorithm 301 * @param recipient1Cert the certificate of the first recipient (sender) 302 * @param recipient2Cert the certificate of the second recipient 303 * 304 * @return the BER encoding of the <code>AuthEnvelopedData</code> object just created 305 * 306 * @throws CMSException if the <code>AuthEnvelopedData</code> object cannot 307 * be created 308 * @throws IOException if an I/O error occurs 309 */ 310 public byte[] createAuthEnvelopedDataOutputStream(byte[] message, 311 AlgorithmID contentAuthEncAlg, 312 X509Certificate recipient1Cert, 313 X509Certificate recipient2Cert) 314 throws CMSException, IOException { 315 316 System.out.println("Create a new AuthEnvelopedData message using " + contentAuthEncAlg); 317 318 // we are testing the stream interface 319 ByteArrayInputStream is = new ByteArrayInputStream(message); 320 // the stream to which to write the AuthEnvelopedData 321 ByteArrayOutputStream resultStream = new ByteArrayOutputStream(); 322 AuthEnvelopedDataOutputStream authEnvelopedData; 323 324 // wrap AuthEnvelopedData into a ContentInfo 325 ContentInfoOutputStream contentInfoStream = 326 new ContentInfoOutputStream(ObjectID.cms_authEnvelopedData, resultStream); 327 328 // create a new AuthEnvelopedData object 329 authEnvelopedData = new AuthEnvelopedDataOutputStream(contentInfoStream, 330 contentAuthEncAlg); 331 332 // create the recipient infos 333 RecipientInfo[] recipients = createRecipients(contentAuthEncAlg, recipient1Cert, recipient2Cert); 334 // specify the recipients of the encrypted message 335 authEnvelopedData.setRecipientInfos(recipients); 336 337 // create some authenticated attributes 338 try { 339 Attribute[] attributes = { new Attribute(new CMSContentType(ObjectID.cms_data)) }; 340 authEnvelopedData.setAuthenticatedAttributes(attributes); 341 } catch (Exception ex) { 342 throw new CMSException("Error creating attribute: " + ex.toString()); 343 } 344 345 // compress message 346 CompressedDataOutputStream compressedData = 347 new CompressedDataOutputStream(authEnvelopedData, 348 (AlgorithmID)CMSAlgorithmID.zlib_compress.clone()); 349 350 int blockSize = 16; // in real world we would use a block size like 2048 351 // write in the data to be encrypted 352 byte[] buffer = new byte[blockSize]; 353 int bytesRead; 354 while ((bytesRead = is.read(buffer)) != -1) { 355 compressedData.write(buffer, 0, bytesRead); 356 } 357 358 // closing the stream finishes encryption and closes the underlying stream 359 compressedData.close(); 360 // authEnvelopedData.close(); 361 return resultStream.toByteArray(); 362 } 363 364 365 /** 366 * Decrypts the encrypted content of the given <code>AuthEnvelopedData</code> object for 367 * the recipient identified by its index into the recipientInfos field and verifies 368 * the message authentication code. 369 * <p> 370 * This way of decrypting the content may be used for any type of RecipientInfo 371 * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo), but requires to 372 * know at what index of the recipientInfo field the RecipientInfo for the 373 * particular recipient in mind can be found. If the recipient in mind uses 374 * a RecipientInfo of type KeyAgreeRecipientInfo some processing overhead may 375 * take place because a KeyAgreeRecipientInfo may contain encrypted content-encryption 376 * keys for more than only one recipient; since the recipientInfoIndex only 377 * specifies the RecipientInfo but not the encrypted content encryption key 378 * -- if there are more than only one -- repeated decryption runs may be 379 * required as long as the decryption process completes successfully. 380 * 381 * @param encoding the <code>AuthEnvelopedData</code> object as DER encoded byte array 382 * @param key the key to decrypt the message 383 * @param recipientInfoIndex the index into the <code>RecipientInfo</code> array 384 * to which the specified key belongs 385 * 386 * @return the recovered message, as byte array 387 * @throws CMSException if the message cannot be recovered or MAC verification fails 388 * @throws IOException if a stream read/write error occurs 389 */ 390 public byte[] getAuthEnvelopedDataStream(byte[] encoding, Key key, int recipientInfoIndex) 391 throws CMSException, IOException { 392 393 // create the AuthEnvelopedData object from a BER encoded byte array 394 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 395 AuthEnvelopedDataStream authEnvelopedData = new AuthEnvelopedDataStream(is); 396 397 System.out.println("Information about the authenticated encrypted data:"); 398 EncryptedContentInfoStream eci = authEnvelopedData.getEncryptedContentInfo(); 399 System.out.println("Content type: "+eci.getContentType().getName()); 400 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 401 402 System.out.println("\nThis message can be decrypted by the owners of the following certificates:"); 403 RecipientInfo[] recipients = authEnvelopedData.getRecipientInfos(); 404 405 // for demonstration purposes we only look one time for all recipients included: 406 if (recipientInfoIndex == 0) { 407 int k = 0; 408 for (int i=0; i<recipients.length; i++) { 409 KeyIdentifier[] recipientIDs = recipients[i].getRecipientIdentifiers(); 410 for (int j = 0; j < recipientIDs.length; j++) { 411 System.out.println("Recipient "+(++k)+":"); 412 System.out.println(recipientIDs[j]); 413 } 414 } 415 } 416 // decrypt the message for the first recipient and verify mac 417 try { 418 authEnvelopedData.setupCipher(key, recipientInfoIndex); 419 InputStream decrypted = authEnvelopedData.getInputStream(); 420 ByteArrayOutputStream os = new ByteArrayOutputStream(); 421 Util.copyStream(decrypted, os, null); 422 byte[] content = os.toByteArray(); 423 424 // get authenticated attributes 425 Attribute contentTypeAttribute = authEnvelopedData.getAuthenticatedAttribute(ObjectID.contentType); 426 if (contentTypeAttribute != null) { 427 CMSContentType contentType = (CMSContentType)contentTypeAttribute.getAttributeValue(); 428 System.out.println("Authenticated content type attribute included: " + contentType.get().getName()); 429 } 430 431 return content; 432 } catch (InvalidKeyException ex) { 433 throw new CMSException("Private key error: "+ex.toString()); 434 } catch (NoSuchAlgorithmException ex) { 435 throw new CMSException("Content encryption algorithm not implemented: "+ex.toString()); 436 } catch (CodingException ex) { 437 throw new CMSException("Error reading authenticated attributes: "+ex.toString()); 438 } 439 } 440 441 /** 442 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for 443 * the recipient identified by recipient identifier and verifies the message 444 * authentication code. 445 * <p> 446 * This way of decrypting the content may be used for any type of RecipientInfo 447 * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo). The 448 * recipient in mind is identified by its recipient identifier. 449 * 450 * @param encoding the <code>AuthEnvelopedData</code> object as BER encoded byte array 451 * @param key the key to decrypt the message 452 * @param recipientID the recipient identifier uniquely identifying the key of the 453 * recipient 454 * 455 * @return the recovered message, as byte array 456 * @throws CMSException if the message cannot be recovered 457 * @throws IOException if a stream read/write error occurs 458 */ 459 public byte[] getAuthEnvelopedDataStream(byte[] encoding, Key key, KeyIdentifier recipientID) 460 throws CMSException, IOException { 461 462 // create the AuthEnvelopedData object from a DER encoded byte array 463 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 464 AuthEnvelopedDataStream authEnvelopedData = new AuthEnvelopedDataStream(is); 465 466 System.out.println("Information about the encrypted data:"); 467 EncryptedContentInfoStream eci = authEnvelopedData.getEncryptedContentInfo(); 468 System.out.println("Content type: "+eci.getContentType().getName()); 469 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 470 471 // get the right RecipientInfo 472 System.out.println("\nSearch for RecipientInfo:"); 473 RecipientInfo recipient = authEnvelopedData.getRecipientInfo(recipientID); 474 if (recipient != null) { 475 System.out.println("RecipientInfo: " + recipient); 476 } else { 477 throw new CMSException("No recipient with ID: " + recipientID); 478 } 479 // decrypt the content encryption key and the content; verify mac 480 try { 481 System.out.println("Decrypt encrypted content encryption key..."); 482 SecretKey cek = recipient.decryptKey(key, recipientID); 483 System.out.println("Decrypt content with decrypted content encryption key..."); 484 authEnvelopedData.setupCipher(cek); 485 InputStream decrypted = authEnvelopedData.getInputStream(); 486 ByteArrayOutputStream os = new ByteArrayOutputStream(); 487 Util.copyStream(decrypted, os, null); 488 byte[] content = os.toByteArray(); 489 490 // get authenticated attributes 491 Attribute contentTypeAttribute = authEnvelopedData.getAuthenticatedAttribute(ObjectID.contentType); 492 if (contentTypeAttribute != null) { 493 CMSContentType contentType = (CMSContentType)contentTypeAttribute.getAttributeValue(); 494 System.out.println("Authenticated content type attribute included: " + contentType.get().getName()); 495 } 496 497 return content; 498 } catch (InvalidKeyException ex) { 499 throw new CMSException("Private key error: "+ex.toString()); 500 } catch (NoSuchAlgorithmException ex) { 501 throw new CMSException("Content encryption algorithm not implemented: "+ex.toString()); 502 } catch (CodingException ex) { 503 throw new CMSException("Error reading authenticated attributes: "+ex.toString()); 504 } 505 } 506 507 /** 508 * Decrypts the encrypted content of the given <code>AuthEnvelopedData</code> object for 509 * the recipient identified by its recipient certificate and verifies the message 510 * authentication code. 511 * <p> 512 * 513 * @param encoding the <code>AuthEnvelopedData</code> object as BER encoded byte array 514 * @param key the key to decrypt the message 515 * @param recipientCert the certificate of the recipient having a RecipientInfo of 516 * type KeyTransRecipientInfo or KeyAgreeRecipientInfo 517 * 518 * @return the recovered message, as byte array 519 * @throws CMSException if the message cannot be recovered 520 * @throws IOException if a stream read/write error occurs 521 */ 522 public byte[] getAuthEnvelopedDataStream(byte[] encoding, Key key, X509Certificate recipientCert) 523 throws CMSException, IOException { 524 525 // create the AuthEnvelopedData object from a BER encoded byte array 526 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 527 AuthEnvelopedDataStream authEnvelopedData = new AuthEnvelopedDataStream(is); 528 529 System.out.println("Information about the encrypted data:"); 530 EncryptedContentInfoStream eci = (EncryptedContentInfoStream)authEnvelopedData.getEncryptedContentInfo(); 531 System.out.println("Content type: "+eci.getContentType().getName()); 532 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 533 534 // decrypt the content encryption key and the content; verify mac 535 try { 536 System.out.println("Decrypt the content..."); 537 authEnvelopedData.setupCipher(key, recipientCert); 538 InputStream decrypted = authEnvelopedData.getInputStream(); 539 ByteArrayOutputStream os = new ByteArrayOutputStream(); 540 Util.copyStream(decrypted, os, null); 541 byte[] content = os.toByteArray(); 542 543 // get authenticated attributes 544 Attribute contentTypeAttribute = authEnvelopedData.getAuthenticatedAttribute(ObjectID.contentType); 545 if (contentTypeAttribute != null) { 546 CMSContentType contentType = (CMSContentType)contentTypeAttribute.getAttributeValue(); 547 System.out.println("Authenticated content type attribute included: " + contentType.get().getName()); 548 } 549 550 return content; 551 } catch (InvalidKeyException ex) { 552 throw new CMSException("Private key error: "+ex.toString()); 553 } catch (NoSuchAlgorithmException ex) { 554 throw new CMSException("Content encryption algorithm not implemented: "+ex.toString()); 555 } catch (CodingException ex) { 556 throw new CMSException("Error reading authenticated attributes: "+ex.toString()); 557 } 558 } 559 560 561 // non stream 562 563 /** 564 * Creates a CMS <code>AuthEnvelopedData</code> message. 565 * 566 * @param message the message to be enveloped, as byte representation 567 * @param contentAuthEncAlg the id of the content-authenticated encryption algorithm 568 * @param recipient1Cert the certificate of the first recipient (sender) 569 * @param recipient2Cert the certificate of the second recipient 570 * 571 * @return the encoded <code>AuthEnvelopedData</code>, as byte array 572 * 573 * @throws CMSException if the <code>AuthEnvelopedData</code> object cannot 574 * be created 575 */ 576 public byte[] createAuthEnvelopedData( 577 byte[] message, 578 AlgorithmID contentAuthEncAlg, 579 X509Certificate recipient1Cert, 580 X509Certificate recipient2Cert) 581 throws CMSException { 582 583 System.out.println("Create a new AuthEnvelopedData message using " + contentAuthEncAlg); 584 585 AuthEnvelopedData authEnvelopedData; 586 587 // create a new AuthEnvelopedData object 588 authEnvelopedData = new AuthEnvelopedData(ObjectID.cms_compressedData, message, contentAuthEncAlg); 589 590 // create some authenticated attributes 591 try { 592 Attribute[] attributes = { new Attribute(new CMSContentType(ObjectID.cms_data)) }; 593 authEnvelopedData.setAuthenticatedAttributes(attributes); 594 } catch (Exception ex) { 595 throw new CMSException("Error creating attribute: " + ex.toString()); 596 } 597 598 // set the RecipientInfos 599 RecipientInfo[] recipients = createRecipients(contentAuthEncAlg, recipient1Cert, recipient2Cert); 600 authEnvelopedData.setRecipientInfos(recipients); 601 authEnvelopedData.getEncryptedContentInfo().setBlockSize(2048); 602 603 // wrap into ContentInfo 604 ContentInfo contentInfo = new ContentInfo(authEnvelopedData); 605 // return encoded EnvelopedData 606 return contentInfo.getEncoded(); 607 } 608 609 610 /** 611 * Decrypts the encrypted content of the given <code>AuthEnvelopedData</code> object for 612 * the recipient identified by its index into the recipientInfos field and verifies 613 * the message authentication code. 614 * <p> 615 * This way of decrypting the content may be used for any type of RecipientInfo 616 * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo), but requires to 617 * know at what index of the recipientInfo field the RecipientInfo for the 618 * particular recipient in mind can be found. If the recipient in mind uses 619 * a RecipientInfo of type KeyAgreeRecipientInfo some processing overhead may 620 * take place because a KeyAgreeRecipientInfo may contain encrypted content-encryption 621 * keys for more than only one recipient; since the recipientInfoIndex only 622 * specifies the RecipientInfo but not the encrypted content encryption key 623 * -- if there are more than only one -- repeated decryption runs may be 624 * required as long as the decryption process completes successfully. 625 * 626 * @param enc the encoded <code>AuthEnvelopedData</code> 627 * 628 * @param key the key to decrypt the message 629 * 630 * @param recipientInfoIndex the index into the <code>RecipientInfo</code> array 631 * to which the specified key belongs 632 * 633 * @return the recovered message, as byte array 634 * 635 * @throws CMSException if the message cannot be recovered 636 * @throws IOException if an I/O error occurs 637 */ 638 public byte[] getAuthEnvelopedData(byte[] enc, Key key, int recipientInfoIndex) 639 throws CMSException, IOException { 640 ByteArrayInputStream bais = new ByteArrayInputStream(enc); 641 AuthEnvelopedData authEnvelopedData = new AuthEnvelopedData(bais); 642 643 System.out.println("Information about the encrypted data:"); 644 EncryptedContentInfo eci = (EncryptedContentInfo)authEnvelopedData.getEncryptedContentInfo(); 645 System.out.println("Content type: "+eci.getContentType().getName()); 646 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 647 648 System.out.println("\nThis message can be decrypted by the owners of the following certificates:"); 649 RecipientInfo[] recipients = authEnvelopedData.getRecipientInfos(); 650 651 // for demonstration purposes we only look one time for all recipients included: 652 if (recipientInfoIndex == 0) { 653 int k = 0; 654 for (int i=0; i<recipients.length; i++) { 655 KeyIdentifier[] recipientIDs = recipients[i].getRecipientIdentifiers(); 656 for (int j = 0; j < recipientIDs.length; j++) { 657 System.out.println("Recipient "+(++k)+":"); 658 System.out.println(recipientIDs[j]); 659 } 660 } 661 } 662 663 // decrypt the message and verify the mac 664 try { 665 authEnvelopedData.setupCipher(key, recipientInfoIndex); 666 byte[] content = authEnvelopedData.getContent(); 667 668 // get authenticated attributes 669 Attribute contentTypeAttribute = authEnvelopedData.getAuthenticatedAttribute(ObjectID.contentType); 670 if (contentTypeAttribute != null) { 671 CMSContentType contentType = (CMSContentType)contentTypeAttribute.getAttributeValue(); 672 System.out.println("Authenticated content type attribute included: " + contentType.get().getName()); 673 } 674 675 return content; 676 } catch (InvalidKeyException ex) { 677 throw new CMSException("Private key error: "+ex.toString()); 678 } catch (NoSuchAlgorithmException ex) { 679 throw new CMSException("Content encryption algorithm not implemented: "+ex.toString()); 680 } catch (CodingException ex) { 681 throw new CMSException("Error reading authenticated attributes: "+ex.toString()); 682 } 683 } 684 685 /** 686 * Decrypts the encrypted content of the given <code>AuthEnvelopedData</code> object for 687 * the recipient identified by recipient identifier. 688 * <p> 689 * This way of decrypting the content may be used for any type of RecipientInfo 690 * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo). The 691 * recipient in mind is identified by its recipient identifier. 692 * 693 * @param enc the BER encoded <code>AuthEnvelopedData</code> ASN.1 object 694 * @param key the key to decrypt the message 695 * @param recipientID the recipient identifier uniquely identifying the key of the 696 * recipient 697 * 698 * @return the recovered message, as byte array 699 * @throws CMSException if the message cannot be recovered 700 * @throws IOException if an I/O error occurs 701 */ 702 public byte[] getAuthEnvelopedData(byte[] enc, Key key, KeyIdentifier recipientID) 703 throws CMSException, IOException { 704 ByteArrayInputStream bais = new ByteArrayInputStream(enc); 705 AuthEnvelopedData authEnvelopedData = new AuthEnvelopedData(bais); 706 707 System.out.println("Information about the encrypted data:"); 708 EncryptedContentInfo eci = (EncryptedContentInfo)authEnvelopedData.getEncryptedContentInfo(); 709 System.out.println("Content type: "+eci.getContentType().getName()); 710 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 711 712 // get the right RecipientInfo 713 System.out.println("\nSearch for RecipientInfo:"); 714 RecipientInfo recipient = authEnvelopedData.getRecipientInfo(recipientID); 715 if (recipient != null) { 716 System.out.println("RecipientInfo: " + recipient); 717 } else { 718 throw new CMSException("No recipient with ID: " + recipientID); 719 } 720 // decrypt the content encryption key and the content 721 try { 722 byte[] content = null; 723 System.out.println("Decrypt encrypted content encryption key..."); 724 SecretKey cek = recipient.decryptKey(key, recipientID); 725 // decrypt content and verify mac 726 System.out.println("Decrypt content with decrypted content encryption key..."); 727 authEnvelopedData.setupCipher(cek); 728 content = authEnvelopedData.getContent(); 729 // get authenticated attributes 730 Attribute contentTypeAttribute = authEnvelopedData.getAuthenticatedAttribute(ObjectID.contentType); 731 if (contentTypeAttribute != null) { 732 CMSContentType contentType = (CMSContentType)contentTypeAttribute.getAttributeValue(); 733 System.out.println("Authenticated content type attribute included: " + contentType.get().getName()); 734 } 735 736 return content; 737 } catch (InvalidKeyException ex) { 738 throw new CMSException("Private key error: "+ex.toString()); 739 } catch (NoSuchAlgorithmException ex) { 740 throw new CMSException("Content encryption algorithm not implemented: "+ex.toString()); 741 } catch (CodingException ex) { 742 throw new CMSException("Error reading authenticated attributes: "+ex.toString()); 743 } 744 } 745 746 /** 747 * Decrypts the encrypted content of the given <code>AuthEnvelopedData</code> object for 748 * the recipient identified by its recipient certificate. 749 * 750 * @param enc the BER encoded <code>AuthEnvelopedData</code> ASN.1 object 751 * @param key the key to decrypt the message 752 * @param recipientCert the certificate of the recipient having a RecipientInfo of 753 * type KeyTransRecipientInfo or KeyAgreeRecipientInfo 754 * 755 * @return the recovered message, as byte array 756 * @throws CMSException if the message cannot be recovered 757 */ 758 public byte[] getAuthEnvelopedData(byte[] enc, Key key, X509Certificate recipientCert) 759 throws CMSException, IOException { 760 ByteArrayInputStream bais = new ByteArrayInputStream(enc); 761 AuthEnvelopedData authEnvelopedData = new AuthEnvelopedData(bais); 762 763 System.out.println("Information about the encrypted data:"); 764 EncryptedContentInfo eci = (EncryptedContentInfo)authEnvelopedData.getEncryptedContentInfo(); 765 System.out.println("Content type: "+eci.getContentType().getName()); 766 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 767 768 // decrypt the content encryption key and the content 769 try { 770 System.out.println("Decrypt the content and verify mac..."); 771 // decrypt content and verify mac 772 authEnvelopedData.setupCipher(key, recipientCert); 773 774 byte[] content = authEnvelopedData.getContent(); 775 776 // get authenticated attributes 777 Attribute contentTypeAttribute = authEnvelopedData.getAuthenticatedAttribute(ObjectID.contentType); 778 if (contentTypeAttribute != null) { 779 CMSContentType contentType = (CMSContentType)contentTypeAttribute.getAttributeValue(); 780 System.out.println("Authenticated content type attribute included: " + contentType.get().getName()); 781 } 782 783 return content; 784 } catch (InvalidKeyException ex) { 785 throw new CMSException("Private key error: "+ex.toString()); 786 } catch (NoSuchAlgorithmException ex) { 787 throw new CMSException("Content encryption algorithm not implemented: "+ex.toString()); 788 } catch (CodingException ex) { 789 throw new CMSException("Error reading authenticated attributes: "+ex.toString()); 790 } 791 792 } 793 794 /** 795 * Creates the RecipientInfos. 796 * 797 * @param contentAuthEncAlg the content encryption algorithm 798 * @param recipient1Cert the certificate of the first recipient (sender) 799 * @param recipient2Cert the certificate of the second recipient 800 * 801 * @return the RecipientInfos created, one 802 * KeyAgreeRecipientInfo (for two recipients with same domain 803 * parameters) 804 * 805 * @throws CMSException if an error occurs when creating the recipient infos 806 */ 807 public RecipientInfo[] createRecipients( 808 AlgorithmID contentAuthEncAlg, 809 X509Certificate recipient1Cert, 810 X509Certificate recipient2Cert) throws CMSException { 811 812 RecipientInfo[] recipients = new RecipientInfo[1]; 813 try { 814 815 // next recipients use key agreement 816 // the key encryption (key agreement) algorithm to use: 817 AlgorithmID keyEA = (AlgorithmID)AlgorithmID.ecka_eg_X963KDF_SHA256.clone(); 818 // the key wrap algorithm to use: 819 AlgorithmID keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes128_wrap.clone(); 820 // the length of the key encryption key to be generated: 821 int kekLength = 128; 822 if ((contentAuthEncAlg.equals(AlgorithmID.aes192_GCM) || 823 (contentAuthEncAlg.equals(AlgorithmID.aes_CBC_CMAC_192)))) { 824 keyEA = (AlgorithmID)AlgorithmID.ecka_eg_X963KDF_SHA384.clone(); 825 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes192_wrap.clone(); 826 kekLength = 192; 827 } else if ((contentAuthEncAlg.equals(AlgorithmID.aes256_GCM) || 828 (contentAuthEncAlg.equals(AlgorithmID.aes_CBC_CMAC_256)))) { 829 keyEA = (AlgorithmID)AlgorithmID.ecka_eg_X963KDF_SHA512.clone(); 830 keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone(); 831 kekLength = 256; 832 } 833 recipients[0] = new KeyAgreeRecipientInfo(keyEA, keyWrapAlg, kekLength); 834 // ecdhUser1 is the third receiver (cert identified by IssuerAndSerialNumber) 835 ((KeyAgreeRecipientInfo)recipients[0]).addRecipient(recipient1Cert, CertificateIdentifier.ISSUER_AND_SERIALNUMBER); 836 // ecdhUser2 is the fourth receiver (cert identified by RecipientKeyIdentifier) 837 ((KeyAgreeRecipientInfo)recipients[0]).addRecipient(recipient2Cert, CertificateIdentifier.RECIPIENT_KEY_IDENTIFIER); 838 839 } catch (Exception ex) { 840 throw new CMSException("Error adding recipients: " + ex.getMessage()); 841 } 842 return recipients; 843 } 844 845 /** 846 * Parses an AuthEnvelopedData and decrypts the content for all test recipients 847 * using the index into the recipientInfos field for identifying the recipient. 848 * 849 * @param stream whether to use AuthEnvelopedDataStream or AuthEnvelopedData 850 * @param encodedAuthEnvelopedData the encoded AuthEnvelopedData object 851 * @param recipient1PrivateKey the private key of the first recipient (sender) 852 * @param recipient2PrivateKey the private key of the second recipient 853 * 854 * @throws Exception if some error occurs during decoding/decryption 855 */ 856 public void parseAuthEnvelopedDataWithRecipientInfoIndex( 857 boolean stream, 858 byte[] encodedAuthEnvelopedData, 859 PrivateKey recipient1PrivateKey, 860 PrivateKey recipient2PrivateKey) throws Exception { 861 byte[] receivedMessage; 862 if (stream) { 863 // ecdhUser1 864 System.out.println("\nDecrypt for ecdhUser1:"); 865 receivedMessage = getAuthEnvelopedDataStream(encodedAuthEnvelopedData, recipient1PrivateKey, 0); 866 // decompress 867 receivedMessage = getCompressedDataStream(receivedMessage); 868 System.out.print("\nDecrypted content: "); 869 System.out.println(new String(receivedMessage)); 870 // ecdhUser2 871 System.out.println("\nDecrypt for ecdhUser2:"); 872 receivedMessage = getAuthEnvelopedDataStream(encodedAuthEnvelopedData, recipient2PrivateKey, 0); 873 // decompress 874 receivedMessage = getCompressedDataStream(receivedMessage); 875 System.out.print("\nDecrypted content: "); 876 System.out.println(new String(receivedMessage)); 877 878 } else { 879 // ecdhUser1 880 System.out.println("\nDecrypt for ecdhUser1:"); 881 receivedMessage = getAuthEnvelopedData(encodedAuthEnvelopedData, recipient1PrivateKey, 0); 882 // decompress 883 receivedMessage = getCompressedData(receivedMessage); 884 System.out.print("\nDecrypted content: "); 885 System.out.println(new String(receivedMessage)); 886 // ecdhUser2 887 System.out.println("\nDecrypt for ecdhUser2:"); 888 receivedMessage = getAuthEnvelopedData(encodedAuthEnvelopedData, recipient2PrivateKey, 0); 889 // decompress 890 receivedMessage = getCompressedData(receivedMessage); 891 System.out.print("\nDecrypted content: "); 892 System.out.println(new String(receivedMessage)); 893 894 } 895 } 896 897 /** 898 * Parses an AuthEnvelopedData and decrypts the content for all test recipients 899 * using their recipient identifiers for identifying the recipient. 900 * 901 * @param stream whether to use AuthEnvelopedDataStream or AuthEnvelopedData 902 * @param encodedAuthEnvelopedData the encoded AuthEnvelopedData object 903 * @param recipient1PrivateKey the private key of the first recipient (sender) 904 * @param recipient1Cert the certificate of the first recipient (sender) 905 * @param recipient2PrivateKey the private key of the second recipient 906 * @param recipient2Cert the certificate of the second recipient 907 * 908 * @throws Exception if some error occurs during decoding/decryption 909 */ 910 public void parseAuthEnvelopedDataWithRecipientIdentifier( 911 boolean stream, 912 byte[] encodedAuthEnvelopedData, 913 PrivateKey recipient1PrivateKey, 914 X509Certificate recipient1Cert, 915 PrivateKey recipient2PrivateKey, 916 X509Certificate recipient2Cert) throws Exception { 917 byte[] receivedMessage; 918 if (stream) { 919 // ecdhUser1 920 System.out.println("\nDecrypt for ecdhUser1:"); 921 receivedMessage = getAuthEnvelopedDataStream(encodedAuthEnvelopedData, recipient1PrivateKey, new IssuerAndSerialNumber(recipient1Cert)); 922 // decompress 923 receivedMessage = getCompressedDataStream(receivedMessage); 924 System.out.print("\nDecrypted content: "); 925 System.out.println(new String(receivedMessage)); 926 // ecdhUser2 927 System.out.println("\nDecrypt for ecdhUser2:"); 928 receivedMessage = getAuthEnvelopedDataStream(encodedAuthEnvelopedData, recipient2PrivateKey, new RecipientKeyIdentifier(recipient2Cert)); 929 // decompress 930 receivedMessage = getCompressedDataStream(receivedMessage); 931 System.out.print("\nDecrypted content: "); 932 System.out.println(new String(receivedMessage)); 933 } else { 934 // ecdhUser1 935 System.out.println("\nDecrypt for ecdhUser1:"); 936 receivedMessage = getAuthEnvelopedData(encodedAuthEnvelopedData, recipient1PrivateKey, new IssuerAndSerialNumber(recipient1Cert)); 937 // decompress 938 receivedMessage = getCompressedData(receivedMessage); 939 System.out.print("\nDecrypted content: "); 940 System.out.println(new String(receivedMessage)); 941 // ecdhUser2 942 System.out.println("\nDecrypt for ecdhUser2:"); 943 receivedMessage = getAuthEnvelopedData(encodedAuthEnvelopedData, recipient2PrivateKey, new RecipientKeyIdentifier(recipient2Cert)); 944 // decompress 945 receivedMessage = getCompressedData(receivedMessage); 946 System.out.print("\nDecrypted content: "); 947 System.out.println(new String(receivedMessage)); 948 } 949 } 950 951 /** 952 * Parses an AuthEnvelopedData and decrypts the content for all test recipients 953 * using their recipient certificate for identifying the recipient. 954 * 955 * @param stream whether to use AuthEnvelopedDataStream or AuthEnvelopedData 956 * @param encodedAuthEnvelopedData the encoded AuthEnvelopedData object 957 * @param recipient1PrivateKey the private key of the first recipient (sender) 958 * @param recipient1Cert the certificate of the first recipient (sender) 959 * @param recipient2PrivateKey the private key of the second recipient 960 * @param recipient2Cert the certificate of the second recipient 961 * 962 * @throws Exception if some error occurs during decoding/decryption 963 */ 964 public void parseAuthEnvelopedDataWithRecipientCert( 965 boolean stream, 966 byte[] encodedAuthEnvelopedData, 967 PrivateKey recipient1PrivateKey, 968 X509Certificate recipient1Cert, 969 PrivateKey recipient2PrivateKey, 970 X509Certificate recipient2Cert) throws Exception { 971 byte[] receivedMessage; 972 if (stream) { 973 // ecdhUser1 974 System.out.println("\nDecrypt for ecdhUser1:"); 975 receivedMessage = getAuthEnvelopedDataStream(encodedAuthEnvelopedData, recipient1PrivateKey, recipient1Cert); 976 // decompress 977 receivedMessage = getCompressedDataStream(receivedMessage); 978 System.out.print("\nDecrypted content: "); 979 System.out.println(new String(receivedMessage)); 980 // ecdhUser2 981 System.out.println("\nDecrypt for ecdhUser2:"); 982 receivedMessage = getAuthEnvelopedDataStream(encodedAuthEnvelopedData, recipient2PrivateKey, recipient2Cert); 983 // decompress 984 receivedMessage = getCompressedDataStream(receivedMessage); 985 System.out.print("\nDecrypted content: "); 986 System.out.println(new String(receivedMessage)); 987 } else { 988 // ecdhUser1 989 System.out.println("\nDecrypt for ecdhUser1:"); 990 receivedMessage = getAuthEnvelopedData(encodedAuthEnvelopedData, recipient1PrivateKey, recipient1Cert); 991 // decompress 992 receivedMessage = getCompressedData(receivedMessage); 993 System.out.print("\nDecrypted content: "); 994 System.out.println(new String(receivedMessage)); 995 // ecdhUser2 996 System.out.println("\nDecrypt for ecdhUser2:"); 997 receivedMessage = getAuthEnvelopedData(encodedAuthEnvelopedData, recipient2PrivateKey, recipient2Cert); 998 // decompress 999 receivedMessage = getCompressedData(receivedMessage); 1000 System.out.print("\nDecrypted content: "); 1001 System.out.println(new String(receivedMessage)); 1002 } 1003 } 1004 1005 /** 1006 * Creates an ECDSA signed CMS <code>SignedDataStream</code> object and wraps it by a 1007 * CMS <code>ContentInfoStream</code>. 1008 * 1009 * @param message the message to be signed, as byte representation 1010 * @param mode the transmission mode, either IMPLICIT or EXPLICIT 1011 * @param hashAlgorithm the hash algorithm to be used 1012 * @param signatureAlgorithm the signature algorithm to be used 1013 * @param signerKey the private key of the signer 1014 * @param certificates the certificate chain of the signer 1015 * 1016 * @return the DER encoding of the <code>ContentInfo</code> object just created 1017 * 1018 * @throws CMSException if the <code>SignedData</code>, <code>ContentInfo</code> 1019 * object cannot be created 1020 * @throws IOException if an I/O related error occurs 1021 */ 1022 public byte[] createSignedDataStream(byte[] message, 1023 int mode, 1024 AlgorithmID hashAlgorithm, 1025 AlgorithmID signatureAlgorithm, 1026 PrivateKey signerKey, 1027 X509Certificate[] certificates) 1028 throws CMSException, IOException { 1029 1030 System.out.print("Create a new message signed with " + signatureAlgorithm.getName()); 1031 1032 // we are testing the stream interface 1033 ByteArrayInputStream is = new ByteArrayInputStream(message); 1034 // create a new SignedData object which includes the data 1035 SignedDataStream signed_data = new SignedDataStream(is, ObjectID.cms_authEnvelopedData, mode); 1036 1037 // SignedData shall include the certificate chain for verifying 1038 signed_data.setCertificates(certificates); 1039 1040 // cert at index 0 is the user certificate 1041 IssuerAndSerialNumber issuer = new IssuerAndSerialNumber(certificates[0]); 1042 1043 // create a new SignerInfo 1044 AlgorithmID ecdsaSig = (AlgorithmID)signatureAlgorithm.clone(); 1045 // CMS-ECDSA requires to encode the parameter field as NULL (see RFC 3278) 1046 ecdsaSig.encodeAbsentParametersAsNull(true); 1047 SignerInfo signer_info = new SignerInfo(issuer, (AlgorithmID)hashAlgorithm.clone(), ecdsaSig, signerKey); 1048 1049 try { 1050 // create some signed attributes 1051 // the message digest attribute is automatically added 1052 Attribute[] attributes = new Attribute[2]; 1053 // content type is data 1054 CMSContentType contentType = new CMSContentType(ObjectID.cms_authEnvelopedData); 1055 attributes[0] = new Attribute(contentType); 1056 // signing time is now 1057 SigningTime signingTime = new SigningTime(); 1058 attributes[1] = new Attribute(signingTime); 1059 1060 // set the attributes 1061 signer_info.setSignedAttributes(attributes); 1062 } catch (Exception ex) { 1063 throw new CMSException("Error adding attributes: " + ex.toString()); 1064 } 1065 1066 // finish the creation of SignerInfo by calling method addSigner 1067 try { 1068 signed_data.addSignerInfo(signer_info); 1069 } catch (NoSuchAlgorithmException ex) { 1070 throw new CMSException("No implementation for signature algorithm: "+ex.getMessage()); 1071 } 1072 1073 // write the data through SignedData to any out-of-band place 1074 if (mode == SignedDataStream.EXPLICIT) { 1075 InputStream data_is = signed_data.getInputStream(); 1076 byte[] buf = new byte[1024]; 1077 int r; 1078 while ((r = data_is.read(buf)) > 0) { 1079 ; // skip data 1080 } 1081 } 1082 1083 signed_data.setBlockSize(2048); 1084 // create the ContentInfo 1085 ContentInfoStream cis = new ContentInfoStream(signed_data); 1086 // return the SignedData as DER encoded byte array with block size 2048 1087 ByteArrayOutputStream os = new ByteArrayOutputStream(); 1088 cis.writeTo(os); 1089 return os.toByteArray(); 1090 } 1091 1092 1093 /** 1094 * Parses a CMS <code>ContentInfo</code> object holding a <code>SignedData</code> 1095 * object and verifies the signature. 1096 * 1097 * @param signedData the <code>ContentInfo</code> holding the <code>SignedData</code> 1098 * object as BER encoded byte array 1099 * @param message the the message which was transmitted out-of-band (explicit signed) 1100 * @param certificates the certificate of the signer (used for alternative signature verification) 1101 * 1102 * @return the inherent message as byte array 1103 * 1104 * @throws CMSException if any signature does not verify 1105 * @throws IOException if an I/O related error occurs 1106 */ 1107 public byte[] getSignedDataStream(byte[] signedData, byte[] message, X509Certificate[] certificates) 1108 throws CMSException, IOException { 1109 1110 // we are testing the stream interface 1111 ByteArrayInputStream is = new ByteArrayInputStream(signedData); 1112 1113 SignedDataStream signed_data = new SignedDataStream(is); 1114 1115 if (signed_data.getMode() == SignedDataStream.EXPLICIT) { 1116 // in explicit mode explicitly supply the content for hash computation 1117 signed_data.setInputStream(new ByteArrayInputStream(message)); 1118 } 1119 1120 // get an InputStream for reading the signed content and update hash computation 1121 InputStream data = signed_data.getInputStream(); 1122 ByteArrayOutputStream os = new ByteArrayOutputStream(); 1123 Util.copyStream(data, os, null); 1124 1125 System.out.println("SignedData contains the following signer information:"); 1126 SignerInfo[] signer_infos = signed_data.getSignerInfos(); 1127 1128 int numberOfSignerInfos = signer_infos.length; 1129 if (numberOfSignerInfos == 0) { 1130 String warning = "Warning: Unsigned message (no SignerInfo included)!"; 1131 System.err.println(warning); 1132 throw new CMSException(warning); 1133 } else { 1134 for (int i = 0; i < numberOfSignerInfos; i++) { 1135 try { 1136 // verify the signed data using the SignerInfo at index i 1137 X509Certificate signer_cert = signed_data.verify(i); 1138 // if the signature is OK the certificate of the signer is returned 1139 System.out.println("Signature OK from signer: "+signer_cert.getSubjectDN()); 1140 // check for some included attributes 1141 SigningTime signingTime = (SigningTime)signer_infos[i].getSignedAttributeValue(ObjectID.signingTime); 1142 if (signingTime != null) { 1143 System.out.println("This message has been signed at " + signingTime.get()); 1144 } 1145 CMSContentType contentType = (CMSContentType)signer_infos[i].getSignedAttributeValue(ObjectID.contentType); 1146 if (contentType != null) { 1147 System.out.println("The content has CMS content type " + contentType.get().getName()); 1148 } 1149 } catch (SignatureException ex) { 1150 // if the signature is not OK a SignatureException is thrown 1151 System.out.println("Signature ERROR from signer: "+signed_data.getCertificate(signer_infos[i].getSignerIdentifier()).getSubjectDN()); 1152 throw new CMSException(ex.toString()); 1153 } 1154 } 1155 // now check alternative signature verification 1156 System.out.println("Now check the signature assuming that no certs have been included:"); 1157 try { 1158 SignerInfo signer_info = signed_data.verify(certificates[0]); 1159 // if the signature is OK the certificate of the signer is returned 1160 System.out.println("Signature OK from signer: "+signed_data.getCertificate(signer_info.getSignerIdentifier()).getSubjectDN()); 1161 } catch (SignatureException ex) { 1162 // if the signature is not OK a SignatureException is thrown 1163 System.out.println("Signature ERROR from signer: "+certificates[0].getSubjectDN()); 1164 throw new CMSException(ex.toString()); 1165 } 1166 // in practice we also would validate the signer certificate(s) 1167 } 1168 return os.toByteArray(); 1169 } 1170 1171 1172 /** 1173 * Creates an ECDSA signed CMS <code>SignedData</code> object and wraps it by a CMS 1174 * <code>ContentInfo</code> object. 1175 * <p> 1176 * 1177 * @param message the message to be signed, as byte representation 1178 * @param mode the mode, either SignedData.IMPLICIT or SignedData.EXPLICIT 1179 * @param hashAlgorithm the hash algorithm to be used 1180 * @param signatureAlgorithm the signature algorithm to be used 1181 * @param signerKey the private key of the signer 1182 * @param certificates the certificate chain of the signer 1183 * 1184 * @return the DER encoded <code>SignedData</code>-<code>ContentInfo</code> object 1185 * 1186 * @throws CMSException if the <code>SignedData</code>-<code>ContentInfo</code> object cannot 1187 * be created 1188 * @throws IOException if an I/O related error occurs 1189 */ 1190 public byte[] createSignedData(byte[] message, 1191 int mode, 1192 AlgorithmID hashAlgorithm, 1193 AlgorithmID signatureAlgorithm, 1194 PrivateKey signerKey, 1195 X509Certificate[] certificates) 1196 throws CMSException, IOException { 1197 1198 System.out.println("Create a new message signed with " + signatureAlgorithm.getName()); 1199 1200 // create a new SignedData object which includes the data 1201 SignedData signed_data = new SignedData(message, ObjectID.cms_authEnvelopedData, mode); 1202 1203 // SignedData shall include the certificate chain for verifying 1204 signed_data.setCertificates(certificates); 1205 1206 // cert at index 0 is the user certificate 1207 IssuerAndSerialNumber issuer = new IssuerAndSerialNumber(certificates[0]); 1208 1209 // create a new SignerInfo 1210 AlgorithmID ecdsaSig = (AlgorithmID)signatureAlgorithm.clone(); 1211 // CMS-ECC requires that the parameters field is encoded as ASN.1 NULL object (see RFC 3278) 1212 ecdsaSig.encodeAbsentParametersAsNull(true); 1213 SignerInfo signer_info = new SignerInfo(issuer, (AlgorithmID)hashAlgorithm.clone(), ecdsaSig, signerKey); 1214 1215 try { 1216 // create some signed attributes 1217 // the message digest attribute is automatically added 1218 Attribute[] attributes = new Attribute[2]; 1219 // content type is data 1220 CMSContentType contentType = new CMSContentType(ObjectID.cms_authEnvelopedData); 1221 attributes[0] = new Attribute(contentType); 1222 // signing time is now 1223 SigningTime signingTime = new SigningTime(); 1224 attributes[1] = new Attribute(signingTime); 1225 1226 // set the attributes 1227 signer_info.setSignedAttributes(attributes); 1228 } catch (Exception ex) { 1229 throw new CMSException("Error adding attributes: " + ex.toString()); 1230 } 1231 1232 // finish the creation of SignerInfo by calling method addSigner 1233 try { 1234 signed_data.addSignerInfo(signer_info); 1235 } catch (NoSuchAlgorithmException ex) { 1236 throw new CMSException("No implementation for signature algorithm: "+ex.getMessage()); 1237 } 1238 1239 ContentInfo ci = new ContentInfo(signed_data); 1240 return ci.getEncoded(); 1241 } 1242 1243 1244 /** 1245 * Parses a CMS <code>ContentInfo</code> holding a <code>SignedData</code> 1246 * object and verifies the signature. 1247 * 1248 * @param signedData the <code>ContentInfo</code> holding the <code>SignedData</code> 1249 * object as DER encoded byte array 1250 * @param message the message which was transmitted out-of-band (explicit signed) 1251 * @param certificates the certificate of the signer (used for alternative signature verification) 1252 * 1253 * @return the inherent message as byte array 1254 * 1255 * @throws CMSException if any signature does not verify 1256 * @throws IOException if an I/O related error occurs 1257 */ 1258 public byte[] getSignedData(byte[] signedData, byte[] message, X509Certificate[] certificates) 1259 throws CMSException, IOException { 1260 1261 ByteArrayInputStream is = new ByteArrayInputStream(signedData); 1262 // create the SignedData object 1263 SignedData signed_data = new SignedData(is); 1264 1265 if (signed_data.getMode() == SignedData.EXPLICIT) { 1266 // in explcit mode explictly supply the content data to do the hash calculation 1267 signed_data.setContent(message); 1268 } 1269 1270 System.out.println("SignedData contains the following signer information:"); 1271 SignerInfo[] signer_infos = signed_data.getSignerInfos(); 1272 1273 int numberOfSignerInfos = signer_infos.length; 1274 if (numberOfSignerInfos == 0) { 1275 String warning = "Warning: Unsigned message (no SignerInfo included)!"; 1276 System.err.println(warning); 1277 throw new CMSException(warning); 1278 } else { 1279 for (int i = 0; i < numberOfSignerInfos; i++) { 1280 try { 1281 // verify the signed data using the SignerInfo at index i 1282 X509Certificate signer_cert = signed_data.verify(i); 1283 // if the signature is OK the certificate of the signer is returned 1284 System.out.println("Signature OK from signer: "+signer_cert.getSubjectDN()); 1285 // check some attributes 1286 SigningTime signingTime = (SigningTime)signer_infos[i].getSignedAttributeValue(ObjectID.signingTime); 1287 if (signingTime != null) { 1288 System.out.println("This message has been signed at " + signingTime.get()); 1289 } 1290 CMSContentType contentType = (CMSContentType)signer_infos[i].getSignedAttributeValue(ObjectID.contentType); 1291 if (contentType != null) { 1292 System.out.println("The content has CMS content type " + contentType.get().getName()); 1293 } 1294 } catch (SignatureException ex) { 1295 // if the signature is not OK a SignatureException is thrown 1296 System.out.println("Signature ERROR from signer: "+signed_data.getCertificate(signer_infos[i].getSignerIdentifier()).getSubjectDN()); 1297 throw new CMSException(ex.toString()); 1298 } 1299 } 1300 1301 // now check alternative signature verification 1302 System.out.println("Now check the signature assuming that no certs have been included:"); 1303 try { 1304 SignerInfo signer_info = signed_data.verify(certificates[0]); 1305 // if the signature is OK the certificate of the signer is returned 1306 System.out.println("Signature OK from signer: "+signed_data.getCertificate(signer_info.getSignerIdentifier()).getSubjectDN()); 1307 } catch (SignatureException ex) { 1308 // if the signature is not OK a SignatureException is thrown 1309 System.out.println("Signature ERROR from signer: "+certificates[0].getSubjectDN()); 1310 throw new CMSException(ex.toString()); 1311 } 1312 // in practice we also would validate the signer certificate(s) 1313 } 1314 return signed_data.getContent(); 1315 } 1316 1317 /** 1318 * Creates a CMS <code>CompressedData</code> object. 1319 * <p> 1320 * @param message the message to be compressed, as byte representation 1321 * 1322 * @return the BER encoding of the <code>CompressedData</code> object just created 1323 * 1324 * @throws CMSException if the <code>CompressedData</code> object cannot 1325 * be created 1326 * @throws IOException if an I/O error occurs 1327 * @throws NoSuchAlgorithmException if the compression algorithm is not supported 1328 */ 1329 public byte[] createCompressedDataStream(byte[] message) 1330 throws CMSException, IOException, NoSuchAlgorithmException { 1331 1332 System.out.println("Create a new CompressedData message"); 1333 1334 // we are testing the stream interface 1335 ByteArrayInputStream is = new ByteArrayInputStream(message); 1336 1337 // create a new CompressedData object 1338 CompressedDataStream compressedData = new CompressedDataStream(is, 1339 (AlgorithmID)CMSAlgorithmID.zlib_compress.clone(), 1340 CompressedDataStream.IMPLICIT); 1341 1342 // for testing return the CompressedData as BER encoded byte array with block size of 4 1343 ByteArrayOutputStream os = new ByteArrayOutputStream(); 1344 compressedData.setBlockSize(4); 1345 ContentInfoStream cis = new ContentInfoStream(compressedData); 1346 cis.writeTo(os); 1347 return os.toByteArray(); 1348 } 1349 1350 /** 1351 * Parses a CMS <code>CompressedData</code> object. 1352 * 1353 * @param encoding the <code>CompressedData</code> object as BER encoded byte array 1354 * 1355 * @return the decompressed message as byte array 1356 * 1357 * @throws CMSException if the CompressedData cannot be parsed 1358 * @throws IOException if an I/O error occurs 1359 * @throws NoSuchAlgorithmException if the compression algorithm is not supported 1360 */ 1361 public byte[] getCompressedDataStream(byte[] encoding) 1362 throws CMSException, IOException, NoSuchAlgorithmException { 1363 1364 System.out.println("Parse CompressedData message."); 1365 // we are testing the stream interface 1366 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 1367 // create the CompressedData object 1368 CompressedDataStream compressedData = new CompressedDataStream(is); 1369 // get an InputStream for reading and decompressing the content 1370 InputStream data = compressedData.getInputStream(); 1371 ByteArrayOutputStream os = new ByteArrayOutputStream(); 1372 Util.copyStream(data, os, null); 1373 1374 return os.toByteArray(); 1375 } 1376 1377 1378 /** 1379 * Creates a CMS <code>CompressedData</code> object. 1380 * <p> 1381 * 1382 * @param message the message to be compressed, as byte representation 1383 * 1384 * @return the DER encoded <code>CompressedData</code> 1385 * 1386 * @throws CMSException if the <code>CompressedData</code> object cannot 1387 * be created 1388 * @throws IOException if an I/O error occurs 1389 * @throws NoSuchAlgorithmException if the compression algorithm is not supported 1390 */ 1391 public byte[] createCompressedData(byte[] message) 1392 throws CMSException, IOException, NoSuchAlgorithmException { 1393 1394 System.out.println("Create a new CompressedData message"); 1395 1396 // create a new CompressedData object 1397 CompressedData compressedData = new CompressedData(message, 1398 (AlgorithmID)CMSAlgorithmID.zlib_compress.clone(), 1399 CompressedData.IMPLICIT); 1400 ContentInfo ci = new ContentInfo(compressedData); 1401 return ci.getEncoded(); 1402 } 1403 1404 /** 1405 * Parses a CMS <code>CompressedData</code> object. 1406 * 1407 * @param encoding the DER encoded <code>CompressedData</code> object 1408 * 1409 * @return the decompressed message as byte array 1410 * 1411 * @throws CMSException if the CompressedData cannot be parsed 1412 * @throws IOException if an I/O error occurs 1413 * @throws NoSuchAlgorithmException if the compression algorithm is not supported 1414 */ 1415 public byte[] getCompressedData(byte[] encoding) 1416 throws CMSException, IOException, NoSuchAlgorithmException { 1417 1418 System.out.println("Parse CompressedData message."); 1419 ByteArrayInputStream encodedStream = new ByteArrayInputStream(encoding); 1420 // create the CompressedData object 1421 CompressedData compressedData = new CompressedData(encodedStream); 1422 // decompress 1423 return compressedData.getContent(); 1424 } 1425 1426 /** 1427 * Starts the test. 1428 */ 1429 public void start() { 1430 1431 PrivateKey signerPrivateKey = null; 1432 X509Certificate[] signerCertChain = null; 1433 PrivateKey recipient1PrivateKey = null; 1434 X509Certificate recipient1Cert = null; 1435 PrivateKey recipient2PrivateKey = null; 1436 X509Certificate recipient2Cert = null; 1437 1438 // AES-GCM 1439 1440 // AES128-GCM 1441 AlgorithmID contentAuthEncAlg = (AlgorithmID)AlgorithmID.aes128_GCM.clone(); 1442 signerPrivateKey = ecdsa256bitSignerPrivateKey_; 1443 signerCertChain = ecdsa256bitSignerCertChain_; 1444 recipient1PrivateKey = ecdh256bitRecipient1PrivateKey_; 1445 recipient1Cert = ecdh256bitRecipient1Cert_; 1446 recipient2PrivateKey = ecdh256bitRecipient2PrivateKey_; 1447 recipient2Cert = ecdh256bitRecipient2Cert_; 1448 start(contentAuthEncAlg, signerPrivateKey, signerCertChain, recipient1PrivateKey, recipient1Cert, recipient2PrivateKey, recipient2Cert); 1449 // AES192-GCM 1450 contentAuthEncAlg = (AlgorithmID)AlgorithmID.aes192_GCM.clone(); 1451 signerPrivateKey = ecdsa384bitSignerPrivateKey_; 1452 signerCertChain = ecdsa384bitSignerCertChain_; 1453 recipient1PrivateKey = ecdh384bitRecipient1PrivateKey_; 1454 recipient1Cert = ecdh384bitRecipient1Cert_; 1455 recipient2PrivateKey = ecdh384bitRecipient2PrivateKey_; 1456 recipient2Cert = ecdh384bitRecipient2Cert_; 1457 start(contentAuthEncAlg, signerPrivateKey, signerCertChain, recipient1PrivateKey, recipient1Cert, recipient2PrivateKey, recipient2Cert); 1458 // AES256-GCM 1459 contentAuthEncAlg = (AlgorithmID)AlgorithmID.aes256_GCM.clone(); 1460 signerPrivateKey = ecdsa521bitSignerPrivateKey_; 1461 signerCertChain = ecdsa521bitSignerCertChain_; 1462 recipient1PrivateKey = ecdh521bitRecipient1PrivateKey_; 1463 recipient1Cert = ecdh521bitRecipient1Cert_; 1464 recipient2PrivateKey = ecdh521bitRecipient2PrivateKey_; 1465 recipient2Cert = ecdh521bitRecipient2Cert_; 1466 start(contentAuthEncAlg, signerPrivateKey, signerCertChain, recipient1PrivateKey, recipient1Cert, recipient2PrivateKey, recipient2Cert); 1467 1468 // AES-CBC-CMAC 1469 1470 // AES-CBC-CMAC-128 1471 contentAuthEncAlg = (AlgorithmID)AlgorithmID.aes_CBC_CMAC_128.clone(); 1472 signerPrivateKey = ecdsa256bitSignerPrivateKey_; 1473 signerCertChain = ecdsa256bitSignerCertChain_; 1474 recipient1PrivateKey = ecdh256bitRecipient1PrivateKey_; 1475 recipient1Cert = ecdh256bitRecipient1Cert_; 1476 recipient2PrivateKey = ecdh256bitRecipient2PrivateKey_; 1477 recipient2Cert = ecdh256bitRecipient2Cert_; 1478 start(contentAuthEncAlg, signerPrivateKey, signerCertChain, recipient1PrivateKey, recipient1Cert, recipient2PrivateKey, recipient2Cert); 1479 // AES-CBC-CMAC-192 1480 contentAuthEncAlg = (AlgorithmID)AlgorithmID.aes_CBC_CMAC_192.clone(); 1481 signerPrivateKey = ecdsa384bitSignerPrivateKey_; 1482 signerCertChain = ecdsa384bitSignerCertChain_; 1483 recipient1PrivateKey = ecdh384bitRecipient1PrivateKey_; 1484 recipient1Cert = ecdh384bitRecipient1Cert_; 1485 recipient2PrivateKey = ecdh384bitRecipient2PrivateKey_; 1486 recipient2Cert = ecdh384bitRecipient2Cert_; 1487 start(contentAuthEncAlg, signerPrivateKey, signerCertChain, recipient1PrivateKey, recipient1Cert, recipient2PrivateKey, recipient2Cert); 1488 // AES-CBC-CMAC-256 1489 contentAuthEncAlg = (AlgorithmID)AlgorithmID.aes_CBC_CMAC_256.clone(); 1490 signerPrivateKey = ecdsa521bitSignerPrivateKey_; 1491 signerCertChain = ecdsa521bitSignerCertChain_; 1492 recipient1PrivateKey = ecdh521bitRecipient1PrivateKey_; 1493 recipient1Cert = ecdh521bitRecipient1Cert_; 1494 recipient2PrivateKey = ecdh521bitRecipient2PrivateKey_; 1495 recipient2Cert = ecdh521bitRecipient2Cert_; 1496 start(contentAuthEncAlg, signerPrivateKey, signerCertChain, recipient1PrivateKey, recipient1Cert, recipient2PrivateKey, recipient2Cert); 1497 } 1498 1499 /** 1500 * Starts the test for the given content-authenticated encryption algorithm. 1501 * 1502 * @param contentAuthEncAlg the id of the content-authenticated encryption algorithm 1503 */ 1504 public void start(AlgorithmID contentAuthEncAlg, 1505 PrivateKey signerPrivateKey, 1506 X509Certificate[] signerCertChain, 1507 PrivateKey recipient1PrivateKey, 1508 X509Certificate recipient1Cert, 1509 PrivateKey recipient2PrivateKey, 1510 X509Certificate recipient2Cert) { 1511 // the test message 1512 String m = "This is the test message."; 1513 System.out.println("Test message: \""+m+"\""); 1514 System.out.println(); 1515 byte[] message = m.getBytes(); 1516 1517 try { 1518 byte[] encodedAuthEnvelopedData; 1519 byte[] encodedSignedAuthEnvelopedData; 1520 System.out.println("Stream implementation demos"); 1521 System.out.println("==========================="); 1522 1523 AlgorithmID hashAlgorithm = AlgorithmID.sha256; 1524 AlgorithmID signatureAlgorithm = AlgorithmID.ecdsa_With_SHA256; 1525 1526 1527 // the stream implementation 1528 System.out.println("\nCMS Signed AuthEnvelopedDataStream demo [create]:\n"); 1529 // compress content 1530 byte[] compressedData = createCompressedDataStream(message); 1531 encodedAuthEnvelopedData = createAuthEnvelopedDataStream(compressedData, 1532 (AlgorithmID)contentAuthEncAlg.clone(), 1533 recipient1Cert, 1534 recipient2Cert); 1535 encodedSignedAuthEnvelopedData = createSignedDataStream(encodedAuthEnvelopedData, 1536 SignedDataStream.IMPLICIT, 1537 (AlgorithmID)hashAlgorithm.clone(), 1538 (AlgorithmID)signatureAlgorithm.clone(), 1539 signerPrivateKey, 1540 signerCertChain); 1541 1542 // transmit data 1543 System.out.println("\nCMS Signed AuthEnvelopedDataStream demo [parse]:\n"); 1544 // verify signature 1545 encodedAuthEnvelopedData = getSignedDataStream(encodedSignedAuthEnvelopedData, null, signerCertChain); 1546 // parse contents 1547 System.out.println("Decrypt for the several recipients using their index into the recipientInfos field."); 1548 parseAuthEnvelopedDataWithRecipientInfoIndex(true, encodedAuthEnvelopedData, recipient1PrivateKey, recipient2PrivateKey); 1549 System.out.println("Decrypt for the several recipients using their RecipientIdentifier."); 1550 parseAuthEnvelopedDataWithRecipientIdentifier(true, encodedAuthEnvelopedData, recipient1PrivateKey, recipient1Cert, recipient2PrivateKey, recipient2Cert); 1551 System.out.println("Decrypt for the several recipients using their certificate."); 1552 parseAuthEnvelopedDataWithRecipientCert(true, encodedAuthEnvelopedData, recipient1PrivateKey, recipient1Cert, recipient2PrivateKey, recipient2Cert); 1553 1554 // the non-stream implementation 1555 System.out.println("\nNon-stream implementation demos"); 1556 System.out.println("==============================="); 1557 1558 1559 System.out.println("\nCMS Signed AuthEnvelopedData demo [create]:\n"); 1560 // compress content 1561 compressedData = createCompressedData(message); 1562 encodedAuthEnvelopedData = createAuthEnvelopedData(compressedData, 1563 (AlgorithmID)contentAuthEncAlg.clone(), 1564 recipient1Cert, 1565 recipient2Cert); 1566 encodedSignedAuthEnvelopedData = createSignedData(encodedAuthEnvelopedData, 1567 SignedData.IMPLICIT, 1568 (AlgorithmID)hashAlgorithm.clone(), 1569 (AlgorithmID)signatureAlgorithm.clone(), 1570 signerPrivateKey, 1571 signerCertChain); 1572 // transmit data 1573 System.out.println("\nCMS Signed AuthEnvelopedData demo [parse]:\n"); 1574 // verify signature 1575 encodedAuthEnvelopedData = getSignedData(encodedSignedAuthEnvelopedData, null, signerCertChain); 1576 // parse contents 1577 System.out.println("Decrypt for the several recipients using their index into the recipientInfos field."); 1578 parseAuthEnvelopedDataWithRecipientInfoIndex(false, encodedAuthEnvelopedData, recipient1PrivateKey, recipient2PrivateKey); 1579 System.out.println("Decrypt for the several recipients using their RecipientIdentifier."); 1580 parseAuthEnvelopedDataWithRecipientIdentifier(false, encodedAuthEnvelopedData, recipient1PrivateKey, recipient1Cert, recipient2PrivateKey, recipient2Cert); 1581 System.out.println("Decrypt for the several recipients using their certificate."); 1582 parseAuthEnvelopedDataWithRecipientCert(false, encodedAuthEnvelopedData, recipient1PrivateKey, recipient1Cert, recipient2PrivateKey, recipient2Cert); 1583 1584 1585 System.out.println("OutputStream implementation demos"); 1586 System.out.println("==========================="); 1587 1588 1589 // the stream implementation 1590 System.out.println("\nCMS Signed AuthEnvelopedDataOutputStream demo [create]:\n"); 1591 // compression of content is done in method createAuthEnvelopedDataOutputStream 1592 encodedAuthEnvelopedData = createAuthEnvelopedDataOutputStream(message, 1593 (AlgorithmID)contentAuthEncAlg.clone(), recipient1Cert, 1594 recipient2Cert); 1595 encodedSignedAuthEnvelopedData = createSignedDataStream(encodedAuthEnvelopedData, 1596 SignedDataStream.IMPLICIT, 1597 (AlgorithmID)hashAlgorithm.clone(), 1598 (AlgorithmID)signatureAlgorithm.clone(), 1599 signerPrivateKey, 1600 signerCertChain); 1601 1602 // transmit data 1603 System.out.println("\nCMS Signed AuthEnvelopedDataStream demo [parse]:\n"); 1604 // verify signature 1605 encodedAuthEnvelopedData = getSignedDataStream(encodedSignedAuthEnvelopedData, null, signerCertChain); 1606 // parse contents 1607 System.out.println("Decrypt for the several recipients using their index into the recipientInfos field."); 1608 parseAuthEnvelopedDataWithRecipientInfoIndex(true, encodedAuthEnvelopedData, recipient1PrivateKey, recipient2PrivateKey); 1609 System.out.println("Decrypt for the several recipients using their RecipientIdentifier."); 1610 parseAuthEnvelopedDataWithRecipientIdentifier(true, encodedAuthEnvelopedData, recipient1PrivateKey, recipient1Cert, recipient2PrivateKey, recipient2Cert); 1611 System.out.println("Decrypt for the several recipients using their certificate."); 1612 parseAuthEnvelopedDataWithRecipientCert(true, encodedAuthEnvelopedData, recipient1PrivateKey, recipient1Cert, recipient2PrivateKey, recipient2Cert); 1613 1614 1615 } catch (Exception ex) { 1616 ex.printStackTrace(); 1617 throw new RuntimeException(ex.toString()); 1618 } 1619 } 1620 1621 1622 /** 1623 * Main method. 1624 * 1625 * @throws IOException 1626 * if an I/O error occurs when reading required keys 1627 * and certificates from files 1628 */ 1629 public static void main(String argv[]) throws Exception { 1630 1631 DemoUtil.initDemos(); 1632 ECCDemoUtil.installIaikEccProvider(); 1633 1634 (new EckaEGAuthEnvelopedDataDemo()).start(); 1635 System.out.println("\nReady!"); 1636 DemoUtil.waitKey(); 1637 } 1638 }