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}