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/encryptedData/EncryptedDataDemo.java 17    12.02.25 17:58 Dbratko $
029// $Revision: 17 $
030//
031
032package demo.cms.encryptedData;
033
034import iaik.asn1.structures.AlgorithmID;
035import iaik.cms.CMSException;
036import iaik.cms.EncryptedContentInfo;
037import iaik.cms.EncryptedContentInfoStream;
038import iaik.cms.EncryptedData;
039import iaik.cms.EncryptedDataStream;
040import iaik.security.random.SecRandom;
041import iaik.utils.Util;
042
043import java.io.ByteArrayInputStream;
044import java.io.ByteArrayOutputStream;
045import java.io.IOException;
046import java.io.InputStream;
047import java.security.InvalidAlgorithmParameterException;
048import java.security.InvalidKeyException;
049import java.security.NoSuchAlgorithmException;
050import java.security.SecureRandom;
051import java.security.spec.InvalidParameterSpecException;
052
053import demo.DemoUtil;
054
055/**
056 * Demonstrates the usage of class {@link iaik.cms.EncryptedDataStream} and
057 * {@link iaik.cms.EncryptedData} for encrypting data using the CMS type
058 * EncryptedData.
059 */
060public class EncryptedDataDemo {
061
062  // secure random number generator
063  SecureRandom random;
064
065  /**
066   * Default constructor.
067   */
068  public EncryptedDataDemo() {
069    
070    System.out.println();
071    System.out.println("**********************************************************************************");
072    System.out.println("*                           EncryptedDataDemo demo                               *");
073    System.out.println("*        (shows the usage of the CMS EncryptedData type implementation)          *");
074    System.out.println("**********************************************************************************");
075    System.out.println();
076
077    random = SecRandom.getDefault();
078  }
079
080
081  /**
082   * Creates a CMS <code>EncryptedDataStream</code> message.
083   * <p>
084   * The supplied content is PBE-encrypted using the specified password.
085   *
086   * @param message the message to be encrypted, as byte representation
087   * @param pbeAlgorithm the PBE algorithm to be used
088   * @param password the password
089   * @return the DER encoding of the <code>EncryptedData</code> object just created
090   * @throws CMSException if the <code>EncryptedData</code> object cannot
091   *                          be created
092   * @throws IOException if an I/O error occurs
093   */
094  public byte[] createEncryptedDataStream(byte[] message, AlgorithmID pbeAlgorithm, char[] password) throws CMSException, IOException {
095
096    EncryptedDataStream encrypted_data;
097
098    // we are testing the stream interface
099    ByteArrayInputStream is = new ByteArrayInputStream(message);
100    // create a new EncryptedData object encrypted with TripleDES CBC
101    try {
102      encrypted_data = new EncryptedDataStream(is, 2048);
103      encrypted_data.setupCipher(pbeAlgorithm, password);
104    } catch (InvalidKeyException ex) {
105      throw new CMSException("Key error: "+ex.getMessage());
106    } catch (NoSuchAlgorithmException ex) {
107      throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
108    }
109
110    // return the EncryptedData as DER encoded byte array with block size 2048
111    ByteArrayOutputStream os = new ByteArrayOutputStream();
112    encrypted_data.writeTo(os);
113    return os.toByteArray();
114  }
115
116  /**
117   * Decrypts the PBE-encrypted content of the given CMS <code>EncryptedData</code> object
118   * using the specified password and returns the decrypted (= original) message.
119   *
120   * @param encoding the <code>EncryptedData</code> object as DER encoded byte array
121   * @param password the password to decrypt the message
122   *
123   * @return the recovered message, as byte array
124   * @throws CMSException if the message cannot be recovered
125   * @throws IOException if an I/O error occurs
126   */
127  public byte[] getEncryptedDataStream(byte[] encoding, char[] password) throws CMSException, IOException {
128
129    // create the EncryptpedData object from a DER encoded byte array
130    // we are testing the stream interface
131    ByteArrayInputStream is = new ByteArrayInputStream(encoding);
132    EncryptedDataStream encrypted_data = new EncryptedDataStream(is);
133
134    System.out.println("Information about the encrypted data:");
135    EncryptedContentInfoStream eci = encrypted_data.getEncryptedContentInfo();
136    System.out.println("Content type: "+eci.getContentType().getName());
137    System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
138
139    // decrypt the message
140    try {
141      encrypted_data.setupCipher(password);
142      InputStream decrypted = encrypted_data.getInputStream();
143      ByteArrayOutputStream os = new ByteArrayOutputStream();
144      Util.copyStream(decrypted, os, null);
145
146      return os.toByteArray();
147
148    } catch (InvalidKeyException ex) {
149      throw new CMSException("Key error: "+ex.getMessage());
150    } catch (NoSuchAlgorithmException ex) {
151      throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
152    } catch (InvalidAlgorithmParameterException ex) {
153      throw new CMSException("Invalid Parameters: "+ex.getMessage());
154    } catch (InvalidParameterSpecException ex) {
155      throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
156    }
157  }
158
159  /**
160   * Creates a CMS <code>EncryptedData</code> message.
161   * <p>
162   * The supplied content is PBE-encrypted using the specified password.
163   *
164   * @param message the message to be encrypted, as byte representation
165   * @param pbeAlgorithm the PBE algorithm to be used
166   * @param password the password
167   * @return the DER encoding of the <code>EncryptedData</code> object just created
168   * @throws CMSException if the <code>EncryptedData</code> object cannot
169   *                          be created
170   * @throws IOException if an I/O error occurs
171   */
172  public byte[] createEncryptedData(byte[] message, AlgorithmID pbeAlgorithm, char[] password) throws CMSException, IOException {
173
174    EncryptedData encrypted_data;
175
176    try {
177      encrypted_data = new EncryptedData(message);
178      // encrypt the message
179      encrypted_data.setupCipher(pbeAlgorithm, password);
180    } catch (InvalidKeyException ex) {
181      throw new CMSException("Key error: "+ex.getMessage());
182    } catch (NoSuchAlgorithmException ex) {
183      throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
184    }
185    return encrypted_data.getEncoded();
186
187  }
188
189  /**
190   * Decrypts the PBE-encrypted content of the given CMS <code>EncryptedData</code> object
191   * using the specified password and returns the decrypted (= original) message.
192   *
193   * @param encoding the DER encoded <code>EncryptedData</code> object
194   * @param password the password to decrypt the message
195   *
196   * @return the recovered message, as byte array
197   * @throws CMSException if the message cannot be recovered
198   * @throws IOException if an I/O error occurs
199   */
200  public byte[] getEncryptedData(byte[] encoding, char[] password) throws CMSException, IOException {
201
202    // create an EncryptedData from the ASN1Object
203    EncryptedData encrypted_data = new EncryptedData(new ByteArrayInputStream(encoding));
204
205    System.out.println("Information about the encrypted data:");
206    EncryptedContentInfo eci = (EncryptedContentInfo)encrypted_data.getEncryptedContentInfo();
207    System.out.println("Content type: "+eci.getContentType().getName());
208    System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
209
210    // decrypt the message
211    try {
212      encrypted_data.setupCipher(password);
213      return encrypted_data.getContent();
214
215    } catch (InvalidKeyException ex) {
216      throw new CMSException("Key error: "+ex.getMessage());
217    } catch (NoSuchAlgorithmException ex) {
218      throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
219    } catch (InvalidAlgorithmParameterException ex) {
220      throw new CMSException("Invalid Parameters: "+ex.getMessage());
221    } catch (InvalidParameterSpecException ex) {
222      throw new CMSException("Content encryption algorithm not implemented: "+ex.getMessage());
223    }
224  }
225  
226
227  /**
228   * Starts the tests.
229   */
230  public void start() {
231     // the test message
232    String m = "This is the test message.";
233    System.out.println("Test message: \""+m+"\"");
234    System.out.println();
235    byte[] message = m.getBytes();
236
237    try {
238      byte[] encoding;
239      byte[] received_message = null;
240      System.out.println("Stream implementation demos");
241      System.out.println("===========================");
242
243
244      //
245      // test CMS EncryptedDataStream
246      //
247      System.out.println("\nEncryptedDataStream demo [create]:\n");
248      encoding = createEncryptedDataStream(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray());
249      // transmit data
250      System.out.println("\nEncryptedDataStream demo [parse]:\n");
251      received_message = getEncryptedDataStream(encoding, "password".toCharArray());
252      System.out.print("\nContent: ");
253      System.out.println(new String(received_message));
254
255
256
257      // the non-stream implementation
258      System.out.println("\nNon-stream implementation demos");
259      System.out.println("===============================");
260
261      //
262      // test CMS EncryptedData
263      //
264      System.out.println("\nEncryptedData demo [create]:\n");
265      encoding = createEncryptedData(message, (AlgorithmID)AlgorithmID.pbeWithSHAAnd3_KeyTripleDES_CBC.clone(), "password".toCharArray());
266      // transmit data
267      System.out.println("\nEncryptedData demo [parse]:\n");
268      received_message = getEncryptedData(encoding, "password".toCharArray());
269      System.out.print("\nContent: ");
270      System.out.println(new String(received_message));
271
272        } catch (Exception ex) {
273          ex.printStackTrace();
274          throw new RuntimeException(ex.toString());
275        }
276  }
277
278  /**
279   * Maim method.
280   */
281  public static void main(String argv[]) throws Exception {
282
283    DemoUtil.initDemos();
284
285    (new EncryptedDataDemo()).start();
286    System.out.println("\nReady!");
287    DemoUtil.waitKey();
288  }
289}