/// <summary> /// Computes the <seealso cref="ChecksumTable" /> for this cache. The checksum table /// forms part of the so-called "update keys". /// </summary> /// <returns> The <seealso cref="ChecksumTable" />. </returns> /// <exception cref="IOException"> if an I/O error occurs. </exception> public ChecksumTable CreateChecksumTable() { /* create the checksum table */ var size = store.GetTypeCount(); var table = new ChecksumTable(size); /* loop through all the reference tables and get their CRC and versions */ for (var i = 0; i < size; i++) { var buf = store.Read(255, i); var crc = 0; var version = 0; var whirlpool = new byte[64]; /* * if there is actually a reference table, calculate the CRC, * version and whirlpool hash */ if (buf.limit() > 0) // some indices are not used, is this appropriate? { var @ref = ReferenceTable.Decode(Container.Decode(buf) .GetData()); crc = ByteBufferExtensions.GetCrcChecksum(buf); version = @ref.GetVersion(); buf.position(0); whirlpool = ByteBufferExtensions.GetWhirlpoolDigest(buf); } table.SetEntry(i, new ChecksumTable.Entry(crc, version, whirlpool)); } /* return the table */ return(table); }
/// <summary> /// Decodes the <seealso cref="ChecksumTable" /> in the specified /// <seealso cref="ByteBuffer" /> and decrypts the final whirlpool hash. /// </summary> /// <param name="buffer"> The <seealso cref="ByteBuffer" /> containing the table. </param> /// <param name="whirlpool"> If whirlpool digests should be read. </param> /// <param name="modulus"> The modulus. </param> /// <param name="publicKey"> The public key. </param> /// <returns> The decoded <seealso cref="ChecksumTable" />. </returns> /// <exception cref="IOException"> if an I/O error occurs. </exception> public static ChecksumTable Decode(ByteBuffer buffer, bool whirlpool, BigInteger modulus, BigInteger publicKey) { /* find out how many entries there are and allocate a new table */ var size = whirlpool ? (buffer.limit() / 8) : (buffer.get() & 0xFF); var table = new ChecksumTable(size); /* calculate the whirlpool digest we expect to have at the end */ byte[] masterDigest = null; if (whirlpool) { var temp = new byte[size * 72 + 1]; buffer.position(0); buffer.get(temp); masterDigest = Whirlpool.Crypt(temp, 0, temp.Length); } /* read the entries */ buffer.position(1); for (var i = 0; i < size; i++) { var crc = buffer.getInt(); var version = buffer.getInt(); var digest = new byte[64]; if (whirlpool) { buffer.get(digest); } table.entries[i] = new Entry(crc, version, digest); } /* read the trailing digest and check if it matches up */ if (whirlpool) { var bytes = new byte[buffer.remaining()]; buffer.get(bytes); var temp = ByteBuffer.wrap(bytes); if (modulus != null && publicKey != null) { temp = Rsa.Crypt(buffer, modulus, publicKey); } if (temp.limit() != 66) { throw new IOException("Decrypted data is not 66 bytes long"); } for (var i = 0; i < 64; i++) { if (temp.get(i + 1) != masterDigest[i]) { throw new IOException("Whirlpool digest mismatch"); } } } /* if it looks good return the table */ return(table); }