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/PKCS7CMSDigestedDataDemo.java 18    12.02.25 17:58 Dbratko $
029// $Revision: 18 $
030//
031
032package demo.cms.pkcs7cms;
033
034import iaik.asn1.ASN1Object;
035import iaik.asn1.structures.AlgorithmID;
036import iaik.cms.CMSException;
037import iaik.cms.DigestedData;
038import iaik.cms.DigestedDataStream;
039import iaik.security.random.SecRandom;
040import iaik.utils.Util;
041
042import java.io.ByteArrayInputStream;
043import java.io.ByteArrayOutputStream;
044import java.io.IOException;
045import java.io.InputStream;
046import java.security.NoSuchAlgorithmException;
047import java.security.SecureRandom;
048
049import demo.DemoUtil;
050
051/**
052 * Compares the usage of IAIK CMS DigestedData(Stream) with IAIK PKSC#7 DigestedData(Stream).
053 */
054public class PKCS7CMSDigestedDataDemo {
055
056  // secure random number generator
057  SecureRandom random;
058
059  /**
060   * Default constructor.
061   */
062  public PKCS7CMSDigestedDataDemo() throws IOException {
063    
064    System.out.println();
065    System.out.println("***********************************************************************************************");
066    System.out.println("*                                 PKCS7CMSDigestedDataDemo                                    *");
067    System.out.println("* (tests the CMS DigestedData against the IAIK-JCE PKCS#7 DigestedData type implementation)   *");
068    System.out.println("***********************************************************************************************");
069    System.out.println();
070
071    random = SecRandom.getDefault();
072  }
073
074
075  /**
076   * Creates a CMS <code>DigestedData</code> object.
077   * <p>
078   * @param message the message to be digested, as byte representation
079   * @param mode IMPLICIT (include message) or EXPLICIT (do not include message)
080   * @return the DER encoding of the <code>DigestedData</code> object just created
081   * @throws CMSException if the <code>DigestedData</code> object cannot
082   *                          be created
083   * @throws IOException if an I/O error occurs
084   */
085  public byte[] createDigestedDataStream(byte[] message, int mode) throws CMSException, IOException  {
086
087    System.out.println("Create a new message to be digested:");
088
089    // we are testing the stream interface
090    ByteArrayInputStream is = new ByteArrayInputStream(message);
091
092    // create a new DigestedData object which includes the data
093    DigestedDataStream digested_data = null;
094
095    digested_data = new DigestedDataStream(is, (AlgorithmID)AlgorithmID.sha256.clone(), mode);
096
097
098    // write the data through DigestedData to any out-of-band place
099    if (mode == DigestedDataStream.EXPLICIT) {
100      InputStream data_is = digested_data.getInputStream();
101      byte[] buf = new byte[1024];
102      int r;
103      while ((r = data_is.read(buf)) > 0) {
104        ;   // skip data
105      }  
106    }
107
108    // return the DigestedData as DER encoded byte array with block size 2048
109    ByteArrayOutputStream os = new ByteArrayOutputStream();
110    digested_data.writeTo(os, 2048);
111    return os.toByteArray();
112  }
113
114
115
116  /**
117   * Parses a CMS <code>DigestedData</code> object and verifies the hash.
118   *
119   * @param digestedData <code>DigestedData</code> object as DER encoded byte array
120   * @param message the the message which was transmitted out-of-band
121   *
122   * @return the inherent message as byte array
123   * @throws CMSException if any signature does not verify
124   * @throws IOException if an I/O error occurs
125   */
126  public byte[] getDigestedDataStream(byte[] digestedData, byte[] message) throws CMSException, IOException {
127
128    // we are testing the stream interface
129    ByteArrayInputStream is = new ByteArrayInputStream(digestedData);
130    // create the DigestedData object
131    DigestedDataStream digested_data = null;
132    if (message == null) {
133      // implicitly; read the DER encoded object
134      digested_data = new DigestedDataStream(is);
135    }
136    else {
137      // explicitly; set the data stream for digesting the message
138      digested_data = new DigestedDataStream(new ByteArrayInputStream(message), 
139                                             (AlgorithmID)AlgorithmID.sha256.clone());
140    }
141
142    // get an InputStream for reading the signed content
143    InputStream data = digested_data.getInputStream();
144    ByteArrayOutputStream os = new ByteArrayOutputStream();
145    Util.copyStream(data, os, null);
146
147    if (message != null) {
148
149      digested_data.decode(is);
150    }
151
152    if (digested_data.verify()) {
153       System.out.println("Hash ok!");
154    } else {
155       System.out.println("Hash verification failed!");
156    }
157
158    return os.toByteArray();
159  }
160
161
162  /**
163   * Creates a CMS <code>DigestedData</code> object.
164   * <p>
165   *
166   * @param message the message to be digested, as byte representation
167   * @param mode IMPLICIT (include message) or EXPLICIT (do not include message)
168   * @return the <code>DigestedData</code> as ASN.1 object
169   * @throws CMSException if the <code>DigestedData</code> object cannot
170   *                          be created
171   * @throws IOException if an I/O error occurs
172   */
173  public ASN1Object createDigestedData(byte[] message, int mode) throws CMSException, IOException  {
174
175    System.out.println("Create a new digested message:");
176
177    // create a new DigestedData object which includes the data
178    DigestedData digested_data = new DigestedData(message, (AlgorithmID)AlgorithmID.sha256.clone(), mode);
179
180    return digested_data.toASN1Object();
181  }
182
183  /**
184   * Parses a CMS <code>DigestedData</code> object and verifies the hash value.
185   *
186   * @param obj <code>DigestedData</code> object in ASN.1 representation
187   * @param message the the message which was transmitted out-of-band (explicit digested)
188   *
189   * @return the message
190   * @throws CMSException if some parsing exception occurs
191   * @throws IOException if an I/O error occurs
192   */
193  public byte[] getDigestedData(ASN1Object obj, byte[] message) throws CMSException, IOException {
194
195    // create the DigestedData object
196    DigestedData digested_data = null;
197    if (message == null) {
198      // implicitly digested; read the ASN.1 object
199      digested_data = new DigestedData(obj);
200    }
201    else {
202      // explicitly digested; set the data for digesting the message
203      try {
204         digested_data = new DigestedData(message, (AlgorithmID)AlgorithmID.sha256.clone());
205         // if explicitly digested now the DER encoded object
206         digested_data.decode(obj);
207
208      } catch (NoSuchAlgorithmException ex) {
209         throw new CMSException(ex.toString());
210      }
211    }
212
213    // now verify the digest
214    if (digested_data.verify()) {
215       System.out.println("Hash ok!");
216    } else {
217       System.out.println("Hash verification failed!");
218    }
219
220    return digested_data.getContent();
221  }
222  
223  //  PKCS#7
224  
225  /**
226   * Creates a PKCS#7 <code>DigestedData</code> object.
227   * <p>
228   * @param message the message to be digested, as byte representation
229   * @param mode IMPLICIT (include message) or EXPLICIT (do not include message)
230   * @return the DER encoding of the <code>DigestedData</code> object just created
231   * @throws iaik.pkcs.PKCSException if the <code>DigestedData</code> object cannot
232   *                          be created
233   * @throws IOException if an I/O error occurs
234   */
235  public byte[] createPKCS7DigestedDataStream(byte[] message, int mode) 
236    throws iaik.pkcs.PKCSException, IOException  {
237
238    System.out.println("Create a new message to be digested:");
239
240    // we are testing the stream interface
241    ByteArrayInputStream is = new ByteArrayInputStream(message);
242
243    // create a new DigestedData object which includes the data
244    iaik.pkcs.pkcs7.DigestedDataStream digested_data = null;
245
246    digested_data = new iaik.pkcs.pkcs7.DigestedDataStream(is, (AlgorithmID)AlgorithmID.sha256.clone(), mode);
247
248
249    // write the data through DigestedData to any out-of-band place
250    if (mode == iaik.pkcs.pkcs7.DigestedDataStream.EXPLICIT) {
251      InputStream data_is = digested_data.getInputStream();
252      byte[] buf = new byte[1024];
253      int r;
254      while ((r = data_is.read(buf)) > 0) {
255        ;   // skip data
256      }  
257    }
258
259    // return the DigestedData as DER encoded byte array with block size 2048
260    ByteArrayOutputStream os = new ByteArrayOutputStream();
261    digested_data.writeTo(os, 2048);
262    return os.toByteArray();
263  }
264
265
266
267  /**
268   * Parses a PKCS#7 <code>DigestedData</code> object and verifies the hash.
269   *
270   * @param digestedData <code>DigestedData</code> object as DER encoded byte array
271   * @param message the the message which was transmitted out-of-band
272   *
273   * @return the inherent message as byte array
274   * @throws iaik.pkcs.PKCSException if any signature does not verify
275   * @throws IOException if an I/O error occurs
276   */
277  public byte[] getPKCS7DigestedDataStream(byte[] digestedData, byte[] message) 
278    throws iaik.pkcs.PKCSException, IOException {
279
280    // we are testing the stream interface
281    ByteArrayInputStream is = new ByteArrayInputStream(digestedData);
282    // create the DigestedData object
283    iaik.pkcs.pkcs7.DigestedDataStream digested_data = null;
284    if (message == null) {
285      // implicitly; read the DER encoded object
286      digested_data = new iaik.pkcs.pkcs7.DigestedDataStream(is);
287    }
288    else {
289      // explicitly; set the data stream for digesting the message
290      digested_data = new iaik.pkcs.pkcs7.DigestedDataStream(new ByteArrayInputStream(message),
291                                                             (AlgorithmID)AlgorithmID.sha256.clone());
292    }
293
294    // get an InputStream for reading the signed content
295    InputStream data = digested_data.getInputStream();
296    ByteArrayOutputStream os = new ByteArrayOutputStream();
297    Util.copyStream(data, os, null);
298
299    if (message != null) {
300
301      digested_data.decode(is);
302    }
303
304    if (digested_data.verify()) {
305       System.out.println("Hash ok!");
306    } else {
307       System.out.println("Hash verification failed!");
308    }
309
310    return os.toByteArray();
311  }
312
313
314  /**
315   * Creates a PKCS#7 <code>DigestedData</code> object.
316   * <p>
317   *
318   * @param message the message to be digested, as byte representation
319   * @param mode IMPLICIT (include message) or EXPLICIT (do not include message)
320   * @return the <code>DigestedData</code> as ASN.1 object
321   * @throws iaik.pkcs.PKCSException if the <code>DigestedData</code> object cannot
322   *                          be created
323   * @throws IOException if an I/O error occurs
324   */
325  public ASN1Object createPKCS7DigestedData(byte[] message, int mode) 
326    throws iaik.pkcs.PKCSException, IOException  {
327
328    System.out.println("Create a new digested message:");
329
330    // create a new DigestedData object which includes the data
331    iaik.pkcs.pkcs7.DigestedData digested_data = new iaik.pkcs.pkcs7.DigestedData(message, 
332                                                                                  (AlgorithmID)AlgorithmID.sha256.clone(),
333                                                                                  mode);
334
335    return digested_data.toASN1Object();
336  }
337
338  /**
339   * Parses a PKCS#7 <code>DigestedData</code> object and verifies the hash value.
340   *
341   * @param obj <code>DigestedData</code> object in ASN.1 representation
342   * @param message the the message which was transmitted out-of-band (explicit digested)
343   *
344   * @return the message
345   * @throws iaik.pkcs.PKCSException if some parsing exception occurs
346   * @throws IOException if an I/O error occurs
347   */
348  public byte[] getPKCS7DigestedData(ASN1Object obj, byte[] message) 
349    throws iaik.pkcs.PKCSException, IOException {
350
351    // create the DigestedData object
352    iaik.pkcs.pkcs7.DigestedData digested_data = null;
353    if (message == null) {
354      // implicitly digested; read the ASN.1 object
355      digested_data = new iaik.pkcs.pkcs7.DigestedData(obj);
356    }
357    else {
358      // explicitly digested; set the data for digesting the message
359      try {
360         digested_data = new iaik.pkcs.pkcs7.DigestedData(message, (AlgorithmID)AlgorithmID.sha256.clone());
361         // if explicitly digested now the DER encoded object
362         digested_data.decode(obj);
363
364      } catch (NoSuchAlgorithmException ex) {
365         throw new iaik.pkcs.PKCSException(ex.toString());
366      }
367    }
368
369    // now verify the digest
370    if (digested_data.verify()) {
371       System.out.println("Hash ok!");
372    } else {
373       System.out.println("Hash verification failed!");
374    }
375
376    return digested_data.getContent();
377  }
378
379
380
381
382  /**
383   * Starts the tests.
384   */
385  public void start() {
386     // the test message
387    String m = "This is the test message.";
388    System.out.println("Test message: \""+m+"\"");
389    System.out.println();
390    byte[] message = m.getBytes();
391
392    try {
393      byte[] data;
394      byte[] received_message = null;
395      System.out.println("Stream implementation demos");
396      System.out.println("===========================");
397
398      // the stream implementation
399   
400      //
401      // test CMS Implicit DigestedDataStream
402      //
403      System.out.println("\nImplicit DigestedDataStream demo [create]:\n");
404      data = createDigestedDataStream(message, DigestedDataStream.IMPLICIT);
405      // transmit data
406      System.out.println("\nImplicit DigestedDataStream demo [parse]:\n");
407      received_message = getDigestedDataStream(data, null);
408      System.out.print("\nContent: ");
409      System.out.println(new String(received_message));
410
411      //
412      // test CMS Explicit DigestedDataStream
413      //
414      System.out.println("\nExplicit DigestedDataStream demo [create]:\n");
415      data = createDigestedDataStream(message, DigestedDataStream.EXPLICIT);
416      // transmit data
417      System.out.println("\nExplicit DigestedDataStream demo [parse]:\n");
418      received_message = getDigestedDataStream(data, message);
419      System.out.print("\nContent: ");
420      System.out.println(new String(received_message));
421      
422      System.out.println("Testing compatiblity to PKCS#7...");
423      
424      System.out.println("\nCMS Implicit DigestedDataStream demo [create]:\n");
425      data = createDigestedDataStream(message, DigestedDataStream.IMPLICIT);
426      // transmit data
427      System.out.println("\nPKCS#7 Implicit DigestedDataStream demo [parse]:\n");
428      received_message = getPKCS7DigestedDataStream(data, null);
429      System.out.print("\nContent: ");
430      System.out.println(new String(received_message));
431      
432      System.out.println("\nPKCS#7 Implicit DigestedDataStream demo [create]:\n");
433      data = createPKCS7DigestedDataStream(message, DigestedDataStream.IMPLICIT);
434      // transmit data
435      System.out.println("\nCMS Implicit DigestedDataStream demo [parse]:\n");
436      received_message = getDigestedDataStream(data, null);
437      System.out.print("\nContent: ");
438      System.out.println(new String(received_message));
439
440      //
441      // test CMS Explicit DigestedDataStream
442      //
443      System.out.println("\nCMS Explicit DigestedDataStream demo [create]:\n");
444      data = createDigestedDataStream(message, DigestedDataStream.EXPLICIT);
445      // transmit data
446      System.out.println("\nPKCS#7 Explicit DigestedDataStream demo [parse]:\n");
447      received_message = getPKCS7DigestedDataStream(data, message);
448      System.out.print("\nContent: ");
449      System.out.println(new String(received_message));
450      
451      System.out.println("\nPKCS#7 Explicit DigestedDataStream demo [create]:\n");
452      data = createPKCS7DigestedDataStream(message, DigestedDataStream.EXPLICIT);
453      // transmit data
454      System.out.println("\nCMS Explicit DigestedDataStream demo [parse]:\n");
455      received_message = getDigestedDataStream(data, message);
456      System.out.print("\nContent: ");
457      System.out.println(new String(received_message));
458
459
460   
461      // the non-stream implementation
462      System.out.println("\nNon-stream implementation demos");
463      System.out.println("===============================");
464
465      ASN1Object obj = null;
466
467      //
468      // test CMS Implicit DigestedData
469      //
470      System.out.println("\nImplicit DigestedData demo [create]:\n");
471      obj = createDigestedData(message, DigestedData.IMPLICIT);
472      // transmit data
473      System.out.println("\nImplicit DigestedData demo [parse]:\n");
474      received_message = getDigestedData(obj, null);
475      System.out.print("\nContent: ");
476      System.out.println(new String(received_message));
477
478      //
479      // test CMS Explicit DigestedData
480      //
481      System.out.println("\nExplicit DigestedData demo [create]:\n");
482      obj = createDigestedData(message, DigestedData.EXPLICIT);
483      // transmit data
484      System.out.println("\nExplicit DigestedData demo [parse]:\n");
485      received_message = getDigestedData(obj, message);
486      System.out.print("\nContent: ");
487      System.out.println(new String(received_message));
488      
489      /// CMS <---> PKCS#7
490      System.out.println("Testing compatibility to PKCS#7...");
491      
492      //
493      // test PKCS#7 Implicit DigestedData
494      //
495      System.out.println("\nCMS Implicit DigestedData demo [create]:\n");
496      obj = createDigestedData(message, DigestedData.IMPLICIT);
497      // transmit data
498      System.out.println("\nPKCS#7 Implicit DigestedData demo [parse]:\n");
499      received_message = getPKCS7DigestedData(obj, null);
500      System.out.print("\nContent: ");
501      System.out.println(new String(received_message));
502      
503      System.out.println("\nPKCS#7 Implicit DigestedData demo [create]:\n");
504      obj = createPKCS7DigestedData(message, DigestedData.IMPLICIT);
505      // transmit data
506      System.out.println("\nCMS Implicit DigestedData demo [parse]:\n");
507      received_message = getDigestedData(obj, null);
508      System.out.print("\nContent: ");
509      System.out.println(new String(received_message));
510
511
512      //
513      // test PKCS#7 Explicit DigestedData
514      //
515      System.out.println("\nCMS Explicit DigestedData demo [create]:\n");
516      obj = createDigestedData(message, DigestedData.EXPLICIT);
517      // transmit data
518      System.out.println("\nPKCS#7 Explicit DigestedData demo [parse]:\n");
519      received_message = getPKCS7DigestedData(obj, message);
520      System.out.print("\nContent: ");
521      System.out.println(new String(received_message));
522      
523      System.out.println("\nPKCS7 Explicit DigestedData demo [create]:\n");
524      obj = createPKCS7DigestedData(message, DigestedData.EXPLICIT);
525      // transmit data
526      System.out.println("\nCMS Explicit DigestedData demo [parse]:\n");
527      received_message = getDigestedData(obj, message);
528      System.out.print("\nContent: ");
529      System.out.println(new String(received_message));
530 
531        } catch (Exception ex) {
532          ex.printStackTrace();
533          throw new RuntimeException(ex.toString());
534        }
535  }
536
537  /**
538   * Tests the IAIK CMS DigestedData(Stream) implementation against
539   * the PKCS#7 DigestedData(Stream) implementation
540   */
541  public static void main(String argv[]) throws Exception {
542
543        DemoUtil.initDemos();
544
545    (new PKCS7CMSDigestedDataDemo()).start();
546    System.out.println("\nReady!");
547    DemoUtil.waitKey();
548  }
549}