/// <summary>
        ///     Calculates the whirlpool digest of the specified buffer.
        /// </summary>
        /// <param name="buf"> The buffer. </param>
        /// <returns> The 64-byte whirlpool digest. </returns>
        public static byte[] GetWhirlpoolDigest(this ByteBuffer buf)
        {
            var bytes = new byte[buf.limit()];

            buf.get(bytes);
            return(Whirlpool.Crypt(bytes, 0, bytes.Length));
        }
        /// <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);
        }
        /// <summary>
        ///     Encodes this <seealso cref="ChecksumTable" /> and encrypts the final whirlpool hash.
        /// </summary>
        /// <param name="whirlpool"> If whirlpool digests should be encoded. </param>
        /// <param name="modulus"> The modulus. </param>
        /// <param name="privateKey"> The private key. </param>
        /// <returns> The encoded <seealso cref="ByteBuffer" />. </returns>
        /// <exception cref="IOException"> if an I/O error occurs. </exception>
        public virtual ByteBuffer Encode(bool whirlpool, BigInteger modulus, BigInteger privateKey)
        {
            var bout = new ByteArrayOutputStream();
            var os   = new DataOutputStream(bout);

            try
            {
                /* as the new whirlpool format is more complicated we must write the number of entries */
                if (whirlpool)
                {
                    os.write(entries.Length);
                }

                /* encode the individual entries */
                for (var i = 0; i < entries.Length; i++)
                {
                    var entry = entries[i];
                    os.writeInt(entry.GetCrc());
                    os.writeInt(entry.GetVersion());
                    if (whirlpool)
                    {
                        os.write(entry.GetWhirlpool());
                    }
                }

                /* compute (and encrypt) the digest of the whole table */
                byte[] bytes;
                if (whirlpool)
                {
                    bytes = bout.toByteArray();
                    var temp = ByteBuffer.allocate(66);
                    temp.put(0);
                    temp.put(Whirlpool.Crypt(bytes, 5, bytes.Length - 5));
                    temp.put(0);
                    temp.flip();

                    if (modulus != null && privateKey != null)
                    {
                        temp = Rsa.Crypt(temp, modulus, privateKey);
                    }

                    bytes = new byte[temp.limit()];
                    temp.get(bytes);
                    os.write(bytes);
                }

                bytes = bout.toByteArray();
                return(ByteBuffer.wrap(bytes));
            }
            finally
            {
                os.close();
            }
        }
示例#4
0
        /// <summary>
        ///     Writes a file to the cache and updates the <seealso cref="ReferenceTable" /> that
        ///     it is associated with.
        /// </summary>
        /// <param name="type"> The type of file. </param>
        /// <param name="file"> The file id. </param>
        /// <param name="container"> The <seealso cref="Container" /> to write. </param>
        /// <exception cref="IOException"> if an I/O error occurs. </exception>
        public void Write(int type, int file, Container container)
        {
            /* we don't want people reading/manipulating these manually */
            if (type == 255)
            {
                throw new IOException("Reference tables can only be modified with the low level FileStore API!");
            }

            /* increment the container's version */
            container.SetVersion(container.GetVersion() + 1);

            /* decode the reference table for this index */
            var tableContainer = Container.Decode(store.Read(255, type));
            var table          = ReferenceTable.Decode(tableContainer.GetData());

            /* grab the bytes we need for the checksum */
            var buffer = container.Encode();
            var bytes  = new byte[buffer.limit() - 2]; // last two bytes are the version and shouldn't be included

            buffer.mark();
            try
            {
                buffer.position(0);
                buffer.get(bytes, 0, bytes.Length);
            }
            finally
            {
                buffer.reset();
            }

            /* calculate the new CRC checksum */
            var crc = new CRC32();

            crc.update(bytes, 0, bytes.Length);

            /* update the version and checksum for this file */
            var entry = table.GetEntry(file);

            if (entry == null)
            {
                /* create a new entry for the file */
                entry = new ReferenceTable.Entry();
                table.PutEntry(file, entry);
            }
            entry.SetVersion(container.GetVersion());
            entry.SetCrc((int)crc.getValue());

            /* calculate and update the whirlpool digest if we need to */
            if ((table.GetFlags() & ReferenceTable.FLAG_WHIRLPOOL) != 0)
            {
                var whirlpool = Whirlpool.Crypt(bytes, 0, bytes.Length);
                entry.SetWhirlpool(whirlpool);
            }

            /* update the reference table version */
            table.SetVersion(table.GetVersion() + 1);

            /* save the reference table */
            tableContainer = new Container(tableContainer.GetType(), table.Encode());
            store.Write(255, type, tableContainer.Encode());

            /* save the file itself */
            store.Write(type, file, buffer);
        }