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 }