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