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