Home | History | Annotate | Download | only in index
      1 /*
      2  * IndexHash
      3  *
      4  * Author: Lasse Collin <lasse.collin (at) tukaani.org>
      5  *
      6  * This file has been put into the public domain.
      7  * You can do whatever you want with this file.
      8  */
      9 
     10 package org.tukaani.xz.index;
     11 
     12 import java.io.InputStream;
     13 import java.io.DataInputStream;
     14 import java.io.IOException;
     15 import java.nio.ByteBuffer;
     16 import java.util.Arrays;
     17 import java.util.zip.CheckedInputStream;
     18 import org.tukaani.xz.common.DecoderUtil;
     19 import org.tukaani.xz.XZIOException;
     20 import org.tukaani.xz.CorruptedInputException;
     21 
     22 public class IndexHash extends IndexBase {
     23     private org.tukaani.xz.check.Check hash;
     24 
     25     public IndexHash() {
     26         super(new CorruptedInputException());
     27 
     28         try {
     29             hash = new org.tukaani.xz.check.SHA256();
     30         } catch (java.security.NoSuchAlgorithmException e) {
     31             hash = new org.tukaani.xz.check.CRC32();
     32         }
     33     }
     34 
     35     public void add(long unpaddedSize, long uncompressedSize)
     36             throws XZIOException {
     37         super.add(unpaddedSize, uncompressedSize);
     38 
     39         ByteBuffer buf = ByteBuffer.allocate(2 * 8);
     40         buf.putLong(unpaddedSize);
     41         buf.putLong(uncompressedSize);
     42         hash.update(buf.array());
     43     }
     44 
     45     public void validate(InputStream in) throws IOException {
     46         // Index Indicator (0x00) has already been read by BlockInputStream
     47         // so add 0x00 to the CRC32 here.
     48         java.util.zip.CRC32 crc32 = new java.util.zip.CRC32();
     49         crc32.update('\0');
     50         CheckedInputStream inChecked = new CheckedInputStream(in, crc32);
     51 
     52         // Get and validate the Number of Records field.
     53         long storedRecordCount = DecoderUtil.decodeVLI(inChecked);
     54         if (storedRecordCount != recordCount)
     55             throw new CorruptedInputException("XZ Index is corrupt");
     56 
     57         // Decode and hash the Index field and compare it to
     58         // the hash value calculated from the decoded Blocks.
     59         IndexHash stored = new IndexHash();
     60         for (long i = 0; i < recordCount; ++i) {
     61             long unpaddedSize = DecoderUtil.decodeVLI(inChecked);
     62             long uncompressedSize = DecoderUtil.decodeVLI(inChecked);
     63 
     64             try {
     65                 stored.add(unpaddedSize, uncompressedSize);
     66             } catch (XZIOException e) {
     67                 throw new CorruptedInputException("XZ Index is corrupt");
     68             }
     69 
     70             if (stored.blocksSum > blocksSum
     71                     || stored.uncompressedSum > uncompressedSum
     72                     || stored.indexListSize > indexListSize)
     73                 throw new CorruptedInputException("XZ Index is corrupt");
     74         }
     75 
     76         if (stored.blocksSum != blocksSum
     77                 || stored.uncompressedSum != uncompressedSum
     78                 || stored.indexListSize != indexListSize
     79                 || !Arrays.equals(stored.hash.finish(), hash.finish()))
     80             throw new CorruptedInputException("XZ Index is corrupt");
     81 
     82         // Index Padding
     83         DataInputStream inData = new DataInputStream(inChecked);
     84         for (int i = getIndexPaddingSize(); i > 0; --i)
     85             if (inData.readUnsignedByte() != 0x00)
     86                 throw new CorruptedInputException("XZ Index is corrupt");
     87 
     88         // CRC32
     89         long value = crc32.getValue();
     90         for (int i = 0; i < 4; ++i)
     91             if (((value >>> (i * 8)) & 0xFF) != inData.readUnsignedByte())
     92                 throw new CorruptedInputException("XZ Index is corrupt");
     93     }
     94 }
     95