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/pkcs7cms/PKCS7CMSEncryptedDataDemo.java 16 12.02.25 17:58 Dbratko $
059 // $Revision: 16 $
060 //
061
062 package demo.cms.pkcs7cms;
063
064 import iaik.asn1.ASN1Object;
065 import iaik.asn1.structures.AlgorithmID;
066 import iaik.cms.CMSException;
067 import iaik.cms.EncryptedContentInfo;
068 import iaik.cms.EncryptedContentInfoStream;
069 import iaik.cms.EncryptedData;
070 import iaik.cms.EncryptedDataStream;
071 import iaik.security.random.SecRandom;
072 import iaik.utils.Util;
073
074 import java.io.ByteArrayInputStream;
075 import java.io.ByteArrayOutputStream;
076 import java.io.IOException;
077 import java.io.InputStream;
078 import java.security.InvalidAlgorithmParameterException;
079 import java.security.InvalidKeyException;
080 import java.security.NoSuchAlgorithmException;
081 import java.security.SecureRandom;
082 import java.security.spec.InvalidParameterSpecException;
083
084 import demo.DemoUtil;
085
086 /**
087 * Compares the usage of IAIK CMS with the IAIK PKCS#7 EncryptedData(Stream) implementation.
088 */
089 public class PKCS7CMSEncryptedDataDemo {
090
091 // secure random number generator
092 SecureRandom random;
093
094 /**
095 * Default constructor.
096 */
097 public PKCS7CMSEncryptedDataDemo() {
098
099 System.out.println();
100 System.out.println("***********************************************************************************************");
101 System.out.println("* PKCS7CMSEncryptedDataDemo *");
102 System.out.println("* (tests the CMS EncryptedData against the IAIK-JCE PKCS#7 EncryptedData type implementation) *");
103 System.out.println("***********************************************************************************************");
104 System.out.println();
105
106 random = SecRandom.getDefault();
107 }
108
109
110 /**
111 * Creates a CMS <code>EncryptedDataStream</code> message.
112 * <p>
113 * The supplied content is PBE-encrypted using the specified password.
114 *
115 * @param message the message to be encrypted, as byte representation
116 * @param pbeAlgorithm the PBE algorithm to be used
117 * @param password the password
118 * @return the DER encoding of the <code>EncryptedData</code> object just created
119 * @throws CMSException if the <code>EncryptedData</code> object cannot
120 * be created
121 * @throws IOException if an I/O error occurs
122 */
123 public byte[] createEncryptedDataStream(byte[] message, AlgorithmID pbeAlgorithm, char[] password) throws CMSException, IOException {
124
125 EncryptedDataStream encrypted_data;
126
127 // we are testing the stream interface
128 ByteArrayInputStream is = new ByteArrayInputStream(message);
129 // create a new EnvelopedData object encrypted with TripleDES CBC
130 try {
131 encrypted_data = new EncryptedDataStream(is, 2048);
132 encrypted_data.setupCipher(pbeAlgorithm, password);
133 } catch (InvalidKeyException ex) {
134 throw new CMSException("Key error: "+ex.toString());
135 } catch (NoSuchAlgorithmException ex) {
136 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
137 }
138
139 // return the EnvelopedDate as DER encoded byte array with block size 2048
140 ByteArrayOutputStream os = new ByteArrayOutputStream();
141 encrypted_data.writeTo(os);
142 return os.toByteArray();
143 }
144
145 /**
146 * Decrypts the PBE-encrypted content of the given CMS <code>EncryptedData</code> object
147 * using the specified password and returns the decrypted (= original) message.
148 *
149 * @param encoding the <code>EncryptedData</code> object as DER encoded byte array
150 * @param password the password to decrypt the message
151 *
152 * @return the recovered message, as byte array
153 * @throws CMSException if the message cannot be recovered
154 * @throws IOException if an I/O error occurs
155 */
156 public byte[] getEncryptedDataStream(byte[] encoding, char[] password) throws CMSException, IOException {
157
158 // create the EncryptpedData object from a DER encoded byte array
159 // we are testing the stream interface
160 ByteArrayInputStream is = new ByteArrayInputStream(encoding);
161 EncryptedDataStream encrypted_data = new EncryptedDataStream(is);
162
163 System.out.println("Information about the encrypted data:");
164 EncryptedContentInfoStream eci = encrypted_data.getEncryptedContentInfo();
165 System.out.println("Content type: "+eci.getContentType().getName());
166 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
167
168 // decrypt the message
169 try {
170 encrypted_data.setupCipher(password);
171 InputStream decrypted = encrypted_data.getInputStream();
172 ByteArrayOutputStream os = new ByteArrayOutputStream();
173 Util.copyStream(decrypted, os, null);
174
175 return os.toByteArray();
176
177 } catch (InvalidKeyException ex) {
178 throw new CMSException("Key error: "+ex.toString());
179 } catch (NoSuchAlgorithmException ex) {
180 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
181 } catch (InvalidAlgorithmParameterException ex) {
182 throw new CMSException("Invalid Parameters: "+ex.toString());
183 } catch (InvalidParameterSpecException ex) {
184 throw new CMSException("Invalid Parameters: "+ex.toString());
185 }
186 }
187
188 /**
189 * Creates a CMS <code>EncryptedData</code> message.
190 * <p>
191 * The supplied content is PBE-encrypted using the specified password.
192 *
193 * @param message the message to be encrypted, as byte representation
194 * @param pbeAlgorithm the PBE algorithm to be used
195 * @param password the password
196 * @return the DER encoding of the <code>EncryptedData</code> object just created
197 * @throws CMSException if the <code>EncryptedData</code> object cannot
198 * be created
199 * @throws IOException if an I/O error occurs
200 */
201 public ASN1Object createEncryptedData(byte[] message, AlgorithmID pbeAlgorithm, char[] password) throws CMSException, IOException {
202
203 EncryptedData encrypted_data;
204
205 try {
206 encrypted_data = new EncryptedData(message);
207 // encrypt the message
208 encrypted_data.setupCipher(pbeAlgorithm, password);
209 } catch (InvalidKeyException ex) {
210 throw new CMSException("Key error: "+ex.toString());
211 } catch (NoSuchAlgorithmException ex) {
212 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
213 }
214 return encrypted_data.toASN1Object();
215
216 }
217
218 /**
219 * Decrypts the PBE-encrypted content of the given CMS <code>EncryptedData</code> object
220 * using the specified password and returns the decrypted (= original) message.
221 *
222 * @param asn1Object the <code>EncryptedData</code> object as ASN1Object
223 * @param password the password to decrypt the message
224 *
225 * @return the recovered message, as byte array
226 * @throws CMSException if the message cannot be recovered
227 * @throws IOException if an I/O error occurs
228 */
229 public byte[] getEncryptedData(ASN1Object asn1Object, char[] password) throws CMSException, IOException {
230
231 // create an EncryptedData from the ASN1Object
232 EncryptedData encrypted_data = new EncryptedData(asn1Object);
233
234 System.out.println("Information about the encrypted data:");
235 EncryptedContentInfo eci = (EncryptedContentInfo)encrypted_data.getEncryptedContentInfo();
236 System.out.println("Content type: "+eci.getContentType().getName());
237 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
238
239 // decrypt the message
240 try {
241 encrypted_data.setupCipher(password);
242 return encrypted_data.getContent();
243
244 } catch (InvalidKeyException ex) {
245 throw new CMSException("Key error: "+ex.toString());
246 } catch (NoSuchAlgorithmException ex) {
247 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
248 } catch (InvalidAlgorithmParameterException ex) {
249 throw new CMSException("Invalid Parameters: "+ex.toString());
250 } catch (InvalidParameterSpecException ex) {
251 throw new CMSException("Invalid Parameters: "+ex.toString());
252 }
253 }
254
255 // PKCS#7
256
257
258 /**
259 * Creates a PKCS#7 <code>EncryptedDataStream</code> message.
260 * <p>
261 * The supplied content is PBE-encrypted using the specified password.
262 *
263 * @param message the message to be encrypted, as byte representation
264 * @param pbeAlgorithm the PBE algorithm to be used
265 * @param password the password
266 * @return the DER encoding of the <code>EncryptedData</code> object just created
267 * @throws iaik.pkcs.PKCSException if the <code>EncryptedData</code> object cannot
268 * be created
269 * @throws IOException if an I/O error occurs
270 */
271 public byte[] createPKCS7EncryptedDataStream(byte[] message, AlgorithmID pbeAlgorithm, char[] password)
272 throws iaik.pkcs.PKCSException, IOException {
273
274 iaik.pkcs.pkcs7.EncryptedDataStream encrypted_data;
275
276 // we are testing the stream interface
277 ByteArrayInputStream is = new ByteArrayInputStream(message);
278 // create a new EnvelopedData object encrypted with TripleDES CBC
279 try {
280 encrypted_data = new iaik.pkcs.pkcs7.EncryptedDataStream(is, 2048);
281 encrypted_data.setupCipher(pbeAlgorithm, password);
282 } catch (InvalidKeyException ex) {
283 throw new iaik.pkcs.PKCSException("Key error: "+ex.toString());
284 } catch (NoSuchAlgorithmException ex) {
285 throw new iaik.pkcs.PKCSException("Content encryption algorithm not implemented: "+ex.getMessage());
286 }
287
288 // return the EnvelopedDate as DER encoded byte array with block size 2048
289 ByteArrayOutputStream os = new ByteArrayOutputStream();
290 encrypted_data.writeTo(os);
291 return os.toByteArray();
292 }
293
294 /**
295 * Decrypts the PBE-encrypted content of the given PKCS#7 <code>EncryptedData</code> object
296 * using the specified password and returns the decrypted (= original) message.
297 *
298 * @param encoding the <code>EncryptedData</code> object as DER encoded byte array
299 * @param password the password to decrypt the message
300 *
301 * @return the recovered message, as byte array
302 * @throws iaik.pkcs.PKCSException if the message cannot be recovered
303 * @throws IOException if an I/O error occurs
304 */
305 public byte[] getPKCS7EncryptedDataStream(byte[] encoding, char[] password)
306 throws iaik.pkcs.PKCSException, IOException {
307
308 // create the EncryptpedData object from a DER encoded byte array
309 // we are testing the stream interface
310 ByteArrayInputStream is = new ByteArrayInputStream(encoding);
311 iaik.pkcs.pkcs7.EncryptedDataStream encrypted_data = new iaik.pkcs.pkcs7.EncryptedDataStream(is);
312
313 System.out.println("Information about the encrypted data:");
314 iaik.pkcs.pkcs7.EncryptedContentInfoStream eci = (iaik.pkcs.pkcs7.EncryptedContentInfoStream)encrypted_data.getEncryptedContentInfo();
315 System.out.println("Content type: "+eci.getContentType().getName());
316 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
317
318 // decrypt the message
319 try {
320 encrypted_data.setupCipher(password);
321 InputStream decrypted = encrypted_data.getInputStream();
322 ByteArrayOutputStream os = new ByteArrayOutputStream();
323 Util.copyStream(decrypted, os, null);
324
325 return os.toByteArray();
326
327 } catch (InvalidKeyException ex) {
328 throw new iaik.pkcs.PKCSException("Key error: "+ex.toString());
329 } catch (NoSuchAlgorithmException ex) {
330 throw new iaik.pkcs.PKCSException("Content encryption algorithm not implemented: "+ex.getMessage());
331 } catch (InvalidAlgorithmParameterException ex) {
332 throw new iaik.pkcs.PKCSException("Invalid Parameters: "+ex.toString());
333 } catch (InvalidParameterSpecException ex) {
334 throw new iaik.pkcs.PKCSException("Invalid Parameters: "+ex.toString());
335 }
336 }
337
338 /**
339 * Creates a PKCS#7 <code>EncryptedData</code> message.
340 * <p>
341 * The supplied content is PBE-encrypted using the specified password.
342 *
343 * @param message the message to be encrypted, as byte representation
344 * @param pbeAlgorithm the PBE algorithm to be used
345 * @param password the password
346 * @return the DER encoding of the <code>EncryptedData</code> object just created
347 * @throws iaik.pkcs.PKCSException if the <code>EncryptedData</code> object cannot
348 * be created
349 * @throws IOException if an I/O error occurs
350 */
351 public ASN1Object createPKCS7EncryptedData(byte[] message, AlgorithmID pbeAlgorithm, char[] password)
352 throws iaik.pkcs.PKCSException, IOException {
353
354 iaik.pkcs.pkcs7.EncryptedData encrypted_data;
355
356 try {
357 encrypted_data = new iaik.pkcs.pkcs7.EncryptedData(message);
358 // encrypt the message
359 encrypted_data.setupCipher(pbeAlgorithm, password);
360 } catch (InvalidKeyException ex) {
361 throw new iaik.pkcs.PKCSException("Key error: "+ex.toString());
362 } catch (NoSuchAlgorithmException ex) {
363 throw new iaik.pkcs.PKCSException("Content encryption algorithm not implemented: "+ex.getMessage());
364 }
365 return encrypted_data.toASN1Object();
366
367 }
368
369 /**
370 * Decrypts the PBE-encrypted content of the given PKCS#7 <code>EncryptedData</code> object
371 * using the specified password and returns the decrypted (= original) message.
372 *
373 * @param asn1Object the <code>EncryptedData</code> object as ASN1Object
374 * @param password the password to decrypt the message
375 *
376 * @return the recovered message, as byte array
377 * @throws iaik.pkcs.PKCSException if the message cannot be recovered
378 * @throws IOException if an I/O error occurs
379 */
380 public byte[] getPKCS7EncryptedData(ASN1Object asn1Object, char[] password)
381 throws iaik.pkcs.PKCSException, IOException {
382
383 // create an EncryptedData from the ASN1Object
384 iaik.pkcs.pkcs7.EncryptedData encrypted_data = new iaik.pkcs.pkcs7.EncryptedData(asn1Object);
385
386 System.out.println("Information about the encrypted data:");
387 iaik.pkcs.pkcs7.EncryptedContentInfo eci = (iaik.pkcs.pkcs7.EncryptedContentInfo)encrypted_data.getEncryptedContentInfo();
388 System.out.println("Content type: "+eci.getContentType().getName());
389 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
390
391 // decrypt the message
392 try {
393 encrypted_data.setupCipher(password);
394 return encrypted_data.getContent();
395
396 } catch (InvalidKeyException ex) {
397 throw new iaik.pkcs.PKCSException("Key error: "+ex.toString());
398 } catch (NoSuchAlgorithmException ex) {
399 throw new iaik.pkcs.PKCSException("Content encryption algorithm not implemented: "+ex.getMessage());
400 } catch (InvalidAlgorithmParameterException ex) {
401 throw new iaik.pkcs.PKCSException("Invalid Parameters: "+ex.toString());
402 } catch (InvalidParameterSpecException ex) {
403 throw new iaik.pkcs.PKCSException("Invalid Parameters: "+ex.toString());
404 }
405 }
406
407
408 /**
409 * Starts the tests.
410 */
411 public void start() {
412 // the test message
413 String m = "This is the test message.";
414 System.out.println("Test message: \""+m+"\"");
415 System.out.println();
416 byte[] message = m.getBytes();
417
418 try {
419 byte[] data;
420 byte[] received_message = null;
421 System.out.println("Stream implementation demos");
422 System.out.println("===========================");
423
424
425 //
426 // test CMS EncryptedDataStream
427 //
428 System.out.println("\nEncryptedDataStream demo [create]:\n");
429 data = createEncryptedDataStream(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray());
430 // transmit data
431 System.out.println("\nEncryptedDataStream demo [parse]:\n");
432 received_message = getEncryptedDataStream(data, "password".toCharArray());
433 System.out.print("\nContent: ");
434 System.out.println(new String(received_message));
435
436 System.out.println("Testing compatibility to PKCS#7...");
437
438 System.out.println("\nCMS EncryptedDataStream demo [create]:\n");
439 data = createEncryptedDataStream(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray());
440 // transmit data
441 System.out.println("\nPKCS#7 EncryptedDataStream demo [parse]:\n");
442 received_message = getPKCS7EncryptedDataStream(data, "password".toCharArray());
443 System.out.print("\nContent: ");
444 System.out.println(new String(received_message));
445
446 System.out.println("\nPKCS7 EncryptedDataStream demo [create]:\n");
447 data = createPKCS7EncryptedDataStream(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray());
448 // transmit data
449 System.out.println("\nCMS EncryptedDataStream demo [parse]:\n");
450 received_message = getEncryptedDataStream(data, "password".toCharArray());
451 System.out.print("\nContent: ");
452 System.out.println(new String(received_message));
453
454
455 // the non-stream implementation
456 System.out.println("\nNon-stream implementation demos");
457 System.out.println("===============================");
458
459 ASN1Object obj = null;
460
461
462 //
463 // test CMS EncryptedData
464 //
465 System.out.println("\nEncryptedData demo [create]:\n");
466 obj = createEncryptedData(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray());
467 // transmit data
468 System.out.println("\nEncryptedData demo [parse]:\n");
469 received_message = getEncryptedData(obj, "password".toCharArray());
470 System.out.print("\nContent: ");
471 System.out.println(new String(received_message));
472
473 System.out.println("Testing compatibility to PKCS#7...");
474
475 System.out.println("\nCMS EncryptedData demo [create]:\n");
476 obj = createEncryptedData(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray());
477 // transmit data
478 System.out.println("\nPKCS#7 EncryptedData demo [parse]:\n");
479 received_message = getPKCS7EncryptedData(obj, "password".toCharArray());
480 System.out.print("\nContent: ");
481 System.out.println(new String(received_message));
482
483 System.out.println("\nPKCS#7 EncryptedData demo [create]:\n");
484 obj = createPKCS7EncryptedData(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray());
485 // transmit data
486 System.out.println("\nCMS EncryptedData demo [parse]:\n");
487 received_message = getEncryptedData(obj, "password".toCharArray());
488 System.out.print("\nContent: ");
489 System.out.println(new String(received_message));
490
491 } catch (Exception ex) {
492 ex.printStackTrace();
493 throw new RuntimeException(ex.toString());
494 }
495 }
496
497 /**
498 * Tests the IAIK CMS against the IAIK PKCS#7 EncryptedData(Stream) implementation.
499 */
500 public static void main(String argv[]) throws Exception {
501
502 DemoUtil.initDemos();
503
504 (new PKCS7CMSEncryptedDataDemo()).start();
505 System.out.println("\nReady!");
506 DemoUtil.waitKey();
507 }
508 }