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