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/digestedData/DigestedDataDemo.java 19    12.02.25 17:58 Dbratko $
029// $Revision: 19 $
030//
031
032package demo.cms.digestedData;
033
034import iaik.asn1.structures.AlgorithmID;
035import iaik.cms.CMSException;
036import iaik.cms.DigestedData;
037import iaik.cms.DigestedDataStream;
038import iaik.security.random.SecRandom;
039import iaik.utils.Util;
040
041import java.io.ByteArrayInputStream;
042import java.io.ByteArrayOutputStream;
043import java.io.IOException;
044import java.io.InputStream;
045import java.security.NoSuchAlgorithmException;
046import java.security.SecureRandom;
047
048import demo.DemoUtil;
049
050/**
051 * Demonstrates the usage of class {@link iaik.cms.DigestedDataStream} and
052 * {@link iaik.cms.DigestedData} for digesting data using the CMS type
053 * DigestedData.
054 */
055public class DigestedDataDemo {
056
057  // secure random number generator
058  SecureRandom random;
059
060  /**
061   * Default constructor.
062   */
063  public DigestedDataDemo() throws IOException {
064    System.out.println();
065    System.out.println("**********************************************************************************");
066    System.out.println("*                           CMSDigestedData demo                                 *");
067    System.out.println("*        (shows the usage of the CMS DigestedData type implementation)           *");
068    System.out.println("**********************************************************************************");
069    System.out.println();
070    
071    random = SecRandom.getDefault();
072  }
073
074
075  /**
076   * Creates a CMS <code>DigestedData</code> object.
077   * <p>
078   * @param message the message to be digested, as byte representation
079   * @param mode IMPLICIT (include message) or EXPLICIT (do not include message)
080   * @return the DER encoding of the <code>DigestedData</code> object just created
081   * @throws CMSException if the <code>DigestedData</code> object cannot
082   *                          be created
083   * @throws IOException if an I/O error occurs
084   */
085  public byte[] createDigestedDataStream(byte[] message, int mode) throws CMSException, IOException  {
086
087    System.out.println("Create a new message to be digested:");
088
089    // we are testing the stream interface
090    ByteArrayInputStream is = new ByteArrayInputStream(message);
091
092    // create a new DigestedData object which includes the data
093    DigestedDataStream digested_data = null;
094
095    digested_data = new DigestedDataStream(is, (AlgorithmID)AlgorithmID.sha256.clone(), mode);
096
097
098    // write the data through DigestedData to any out-of-band place
099    if (mode == DigestedDataStream.EXPLICIT) {
100      InputStream data_is = digested_data.getInputStream();
101      byte[] buf = new byte[1024];
102      int r;
103      while ((r = data_is.read(buf)) > 0) {
104        ;   // skip data
105      }  
106    }
107
108    // return the DigestedData as DER encoded byte array with block size 2048
109    ByteArrayOutputStream os = new ByteArrayOutputStream();
110    digested_data.writeTo(os, 2048);
111    return os.toByteArray();
112  }
113
114  /**
115   * Parses a CMS <code>DigestedData</code> object and verifies the hash.
116   *
117   * @param digestedData <code>DigestedData</code> object as DER encoded byte array
118   * @param message the the message which was transmitted out-of-band
119   *
120   * @return the inherent message as byte array
121   * @throws CMSException if some parsing error occurs or the hash verification fails
122   * @throws IOException if an I/O error occurs
123   */
124  public byte[] getDigestedDataStream(byte[] digestedData, byte[] message) throws CMSException, IOException {
125
126    // we are testing the stream interface
127    ByteArrayInputStream is = new ByteArrayInputStream(digestedData);
128    // create the DigestedData object
129    DigestedDataStream digested_data = null;
130    if (message == null) {
131      // implicitly; read the DER encoded object
132      digested_data = new DigestedDataStream(is);
133    } else {
134      // explicitly; set the data stream for digesting the message
135      digested_data = new DigestedDataStream(new ByteArrayInputStream(message), (AlgorithmID)AlgorithmID.sha256.clone());
136    }
137
138    // get an InputStream for reading the content
139    InputStream data = digested_data.getInputStream();
140    ByteArrayOutputStream os = new ByteArrayOutputStream();
141    Util.copyStream(data, os, null);
142
143    if (message != null) {
144      // explicit mode: decode the DigestedData now  
145      digested_data.decode(is);
146    }
147
148    if (digested_data.verify()) {
149       System.out.println("Hash ok!");
150    } else {
151       throw new CMSException("Hash verification failed!");
152    }
153
154    return os.toByteArray();
155  }
156
157
158  /**
159   * Creates a CMS <code>DigestedData</code> object.
160   * <p>
161   *
162   * @param message the message to be digested, as byte representation
163   * @param mode IMPLICIT (include message) or EXPLICIT (do not include message)
164   * @return the DER encoded <code>DigestedData</code>
165   * @throws CMSException if the <code>DigestedData</code> object cannot
166   *                          be created
167   * @throws IOException if an I/O error occurs
168   */
169  public byte[] createDigestedData(byte[] message, int mode) throws CMSException, IOException  {
170
171    System.out.println("Create a new digested message:");
172
173    // create a new DigestedData object which includes the data
174    DigestedData digested_data = new DigestedData(message, (AlgorithmID)AlgorithmID.sha256.clone(), mode);
175
176    return digested_data.getEncoded();
177  }
178
179  /**
180   * Parses a CMS <code>DigestedData</code> object and verifies the hash value.
181   *
182   * @param encoding the DER encoded <code>DigestedData</code> object 
183   * @param message the the message which was transmitted out-of-band (explicit digested)
184   *
185   * @return the message
186   * @throws CMSException if some parsing error occurs or the hash verification fails
187   * @throws IOException if an I/O error occurs
188   */
189  public byte[] getDigestedData(byte[] encoding, byte[] message) throws CMSException, IOException {
190    
191    ByteArrayInputStream encodedStream = new ByteArrayInputStream(encoding);
192    // create the DigestedData object
193    DigestedData digested_data = null;
194    if (message == null) {
195      // implicitly digested; read the ASN.1 object
196      digested_data = new DigestedData(encodedStream);
197    }
198    else {
199      // explicitly digested; set the data for digesting the message
200      try {
201         digested_data = new DigestedData(message, (AlgorithmID)AlgorithmID.sha256.clone());
202         // if explicitly digested now the DER encoded object
203         digested_data.decode(encodedStream);
204
205      } catch (NoSuchAlgorithmException ex) {
206         throw new CMSException(ex.getMessage());
207      }
208    }
209
210    // now verify the digest
211    if (digested_data.verify()) {
212       System.out.println("Hash ok!");
213    } else {
214       throw new CMSException("Hash verification failed!");
215    }
216
217    return digested_data.getContent();
218  }
219  
220  /**
221   * Starts the tests.
222   */
223  public void start() {
224     // the test message
225    String m = "This is the test message.";
226    System.out.println("Test message: \""+m+"\"");
227    System.out.println();
228    byte[] message = m.getBytes();
229
230    try {
231      byte[] encoding;
232      byte[] received_message = null;
233      System.out.println("Stream implementation demos");
234      System.out.println("===========================");
235
236      // the stream implementation
237   
238      //
239      // test CMS Implicit DigestedDataStream
240      //
241      System.out.println("\nImplicit DigestedDataStream demo [create]:\n");
242      encoding = createDigestedDataStream(message, DigestedDataStream.IMPLICIT);
243      // transmit data
244      System.out.println("\nImplicit DigestedDataStream demo [parse]:\n");
245      received_message = getDigestedDataStream(encoding, null);
246      System.out.print("\nContent: ");
247      System.out.println(new String(received_message));
248
249      //
250      // test CMS Explicit DigestedDataStream
251      //
252      System.out.println("\nExplicit DigestedDataStream demo [create]:\n");
253      encoding = createDigestedDataStream(message, DigestedDataStream.EXPLICIT);
254      // transmit data
255      System.out.println("\nExplicit DigestedDataStream demo [parse]:\n");
256      received_message = getDigestedDataStream(encoding, message);
257      System.out.print("\nContent: ");
258      System.out.println(new String(received_message));
259      
260      // the non-stream implementation
261      System.out.println("\nNon-stream implementation demos");
262      System.out.println("===============================");
263
264      //
265      // test CMS Implicit DigestedData
266      //
267      System.out.println("\nImplicit DigestedData demo [create]:\n");
268      encoding = createDigestedData(message, DigestedData.IMPLICIT);
269      // transmit data
270      System.out.println("\nImplicit DigestedData demo [parse]:\n");
271      received_message = getDigestedData(encoding, null);
272      System.out.print("\nContent: ");
273      System.out.println(new String(received_message));
274
275      //
276      // test CMS Explicit DigestedData
277      //
278      System.out.println("\nExplicit DigestedData demo [create]:\n");
279      encoding = createDigestedData(message, DigestedData.EXPLICIT);
280      // transmit data
281      System.out.println("\nExplicit DigestedData demo [parse]:\n");
282      received_message = getDigestedData(encoding, message);
283      System.out.print("\nContent: ");
284      System.out.println(new String(received_message));
285      
286        } catch (Exception ex) {
287          ex.printStackTrace();
288          throw new RuntimeException(ex.toString());
289        }
290  }
291
292  /**
293   * Main method.
294   */
295  public static void main(String argv[]) throws Exception {
296
297        DemoUtil.initDemos();
298
299    (new DigestedDataDemo()).start();
300    System.out.println("\nReady!");
301    DemoUtil.waitKey();
302  }
303}