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/DigestedDataOutputStreamDemo.java 15    12.02.25 17:58 Dbratko $
029// $Revision: 15 $
030//
031
032package demo.cms.digestedData;
033
034import iaik.asn1.ObjectID;
035import iaik.asn1.structures.AlgorithmID;
036import iaik.cms.CMSException;
037import iaik.cms.ContentInfoOutputStream;
038import iaik.cms.DigestedDataOutputStream;
039import iaik.cms.DigestedDataStream;
040import iaik.utils.Util;
041
042import java.io.ByteArrayInputStream;
043import java.io.ByteArrayOutputStream;
044import java.io.IOException;
045import java.io.InputStream;
046
047import demo.DemoUtil;
048
049/**
050 * Demonstrates the usage of class {@link iaik.cms.DigestedDataOutputStream} and
051 * {@link iaik.cms.DigestedData} for digesting data using the CMS type
052 * DigestedData.
053 */
054public class DigestedDataOutputStreamDemo {
055
056  /**
057   * Default constructor.
058   */
059  public DigestedDataOutputStreamDemo() throws IOException {
060    System.out.println();
061    System.out.println("**********************************************************************************");
062    System.out.println("*                  DigestedDataOutputStream demo                                 *");
063    System.out.println("*        (shows the usage of the DigestedDataOutputStream implementation)        *");
064    System.out.println("**********************************************************************************");
065    System.out.println();
066  }
067
068
069  /**
070   * Uses the IAIK-CMS DigestedDataOutputStream class to create a CMS <code>DigestedData</code> 
071   * object for digesting the given message.
072   * 
073   * @param message the message to be digested, as byte representation
074   * @param mode IMPLICIT (include message) or EXPLICIT (do not include message)
075   * 
076   * @return the BER encoding of the <code>DigestedData</code> object just created,
077   *         wrapped in a ContentInfo
078   * 
079   * @throws CMSException if the <code>DigestedData</code> object cannot
080   *                          be created
081   * @throws IOException if an I/O error occurs
082   */
083  public byte[] createDigestedData(byte[] message, int mode) throws CMSException, IOException  {
084
085    System.out.println("Create a new message to be digested:");
086
087    // the stream from which to read the data to be digested
088    ByteArrayInputStream is = new ByteArrayInputStream(message);
089
090    // the stream to which to write the DigestedData
091    ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
092    
093    // wrap DigestedData into a ContentInfo 
094    ContentInfoOutputStream contentInfoStream = 
095      new ContentInfoOutputStream(ObjectID.cms_digestedData, resultStream);
096    // create a new DigestedData object 
097    DigestedDataOutputStream digestedData = 
098      new DigestedDataOutputStream(contentInfoStream,
099                                   (AlgorithmID)AlgorithmID.sha256.clone(),
100                                   mode);
101
102
103    int blockSize = 8; // in real world we would use a block size like 2048
104    //  write in the data to be digested
105    byte[] buffer = new byte[blockSize];
106    int bytesRead;
107    while ((bytesRead = is.read(buffer)) != -1) {
108      digestedData.write(buffer, 0, bytesRead);
109    }
110    
111    // closing the stream finishes digest calculation and closes the underlying stream
112    digestedData.close();
113    return resultStream.toByteArray();
114  }
115
116  /**
117   * Parses a CMS <code>DigestedData</code> object and verifies the hash.
118   *
119   * @param digestedData <code>DigestedData</code> object as BER encoded byte array
120   * @param message the message which may have been transmitted out-of-band
121   *
122   * @return the inherent message as byte array
123   * 
124   * @throws CMSException if some parsing error occurs or the hash verification fails
125   * @throws IOException if an I/O error occurs
126   */
127  public byte[] getDigestedData(byte[] digestedData, byte[] message) throws CMSException, IOException {
128
129    // we are testing the stream interface
130    ByteArrayInputStream is = new ByteArrayInputStream(digestedData);
131    // create the DigestedData object
132    DigestedDataStream digested_data = new DigestedDataStream(is);
133    
134    if (message != null) {
135      // explicit mode: set content received by other means
136      digested_data.setInputStream(new ByteArrayInputStream(message));
137    }
138
139    // get an InputStream for reading the content
140    InputStream data = digested_data.getInputStream();
141    ByteArrayOutputStream os = new ByteArrayOutputStream();
142    Util.copyStream(data, os, null);
143
144
145    if (digested_data.verify()) {
146       System.out.println("Hash ok!");
147    } else {
148       throw new CMSException("Hash verification failed!");
149    }
150
151    return os.toByteArray();
152  }
153
154
155  
156  /**
157   * Starts the tests.
158   */
159  public void start() {
160     // the test message
161    String m = "This is the test message.";
162    System.out.println("Test message: \""+m+"\"");
163    System.out.println();
164    byte[] message = m.getBytes();
165
166    try {
167      byte[] encoding;
168      byte[] received_message = null;
169      
170      //
171      // test CMS Implicit DigestedDataOutputStream
172      //
173      System.out.println("\nImplicit DigestedDataOutputStream demo [create]:\n");
174      encoding = createDigestedData(message, DigestedDataOutputStream.IMPLICIT);
175      // transmit data
176      System.out.println("\nImplicit DigestedDataOutputStream demo [parse]:\n");
177      received_message = getDigestedData(encoding, null);
178      System.out.print("\nContent: ");
179      System.out.println(new String(received_message));
180
181      //
182      // test CMS Explicit DigestedDataOutputStream
183      //
184      System.out.println("\nExplicit DigestedDataOutputStream demo [create]:\n");
185      encoding = createDigestedData(message, DigestedDataOutputStream.EXPLICIT);
186      // transmit data
187      System.out.println("\nExplicit DigestedDataOutputStream demo [parse]:\n");
188      received_message = getDigestedData(encoding, message);
189      System.out.print("\nContent: ");
190      System.out.println(new String(received_message));
191      
192      
193        } catch (Exception ex) {
194          ex.printStackTrace();
195          throw new RuntimeException(ex.toString());
196        }
197  }
198
199  /**
200   * Main method.
201   */
202  public static void main(String argv[]) throws Exception {
203
204        DemoUtil.initDemos();
205
206    (new DigestedDataOutputStreamDemo()).start();
207    System.out.println("\nReady!");
208    DemoUtil.waitKey();
209  }
210}