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/PKCS7CMSEncryptedDataDemo.java 16 12.02.25 17:58 Dbratko $ 059 // $Revision: 16 $ 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.EncryptedContentInfo; 068 import iaik.cms.EncryptedContentInfoStream; 069 import iaik.cms.EncryptedData; 070 import iaik.cms.EncryptedDataStream; 071 import iaik.security.random.SecRandom; 072 import iaik.utils.Util; 073 074 import java.io.ByteArrayInputStream; 075 import java.io.ByteArrayOutputStream; 076 import java.io.IOException; 077 import java.io.InputStream; 078 import java.security.InvalidAlgorithmParameterException; 079 import java.security.InvalidKeyException; 080 import java.security.NoSuchAlgorithmException; 081 import java.security.SecureRandom; 082 import java.security.spec.InvalidParameterSpecException; 083 084 import demo.DemoUtil; 085 086 /** 087 * Compares the usage of IAIK CMS with the IAIK PKCS#7 EncryptedData(Stream) implementation. 088 */ 089 public class PKCS7CMSEncryptedDataDemo { 090 091 // secure random number generator 092 SecureRandom random; 093 094 /** 095 * Default constructor. 096 */ 097 public PKCS7CMSEncryptedDataDemo() { 098 099 System.out.println(); 100 System.out.println("***********************************************************************************************"); 101 System.out.println("* PKCS7CMSEncryptedDataDemo *"); 102 System.out.println("* (tests the CMS EncryptedData against the IAIK-JCE PKCS#7 EncryptedData type implementation) *"); 103 System.out.println("***********************************************************************************************"); 104 System.out.println(); 105 106 random = SecRandom.getDefault(); 107 } 108 109 110 /** 111 * Creates a CMS <code>EncryptedDataStream</code> message. 112 * <p> 113 * The supplied content is PBE-encrypted using the specified password. 114 * 115 * @param message the message to be encrypted, as byte representation 116 * @param pbeAlgorithm the PBE algorithm to be used 117 * @param password the password 118 * @return the DER encoding of the <code>EncryptedData</code> object just created 119 * @throws CMSException if the <code>EncryptedData</code> object cannot 120 * be created 121 * @throws IOException if an I/O error occurs 122 */ 123 public byte[] createEncryptedDataStream(byte[] message, AlgorithmID pbeAlgorithm, char[] password) throws CMSException, IOException { 124 125 EncryptedDataStream encrypted_data; 126 127 // we are testing the stream interface 128 ByteArrayInputStream is = new ByteArrayInputStream(message); 129 // create a new EnvelopedData object encrypted with TripleDES CBC 130 try { 131 encrypted_data = new EncryptedDataStream(is, 2048); 132 encrypted_data.setupCipher(pbeAlgorithm, password); 133 } catch (InvalidKeyException ex) { 134 throw new CMSException("Key error: "+ex.toString()); 135 } catch (NoSuchAlgorithmException ex) { 136 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage()); 137 } 138 139 // return the EnvelopedDate as DER encoded byte array with block size 2048 140 ByteArrayOutputStream os = new ByteArrayOutputStream(); 141 encrypted_data.writeTo(os); 142 return os.toByteArray(); 143 } 144 145 /** 146 * Decrypts the PBE-encrypted content of the given CMS <code>EncryptedData</code> object 147 * using the specified password and returns the decrypted (= original) message. 148 * 149 * @param encoding the <code>EncryptedData</code> object as DER encoded byte array 150 * @param password the password to decrypt the message 151 * 152 * @return the recovered message, as byte array 153 * @throws CMSException if the message cannot be recovered 154 * @throws IOException if an I/O error occurs 155 */ 156 public byte[] getEncryptedDataStream(byte[] encoding, char[] password) throws CMSException, IOException { 157 158 // create the EncryptpedData object from a DER encoded byte array 159 // we are testing the stream interface 160 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 161 EncryptedDataStream encrypted_data = new EncryptedDataStream(is); 162 163 System.out.println("Information about the encrypted data:"); 164 EncryptedContentInfoStream eci = encrypted_data.getEncryptedContentInfo(); 165 System.out.println("Content type: "+eci.getContentType().getName()); 166 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 167 168 // decrypt the message 169 try { 170 encrypted_data.setupCipher(password); 171 InputStream decrypted = encrypted_data.getInputStream(); 172 ByteArrayOutputStream os = new ByteArrayOutputStream(); 173 Util.copyStream(decrypted, os, null); 174 175 return os.toByteArray(); 176 177 } catch (InvalidKeyException ex) { 178 throw new CMSException("Key error: "+ex.toString()); 179 } catch (NoSuchAlgorithmException ex) { 180 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage()); 181 } catch (InvalidAlgorithmParameterException ex) { 182 throw new CMSException("Invalid Parameters: "+ex.toString()); 183 } catch (InvalidParameterSpecException ex) { 184 throw new CMSException("Invalid Parameters: "+ex.toString()); 185 } 186 } 187 188 /** 189 * Creates a CMS <code>EncryptedData</code> message. 190 * <p> 191 * The supplied content is PBE-encrypted using the specified password. 192 * 193 * @param message the message to be encrypted, as byte representation 194 * @param pbeAlgorithm the PBE algorithm to be used 195 * @param password the password 196 * @return the DER encoding of the <code>EncryptedData</code> object just created 197 * @throws CMSException if the <code>EncryptedData</code> object cannot 198 * be created 199 * @throws IOException if an I/O error occurs 200 */ 201 public ASN1Object createEncryptedData(byte[] message, AlgorithmID pbeAlgorithm, char[] password) throws CMSException, IOException { 202 203 EncryptedData encrypted_data; 204 205 try { 206 encrypted_data = new EncryptedData(message); 207 // encrypt the message 208 encrypted_data.setupCipher(pbeAlgorithm, password); 209 } catch (InvalidKeyException ex) { 210 throw new CMSException("Key error: "+ex.toString()); 211 } catch (NoSuchAlgorithmException ex) { 212 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage()); 213 } 214 return encrypted_data.toASN1Object(); 215 216 } 217 218 /** 219 * Decrypts the PBE-encrypted content of the given CMS <code>EncryptedData</code> object 220 * using the specified password and returns the decrypted (= original) message. 221 * 222 * @param asn1Object the <code>EncryptedData</code> object as ASN1Object 223 * @param password the password to decrypt the message 224 * 225 * @return the recovered message, as byte array 226 * @throws CMSException if the message cannot be recovered 227 * @throws IOException if an I/O error occurs 228 */ 229 public byte[] getEncryptedData(ASN1Object asn1Object, char[] password) throws CMSException, IOException { 230 231 // create an EncryptedData from the ASN1Object 232 EncryptedData encrypted_data = new EncryptedData(asn1Object); 233 234 System.out.println("Information about the encrypted data:"); 235 EncryptedContentInfo eci = (EncryptedContentInfo)encrypted_data.getEncryptedContentInfo(); 236 System.out.println("Content type: "+eci.getContentType().getName()); 237 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 238 239 // decrypt the message 240 try { 241 encrypted_data.setupCipher(password); 242 return encrypted_data.getContent(); 243 244 } catch (InvalidKeyException ex) { 245 throw new CMSException("Key error: "+ex.toString()); 246 } catch (NoSuchAlgorithmException ex) { 247 throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage()); 248 } catch (InvalidAlgorithmParameterException ex) { 249 throw new CMSException("Invalid Parameters: "+ex.toString()); 250 } catch (InvalidParameterSpecException ex) { 251 throw new CMSException("Invalid Parameters: "+ex.toString()); 252 } 253 } 254 255 // PKCS#7 256 257 258 /** 259 * Creates a PKCS#7 <code>EncryptedDataStream</code> message. 260 * <p> 261 * The supplied content is PBE-encrypted using the specified password. 262 * 263 * @param message the message to be encrypted, as byte representation 264 * @param pbeAlgorithm the PBE algorithm to be used 265 * @param password the password 266 * @return the DER encoding of the <code>EncryptedData</code> object just created 267 * @throws iaik.pkcs.PKCSException if the <code>EncryptedData</code> object cannot 268 * be created 269 * @throws IOException if an I/O error occurs 270 */ 271 public byte[] createPKCS7EncryptedDataStream(byte[] message, AlgorithmID pbeAlgorithm, char[] password) 272 throws iaik.pkcs.PKCSException, IOException { 273 274 iaik.pkcs.pkcs7.EncryptedDataStream encrypted_data; 275 276 // we are testing the stream interface 277 ByteArrayInputStream is = new ByteArrayInputStream(message); 278 // create a new EnvelopedData object encrypted with TripleDES CBC 279 try { 280 encrypted_data = new iaik.pkcs.pkcs7.EncryptedDataStream(is, 2048); 281 encrypted_data.setupCipher(pbeAlgorithm, password); 282 } catch (InvalidKeyException ex) { 283 throw new iaik.pkcs.PKCSException("Key error: "+ex.toString()); 284 } catch (NoSuchAlgorithmException ex) { 285 throw new iaik.pkcs.PKCSException("Content encryption algorithm not implemented: "+ex.getMessage()); 286 } 287 288 // return the EnvelopedDate as DER encoded byte array with block size 2048 289 ByteArrayOutputStream os = new ByteArrayOutputStream(); 290 encrypted_data.writeTo(os); 291 return os.toByteArray(); 292 } 293 294 /** 295 * Decrypts the PBE-encrypted content of the given PKCS#7 <code>EncryptedData</code> object 296 * using the specified password and returns the decrypted (= original) message. 297 * 298 * @param encoding the <code>EncryptedData</code> object as DER encoded byte array 299 * @param password the password to decrypt the message 300 * 301 * @return the recovered message, as byte array 302 * @throws iaik.pkcs.PKCSException if the message cannot be recovered 303 * @throws IOException if an I/O error occurs 304 */ 305 public byte[] getPKCS7EncryptedDataStream(byte[] encoding, char[] password) 306 throws iaik.pkcs.PKCSException, IOException { 307 308 // create the EncryptpedData object from a DER encoded byte array 309 // we are testing the stream interface 310 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 311 iaik.pkcs.pkcs7.EncryptedDataStream encrypted_data = new iaik.pkcs.pkcs7.EncryptedDataStream(is); 312 313 System.out.println("Information about the encrypted data:"); 314 iaik.pkcs.pkcs7.EncryptedContentInfoStream eci = (iaik.pkcs.pkcs7.EncryptedContentInfoStream)encrypted_data.getEncryptedContentInfo(); 315 System.out.println("Content type: "+eci.getContentType().getName()); 316 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 317 318 // decrypt the message 319 try { 320 encrypted_data.setupCipher(password); 321 InputStream decrypted = encrypted_data.getInputStream(); 322 ByteArrayOutputStream os = new ByteArrayOutputStream(); 323 Util.copyStream(decrypted, os, null); 324 325 return os.toByteArray(); 326 327 } catch (InvalidKeyException ex) { 328 throw new iaik.pkcs.PKCSException("Key error: "+ex.toString()); 329 } catch (NoSuchAlgorithmException ex) { 330 throw new iaik.pkcs.PKCSException("Content encryption algorithm not implemented: "+ex.getMessage()); 331 } catch (InvalidAlgorithmParameterException ex) { 332 throw new iaik.pkcs.PKCSException("Invalid Parameters: "+ex.toString()); 333 } catch (InvalidParameterSpecException ex) { 334 throw new iaik.pkcs.PKCSException("Invalid Parameters: "+ex.toString()); 335 } 336 } 337 338 /** 339 * Creates a PKCS#7 <code>EncryptedData</code> message. 340 * <p> 341 * The supplied content is PBE-encrypted using the specified password. 342 * 343 * @param message the message to be encrypted, as byte representation 344 * @param pbeAlgorithm the PBE algorithm to be used 345 * @param password the password 346 * @return the DER encoding of the <code>EncryptedData</code> object just created 347 * @throws iaik.pkcs.PKCSException if the <code>EncryptedData</code> object cannot 348 * be created 349 * @throws IOException if an I/O error occurs 350 */ 351 public ASN1Object createPKCS7EncryptedData(byte[] message, AlgorithmID pbeAlgorithm, char[] password) 352 throws iaik.pkcs.PKCSException, IOException { 353 354 iaik.pkcs.pkcs7.EncryptedData encrypted_data; 355 356 try { 357 encrypted_data = new iaik.pkcs.pkcs7.EncryptedData(message); 358 // encrypt the message 359 encrypted_data.setupCipher(pbeAlgorithm, password); 360 } catch (InvalidKeyException ex) { 361 throw new iaik.pkcs.PKCSException("Key error: "+ex.toString()); 362 } catch (NoSuchAlgorithmException ex) { 363 throw new iaik.pkcs.PKCSException("Content encryption algorithm not implemented: "+ex.getMessage()); 364 } 365 return encrypted_data.toASN1Object(); 366 367 } 368 369 /** 370 * Decrypts the PBE-encrypted content of the given PKCS#7 <code>EncryptedData</code> object 371 * using the specified password and returns the decrypted (= original) message. 372 * 373 * @param asn1Object the <code>EncryptedData</code> object as ASN1Object 374 * @param password the password to decrypt the message 375 * 376 * @return the recovered message, as byte array 377 * @throws iaik.pkcs.PKCSException if the message cannot be recovered 378 * @throws IOException if an I/O error occurs 379 */ 380 public byte[] getPKCS7EncryptedData(ASN1Object asn1Object, char[] password) 381 throws iaik.pkcs.PKCSException, IOException { 382 383 // create an EncryptedData from the ASN1Object 384 iaik.pkcs.pkcs7.EncryptedData encrypted_data = new iaik.pkcs.pkcs7.EncryptedData(asn1Object); 385 386 System.out.println("Information about the encrypted data:"); 387 iaik.pkcs.pkcs7.EncryptedContentInfo eci = (iaik.pkcs.pkcs7.EncryptedContentInfo)encrypted_data.getEncryptedContentInfo(); 388 System.out.println("Content type: "+eci.getContentType().getName()); 389 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 390 391 // decrypt the message 392 try { 393 encrypted_data.setupCipher(password); 394 return encrypted_data.getContent(); 395 396 } catch (InvalidKeyException ex) { 397 throw new iaik.pkcs.PKCSException("Key error: "+ex.toString()); 398 } catch (NoSuchAlgorithmException ex) { 399 throw new iaik.pkcs.PKCSException("Content encryption algorithm not implemented: "+ex.getMessage()); 400 } catch (InvalidAlgorithmParameterException ex) { 401 throw new iaik.pkcs.PKCSException("Invalid Parameters: "+ex.toString()); 402 } catch (InvalidParameterSpecException ex) { 403 throw new iaik.pkcs.PKCSException("Invalid Parameters: "+ex.toString()); 404 } 405 } 406 407 408 /** 409 * Starts the tests. 410 */ 411 public void start() { 412 // the test message 413 String m = "This is the test message."; 414 System.out.println("Test message: \""+m+"\""); 415 System.out.println(); 416 byte[] message = m.getBytes(); 417 418 try { 419 byte[] data; 420 byte[] received_message = null; 421 System.out.println("Stream implementation demos"); 422 System.out.println("==========================="); 423 424 425 // 426 // test CMS EncryptedDataStream 427 // 428 System.out.println("\nEncryptedDataStream demo [create]:\n"); 429 data = createEncryptedDataStream(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray()); 430 // transmit data 431 System.out.println("\nEncryptedDataStream demo [parse]:\n"); 432 received_message = getEncryptedDataStream(data, "password".toCharArray()); 433 System.out.print("\nContent: "); 434 System.out.println(new String(received_message)); 435 436 System.out.println("Testing compatibility to PKCS#7..."); 437 438 System.out.println("\nCMS EncryptedDataStream demo [create]:\n"); 439 data = createEncryptedDataStream(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray()); 440 // transmit data 441 System.out.println("\nPKCS#7 EncryptedDataStream demo [parse]:\n"); 442 received_message = getPKCS7EncryptedDataStream(data, "password".toCharArray()); 443 System.out.print("\nContent: "); 444 System.out.println(new String(received_message)); 445 446 System.out.println("\nPKCS7 EncryptedDataStream demo [create]:\n"); 447 data = createPKCS7EncryptedDataStream(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray()); 448 // transmit data 449 System.out.println("\nCMS EncryptedDataStream demo [parse]:\n"); 450 received_message = getEncryptedDataStream(data, "password".toCharArray()); 451 System.out.print("\nContent: "); 452 System.out.println(new String(received_message)); 453 454 455 // the non-stream implementation 456 System.out.println("\nNon-stream implementation demos"); 457 System.out.println("==============================="); 458 459 ASN1Object obj = null; 460 461 462 // 463 // test CMS EncryptedData 464 // 465 System.out.println("\nEncryptedData demo [create]:\n"); 466 obj = createEncryptedData(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray()); 467 // transmit data 468 System.out.println("\nEncryptedData demo [parse]:\n"); 469 received_message = getEncryptedData(obj, "password".toCharArray()); 470 System.out.print("\nContent: "); 471 System.out.println(new String(received_message)); 472 473 System.out.println("Testing compatibility to PKCS#7..."); 474 475 System.out.println("\nCMS EncryptedData demo [create]:\n"); 476 obj = createEncryptedData(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray()); 477 // transmit data 478 System.out.println("\nPKCS#7 EncryptedData demo [parse]:\n"); 479 received_message = getPKCS7EncryptedData(obj, "password".toCharArray()); 480 System.out.print("\nContent: "); 481 System.out.println(new String(received_message)); 482 483 System.out.println("\nPKCS#7 EncryptedData demo [create]:\n"); 484 obj = createPKCS7EncryptedData(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray()); 485 // transmit data 486 System.out.println("\nCMS EncryptedData demo [parse]:\n"); 487 received_message = getEncryptedData(obj, "password".toCharArray()); 488 System.out.print("\nContent: "); 489 System.out.println(new String(received_message)); 490 491 } catch (Exception ex) { 492 ex.printStackTrace(); 493 throw new RuntimeException(ex.toString()); 494 } 495 } 496 497 /** 498 * Tests the IAIK CMS against the IAIK PKCS#7 EncryptedData(Stream) implementation. 499 */ 500 public static void main(String argv[]) throws Exception { 501 502 DemoUtil.initDemos(); 503 504 (new PKCS7CMSEncryptedDataDemo()).start(); 505 System.out.println("\nReady!"); 506 DemoUtil.waitKey(); 507 } 508 }