001// Copyright (C) 2002 IAIK
002// https://sic.tech/
003//
004// Copyright (C) 2003 - 2025 Stiftung Secure Information and 
005//                           Communication Technologies SIC
006// https://sic.tech/
007//
008// All rights reserved.
009//
010// This source is provided for inspection purposes and recompilation only,
011// unless specified differently in a contract with IAIK. This source has to
012// be kept in strict confidence and must not be disclosed to any third party
013// under any circumstances. Redistribution in source and binary forms, with
014// or without modification, are <not> permitted in any case!
015//
016// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
017// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
018// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
019// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
020// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
021// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
022// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
023// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
024// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
025// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
026// SUCH DAMAGE.
027//
028// $Header: /IAIK-CMS/current/src/demo/cms/pkcs7cms/PKCS7CMSEncryptedDataDemo.java 16    12.02.25 17:58 Dbratko $
029// $Revision: 16 $
030//
031
032package demo.cms.pkcs7cms;
033
034import iaik.asn1.ASN1Object;
035import iaik.asn1.structures.AlgorithmID;
036import iaik.cms.CMSException;
037import iaik.cms.EncryptedContentInfo;
038import iaik.cms.EncryptedContentInfoStream;
039import iaik.cms.EncryptedData;
040import iaik.cms.EncryptedDataStream;
041import iaik.security.random.SecRandom;
042import iaik.utils.Util;
043
044import java.io.ByteArrayInputStream;
045import java.io.ByteArrayOutputStream;
046import java.io.IOException;
047import java.io.InputStream;
048import java.security.InvalidAlgorithmParameterException;
049import java.security.InvalidKeyException;
050import java.security.NoSuchAlgorithmException;
051import java.security.SecureRandom;
052import java.security.spec.InvalidParameterSpecException;
053
054import demo.DemoUtil;
055
056/**
057 * Compares the usage of IAIK CMS with the IAIK PKCS#7 EncryptedData(Stream) implementation.
058 */
059public class PKCS7CMSEncryptedDataDemo {
060
061  // secure random number generator
062  SecureRandom random;
063
064  /**
065   * Default constructor.
066   */
067  public PKCS7CMSEncryptedDataDemo() {
068    
069    System.out.println();
070    System.out.println("***********************************************************************************************");
071    System.out.println("*                                 PKCS7CMSEncryptedDataDemo                                   *");
072    System.out.println("* (tests the CMS EncryptedData against the IAIK-JCE PKCS#7 EncryptedData type implementation) *");
073    System.out.println("***********************************************************************************************");
074    System.out.println();
075    
076    random = SecRandom.getDefault();
077  }
078
079
080  /**
081   * Creates a CMS <code>EncryptedDataStream</code> message.
082   * <p>
083   * The supplied content is PBE-encrypted using the specified password.
084   *
085   * @param message the message to be encrypted, as byte representation
086   * @param pbeAlgorithm the PBE algorithm to be used
087   * @param password the password
088   * @return the DER encoding of the <code>EncryptedData</code> object just created
089   * @throws CMSException if the <code>EncryptedData</code> object cannot
090   *                          be created
091   * @throws IOException if an I/O error occurs
092   */
093  public byte[] createEncryptedDataStream(byte[] message, AlgorithmID pbeAlgorithm, char[] password) throws CMSException, IOException {
094
095    EncryptedDataStream encrypted_data;
096
097    // we are testing the stream interface
098    ByteArrayInputStream is = new ByteArrayInputStream(message);
099    // create a new EnvelopedData object encrypted with TripleDES CBC
100    try {
101      encrypted_data = new EncryptedDataStream(is, 2048);
102      encrypted_data.setupCipher(pbeAlgorithm, password);
103    } catch (InvalidKeyException ex) {
104      throw new CMSException("Key error: "+ex.toString());
105    } catch (NoSuchAlgorithmException ex) {
106      throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
107    }
108
109    // return the EnvelopedDate as DER encoded byte array with block size 2048
110    ByteArrayOutputStream os = new ByteArrayOutputStream();
111    encrypted_data.writeTo(os);
112    return os.toByteArray();
113  }
114
115  /**
116   * Decrypts the PBE-encrypted content of the given CMS <code>EncryptedData</code> object
117   * using the specified password and returns the decrypted (= original) message.
118   *
119   * @param encoding the <code>EncryptedData</code> object as DER encoded byte array
120   * @param password the password to decrypt the message
121   *
122   * @return the recovered message, as byte array
123   * @throws CMSException if the message cannot be recovered
124   * @throws IOException if an I/O error occurs
125   */
126  public byte[] getEncryptedDataStream(byte[] encoding, char[] password) throws CMSException, IOException {
127
128    // create the EncryptpedData object from a DER encoded byte array
129    // we are testing the stream interface
130    ByteArrayInputStream is = new ByteArrayInputStream(encoding);
131    EncryptedDataStream encrypted_data = new EncryptedDataStream(is);
132
133    System.out.println("Information about the encrypted data:");
134    EncryptedContentInfoStream eci = encrypted_data.getEncryptedContentInfo();
135    System.out.println("Content type: "+eci.getContentType().getName());
136    System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
137
138    // decrypt the message
139    try {
140      encrypted_data.setupCipher(password);
141      InputStream decrypted = encrypted_data.getInputStream();
142      ByteArrayOutputStream os = new ByteArrayOutputStream();
143      Util.copyStream(decrypted, os, null);
144
145      return os.toByteArray();
146
147    } catch (InvalidKeyException ex) {
148      throw new CMSException("Key error: "+ex.toString());
149    } catch (NoSuchAlgorithmException ex) {
150      throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
151    } catch (InvalidAlgorithmParameterException ex) {
152      throw new CMSException("Invalid Parameters: "+ex.toString());
153    } catch (InvalidParameterSpecException ex) {
154      throw new CMSException("Invalid Parameters: "+ex.toString());
155    }
156  }
157
158  /**
159   * Creates a CMS <code>EncryptedData</code> message.
160   * <p>
161   * The supplied content is PBE-encrypted using the specified password.
162   *
163   * @param message the message to be encrypted, as byte representation
164   * @param pbeAlgorithm the PBE algorithm to be used
165   * @param password the password
166   * @return the DER encoding of the <code>EncryptedData</code> object just created
167   * @throws CMSException if the <code>EncryptedData</code> object cannot
168   *                          be created
169   * @throws IOException if an I/O error occurs
170   */
171  public ASN1Object createEncryptedData(byte[] message, AlgorithmID pbeAlgorithm, char[] password) throws CMSException, IOException {
172
173    EncryptedData encrypted_data;
174
175    try {
176      encrypted_data = new EncryptedData(message);
177      // encrypt the message
178      encrypted_data.setupCipher(pbeAlgorithm, password);
179    } catch (InvalidKeyException ex) {
180      throw new CMSException("Key error: "+ex.toString());
181    } catch (NoSuchAlgorithmException ex) {
182      throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
183    }
184    return encrypted_data.toASN1Object();
185
186  }
187
188  /**
189   * Decrypts the PBE-encrypted content of the given CMS <code>EncryptedData</code> object
190   * using the specified password and returns the decrypted (= original) message.
191   *
192   * @param asn1Object the <code>EncryptedData</code> object as ASN1Object
193   * @param password the password to decrypt the message
194   *
195   * @return the recovered message, as byte array
196   * @throws CMSException if the message cannot be recovered
197   * @throws IOException if an I/O error occurs
198   */
199  public byte[] getEncryptedData(ASN1Object asn1Object, char[] password) throws CMSException, IOException {
200
201    // create an EncryptedData from the ASN1Object
202    EncryptedData encrypted_data = new EncryptedData(asn1Object);
203
204    System.out.println("Information about the encrypted data:");
205    EncryptedContentInfo eci = (EncryptedContentInfo)encrypted_data.getEncryptedContentInfo();
206    System.out.println("Content type: "+eci.getContentType().getName());
207    System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
208
209    // decrypt the message
210    try {
211      encrypted_data.setupCipher(password);
212      return encrypted_data.getContent();
213
214    } catch (InvalidKeyException ex) {
215      throw new CMSException("Key error: "+ex.toString());
216    } catch (NoSuchAlgorithmException ex) {
217      throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
218    } catch (InvalidAlgorithmParameterException ex) {
219      throw new CMSException("Invalid Parameters: "+ex.toString());
220    } catch (InvalidParameterSpecException ex) {
221      throw new CMSException("Invalid Parameters: "+ex.toString());
222    }
223  }
224  
225  // PKCS#7
226  
227  
228  /**
229   * Creates a PKCS#7 <code>EncryptedDataStream</code> message.
230   * <p>
231   * The supplied content is PBE-encrypted using the specified password.
232   *
233   * @param message the message to be encrypted, as byte representation
234   * @param pbeAlgorithm the PBE algorithm to be used
235   * @param password the password
236   * @return the DER encoding of the <code>EncryptedData</code> object just created
237   * @throws iaik.pkcs.PKCSException if the <code>EncryptedData</code> object cannot
238   *                          be created
239   * @throws IOException if an I/O error occurs
240   */
241  public byte[] createPKCS7EncryptedDataStream(byte[] message, AlgorithmID pbeAlgorithm, char[] password) 
242    throws iaik.pkcs.PKCSException, IOException {
243
244    iaik.pkcs.pkcs7.EncryptedDataStream encrypted_data;
245
246    // we are testing the stream interface
247    ByteArrayInputStream is = new ByteArrayInputStream(message);
248    // create a new EnvelopedData object encrypted with TripleDES CBC
249    try {
250      encrypted_data = new iaik.pkcs.pkcs7.EncryptedDataStream(is, 2048);
251      encrypted_data.setupCipher(pbeAlgorithm, password);
252    } catch (InvalidKeyException ex) {
253      throw new iaik.pkcs.PKCSException("Key error: "+ex.toString());
254    } catch (NoSuchAlgorithmException ex) {
255      throw new iaik.pkcs.PKCSException("Content encryption algorithm not implemented: "+ex.getMessage());
256    }
257
258    // return the EnvelopedDate as DER encoded byte array with block size 2048
259    ByteArrayOutputStream os = new ByteArrayOutputStream();
260    encrypted_data.writeTo(os);
261    return os.toByteArray();
262  }
263
264  /**
265   * Decrypts the PBE-encrypted content of the given PKCS#7 <code>EncryptedData</code> object
266   * using the specified password and returns the decrypted (= original) message.
267   *
268   * @param encoding the <code>EncryptedData</code> object as DER encoded byte array
269   * @param password the password to decrypt the message
270   *
271   * @return the recovered message, as byte array
272   * @throws iaik.pkcs.PKCSException if the message cannot be recovered
273   * @throws IOException if an I/O error occurs
274   */
275  public byte[] getPKCS7EncryptedDataStream(byte[] encoding, char[] password) 
276    throws iaik.pkcs.PKCSException, IOException {
277
278    // create the EncryptpedData object from a DER encoded byte array
279    // we are testing the stream interface
280    ByteArrayInputStream is = new ByteArrayInputStream(encoding);
281    iaik.pkcs.pkcs7.EncryptedDataStream encrypted_data = new iaik.pkcs.pkcs7.EncryptedDataStream(is);
282
283    System.out.println("Information about the encrypted data:");
284    iaik.pkcs.pkcs7.EncryptedContentInfoStream eci = (iaik.pkcs.pkcs7.EncryptedContentInfoStream)encrypted_data.getEncryptedContentInfo();
285    System.out.println("Content type: "+eci.getContentType().getName());
286    System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
287
288    // decrypt the message
289    try {
290      encrypted_data.setupCipher(password);
291      InputStream decrypted = encrypted_data.getInputStream();
292      ByteArrayOutputStream os = new ByteArrayOutputStream();
293      Util.copyStream(decrypted, os, null);
294
295      return os.toByteArray();
296
297    } catch (InvalidKeyException ex) {
298      throw new iaik.pkcs.PKCSException("Key error: "+ex.toString());
299    } catch (NoSuchAlgorithmException ex) {
300      throw new iaik.pkcs.PKCSException("Content encryption algorithm not implemented: "+ex.getMessage());
301    } catch (InvalidAlgorithmParameterException ex) {
302      throw new iaik.pkcs.PKCSException("Invalid Parameters: "+ex.toString());
303    } catch (InvalidParameterSpecException ex) {
304      throw new iaik.pkcs.PKCSException("Invalid Parameters: "+ex.toString());
305    }
306  }
307
308  /**
309   * Creates a PKCS#7 <code>EncryptedData</code> message.
310   * <p>
311   * The supplied content is PBE-encrypted using the specified password.
312   *
313   * @param message the message to be encrypted, as byte representation
314   * @param pbeAlgorithm the PBE algorithm to be used
315   * @param password the password
316   * @return the DER encoding of the <code>EncryptedData</code> object just created
317   * @throws iaik.pkcs.PKCSException if the <code>EncryptedData</code> object cannot
318   *                          be created
319   * @throws IOException if an I/O error occurs
320   */
321  public ASN1Object createPKCS7EncryptedData(byte[] message, AlgorithmID pbeAlgorithm, char[] password) 
322    throws iaik.pkcs.PKCSException, IOException {
323
324    iaik.pkcs.pkcs7.EncryptedData encrypted_data;
325
326    try {
327      encrypted_data = new iaik.pkcs.pkcs7.EncryptedData(message);
328      // encrypt the message
329      encrypted_data.setupCipher(pbeAlgorithm, password);
330    } catch (InvalidKeyException ex) {
331      throw new iaik.pkcs.PKCSException("Key error: "+ex.toString());
332    } catch (NoSuchAlgorithmException ex) {
333      throw new iaik.pkcs.PKCSException("Content encryption algorithm not implemented: "+ex.getMessage());
334    }
335    return encrypted_data.toASN1Object();
336
337  }
338
339  /**
340   * Decrypts the PBE-encrypted content of the given PKCS#7 <code>EncryptedData</code> object
341   * using the specified password and returns the decrypted (= original) message.
342   *
343   * @param asn1Object the <code>EncryptedData</code> object as ASN1Object
344   * @param password the password to decrypt the message
345   *
346   * @return the recovered message, as byte array
347   * @throws iaik.pkcs.PKCSException if the message cannot be recovered
348   * @throws IOException if an I/O error occurs
349   */
350  public byte[] getPKCS7EncryptedData(ASN1Object asn1Object, char[] password) 
351    throws iaik.pkcs.PKCSException, IOException {
352
353    // create an EncryptedData from the ASN1Object
354    iaik.pkcs.pkcs7.EncryptedData encrypted_data = new iaik.pkcs.pkcs7.EncryptedData(asn1Object);
355
356    System.out.println("Information about the encrypted data:");
357    iaik.pkcs.pkcs7.EncryptedContentInfo eci = (iaik.pkcs.pkcs7.EncryptedContentInfo)encrypted_data.getEncryptedContentInfo();
358    System.out.println("Content type: "+eci.getContentType().getName());
359    System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
360
361    // decrypt the message
362    try {
363      encrypted_data.setupCipher(password);
364      return encrypted_data.getContent();
365
366    } catch (InvalidKeyException ex) {
367      throw new iaik.pkcs.PKCSException("Key error: "+ex.toString());
368    } catch (NoSuchAlgorithmException ex) {
369      throw new iaik.pkcs.PKCSException("Content encryption algorithm not implemented: "+ex.getMessage());
370    } catch (InvalidAlgorithmParameterException ex) {
371      throw new iaik.pkcs.PKCSException("Invalid Parameters: "+ex.toString());
372    } catch (InvalidParameterSpecException ex) {
373      throw new iaik.pkcs.PKCSException("Invalid Parameters: "+ex.toString()); 
374    }
375  }
376
377
378  /**
379   * Starts the tests.
380   */
381  public void start() {
382     // the test message
383    String m = "This is the test message.";
384    System.out.println("Test message: \""+m+"\"");
385    System.out.println();
386    byte[] message = m.getBytes();
387
388    try {
389      byte[] data;
390      byte[] received_message = null;
391      System.out.println("Stream implementation demos");
392      System.out.println("===========================");
393
394
395      //
396      // test CMS EncryptedDataStream
397      //
398      System.out.println("\nEncryptedDataStream demo [create]:\n");
399      data = createEncryptedDataStream(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray());
400      // transmit data
401      System.out.println("\nEncryptedDataStream demo [parse]:\n");
402      received_message = getEncryptedDataStream(data, "password".toCharArray());
403      System.out.print("\nContent: ");
404      System.out.println(new String(received_message));
405
406      System.out.println("Testing compatibility to PKCS#7...");
407      
408      System.out.println("\nCMS EncryptedDataStream demo [create]:\n");
409      data = createEncryptedDataStream(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray());
410      // transmit data
411      System.out.println("\nPKCS#7 EncryptedDataStream demo [parse]:\n");
412      received_message = getPKCS7EncryptedDataStream(data, "password".toCharArray());
413      System.out.print("\nContent: ");
414      System.out.println(new String(received_message));
415      
416      System.out.println("\nPKCS7 EncryptedDataStream demo [create]:\n");
417      data = createPKCS7EncryptedDataStream(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray());
418      // transmit data
419      System.out.println("\nCMS EncryptedDataStream demo [parse]:\n");
420      received_message = getEncryptedDataStream(data, "password".toCharArray());
421      System.out.print("\nContent: ");
422      System.out.println(new String(received_message));
423
424
425      // the non-stream implementation
426      System.out.println("\nNon-stream implementation demos");
427      System.out.println("===============================");
428
429      ASN1Object obj = null;
430
431
432      //
433      // test CMS EncryptedData
434      //
435      System.out.println("\nEncryptedData demo [create]:\n");
436      obj = createEncryptedData(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray());
437      // transmit data
438      System.out.println("\nEncryptedData demo [parse]:\n");
439      received_message = getEncryptedData(obj, "password".toCharArray());
440      System.out.print("\nContent: ");
441      System.out.println(new String(received_message));
442      
443      System.out.println("Testing compatibility to PKCS#7...");
444      
445      System.out.println("\nCMS EncryptedData demo [create]:\n");
446      obj = createEncryptedData(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray());
447      // transmit data
448      System.out.println("\nPKCS#7 EncryptedData demo [parse]:\n");
449      received_message = getPKCS7EncryptedData(obj, "password".toCharArray());
450      System.out.print("\nContent: ");
451      System.out.println(new String(received_message));
452      
453      System.out.println("\nPKCS#7 EncryptedData demo [create]:\n");
454      obj = createPKCS7EncryptedData(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray());
455      // transmit data
456      System.out.println("\nCMS EncryptedData demo [parse]:\n");
457      received_message = getEncryptedData(obj, "password".toCharArray());
458      System.out.print("\nContent: ");
459      System.out.println(new String(received_message));
460
461        } catch (Exception ex) {
462          ex.printStackTrace();
463          throw new RuntimeException(ex.toString());
464        }
465  }
466
467  /**
468   * Tests the IAIK CMS against the IAIK PKCS#7 EncryptedData(Stream) implementation.
469   */
470  public static void main(String argv[]) throws Exception {
471
472    DemoUtil.initDemos();
473
474    (new PKCS7CMSEncryptedDataDemo()).start();
475    System.out.println("\nReady!");
476    DemoUtil.waitKey();
477  }
478}