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