예제 #1
0
        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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        /// <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);
        }
예제 #4
0
 public void BytesToHexNull()
 {
     byte[] result = HexHelper.HexToBytes(null);
     Assert.NotNull(result);
     Assert.Equal(0, result.Length);
 }
예제 #5
0
        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));
        }