public void HexToBytesBadChars() { const string GoodChars = "0123456789ABCDEFabcdef"; var badCharactersMistakenlyAllowed = new List <char>(); for (char c = '!'; c <= '~'; c++) { if (GoodChars.IndexOf(c) == -1) { try { HexHelper.HexToBytes(new string(new[] { c, c })); // Should not get here. badCharactersMistakenlyAllowed.Add(c); } catch (ArgumentException) { } } } Assert.Equal(0, badCharactersMistakenlyAllowed.Count); }
public void HexToBytesBasics() { byte[] bytes = HexHelper.HexToBytes("0123456789ABCDEFabcdef"); AssertBytes(new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xAB, 0xCD, 0xEF, }, bytes); bytes = HexHelper.HexToBytes(string.Empty); AssertBytes(Array.Empty <byte>(), bytes); // 0x prefix. bytes = HexHelper.HexToBytes("0x1234"); AssertBytes(new byte[] { 0x12, 0x34 }, bytes); // Odd number of hex digits - last should be ignored. bytes = HexHelper.HexToBytes("fAbCd"); AssertBytes(new byte[] { 0xFA, 0xBC }, bytes); // Whitespace - should be trimmed. bytes = HexHelper.HexToBytes(" ABCD\t\t"); AssertBytes(new byte[] { 0xAB, 0xCD }, bytes); // Whitespace + 0x bytes = HexHelper.HexToBytes(" 0x9876"); AssertBytes(new byte[] { 0x98, 0x76 }, bytes); }
/// <summary> /// Creates a new info hash. /// </summary> /// <param name="hex">The hash as an hexadecimal string.</param> public InfoHash(string hex) { if (hex == null) { throw new ArgumentNullException("hex"); } else if (hex.Length != 40) { throw new ArgumentException("The hash must be 20 bytes in size (40 hexadecimal characters).", "hex"); } this.hash = HexHelper.HexToBytes(hex); }
public void BytesToHexNull() { byte[] result = HexHelper.HexToBytes(null); Assert.NotNull(result); Assert.Equal(0, result.Length); }
private void Load(BEncoding.Dictionary torrentInfo) { ClearInfo(); BEncoding.List announceList; if (torrentInfo.TryGetList("announce-list", out announceList)) { int announceCount = announceList.Count; var newAnnounceList = new List <AnnounceItem>(announceCount); for (int i = 0; i < announceCount; i++) { var urlList = (announceList[i] as BEncoding.List); if (urlList != null) { int urlCount = urlList.Count; var newUrlList = new List <string>(urlCount); for (int j = 0; j < urlCount; j++) { string url = urlList.GetString(j); if (!string.IsNullOrEmpty(url)) { newUrlList.Add(url); } } if (newUrlList.Count > 0) { newAnnounceList.Add(new AnnounceItem(newUrlList.ToArray())); } } } announces = newAnnounceList.ToArray(); } else { string announceUrl; if (torrentInfo.TryGetString("announce", out announceUrl)) { announces = new AnnounceItem[] { new AnnounceItem(announceUrl) }; } } long creationDateTimestamp; if (!torrentInfo.TryGetString("comment", out comment)) { comment = null; } if (!torrentInfo.TryGetString("created by", out createdBy)) { createdBy = null; } if (torrentInfo.TryGetInteger("creation date", out creationDateTimestamp)) { creationDate = TimeHelper.GetDateFromUnixTimestamp(creationDateTimestamp); } else { creationDate = DateTime.MinValue; } BEncoding.Dictionary info; if (!torrentInfo.TryGetDictionary("info", out info)) { throw new InvalidDataException("The info dictionary is missing in the torrent meta-data."); } infoHash = ComputeInfoHash(info); long pieceSize; if (!info.TryGetInteger("piece length", out pieceSize)) { throw new InvalidDataException("The piece length is missing in the torrent meta-data. But it is required for all torrents."); } byte[] pieceHashData; if (!info.TryGetByteArray("pieces", out pieceHashData)) { throw new InvalidDataException("The piece hashes are missing in the torrent meta-data. But it is required for all torrents."); } else if ((pieceHashData.Length % 20) != 0) { throw new InvalidDataException("The piece hashes are invalid in the torrent meta-data. It must be a multiple of 20 (for SHA1 hashes)."); } int pieceCount = (pieceHashData.Length / 20); pieceHashes = new PieceHash[pieceCount]; for (int i = 0; i < pieceCount; i++) { byte[] pieceHashBytes = new byte[20]; Buffer.BlockCopy(pieceHashData, (i * 20), pieceHashBytes, 0, 20); pieceHashes[i] = new PieceHash(pieceHashBytes); } long isPrivate; if (info.TryGetInteger("private", out isPrivate) && isPrivate == 1) { this.isPrivate = true; } if (!info.TryGetString("source", out source)) { source = null; } if (!info.TryGetString("name", out name) || string.IsNullOrEmpty(name)) { throw new InvalidDataException("The name string is missing in the torrent meta-data. But it is required for all torrents."); } this.pieceSize = (int)pieceSize; BEncoding.List fileList; if (info.TryGetList("files", out fileList)) { int fileCount = fileList.Count; files = new FileItem[fileCount]; for (int i = 0; i < fileCount; i++) { var fileItem = fileList[i] as BEncoding.Dictionary; if (fileItem == null) { throw new InvalidDataException("The format of the torrent meta-data is invalid. Expected a dictionary of file information."); } long fileSize; if (!fileItem.TryGetInteger("length", out fileSize)) { throw new InvalidDataException("The format of the torrent meta-data is invalid. Expected a file size."); } string fileMD5HashHex; byte[] fileMD5Hash = null; if (fileItem.TryGetString("md5sum", out fileMD5HashHex) && fileMD5HashHex.Length == 32) { fileMD5Hash = HexHelper.HexToBytes(fileMD5HashHex); } BEncoding.List pathList; if (!fileItem.TryGetList("path", out pathList)) { throw new InvalidDataException("The format of the torrent meta-data is invalid. Expected a file path."); } int pathPartCount = pathList.Count; string[] pathParts = new string[pathPartCount]; for (int j = 0; j < pathPartCount; j++) { string pathPart = pathList.GetString(j); if (string.IsNullOrEmpty(pathPart)) { throw new InvalidDataException("The format of the torrent meta-data is invalid. Expected a file path."); } pathParts[j] = pathPart; } string filePath = string.Join("/", pathParts); files[i] = new FileItem(filePath, fileSize, fileMD5Hash); } } else { long fileSize; if (!info.TryGetInteger("length", out fileSize)) { throw new InvalidDataException("The file length is missing in the torrent meta-data. But it is required for single-file torrents."); } string fileMD5HashHex; byte[] fileMD5Hash = null; if (info.TryGetString("md5sum", out fileMD5HashHex) && fileMD5HashHex.Length == 32) { fileMD5Hash = HexHelper.HexToBytes(fileMD5HashHex); } files = new FileItem[] { new FileItem(name, fileSize, fileMD5Hash) }; } totalSize = ComputeTotalSize(); int expectedPieceCount = (int)((totalSize - 1) / pieceSize) + 1; if (expectedPieceCount != pieceHashes.Length) { throw new InvalidOperationException(string.Format("The calculated number of pieces is {0} while there are {1} piece hashes.", expectedPieceCount, pieceHashes.Length)); } }
public void TestCreateNtlmChallengeMessage() { const string originHex = "4e544c4d53535000020000000c000c0030000000010281000123456789abcdef0000000000000000620062003c00000044004f004d00410049004e0002000c0044004f004d00410049004e0001000c005300450052005600450052000400140064006f006d00610069006e002e0063006f006d00030022007300650072007600650072002e0064006f006d00610069006e002e0063006f006d0000000000"; var messageStruct = new ChallengeMessageStruct { Signature = Constants.NtlmsspBytes, Type = MessageType.Challenge, Flags = MessageFlag.NegotiateUnicode | MessageFlag.NegotiateNtlm | MessageFlag.TargetTypeDomain | MessageFlag.NegotiateTargetInfo, Challenge = HexHelper.HexToBytes("0123456789abcdef"), Context = HexHelper.HexToBytes("0000000000000000") }; var message = new NtlmChallengeMessage(messageStruct, "DOMAIN"); message.TargetInfoList.Add(new NtlmTargetInfo(TargetInfoType.DomainName, "DOMAIN", Encoding.Unicode)); message.TargetInfoList.Add(new NtlmTargetInfo(TargetInfoType.ServerName, "SERVER", Encoding.Unicode)); message.TargetInfoList.Add(new NtlmTargetInfo(TargetInfoType.DnsDomainName, "domain.com", Encoding.Unicode)); message.TargetInfoList.Add(new NtlmTargetInfo(TargetInfoType.FQDN, "server.domain.com", Encoding.Unicode)); message.TargetInfoList.Add(new NtlmTargetInfo(TargetInfoType.Terminator)); message.Rectify(); Assert.IsTrue(message.Signature == Constants.Ntlmssp); Assert.IsTrue(message.Type == MessageType.Challenge); Assert.IsTrue(message.Flags == (MessageFlag.NegotiateUnicode | MessageFlag.NegotiateNtlm | MessageFlag.TargetTypeDomain | MessageFlag.NegotiateTargetInfo)); const string challengeHex = "0123456789abcdef"; Assert.IsTrue(message.Message.Challenge.BytesToHex() .Equals(challengeHex, StringComparison.InvariantCultureIgnoreCase)); Assert.IsTrue(message.Message.TargetNameLength == 12); Assert.IsTrue(message.Message.TargetNameSpace == 12); Assert.IsTrue(message.Message.TargetNameOffset == 48); Assert.IsTrue(message.TargetName == "DOMAIN"); Assert.IsTrue(message.Message.TargetInfosLength == 98); Assert.IsTrue(message.Message.TargetInfosSpace == 98); Assert.IsTrue(message.Message.TargetInfosOffset == 60); var info = message.TargetInfoList; Assert.IsTrue(info.Count == 5); Assert.IsTrue(info[0].TargetInfoType == TargetInfoType.DomainName); Assert.IsTrue(info[0].TargetContent == "DOMAIN"); Assert.IsTrue(info[1].TargetInfoType == TargetInfoType.ServerName); Assert.IsTrue(info[1].TargetContent == "SERVER"); Assert.IsTrue(info[2].TargetInfoType == TargetInfoType.DnsDomainName); Assert.IsTrue(info[2].TargetContent == "domain.com"); Assert.IsTrue(info[3].TargetInfoType == TargetInfoType.FQDN); Assert.IsTrue(info[3].TargetContent == "server.domain.com"); Assert.IsTrue(info[4].TargetInfoType == TargetInfoType.Terminator); Assert.IsTrue(info[4].TargetContent == null); var actualHex = message.ToBytes().BytesToHex(); Assert.IsTrue(originHex.Equals(actualHex, StringComparison.InvariantCultureIgnoreCase)); }