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