Content Information is a variable size data structure. Content Information size is proportional to the length of the content it represents. Content Information starts with a single 2 byte WORD value representing the data structure version. Version 1.0 of the Content Information data structure is formatted as follows. All fields are in host byte order.
        /// <summary>
        /// Parse the information of the content
        /// </summary>
        /// <param name="data">The byte data in little-endian order.</param>
        /// <param name="index">The start index.</param>
        /// <returns>Returns the content information data structure.</returns>
        public static Content_Information_Data_Structure ParseContentInformation(byte[] data, ref int index)
        {
            Content_Information_Data_Structure contentInfo = new Content_Information_Data_Structure();

            byte[] informationData = GetBytes(data, ref index, data.Length - index);
            int    tempIndex       = 0;

            contentInfo.Version                  = GetUInt16(informationData, ref tempIndex);
            contentInfo.dwHashAlgo               = (dwHashAlgo_Values)GetUInt32(informationData, ref tempIndex);
            contentInfo.dwOffsetInFirstSegment   = GetUInt32(informationData, ref tempIndex);
            contentInfo.dwReadBytesInLastSegment = GetUInt32(informationData, ref tempIndex);
            contentInfo.cSegments                = GetUInt32(informationData, ref tempIndex);
            contentInfo.segments                 = ParseSements(
                contentInfo.dwHashAlgo,
                contentInfo.cSegments,
                informationData,
                ref tempIndex);
            contentInfo.blocks = ParseBlocks(
                contentInfo.dwHashAlgo,
                contentInfo.cSegments,
                informationData,
                ref tempIndex);

            return(contentInfo);
        }
        /// <summary>
        /// Convert the ContentInformaiton struct defined in stack to adapter
        /// </summary>
        /// <param name="contentInfoStack">The contentInformation  defined in pccrc</param>
        /// <returns>Return the ContentInformaiton type defined in adapter</returns>
        public static SegmentInformation ConvertFromstackForContentInfo(Content_Information_Data_Structure contentInfoStack)
        {
            SegmentInformation contentInfo;
            contentInfo.DwHashAlgo = ConvertFromStackFordwHash(contentInfoStack.dwHashAlgo);
            contentInfo.DwOffsetInFirstSegment = contentInfoStack.dwOffsetInFirstSegment;
            contentInfo.DwReadBytesInLastSegment = contentInfoStack.dwReadBytesInLastSegment;
            contentInfo.Version = contentInfoStack.Version;
            contentInfo.CSegments = contentInfoStack.cSegments;
            contentInfo.Blocks = ConvertFromStackForSegBlocks(contentInfoStack.blocks);
            contentInfo.Segments = ConvertFromStackForSegDescription(contentInfoStack.segments);

            return contentInfo;
        }
        /// <summary>
        /// Validate the segmentInformation In SEGMTNE_INFO_MESSAGE.
        /// </summary>
        /// <param name="segmentInformation">The segmetnInformation.</param>
        private void ValidateSegmentInformationFromPccrc(Content_Information_Data_Structure segmentInformation)
        {
            int valueOfDwHashAlgo = 0;
            int hashLength = 0;
            switch (segmentInformation.dwHashAlgo)
            {
                case dwHashAlgo_Values.V1:
                    valueOfDwHashAlgo = 0x0000800C;
                    hashLength = 32;
                    break;
                case dwHashAlgo_Values.V2:
                    hashLength = 48;
                    valueOfDwHashAlgo = 0x0000800D;
                    break;
                case dwHashAlgo_Values.V3:
                    hashLength = 64;
                    valueOfDwHashAlgo = 0x0000800E;
                    break;
                default:
                    break;
            }

            #region MS-PCCRC_R54
            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R54, all fields are {0}in little-endian byte order",
                BitConverter.IsLittleEndian ? string.Empty : "not ");

            // Verify MS-PCCRC requirement: MS-PCCRC_R54
            Site.CaptureRequirementIfIsTrue(
                BitConverter.IsLittleEndian,
                PCCRCDOCSHORTNAME,
                54,
                @"[In Content Information Data Structure Version] All fields[Version,dwHashAlgo,
                dwOffsetInFirstSegment,dwReadBytesInLastSegment,cSegments,segments (variable),
                blocks (variable)]  are in little-endian byte order.");

            #endregion

            #region MS-PCCRC_R55
            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R55, the actual value of Version is 0x{0:X8}",
                segmentInformation.Version);

            // Verify MS-PCCRC requirement: MS-PCCRC_R55
            Site.CaptureRequirementIfAreEqual<int>(
                0x0100,
                segmentInformation.Version,
                PCCRCDOCSHORTNAME,
                55,
                @"[In Content Information Data Structure Version] Version (2 bytes):  Content Information
                version (0x0100 is version 1.0).");

            #endregion

            this.ValidatePccrcSegmentInfoVersion(segmentInformation, valueOfDwHashAlgo, hashLength);

            this.ValidatePccrcCSegment(segmentInformation, hashLength);

            #region MS-PCCRC_R86

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R86, the actual number of SegmentContentBlocks fields in blocks field is {0}",
                segmentInformation.blocks.Length);

            // Verify MS-PCCRC requirement: MS-PCCRC_R86
            Site.CaptureRequirementIfAreEqual<uint>(
                segmentInformation.cSegments,
                (uint)segmentInformation.blocks.Length,
                PCCRCDOCSHORTNAME,
                86,
                @"[In SegmentContentBlocks] The blocks field contains a number cSegments of
                SegmentContentBlocks fields.");

            #endregion

            #region MS-PCCRC_R89

            bool isVerifyR89 = true;

            foreach (SegmentContentBlocks segContentBlocks in segmentInformation.blocks)
            {
                if (segContentBlocks.BlockHashes.Length != segContentBlocks.cBlocks * hashLength)
                {
                    isVerifyR89 = false;
                    break;
                }
            }

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R89, the actual size of BlockHashes field is {0} cBlokcs * {1}",
                isVerifyR89 ? string.Empty : "not ",
                hashLength);

            // Verify MS-PCCRC requirement: MS-PCCRC_R89
            Site.CaptureRequirementIfIsTrue(
                isVerifyR89,
                PCCRCDOCSHORTNAME,
                89,
                @"[In SegmentContentBlocks] BlockHashes (variable):The size of this field is
                cBlocks * (32, 48 or 64, depending on which hash was used).");
            #endregion
        }
        /// <summary>
        /// Validate the SegmentInformation in the Segment_info-Message.
        /// </summary>
        /// <param name="segmentInformation">The segmentInformation need to be validate.</param>
        private void ValidateSegmentInformation(Content_Information_Data_Structure segmentInformation)
        {
            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCHC_R43:The SegmentInformation is an instance of  Content_Information_Data_Structure.");

            // Capture MS-PCHC R43
            Site.CaptureRequirement(
                43,
                @"[In SEGMENT_INFO_MESSAGE] SegmentInformation (variable):
                A Content Information data structure ([MS-PCCRC] section 2.3).");

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCHC_R45:The SegmentInformation is an instance of Content_Information_Data_Structure
                which surely contains the subfields of the segment's Content Information data structure,
                and SegmentContentBlocks. And can be validated unmarshalled correctly from stack.");

            // Capture MS-PCHC R45
            Site.CaptureRequirement(
                45,
                @"[In SEGMENT_INFO_MESSAGE] The SegmentInformation field also contains the subfields of
                the segment's Content Information data structure, SegmentDescription, and SegmentContentBlocks,
                as specified in [MS-PCCRC] sections 2.3.1.1 and 2.3.1.2, respectively.");

            // Capture MS-PCHC R49
            Site.CaptureRequirementIfAreEqual<uint>(
                1,
                segmentInformation.cSegments,
                49,
                "[In SEGMENT_INFO_MESSAGE, SEGMENT_INFORMATION (variable)] The cSegments field MUST be set to 1.");

            // Capture MS-PCHC R50
            Site.Assert.IsInstanceOfType(
                segmentInformation.segments,
                typeof(SegmentDescription[]),
                @"Validate the segments is SegmentDescription array, in MS-PCHC client,
                only the size of the SegmentDescription will be verified,the actual is {0} array.",
                segmentInformation.segments);

            Site.CaptureRequirementIfAreEqual<int>(
                1,
                segmentInformation.segments.Length,
                50,
                @"[In SEGMENT_INFO_MESSAGE, SEGMENT_INFORMATION (variable)] The segments field MUST contain the single
                SegmentDescription ([MS-PCCRC] section 2.3.1.1) in the original Content Information data structure
                corresponding to the segment being offered.");

            // Capture MS-PCHC R51
            Site.Assert.IsInstanceOfType(
                segmentInformation.blocks,
                typeof(SegmentContentBlocks[]),
                @"Validate the blocks is SegmentContentBlocks array, in MS-PCHC client,
                only the size of the SegmentContentBlocks will be verified, the actual is {0} array.",
                segmentInformation.blocks);

            Site.CaptureRequirementIfAreEqual<int>(
                1,
                segmentInformation.blocks.Length,
                51,
                @"[In SEGMENT_INFO_MESSAGE, SEGMENT_INFORMATION (variable)] The blocks field MUST
                contain a single SegmentContentBlocks ([MS-PCCRC] section 2.3.1.2) corresponding
                to the segment being offered, copied from the blocks field in the original
                Content Information data structure.");
        }
        /// <summary>
        /// Validate pccrc segment info version part.
        /// </summary>
        /// <param name="segmentInformation">Content Information data structure.</param>
        /// <param name="valueOfDwHashAlgo">Value of DwHashAlgo.</param>
        /// <param name="hashLength">The length of hash.</param>
        private void ValidatePccrcSegmentInfoVersion(Content_Information_Data_Structure segmentInformation, int valueOfDwHashAlgo, int hashLength)
        {
            #region MS-PCCRC_R57

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R57, the actual value of Version is 0x{0:X8}",
                segmentInformation.Version);

            // Verify MS-PCCRC requirement: MS-PCCRC_R57
            Site.CaptureRequirementIfAreEqual<int>(
                0x0100,
                segmentInformation.Version,
                PCCRCDOCSHORTNAME,
                57,
                @"[In Content Information Data Structure Version] Version (2 bytes):  MUST be 0x0100.");

            #endregion

            #region MS-PCCRC_R53
            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R53:Content Information starts the data structure version.
                The Version is parsed at the first 2 byte word in Content Information by stack.
                If MS-PCCRC_R57 is verified successfully, MS-PCCRC_R53 is captured directly.");

            Site.CaptureRequirement(
                PCCRCDOCSHORTNAME,
                53,
                @"[In Content Information Data Structure Version] Content Information starts with
                a single 2 byte WORD value representing the data structure version.");

            #endregion

            #region MS-PCCRC_R56
            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R56, Version is parsed at the first 2 byte word in Content Information by stack.
                If MS-PCCRC_R57 is verified successfully, it indicates that the low byte is the minor version
                numberand the high byte is the major version number.");

            Site.CaptureRequirement(
                PCCRCDOCSHORTNAME,
                56,
                @"[In Content Information Data Structure Version] Version (2 bytes):  The low byte is the minor
                version number and the high byte is the major version number.");

            #endregion

            #region MS-PCCRC_R58

            // Add the debug information.
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R58, the actual length of dwHashAlgo is: {0}",
                Marshal.SizeOf(valueOfDwHashAlgo));

            // Verify MS-PCCRC requirement: MS-PCCRC_R58
            Site.CaptureRequirementIfAreEqual<int>(
                4,
                Marshal.SizeOf(valueOfDwHashAlgo),
                PCCRCDOCSHORTNAME,
                58,
                @"[In Content Information Data Structure Version 1.0] dwHashAlgo (4 bytes):  Hash algorithm to use. <2> ");

            #endregion

            #region MS-PCCRC_R581

            bool isVerifyR581 = valueOfDwHashAlgo == 0x0000800C
                || valueOfDwHashAlgo == 0x0000800D
                || valueOfDwHashAlgo == 0x0000800E;

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R581, the actual value of dwHashAlgo is 0x{0:X8}.",
                valueOfDwHashAlgo);

            // Verify MS-PCCRC requirement: MS-PCCRC_R581
            Site.CaptureRequirementIfIsTrue(
                isVerifyR581,
                PCCRCDOCSHORTNAME,
                581,
                @"[In Content Information Data Structure Version 1.0] dwHashAlgo (4 bytes): MUST be one of the following
                values:0x0000800C,0x0000800D,0x0000800E.");

            #endregion

            #region MS-PCCRC_R59

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R59, When segmentInformation.dwHashAlgo is 0x0000800C,
                it is the SHA-256 hash algorithm. The actual value of dwHashAlgo is 0x{0:X8}.",
                valueOfDwHashAlgo);

            // Verify MS-PCCRC requirement: MS-PCCRC_R59
            Site.CaptureRequirementIfAreEqual<int>(
                0x0000800C,
                valueOfDwHashAlgo,
                PCCRCDOCSHORTNAME,
                59,
                @"[In Content Information Data Structure Version] dwHashAlgo (4 bytes):
                When use the SHA-256 hash algorithm, the value is 0x0000800C.");

            #endregion

            #region MS-PCCRC_R62

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R62, dwOffsetInFirstSegment (4 bytes).
                In MS-PCHC client, only the size of the dwOffsetInFirstSegment will be verified.");

            // Verify MS-PCCRC requirement: MS-PCCRC_R62
            Site.CaptureRequirementIfAreEqual<int>(
                Marshal.SizeOf(segmentInformation.dwOffsetInFirstSegment),
                4,
                PCCRCDOCSHORTNAME,
                62,
                @"[In Content Information Data Structure Version] dwOffsetInFirstSegment (4 bytes):
                Number of bytes into the first segment within the Content Information data structure at
                which the content range begins.");
            #endregion

            #region MS-PCCRC_R63
            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R63, dwReadBytesInLastSegment (4 bytes).
                In MS_PCHC client, only the size of the dwReadBytesInLastSegment will be verified.");

            // Verify MS-PCCRC requirement: MS-PCCRC_R63
            Site.CaptureRequirementIfAreEqual<int>(
                Marshal.SizeOf(segmentInformation.dwReadBytesInLastSegment),
                4,
                PCCRCDOCSHORTNAME,
                63,
                @"[In Content Information Data Structure Version] dwReadBytesInLastSegment (4 bytes):
                Total number of bytes of the content range which lie within the final segment in the
                Content Information data structure.");
            #endregion

            #region MS-PCCRC_R64

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R64, the actual value of the cSegments is {0},
                the size of the cSegments is {1} bytes.",
                segmentInformation.cSegments,
                Marshal.SizeOf(segmentInformation.cSegments));

            // Verify MS-PCCRC requirement: MS-PCCRC_R64
            Site.CaptureRequirementIfAreEqual<int>(
                segmentInformation.segments.Length,
                (int)segmentInformation.cSegments,
                PCCRCDOCSHORTNAME,
                64,
                @"[In Content Information Data Structure Version] cSegments (4 bytes):
                The number of segments which intersect the content range and hence are contained
                in the Content Information data structure.");

            #endregion

            #region MS-PCCRC_R65
            bool isVerifyR65 = true;

            for (int i = 0; i < segmentInformation.cSegments; i++)
            {
                if (!(segmentInformation.segments[i].cbBlockSize == 65536
                       && segmentInformation.segments[i].SegmentHashOfData.Length == hashLength
                       && segmentInformation.segments[i].SegmentSecret.Length == hashLength))
                {
                    isVerifyR65 = false;
                    break;
                }
            }

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R65, the segments variable {0} the Segment start offset,
                length, block size, SegmentHashofData and SegmentSecret for each segment.",
                isVerifyR65 ? "contains" : "does't contain");

            // Verify MS-PCCRC requirement: MS-PCCRC_R65
            Site.CaptureRequirementIfIsTrue(
                isVerifyR65,
                PCCRCDOCSHORTNAME,
                65,
                @"[In Content Information Data Structure Version] segments (variable):  Segment start offset, length,
                block size, SegmentHashofData and SegmentSecret for each segment.");

            #endregion
        }
        /// <summary>
        /// Validate pccrc cSegments part.
        /// </summary>
        /// <param name="segmentInformation">Content information data structure.</param>
        /// <param name="hashLength">The hash length.</param>
        private void ValidatePccrcCSegment(Content_Information_Data_Structure segmentInformation, int hashLength)
        {
            #region MS-PCCRC_R67

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R67, the actual number of SegmentDescription fields in segments field is {0}",
                segmentInformation.segments.Length);

            // Verify MS-PCCRC requirement: MS-PCCRC_R67
            Site.CaptureRequirementIfAreEqual<uint>(
                segmentInformation.cSegments,
                (uint)segmentInformation.segments.Length,
                PCCRCDOCSHORTNAME,
                67,
                @"[In SegmentDescription] The segments field is composed of a number cSegments of
                SegmentDescription fields.");

            #endregion

            #region MS-PCCRC_R69
            bool isVerifyR69 = true;
            for (int i = 0; i < segmentInformation.cSegments - 1; i++)
            {
                if (segmentInformation.segments[i].cbSegment != STANDARDSEGMENTSIZE)
                {
                    isVerifyR69 = false;
                    break;
                }
            }

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R69, the actual size of every segment except for the last segment is {0}32 megabytes",
                isVerifyR69 ? string.Empty : "not ");

            // Verify MS-PCCRC requirement: MS-PCCRC_R69
            Site.CaptureRequirementIfIsTrue(
                isVerifyR69,
                PCCRCDOCSHORTNAME,
                69,
                @"[In SegmentDescription] Every segment except for the last segment must be exactly
                32 megabytes in size");

            #endregion

            #region MS-PCCRC_R74
            bool isVerifyR74 = true;

            for (int i = 1; i < segmentInformation.cSegments; i++)
            {
                ulong offset = segmentInformation.segments[i - 1].ullOffsetInContent
                    + segmentInformation.segments[i - 1].cbSegment;
                if (segmentInformation.segments[i].ullOffsetInContent != offset)
                {
                    isVerifyR74 = false;
                    break;
                }
            }

            if (segmentInformation.segments[0].ullOffsetInContent != 0)
            {
                isVerifyR74 = false;
            }

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R74, the ullOffsetInContent in every SegmentDescription field is
                {0}content offset at which the start of the segment begins.",
                isVerifyR74 ? string.Empty : "not ");

            // Verify MS-PCCRC requirement: MS-PCCRC_R74
            Site.CaptureRequirementIfIsTrue(
                isVerifyR74,
                PCCRCDOCSHORTNAME,
                74,
                @"[In SegmentDescription] ullOffsetInContent (8 bytes):  Content offset at which the start
                of the segment begins.");

            #endregion

            #region MS-PCCRC_R75

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R75. The actual size of the cbSegment is {0}.",
                Marshal.SizeOf(segmentInformation.segments[0].cbSegment));

            // Verify MS-PCCRC requirement: MS-PCCRC_R75
            Site.CaptureRequirementIfAreEqual<int>(
                4,
                Marshal.SizeOf(segmentInformation.segments[0].cbSegment),
                PCCRCDOCSHORTNAME,
                75,
                @"[In SegmentDescription] cbSegment (4 bytes):  Total number of bytes in the segment,
                regardless of how many of those bytes intersect the content range.");

            #endregion

            #region MS-PCCRC_R76

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R76. The actual size of the cbSegment is {0}.",
                Marshal.SizeOf(segmentInformation.segments[0].cbBlockSize));

            // Verify MS-PCCRC requirement: MS-PCCRC_R76
            Site.CaptureRequirementIfAreEqual<int>(
                4,
                Marshal.SizeOf(segmentInformation.segments[0].cbBlockSize),
                PCCRCDOCSHORTNAME,
                76,
                @"[In SegmentDescription] cbBlockSize (4 bytes):
                Length of a content block within this segment, in bytes.");

            #endregion

            #region MS-PCCRC_R77
            bool isVerifyR77 = true;
            for (int i = 0; i < segmentInformation.cSegments; i++)
            {
                if (segmentInformation.segments[i].cbBlockSize != 65536)
                {
                    isVerifyR77 = false;
                }
            }

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R77, the block size of every segment is {0}65536 bytes",
                isVerifyR77 ? string.Empty : "not ");

            // Verify MS-PCCRC requirement: MS-PCCRC_R77
            Site.CaptureRequirementIfIsTrue(
                isVerifyR77,
                PCCRCDOCSHORTNAME,
                77,
                @"[In SegmentDescription] cbBlockSize (4 bytes):
                Every segment MUST use the block size of 65536 bytes.");

            #endregion

            #region MS-PCCRC_R79
            bool isVerifyR79 = true;
            for (int i = 0; i < segmentInformation.cSegments; i++)
            {
                if (segmentInformation.segments[i].SegmentHashOfData.Length != hashLength)
                {
                    isVerifyR79 = false;
                }
            }

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R79, the SegmentHashOfData is {0} of length 32",
                isVerifyR79 ? string.Empty : "not ");

            // Verify MS-PCCRC requirement: MS-PCCRC_R79
            Site.CaptureRequirementIfIsTrue(
                isVerifyR79,
                PCCRCDOCSHORTNAME,
                79,
                @"[In SegmentDescription]  SegmentHashOfData (variable): The hash is of length 32 if dwHashAlgo
                at the start of the Content Information was 0x800C = SHA-256.");

            #endregion

            #region MS-PCCRC_R83
            bool isVerifyR83 = true;
            for (int i = 0; i < segmentInformation.cSegments; i++)
            {
                if (segmentInformation.segments[i].SegmentSecret.Length != hashLength)
                {
                    isVerifyR83 = false;
                }
            }

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R83, the actual length of the SegmentSecret is {0}",
                hashLength);

            // Verify MS-PCCRC requirement: MS-PCCRC_R83
            Site.CaptureRequirementIfIsTrue(
                isVerifyR83,
                PCCRCDOCSHORTNAME,
                83,
                @"[In SegmentDescription]  SegmentSecret (variable):The hash is of length 32 if dwHashAlgo
                at the start of the Content Information was 0x800C = SHA-256.");

            #endregion
        }
        /// <summary>
        /// Generate the content information structure use the file data.
        /// </summary>
        /// <param name="data">The file data.</param>
        /// <returns>The content information structure</returns>
        public Content_Information_Data_Structure GenerateContentInformation(byte[] data)
        {
            int         segmentIndex  = 0;
            int         blockIndex    = 0;
            List <byte> blockHashList = new List <byte>();
            Content_Information_Data_Structure contentInformation = new Content_Information_Data_Structure();

            int blockCount = data.Length / BLOCKBYTECOUNT;

            if (data.Length > BLOCKBYTECOUNT * blockCount)
            {
                blockCount = blockCount + 1;
            }

            int segmentCount = blockCount / SEGMENTBLOCKCOUNT;

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

            contentInformation.Version                  = 0x0100;
            contentInformation.dwHashAlgo               = this.dwHashAlgo;
            contentInformation.dwOffsetInFirstSegment   = 0;
            contentInformation.dwReadBytesInLastSegment = 0;
            contentInformation.cSegments                = (uint)segmentCount;
            contentInformation.segments                 = new SegmentDescription[segmentCount];
            contentInformation.blocks = new SegmentContentBlocks[segmentCount];

            for (int i = 0; i < blockCount; i++)
            {
                int copyLength = BLOCKBYTECOUNT;
                if (data.Length < BLOCKBYTECOUNT * (i + 1))
                {
                    copyLength = data.Length - (BLOCKBYTECOUNT * i);
                }

                byte[] temp = new byte[copyLength];
                Array.Copy(data, i * BLOCKBYTECOUNT, temp, 0, copyLength);
                byte[] blockHash = this.ComputeBlockHash(temp);
                blockHashList.AddRange(blockHash);
                blockIndex = i - (segmentIndex * SEGMENTBLOCKCOUNT);

                if (blockIndex + 1 == SEGMENTBLOCKCOUNT ||
                    i + 1 == blockCount)
                {
                    contentInformation.segments[segmentIndex].ullOffsetInContent =
                        (ulong)(segmentIndex * BLOCKBYTECOUNT * SEGMENTBLOCKCOUNT);
                    contentInformation.segments[segmentIndex].cbSegment =
                        (uint)((blockIndex * BLOCKBYTECOUNT) + copyLength);
                    contentInformation.segments[segmentIndex].cbBlockSize =
                        (uint)BLOCKBYTECOUNT;
                    contentInformation.segments[segmentIndex].SegmentHashOfData = this.ComputeHod(blockHashList);
                    contentInformation.segments[segmentIndex].SegmentSecret     = this.ComputeKp(this.ComputeHod(blockHashList));
                    contentInformation.blocks[segmentIndex].cBlocks             = (uint)blockIndex + 1;
                    contentInformation.blocks[segmentIndex].BlockHashes         = blockHash;

                    blockHashList.Clear();
                    segmentIndex++;
                }
            }

            return(contentInformation);
        }
        /// <summary>
        /// Offer the block hashes to the hosted cache server.
        /// </summary>
        /// <param name="contentInfo">The content information</param>
        public void OfferHostedCacheContentInfo(Content_Information_Data_Structure contentInfo)
        {
            // It's important to make sure the hosted cache server having the block hash.
            int connectionInfoPort = int.Parse(Site.Properties["PCHC.SegmentInfoMessage.PccrrTransPort"]);

            SEGMENT_INFO_MESSAGE segmentInfoMsgStack = this.pchcClient.CreateSegmentInfoMessage(
                connectionInfoPort,
                contentInfo);
            this.pchcClient.SendSegmentInfoMessage(segmentInfoMsgStack);
        }
        private void executeButton_Click(object sender, EventArgs e)
        {
            try
            {
                if (!CheckInput())
                    return;

                logger.Clear();

                #region Read settings from UI

                var version = (BranchCacheVersion)branchCacheVersionComboBox.SelectedItem;
                var operationMode = (OperationMode)operationModeComboBox.SelectedItem;
                var transport = (ContentInformationTransport)transportComboBox.SelectedItem;

                var serverSecret = serverSecretTextBox.Text;
                var filePath = filePathTextBox.Text;

                var hashAlgoValue = (dwHashAlgo_Values)hashAlgorithmComboBox.SelectedItem;
                HashAlgorithm hashAlgorithm;
                HMAC hmacAlgorithm;
                int hashBlockSize;

                string server = null;
                string file = null;
                string sharedFolder = null;
                Match filePathMatch = null;
                switch (transport)
                {
                    case ContentInformationTransport.PCCRTP:
                        filePathMatch = Regex.Match(filePath, httpFilePathPattern);
                        server = filePathMatch.Groups["Server"].Value;
                        file = filePathMatch.Groups["FileName"].Value;
                        break;
                    case ContentInformationTransport.SMB2:
                        filePathMatch = Regex.Match(filePath, smb2FilePathPattern);
                        server = filePathMatch.Groups["Server"].Value;
                        sharedFolder = filePathMatch.Groups["SharedFolder"].Value;
                        file = filePathMatch.Groups["FileName"].Value;
                        break;
                    default:
                        throw new NotImplementedException();
                }

                SecurityPackageType securityPackageType = (SecurityPackageType)smb2AuthenticationComboBox.SelectedItem;

                string domainName = domainNameTextBox.Text;
                string userName = userNameTextBox.Text;
                string userPassword = userPasswordTextBox.Text;

                #endregion

                var timeout = TimeSpan.FromSeconds(60);

                byte[] content;
                byte[] contentInformation;

                Content_Information_Data_Structure contentInformationStructure = new Content_Information_Data_Structure();
                Content_Information_Data_Structure_V2 contentInformationStructureV2 = new Content_Information_Data_Structure_V2();

                #region Read content and content information

                if (operationMode == OperationMode.RemoteHashVerification)
                {
                    switch (transport)
                    {
                        case ContentInformationTransport.PCCRTP:
                            PccrtpClient pccrtpClient = new PccrtpClient();
                            PccrtpRequest pccrtpRequest = pccrtpClient.CreatePccrtpRequest(
                                server,
                                80,
                                file,
                                version);
                            PccrtpResponse pccrtpResponse = pccrtpClient.SendHttpRequest(
                                HttpVersionType.HttpVersion11,
                                pccrtpRequest,
                                (int)timeout.TotalMilliseconds);

                            if (pccrtpResponse.HttpResponse.ContentEncoding == "peerdist")
                            {
                                contentInformation = pccrtpResponse.PayloadData;

                                content = Utility.DownloadHTTPFile(server, file);
                            }
                            else
                            {
                                content = pccrtpResponse.PayloadData;

                                Thread.Sleep(5000); // Wait for hash generation

                                pccrtpResponse = pccrtpClient.SendHttpRequest(
                                    HttpVersionType.HttpVersion11,
                                    pccrtpRequest,
                                    (int)timeout.TotalMilliseconds);

                                contentInformation = pccrtpResponse.PayloadData;
                            }

                            break;

                        case ContentInformationTransport.SMB2:
                            using (Smb2ClientTransport smb2Client = new Smb2ClientTransport(timeout))
                            {
                                smb2Client.OpenFile(
                                    server,
                                    sharedFolder,
                                    file,
                                    securityPackageType,
                                    domainName,
                                    userName,
                                    userPassword,
                                    AccessMask.GENERIC_READ);

                                content = smb2Client.ReadAllBytes();

                                Thread.Sleep(5000); // Wait for hash generation

                                HASH_HEADER hashHeader;
                                smb2Client.ReadHash(
                                    SRV_READ_HASH_Request_HashType_Values.SRV_HASH_TYPE_PEER_DIST,
                                    version == BranchCacheVersion.V1 ? SRV_READ_HASH_Request_HashVersion_Values.SRV_HASH_VER_1 : SRV_READ_HASH_Request_HashVersion_Values.SRV_HASH_VER_2,
                                    version == BranchCacheVersion.V1 ? SRV_READ_HASH_Request_HashRetrievalType_Values.SRV_HASH_RETRIEVE_HASH_BASED : SRV_READ_HASH_Request_HashRetrievalType_Values.SRV_HASH_RETRIEVE_FILE_BASED,
                                    0,
                                    uint.MaxValue,
                                    out hashHeader,
                                    out contentInformation);
                            }

                            break;

                        default:
                            throw new NotImplementedException();
                    }

                    switch (version)
                    {
                        case BranchCacheVersion.V1:
                            contentInformationStructure = PccrcUtility.ParseContentInformation(contentInformation);
                            break;
                        case BranchCacheVersion.V2:
                            contentInformationStructureV2 = PccrcUtility.ParseContentInformationV2(contentInformation);
                            break;
                        default:
                            throw new NotImplementedException();
                    }
                }
                else
                {
                    content = File.ReadAllBytes(filePath);
                }

                #endregion

                #region Calculate hash and execute verification

                switch (version)
                {
                    case BranchCacheVersion.V1:

                        if (operationMode == OperationMode.RemoteHashVerification)
                            PccrcUtility.GetHashAlgorithm(contentInformationStructure.dwHashAlgo, out hashAlgorithm, out hmacAlgorithm, out hashBlockSize);
                        else
                            PccrcUtility.GetHashAlgorithm(hashAlgoValue, out hashAlgorithm, out hmacAlgorithm, out hashBlockSize);
                        hmacAlgorithm.Key = hashAlgorithm.ComputeHash(Encoding.Unicode.GetBytes(serverSecret));

                        logger.LogInfo(
                            "Ks = Hash(ServerSecret): {0}",
                            Utility.ToHexString(hmacAlgorithm.Key));

                        logger.NewLine();

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

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

                        for (int segmentIndex = 0; segmentIndex < segmentCount; segmentIndex++)
                        {
                            logger.LogInfo("Segment{0}", segmentIndex);
                            logger.NewLine();
                            logger.Indent();

                            List<byte> blockHashList = new List<byte>();

                            List<byte> tempList = new List<byte>();

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

                            for (int blockIndex = 0; blockIndex < blockCount; blockIndex++)
                            {
                                logger.LogInfo(
                                    "Block{0} Offset {1} Length {2}",
                                    blockIndex,
                                    BLOCKBYTECOUNT * SEGMENTBLOCKCOUNT * segmentIndex + BLOCKBYTECOUNT * blockIndex,
                                    BLOCKBYTECOUNT);
                                logger.NewLine();
                                logger.Indent();

                                var block = content.Skip(BLOCKBYTECOUNT * SEGMENTBLOCKCOUNT * segmentIndex + BLOCKBYTECOUNT * blockIndex).Take(BLOCKBYTECOUNT).ToArray();

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

                                logger.LogInfo("BlockHash{0} = Hash(Block): {1}", blockIndex, Utility.ToHexString(blockHash));

                                if (operationMode == OperationMode.RemoteHashVerification &&
                                    !blockHash.SequenceEqual(contentInformationStructure.blocks[segmentIndex].BlockHashes.Skip(blockIndex * hashBlockSize).Take(hashBlockSize)))
                                {
                                    logger.LogError("Server Returned: {0}", Utility.ToHexString(contentInformationStructure.blocks[segmentIndex].BlockHashes.Skip(blockIndex * hashBlockSize).Take(hashBlockSize).ToArray()));
                                }

                                blockHashList.AddRange(blockHash);

                                logger.Unindent();
                                logger.NewLine();
                            }

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

                            logger.LogInfo(
                                "HoD = Hash(BlockHash0 + BlockHash1 + ... + BlockHashN): {0}",
                                Utility.ToHexString(hod));

                            if (operationMode == OperationMode.RemoteHashVerification &&
                                !hod.SequenceEqual(contentInformationStructure.segments[segmentIndex].SegmentHashOfData))
                            {
                                logger.LogError("Server Returned: {0}", Utility.ToHexString(contentInformationStructure.segments[segmentIndex].SegmentHashOfData));
                            }

                            logger.NewLine();

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

                            logger.LogInfo(
                                "Kp = HMAC(Ks, HoD): {0}",
                                Utility.ToHexString(kp));

                            if (operationMode == OperationMode.RemoteHashVerification &&
                                !kp.SequenceEqual(contentInformationStructure.segments[segmentIndex].SegmentSecret))
                            {
                                logger.LogError("Server Returned: {0}", Utility.ToHexString(contentInformationStructure.segments[segmentIndex].SegmentSecret));
                            }

                            logger.NewLine();

                            tempList.AddRange(hod);
                            tempList.AddRange(Encoding.Unicode.GetBytes(HOHODK_APPEND_STRING));

                            byte[] hoHoDK = hashAlgorithm.ComputeHash(tempList.ToArray());

                            logger.LogInfo(
                                "hoHoDK = HMAC(HoD + \"MS_P2P_CACHING\"): {0}",
                                Utility.ToHexString(hoHoDK));

                            logger.NewLine();

                            logger.Unindent();
                        }
                        break;

                    case BranchCacheVersion.V2:

                        PccrcUtility.GetHashAlgorithm(dwHashAlgoV2_Values.TRUNCATED_SHA512, out hashAlgorithm, out hmacAlgorithm);
                        hmacAlgorithm.Key = hashAlgorithm.ComputeHash(Encoding.Unicode.GetBytes(serverSecret)).Take(32).ToArray();

                        logger.LogInfo(
                            "Ks = Hash(ServerSecret): {0}",
                            Utility.ToHexString(hmacAlgorithm.Key));

                        logger.NewLine();

                        int segmentLength = BLOCKBYTECOUNT;
                        int chunkCount = 1;

                        if (operationMode == OperationMode.RemoteHashVerification)
                            chunkCount = contentInformationStructureV2.chunks.Length;

                        int segmentOffset = 0;
                        for (int chunkIndex = 0; chunkIndex < chunkCount; chunkIndex++)
                        {
                            logger.LogInfo("Chunk{0}", chunkIndex);
                            logger.NewLine();
                            logger.Indent();

                            segmentCount = content.Length / segmentLength;
                            if (content.Length > segmentCount * segmentLength)
                                segmentCount++;

                            if (operationMode == OperationMode.RemoteHashVerification)
                                segmentCount = contentInformationStructureV2.chunks[chunkIndex].chunkData.Length;

                            for (int segmentIndex = 0; segmentIndex < segmentCount; ++segmentIndex)
                            {
                                logger.LogInfo(
                                    "Segment{0} Offset {1} Length {2}",
                                    segmentIndex,
                                    segmentOffset,
                                    BLOCKBYTECOUNT);
                                logger.NewLine();
                                logger.Indent();

                                if (operationMode == OperationMode.RemoteHashVerification)
                                    segmentLength = (int)contentInformationStructureV2.chunks[chunkIndex].chunkData[segmentIndex].cbSegment;

                                List<byte> tempList = new List<byte>();

                                var segment = content.Skip(segmentOffset).Take(segmentLength).ToArray();

                                segmentOffset += segmentLength;

                                //TRANCATED_SHA_512
                                byte[] hod = hashAlgorithm.ComputeHash(segment).Take(32).ToArray();

                                logger.LogInfo(
                                    "HoD = Hash(Segment): {0}",
                                    Utility.ToHexString(hod));

                                if (operationMode == OperationMode.RemoteHashVerification &&
                                    !hod.SequenceEqual(contentInformationStructureV2.chunks[chunkIndex].chunkData[segmentIndex].SegmentHashOfData))
                                {
                                    logger.LogError("Server Returned: {0}", Utility.ToHexString(contentInformationStructureV2.chunks[chunkIndex].chunkData[segmentIndex].SegmentHashOfData));
                                }

                                logger.NewLine();

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

                                logger.LogInfo(
                                    "Kp = HMAC(Ks, HoD): {0}",
                                    Utility.ToHexString(kp));

                                if (operationMode == OperationMode.RemoteHashVerification &&
                                    !kp.SequenceEqual(contentInformationStructureV2.chunks[chunkIndex].chunkData[segmentIndex].SegmentSecret))
                                {
                                    logger.LogError("Server Returned: {0}", Utility.ToHexString(contentInformationStructureV2.chunks[chunkIndex].chunkData[segmentIndex].SegmentSecret));
                                }

                                logger.NewLine();

                                tempList.AddRange(hod);
                                tempList.AddRange(Encoding.Unicode.GetBytes(HOHODK_APPEND_STRING));

                                byte[] hoHoDK = hashAlgorithm.ComputeHash(tempList.ToArray());

                                logger.LogInfo(
                                    "hoHoDK = HMAC(HoD + \"MS_P2P_CACHING\"): {0}",
                                    Utility.ToHexString(hoHoDK));

                                logger.NewLine();

                                logger.Unindent();
                            }
                        }

                        break;

                    default:
                        throw new NotImplementedException();
                }

                if (operationMode == OperationMode.RemoteHashVerification)
                {
                    if (logger.HasError)
                    {
                        Utility.ShowMessageBox("Hash verification error found!", MessageBoxIcon.Error);
                    }
                    else
                    {
                        Utility.ShowMessageBox("Hash verification passed!", MessageBoxIcon.Information);
                    }
                }

                #endregion
            }
            catch (Exception ex)
            {
                Utility.ShowMessageBox(ex.Message + "\r\n\r\n" + ex.StackTrace, MessageBoxIcon.Error);
            }
        }
        /// <summary>
        /// Create SEGMENT_INFO_MESSAGE package.
        /// </summary>
        /// <param name="connectionInfoPort">
        /// A 16-bit unsigned integer that MUST be set by the client to the port 
        /// on which it is listening as a server-role peer, for use with the retrieval protocol.
        /// </param>
        /// <param name="segmentInformation">A Content Information data structure.</param>
        /// <returns>Return the SEGMENT_INFO_MESSAGE.</returns>
        public SEGMENT_INFO_MESSAGE CreateSegmentInfoMessage(
            int connectionInfoPort,
            Content_Information_Data_Structure segmentInformation)
        {
            MESSAGE_HEADER messageHeader;

            // MajorVersion (1 byte):  The major part of the version, which MUST be 0x01.
            // MinorVersion (1 byte):  The minor part of the version, which MUST be 0x00.
            // Padding (4 bytes):  The value of this field is indeterminate and MUST be ignored on processing
            messageHeader.MajorVersion = 1;
            messageHeader.MinorVersion = 0;
            messageHeader.MsgType = PCHC_MESSAGE_TYPE.SEGMENT_INFO_MESSAGE;
            messageHeader.Padding = new byte[4];
            Content_Information_Data_Structure segmentInfomation = segmentInformation;

            CONNECTION_INFORMATION connectionInfo;

            // Padding (6 bytes):  The value of this field is indeterminated and MUST be ignored on processing.
            // Port (2 bytes): A 16-bit unsigned integer that MUST be set by the client to the port on
            // which it is listening as a server-role peer, for use with the retrieval protocol.
            connectionInfo.Padding = new byte[6];
            connectionInfo.Port = (ushort)connectionInfoPort;

            // ContentTag (16 bytes):  A structure consisting of 16 bytes of opaque data.
            byte[] contentTag = new byte[16];

            SEGMENT_INFO_MESSAGE segmentInfoMessage;
            segmentInfoMessage.ConnectionInfo = connectionInfo;
            segmentInfoMessage.ContentTag = contentTag;
            segmentInfoMessage.MsgHeader = messageHeader;
            segmentInfoMessage.SegmentInfo = segmentInfomation;

            return segmentInfoMessage;
        }
        public void Start(int port, CryptoAlgoId_Values cryptoAlgoId, ProtoVersion protoVersion, Content_Information_Data_Structure contentInformation, byte[] content, EventQueue eventQueue)
        {
            this.contentInformation = contentInformation;

            base.Start(port, cryptoAlgoId, protoVersion, content, eventQueue);
        }
        /// <summary>
        /// Parse the information of the content
        /// </summary>
        /// <param name="data">The byte data in little-endian order.</param>
        /// <param name="index">The start index.</param>
        /// <returns>Returns the content information data structure.</returns>
        public static Content_Information_Data_Structure ParseContentInformation(byte[] data, ref int index)
        {
            Content_Information_Data_Structure contentInfo = new Content_Information_Data_Structure();
            byte[] informationData = GetBytes(data, ref index, data.Length - index);
            int tempIndex = 0;

            contentInfo.Version = GetUInt16(informationData, ref tempIndex);
            contentInfo.dwHashAlgo = (dwHashAlgo_Values)GetUInt32(informationData, ref tempIndex);
            contentInfo.dwOffsetInFirstSegment = GetUInt32(informationData, ref tempIndex);
            contentInfo.dwReadBytesInLastSegment = GetUInt32(informationData, ref tempIndex);
            contentInfo.cSegments = GetUInt32(informationData, ref tempIndex);
            contentInfo.segments = ParseSements(
                contentInfo.dwHashAlgo,
                contentInfo.cSegments,
                informationData,
                ref tempIndex);
            contentInfo.blocks = ParseBlocks(
                contentInfo.dwHashAlgo,
                contentInfo.cSegments,
                informationData,
                ref tempIndex);

            return contentInfo;
        }
        /// <summary>
        /// Generate the content information structure use the file data.
        /// </summary>
        /// <param name="data">The file data.</param>
        /// <returns>The content information structure</returns>
        public Content_Information_Data_Structure GenerateContentInformation(byte[] data)
        {
            int segmentIndex = 0;
            int blockIndex = 0;
            List<byte> blockHashList = new List<byte>();
            Content_Information_Data_Structure contentInformation = new Content_Information_Data_Structure();

            int blockCount = data.Length / BLOCKBYTECOUNT;
            if (data.Length > BLOCKBYTECOUNT * blockCount)
            {
                blockCount = blockCount + 1;
            }

            int segmentCount = blockCount / SEGMENTBLOCKCOUNT;
            if (blockCount > SEGMENTBLOCKCOUNT * segmentCount)
            {
                segmentCount = segmentCount + 1;
            }

            contentInformation.Version = 0x0100;
            contentInformation.dwHashAlgo = this.dwHashAlgo;
            contentInformation.dwOffsetInFirstSegment = 0;
            contentInformation.dwReadBytesInLastSegment = 0;
            contentInformation.cSegments = (uint)segmentCount;
            contentInformation.segments = new SegmentDescription[segmentCount];
            contentInformation.blocks = new SegmentContentBlocks[segmentCount];

            for (int i = 0; i < blockCount; i++)
            {
                int copyLength = BLOCKBYTECOUNT;
                if (data.Length < BLOCKBYTECOUNT * (i + 1))
                {
                    copyLength = data.Length - (BLOCKBYTECOUNT * i);
                }

                byte[] temp = new byte[copyLength];
                Array.Copy(data, i * BLOCKBYTECOUNT, temp, 0, copyLength);
                byte[] blockHash = this.ComputeBlockHash(temp);
                blockHashList.AddRange(blockHash);
                blockIndex = i - (segmentIndex * SEGMENTBLOCKCOUNT);

                if (blockIndex + 1 == SEGMENTBLOCKCOUNT
                    || i + 1 == blockCount)
                {
                    contentInformation.segments[segmentIndex].ullOffsetInContent =
                        (ulong)(segmentIndex * BLOCKBYTECOUNT * SEGMENTBLOCKCOUNT);
                    contentInformation.segments[segmentIndex].cbSegment =
                        (uint)((blockIndex * BLOCKBYTECOUNT) + copyLength);
                    contentInformation.segments[segmentIndex].cbBlockSize =
                        (uint)BLOCKBYTECOUNT;
                    contentInformation.segments[segmentIndex].SegmentHashOfData = this.ComputeHod(blockHashList);
                    contentInformation.segments[segmentIndex].SegmentSecret = this.ComputeKp(this.ComputeHod(blockHashList));
                    contentInformation.blocks[segmentIndex].cBlocks = (uint)blockIndex + 1;
                    contentInformation.blocks[segmentIndex].BlockHashes = blockHash;

                    blockHashList.Clear();
                    segmentIndex++;
                }
            }

            return contentInformation;
        }
        public Content_Information_Data_Structure CreateContentInformationV1()
        {
            var contentInformation = new Content_Information_Data_Structure
            {
                Version = 0x0100,
                dwHashAlgo = dwHashAlgo_Values.SHA256,
                cSegments = 1,
                segments = new SegmentDescription[]
                    {
                        new SegmentDescription
                        {
                             cbBlockSize = DefaultBlockSize,
                             cbSegment = DefaultBlockSize,
                             SegmentHashOfData = TestUtility.GenerateRandomArray(32),
                             SegmentSecret = TestUtility.GenerateRandomArray(32),
                             ullOffsetInContent = 0
                        }
                    },
                dwOffsetInFirstSegment = 0,
                dwReadBytesInLastSegment = DefaultBlockSize,
                blocks = new SegmentContentBlocks[]
                {
                    new SegmentContentBlocks
                    {
                        cBlocks = 1,
                        BlockHashes = TestUtility.GenerateRandomArray(32),
                    }
                }
            };

            return contentInformation;
        }
        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.");
            }
        }