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/envelopedData/ExplicitEnvelopedDataDemo.java 8 12.02.25 17:58 Dbratko $
059 // $Revision: 8 $
060 //
061
062
063 package demo.cms.envelopedData;
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 import java.util.Arrays;
075
076 import javax.crypto.KeyGenerator;
077 import javax.crypto.SecretKey;
078
079 import demo.DemoUtil;
080 import demo.keystore.CMSKeyStore;
081 import iaik.asn1.structures.AlgorithmID;
082 import iaik.cms.CMSException;
083 import iaik.cms.CertificateIdentifier;
084 import iaik.cms.EncryptedContentInfo;
085 import iaik.cms.EncryptedContentInfoStream;
086 import iaik.cms.EnvelopedData;
087 import iaik.cms.EnvelopedDataStream;
088 import iaik.cms.IssuerAndSerialNumber;
089 import iaik.cms.KEKIdentifier;
090 import iaik.cms.KEKRecipientInfo;
091 import iaik.cms.KeyAgreeRecipientInfo;
092 import iaik.cms.KeyIdentifier;
093 import iaik.cms.KeyTransRecipientInfo;
094 import iaik.cms.RecipientInfo;
095 import iaik.cms.RecipientKeyIdentifier;
096 import iaik.cms.SecurityProvider;
097 import iaik.cms.SubjectKeyID;
098 import iaik.security.random.SecRandom;
099 import iaik.utils.Util;
100 import iaik.x509.X509Certificate;
101
102
103 /**
104 * Demonstrates the usage of class {@link iaik.cms.EnvelopedDataStream} and
105 * {@link iaik.cms.EnvelopedData} for encrypting data using the CMS type
106 * EnvelopedData where the encrypted data is not included in the EncryptedContentInfo
107 * (transferred by other means).
108 * <p>
109 * This demo creates an EnvelopedData object and subsequently shows several
110 * ways that may be used for decrypting the content for some particular
111 * recipient.
112 * <p>
113 * Keys and certificates are retrieved from the demo KeyStore ("cms.keystore")
114 * which has to be located in your current working directory and may be
115 * created by running the {@link demo.keystore.SetupCMSKeyStore
116 * SetupCMSKeyStore} program.
117 * <p>
118 * This demo uses TripleDES which has been deprecated by S/MIMEv4 (RFC 8551),
119 * see {@link ExplicitAESEnvelopedDataDemo ExplicitAESEnvelopedDataDemo} for an AES based demo.
120 *
121 * @see iaik.cms.EnvelopedDataStream
122 * @see iaik.cms.EnvelopedData
123 * @see iaik.cms.RecipientInfo
124 * @see iaik.cms.KeyTransRecipientInfo
125 * @see iaik.cms.KeyAgreeRecipientInfo
126 * @see iaik.cms.KEKRecipientInfo
127 */
128 public class ExplicitEnvelopedDataDemo {
129
130 // certificate of rsaUser 1
131 X509Certificate rsaUser1_;
132 // private key of rsaUser 1
133 PrivateKey rsaUser1Pk_;
134 // certificate of rsaUser 2
135 X509Certificate rsaUser2_;
136 // private key of rsaUser 2
137 PrivateKey rsaUser2Pk_;
138
139 // certificate of esdhUser 1
140 X509Certificate esdhUser1_;
141 // private key of esdhUser 1
142 PrivateKey esdhUser1Pk_;
143 // certificate of esdhUser 2
144 X509Certificate esdhUser2_;
145 // private key of esdhUser 2
146 PrivateKey esdhUser2Pk_;
147
148 // key encryption key for KEKRecipientInfo
149 SecretKey kek_;
150 byte[] kekID_;
151
152 // content encryption algorithm to be used
153 AlgorithmID contentEncAlg_;
154 // cek algorithm
155 String cekAlg_;
156 // key wrap algorithm to be used
157 AlgorithmID keyWrapAlg_;
158 // key length (same for content encryption key and key encryption key
159 int keyLength_;
160
161 // secure random number generator
162 SecureRandom random_;
163
164 /**
165 * Creates an EnvelopedDataDemo and setups the demo certificates.
166 * <br>
167 * Keys and certificates are retrieved from the demo KeyStore ("cms.keystore")
168 * file which has to be located in your current working directory and may be
169 * created by running {@link demo.keystore.SetupCMSKeyStore
170 * SetupCMSKeyStore}.
171 * <br>
172 * TripleDES and TripleDES KeyWrap are used for content encryption and
173 * content encryption key wrapping.
174 *
175 * @throws IOException if an file read error occurs
176 * @throws NoSuchAlgorithmException if the requested TripleDES or TripleDES KeyWrap
177 * algorithms are not supported
178 */
179 public ExplicitEnvelopedDataDemo() throws IOException, NoSuchAlgorithmException {
180 this((AlgorithmID)AlgorithmID.des_EDE3_CBC.clone(),
181 (AlgorithmID)AlgorithmID.cms_3DES_wrap.clone(),
182 (AlgorithmID)AlgorithmID.cms_3DES_wrap.clone(),
183 192);
184 }
185
186 /**
187 * Creates an EnvelopedDataDemo and setups the demo certificates.
188 * <br>
189 * Keys and certificates are retrieved from the demo KeyStore ("cms.keystore")
190 * file which has to be located in your current working directory and may be
191 * created by running {@link demo.keystore.SetupCMSKeyStore
192 * SetupCMSKeyStore}.
193 *
194 * @param contentEncAlg the content encryption algorithm to be used
195 * @param keyWrapAlg the key wrap algorithm to be used for wrapping the content
196 * encryption key (for KeyAgreeRecipientInfos)
197 * @param keyLength the key length to be used (same for content encryption key
198 * and key encryption key) (for KeyAgreeRecipientInfos and
199 * KEKRecipientInfos)
200 *
201 * @throws IOException if an file read error occurs
202 * @throws NoSuchAlgorithmException if the requested algorithms are not supported
203 */
204 public ExplicitEnvelopedDataDemo(AlgorithmID contentEncAlg,
205 AlgorithmID keyWrapAlg,
206 int keyLength) throws IOException, NoSuchAlgorithmException {
207 this(contentEncAlg, keyWrapAlg, keyWrapAlg, keyLength);
208
209 }
210
211
212 /**
213 * Creates an EnvelopedDataDemo and setups the demo certificates.
214 * <br>
215 * Keys and certificates are retrieved from the demo KeyStore ("cms.keystore")
216 * file which has to be located in your current working directory and may be
217 * created by running {@link demo.keystore.SetupCMSKeyStore
218 * SetupCMSKeyStore}.
219 *
220 * @param contentEncAlg the content encryption algorithm to be used
221 * @param keyWrapAlg the key wrap algorithm to be used for wrapping the content
222 * encryption key (for KeyAgreeRecipientInfos)
223 * @param kekAlg the name of the key encryption key algorithm to be used
224 * (for KEKRecipientInfos)
225 * @param keyLength the key length to be used (same for content encryption key
226 * and key encryption key) (for KeyAgreeRecipientInfos and
227 * KEKRecipientInfos)
228 *
229 * @throws IOException if an file read error occurs
230 * @throws NoSuchAlgorithmException if the requested algorithms are not supported
231 */
232 public ExplicitEnvelopedDataDemo(AlgorithmID contentEncAlg,
233 AlgorithmID keyWrapAlg,
234 AlgorithmID kekAlg,
235 int keyLength) throws IOException, NoSuchAlgorithmException {
236
237 System.out.println();
238 System.out.println("**********************************************************************************");
239 System.out.println(" Explicit EnvelopedDataDemo " + contentEncAlg.getName());
240 System.out.println(" (shows the usage of the CMS EnvelopedData type implementation) ");
241 System.out.println("**********************************************************************************");
242 System.out.println();
243
244 // add all certificates to the list
245 X509Certificate[] certs = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1);
246 rsaUser1_ = certs[0];
247 rsaUser1Pk_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1);
248 rsaUser2_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0];
249 rsaUser2Pk_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2);
250
251 esdhUser1_ = CMSKeyStore.getCertificateChain(CMSKeyStore.ESDH, CMSKeyStore.SZ_2048_CRYPT_1)[0];
252 esdhUser1Pk_ = CMSKeyStore.getPrivateKey(CMSKeyStore.ESDH, CMSKeyStore.SZ_2048_CRYPT_1);
253 esdhUser2_ = CMSKeyStore.getCertificateChain(CMSKeyStore.ESDH, CMSKeyStore.SZ_2048_CRYPT_2)[0];
254 esdhUser2Pk_ = CMSKeyStore.getPrivateKey(CMSKeyStore.ESDH, CMSKeyStore.SZ_2048_CRYPT_2);
255 random_ = SecRandom.getDefault();
256
257 contentEncAlg_ = contentEncAlg;
258 keyWrapAlg_ = keyWrapAlg;
259 keyLength_ = keyLength;
260
261
262 // create a secret key encryption key for a KEKRecipientInfo
263 KeyGenerator kg = SecurityProvider.getSecurityProvider().getKeyGenerator(kekAlg, keyLength_);
264 kek_ = kg.generateKey();
265 kekID_ = new byte[] { 00, 00, 00, 01 };
266 }
267
268
269 /**
270 * Creates a CMS <code>EnvelopedDataStream</code> message.
271 *
272 * @param message the message to be enveloped, as byte representation
273 * @return the DER encoding of the <code>EnvelopedData</code> object just created
274 * @throws CMSException if the <code>EnvelopedData</code> object cannot
275 * be created
276 * @throws IOException if an I/O error occurs
277 */
278 public EnvelopedDataAndEncryptedContent createEnvelopedDataStream(byte[] message) throws CMSException, IOException {
279
280 EnvelopedDataStream enveloped_data;
281
282 // we are testing the stream interface
283 ByteArrayInputStream is = new ByteArrayInputStream(message);
284 // create a new EnvelopedData object encrypted with TripleDES CBC
285 try {
286 enveloped_data = new EnvelopedDataStream(is, (AlgorithmID)contentEncAlg_.clone());
287 } catch (NoSuchAlgorithmException ex) {
288 throw new CMSException("No implementation for content encryption algorithm: " + ex.toString());
289 }
290
291 // encrypted content shall be transmitted outside the EnvelopedData
292 enveloped_data.setMode(EnvelopedDataStream.EXPLICIT);
293
294 // create the recipient infos
295 RecipientInfo[] recipients = createRecipients();
296 // specify the recipients of the encrypted message
297 enveloped_data.setRecipientInfos(recipients);
298
299 // read and encrypt the content data to be transmitted outside the EnvelopedData
300 InputStream encryptedContentIs = enveloped_data.getInputStream();
301 byte[] encryptedContent = Util.readStream(encryptedContentIs);
302
303 // return the EnvelopedDate as DER encoded byte array with block size 2048
304 ByteArrayOutputStream os = new ByteArrayOutputStream();
305 enveloped_data.writeTo(os);
306 byte[] encodedEnvelopedData = os.toByteArray();
307 return new EnvelopedDataAndEncryptedContent(encodedEnvelopedData, encryptedContent);
308 }
309
310 /**
311 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
312 * the recipient identified by its index into the recipientInfos field.
313 * <p>
314 * This way of decrypting the content may be used for any type of RecipientInfo
315 * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo), but requires to
316 * know at what index of the recipientInfo field the RecipientInfo for the
317 * particular recipient in mind can be found. If the recipient in mind uses
318 * a RecipientInfo of type KeyAgreeRecipientInfo some processing overhead may
319 * take place because a KeyAgreeRecipientInfo may contain encrypted content-encryption
320 * keys for more than only one recipient; since the recipientInfoIndex only
321 * specifies the RecipientInfo but not the encrypted content encryption key
322 * -- if there are more than only one -- repeated decryption runs may be
323 * required as long as the decryption process completes successfully.
324 *
325 * @param encoding the <code>EnvelopedData</code> object as DER encoded byte array
326 * @param key the key to decrypt the message
327 * @param recipientInfoIndex the index into the <code>RecipientInfo</code> array
328 * to which the specified key belongs
329 *
330 * @return the recovered message, as byte array
331 * @throws CMSException if the message cannot be recovered
332 * @throws IOException if a stream read/write error occurs
333 */
334 public byte[] getEnvelopedDataStream(byte[] encoding, byte[] encryptedContent, Key key, int recipientInfoIndex)
335 throws CMSException, IOException {
336
337 // create the EnvelopedData object from a DER encoded byte array
338 // we are testing the stream interface
339 ByteArrayInputStream is = new ByteArrayInputStream(encoding);
340 EnvelopedDataStream enveloped_data = new EnvelopedDataStream(is);
341
342 System.out.println("Information about the encrypted data:");
343 EncryptedContentInfoStream eci = (EncryptedContentInfoStream)enveloped_data.getEncryptedContentInfo();
344 System.out.println("Content type: "+eci.getContentType().getName());
345 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
346
347 System.out.println("\nThis message can be decrypted by the owners of the following certificates:");
348 RecipientInfo[] recipients = enveloped_data.getRecipientInfos();
349
350 // for demonstration purposes we only look one time for all recipients included:
351 if (recipientInfoIndex == 0) {
352 int k = 0;
353 for (int i=0; i<recipients.length; i++) {
354 KeyIdentifier[] recipientIDs = recipients[i].getRecipientIdentifiers();
355 for (int j = 0; j < recipientIDs.length; j++) {
356 System.out.println("Recipient "+(++k)+":");
357 System.out.println(recipientIDs[j]);
358 }
359 }
360 }
361
362 // set the encrypted content received by other means
363 enveloped_data.setInputStream(new ByteArrayInputStream(encryptedContent));
364
365 // decrypt the message for the first recipient
366 try {
367 enveloped_data.setupCipher(key, recipientInfoIndex);
368 InputStream decrypted = enveloped_data.getInputStream();
369 ByteArrayOutputStream os = new ByteArrayOutputStream();
370 Util.copyStream(decrypted, os, null);
371
372 return os.toByteArray();
373
374 } catch (InvalidKeyException ex) {
375 throw new CMSException("Private key error: "+ex.getMessage());
376 } catch (NoSuchAlgorithmException ex) {
377 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
378 }
379 }
380
381 /**
382 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
383 * the recipient identified by recipient identifier.
384 * <p>
385 * This way of decrypting the content may be used for any type of RecipientInfo
386 * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo). The
387 * recipient in mind is identified by its recipient identifier.
388 *
389 * @param encoding the <code>EnvelopedData</code> object as DER encoded byte array
390 * @param key the key to decrypt the message
391 * @param recipientID the recipient identifier uniquely identifying the key of the
392 * recipient
393 *
394 * @return the recovered message, as byte array
395 * @throws CMSException if the message cannot be recovered
396 * @throws IOException if a stream read/write error occurs
397 */
398 public byte[] getEnvelopedDataStream(byte[] encoding, byte[] encryptedContent, Key key, KeyIdentifier recipientID)
399 throws CMSException, IOException {
400
401 // create the EnvelopedData object from a DER encoded byte array
402 // we are testing the stream interface
403 ByteArrayInputStream is = new ByteArrayInputStream(encoding);
404 EnvelopedDataStream enveloped_data = new EnvelopedDataStream(is);
405
406 System.out.println("Information about the encrypted data:");
407 EncryptedContentInfoStream eci = (EncryptedContentInfoStream)enveloped_data.getEncryptedContentInfo();
408 System.out.println("Content type: "+eci.getContentType().getName());
409 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
410
411 // get the right RecipientInfo
412 System.out.println("\nSearch for RecipientInfo:");
413 RecipientInfo recipient = enveloped_data.getRecipientInfo(recipientID);
414 if (recipient != null) {
415 System.out.println("RecipientInfo: " + recipient);
416 } else {
417 throw new CMSException("No recipient with ID: " + recipientID);
418 }
419
420 // set the encrypted content received by other means
421 enveloped_data.setInputStream(new ByteArrayInputStream(encryptedContent));
422
423 // decrypt the content encryption key and the content
424 try {
425 System.out.println("Decrypt encrypted content encryption key...");
426 SecretKey cek = recipient.decryptKey(key, recipientID);
427 System.out.println("Decrypt content with decrypted content encryption key...");
428 enveloped_data.setupCipher(cek);
429 InputStream decrypted = enveloped_data.getInputStream();
430 ByteArrayOutputStream os = new ByteArrayOutputStream();
431 Util.copyStream(decrypted, os, null);
432
433 return os.toByteArray();
434
435 } catch (InvalidKeyException ex) {
436 throw new CMSException("Private key error: "+ex.getMessage());
437 } catch (NoSuchAlgorithmException ex) {
438 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
439 }
440 }
441
442 /**
443 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
444 * the recipient identified by its recipient certificate or kekID.
445 * <p>
446 * Since recipient certificates only may be used for for RecipientInfos of type
447 * KeyTransRecipientInfo or KeyAgreeRecipientInfo, a key id has to be supplied
448 * for decrypting the content for a recipient using a KEKRecipientInfo.
449 *
450 * @param encoding the <code>EnvelopedData</code> object as DER encoded byte array
451 * @param key the key to decrypt the message
452 * @param recipientCert the certificate of the recipient having a RecipientInfo of
453 * type KeyTransRecipientInfo or KeyAgreeRecipientInfo
454 * @param kekID the kekID identifying the recipient key when using a RecipientInfo
455 * of type KEKRecipientInfo
456 *
457 * @return the recovered message, as byte array
458 * @throws CMSException if the message cannot be recovered
459 * @throws IOException if a stream read/write error occurs
460 */
461 public byte[] getEnvelopedDataStream(byte[] encoding, byte[] encryptedContent, Key key, X509Certificate recipientCert, byte[] kekID)
462 throws CMSException, IOException {
463
464 // create the EnvelopedData object from a DER encoded byte array
465 // we are testing the stream interface
466 ByteArrayInputStream is = new ByteArrayInputStream(encoding);
467 EnvelopedDataStream enveloped_data = new EnvelopedDataStream(is);
468
469 System.out.println("Information about the encrypted data:");
470 EncryptedContentInfoStream eci = (EncryptedContentInfoStream)enveloped_data.getEncryptedContentInfo();
471 System.out.println("Content type: "+eci.getContentType().getName());
472 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
473
474 // set the encrypted content received by other means
475 enveloped_data.setInputStream(new ByteArrayInputStream(encryptedContent));
476
477 // decrypt the content encryption key and the content
478 try {
479 System.out.println("Decrypt the content...");
480 if (recipientCert != null) {
481 enveloped_data.setupCipher(key, recipientCert);
482 } else {
483 // KEKRecipientInfo
484 enveloped_data.setupCipher(key, new KEKIdentifier(kekID));
485 }
486 InputStream decrypted = enveloped_data.getInputStream();
487 ByteArrayOutputStream os = new ByteArrayOutputStream();
488 Util.copyStream(decrypted, os, null);
489
490 return os.toByteArray();
491
492 } catch (InvalidKeyException ex) {
493 throw new CMSException("Private key error: "+ex.getMessage());
494 } catch (NoSuchAlgorithmException ex) {
495 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
496 }
497 }
498
499
500 // non stream
501
502 /**
503 * Creates a CMS <code>EnvelopedData</code> message.
504 *
505 * @param message the message to be enveloped, as byte representation
506 *
507 * @return the encoded <code>EnvelopedData</code>, as byte array
508 *
509 * @throws CMSException if the <code>EnvelopedData</code> object cannot
510 * be created
511 */
512 public EnvelopedDataAndEncryptedContent createEnvelopedData(byte[] message) throws CMSException {
513
514 EnvelopedData enveloped_data;
515
516 // create a new EnvelopedData object encrypted with TripleDES CBC
517 try {
518 enveloped_data = new EnvelopedData(message, (AlgorithmID)contentEncAlg_.clone());
519 } catch (NoSuchAlgorithmException ex) {
520 throw new CMSException("No implementation for content encryption algorithm: " + ex.toString());
521 }
522
523 // encrypted content shall be transmitted outside the EnvelopedData
524 enveloped_data.setMode(EnvelopedDataStream.EXPLICIT);
525
526 // set the RecipientInfos
527 RecipientInfo[] recipients = createRecipients();
528 enveloped_data.setRecipientInfos(recipients);
529
530 // get the encrypted content data to be transmitted outside the EnvelopedData
531 byte[] encryptedContent = enveloped_data.getContent();
532
533 // return encoded EnvelopedData
534 byte[] encodedEnvelopedData = enveloped_data.getEncoded();
535 return new EnvelopedDataAndEncryptedContent(encodedEnvelopedData, encryptedContent);
536 }
537
538
539 /**
540 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
541 * the recipient identified by its index into the recipientInfos field.
542 * <p>
543 * This way of decrypting the content may be used for any type of RecipientInfo
544 * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo), but requires to
545 * know at what index of the recipientInfo field the RecipientInfo for the
546 * particular recipient in mind can be found. If the recipient in mind uses
547 * a RecipientInfo of type KeyAgreeRecipientInfo some processing overhead may
548 * take place because a KeyAgreeRecipientInfo may contain encrypted content-encryption
549 * keys for more than only one recipient; since the recipientInfoIndex only
550 * specifies the RecipientInfo but not the encrypted content encryption key
551 * -- if there are more than only one -- repeated decryption runs may be
552 * required as long as the decryption process completes successfully.
553 *
554 * @param enc the encoded <code>EnvelopedData</code>
555 *
556 * @param key the key to decrypt the message
557 *
558 * @param recipientInfoIndex the index into the <code>RecipientInfo</code> array
559 * to which the specified key belongs
560 *
561 * @return the recovered message, as byte array
562 *
563 * @throws CMSException if the message cannot be recovered
564 * @throws IOException if an I/O error occurs
565 */
566 public byte[] getEnvelopedData(byte[] enc, byte[] encryptedContent, Key key, int recipientInfoIndex)
567 throws CMSException, IOException {
568 ByteArrayInputStream bais = new ByteArrayInputStream(enc);
569 EnvelopedData enveloped_data = new EnvelopedData(bais);
570
571 System.out.println("Information about the encrypted data:");
572 EncryptedContentInfo eci = (EncryptedContentInfo)enveloped_data.getEncryptedContentInfo();
573 System.out.println("Content type: "+eci.getContentType().getName());
574 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
575
576 System.out.println("\nThis message can be decrypted by the owners of the following certificates:");
577 RecipientInfo[] recipients = enveloped_data.getRecipientInfos();
578
579 // set the encrypted content received by other means
580 enveloped_data.setContent(encryptedContent);
581
582 // for demonstration purposes we only look one time for all recipients included:
583 if (recipientInfoIndex == 0) {
584 int k = 0;
585 for (int i=0; i<recipients.length; i++) {
586 KeyIdentifier[] recipientIDs = recipients[i].getRecipientIdentifiers();
587 for (int j = 0; j < recipientIDs.length; j++) {
588 System.out.println("Recipient "+(++k)+":");
589 System.out.println(recipientIDs[j]);
590 }
591 }
592 }
593
594 // decrypt the message
595 try {
596 enveloped_data.setupCipher(key, recipientInfoIndex);
597 return enveloped_data.getContent();
598
599 } catch (InvalidKeyException ex) {
600 throw new CMSException("Private key error: "+ex.getMessage());
601 } catch (NoSuchAlgorithmException ex) {
602 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
603 }
604 }
605
606 /**
607 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
608 * the recipient identified by recipient identifier.
609 * <p>
610 * This way of decrypting the content may be used for any type of RecipientInfo
611 * (KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo). The
612 * recipient in mind is identified by its recipient identifier.
613 *
614 * @param enc the DER encoded <code>EnvelopedData</code> ASN.1 object
615 * @param key the key to decrypt the message
616 * @param recipientID the recipient identifier uniquely identifying the key of the
617 * recipient
618 *
619 * @return the recovered message, as byte array
620 * @throws CMSException if the message cannot be recovered
621 * @throws IOException if an I/O error occurs
622 */
623 public byte[] getEnvelopedData(byte[] enc, byte[] encryptedContent, Key key, KeyIdentifier recipientID)
624 throws CMSException, IOException {
625 ByteArrayInputStream bais = new ByteArrayInputStream(enc);
626 EnvelopedData enveloped_data = new EnvelopedData(bais);
627
628 System.out.println("Information about the encrypted data:");
629 EncryptedContentInfo eci = (EncryptedContentInfo)enveloped_data.getEncryptedContentInfo();
630 System.out.println("Content type: "+eci.getContentType().getName());
631 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
632
633 System.out.println("\nThis message can be decrypted by the owners of the following certificates:");
634
635 // get the right RecipientInfo
636 System.out.println("\nSearch for RecipientInfo:");
637 RecipientInfo recipient = enveloped_data.getRecipientInfo(recipientID);
638 if (recipient != null) {
639 System.out.println("RecipientInfo: " + recipient);
640 } else {
641 throw new CMSException("No recipient with ID: " + recipientID);
642 }
643
644 // set the encrypted content received by other means
645 enveloped_data.setContent(encryptedContent);
646
647 // decrypt the content encryption key and the content
648 try {
649 System.out.println("Decrypt encrypted content encryption key...");
650 SecretKey cek = recipient.decryptKey(key, recipientID);
651 System.out.println("Decrypt content with decrypted content encryption key...");
652 enveloped_data.setupCipher(cek);
653 return enveloped_data.getContent();
654
655 } catch (InvalidKeyException ex) {
656 throw new CMSException("Private key error: "+ex.getMessage());
657 } catch (NoSuchAlgorithmException ex) {
658 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
659 }
660 }
661
662 /**
663 * Decrypts the encrypted content of the given <code>EnvelopedData</code> object for
664 * the recipient identified by its recipient certificate or keyID.
665 * <p>
666 * Since recipient certificates only may be used for for RecipientInfos of type
667 * KeyTransRecipientInfo or KeyAgreeRecipientInfo, a key id has to be supplied
668 * for decrypting the content for a recipient using a KEKRecipientInfo.
669 *
670 * @param enc the DER encoded <code>EnvelopedData</code> ASN.1 object
671 * @param key the key to decrypt the message
672 * @param recipientCert the certificate of the recipient having a RecipientInfo of
673 * type KeyTransRecipientInfo or KeyAgreeRecipientInfo
674 * @param kekID the kekID identifying the recipient key when using a RecipientInfo
675 * of type KEKRecipientInfo
676 *
677 * @return the recovered message, as byte array
678 * @throws CMSException if the message cannot be recovered
679 */
680 public byte[] getEnvelopedData(byte[] enc, byte[] encryptedContent, Key key, X509Certificate recipientCert, byte[] kekID)
681 throws CMSException, IOException {
682 ByteArrayInputStream bais = new ByteArrayInputStream(enc);
683 EnvelopedData enveloped_data = new EnvelopedData(bais);
684
685 System.out.println("Information about the encrypted data:");
686 EncryptedContentInfo eci = (EncryptedContentInfo)enveloped_data.getEncryptedContentInfo();
687 System.out.println("Content type: "+eci.getContentType().getName());
688 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
689
690 System.out.println("\nThis message can be decrypted by the owners of the following certificates:");
691
692 // set the encrypted content received by other means
693 enveloped_data.setContent(encryptedContent);
694
695 // decrypt the content encryption key and the content
696 try {
697 System.out.println("Decrypt the content...");
698 if (recipientCert != null) {
699 enveloped_data.setupCipher(key, recipientCert);
700 } else {
701 // KEKRecipientInfo
702 enveloped_data.setupCipher(key, new KEKIdentifier(kekID));
703 }
704 return enveloped_data.getContent();
705
706 } catch (InvalidKeyException ex) {
707 throw new CMSException("Private key error: "+ex.getMessage());
708 } catch (NoSuchAlgorithmException ex) {
709 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
710 }
711 }
712
713 /**
714 * Creates the RecipientInfos.
715 *
716 * @return the RecipientInfos created, two KeyTransRecipientInfos, one
717 * KeyAgreeRecipientInfo (for two recipients with same domain
718 * parameters), and one KEKRecipientInfo
719 *
720 * @throws CMSException if an error occurs when creating the recipient infos
721 */
722 public RecipientInfo[] createRecipients() throws CMSException {
723
724 RecipientInfo[] recipients = new RecipientInfo[4];
725 try {
726 // rsaUser1 is the first receiver (cert identified by IssuerAndSerialNumber)
727 recipients[0] = new KeyTransRecipientInfo(rsaUser1_,
728 (AlgorithmID)AlgorithmID.rsaEncryption.clone());
729 // rsaUser2 is the second receiver (cert identifief by SubjectKeyIdentifier)
730 recipients[1] = new KeyTransRecipientInfo(rsaUser2_,
731 CertificateIdentifier.SUBJECT_KEY_IDENTIFIER,
732 (AlgorithmID)AlgorithmID.rsaEncryption.clone());
733
734 // next recipients use key agreement
735 // the key encryption (key agreement) algorithm to use:
736 AlgorithmID keyEA = (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone();
737 // the key wrap algorithm to use:
738 AlgorithmID keyWrapAlg = (AlgorithmID)keyWrapAlg_.clone();
739 // the length of the key encryption key to be generated:
740 int kekLength = keyLength_;
741 recipients[2] = new KeyAgreeRecipientInfo(keyEA, keyWrapAlg, kekLength);
742 // esdhUser1 is the third receiver (cert identified by IssuerAndSerialNumber)
743 ((KeyAgreeRecipientInfo)recipients[2]).addRecipient(esdhUser1_, CertificateIdentifier.ISSUER_AND_SERIALNUMBER);
744 // esdhUser2 is the fourth receiver (cert identified by RecipientKeyIdentifier)
745 ((KeyAgreeRecipientInfo)recipients[2]).addRecipient(esdhUser2_, CertificateIdentifier.RECIPIENT_KEY_IDENTIFIER);
746
747 // last receiver uses a symmetric key encryption key
748 AlgorithmID kea = (AlgorithmID)keyWrapAlg_.clone();
749 KEKIdentifier kekIdentifier = new KEKIdentifier(kekID_);
750 recipients[3] = new KEKRecipientInfo(kekIdentifier, kea, kek_);
751 } catch (Exception ex) {
752 throw new CMSException("Error adding recipients: " + ex.getMessage());
753 }
754 return recipients;
755 }
756
757 /**
758 * Parses an EnvelopedData and decrypts the content for all test recipients
759 * using the index into the recipientInfos field for identifying the recipient.
760 *
761 * @param stream whether to use EnvelopedDataStream or EnvelopedData
762 * @param message the original message (to be compared to the decryption result)
763 * @param encodedEnvelopedData the encoded EnvelopedData object
764 *
765 * @throws Exception if some error occurs during decoding/decryption
766 */
767 public void parseEnvelopedDataWithRecipientInfoIndex(boolean stream,
768 byte[] message, byte[] encodedEnvelopedData, byte[] encryptedContent) throws Exception {
769 byte[] receivedMessage;
770 if (stream) {
771 // rsaUser1
772 System.out.println("\nDecrypt for rsaUser1:");
773 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, encryptedContent, rsaUser1Pk_, 0);
774 if (!Arrays.equals(message, receivedMessage)) {
775 throw new IOException("Decryption error!");
776 }
777 System.out.print("\nDecrypted content: ");
778 System.out.println(new String(receivedMessage));
779 // rsaUser2
780 System.out.println("\nDecrypt for rsaUser2:");
781 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, encryptedContent, rsaUser2Pk_, 1);
782 if (!Arrays.equals(message, receivedMessage)) {
783 throw new IOException("Decryption error!");
784 }
785 System.out.print("\nDecrypted content: ");
786 System.out.println(new String(receivedMessage));
787 // esdhUser1
788 System.out.println("\nDecrypt for esdhUser1:");
789 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, encryptedContent, esdhUser1Pk_, 2);
790 if (!Arrays.equals(message, receivedMessage)) {
791 throw new IOException("Decryption error!");
792 }
793 System.out.print("\nDecrypted content: ");
794 System.out.println(new String(receivedMessage));
795 // esdhUser2
796 System.out.println("\nDecrypt for esdhUser2:");
797 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, encryptedContent, esdhUser2Pk_, 2);
798 if (!Arrays.equals(message, receivedMessage)) {
799 throw new IOException("Decryption error!");
800 }
801 System.out.print("\nDecrypted content: ");
802 System.out.println(new String(receivedMessage));
803 // kekUser
804 System.out.println("\nDecrypt for kekUser:");
805 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, encryptedContent, kek_, 3);
806 if (!Arrays.equals(message, receivedMessage)) {
807 throw new IOException("Decryption error!");
808 }
809 System.out.print("\nDecrypted content: ");
810 System.out.println(new String(receivedMessage));
811 } else {
812 // rsaUser1
813 System.out.println("\nDecrypt for rsaUser1:");
814 receivedMessage = getEnvelopedData(encodedEnvelopedData, encryptedContent, rsaUser1Pk_, 0);
815 if (!Arrays.equals(message, receivedMessage)) {
816 throw new IOException("Decryption error!");
817 }
818 System.out.print("\nDecrypted content: ");
819 System.out.println(new String(receivedMessage));
820 // rsaUser2
821 System.out.println("\nDecrypt for rsaUser2:");
822 receivedMessage = getEnvelopedData(encodedEnvelopedData, encryptedContent, rsaUser2Pk_, 1);
823 if (!Arrays.equals(message, receivedMessage)) {
824 throw new IOException("Decryption error!");
825 }
826 System.out.print("\nDecrypted content: ");
827 System.out.println(new String(receivedMessage));
828 // esdhUser1
829 System.out.println("\nDecrypt for esdhUser1:");
830 receivedMessage = getEnvelopedData(encodedEnvelopedData, encryptedContent, esdhUser1Pk_, 2);
831 if (!Arrays.equals(message, receivedMessage)) {
832 throw new IOException("Decryption error!");
833 }
834 System.out.print("\nDecrypted content: ");
835 System.out.println(new String(receivedMessage));
836 // esdhUser2
837 System.out.println("\nDecrypt for esdhUser2:");
838 receivedMessage = getEnvelopedData(encodedEnvelopedData, encryptedContent, esdhUser2Pk_, 2);
839 if (!Arrays.equals(message, receivedMessage)) {
840 throw new IOException("Decryption error!");
841 }
842 System.out.print("\nDecrypted content: ");
843 System.out.println(new String(receivedMessage));
844 // kekUser
845 System.out.println("\nDecrypt for kekUser:");
846 receivedMessage = getEnvelopedData(encodedEnvelopedData, encryptedContent, kek_, 3);
847 if (!Arrays.equals(message, receivedMessage)) {
848 throw new IOException("Decryption error!");
849 }
850 System.out.print("\nDecrypted content: ");
851 System.out.println(new String(receivedMessage));
852 }
853 }
854
855 /**
856 * Parses an EnvelopedData and decrypts the content for all test recipients
857 * using their recipient identifiers for identifying the recipient.
858 *
859 * @param stream whether to use EnvelopedDataStream or EnvelopedData
860 * @param message the original message (to be compared to the decryption result)
861 * @param encodedEnvelopedData the encoded EnvelopedData object
862 *
863 * @throws Exception if some error occurs during decoding/decryption
864 */
865 public void parseEnvelopedDataWithRecipientIdentifier(boolean stream,
866 byte[] message, byte[] encodedEnvelopedData, byte[] encryptedContent) throws Exception {
867 byte[] receivedMessage;
868 if (stream) {
869 // rsaUser1
870 System.out.println("\nDecrypt for rsaUser1:");
871 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, encryptedContent, rsaUser1Pk_, new IssuerAndSerialNumber(rsaUser1_));
872 if (!Arrays.equals(message, receivedMessage)) {
873 throw new IOException("Decryption error!");
874 }
875 System.out.print("\nDecrypted content: ");
876 System.out.println(new String(receivedMessage));
877 // rsaUser2
878 System.out.println("\nDecrypt for rsaUser2:");
879 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, encryptedContent, rsaUser2Pk_, new SubjectKeyID(rsaUser2_));
880 if (!Arrays.equals(message, receivedMessage)) {
881 throw new IOException("Decryption error!");
882 }
883 System.out.print("\nDecrypted content: ");
884 System.out.println(new String(receivedMessage));
885 // esdhUser1
886 System.out.println("\nDecrypt for esdhUser1:");
887 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, encryptedContent, esdhUser1Pk_, new IssuerAndSerialNumber(esdhUser1_));
888 if (!Arrays.equals(message, receivedMessage)) {
889 throw new IOException("Decryption error!");
890 }
891 System.out.print("\nDecrypted content: ");
892 System.out.println(new String(receivedMessage));
893 // esdhUser2
894 System.out.println("\nDecrypt for esdhUser2:");
895 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, encryptedContent, esdhUser2Pk_, new RecipientKeyIdentifier(esdhUser2_));
896 if (!Arrays.equals(message, receivedMessage)) {
897 throw new IOException("Decryption error!");
898 }
899 System.out.print("\nDecrypted content: ");
900 System.out.println(new String(receivedMessage));
901 // kekUser
902 System.out.println("\nDecrypt for kekUser:");
903 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, encryptedContent, kek_, new KEKIdentifier(kekID_));
904 if (!Arrays.equals(message, receivedMessage)) {
905 throw new IOException("Decryption error!");
906 }
907 System.out.print("\nDecrypted content: ");
908 System.out.println(new String(receivedMessage));
909 } else {
910 // rsaUser1
911 System.out.println("\nDecrypt for rsaUser1:");
912 receivedMessage = getEnvelopedData(encodedEnvelopedData, encryptedContent, rsaUser1Pk_, new IssuerAndSerialNumber(rsaUser1_));
913 if (!Arrays.equals(message, receivedMessage)) {
914 throw new IOException("Decryption error!");
915 }
916 System.out.print("\nDecrypted content: ");
917 System.out.println(new String(receivedMessage));
918 // rsaUser2
919 System.out.println("\nDecrypt for rsaUser2:");
920 receivedMessage = getEnvelopedData(encodedEnvelopedData, encryptedContent, rsaUser2Pk_, new SubjectKeyID(rsaUser2_));
921 if (!Arrays.equals(message, receivedMessage)) {
922 throw new IOException("Decryption error!");
923 }
924 System.out.print("\nDecrypted content: ");
925 System.out.println(new String(receivedMessage));
926 // esdhUser1
927 System.out.println("\nDecrypt for esdhUser1:");
928 receivedMessage = getEnvelopedData(encodedEnvelopedData, encryptedContent, esdhUser1Pk_, new IssuerAndSerialNumber(esdhUser1_));
929 if (!Arrays.equals(message, receivedMessage)) {
930 throw new IOException("Decryption error!");
931 }
932 System.out.print("\nDecrypted content: ");
933 System.out.println(new String(receivedMessage));
934 // esdhUser2
935 System.out.println("\nDecrypt for esdhUser2:");
936 receivedMessage = getEnvelopedData(encodedEnvelopedData, encryptedContent, esdhUser2Pk_, new RecipientKeyIdentifier(esdhUser2_));
937 if (!Arrays.equals(message, receivedMessage)) {
938 throw new IOException("Decryption error!");
939 }
940 System.out.print("\nDecrypted content: ");
941 System.out.println(new String(receivedMessage));
942 // kekUser
943 System.out.println("\nDecrypt for kekUser:");
944 receivedMessage = getEnvelopedData(encodedEnvelopedData, encryptedContent, kek_, new KEKIdentifier(kekID_));
945 if (!Arrays.equals(message, receivedMessage)) {
946 throw new IOException("Decryption error!");
947 }
948 System.out.print("\nDecrypted content: ");
949 System.out.println(new String(receivedMessage));
950 }
951 }
952
953 /**
954 * Parses an EnvelopedData and decrypts the content for all test recipients
955 * using their recipient certificate (for RecipientInfos of type KeyTransRecipientInfo
956 * or KeyAgreeRecipientInfo) or key id (for RecipientInfos of type KEKRecipientInfo)
957 * for identifying the recipient.
958 *
959 * @param stream whether to use EnvelopedDataStream or EnvelopedData
960 * @param message the original message (to be compared to the decryption result)
961 * @param encodedEnvelopedData the encoded EnvelopedData object
962 *
963 * @throws Exception if some error occurs during decoding/decryption
964 */
965 public void parseEnvelopedDataWithRecipientCertOrKEKId(boolean stream,
966 byte[] message, byte[] encodedEnvelopedData, byte[] encryptedContent) throws Exception {
967 byte[] receivedMessage;
968 if (stream) {
969 // rsaUser1
970 System.out.println("\nDecrypt for rsaUser1:");
971 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, encryptedContent, rsaUser1Pk_, rsaUser1_, null);
972 if (!Arrays.equals(message, receivedMessage)) {
973 throw new IOException("Decryption error!");
974 }
975 System.out.print("\nDecrypted content: ");
976 System.out.println(new String(receivedMessage));
977 // rsaUser2
978 System.out.println("\nDecrypt for rsaUser2:");
979 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, encryptedContent, rsaUser2Pk_, rsaUser2_, null);
980 if (!Arrays.equals(message, receivedMessage)) {
981 throw new IOException("Decryption error!");
982 }
983 System.out.print("\nDecrypted content: ");
984 System.out.println(new String(receivedMessage));
985 // esdhUser1
986 System.out.println("\nDecrypt for esdhUser1:");
987 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, encryptedContent, esdhUser1Pk_, esdhUser1_, null);
988 if (!Arrays.equals(message, receivedMessage)) {
989 throw new IOException("Decryption error!");
990 }
991 System.out.print("\nDecrypted content: ");
992 System.out.println(new String(receivedMessage));
993 // esdhUser2
994 System.out.println("\nDecrypt for esdhUser2:");
995 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, encryptedContent, esdhUser2Pk_, esdhUser2_, null);
996 if (!Arrays.equals(message, receivedMessage)) {
997 throw new IOException("Decryption error!");
998 }
999 System.out.print("\nDecrypted content: ");
1000 System.out.println(new String(receivedMessage));
1001 // kekUser
1002 System.out.println("\nDecrypt for kekUser:");
1003 receivedMessage = getEnvelopedDataStream(encodedEnvelopedData, encryptedContent, kek_, null, kekID_);
1004 if (!Arrays.equals(message, receivedMessage)) {
1005 throw new IOException("Decryption error!");
1006 }
1007 System.out.print("\nDecrypted content: ");
1008 System.out.println(new String(receivedMessage));
1009 } else {
1010 // rsaUser1
1011 System.out.println("\nDecrypt for rsaUser1:");
1012 receivedMessage = getEnvelopedData(encodedEnvelopedData, encryptedContent, rsaUser1Pk_, rsaUser1_, null);
1013 if (!Arrays.equals(message, receivedMessage)) {
1014 throw new IOException("Decryption error!");
1015 }
1016 System.out.print("\nDecrypted content: ");
1017 System.out.println(new String(receivedMessage));
1018 // rsaUser2
1019 System.out.println("\nDecrypt for rsaUser2:");
1020 receivedMessage = getEnvelopedData(encodedEnvelopedData, encryptedContent, rsaUser2Pk_, rsaUser2_, null);
1021 if (!Arrays.equals(message, receivedMessage)) {
1022 throw new IOException("Decryption error!");
1023 }
1024 System.out.print("\nDecrypted content: ");
1025 System.out.println(new String(receivedMessage));
1026 // esdhUser1
1027 System.out.println("\nDecrypt for esdhUser1:");
1028 receivedMessage = getEnvelopedData(encodedEnvelopedData, encryptedContent, esdhUser1Pk_, esdhUser1_, null);
1029 if (!Arrays.equals(message, receivedMessage)) {
1030 throw new IOException("Decryption error!");
1031 }
1032 System.out.print("\nDecrypted content: ");
1033 System.out.println(new String(receivedMessage));
1034 // esdhUser2
1035 System.out.println("\nDecrypt for esdhUser2:");
1036 receivedMessage = getEnvelopedData(encodedEnvelopedData, encryptedContent, esdhUser2Pk_, esdhUser2_, null);
1037 if (!Arrays.equals(message, receivedMessage)) {
1038 throw new IOException("Decryption error!");
1039 }
1040 System.out.print("\nDecrypted content: ");
1041 System.out.println(new String(receivedMessage));
1042 // kekUser
1043 System.out.println("\nDecrypt for kekUser:");
1044 receivedMessage = getEnvelopedData(encodedEnvelopedData, encryptedContent, kek_, null, kekID_);
1045 if (!Arrays.equals(message, receivedMessage)) {
1046 throw new IOException("Decryption error!");
1047 }
1048 System.out.print("\nDecrypted content: ");
1049 System.out.println(new String(receivedMessage));
1050 }
1051 }
1052
1053 /**
1054 * Starts the test.
1055 */
1056 public void start() {
1057 // the test message
1058 String m = "This is the test message.";
1059 System.out.println("Test message: \""+m+"\"");
1060 System.out.println();
1061 byte[] message = m.getBytes();
1062
1063 try {
1064 EnvelopedDataAndEncryptedContent envelopedDataAndEncryptedContent;
1065 System.out.println("Stream implementation demos");
1066 System.out.println("===========================");
1067
1068
1069 // the stream implementation
1070 //
1071 // test CMS EnvelopedDataStream
1072 //
1073 System.out.println("\nCMS EnvelopedDataStream demo [create]:\n");
1074 envelopedDataAndEncryptedContent = createEnvelopedDataStream(message);
1075 byte[] encodedEnvelopedData = envelopedDataAndEncryptedContent.getEnvelopedData();
1076 byte[] encryptedContent = envelopedDataAndEncryptedContent.getEncryptedContent();
1077 // transmit data
1078 System.out.println("\nCMS EnvelopedDataStream demo [parse]:\n");
1079 System.out.println("Decrypt for the several recipients using their index into the recipientInfos field.");
1080 parseEnvelopedDataWithRecipientInfoIndex(true, message, encodedEnvelopedData, encryptedContent);
1081 System.out.println("Decrypt for the several recipients using their RecipientIdentifier.");
1082 parseEnvelopedDataWithRecipientIdentifier(true, message, encodedEnvelopedData, encryptedContent);
1083 System.out.println("Decrypt for the several recipients using their certificate or symmetric kek.");
1084 parseEnvelopedDataWithRecipientCertOrKEKId(true, message, encodedEnvelopedData, encryptedContent);
1085
1086 // the non-stream implementation
1087 System.out.println("\nNon-stream implementation demos");
1088 System.out.println("===============================");
1089
1090
1091 //
1092 // test CMS EnvelopedData
1093 //
1094 System.out.println("\nCMS EnvelopedData demo [create]:\n");
1095 envelopedDataAndEncryptedContent = createEnvelopedData(message);
1096 encodedEnvelopedData = envelopedDataAndEncryptedContent.getEnvelopedData();
1097 encryptedContent = envelopedDataAndEncryptedContent.getEncryptedContent();
1098 // transmit data
1099 System.out.println("\nCMS EnvelopedData demo [parse]:\n");
1100 System.out.println("Decrypt for the several recipients using their index into the recipientInfos field.");
1101 parseEnvelopedDataWithRecipientInfoIndex(false, message, encodedEnvelopedData, encryptedContent);
1102 System.out.println("Decrypt for the several recipients using their RecipientIdentifier.");
1103 parseEnvelopedDataWithRecipientIdentifier(false, message, encodedEnvelopedData, encryptedContent);
1104 System.out.println("Decrypt for the several recipients using their certificate or symmetric kek.");
1105 parseEnvelopedDataWithRecipientCertOrKEKId(false, message, encodedEnvelopedData, encryptedContent);
1106
1107
1108 } catch (Exception ex) {
1109 ex.printStackTrace();
1110 throw new RuntimeException(ex.toString());
1111 }
1112 }
1113
1114 /**
1115 * Main method.
1116 *
1117 * @throws IOException
1118 * if an I/O error occurs when reading required keys
1119 * and certificates from files
1120 */
1121 public static void main(String argv[]) throws Exception {
1122
1123 DemoUtil.initDemos();
1124 (new ExplicitEnvelopedDataDemo()).start();
1125 System.out.println("\nReady!");
1126 DemoUtil.waitKey();
1127 }
1128
1129 /**
1130 * Helper class to wrap encoded EnvelopedData and encrypted content.
1131 */
1132 private final static class EnvelopedDataAndEncryptedContent {
1133
1134 /**
1135 * The encoded EnvelopedData.
1136 */
1137 private byte[] envelopedData_;
1138
1139 /**
1140 * The encrypted content.
1141 */
1142 private byte[] encryptedContent_;
1143
1144 /**
1145 * Creates a EnvelopedDataAndEncryptedContent.
1146 *
1147 * @param envelopedData the encoded EnvelopedData.
1148 * @param encryptedContent the encrypted content
1149 */
1150 public EnvelopedDataAndEncryptedContent(byte[] envelopedData, byte[] encryptedContent) {
1151 envelopedData_ = envelopedData;
1152 encryptedContent_ = encryptedContent;
1153 }
1154
1155 /**
1156 * Gets the encoded EnvelopedData.
1157 *
1158 * @return the encoded EnvelopedData
1159 */
1160 public byte[] getEnvelopedData() {
1161 return envelopedData_;
1162 }
1163
1164 /**
1165 * Gets the encrypted content.
1166 *
1167 *
1168 * @return the encrypted content
1169 */
1170 public byte[] getEncryptedContent() {
1171 return encryptedContent_;
1172 }
1173 }
1174 }