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 }