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