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/basic/CMSDemo.java 42 12.02.25 17:58 Dbratko $ 059 // $Revision: 42 $ 060 // 061 062 package demo.cms.basic; 063 064 import java.io.ByteArrayInputStream; 065 import java.io.ByteArrayOutputStream; 066 import java.io.IOException; 067 import java.io.InputStream; 068 import java.security.InvalidAlgorithmParameterException; 069 import java.security.InvalidKeyException; 070 import java.security.NoSuchAlgorithmException; 071 import java.security.PrivateKey; 072 import java.security.SignatureException; 073 import java.security.spec.InvalidParameterSpecException; 074 075 import demo.DemoUtil; 076 import demo.keystore.CMSKeyStore; 077 import iaik.asn1.ObjectID; 078 import iaik.asn1.structures.AlgorithmID; 079 import iaik.asn1.structures.Attribute; 080 import iaik.cms.AuthenticatedData; 081 import iaik.cms.AuthenticatedDataStream; 082 import iaik.cms.CMSException; 083 import iaik.cms.ContentInfo; 084 import iaik.cms.ContentInfoStream; 085 import iaik.cms.Data; 086 import iaik.cms.DataStream; 087 import iaik.cms.DigestedData; 088 import iaik.cms.DigestedDataStream; 089 import iaik.cms.EncryptedContentInfo; 090 import iaik.cms.EncryptedContentInfoStream; 091 import iaik.cms.EncryptedData; 092 import iaik.cms.EncryptedDataStream; 093 import iaik.cms.EnvelopedData; 094 import iaik.cms.EnvelopedDataStream; 095 import iaik.cms.IssuerAndSerialNumber; 096 import iaik.cms.KeyTransRecipientInfo; 097 import iaik.cms.RecipientInfo; 098 import iaik.cms.SignedData; 099 import iaik.cms.SignedDataStream; 100 import iaik.cms.SignerInfo; 101 import iaik.cms.attributes.CMSContentType; 102 import iaik.cms.attributes.SigningTime; 103 import iaik.utils.Util; 104 import iaik.x509.X509Certificate; 105 106 /** 107 * This class shows some CMS examples where the content types are 108 * wrapped into a ContentInfo. 109 * <p> 110 * All keys and certificates are read from a keystore created by the 111 * SetupCMSKeyStore program. 112 * <p> 113 * This class demonstrates how to wrap the several CMS types into ContentInfos: 114 * <p><ul> 115 * <li>Data 116 * <li>AuthenticatedData 117 * <li>EncryptedData for PBE encrypting the content 118 * <li>EnvelopedData 119 * <li>DigestedData including the message 120 * <li>DigestedData without message 121 * <li>SignedData including the message 122 * <li>SignedData without message 123 * </ul><p> 124 * Additionally, a <i>SignedAndEncryptedData</i> test is performed, which 125 * is a sequential combination of signed and enveloped data content types. 126 * <p> 127 * All sub-tests use the same proceeding: A test message is properly 128 * processed to give the requested content type object, which subsequently 129 * is encoded to be "sent" to some recipient, who parses it for the 130 * inherent structures. 131 */ 132 public class CMSDemo { 133 134 // signing certificate of user 1 135 X509Certificate user1_sign; 136 // signing private key of user 1 137 PrivateKey user1_sign_pk; 138 // signing certificate of user 2 139 X509Certificate user2_sign; 140 // signing private key of user 2 141 PrivateKey user2_sign_pk; 142 143 // encryption certificate of user 1 144 X509Certificate user1_crypt; 145 // encryption private key of user 1 146 PrivateKey user1_crypt_pk; 147 // encryption certificate of user 2 148 X509Certificate user2_crypt; 149 // encryption private key of user 2 150 PrivateKey user2_crypt_pk; 151 // a certificate chain containing the user certs + CA 152 153 X509Certificate[] certificates; 154 155 156 /** 157 * Setup the demo certificate chains. 158 * 159 * Keys and certificate are retrieved from the demo KeyStore. 160 * 161 * @throws IOException if an file read error occurs 162 */ 163 public CMSDemo() throws IOException { 164 165 System.out.println(); 166 System.out.println("***************************************************************************************"); 167 System.out.println("* Basic CMS Demo *"); 168 System.out.println("* (shows the usage of the several CMS content type implementations) *"); 169 System.out.println("***************************************************************************************"); 170 System.out.println(); 171 172 173 // signing certs 174 X509Certificate[] certs = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1); 175 user1_sign = certs[0]; 176 user1_sign_pk = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1); 177 user2_sign = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1)[0]; 178 user2_sign_pk = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1); 179 certificates = new X509Certificate[certs.length+1]; 180 System.arraycopy(certs, 0, certificates, 0, certs.length); 181 certificates[certs.length] = user2_sign; 182 183 // encryption certs 184 user1_crypt = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0]; 185 user1_crypt_pk = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1); 186 user2_crypt = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0]; 187 user2_crypt_pk = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2); 188 189 } 190 191 /** 192 * Creates a CMS <code>Data</code> object and wraps it into a ContentInfo. 193 * <p> 194 * @param message the message to be sent, as byte representation 195 * @return the encoded ContentInfo containing the <code>Data</code> object just created 196 * @throws CMSException if the <code>Data</code> object cannot 197 * be created 198 * @throws IOException if an I/O error occurs 199 */ 200 public byte[] createDataStream(byte[] message) throws CMSException, IOException { 201 202 System.out.println("Create a new Data message:"); 203 204 // we are testing the stream interface 205 ByteArrayInputStream is = new ByteArrayInputStream(message); 206 207 // create a new Data object which includes the data 208 DataStream data = new DataStream(is, 2048); 209 210 ContentInfoStream cis = new ContentInfoStream(data); 211 // return the ContentInfo as BER encoded byte array where Data is encoded with block size 2048 212 ByteArrayOutputStream os = new ByteArrayOutputStream(); 213 cis.writeTo(os); 214 return os.toByteArray(); 215 } 216 217 /** 218 * Parses a CMS <code>Data</code> object. 219 * 220 * @param data the encoded ContentInfo holding the <code>Data</code> 221 * 222 * @return the inherent message as byte array 223 * @throws CMSException if an parsing exception occurs 224 * @throws IOException if an I/O error occurs 225 */ 226 public byte[] getDataStream(byte[] data) throws CMSException, IOException { 227 228 // we are testing the stream interface 229 ByteArrayInputStream is = new ByteArrayInputStream(data); 230 ContentInfoStream cis = new ContentInfoStream(is); 231 System.out.println("This ContentInfo holds content of type " + cis.getContentType().getName()); 232 // create the Data object 233 DataStream dataStream = (DataStream)cis.getContent(); 234 235 // get an InputStream for reading the signed content 236 InputStream content = dataStream.getInputStream(); 237 ByteArrayOutputStream os = new ByteArrayOutputStream(); 238 Util.copyStream(content, os, null); 239 240 return os.toByteArray(); 241 } 242 243 /** 244 * Creates a CMS <code>EnvelopedData</code> and wraps it into a ContentInfo. 245 * 246 * @param message the message to be enveloped, as byte representation 247 * @return the encoded ContentInfo containing the EnvelopedData object just created 248 * 249 * @throws CMSException if the <code>EnvelopedData</code> object cannot 250 * be created 251 * @throws IOException if an I/O error occurs 252 */ 253 public byte[] createEnvelopedDataStream(byte[] message) throws CMSException, IOException { 254 255 EnvelopedDataStream enveloped_data; 256 257 // we are testing the stream interface 258 ByteArrayInputStream is = new ByteArrayInputStream(message); 259 // create a new EnvelopedData object encrypted with TripleDES CBC 260 try { 261 enveloped_data = new EnvelopedDataStream(is, (AlgorithmID)AlgorithmID.aes256_CBC.clone()); 262 } catch (NoSuchAlgorithmException ex) { 263 throw new CMSException(ex.toString()); 264 } 265 266 // create the recipient infos 267 RecipientInfo[] recipients = new RecipientInfo[2]; 268 // user1 is the first receiver 269 recipients[0] = new KeyTransRecipientInfo(user1_crypt, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 270 // user2 is the second receiver 271 recipients[1] = new KeyTransRecipientInfo(user2_crypt, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 272 273 // specify the recipients of the encrypted message 274 enveloped_data.setRecipientInfos(recipients); 275 276 // return the EnvelopedDate as DER encoded byte array with block size 2048 277 ByteArrayOutputStream os = new ByteArrayOutputStream(); 278 enveloped_data.setBlockSize(2048); 279 ContentInfoStream cis = new ContentInfoStream(enveloped_data); 280 cis.writeTo(os); 281 return os.toByteArray(); 282 } 283 284 /** 285 * Decrypts the encrypted content of the given EnvelopedData object for the 286 * specified recipient and returns the decrypted (= original) message. 287 * 288 * @param encoding the encoded ContentInfo containing an EnvelopedData object 289 * @param privateKey the private key to decrypt the message 290 * @param recipientInfoIndex the index into the <code>RecipientInfo</code> array 291 * to which the specified private key belongs 292 * 293 * @return the recovered message, as byte array 294 * @throws CMSException if the message cannot be recovered 295 * @throws IOException if an I/O error occurs 296 */ 297 public byte[] getEnvelopedDataStream(byte[] encoding, PrivateKey privateKey, int recipientInfoIndex) throws CMSException, IOException { 298 299 // create the EnvelopedData object from a DER encoded byte array 300 // we are testing the stream interface 301 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 302 ContentInfoStream cis = new ContentInfoStream(is); 303 EnvelopedDataStream enveloped_data = (EnvelopedDataStream)cis.getContent(); 304 305 System.out.println("Information about the encrypted data:"); 306 EncryptedContentInfoStream eci = (EncryptedContentInfoStream)enveloped_data.getEncryptedContentInfo(); 307 System.out.println("Content type: "+eci.getContentType().getName()); 308 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 309 310 System.out.println("\nThis message can be decrypted by the owners of the following certificates:"); 311 RecipientInfo[] recipients = enveloped_data.getRecipientInfos(); 312 for (int i=0; i<recipients.length; i++) { 313 System.out.println("Recipient "+(i+1)+":"); 314 System.out.println(recipients[i].getRecipientIdentifiers()[0]); 315 } 316 317 // decrypt the message 318 try { 319 enveloped_data.setupCipher(privateKey, recipientInfoIndex); 320 InputStream decrypted = enveloped_data.getInputStream(); 321 ByteArrayOutputStream os = new ByteArrayOutputStream(); 322 Util.copyStream(decrypted, os, null); 323 324 return os.toByteArray(); 325 326 } catch (InvalidKeyException ex) { 327 throw new CMSException("Private key error: "+ex.toString()); 328 } catch (NoSuchAlgorithmException ex) { 329 throw new CMSException("Content encryption algorithm not implemented: "+ex.toString()); 330 } 331 } 332 333 /** 334 * Creates a CMS <code>SignedData</code> object ans wraps it into a ContentInfo. 335 * <p> 336 * 337 * @param message the message to be signed, as byte representation 338 * @param mode the mode indicating whether to include the content 339 * (SignedDataStream.IMPLICIT) or not (SignedDataStream.EXPLICIT) 340 * @return the encoding of the ContentInfo holding the <code>SignedData</code> object just created 341 * @throws CMSException if the <code>SignedData</code> object cannot 342 * be created 343 * @throws IOException if an I/O error occurs 344 */ 345 public byte[] createSignedDataStream(byte[] message, int mode) throws CMSException, IOException { 346 347 System.out.println("Create a new message signed by user 1:"); 348 349 // we are testing the stream interface 350 ByteArrayInputStream is = new ByteArrayInputStream(message); 351 // create a new SignedData object which includes the data 352 SignedDataStream signed_data = new SignedDataStream(is, mode); 353 // SignedData shall include the certificate chain for verifying 354 signed_data.setCertificates(certificates); 355 356 // cert at index 0 is the user certificate 357 IssuerAndSerialNumber issuer = new IssuerAndSerialNumber(user1_sign); 358 359 // create a new SignerInfo 360 SignerInfo signer_info = new SignerInfo(issuer, (AlgorithmID)AlgorithmID.sha256.clone(), AlgorithmID.sha256WithRSAEncryption, user1_sign_pk); 361 362 // create some signed attributes 363 // the message digest attribute is automatically added 364 Attribute[] attributes = new Attribute[2]; 365 try { 366 // content type is data 367 CMSContentType contentType = new CMSContentType(ObjectID.cms_data); 368 attributes[0] = new Attribute(contentType); 369 // signing time is now 370 SigningTime signingTime = new SigningTime(); 371 attributes[1] = new Attribute(signingTime); 372 } catch (Exception ex) { 373 throw new CMSException("Error creating attribute: " + ex.toString()); 374 } 375 376 // set the attributes 377 signer_info.setSignedAttributes(attributes); 378 // finish the creation of SignerInfo by calling method addSigner 379 try { 380 signed_data.addSignerInfo(signer_info); 381 382 // another SignerInfo without authenticated attributes 383 signer_info = new SignerInfo(new IssuerAndSerialNumber(user2_sign), 384 (AlgorithmID)AlgorithmID.sha256.clone(), user2_sign_pk); 385 // the message digest itself is protected 386 signed_data.addSignerInfo(signer_info); 387 388 } catch (NoSuchAlgorithmException ex) { 389 throw new CMSException("No implementation for signature algorithm: "+ex.getMessage()); 390 } 391 // ensure block encoding 392 signed_data.setBlockSize(2048); 393 394 // write the data through SignedData to any out-of-band place 395 if (mode == SignedDataStream.EXPLICIT) { 396 InputStream data_is = signed_data.getInputStream(); 397 byte[] buf = new byte[1024]; 398 int r; 399 while ((r = data_is.read(buf)) > 0) { 400 ; // skip data 401 } 402 } 403 404 // create the ContentInfo 405 ContentInfoStream cis = new ContentInfoStream(signed_data); 406 // return the SignedData as encoded byte array with block size 2048 407 ByteArrayOutputStream os = new ByteArrayOutputStream(); 408 409 cis.writeTo(os); 410 return os.toByteArray(); 411 } 412 413 /** 414 * Parses a CMS <code>SignedData</code> object and verifies the signatures 415 * for all participated signers. 416 * 417 * @param signedData the ContentInfo with inherent SignedData, as BER encoded byte array 418 * @param message the the message which was transmitted out-of-band (explicit signed) 419 * 420 * @return the inherent message as byte array, or <code>null</code> if there 421 * is no message included into the supplied <code>SignedData</code> 422 * object 423 * @throws CMSException if any signature does not verify 424 * @throws IOException if an I/O error occurs 425 */ 426 public byte[] getSignedDataStream(byte[] signedData, byte[] message) throws CMSException, IOException { 427 428 // we are testing the stream interface 429 ByteArrayInputStream is = new ByteArrayInputStream(signedData); 430 // create the ContentInfo object 431 SignedDataStream signed_data = new SignedDataStream(is); 432 433 if (signed_data.getMode() == SignedDataStream.EXPLICIT) { 434 // explicitly signed; set the content received by other means 435 signed_data.setInputStream(new ByteArrayInputStream(message)); 436 } 437 438 // get an InputStream for reading the signed content 439 InputStream data = signed_data.getInputStream(); 440 ByteArrayOutputStream os = new ByteArrayOutputStream(); 441 Util.copyStream(data, os, null); 442 443 System.out.println("SignedData contains the following signer information:"); 444 SignerInfo[] signer_infos = signed_data.getSignerInfos(); 445 int numberOfSignerInfos = signer_infos.length; 446 if (numberOfSignerInfos == 0) { 447 String warning = "Warning: Unsigned message (no SignerInfo included)!"; 448 System.err.println(warning); 449 throw new CMSException(warning); 450 } else { 451 for (int i = 0; i < numberOfSignerInfos; i++) { 452 try { 453 // verify the signed data using the SignerInfo at index i 454 X509Certificate signer_cert = signed_data.verify(i); 455 // if the signature is OK the certificate of the signer is returned 456 System.out.println("Signature OK from signer: "+signer_cert.getSubjectDN()); 457 // get signed attributes 458 SigningTime signingTime = (SigningTime)signer_infos[i].getSignedAttributeValue(ObjectID.signingTime); 459 if (signingTime != null) { 460 System.out.println("This message has been signed at " + signingTime.get()); 461 } 462 CMSContentType contentType = (CMSContentType)signer_infos[i].getSignedAttributeValue(ObjectID.contentType); 463 if (contentType != null) { 464 System.out.println("The content has CMS content type " + contentType.get().getName()); 465 } 466 467 } catch (SignatureException ex) { 468 // if the signature is not OK a SignatureException is thrown 469 System.out.println("Signature ERROR from signer: "+signed_data.getCertificate((signer_infos[i].getSignerIdentifier())).getSubjectDN()); 470 throw new CMSException(ex.toString()); 471 } 472 } 473 // now check alternative signature verification 474 System.out.println("Now check the signature assuming that no certs have been included:"); 475 try { 476 SignerInfo signer_info = signed_data.verify(user1_sign); 477 // if the signature is OK the certificate of the signer is returned 478 System.out.println("Signature OK from signer: "+signed_data.getCertificate(signer_info.getSignerIdentifier()).getSubjectDN()); 479 480 } catch (SignatureException ex) { 481 // if the signature is not OK a SignatureException is thrown 482 System.out.println("Signature ERROR from signer: "+user1_sign.getSubjectDN()); 483 throw new CMSException(ex.toString()); 484 } 485 486 try { 487 SignerInfo signer_info = signed_data.verify(user2_sign); 488 // if the signature is OK the certificate of the signer is returned 489 System.out.println("Signature OK from signer: "+signed_data.getCertificate(signer_info.getSignerIdentifier()).getSubjectDN()); 490 491 } catch (SignatureException ex) { 492 // if the signature is not OK a SignatureException is thrown 493 System.out.println("Signature ERROR from signer: "+user2_sign.getSubjectDN()); 494 throw new CMSException(ex.toString()); 495 } 496 497 // in practice we also would validate the signer certificate(s) 498 } 499 500 return os.toByteArray(); 501 } 502 503 504 /** 505 * Creates a <i>SignedAndEncrypted</i> (i.e. sequential combination of <code> 506 * SignedData</code> and <code>EnvelopedData</code>). 507 * 508 * @param message the message to be signed and encrypted, as byte representation 509 * @return the encoded ContentInfo holding the signed and encrypted message object 510 * just created 511 * @throws CMSException if the the <code>SignedData</code> or 512 * <code>EnvelopedData</code> object cannot be created 513 * @throws IOException if an I/O error occurs 514 */ 515 public byte[] createSignedAndEncryptedDataStream(byte[] message) throws CMSException, IOException { 516 517 System.out.println("Create a new message signed by user1 encrypted for user2:"); 518 519 byte[] signed = createSignedDataStream(message, SignedData.IMPLICIT); 520 return createEnvelopedDataStream(signed); 521 } 522 523 /** 524 * Recovers the original message and verifies the signature. 525 * 526 * @param in the encoded CMS object 527 * @return the recovered message, as byte array 528 * @throws CMSException if the message cannot be recovered 529 * @throws IOException if an I/O error occurs 530 */ 531 public byte[] getSignedAndEncryptedDataStream(byte[] in) throws CMSException, IOException { 532 533 // user2 means index 2 (hardcoded for this demo) 534 byte[] signed = getEnvelopedDataStream(in, user2_crypt_pk, 1); 535 return getSignedDataStream(signed, null); 536 } 537 538 539 /** 540 * Creates a CMS <code>DigestedData</code> object. 541 * <p> 542 * @param message the message to be digested, as byte representation 543 * @return the encoded ContentInfo containing the DigestedData object just created 544 * @throws CMSException if the <code>DigestedData</code> object cannot 545 * be created 546 * @throws IOException if an I/O error occurs 547 */ 548 public byte[] createDigestedDataStream(byte[] message, int mode) throws CMSException, IOException { 549 550 System.out.println("Create a new message to be digested:"); 551 552 // we are testing the stream interface 553 ByteArrayInputStream is = new ByteArrayInputStream(message); 554 555 // create a new DigestedData object which includes the data 556 DigestedDataStream digested_data = null; 557 558 digested_data = new DigestedDataStream(is, (AlgorithmID)AlgorithmID.sha256.clone(), mode); 559 digested_data.setBlockSize(2048); 560 561 // write the data through DigestedData to any out-of-band place 562 if (mode == DigestedDataStream.EXPLICIT) { 563 InputStream data_is = digested_data.getInputStream(); 564 byte[] buf = new byte[1024]; 565 int r; 566 while ((r = data_is.read(buf)) > 0) { 567 ; // skip data 568 } 569 } 570 571 // wrap into ContentInfo and encode 572 ByteArrayOutputStream os = new ByteArrayOutputStream(); 573 ContentInfoStream cis = new ContentInfoStream(digested_data); 574 cis.writeTo(os); 575 return os.toByteArray(); 576 } 577 578 /** 579 * Parses a CMS <code>DigestedData</code> object and verifies the hash. 580 * 581 * @param digestedData the encoded ContentInfo holding a DigestedData object 582 * @param message the the message which was transmitted out-of-band 583 * 584 * @return the inherent message as byte array, or <code>null</code> if there 585 * is no message included into the supplied <code>DigestedData</code> 586 * object 587 * @throws CMSException if any signature does not verify 588 * @throws IOException if an I/O error occurs 589 */ 590 public byte[] getDigestedDataStream(byte[] digestedData, byte[] message) throws CMSException, IOException { 591 592 // we are testing the stream interface 593 ByteArrayInputStream is = new ByteArrayInputStream(digestedData); 594 // create the DigestedData object 595 DigestedDataStream digested_data = new DigestedDataStream(is); 596 if (digested_data.getMode() == DigestedDataStream.EXPLICIT) { 597 digested_data.setInputStream(new ByteArrayInputStream(message)); 598 } 599 600 // get an InputStream for reading the signed content 601 InputStream data = digested_data.getInputStream(); 602 ByteArrayOutputStream os = new ByteArrayOutputStream(); 603 Util.copyStream(data, os, null); 604 605 if (digested_data.verify()) { 606 System.out.println("Hash ok!"); 607 } else { 608 throw new CMSException("Hash verification failed!"); 609 } 610 611 return os.toByteArray(); 612 } 613 614 /** 615 * Creates a CMS <code>EncryptedDataStream</code> message. 616 * <p> 617 * The supplied content is PBE-encrypted using the specified password. 618 * 619 * @param message the message to be encrypted, as byte representation 620 * @param pbeAlgorithm the PBE algorithm to be used 621 * @param password the password 622 * @return the DER encoding of the ContentInfo holding the <code>EncryptedData</code> object just created 623 * @throws CMSException if the <code>EncryptedData</code> object cannot 624 * be created 625 * @throws IOException if an I/O error occurs 626 */ 627 public byte[] createEncryptedDataStream(byte[] message, AlgorithmID pbeAlgorithm, char[] password) throws CMSException, IOException { 628 629 EncryptedDataStream encrypted_data; 630 631 // we are testing the stream interface 632 ByteArrayInputStream is = new ByteArrayInputStream(message); 633 634 try { 635 encrypted_data = new EncryptedDataStream(is, 2048); 636 encrypted_data.setupCipher(pbeAlgorithm, password); 637 } catch (InvalidKeyException ex) { 638 throw new CMSException("Key error: "+ex.toString()); 639 } catch (NoSuchAlgorithmException ex) { 640 throw new CMSException("Content encryption algorithm not implemented: "+ex.toString()); 641 } 642 643 // wrap into ContentInfo and encode 644 ByteArrayOutputStream os = new ByteArrayOutputStream(); 645 ContentInfoStream cis = new ContentInfoStream(encrypted_data); 646 cis.writeTo(os); 647 return os.toByteArray(); 648 } 649 650 /** 651 * Decrypts the PBE-encrypted content of the given <code>EncryptedData</code> object 652 * using the specified password and returns the decrypted (= original) message. 653 * 654 * @param encoding the encoded ContentInfo holding an <code>EncryptedData</code> object 655 * @param password the password to decrypt the message 656 * 657 * @return the recovered message, as byte array 658 * @throws CMSException if the message cannot be recovered 659 * @throws IOException if an I/O error occurs 660 */ 661 public byte[] getEncryptedDataStream(byte[] encoding, char[] password) throws CMSException, IOException { 662 663 // create the EncryptpedData object from a DER encoded byte array 664 // we are testing the stream interface 665 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 666 // create the ContentInfo 667 ContentInfoStream cis = new ContentInfoStream(is); 668 669 EncryptedDataStream encrypted_data = (EncryptedDataStream)cis.getContent(); 670 671 System.out.println("Information about the encrypted data:"); 672 EncryptedContentInfoStream eci = encrypted_data.getEncryptedContentInfo(); 673 System.out.println("Content type: "+eci.getContentType().getName()); 674 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 675 676 // decrypt the message 677 try { 678 encrypted_data.setupCipher(password); 679 InputStream decrypted = encrypted_data.getInputStream(); 680 ByteArrayOutputStream os = new ByteArrayOutputStream(); 681 Util.copyStream(decrypted, os, null); 682 683 return os.toByteArray(); 684 685 } catch (InvalidKeyException ex) { 686 throw new CMSException("Key error: "+ex.toString()); 687 } catch (NoSuchAlgorithmException ex) { 688 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage()); 689 } catch (InvalidAlgorithmParameterException ex) { 690 throw new CMSException("Invalid Parameters: "+ex.getMessage()); 691 } catch (InvalidParameterSpecException ex) { 692 throw new CMSException("Invalid Parameters: "+ex.getMessage()); 693 } 694 } 695 696 /** 697 * Creates a CMS <code>AuthenticatedDataStream</code> for the given message message. 698 * <p> 699 * <b>Attention:</b> This AuthenticatedData demo uses RSA as key management technique. 700 * In practice (see RFC 5652) a key management technique that provides data origin 701 * authentication should be used like, for instance, Static-Static Diffie-Hellman when 702 * both the originator and recipient public keys are bound to appropriate identities 703 * in X.509 certificates, see, for instance, {@link demo.cms.authenticatedData.AuthenticatedDataDemo 704 * AuthenticatedDataDemo}. 705 * 706 * @param message the message to be authenticated, as byte representation 707 * @param includeAuthAttrs whether to include authenticated attributes 708 * @param mode the mode indicating whether to include the content 709 * (AuthenticatedDataStream.IMPLICIT) or not (AuthenticatedDataStream.EXPLICIT) 710 * @return the BER encoding of the <code>AuthenticatedData</code> object, wrapped in a ContentInfo 711 * @throws CMSException if the <code>AuthenticatedData</code> object cannot 712 * be created 713 * @throws IOException if an I/O error occurs 714 */ 715 public byte[] createAuthenticatedDataStream(byte[] message, 716 boolean includeAuthAttrs, 717 int mode) 718 throws CMSException, IOException { 719 720 AlgorithmID macAlgorithm = (AlgorithmID)AlgorithmID.hMAC_SHA256.clone(); 721 int macKeyLength = 32; 722 AlgorithmID digestAlgorithm = null; 723 // we need a digest algorithm if authenticated attributes shall be included 724 if (includeAuthAttrs == true) { 725 digestAlgorithm = (AlgorithmID)AlgorithmID.sha256.clone(); 726 } 727 ObjectID contentType = ObjectID.cms_data; 728 729 AuthenticatedDataStream authenticatedData; 730 731 // we are testing the stream interface 732 ByteArrayInputStream is = new ByteArrayInputStream(message); 733 // create a new AuthenticatedData object 734 try { 735 authenticatedData = new AuthenticatedDataStream(contentType, 736 is, 737 macAlgorithm, 738 macKeyLength, 739 null, 740 digestAlgorithm, 741 mode); 742 } catch (NoSuchAlgorithmException ex) { 743 throw new CMSException(ex.toString()); 744 } 745 746 // create the recipient infos 747 RecipientInfo[] recipients = new RecipientInfo[2]; 748 // user1 is the first receiver 749 recipients[0] = new KeyTransRecipientInfo(user1_crypt, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 750 // user2 is the second receiver 751 recipients[1] = new KeyTransRecipientInfo(user2_crypt, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 752 // specify the recipients of the authenticated message 753 authenticatedData.setRecipientInfos(recipients); 754 755 if (includeAuthAttrs == true) { 756 // create some autheticated attributes 757 // (the message digest attribute is automatically added) 758 try { 759 Attribute[] attributes = { new Attribute(new CMSContentType(contentType)) }; 760 authenticatedData.setAuthenticatedAttributes(attributes); 761 } catch (Exception ex) { 762 throw new CMSException("Error creating attribute: " + ex.toString()); 763 } 764 } 765 766 // in explicit mode get the content and write it to any out-of-band place 767 if (mode == AuthenticatedDataStream.EXPLICIT) { 768 InputStream data_is = authenticatedData.getInputStream(); 769 byte[] buf = new byte[1024]; 770 int r; 771 while ((r = data_is.read(buf)) > 0) { 772 ; // skip data 773 } 774 } 775 776 // create the ContentInfo 777 ContentInfoStream cis = new ContentInfoStream(authenticatedData); 778 // return the AuthenticatedData as encoded byte array with block size 2048 779 ByteArrayOutputStream os = new ByteArrayOutputStream(); 780 781 cis.writeTo(os); 782 return os.toByteArray(); 783 } 784 785 /** 786 * Decrypts the encrypted MAC key for the recipient identified by its index 787 * into the recipientInfos field and uses the MAC key to verify 788 * the authenticated data. 789 * <p> 790 * This way of decrypting the MAC key and verifying the content may be used for 791 * any type of RecipientInfo (KeyTransRecipientInfo, KeyAgreeRecipientInfo, 792 * KEKRecipientInfo), but requires to know at what index of the recipientInfos 793 * field the RecipientInfo for the particular recipient in mind can be found. 794 * If the recipient in mind uses a RecipientInfo of type KeyAgreeRecipientInfo 795 * some processing overhead may take place because a KeyAgreeRecipientInfo may 796 * contain encrypted mac keys for more than only one recipient; since the 797 * recipientInfoIndex only specifies the RecipientInfo but not the encrypted 798 * mac key -- if there are more than only one -- repeated decryption runs may be 799 * required as long as the decryption process completes successfully. 800 * <p> 801 * <b>Attention:</b> This AuthenticatedData demo uses RSA as key management technique. 802 * In practice (see RFC 5652) a key management technique that provides data origin 803 * authentication should be used like, for instance, Static-Static Diffie-Hellman when 804 * both the originator and recipient public keys are bound to appropriate identities 805 * in X.509 certificates, see, for instance, {@link demo.cms.authenticatedData.AuthenticatedDataDemo 806 * AuthenticatedDataDemo}. 807 * 808 * @param encoding the BER encoded ContentInfo holding the <code>AuthenticatedData</code> object 809 * @param message the content message, if transmitted by other means (explicit mode) 810 * @param key the key to decrypt the mac key 811 * @param recipientInfoIndex the index of the right <code>RecipientInfo</code> to 812 * which the given key belongs 813 * 814 * @return the verified message, as byte array 815 * @throws CMSException if the authenticated data cannot be verified 816 * @throws IOException if a stream read/write error occurs 817 */ 818 public byte[] getAuthenticatedDataStream(byte[] encoding, 819 byte[] message, 820 PrivateKey key, 821 int recipientInfoIndex) 822 throws CMSException, IOException { 823 824 // create the AuthenticatedData object from a DER encoded byte array 825 // we are testing the stream interface 826 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 827 // create the ContentInfo object 828 ContentInfoStream cis = new ContentInfoStream(is); 829 System.out.println("This ContentInfo holds content of type " + cis.getContentType().getName()); 830 AuthenticatedDataStream authenticatedData = (AuthenticatedDataStream)cis.getContent(); 831 832 if (authenticatedData.getMode() == AuthenticatedDataStream.EXPLICIT) { 833 // in explicit mode explicitly supply the content for hash/mac computation 834 authenticatedData.setInputStream(new ByteArrayInputStream(message)); 835 } 836 837 System.out.println("\nThis message can be verified by the following recipients:"); 838 RecipientInfo[] recipients = authenticatedData.getRecipientInfos(); 839 for (int i=0; i<recipients.length; i++) { 840 System.out.println("Recipient "+(i+1)+":"); 841 System.out.println(recipients[i].getRecipientIdentifiers()[0]); 842 } 843 844 // decrypt the mac key and verify the mac for indented recipient 845 try { 846 authenticatedData.setupMac(key, recipientInfoIndex); 847 InputStream contentStream = authenticatedData.getInputStream(); 848 ByteArrayOutputStream os = new ByteArrayOutputStream(); 849 Util.copyStream(contentStream, os, null); 850 851 if (authenticatedData.verifyMac() == false) { 852 throw new CMSException("Mac verification error!"); 853 } 854 System.out.println("Mac successfully verified!"); 855 856 return os.toByteArray(); 857 858 } catch (InvalidKeyException ex) { 859 throw new CMSException("Key error: "+ex.getMessage()); 860 } catch (NoSuchAlgorithmException ex) { 861 throw new CMSException(ex.toString()); 862 } 863 } 864 865 866 867 /** 868 * Creates a CMS <code>Data</code> object. 869 * <p> 870 * @param message the message to be sent, as byte representation 871 * @return the DER encoded ContentInfo holding the <code>Data</code> object just created 872 * @throws CMSException if the <code>Data</code> object cannot 873 * be created 874 */ 875 public byte[] createData(byte[] message) throws CMSException { 876 877 System.out.println("Create a new Data message:"); 878 879 // create a new DigestedData object which includes the data 880 Data data = new Data(message); 881 ContentInfo ci = new ContentInfo(data); 882 // return the ASN.1 representation 883 return ci.toByteArray(); 884 } 885 886 /** 887 * Parses a CMS <code>Data</code> object. 888 * 889 * @param encoding the DER encoded ContentInfo holding with inherent <code>Data</code> 890 * 891 * @return the inherent message as byte array 892 * 893 * @throws CMSException if an parsing exception occurs 894 * @throws IOException if an I/O related error occurs 895 */ 896 public byte[] getData(byte[] encoding) throws CMSException, IOException { 897 898 ByteArrayInputStream encodedStream = new ByteArrayInputStream(encoding); 899 // create the ContentInfo 900 ContentInfo ci = new ContentInfo(encodedStream); 901 System.out.println("This ContentInfo holds content of type " + ci.getContentType().getName()); 902 // create the Data object 903 Data data = (Data)ci.getContent(); 904 905 // get and return the content 906 return data.getData(); 907 } 908 909 /** 910 * Creates a CMS <code>EnvelopedData</code> message and wraps it into a ContentInfo. 911 * <p> 912 * 913 * @param message the message to be enveloped, as byte representation 914 * @return the DER encoded ContentInfo holding the EnvelopedData object just created 915 * @throws CMSException if the <code>EnvelopedData</code> object cannot 916 * be created 917 */ 918 public byte[] createEnvelopedData(byte[] message) throws CMSException { 919 920 EnvelopedData enveloped_data; 921 922 // create a new EnvelopedData object encrypted with TripleDES CBC 923 try { 924 enveloped_data = new EnvelopedData(message, (AlgorithmID)AlgorithmID.aes256_CBC.clone()); 925 } catch (NoSuchAlgorithmException ex) { 926 throw new CMSException(ex.toString()); 927 } 928 929 // create the recipient infos 930 RecipientInfo[] recipients = new RecipientInfo[2]; 931 // user1 is the first receiver 932 recipients[0] = new KeyTransRecipientInfo(user1_crypt, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 933 // user2 is the second receiver 934 recipients[1] = new KeyTransRecipientInfo(user2_crypt, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 935 // specify the recipients of the encrypted message 936 enveloped_data.setRecipientInfos(recipients); 937 938 // wrap into contentInfo 939 ContentInfo ci = new ContentInfo(enveloped_data); 940 // return the EnvelopedDate as DER encoded byte array 941 return ci.toByteArray(); 942 } 943 944 /** 945 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for the 946 * specified recipient and returns the decrypted (= original) message. 947 * 948 * @param encoding the DER encoded ContentInfo holding an EnvelopedData 949 * @param privateKey the private key to decrypt the message 950 * @param recipientInfoIndex the index into the <code>RecipientInfo</code> array 951 * to which the specified private key belongs 952 * 953 * @return the recovered message, as byte array 954 * @throws CMSException if the message cannot be recovered 955 */ 956 public byte[] getEnvelopedData(byte[] encoding, PrivateKey privateKey, int recipientInfoIndex) throws CMSException, IOException { 957 958 ByteArrayInputStream encodedStream = new ByteArrayInputStream(encoding); 959 ContentInfo ci = new ContentInfo(encodedStream); 960 EnvelopedData enveloped_data = (EnvelopedData)ci.getContent(); 961 962 System.out.println("Information about the encrypted data:"); 963 EncryptedContentInfo eci = (EncryptedContentInfo)enveloped_data.getEncryptedContentInfo(); 964 System.out.println("Content type: "+eci.getContentType().getName()); 965 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 966 967 System.out.println("\nThis message can be decrypted by the owners of the following certificates:"); 968 RecipientInfo[] recipients = enveloped_data.getRecipientInfos(); 969 for (int i=0; i<recipients.length; i++) { 970 System.out.println("Recipient "+(i+1)+":"); 971 System.out.println(recipients[i].getRecipientIdentifiers()[0]); 972 } 973 974 // decrypt the message 975 try { 976 enveloped_data.setupCipher(privateKey, recipientInfoIndex); 977 return enveloped_data.getContent(); 978 979 } catch (InvalidKeyException ex) { 980 throw new CMSException("Private key error: "+ex.toString()); 981 } catch (NoSuchAlgorithmException ex) { 982 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage()); 983 } 984 } 985 986 /** 987 * Creates a CMS <code>SignedData</code> object and wraps it into a ContentInfo. 988 * 989 * @param message the message to be signed, as byte representation 990 * @param mode the mode indicating whether to include the content 991 * (SignedDataStream.IMPLICIT) or not (SignedDataStream.EXPLICIT) 992 * @return the DER encoded ContentInfo holding the <code>SignedData</code> object just created 993 * @throws CMSException if the <code>SignedData</code> object cannot 994 * be created 995 */ 996 public byte[] createSignedData(byte[] message, int mode) throws CMSException { 997 998 System.out.println("Create a new message signed by user 1:"); 999 1000 // create a new SignedData object which includes the data 1001 SignedData signed_data = new SignedData(message, mode); 1002 // SignedData shall include the certificate chain for verifying 1003 signed_data.setCertificates(certificates); 1004 1005 // cert at index 0 is the user certificate 1006 IssuerAndSerialNumber issuer = new IssuerAndSerialNumber(user1_sign); 1007 1008 // create a new SignerInfo 1009 SignerInfo signer_info = new SignerInfo(issuer, (AlgorithmID)AlgorithmID.sha256.clone(), user1_sign_pk); 1010 1011 // create some signed attributes 1012 // the message digest attribute is automatically added 1013 Attribute[] attributes = new Attribute[2]; 1014 try { 1015 // content type is data 1016 CMSContentType contentType = new CMSContentType(ObjectID.cms_data); 1017 attributes[0] = new Attribute(contentType); 1018 // signing time is now 1019 SigningTime signingTime = new SigningTime(); 1020 attributes[1] = new Attribute(signingTime); 1021 } catch (Exception ex) { 1022 throw new CMSException("Error creating attribute: " + ex.toString()); 1023 } 1024 1025 // set the attributes 1026 signer_info.setSignedAttributes(attributes); 1027 // finish the creation of SignerInfo by calling method addSigner 1028 try { 1029 signed_data.addSignerInfo(signer_info); 1030 1031 // another SignerInfo without authenticated attributes 1032 signer_info = new SignerInfo(new IssuerAndSerialNumber(user2_sign), 1033 (AlgorithmID)AlgorithmID.sha256.clone(), user2_sign_pk); 1034 // the message digest itself is protected 1035 signed_data.addSignerInfo(signer_info); 1036 1037 } catch (NoSuchAlgorithmException ex) { 1038 throw new CMSException("No implementation for signature algorithm: "+ex.getMessage()); 1039 } 1040 1041 ContentInfo ci = new ContentInfo(signed_data); 1042 return ci.toByteArray(); 1043 } 1044 1045 /** 1046 * Parses a CMS <code>SignedData</code> object and verifies the signatures 1047 * for all participated signers. 1048 * 1049 * @param encoding the ContentInfo with inherent <code>SignedData</code> object, as DER encoding 1050 * @param message the the message which was transmitted out-of-band (explicit signed) 1051 * 1052 * @return the inherent message as byte array, or <code>null</code> if there 1053 * is no message included into the supplied <code>SignedData</code> 1054 * object 1055 * @throws CMSException if any signature does not verify 1056 * @throws IOException if an I/O error occurs 1057 */ 1058 public byte[] getSignedData(byte[] encoding, byte[] message) throws CMSException, IOException { 1059 1060 ByteArrayInputStream encodedStream = new ByteArrayInputStream(encoding); 1061 // create a content info from the ASN.1 object 1062 SignedData signed_data = new SignedData(encodedStream); 1063 1064 if (signed_data.getMode() == SignedData.EXPLICIT) { 1065 // explicit mode: set content received by other means 1066 signed_data.setContent(message); 1067 } 1068 1069 System.out.println("SignedData contains the following signer information:"); 1070 SignerInfo[] signer_infos = signed_data.getSignerInfos(); 1071 1072 int numberOfSignerInfos = signer_infos.length; 1073 if (numberOfSignerInfos == 0) { 1074 String warning = "Warning: Unsigned message (no SignerInfo included)!"; 1075 System.err.println(warning); 1076 throw new CMSException(warning); 1077 } else { 1078 for (int i = 0; i < numberOfSignerInfos; i++) { 1079 try { 1080 // verify the signed data using the SignerInfo at index i 1081 X509Certificate signer_cert = signed_data.verify(i); 1082 // if the signature is OK the certificate of the signer is returned 1083 System.out.println("Signature OK from signer: "+signer_cert.getSubjectDN()); 1084 // get signed attributes 1085 SigningTime signingTime = (SigningTime)signer_infos[i].getSignedAttributeValue(ObjectID.signingTime); 1086 if (signingTime != null) { 1087 System.out.println("This message has been signed at " + signingTime.get()); 1088 } 1089 CMSContentType contentType = (CMSContentType)signer_infos[i].getSignedAttributeValue(ObjectID.contentType); 1090 if (contentType != null) { 1091 System.out.println("The content has CMS content type " + contentType.get().getName()); 1092 } 1093 } catch (SignatureException ex) { 1094 // if the signature is not OK a SignatureException is thrown 1095 System.out.println("Signature ERROR from signer: "+signed_data.getCertificate(signer_infos[i].getSignerIdentifier()).getSubjectDN()); 1096 throw new CMSException(ex.toString()); 1097 } 1098 } 1099 1100 // now check alternative signature verification 1101 System.out.println("Now check the signature assuming that no certs have been included:"); 1102 try { 1103 SignerInfo signer_info = signed_data.verify(user1_sign); 1104 // if the signature is OK the certificate of the signer is returned 1105 System.out.println("Signature OK from signer: "+signed_data.getCertificate(signer_info.getSignerIdentifier()).getSubjectDN()); 1106 1107 } catch (SignatureException ex) { 1108 // if the signature is not OK a SignatureException is thrown 1109 System.out.println("Signature ERROR from signer: "+user1_sign.getSubjectDN()); 1110 throw new CMSException(ex.toString()); 1111 } 1112 1113 try { 1114 SignerInfo signer_info = signed_data.verify(user2_sign); 1115 // if the signature is OK the certificate of the signer is returned 1116 System.out.println("Signature OK from signer: "+signed_data.getCertificate(signer_info.getSignerIdentifier()).getSubjectDN()); 1117 1118 } catch (SignatureException ex) { 1119 // if the signature is not OK a SignatureException is thrown 1120 System.out.println("Signature ERROR from signer: "+user2_sign.getSubjectDN()); 1121 throw new CMSException(ex.toString()); 1122 } 1123 1124 // in practice we also would validate the signer certificate(s) 1125 } 1126 return signed_data.getContent(); 1127 } 1128 1129 1130 1131 /** 1132 * Creates a <i>SignedAndEncrypted</i> (i.e. sequential combination of <code> 1133 * SignedData</code> and <code>EnvelopedData</code>) object. 1134 * 1135 * @param message the message to be signed and encrypted, as byte representation 1136 * @return the DER encoded ContentInfo holding the signed and encrypted message object 1137 * just created 1138 * @throws CMSException if the the <code>SignedData</code> or 1139 * <code>EnvelopedData</code> object cannot be created 1140 */ 1141 public byte[] createSignedAndEncryptedData(byte[] message) throws CMSException { 1142 1143 System.out.println("Create a new message signed by user1 encrypted for user2:"); 1144 1145 byte[] signed = createSignedData(message, SignedData.IMPLICIT); 1146 return createEnvelopedData(signed); 1147 } 1148 1149 /** 1150 * Recovers the original message and verifies the signature. 1151 * 1152 * @param encoding the DER encoded ContentInfo holding a SignedAndEnryptedData object 1153 * @return the recovered message, as byte array 1154 * @throws CMSException if the message cannot be recovered 1155 * @throws IOException if an I/O error occurs 1156 */ 1157 public byte[] getSignedAndEncryptedData(byte[] encoding) throws CMSException, IOException { 1158 1159 // user2 means index 2 (hardcoded for this demo) 1160 byte[] signed = getEnvelopedData(encoding, user2_crypt_pk, 1); 1161 return getSignedData(signed, null); 1162 } 1163 1164 1165 /** 1166 * Creates a CMS <code>DigestedData</code> object. 1167 * <p> 1168 * 1169 * @param message the message to be digested, as byte representation 1170 * @return the <code>DigestedData</code> wrapped into a ContentInfo, as DER encoding 1171 * @throws CMSException if the <code>DigestedData</code> object cannot 1172 * be created 1173 */ 1174 public byte[] createDigestedData(byte[] message, int mode) throws CMSException { 1175 1176 System.out.println("Create a new digested message:"); 1177 1178 // create a new DigestedData object which includes the data 1179 DigestedData digested_data = new DigestedData(message, (AlgorithmID)AlgorithmID.sha256.clone(), mode); 1180 ContentInfo ci = new ContentInfo(digested_data); 1181 return ci.toByteArray(); 1182 } 1183 1184 /** 1185 * Parses a CMS <code>DigestedData</code> object and verifies the hash value. 1186 * 1187 * @param encoding the ContentInfo holding a <code>DigestedData</code>, as DER encoding 1188 * @param message the the message which was transmitted out-of-band (explicit digested) 1189 * 1190 * @return the message 1191 * @throws CMSException if some parsing exception occurs 1192 * @throws IOException if an I/O error occurs 1193 */ 1194 public byte[] getDigestedData(byte[] encoding, byte[] message) throws CMSException, IOException { 1195 1196 ByteArrayInputStream encodedStream = new ByteArrayInputStream(encoding); 1197 // create a content info from the ASN.1 object 1198 ContentInfo ci = new ContentInfo(encodedStream); 1199 System.out.println("This ContentInfo holds content of type " + ci.getContentType().getName()); 1200 1201 DigestedData digested_data = new DigestedData(encodedStream); 1202 1203 if (digested_data.getMode() == DigestedData.EXPLICIT) { 1204 // set content transmitted by other means 1205 digested_data.setContent(message); 1206 } 1207 1208 // now verify the digest 1209 if (digested_data.verify()) { 1210 System.out.println("Hash ok!"); 1211 } else { 1212 throw new CMSException("Hash verification failed!"); 1213 } 1214 1215 return digested_data.getContent(); 1216 } 1217 1218 1219 /** 1220 * Creates a CMS <code>EncryptedData</code> message. 1221 * <p> 1222 * The supplied content is PBE-encrypted using the specified password. 1223 * 1224 * @param message the message to be encrypted, as byte representation 1225 * @param pbeAlgorithm the PBE algorithm to be used 1226 * @param password the password 1227 * @return the <code>EncryptedData</code> object wrapped into a ContentInfo, as DER encoding 1228 * @throws CMSException if the <code>EncryptedData</code> object cannot 1229 * be created 1230 */ 1231 public byte[] createEncryptedData(byte[] message, AlgorithmID pbeAlgorithm, char[] password) throws CMSException { 1232 1233 EncryptedData encrypted_data; 1234 1235 try { 1236 encrypted_data = new EncryptedData(message); 1237 // encrypt the message 1238 encrypted_data.setupCipher(pbeAlgorithm, password); 1239 } catch (InvalidKeyException ex) { 1240 throw new CMSException("Key error: "+ex.toString()); 1241 } catch (NoSuchAlgorithmException ex) { 1242 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage()); 1243 } 1244 // create the ContentInfo 1245 ContentInfo ci = new ContentInfo(encrypted_data); 1246 return ci.toByteArray(); 1247 1248 } 1249 1250 /** 1251 * Decrypts the PBE-encrypted content of the given <code>EncryptedData</code> object 1252 * using the specified password and returns the decrypted (= original) message. 1253 * 1254 * @param encoding the DER encoded ContentInfo holding the <code>EncryptedData</code> object 1255 * @param password the password to decrypt the message 1256 * 1257 * @return the recovered message, as byte array 1258 * @throws CMSException if the message cannot be recovered 1259 * @throws IOException if an I/O error occurs 1260 */ 1261 public byte[] getEncryptedData(byte[] encoding, char[] password) throws CMSException, IOException { 1262 1263 ByteArrayInputStream encodedStream = new ByteArrayInputStream(encoding); 1264 ContentInfo ci = new ContentInfo(encodedStream); 1265 System.out.println("This ContentInfo holds content of type " + ci.getContentType().getName()); 1266 1267 // get the EncryptedData 1268 EncryptedData encrypted_data = (EncryptedData)ci.getContent(); 1269 1270 System.out.println("Information about the encrypted data:"); 1271 EncryptedContentInfo eci = (EncryptedContentInfo)encrypted_data.getEncryptedContentInfo(); 1272 System.out.println("Content type: "+eci.getContentType().getName()); 1273 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 1274 1275 // decrypt the message 1276 try { 1277 encrypted_data.setupCipher(password); 1278 return encrypted_data.getContent(); 1279 1280 } catch (InvalidKeyException ex) { 1281 throw new CMSException("Key error: "+ex.toString()); 1282 } catch (NoSuchAlgorithmException ex) { 1283 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage()); 1284 } catch (InvalidAlgorithmParameterException ex) { 1285 throw new CMSException("Invalid Parameters: "+ex.toString()); 1286 } catch (InvalidParameterSpecException ex) { 1287 throw new CMSException("Invalid Parameters: "+ex.toString()); 1288 } 1289 } 1290 1291 /** 1292 * Creates a CMS <code>AuthenticatedData</code> for the given message message. 1293 * <p> 1294 * <b>Attention:</b> This AuthenticatedData demo uses RSA as key management technique. 1295 * In practice (see RFC 5652) a key management technique that provides data origin 1296 * authentication should be used like, for instance, Static-Static Diffie-Hellman when 1297 * both the originator and recipient public keys are bound to appropriate identities 1298 * in X.509 certificates, see, for instance, {@link demo.cms.authenticatedData.AuthenticatedDataDemo 1299 * AuthenticatedDataDemo}. 1300 * 1301 * @param message the message to be authenticated, as byte representation 1302 * @param includeAuthAttrs whether to include authenticated attributes 1303 * @param mode the mode indicating whether to include the content 1304 * (AuthenticatedData.IMPLICIT) or not (AuthenticatedDatam.EXPLICIT) 1305 * @return the BER encoding of the <code>AuthenticatedData</code> object, wrapped in a ContentInfo 1306 * @throws CMSException if the <code>AuthenticatedData</code> object cannot 1307 * be created 1308 * @throws IOException if an I/O error occurs 1309 */ 1310 public byte[] createAuthenticatedData(byte[] message, 1311 boolean includeAuthAttrs, 1312 int mode) 1313 throws CMSException, IOException { 1314 1315 AlgorithmID macAlgorithm = (AlgorithmID)AlgorithmID.hMAC_SHA256.clone(); 1316 int macKeyLength = 32; 1317 AlgorithmID digestAlgorithm = null; 1318 // we need a digest algorithm if authenticated attributes shall be included 1319 if (includeAuthAttrs == true) { 1320 digestAlgorithm = (AlgorithmID)AlgorithmID.sha256.clone(); 1321 } 1322 ObjectID contentType = ObjectID.cms_data; 1323 1324 AuthenticatedData authenticatedData; 1325 1326 // create a new AuthenticatedData object 1327 try { 1328 authenticatedData = new AuthenticatedData(contentType, 1329 message, 1330 macAlgorithm, 1331 macKeyLength, 1332 null, 1333 digestAlgorithm, 1334 mode); 1335 } catch (NoSuchAlgorithmException ex) { 1336 throw new CMSException(ex.toString()); 1337 } 1338 1339 1340 // create the recipient infos 1341 RecipientInfo[] recipients = new RecipientInfo[2]; 1342 // user1 is the first receiver 1343 recipients[0] = new KeyTransRecipientInfo(user1_crypt, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 1344 // user2 is the second receiver 1345 recipients[1] = new KeyTransRecipientInfo(user2_crypt, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 1346 // specify the recipients of the authenticated message 1347 authenticatedData.setRecipientInfos(recipients); 1348 1349 if (includeAuthAttrs == true) { 1350 // create some autheticated attributes 1351 // (the message digest attribute is automatically added) 1352 try { 1353 Attribute[] attributes = { new Attribute(new CMSContentType(contentType)) }; 1354 authenticatedData.setAuthenticatedAttributes(attributes); 1355 } catch (Exception ex) { 1356 throw new CMSException("Error creating attribute: " + ex.toString()); 1357 } 1358 } 1359 1360 // wrap the AuthenticatedData in a ContentInfo and encode it 1361 ContentInfo ci = new ContentInfo(authenticatedData); 1362 return ci.toByteArray(); 1363 1364 } 1365 1366 /** 1367 * Decrypts the encrypted MAC key for the recipient identified by its index 1368 * into the recipientInfos field and uses the MAC key to verify 1369 * the authenticated data. 1370 * <p> 1371 * This way of decrypting the MAC key and verifying the content may be used for 1372 * any type of RecipientInfo (KeyTransRecipientInfo, KeyAgreeRecipientInfo, 1373 * KEKRecipientInfo), but requires to know at what index of the recipientInfos 1374 * field the RecipientInfo for the particular recipient in mind can be found. 1375 * If the recipient in mind uses a RecipientInfo of type KeyAgreeRecipientInfo 1376 * some processing overhead may take place because a KeyAgreeRecipientInfo may 1377 * contain encrypted mac keys for more than only one recipient; since the 1378 * recipientInfoIndex only specifies the RecipientInfo but not the encrypted 1379 * mac key -- if there are more than only one -- repeated decryption runs may be 1380 * required as long as the decryption process completes successfully. 1381 * <p> 1382 * <b>Attention:</b> This AuthenticatedData demo uses RSA as key management technique. 1383 * In practice (see RFC 5652) a key management technique that provides data origin 1384 * authentication should be used like, for instance, Static-Static Diffie-Hellman when 1385 * both the originator and recipient public keys are bound to appropriate identities 1386 * in X.509 certificates, see, for instance, {@link demo.cms.authenticatedData.AuthenticatedDataDemo 1387 * AuthenticatedDataDemo}. 1388 * 1389 * @param encoding the DER encoded ContentInfo holding the <code>AuthenticatedData</code> object 1390 * @param message the content message, if transmitted by other means (explicit mode) 1391 * @param key the key to decrypt the mac key 1392 * @param recipientInfoIndex the index of the right <code>RecipientInfo</code> to 1393 * which the given key belongs 1394 * 1395 * @return the verified message, as byte array 1396 * @throws CMSException if the authenticated data cannot be verified 1397 * @throws IOException if a IO read/write error occurs 1398 */ 1399 public byte[] getAuthenticatedData(byte[] encoding, 1400 byte[] message, 1401 PrivateKey key, 1402 int recipientInfoIndex) 1403 throws CMSException, IOException { 1404 1405 // create the AuthenticatedData object from a DER encoded byte array 1406 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 1407 ContentInfo ci = new ContentInfo(is); 1408 System.out.println("This ContentInfo holds content of type " + ci.getContentType().getName()); 1409 1410 AuthenticatedData authenticatedData = (AuthenticatedData)ci.getContent(); 1411 1412 if (authenticatedData.getMode() == AuthenticatedData.EXPLICIT) { 1413 // in explicit mode explicitly supply the content for hash/mac computation 1414 authenticatedData.setContent(message); 1415 } 1416 1417 System.out.println("\nThis message can be verified by the following recipients:"); 1418 RecipientInfo[] recipients = authenticatedData.getRecipientInfos(); 1419 for (int i=0; i<recipients.length; i++) { 1420 System.out.println("Recipient "+(i+1)+":"); 1421 System.out.println(recipients[i].getRecipientIdentifiers()[0]); 1422 } 1423 1424 // decrypt the mac key and verify the mac for the first recipient 1425 try { 1426 authenticatedData.setupMac(key, recipientInfoIndex); 1427 if (authenticatedData.verifyMac() == false) { 1428 throw new CMSException("Mac verification error!"); 1429 } 1430 System.out.println("Mac successfully verified!"); 1431 1432 return authenticatedData.getContent(); 1433 1434 } catch (InvalidKeyException ex) { 1435 throw new CMSException("Key error: "+ex.getMessage()); 1436 } catch (NoSuchAlgorithmException ex) { 1437 throw new CMSException(ex.toString()); 1438 } 1439 } 1440 1441 1442 1443 1444 /** 1445 * Tests the CMS content type implementations <code>Data</code>, <code>EnvelopedData</code>, 1446 * <code>SignedData</code>, <code>DigestedData</code>, <code>EncryptedData</code>. 1447 * An additional <i>SignedAndEncryptedData</i> test sequentially combines 1448 * signed and enveloped data. 1449 */ 1450 public void start() { 1451 // the test message 1452 String m = "This is the test message."; 1453 System.out.println("Test message: \""+m+"\""); 1454 System.out.println(); 1455 byte[] message = m.getBytes(); 1456 1457 try { 1458 byte[] encoding; 1459 byte[] received_message = null; 1460 System.out.println("Stream implementation demos"); 1461 System.out.println("==========================="); 1462 1463 // the stream implementation 1464 // 1465 // test CMS DataStream 1466 // 1467 System.out.println("\nDataStream demo [create]:\n"); 1468 encoding = createDataStream(message); 1469 // transmit data 1470 System.out.println("\nDataStream demo [parse]:\n"); 1471 1472 received_message = getDataStream(encoding); 1473 System.out.print("\nContent: "); 1474 System.out.println(new String(received_message)); 1475 1476 1477 // the stream implementation 1478 // 1479 // test CMS EnvelopedDataStream 1480 // 1481 System.out.println("\nEnvelopedDataStream demo [create]:\n"); 1482 encoding = createEnvelopedDataStream(message); 1483 // transmit data 1484 System.out.println("\nEnvelopedDataStream demo [parse]:\n"); 1485 // user1 means index 0 (hardcoded for this demo) 1486 received_message = getEnvelopedDataStream(encoding, user1_crypt_pk, 0); 1487 System.out.print("\nDecrypted content: "); 1488 System.out.println(new String(received_message)); 1489 1490 // 1491 // test CMS Implicit SignedDataStream 1492 // 1493 System.out.println("\nImplicit SignedDataStream demo [create]:\n"); 1494 encoding = createSignedDataStream(message, SignedDataStream.IMPLICIT); 1495 // transmit data 1496 System.out.println("\nImplicit SignedDataStream demo [parse]:\n"); 1497 received_message = getSignedDataStream(encoding, null); 1498 System.out.print("\nSigned content: "); 1499 System.out.println(new String(received_message)); 1500 1501 // 1502 // test CMS Explicit SignedDataStream 1503 // 1504 System.out.println("\nExplicit SignedDataStream demo [create]:\n"); 1505 encoding = createSignedDataStream(message, SignedDataStream.EXPLICIT); 1506 // transmit data 1507 System.out.println("\nExplicit SignedDataStream demo [parse]:\n"); 1508 received_message = getSignedDataStream(encoding, message); 1509 System.out.print("\nSigned content: "); 1510 System.out.println(new String(received_message)); 1511 1512 // test CMS SignedAndEncryptedDataStream 1513 // 1514 System.out.println("\nSignedAndEncryptedDataStream demo [create]:\n"); 1515 encoding = createSignedAndEncryptedDataStream(message); 1516 // transmit data 1517 System.out.println("\nSignedAndEncryptedDataStream demo [parse]:\n"); 1518 received_message = getSignedAndEncryptedDataStream(encoding); 1519 System.out.print("\nSignedAndEncrypted content: "); 1520 System.out.println(new String(received_message)); 1521 1522 1523 // 1524 // test CMS Implicit DigestedDataStream 1525 // 1526 System.out.println("\nImplicit DigestedDataStream demo [create]:\n"); 1527 encoding = createDigestedDataStream(message, DigestedDataStream.IMPLICIT); 1528 // transmit data 1529 System.out.println("\nImplicit DigestedDataStream demo [parse]:\n"); 1530 received_message = getDigestedDataStream(encoding, null); 1531 System.out.print("\nContent: "); 1532 System.out.println(new String(received_message)); 1533 1534 // 1535 // test CMS Explicit DigestedDataStream 1536 // 1537 System.out.println("\nExplicit DigestedDataStream demo [create]:\n"); 1538 encoding = createDigestedDataStream(message, DigestedDataStream.EXPLICIT); 1539 // transmit data 1540 System.out.println("\nExplicit DigestedDataStream demo [parse]:\n"); 1541 received_message = getDigestedDataStream(encoding, message); 1542 System.out.print("\nContent: "); 1543 System.out.println(new String(received_message)); 1544 1545 // 1546 // test CMS EncryptedDataStream 1547 // 1548 System.out.println("\nEncryptedDataStream demo [create]:\n"); 1549 encoding = createEncryptedDataStream(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray()); 1550 // transmit data 1551 System.out.println("\nEncryptedDataStream demo [parse]:\n"); 1552 received_message = getEncryptedDataStream(encoding, "password".toCharArray()); 1553 System.out.print("\nContent: "); 1554 System.out.println(new String(received_message)); 1555 1556 1557 // 1558 // test CMS Implicit AuthenticatedDataStream with auth attributes 1559 // 1560 System.out.println("\nImplicit AuthenticatedDataStream demo with auth attributes [create]:\n"); 1561 encoding = createAuthenticatedDataStream(message, true, AuthenticatedDataStream.IMPLICIT); 1562 // transmit data 1563 System.out.println("\nImplicit AuthenticatedDataStream demo with auth attributes [parse]:\n"); 1564 received_message = getAuthenticatedDataStream(encoding, null, user1_crypt_pk, 0); 1565 System.out.print("\nVerified content: "); 1566 System.out.println(new String(received_message)); 1567 1568 System.out.println("\nImplicit AuthenticatedDataStream demo without auth attributes [create]:\n"); 1569 encoding = createAuthenticatedDataStream(message, false, AuthenticatedDataStream.IMPLICIT); 1570 // transmit data 1571 System.out.println("\nImplicit AuthenticatedDataStream demo without auth attributes [parse]:\n"); 1572 received_message = getAuthenticatedDataStream(encoding, null, user1_crypt_pk, 0); 1573 System.out.print("\nVerified content: "); 1574 System.out.println(new String(received_message)); 1575 1576 // 1577 // test CMS Explicit AuthenticatedDataStream 1578 // 1579 System.out.println("\nExplicit AuthenticatedDataStream demo with auth attributes [create]:\n"); 1580 encoding = createAuthenticatedDataStream(message, true, AuthenticatedDataStream.EXPLICIT); 1581 // transmit data 1582 System.out.println("\nExplicit AuthenticatedDataStream demo with auth attributes [parse]:\n"); 1583 received_message = getAuthenticatedDataStream(encoding, message, user1_crypt_pk, 0); 1584 System.out.print("\nVerified content: "); 1585 System.out.println(new String(received_message)); 1586 1587 System.out.println("\nExplicit AuthenticatedDataStream demo without auth attributes [create]:\n"); 1588 encoding = createAuthenticatedDataStream(message, false, AuthenticatedDataStream.EXPLICIT); 1589 // transmit data 1590 System.out.println("\nExplicit AuthenticatedDataStream demo with auth attributes [parse]:\n"); 1591 received_message = getAuthenticatedDataStream(encoding, message, user1_crypt_pk, 0); 1592 System.out.print("\nVerified content: "); 1593 System.out.println(new String(received_message)); 1594 1595 1596 // the non-stream implementation 1597 System.out.println("\nNon-stream implementation demos"); 1598 System.out.println("==============================="); 1599 1600 // 1601 // test CMS Data 1602 // 1603 System.out.println("\nData demo [create]:\n"); 1604 encoding = createData(message); 1605 // transmit data 1606 System.out.println("\nData demo [parse]:\n"); 1607 1608 received_message = getData(encoding); 1609 System.out.print("\nContent: "); 1610 System.out.println(new String(received_message)); 1611 1612 // 1613 // test CMS EnvelopedData 1614 // 1615 System.out.println("\nEnvelopedData demo [create]:\n"); 1616 encoding = createEnvelopedData(message); 1617 // transmit data 1618 System.out.println("\nEnvelopedData demo [parse]:\n"); 1619 // user1 means index 0 (hardcoded for this demo) 1620 received_message = getEnvelopedData(encoding, user1_crypt_pk, 0); 1621 System.out.print("\nDecrypted content: "); 1622 System.out.println(new String(received_message)); 1623 1624 // 1625 // test CMS Implicit SignedData 1626 // 1627 System.out.println("\nImplicit SignedData demo [create]:\n"); 1628 encoding = createSignedData(message, SignedDataStream.IMPLICIT); 1629 // transmit data 1630 System.out.println("\nImplicit SignedData demo [parse]:\n"); 1631 received_message = getSignedData(encoding, null); 1632 System.out.print("\nSigned content: "); 1633 System.out.println(new String(received_message)); 1634 1635 // 1636 // test CMS Explicit SignedData 1637 // 1638 System.out.println("\nExplicit SignedData demo [create]:\n"); 1639 encoding = createSignedData(message, SignedData.EXPLICIT); 1640 // transmit data 1641 System.out.println("\nExplicit SignedData demo [parse]:\n"); 1642 received_message = getSignedData(encoding, message); 1643 System.out.print("\nSigned content: "); 1644 System.out.println(new String(received_message)); 1645 1646 // 1647 // test CMS SignedAndEncryptedData 1648 // 1649 System.out.println("\nSignedAndEncryptedData demo [create]:\n"); 1650 encoding = createSignedAndEncryptedData(message); 1651 // transmit data 1652 System.out.println("\nSignedAndEncryptedData demo [parse]:\n"); 1653 received_message = getSignedAndEncryptedData(encoding); 1654 System.out.print("\nSignedAndEncrypted content: "); 1655 System.out.println(new String(received_message)); 1656 1657 1658 // 1659 // test CMS Implicit DigestedData 1660 // 1661 System.out.println("\nImplicit DigestedData demo [create]:\n"); 1662 encoding = createDigestedData(message, DigestedData.IMPLICIT); 1663 // transmit data 1664 System.out.println("\nImplicit DigestedData demo [parse]:\n"); 1665 received_message = getDigestedData(encoding, null); 1666 System.out.print("\nContent: "); 1667 System.out.println(new String(received_message)); 1668 1669 // 1670 // test CMS Explicit DigestedData 1671 // 1672 System.out.println("\nExplicit DigestedData demo [create]:\n"); 1673 encoding = createDigestedData(message, DigestedData.EXPLICIT); 1674 // transmit data 1675 System.out.println("\nExplicit DigestedData demo [parse]:\n"); 1676 received_message = getDigestedData(encoding, message); 1677 System.out.print("\nContent: "); 1678 System.out.println(new String(received_message)); 1679 1680 // 1681 // test CMS EncryptedData 1682 // 1683 System.out.println("\nEncryptedData demo [create]:\n"); 1684 encoding = createEncryptedData(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray()); 1685 // transmit data 1686 System.out.println("\nEncryptedData demo [parse]:\n"); 1687 received_message = getEncryptedData(encoding, "password".toCharArray()); 1688 System.out.print("\nContent: "); 1689 System.out.println(new String(received_message)); 1690 1691 // 1692 // test CMS Implicit AuthenticatedData 1693 // 1694 System.out.println("\nImplicit AuthenticatedData demo with auth attributes [create]:\n"); 1695 encoding = createAuthenticatedData(message, true, AuthenticatedData.IMPLICIT); 1696 // transmit data 1697 System.out.println("\nImplicit AuthenticatedData demo with auth attributes [parse]:\n"); 1698 received_message = getAuthenticatedData(encoding, null, user1_crypt_pk, 0); 1699 System.out.print("\nVerified content: "); 1700 System.out.println(new String(received_message)); 1701 1702 System.out.println("\nImplicit AuthenticatedData demo without auth attributes [create]:\n"); 1703 encoding = createAuthenticatedData(message, false, AuthenticatedData.IMPLICIT); 1704 // transmit data 1705 System.out.println("\nImplicit AuthenticatedData demo without auth attributes [parse]:\n"); 1706 received_message = getAuthenticatedData(encoding, null, user1_crypt_pk, 0); 1707 System.out.print("\nVerified content: "); 1708 System.out.println(new String(received_message)); 1709 1710 // 1711 // test CMS Explicit AuthenticatedData 1712 // 1713 System.out.println("\nExplicit AuthenticatedData demo with auth attributes [create]:\n"); 1714 encoding = createAuthenticatedData(message, true, AuthenticatedData.EXPLICIT); 1715 // transmit data 1716 System.out.println("\nExplicit AuthenticatedData demo with auth attributes [parse]:\n"); 1717 received_message = getAuthenticatedData(encoding, message, user1_crypt_pk, 0); 1718 System.out.print("\nVerified content: "); 1719 System.out.println(new String(received_message)); 1720 1721 System.out.println("\nExplicit AuthenticatedData demo without auth attributes [create]:\n"); 1722 encoding = createAuthenticatedData(message, false, AuthenticatedData.EXPLICIT); 1723 // transmit data 1724 System.out.println("\nExplicit AuthenticatedData demo with auth attributes [parse]:\n"); 1725 received_message = getAuthenticatedData(encoding, message, user1_crypt_pk, 0); 1726 System.out.print("\nVerified content: "); 1727 System.out.println(new String(received_message)); 1728 1729 1730 System.out.println("Ready!"); 1731 1732 } catch (Exception ex) { 1733 ex.printStackTrace(); 1734 throw new RuntimeException(ex.toString()); 1735 } 1736 } 1737 1738 1739 /** 1740 * Starts the CMS content type implementation tests. 1741 * 1742 * @throws Exception 1743 * if some error occurs 1744 */ 1745 public static void main(String argv[]) throws Exception { 1746 1747 demo.DemoUtil.initDemos(); 1748 (new CMSDemo()).start(); 1749 1750 DemoUtil.waitKey(); 1751 } 1752 }