private static bool ReadQuery(ref string name, BinaryReaderExt reader, MD5 md5, MemoryStream stream) { if (!reader.TryRead(out name)) { return(false); } if (!IsMessageAuthentic(md5, stream, reader)) { name = null; return(false); } return(true); }
public static bool TryRead(byte[] message, out string token, out string name, out IPEndPoint endPoint, out byte[] payload) { token = null; name = null; endPoint = null; payload = null; if (message.Length == 0) { return(false); } using (var md5 = MD5.Create()) using (var stream = new MemoryStream(message)) using (var reader = new BinaryReaderExt(stream)) { if (!reader.TryRead(out token)) { return(false); } if (token == P2PQueryToken) { return(ReadQuery(ref name, reader, md5, stream)); } if (token == P2PResponse2Token) { return(ReadResponse2(ref name, ref endPoint, ref payload, reader, md5, stream)); } if (token == P2PResponseLegacyToken) { return(ReadLegacyResponse(ref name, ref endPoint, reader, md5, stream)); } return(false); } }
private static bool ReadLegacyResponse(ref string name, ref IPEndPoint endPoint, BinaryReaderExt reader, MD5 md5, MemoryStream stream) { if (!reader.TryRead(out name)) { return(false); } if (!reader.TryRead(out endPoint)) { return(false); } if (!IsMessageAuthentic(md5, stream, reader)) { name = null; endPoint = null; return(false); } return(true); }
private static bool ReadResponse2(ref string name, ref IPEndPoint endPoint, ref byte[] payload, BinaryReaderExt reader, MD5 md5, MemoryStream stream) { // This code is intended to be forwards compatible. // This means that it needs to be able to deal with content types which // it does simply not know (yet). Obviously such content would not // be decoded, however it is super important that we do not discard future // responses just because we calculated the hash wrong. // For this reason, we include the total message length here, so that even if we // do not know the additional content, we include it in our hash code calculation. var contentLengthStart = (int)stream.Position; ushort contentLength; if (!reader.TryRead(out contentLength)) { return(false); } if (reader.BytesLeft < contentLength) { return(false); } var hashStart = (int)reader.BaseStream.Position; var hash = reader.ReadBytes(count: 16); var content = (MessageContent)reader.ReadInt32(); if ((content & MessageContent.Name) == MessageContent.Name) { if (!reader.TryRead(out name)) { return(false); } } if ((content & MessageContent.EndPoint) == MessageContent.EndPoint) { if (!reader.TryRead(out endPoint)) { return(false); } } if ((content & MessageContent.Payload) == MessageContent.Payload) { int payloadLength = reader.ReadUInt16(); payload = reader.ReadBytes(payloadLength); } // We need to black out the actual hash to 0 before // we compute the hash of the received content stream.Position = hashStart; for (var i = 0; i < 16; ++i) { stream.WriteByte(value: 0); } var actualHash = md5.ComputeHash(stream.ToArray(), contentLengthStart, contentLength + 2); if (!AreHashesEqual(hash, actualHash)) { return(false); } return(true); }