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 }