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/encryptedData/EncryptedDataOutputStreamDemo.java 8 12.02.25 17:58 Dbratko $ 059 // $Revision: 8 $ 060 // 061 062 063 package demo.cms.encryptedData; 064 065 import iaik.asn1.CodingException; 066 import iaik.asn1.ObjectID; 067 import iaik.asn1.structures.AlgorithmID; 068 import iaik.asn1.structures.Attribute; 069 import iaik.cms.CMSException; 070 import iaik.cms.ContentInfoOutputStream; 071 import iaik.cms.EncryptedContentInfoStream; 072 import iaik.cms.EncryptedDataOutputStream; 073 import iaik.cms.EncryptedDataStream; 074 import iaik.cms.attributes.CMSContentType; 075 import iaik.security.random.SecRandom; 076 import iaik.utils.CryptoUtils; 077 import iaik.utils.Util; 078 079 import java.io.ByteArrayInputStream; 080 import java.io.ByteArrayOutputStream; 081 import java.io.IOException; 082 import java.io.InputStream; 083 import java.security.InvalidAlgorithmParameterException; 084 import java.security.InvalidKeyException; 085 import java.security.NoSuchAlgorithmException; 086 import java.security.SecureRandom; 087 import java.security.spec.InvalidParameterSpecException; 088 089 import demo.DemoUtil; 090 091 092 /** 093 * Demonstrates the usage of class {@link iaik.cms.EncryptedDataOutputStream} for 094 * PBE encrypting data using the CMS type EnryptedData. 095 */ 096 public class EncryptedDataOutputStreamDemo { 097 098 // secure random number generator 099 SecureRandom random; 100 101 /** 102 * Default constructor. 103 */ 104 public EncryptedDataOutputStreamDemo() { 105 106 System.out.println(); 107 System.out.println("**********************************************************************************"); 108 System.out.println("* EncryptedDataOutputStream demo *"); 109 System.out.println("* (shows the usage of the CMS EncryptedDataOutputStream implementation) *"); 110 System.out.println("**********************************************************************************"); 111 System.out.println(); 112 113 random = SecRandom.getDefault(); 114 115 } 116 117 118 /** 119 * Creates a CMS <code>EncryptedData</code> and wraps it into a ContentInfo. 120 * 121 * @param message the message to be encrypted, as byte representation 122 * @return the encoded EncryptedData object just created, wrapped into a ContentInfo 123 * 124 * @throws CMSException if the <code>EncryptedData</code> object cannot 125 * be created 126 * @throws IOException if an I/O error occurs 127 */ 128 public byte[] createEncryptedData(byte[] message, char[] password) throws CMSException, IOException { 129 130 131 // a stream from which to read the data to be encrypted 132 ByteArrayInputStream is = new ByteArrayInputStream(message); 133 134 // the stream to which to write the EncryptedData 135 ByteArrayOutputStream resultStream = new ByteArrayOutputStream(); 136 137 // wrap EncryptedData into a ContentInfo 138 ContentInfoOutputStream contentInfoStream = 139 new ContentInfoOutputStream(ObjectID.cms_encryptedData, resultStream); 140 141 // create a new EncryptedData object 142 EncryptedDataOutputStream encryptedData = new EncryptedDataOutputStream(contentInfoStream); 143 // setup cipher for encryption 144 AlgorithmID contentEncAlg = (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(); 145 try { 146 encryptedData.setupCipher(contentEncAlg, password, 2000); 147 } catch (InvalidKeyException ex) { 148 throw new CMSException("Cannot setup cipher for encryption: " + ex.toString()); 149 } catch (NoSuchAlgorithmException ex) { 150 throw new CMSException("Cannot setup cipher for encryption: " + ex.toString()); 151 } 152 Attribute[] attributes = new Attribute[1]; 153 try { 154 // just for demonstration: set some unprotected attribute 155 // content type is data 156 CMSContentType contentType = new CMSContentType(ObjectID.cms_data); 157 attributes[0] = new Attribute(contentType); 158 encryptedData.setUnprotectedAttributes(attributes); 159 } catch (Exception ex) { 160 throw new CMSException("Error creating attribute: " + ex.toString()); 161 } 162 163 int blockSize = 8; // in real world we would use a block size like 2048 164 // write in the data to be encrypted 165 byte[] buffer = new byte[blockSize]; 166 int bytesRead; 167 while ((bytesRead = is.read(buffer)) != -1) { 168 encryptedData.write(buffer, 0, bytesRead); 169 } 170 171 // closing the stream finishes encryption and closes the underlying stream 172 encryptedData.close(); 173 return resultStream.toByteArray(); 174 } 175 176 /** 177 * Decrypts the encrypted content of the given EncryptedData object. 178 * 179 * @param encoding the encoded EncryptedData object, wrapped in a ContentInfo 180 * @param password the password to decrypt the message 181 * 182 * @return the recovered message, as byte array 183 * 184 * @throws CMSException if the message cannot be recovered 185 * @throws IOException if an I/O error occurs 186 */ 187 public byte[] getEncryptedData(byte[] encoding, char[] password) throws CMSException, IOException { 188 189 // create the EncryptpedData object from a BER encoded byte array 190 // we are testing the stream interface 191 ByteArrayInputStream is = new ByteArrayInputStream(encoding); 192 EncryptedDataStream encryptedData = new EncryptedDataStream(is); 193 194 System.out.println("Information about the encrypted data:"); 195 EncryptedContentInfoStream eci = encryptedData.getEncryptedContentInfo(); 196 System.out.println("Content type: "+eci.getContentType().getName()); 197 System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName()); 198 199 byte[] content = null; 200 // decrypt the message 201 try { 202 encryptedData.setupCipher(password); 203 InputStream decrypted = encryptedData.getInputStream(); 204 ByteArrayOutputStream os = new ByteArrayOutputStream(); 205 Util.copyStream(decrypted, os, null); 206 content = os.toByteArray(); 207 208 // get any unprotected attributes: 209 Attribute[] attributes = encryptedData.getUnprotectedAttributes(); 210 if ((attributes != null) && (attributes.length > 0)) { 211 System.out.println("Attributes included: "); 212 // we know we have used content type 213 CMSContentType contentType = (CMSContentType)attributes[0].getAttributeValue(); 214 System.out.println(contentType); 215 } 216 217 } catch (InvalidKeyException ex) { 218 throw new CMSException("Key error: " + ex.toString()); 219 } catch (NoSuchAlgorithmException ex) { 220 throw new CMSException("Content encryption algorithm not implemented: " + ex.toString()); 221 } catch (InvalidAlgorithmParameterException ex) { 222 throw new CMSException("Invalid Parameters: " + ex.toString()); 223 } catch (InvalidParameterSpecException ex) { 224 throw new CMSException("Content encryption algorithm not implemented: " + ex.toString()); 225 } catch (CodingException ex) { 226 throw new CMSException("Error decoding attributes: " + ex.toString()); 227 } 228 229 return content; 230 } 231 232 /** 233 * Starts the demo. 234 */ 235 public void start() { 236 // the test message 237 String m = "This is the test message."; 238 System.out.println("Test message: \""+m+"\""); 239 System.out.println(); 240 byte[] message = m.getBytes(); 241 242 // password (in real world use some more secure password) 243 char[] password = { 't', 'o', 'p', '-', 's', 'e', 'c', 'r', 'e', 't', '!' }; 244 245 try { 246 byte[] encoding; 247 byte[] received_message = null; 248 System.out.println("EnvelopedOutputStream implementation demo"); 249 System.out.println("==========================="); 250 251 252 // 253 // test CMS EncryptedDataOutputStream 254 // 255 System.out.println("\nEncryptedDataStream demo [create]:\n"); 256 encoding = createEncryptedData(message, password); 257 // transmit data 258 System.out.println("\nEncryptedDataStream demo [parse]:\n"); 259 received_message = getEncryptedData(encoding, password); 260 System.out.print("\nDecrypted content: "); 261 System.out.println(new String(received_message)); 262 263 if (CryptoUtils.equalsBlock(received_message, message) == false) { 264 throw new Exception("Decrypted content not equal to original one!"); 265 } 266 System.out.println("Ready!"); 267 268 } catch (Exception ex) { 269 ex.printStackTrace(); 270 throw new RuntimeException(ex.toString()); 271 } finally { 272 if (password != null) { 273 for (int i = 0; i < password.length; i++) { 274 password[i] = '\u0000'; 275 } 276 } 277 } 278 } 279 280 281 /** 282 * Main method. 283 * 284 * @throws Exception 285 * if an some error occurs 286 */ 287 public static void main(String argv[]) throws Exception { 288 289 demo.DemoUtil.initDemos(); 290 291 (new EncryptedDataOutputStreamDemo()).start(); 292 System.out.println("\nReady!"); 293 DemoUtil.waitKey(); 294 } 295 }