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/envelopedData/FileEncryptionDemo.java 13 12.02.25 17:58 Dbratko $ 059 // $Revision: 13 $ 060 // 061 062 package demo.cms.envelopedData; 063 064 import iaik.asn1.UTF8String; 065 import iaik.asn1.structures.AlgorithmID; 066 import iaik.cms.CMSAlgorithmID; 067 import iaik.cms.ContentInfoStream; 068 import iaik.cms.EnvelopedDataStream; 069 import iaik.cms.PasswordRecipientInfo; 070 import iaik.cms.RecipientInfo; 071 import iaik.security.random.SecRandom; 072 import iaik.security.spec.PBEKeyAndParameterSpec; 073 import iaik.utils.Util; 074 075 import java.io.BufferedInputStream; 076 import java.io.BufferedOutputStream; 077 import java.io.FileInputStream; 078 import java.io.FileOutputStream; 079 import java.io.IOException; 080 import java.io.InputStream; 081 import java.io.OutputStream; 082 import java.security.SecureRandom; 083 084 import javax.crypto.SecretKey; 085 086 import demo.DemoUtil; 087 088 /** 089 * This class shows how to use the CMS {@link iaik.cms.PasswordRecipientInfo 090 * PasswordRecipientInfo} type for password based encrypting the contents of 091 * a file (and later decrypting it again) with the CMS {@link iaik.cms.EnvelopedDataStream 092 * EnvelopedDataStream} EnvelopedData} content type. 093 * <p> 094 * The contents is encrypted using the AES cipher. For deriving the key 095 * encryption key from the password, the PKCS#5 PBKDF2 key derivation function 096 * is used. The content encryption key is decrypted with AES, too. 097 * <p> 098 * You can modify this demo to use any other supported algorithm(s). Or 099 * you can use it with PBKDF2/AES for encrypting a file simply 100 * by calling: 101 * <pre> 102 * // the file to be encrypted 103 * String dataFile = ...; 104 * // the file to which to write the encrypted data 105 * String encryptedFile = ...; 106 * // password 107 * char[] password = ...; 108 * // encrypt file 109 * FileEncryption fe = new FileEncryption(); 110 * fe.encrypt(dataFile, encryptedFile, password); 111 * </pre> 112 * 113 * Or decrypting a file: 114 * 115 * <pre> 116 * // the encrypted file 117 * String encryptedFile = ...; 118 * // the file to which to write the decrypted data 119 * String decryptedFile = ...; 120 * // password 121 * char[] password = ...; 122 * // decrypt file 123 * FileEncryption fe = new FileEncryption(); 124 * fe.decrypt(encryptedFile, decryptedFile, password); 125 * </pre> 126 * 127 * @see iaik.cms.EnvelopedDataStream 128 * @see iaik.cms.EnvelopedData 129 * @see iaik.cms.EnvelopedDataOutputStream 130 * @see iaik.cms.PasswordRecipientInfo 131 */ 132 public class FileEncryptionDemo { 133 134 /** 135 * Default constructor. 136 */ 137 public FileEncryptionDemo() { 138 System.out.println(); 139 System.out.println("**********************************************************************************"); 140 System.out.println("* File encryption/decryption demo *"); 141 System.out.println("* (shows how to use the PasswordRecipientInfo type for encrypting a file) *"); 142 System.out.println("**********************************************************************************"); 143 System.out.println(); 144 145 } 146 147 148 /** 149 * Uses the given password to encrypt the contents from <code>inFile</code> 150 * and write the encryption result to <code>outFile</code>. 151 * The contents is encrypted using the AES cipher. For dereiving the key 152 * encryption key from the password, the PKCS#5 PBKDF2 key derivation function 153 * is used. The content encryption key is decrypted with AES, too. 154 * 155 * @param inFile the file from which to read the encrypted (enveloped) data 156 * @param outFile the file to which to write the decrypted data 157 * @param password the password to be used for decryption 158 * 159 * @throws Exception if an error occurs 160 */ 161 public void encrypt(String inFile, 162 String outFile, 163 char[] password) 164 throws Exception { 165 166 // stream for reading the data from the file to be encrypted 167 InputStream is = null; 168 // stream for writing the encrypted data to a file 169 OutputStream os = null; 170 171 // key derivation function (PBKDF2) 172 AlgorithmID keyDerivationAlg = (AlgorithmID)AlgorithmID.pbkdf2.clone(); 173 // key encryption algorithm (PWRI-KEK) 174 AlgorithmID keyEncryptionAlg = (AlgorithmID)CMSAlgorithmID.pwri_kek.clone(); 175 // for PWRI-KEK set the kek encryption algorithm parameter (AES) 176 AlgorithmID kekEncryptionAlg = (AlgorithmID)AlgorithmID.aes256_CBC.clone(); 177 keyEncryptionAlg.setParameter(kekEncryptionAlg.toASN1Object()); 178 // content encryption algorithm 179 AlgorithmID cekAlg = (AlgorithmID)AlgorithmID.aes256_CBC.clone(); 180 181 // parameters for key derivation 182 int kekLen = 32; // we use AES as kek algorithm 183 int iterationCount = 10000; 184 byte[] salt = new byte[32]; 185 SecureRandom random = SecRandom.getDefault(); 186 random.nextBytes(salt); 187 PBEKeyAndParameterSpec keyDerivationParamSpec = 188 new PBEKeyAndParameterSpec(UTF8String.getUTF8EncodingFromCharArray(password), 189 salt, 190 iterationCount, 191 kekLen); 192 193 try { 194 195 is = new BufferedInputStream(new FileInputStream(inFile)); 196 197 // create EnvelopedData for encrypting the data with the content encryption algorithm 198 EnvelopedDataStream envelopedData = new EnvelopedDataStream(is, cekAlg); 199 200 // create the PasswordRecipientInfo 201 PasswordRecipientInfo pri = new PasswordRecipientInfo(password, 202 keyDerivationAlg, 203 keyDerivationParamSpec, 204 keyEncryptionAlg, 205 null); 206 // set the RecipientInfo 207 envelopedData.setRecipientInfos(new RecipientInfo[] { pri }); 208 envelopedData.setBlockSize(2048); 209 // wrap into ContentInfo 210 ContentInfoStream cis = new ContentInfoStream(envelopedData); 211 212 // encrypt to file 213 os = new BufferedOutputStream(new FileOutputStream(outFile)); 214 cis.writeTo(os); 215 216 } finally { 217 if (is != null) { 218 try { 219 is.close(); 220 } catch (IOException ex) { 221 // ignore 222 } 223 } 224 if (os != null) { 225 try { 226 os.close(); 227 } catch (IOException ex) { 228 // ignore 229 } 230 } 231 } 232 233 } 234 235 /** 236 * Uses the given password to decrypt the contents from <code>inFile</code> 237 * and write the it to <code>outFile</code>. 238 * 239 * @param inFile the file from which to read the encrypted (enveloped) data 240 * @param outFile the file to which to write the decrypted data 241 * @param password the password to be used for decryption 242 * 243 * @throws Exception if an error occurs 244 */ 245 public void decrypt(String inFile, String outFile, char[] password) 246 throws Exception { 247 248 // stream for reading the encrypted data from a file 249 InputStream is = null; 250 // stream for writing the decrypted data to a file 251 OutputStream os = null; 252 253 try { 254 255 is = new BufferedInputStream(new FileInputStream(inFile)); 256 257 // create EnvelopedData 258 EnvelopedDataStream envelopedData = new EnvelopedDataStream(is); 259 260 // get PasswordRecipientInfo and decrypt the cek 261 PasswordRecipientInfo recipient = (PasswordRecipientInfo)envelopedData.getRecipientInfos()[0]; 262 SecretKey cek = recipient.decryptKey(password, "AES-256"); 263 String alg = cek.getAlgorithm(); 264 // setup cipher for content decryption 265 envelopedData.setupCipher(cek); 266 InputStream decrypted = envelopedData.getInputStream(); 267 // decrypt data to file 268 os = new BufferedOutputStream(new FileOutputStream(outFile)); 269 Util.copyStream(decrypted, os, null); 270 271 } finally { 272 if (is != null) { 273 try { 274 is.close(); 275 } catch (IOException ex) { 276 // ignore 277 } 278 } 279 if (os != null) { 280 try { 281 os.close(); 282 } catch (IOException ex) { 283 // ignore 284 } 285 } 286 } 287 288 } 289 290 291 /** 292 * Starts the demo. 293 */ 294 public void start() { 295 // the file to be encrypted 296 String dataFile = "test.html"; 297 // the file to which to write the encrypted data 298 String encryptedFile = "encrypted.dat"; 299 // the file to which to write the decrypted data 300 String decryptedFile = "decrypted.html"; 301 302 // password (in practice use a more secure one!) 303 char[] password = { 't', 'o', 'p', 'S', 'e', 'c', 'r', 'e', 't' }; 304 305 try { 306 307 // encrypt file 308 System.out.println("Encrypt data from file " + dataFile + " to file " + encryptedFile); 309 encrypt(dataFile, encryptedFile, password); 310 311 // decrypt file 312 System.out.println("Decrypt data from file " + encryptedFile + " to file " + decryptedFile); 313 decrypt(encryptedFile, decryptedFile, password); 314 315 } catch (Exception ex) { 316 ex.printStackTrace(); 317 throw new RuntimeException(ex.toString()); 318 } finally { 319 for (int i = 0; i < password.length; i++) { 320 password[i] = '\u0000'; 321 } 322 } 323 324 } 325 326 327 /** 328 * Main method. 329 * 330 * @throws Exception 331 * if some error occurs 332 */ 333 public static void main(String argv[]) throws Exception { 334 335 DemoUtil.initDemos(); 336 337 (new FileEncryptionDemo()).start(); 338 System.out.println("\nReady!"); 339 DemoUtil.waitKey(); 340 } 341 }