• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * IndexHash
3  *
4  * Author: Lasse Collin <lasse.collin@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 
IndexHash()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 
add(long unpaddedSize, long uncompressedSize)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 
validate(InputStream in)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         // If Block Header Size was corrupt and became Index Indicator,
54         // this error would actually be about corrupt Block Header.
55         // This is why the error message mentions both possibilities.
56         long storedRecordCount = DecoderUtil.decodeVLI(inChecked);
57         if (storedRecordCount != recordCount)
58             throw new CorruptedInputException(
59                     "XZ Block Header or the start of XZ Index is corrupt");
60 
61         // Decode and hash the Index field and compare it to
62         // the hash value calculated from the decoded Blocks.
63         IndexHash stored = new IndexHash();
64         for (long i = 0; i < recordCount; ++i) {
65             long unpaddedSize = DecoderUtil.decodeVLI(inChecked);
66             long uncompressedSize = DecoderUtil.decodeVLI(inChecked);
67 
68             try {
69                 stored.add(unpaddedSize, uncompressedSize);
70             } catch (XZIOException e) {
71                 throw new CorruptedInputException("XZ Index is corrupt");
72             }
73 
74             if (stored.blocksSum > blocksSum
75                     || stored.uncompressedSum > uncompressedSum
76                     || stored.indexListSize > indexListSize)
77                 throw new CorruptedInputException("XZ Index is corrupt");
78         }
79 
80         if (stored.blocksSum != blocksSum
81                 || stored.uncompressedSum != uncompressedSum
82                 || stored.indexListSize != indexListSize
83                 || !Arrays.equals(stored.hash.finish(), hash.finish()))
84             throw new CorruptedInputException("XZ Index is corrupt");
85 
86         // Index Padding
87         DataInputStream inData = new DataInputStream(inChecked);
88         for (int i = getIndexPaddingSize(); i > 0; --i)
89             if (inData.readUnsignedByte() != 0x00)
90                 throw new CorruptedInputException("XZ Index is corrupt");
91 
92         // CRC32
93         long value = crc32.getValue();
94         for (int i = 0; i < 4; ++i)
95             if (((value >>> (i * 8)) & 0xFF) != inData.readUnsignedByte())
96                 throw new CorruptedInputException("XZ Index is corrupt");
97     }
98 }
99