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/compressedData/CompressedDataDemo.java 13    12.02.25 17:58 Dbratko $
059    // $Revision: 13 $
060    //
061    
062    package demo.cms.compressedData;
063    
064    import iaik.asn1.structures.AlgorithmID;
065    import iaik.cms.CMSAlgorithmID;
066    import iaik.cms.CMSException;
067    import iaik.cms.CompressedData;
068    import iaik.cms.CompressedDataStream;
069    import iaik.cms.ContentInfo;
070    import iaik.cms.ContentInfoStream;
071    import iaik.cms.Utils;
072    import iaik.utils.CryptoUtils;
073    import iaik.utils.Util;
074    
075    import java.io.ByteArrayInputStream;
076    import java.io.ByteArrayOutputStream;
077    import java.io.IOException;
078    import java.io.InputStream;
079    import java.security.NoSuchAlgorithmException;
080    
081    import demo.DemoUtil;
082    
083    
084    
085    /**
086     * Demonstrates the usage of class {@link iaik.cms.CompressedDataStream} and
087     * {@link iaik.cms.CompressedData} for compressing/decompressing data using
088     * the CMS type CompressedData.
089     */
090    public class CompressedDataDemo {
091      
092      /**
093       * In explcit mode the compressed content data has to be transmitted by other means.
094       */
095      byte[] compressedContent_;
096    
097      /**
098       * Default constructor.
099       */
100      public CompressedDataDemo() {
101        System.out.println();
102        System.out.println("**********************************************************************************");
103        System.out.println("*                             CompressedDataDemo                                 *");
104        System.out.println("*        (shows the usage of the CMS CompressedData type implementation)         *");
105        System.out.println("**********************************************************************************");
106        System.out.println();
107      }
108    
109    
110      /**
111       * Creates a CMS <code>CompressedData</code> object.
112       * <p>
113       * @param message the message to be compressed, as byte representation
114       * @param mode IMPLICIT (include compressed content) or 
115       *             EXPLICIT (do not include compressed content)
116       *
117       * @return the BER encoding of the <code>CompressedData</code> object just created
118       *
119       * @throws CMSException if the <code>CompressedData</code> object cannot
120       *                          be created
121       * @throws IOException if an I/O error occurs
122       * @throws NoSuchAlgorithmException if the compression algorithm is not supported
123       */
124      public byte[] createCompressedDataStream(byte[] message, int mode) 
125        throws CMSException, IOException, NoSuchAlgorithmException {
126    
127        System.out.println("Create a new CompressedData message.");
128    
129        // we are testing the stream interface
130        ByteArrayInputStream is = new ByteArrayInputStream(message);
131    
132        // create a new CompressedData object 
133        CompressedDataStream compressedData = new CompressedDataStream(is, 
134                                                                       (AlgorithmID)CMSAlgorithmID.zlib_compress.clone(),
135                                                                       mode);
136    
137    
138        // in explicit mode transmit compressed content out-of-band 
139        if (mode == CompressedDataStream.EXPLICIT) {
140          InputStream dataIs = compressedData.getInputStream();
141          ByteArrayOutputStream baos = new ByteArrayOutputStream();
142          Utils.copyStream(dataIs, baos, null);
143          compressedContent_ = baos.toByteArray();
144        }
145    
146        // for testing return the CompressedData as BER encoded byte array with block size of 4
147        ByteArrayOutputStream os = new ByteArrayOutputStream();
148        compressedData.setBlockSize(4);
149        ContentInfoStream cis = new ContentInfoStream(compressedData);
150        cis.writeTo(os);
151        return os.toByteArray();
152      }
153    
154      /**
155       * Parses a CMS <code>CompressedData</code> object.
156       *
157       * @param encoding  the <code>CompressedData</code> object as BER encoded byte array
158       * @param compressedContent the compressed content which was transmitted out-of-band
159       *
160       * @return the decompressed message as byte array
161       *
162       * @throws CMSException if the CompressedData cannot be parsed
163       * @throws IOException if an I/O error occurs
164       * @throws NoSuchAlgorithmException if the compression algorithm is not supported
165       */
166      public byte[] getCompressedDataStream(byte[] encoding, byte[] compressedContent) 
167        throws CMSException, IOException, NoSuchAlgorithmException {
168    
169        System.out.println("Parse CompressedData message.");
170        // we are testing the stream interface
171        ByteArrayInputStream is = new ByteArrayInputStream(encoding);
172        // create the CompressedData object
173        CompressedDataStream compressedData = new CompressedDataStream(is);
174        
175        if (compressedData.getMode() == CompressedDataStream.EXPLICIT) {
176          // in explicit mode now provide the content received by other means
177          compressedData.setInputStream(new ByteArrayInputStream(compressedContent));
178        }
179    
180        // get an InputStream for reading and decompressing the content
181        InputStream data = compressedData.getInputStream();
182        ByteArrayOutputStream os = new ByteArrayOutputStream();
183        Util.copyStream(data, os, null);
184      
185        return os.toByteArray();
186      }
187    
188    
189      /**
190       * Creates a CMS <code>CompressedData</code> object.
191       * <p>
192       *
193       * @param message the message to be compressed, as byte representation
194       * @param mode IMPLICIT (include the compressed content) or 
195       *             EXPLICIT (do not include the compressed content)
196       *
197       * @return the DER encoded <code>CompressedData</code>
198       *
199       * @throws CMSException if the <code>CompressedData</code> object cannot
200       *                          be created
201       * @throws IOException if an I/O error occurs
202       * @throws NoSuchAlgorithmException if the compression algorithm is not supported
203       */
204      public byte[] createCompressedData(byte[] message, int mode)
205        throws CMSException, IOException, NoSuchAlgorithmException {
206    
207        System.out.println("Create a new CompressedData message.");
208    
209        // create a new CompressedData object 
210        CompressedData compressedData = new CompressedData(message, 
211                                                          (AlgorithmID)CMSAlgorithmID.zlib_compress.clone(),
212                                                           mode);
213        // in explicit mode get the compressed content to transmit it by other means
214        if (mode == CompressedData.EXPLICIT) {
215          compressedContent_ = compressedData.getContent();
216        }
217        ContentInfo ci = new ContentInfo(compressedData);
218        return ci.getEncoded();
219      }
220    
221      /**
222       * Parses a CMS <code>CompressedData</code> object.
223       *
224       * @param encoding the DER encoded <code>CompressedData</code> object 
225       * @param compressedContent the compressed content which was transmitted out-of-band
226       *
227       * @return the decompressed message as byte array
228       *
229       * @throws CMSException if the CompressedData cannot be parsed
230       * @throws IOException if an I/O error occurs
231       * @throws NoSuchAlgorithmException if the compression algorithm is not supported
232       */
233      public byte[] getCompressedData(byte[] encoding, byte[] compressedContent) 
234        throws CMSException, IOException, NoSuchAlgorithmException {
235        
236        System.out.println("Parse CompressedData message.");
237        ByteArrayInputStream encodedStream = new ByteArrayInputStream(encoding);
238        // create the CompressedData object
239        CompressedData compressedData = new CompressedData(encodedStream);
240        
241        if (compressedData.getMode() == CompressedData.EXPLICIT) {
242          // in explicit mode provide the compressed content received by other means
243          compressedData.setContent(compressedContent);
244        }
245        // decompress
246        return compressedData.getContent();
247      }
248      
249      /**
250       * Starts the demo.
251       */
252      public void start() {
253         // the test message
254        String m = "ABABABABABABABBABABABABABABABBABABABABABABABBAABABABABABA.";
255        System.out.println("Test message: \""+m+"\"");
256        System.out.println();
257        byte[] message = m.getBytes();
258    
259        try {
260          byte[] encoding;
261          byte[] receivedMessage = null;
262          System.out.println("Stream implementation demos");
263          System.out.println("===========================");
264    
265          // the stream implementation
266       
267          //
268          // test CMS Implicit CompressedDataStream
269          //
270          System.out.println("\nImplicit CompressedDataStream demo [create]\n");
271          encoding = createCompressedDataStream(message, CompressedDataStream.IMPLICIT);
272          // transmit data
273          System.out.println("\nImplicit CompressedDataStream demo [parse]\n");
274          receivedMessage = getCompressedDataStream(encoding, null);
275          if (CryptoUtils.equalsBlock(message, receivedMessage) == false) {
276            throw new CMSException("Decompression error!");
277          }  
278          System.out.print("\nContent: ");
279          System.out.println(new String(receivedMessage));
280    
281          //
282          // test CMS Explicit CompressedDataStream
283          //
284          System.out.println("\nExplicit CompressedDataStream demo [create]\n");
285          encoding = createCompressedDataStream(message, CompressedDataStream.EXPLICIT);
286          // transmit data
287          System.out.println("\nExplicit CompressedDataStream demo [parse]\n");
288          receivedMessage = getCompressedDataStream(encoding, compressedContent_);
289          if (CryptoUtils.equalsBlock(message, receivedMessage) == false) {
290            throw new CMSException("Decompression error!");
291          } 
292          System.out.print("\nContent: ");
293          System.out.println(new String(receivedMessage));
294          
295          // the non-stream implementation
296          System.out.println("\nNon-stream implementation demos");
297          System.out.println("===============================");
298    
299          //
300          // test CMS Implicit CompressedData
301          //
302          System.out.println("\nImplicit CompressedData demo [create]\n");
303          encoding = createCompressedData(message, CompressedData.IMPLICIT);
304          // transmit data
305          System.out.println("\nImplicit CompressedData demo [parse]\n");
306          receivedMessage = getCompressedData(encoding, null);
307          if (CryptoUtils.equalsBlock(message, receivedMessage) == false) {
308            throw new CMSException("Decompression error!");
309          } 
310          System.out.print("\nContent: ");
311          System.out.println(new String(receivedMessage));
312    
313          //
314          // test CMS Explicit CompressedData
315          //
316          System.out.println("\nExplicit CompressedData demo [create]\n");
317          encoding = createCompressedData(message, CompressedData.EXPLICIT);
318          // transmit data
319          System.out.println("\nExplicit CompressedData demo [parse]\n");
320          receivedMessage = getCompressedData(encoding, compressedContent_);
321          if (CryptoUtils.equalsBlock(message, receivedMessage) == false) {
322            throw new CMSException("Decompression error!");
323          } 
324          System.out.print("\nContent: ");
325          System.out.println(new String(receivedMessage));
326          
327            } catch (Exception ex) {
328              ex.printStackTrace();
329              throw new RuntimeException(ex.toString());
330            }
331      }
332    
333      /**
334       * Main method.
335       */
336      public static void main(String argv[]) throws Exception {
337    
338            DemoUtil.initDemos();
339    
340        (new CompressedDataDemo()).start();
341        System.out.println("\nReady!");
342        DemoUtil.waitKey();
343      }
344    }