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