public void VerifyHashGenerationV1(byte[] content, Content_Information_Data_Structure contentInfo)
        {
            const int BLOCKBYTECOUNT    = 0x10000;
            const int SEGMENTBLOCKCOUNT = 512;

            dwHashAlgo_Values hashAlgo = contentInfo.dwHashAlgo;

            int blockTotalCount = content.Length / BLOCKBYTECOUNT;

            if (content.Length > BLOCKBYTECOUNT * blockTotalCount)
            {
                blockTotalCount = blockTotalCount + 1;
            }

            int segmentCount = blockTotalCount / SEGMENTBLOCKCOUNT;

            if (blockTotalCount > SEGMENTBLOCKCOUNT * segmentCount)
            {
                segmentCount = segmentCount + 1;
            }

            HashAlgorithm hashAlgorithm;
            HMAC          hmacAlgorithm;
            int           blockHashSize;

            PccrcUtility.GetHashAlgorithm(hashAlgo, out hashAlgorithm, out hmacAlgorithm, out blockHashSize);
            hmacAlgorithm.Key = hashAlgorithm.ComputeHash(testConfig.ServerSecret);

            for (int segmentIndex = 0; segmentIndex < segmentCount; segmentIndex++)
            {
                List <byte> blockHashList = new List <byte>();

                int blockCount = (segmentIndex == segmentCount - 1) ? (blockTotalCount % SEGMENTBLOCKCOUNT) : (SEGMENTBLOCKCOUNT);

                for (int blockIndex = 0; blockIndex < blockCount; blockIndex++)
                {
                    var block = content.Skip(BLOCKBYTECOUNT * SEGMENTBLOCKCOUNT * segmentIndex + BLOCKBYTECOUNT * blockIndex).Take(BLOCKBYTECOUNT).ToArray();

                    byte[] blockHash = hashAlgorithm.ComputeHash(block);

                    testSite.Assert.IsTrue(
                        blockHash.SequenceEqual((contentInfo.blocks[segmentIndex].BlockHashes).Skip(blockIndex * blockHashSize).Take(blockHashSize).ToArray()),
                        "The local calculated block hash in Segment: {0} Block: {1} should cosistent with the received value.", segmentIndex, blockIndex);

                    blockHashList.AddRange(blockHash);
                }

                byte[] hod = hashAlgorithm.ComputeHash(blockHashList.ToArray());

                testSite.Assert.IsTrue(
                    hod.SequenceEqual(contentInfo.segments[segmentIndex].SegmentHashOfData),
                    "The local calculated Hod should cosistent with the received value.");

                byte[] kp = hmacAlgorithm.ComputeHash(hod);

                testSite.Assert.IsTrue(
                    kp.SequenceEqual(contentInfo.segments[segmentIndex].SegmentSecret),
                    "The local calculated Kp should cosistent with the received value.");
            }
        }
        /// <summary>
        /// Get the hash algorithm and hmac algorithm for V1.
        /// </summary>
        /// <param name="hashAlgo">The hash algorithm value</param>
        /// <returns>The hash algorithm and hmac algorithm</returns>
        public static void GetHashAlgorithm(dwHashAlgo_Values hashAlgo, out HashAlgorithm hashAlgorithm, out HMAC hmacAlgorithm, out int blockHashSize)
        {
            switch (hashAlgo)
            {
            case dwHashAlgo_Values.SHA256:
                hashAlgorithm = HashAlgorithm.Create("SHA256");
                hmacAlgorithm = HMAC.Create("HMACSHA256");
                blockHashSize = 32;
                break;

            case dwHashAlgo_Values.SHA384:
                hashAlgorithm = HashAlgorithm.Create("SHA384");
                hmacAlgorithm = HMAC.Create("HMACSHA384");
                blockHashSize = 48;
                break;

            case dwHashAlgo_Values.SHA512:
                hashAlgorithm = HashAlgorithm.Create("SHA512");
                hmacAlgorithm = HMAC.Create("HMACSHA512");
                blockHashSize = 64;
                break;

            default:
                throw new NotImplementedException();
            }
        }
        /// <summary>
        /// Compute the segment HoD.
        /// </summary>
        /// <param name="kp">The Kp data</param>
        /// <param name="hod">The segment HoD</param>
        /// <param name="hashAlgo">The HoHoDk hash algorithm.</param>
        /// <returns>The HoHoDk data</returns>
        public static byte[] GetHoHoDkBytes(byte[] kp, byte[] hod, dwHashAlgo_Values hashAlgo)
        {
            HMAC        hohodkAlgo = null;
            List <byte> tempList   = new List <byte>();

            switch (hashAlgo)
            {
            case dwHashAlgo_Values.SHA256:
                hohodkAlgo = HMAC.Create(ALGOHMACSHA256);
                break;

            case dwHashAlgo_Values.SHA384:
                hohodkAlgo = HMAC.Create(ALGOHMACSHA384);
                break;

            case dwHashAlgo_Values.SHA512:
                hohodkAlgo = HMAC.Create(ALGOHMACSHA512);
                break;

            default:
                throw new NotImplementedException();
            }

            hohodkAlgo.Key = kp;
            tempList.AddRange(hod);
            tempList.AddRange(Encoding.Unicode.GetBytes(HOHODKAPPENDSTRING));
            var hash = hohodkAlgo.ComputeHash(tempList.ToArray());

            return(hash);
        }
        /// <summary>
        /// Convert the structure to byte array.
        /// </summary>
        /// <param name="algo">The hash algorithm to use.</param>
        /// <returns>The byte array.</returns>
        public byte[] ToByteArray(dwHashAlgo_Values algo)
        {
            List <byte> byteList = new List <byte>();

            byteList.Add((byte)this.cBlocks);
            byteList.Add((byte)(this.cBlocks >> 8));
            byteList.Add((byte)(this.cBlocks >> 16));
            byteList.Add((byte)(this.cBlocks >> 24));

            byteList.AddRange(this.BlockHashes);

            return(byteList.ToArray());
        }
        /// <summary>
        /// Parse the information of the block.
        /// </summary>
        /// <param name="dwHashAlgo">The hash algorithm to use.</param>
        /// <param name="cSegments">The number of segments which intersect the content range and hence are contained
        /// in the Content Information structure.</param>
        /// <param name="data">The byte data in little-endian order.</param>
        /// <param name="index">The start index.</param>
        /// <returns>Returns the block infromation.</returns>
        private static SegmentContentBlocks[] ParseBlocks(
            dwHashAlgo_Values dwHashAlgo,
            uint cSegments,
            byte[] data,
            ref int index)
        {
            SegmentContentBlocks[] retBlocks = new SegmentContentBlocks[cSegments];
            int dataSize = GetDataSizeByHashAlgo(dwHashAlgo);

            for (int i = 0; i < retBlocks.Length; i++)
            {
                retBlocks[i].cBlocks     = GetUInt32(data, ref index);
                retBlocks[i].BlockHashes = GetBytes(
                    data,
                    ref index,
                    (int)(dataSize * retBlocks[i].cBlocks));
            }

            return(retBlocks);
        }
        /// <summary>
        /// Get data size by hash algorithm.
        /// </summary>
        /// <param name="dwHashAlgo">The hash algorithm</param>
        /// <returns>The data size</returns>
        private static int GetDataSizeByHashAlgo(dwHashAlgo_Values dwHashAlgo)
        {
            int dataSize = 0;

            switch (dwHashAlgo)
            {
            case dwHashAlgo_Values.SHA256:
                dataSize = 32;
                break;

            case dwHashAlgo_Values.SHA384:
                dataSize = 48;
                break;

            case dwHashAlgo_Values.SHA512:
                dataSize = 64;
                break;
            }

            return(dataSize);
        }
        /// <summary>
        /// Parse the information of segment.
        /// </summary>
        /// <param name="dwHashAlgo">The hash algorithm to use.</param>
        /// <param name="cSegments">The number of segments which intersect the content range and hence are contained
        /// in the Content Information structure.</param>
        /// <param name="data">The byte data.</param>
        /// <param name="index">The start index.</param>
        /// <returns>Returns the segment infromation.</returns>
        private static SegmentDescription[] ParseSements(
            dwHashAlgo_Values dwHashAlgo,
            uint cSegments,
            byte[] data,
            ref int index)
        {
            SegmentDescription[] retSegments = new SegmentDescription[cSegments];
            int dataSize = GetDataSizeByHashAlgo(dwHashAlgo);

            for (int i = 0; i < retSegments.Length; i++)
            {
                retSegments[i].ullOffsetInContent = GetUInt64(data, ref index);
                retSegments[i].cbSegment          = GetUInt32(data, ref index);
                retSegments[i].cbBlockSize        = GetUInt32(data, ref index);
                byte[] tempSegmentHashOfData = GetBytes(data, ref index, dataSize);
                retSegments[i].SegmentHashOfData = tempSegmentHashOfData;
                byte[] tempSegmentSecret = GetBytes(data, ref index, dataSize);
                retSegments[i].SegmentSecret = tempSegmentSecret;
            }

            return(retSegments);
        }
 /// <summary>
 /// Get the hash algorithm and hmac algorithm for V1.
 /// </summary>
 /// <param name="hashAlgo">The hash algorithm value</param>
 /// <returns>The hash algorithm and hmac algorithm</returns>
 public static void GetHashAlgorithm(dwHashAlgo_Values hashAlgo, out HashAlgorithm hashAlgorithm, out HMAC hmacAlgorithm, out int blockHashSize)
 {
     switch (hashAlgo)
     {
         case dwHashAlgo_Values.SHA256:
             hashAlgorithm = HashAlgorithm.Create("SHA256");
             hmacAlgorithm = HMAC.Create("HMACSHA256");
             blockHashSize = 32;
             break;
         case dwHashAlgo_Values.SHA384:
             hashAlgorithm = HashAlgorithm.Create("SHA384");
             hmacAlgorithm = HMAC.Create("HMACSHA384");
             blockHashSize = 48;
             break;
         case dwHashAlgo_Values.SHA512:
             hashAlgorithm = HashAlgorithm.Create("SHA512");
             hmacAlgorithm = HMAC.Create("HMACSHA512");
             blockHashSize = 64;
             break;
         default:
             throw new NotImplementedException();
     }
 }
        /// <summary>
        /// Compute the segment HoD.
        /// </summary>
        /// <param name="kp">The Kp data</param>
        /// <param name="hod">The segment HoD</param>
        /// <param name="hashAlgo">The HoHoDk hash algorithm.</param>
        /// <returns>The HoHoDk data</returns>
        public static byte[] GetHoHoDkBytes(byte[] kp, byte[] hod, dwHashAlgo_Values hashAlgo)
        {
            HMAC hohodkAlgo = null;
            List<byte> tempList = new List<byte>();
            switch (hashAlgo)
            {
                case dwHashAlgo_Values.SHA256:
                    hohodkAlgo = HMAC.Create(ALGOHMACSHA256);
                    break;
                case dwHashAlgo_Values.SHA384:
                    hohodkAlgo = HMAC.Create(ALGOHMACSHA384);
                    break;
                case dwHashAlgo_Values.SHA512:
                    hohodkAlgo = HMAC.Create(ALGOHMACSHA512);
                    break;
                default:
                    throw new NotImplementedException();
            }

            hohodkAlgo.Key = kp;
            tempList.AddRange(hod);
            tempList.AddRange(Encoding.Unicode.GetBytes(HOHODKAPPENDSTRING));
            var hash = hohodkAlgo.ComputeHash(tempList.ToArray());

            return hash;
        }
        /// <summary>
        /// Convert the structure to byte array.
        /// </summary>
        /// <param name="algo">The hash algorithm to use.</param>
        /// <returns>The byte array.</returns>
        public byte[] ToByteArray(dwHashAlgo_Values algo)
        {
            List<byte> byteList = new List<byte>();

            byteList.Add((byte)this.cBlocks);
            byteList.Add((byte)(this.cBlocks >> 8));
            byteList.Add((byte)(this.cBlocks >> 16));
            byteList.Add((byte)(this.cBlocks >> 24));

            byteList.AddRange(this.BlockHashes);

            return byteList.ToArray();
        }
        /// <summary>
        /// Get data size by hash algorithm.
        /// </summary>
        /// <param name="dwHashAlgo">The hash algorithm</param>
        /// <returns>The data size</returns>
        private static int GetDataSizeByHashAlgo(dwHashAlgo_Values dwHashAlgo)
        {
            int dataSize = 0;
            switch (dwHashAlgo)
            {
                case dwHashAlgo_Values.SHA256:
                    dataSize = 32;
                    break;
                case dwHashAlgo_Values.SHA384:
                    dataSize = 48;
                    break;
                case dwHashAlgo_Values.SHA512:
                    dataSize = 64;
                    break;
            }

            return dataSize;
        }
 /// <summary>
 /// Compute the segment HoD.
 /// </summary>
 /// <param name="kp">The Kp data</param>
 /// <param name="hod">The segment HoD</param>
 /// <param name="hashAlgo">The HoHoDk hash algorithm.</param>
 /// <returns>The HoHoDk data</returns>
 public static string GetHoHoDkString(byte[] kp, byte[] hod, dwHashAlgo_Values hashAlgo)
 {
     byte[] hohodk = GetHoHoDkBytes(kp, hod, hashAlgo);
     return ToHexString(hohodk);
 }
        /// <summary>
        /// Parse the information of the block.
        /// </summary>
        /// <param name="dwHashAlgo">The hash algorithm to use.</param>
        /// <param name="cSegments">The number of segments which intersect the content range and hence are contained 
        /// in the Content Information structure.</param>
        /// <param name="data">The byte data in little-endian order.</param>
        /// <param name="index">The start index.</param>
        /// <returns>Returns the block infromation.</returns>
        private static SegmentContentBlocks[] ParseBlocks(
            dwHashAlgo_Values dwHashAlgo,
            uint cSegments,
            byte[] data,
            ref int index)
        {
            SegmentContentBlocks[] retBlocks = new SegmentContentBlocks[cSegments];
            int dataSize = GetDataSizeByHashAlgo(dwHashAlgo);
            for (int i = 0; i < retBlocks.Length; i++)
            {
                retBlocks[i].cBlocks = GetUInt32(data, ref index);
                retBlocks[i].BlockHashes = GetBytes(
                    data,
                    ref index,
                    (int)(dataSize * retBlocks[i].cBlocks));
            }

            return retBlocks;
        }
 /// <summary>
 /// Compute the segment HoD.
 /// </summary>
 /// <param name="kp">The Kp data</param>
 /// <param name="hod">The segment HoD</param>
 /// <param name="hashAlgo">The HoHoDk hash algorithm.</param>
 /// <returns>The HoHoDk data</returns>
 public static string GetHoHoDkString(byte[] kp, byte[] hod, dwHashAlgo_Values hashAlgo)
 {
     byte[] hohodk = GetHoHoDkBytes(kp, hod, hashAlgo);
     return(ToHexString(hohodk));
 }
        /// <summary>
        /// Parse the information of segment.
        /// </summary>
        /// <param name="dwHashAlgo">The hash algorithm to use.</param>
        /// <param name="cSegments">The number of segments which intersect the content range and hence are contained 
        /// in the Content Information structure.</param>
        /// <param name="data">The byte data.</param>
        /// <param name="index">The start index.</param>
        /// <returns>Returns the segment infromation.</returns>
        private static SegmentDescription[] ParseSements(
            dwHashAlgo_Values dwHashAlgo,
            uint cSegments,
            byte[] data,
            ref int index)
        {
            SegmentDescription[] retSegments = new SegmentDescription[cSegments];
            int dataSize = GetDataSizeByHashAlgo(dwHashAlgo);
            for (int i = 0; i < retSegments.Length; i++)
            {
                retSegments[i].ullOffsetInContent = GetUInt64(data, ref index);
                retSegments[i].cbSegment = GetUInt32(data, ref index);
                retSegments[i].cbBlockSize = GetUInt32(data, ref index);
                byte[] tempSegmentHashOfData = GetBytes(data, ref index, dataSize);
                retSegments[i].SegmentHashOfData = tempSegmentHashOfData;
                byte[] tempSegmentSecret = GetBytes(data, ref index, dataSize);
                retSegments[i].SegmentSecret = tempSegmentSecret;
            }

            return retSegments;
        }
 /// <summary>
 /// Initializes a new instance of the HashGeneration class with server secret and hash algorithm.
 /// </summary>
 /// <param name="secret">The unicode string of the server secret.</param>
 /// <param name="algo">The hash algorithm.</param>
 public HashGeneration(string secret, dwHashAlgo_Values algo)
 {
     this.ServerSecret = Encoding.Unicode.GetBytes(secret);
     this.DwHashAlgo = algo;
 }
 /// <summary>
 /// Initializes a new instance of the HashGeneration class with server secret and hash algorithm.
 /// </summary>
 /// <param name="secret">The binary array of the server secret.</param>
 /// <param name="algo">The hash algorithm.</param>
 public HashGeneration(byte[] secret, dwHashAlgo_Values algo)
 {
     this.ServerSecret = secret;
     this.DwHashAlgo   = algo;
 }
 /// <summary>
 /// Initializes a new instance of the HashGeneration class with server secret and hash algorithm.
 /// </summary>
 /// <param name="secret">The unicode string of the server secret.</param>
 /// <param name="algo">The hash algorithm.</param>
 public HashGeneration(string secret, dwHashAlgo_Values algo)
 {
     this.ServerSecret = Encoding.Unicode.GetBytes(secret);
     this.DwHashAlgo   = algo;
 }
 /// <summary>
 /// Initializes a new instance of the HashGeneration class with server secret and hash algorithm.
 /// </summary>
 /// <param name="secret">The binary array of the server secret.</param>
 /// <param name="algo">The hash algorithm.</param>
 public HashGeneration(byte[] secret, dwHashAlgo_Values algo)
 {
     this.ServerSecret = secret;
     this.DwHashAlgo = algo;
 }