/* * IndexHash * * Author: Lasse Collin * * This file has been put into the public domain. * You can do whatever you want with this file. */ package org.tukaani.xz.index; import java.io.InputStream; import java.io.DataInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.zip.CheckedInputStream; import org.tukaani.xz.common.DecoderUtil; import org.tukaani.xz.XZIOException; import org.tukaani.xz.CorruptedInputException; public class IndexHash extends IndexBase { private org.tukaani.xz.check.Check hash; public IndexHash() { super(new CorruptedInputException()); try { hash = new org.tukaani.xz.check.SHA256(); } catch (java.security.NoSuchAlgorithmException e) { hash = new org.tukaani.xz.check.CRC32(); } } public void add(long unpaddedSize, long uncompressedSize) throws XZIOException { super.add(unpaddedSize, uncompressedSize); ByteBuffer buf = ByteBuffer.allocate(2 * 8); buf.putLong(unpaddedSize); buf.putLong(uncompressedSize); hash.update(buf.array()); } public void validate(InputStream in) throws IOException { // Index Indicator (0x00) has already been read by BlockInputStream // so add 0x00 to the CRC32 here. java.util.zip.CRC32 crc32 = new java.util.zip.CRC32(); crc32.update('\0'); CheckedInputStream inChecked = new CheckedInputStream(in, crc32); // Get and validate the Number of Records field. long storedRecordCount = DecoderUtil.decodeVLI(inChecked); if (storedRecordCount != recordCount) throw new CorruptedInputException("XZ Index is corrupt"); // Decode and hash the Index field and compare it to // the hash value calculated from the decoded Blocks. IndexHash stored = new IndexHash(); for (long i = 0; i < recordCount; ++i) { long unpaddedSize = DecoderUtil.decodeVLI(inChecked); long uncompressedSize = DecoderUtil.decodeVLI(inChecked); try { stored.add(unpaddedSize, uncompressedSize); } catch (XZIOException e) { throw new CorruptedInputException("XZ Index is corrupt"); } if (stored.blocksSum > blocksSum || stored.uncompressedSum > uncompressedSum || stored.indexListSize > indexListSize) throw new CorruptedInputException("XZ Index is corrupt"); } if (stored.blocksSum != blocksSum || stored.uncompressedSum != uncompressedSum || stored.indexListSize != indexListSize || !Arrays.equals(stored.hash.finish(), hash.finish())) throw new CorruptedInputException("XZ Index is corrupt"); // Index Padding DataInputStream inData = new DataInputStream(inChecked); for (int i = getIndexPaddingSize(); i > 0; --i) if (inData.readUnsignedByte() != 0x00) throw new CorruptedInputException("XZ Index is corrupt"); // CRC32 long value = crc32.getValue(); for (int i = 0; i < 4; ++i) if (((value >>> (i * 8)) & 0xFF) != inData.readUnsignedByte()) throw new CorruptedInputException("XZ Index is corrupt"); } }