コード例 #1
0
        /// <inheritdoc/>
        public Message Decode(
            byte[] encoded,
            bool reply)
        {
            if (encoded.Length == 0)
            {
                throw new ArgumentException("Can't parse empty byte array.");
            }

            using var stream = new MemoryStream(encoded);
            var buffer = new byte[sizeof(int)];

            stream.Read(buffer, 0, sizeof(int));
            int frameCount = BitConverter.ToInt32(buffer, 0);
            var frames     = new List <byte[]>();

            for (var i = 0; i < frameCount; i++)
            {
                buffer = new byte[sizeof(int)];
                stream.Read(buffer, 0, sizeof(int));
                int frameSize = BitConverter.ToInt32(buffer, 0);
                buffer = new byte[frameSize];
                stream.Read(buffer, 0, frameSize);
                frames.Add(buffer);
            }

            // (reply == true)            [version, type, peer, timestamp, sign, frames...]
            // (reply == false) [identity, version, type, peer, timestamp, sign, frames...]
            List <byte[]> remains = reply ? frames : frames.Skip(1).ToList();

            var versionToken = Encoding.ASCII.GetString(remains[(int)Message.MessageFrame.Version]);

            AppProtocolVersion remoteVersion = AppProtocolVersion.FromToken(versionToken);
            Peer remotePeer;
            var  dictionary =
                (Bencodex.Types.Dictionary)_codec.Decode(remains[(int)Message.MessageFrame.Peer]);

            try
            {
                remotePeer = new BoundPeer(dictionary);
            }
            catch (KeyNotFoundException)
            {
                remotePeer = new Peer(dictionary);
            }

            _messageValidator.ValidateAppProtocolVersion(
                remotePeer,
                reply ? new byte[] { } : frames[0],
                remoteVersion);

            var type =
                (Message.MessageType)BitConverter.ToInt32(
                    remains[(int)Message.MessageFrame.Type],
                    0);
            long ticks       = BitConverter.ToInt64(remains[(int)Message.MessageFrame.Timestamp], 0);
            var  timestamp   = new DateTimeOffset(ticks, TimeSpan.Zero);
            var  currentTime = DateTimeOffset.UtcNow;

            _messageValidator.ValidateTimestamp(remotePeer, currentTime, timestamp);

            byte[] signature = remains[(int)Message.MessageFrame.Sign];

            byte[][] body = remains.Skip(Message.CommonFrames).ToArray();

            Message message = CreateMessage(type, body);

            message.Version   = remoteVersion;
            message.Remote    = remotePeer;
            message.Timestamp = timestamp;

            var headerWithoutSign = new[]
            {
                remains[(int)Message.MessageFrame.Version],
                remains[(int)Message.MessageFrame.Type],
                remains[(int)Message.MessageFrame.Peer],
                remains[(int)Message.MessageFrame.Timestamp],
            };

            var messageToVerify = headerWithoutSign.Concat(body).Aggregate(
                new byte[] { },
                (arr, bytes) => arr.Concat(bytes).ToArray());

            if (!remotePeer.PublicKey.Verify(messageToVerify, signature))
            {
                throw new InvalidMessageSignatureException(
                          "The signature of an encoded message is invalid.",
                          remotePeer,
                          remotePeer.PublicKey,
                          messageToVerify,
                          signature);
            }

            if (!reply)
            {
                message.Identity = frames[0];
            }

            return(message);
        }
コード例 #2
0
        /// <inheritdoc/>
        public Message Decode(
            NetMQMessage encoded,
            bool reply)
        {
            if (encoded.FrameCount == 0)
            {
                throw new ArgumentException("Can't parse empty NetMQMessage.");
            }

            // (reply == true)            [version, type, peer, timestamp, sign, frames...]
            // (reply == false) [identity, version, type, peer, timestamp, sign, frames...]
            NetMQFrame[] remains = reply ? encoded.ToArray() : encoded.Skip(1).ToArray();

            var versionToken = remains[(int)Message.MessageFrame.Version].ConvertToString();

            AppProtocolVersion remoteVersion = AppProtocolVersion.FromToken(versionToken);
            Peer remotePeer;
            var  dictionary =
                (Bencodex.Types.Dictionary)_codec.Decode(
                    remains[(int)Message.MessageFrame.Peer].ToByteArray());

            try
            {
                remotePeer = new BoundPeer(dictionary);
            }
            catch (KeyNotFoundException)
            {
                remotePeer = new Peer(dictionary);
            }

            _messageValidator.ValidateAppProtocolVersion(
                remotePeer,
                reply ? new byte[] { } : encoded[0].ToByteArray(),
                remoteVersion);

            var type =
                (Message.MessageType)remains[(int)Message.MessageFrame.Type].ConvertToInt32();
            var ticks       = remains[(int)Message.MessageFrame.Timestamp].ConvertToInt64();
            var timestamp   = new DateTimeOffset(ticks, TimeSpan.Zero);
            var currentTime = DateTimeOffset.UtcNow;

            _messageValidator.ValidateTimestamp(remotePeer, currentTime, timestamp);

            byte[] signature = remains[(int)Message.MessageFrame.Sign].ToByteArray();

            NetMQFrame[] body = remains.Skip(Message.CommonFrames)
                                .ToArray();

            Message message = CreateMessage(
                type,
                body.Select(frame => frame.ToByteArray()).ToArray());

            message.Version   = remoteVersion;
            message.Remote    = remotePeer;
            message.Timestamp = timestamp;

            var headerWithoutSign = new[]
            {
                remains[(int)Message.MessageFrame.Version],
                remains[(int)Message.MessageFrame.Type],
                remains[(int)Message.MessageFrame.Peer],
                remains[(int)Message.MessageFrame.Timestamp],
            };

            var messageToVerify = headerWithoutSign.Concat(body).ToByteArray();

            if (!remotePeer.PublicKey.Verify(messageToVerify, signature))
            {
                throw new InvalidMessageSignatureException(
                          "The signature of an encoded message is invalid.",
                          remotePeer,
                          remotePeer.PublicKey,
                          messageToVerify,
                          signature);
            }

            if (!reply)
            {
                message.Identity = encoded[0].Buffer.ToArray();
            }

            return(message);
        }