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