/// <param name="connectionToNeighbor">is null for A->EP mode</param> public byte[] Encode_OptionallySignNeighborHMAC(ConnectionToNeighbor connectionToNeighborNullable) { BinaryProcedures.CreateBinaryWriter(out var ms, out var writer); writer.Write((byte)PacketTypes.RegisterAck2); byte flags = 0; if (connectionToNeighborNullable == null) { flags |= Flag_AtoEP; } writer.Write(flags); if (connectionToNeighborNullable != null) { NeighborToken32 = connectionToNeighborNullable.RemoteNeighborToken32; NeighborToken32.Encode(writer); } GetSharedSignedFields(writer, true, true); ReqP2pSeq16.Encode(writer); if (connectionToNeighborNullable != null) { connectionToNeighborNullable.GetNeighborHMAC(this.GetSignedFieldsForNeighborHMAC).Encode(writer); } return(ms.ToArray()); }
/// <param name="reqReceivedFromInP2pMode">is not null for packets between registered peers</param> public byte[] Encode_OpionallySignNeighborHMAC(ConnectionToNeighbor reqReceivedFromInP2pMode) { BinaryProcedures.CreateBinaryWriter(out var ms, out var writer); writer.Write((byte)PacketTypes.RegisterAck1); byte flags = 0; if (reqReceivedFromInP2pMode == null) { flags |= Flag_EPtoA; } writer.Write(flags); if (reqReceivedFromInP2pMode != null) { NeighborToken32 = reqReceivedFromInP2pMode.RemoteNeighborToken32; NeighborToken32.Encode(writer); } GetSharedSignedFields(writer, true, true); if (reqReceivedFromInP2pMode != null) { ReqP2pSeq16.Encode(writer); this.NeighborHMAC = reqReceivedFromInP2pMode.GetNeighborHMAC(this.GetSignedFieldsForNeighborHMAC); this.NeighborHMAC.Encode(writer); } else { BinaryProcedures.EncodeIPEndPoint(writer, RequesterEndpoint); } return(ms.ToArray()); }
/// <param name="reqReceivedFromInP2pMode">is not null for packets between registered peers</param> public byte[] Encode_OpionallySignNeighborHMAC(ConnectionToNeighbor reqReceivedFromInP2pMode) { BinaryProcedures.CreateBinaryWriter(out var ms, out var writer); writer.Write((byte)PacketTypes.Failure); byte flags = 0; if (reqReceivedFromInP2pMode == null) { flags |= Flag_EPtoA; } writer.Write(flags); if (reqReceivedFromInP2pMode != null) { NeighborToken32 = reqReceivedFromInP2pMode.RemoteNeighborToken32; NeighborToken32.Encode(writer); } ReqP2pSeq16.Encode(writer); writer.Write((byte)ResponseCode); if (reqReceivedFromInP2pMode != null) { this.NeighborHMAC = reqReceivedFromInP2pMode.GetNeighborHMAC(this.GetSignedFieldsForNeighborHMAC); this.NeighborHMAC.Encode(writer); } return(ms.ToArray()); }
public static InviteRequestPacket Decode_VerifyNeighborHMAC(byte[] udpData, ConnectionToNeighbor receivedFromNeighbor) { var r = new InviteRequestPacket(); r.DecodedUdpPayloadData = udpData; var reader = PacketProcedures.CreateBinaryReader(udpData, 1); var flags = reader.ReadByte(); if ((flags & FlagsMask_MustBeZero) != 0) { throw new NotImplementedException(); } r.NeighborToken32 = NeighborToken32.Decode(reader); if (receivedFromNeighbor.LocalNeighborToken32.Equals(r.NeighborToken32) == false) { throw new UnmatchedFieldsException(); } r.ReqTimestamp32S = reader.ReadUInt32(); r.RequesterRegistrationId = RegistrationId.Decode(reader); r.ResponderRegistrationId = RegistrationId.Decode(reader); r.RequesterEcdhePublicKey = EcdhPublicKey.Decode(reader); r.RequesterRegistrationSignature = RegistrationSignature.Decode(reader); r.NumberOfHopsRemaining = reader.ReadByte(); r.ReqP2pSeq16 = RequestP2pSequenceNumber16.Decode(reader); r.NeighborHMAC = HMAC.Decode(reader); if (r.NeighborHMAC.Equals(receivedFromNeighbor.GetNeighborHMAC(r.GetSignedFieldsForNeighborHMAC)) == false) { throw new BadSignatureException("invalid INVITE REQ NeighborHMAC 5902"); } return(r); }
/// <param name="connectionToNeighbor">is not null for packets between registered peers</param> public byte[] Encode_OptionallySignNeighborHMAC(ConnectionToNeighbor connectionToNeighbor) { BinaryProcedures.CreateBinaryWriter(out var ms, out var writer); writer.Write((byte)PacketTypes.RegisterConfirmation); Flags = 0; if (connectionToNeighbor == null) { Flags |= Flag_AtoEP; } writer.Write(Flags); if (connectionToNeighbor != null) { NeighborToken32 = connectionToNeighbor.RemoteNeighborToken32; NeighborToken32.Encode(writer); } writer.Write(ReqTimestamp64); RequesterRegistrationId.Encode(writer); ResponderRegistrationConfirmationSignature.Encode(writer); RequesterRegistrationConfirmationSignature.Encode(writer); ReqP2pSeq16.Encode(writer); if (connectionToNeighbor != null) { this.NeighborHMAC = connectionToNeighbor.GetNeighborHMAC(this.GetSignedFieldsForNeighborHMAC); this.NeighborHMAC.Encode(writer); } return(ms.ToArray()); }
/// <param name="connectionToNeighborNullable"> /// peer that sends ACK2 /// if not null - the scanner will verify ACK2.NeighborHMAC /// </param> public static LowLevelUdpResponseScanner GetScanner(Logger logger, ConnectionToNeighbor connectionToNeighborNullable, RegisterRequestPacket req) { BinaryProcedures.CreateBinaryWriter(out var ms, out var writer); writer.Write((byte)PacketTypes.RegisterAck2); writer.Write((byte)0); // ignored flags if (connectionToNeighborNullable != null) { connectionToNeighborNullable.LocalNeighborToken32.Encode(writer); } writer.Write(req.ReqTimestamp64); req.RequesterRegistrationId.Encode(writer); var r = new LowLevelUdpResponseScanner { IgnoredByteAtOffset1 = 1, ResponseFirstBytes = ms.ToArray() }; if (connectionToNeighborNullable != null) { r.OptionalFilter = (responseData) => { if (connectionToNeighborNullable.IsDisposed) { logger.WriteToLog_needsAttention("ignoring ACK2: connection is disposed"); return(false); } var ack2 = Decode_OptionallyVerify_InitializeP2pStreamAtResponder(logger, responseData, null, null, null); if (ack2.NeighborHMAC.Equals(connectionToNeighborNullable.GetNeighborHMAC(ack2.GetSignedFieldsForNeighborHMAC)) == false) { logger.WriteToLog_attacks("ignoring ACK2: received NeighborHMAC is invalid"); return(false); } return(true); }; } return(r); }
/// <param name="connectionToNeighborNullable">is not null for packets between registered peers. if set, the procedure sets NeighborToken32 and NeighborHMAC</param> public byte[] Encode_OptionallySignNeighborHMAC(ConnectionToNeighbor connectionToNeighborNullable) { PacketProcedures.CreateBinaryWriter(out var ms, out var writer); writer.Write((byte)PacketTypes.RegisterReq); byte flags = 0; if (connectionToNeighborNullable == null) { flags |= Flag_AtoEP; } if (DirectionVectorNullable != null) { flags |= Flag_DirectionVectorExists; } writer.Write(flags); if (connectionToNeighborNullable != null) { NeighborToken32 = connectionToNeighborNullable.RemoteNeighborToken32; NeighborToken32.Encode(writer); } GetSharedSignedFields(writer, true); if (connectionToNeighborNullable == null) { if (ProofOfWork2.Length != 64) { throw new ArgumentException(); } writer.Write(ProofOfWork2); } writer.Write(NumberOfHopsRemaining); writer.Write(NumberOfRandomHopsRemaining); ReqP2pSeq16.Encode(writer); if (connectionToNeighborNullable != null) { NeighborHMAC = connectionToNeighborNullable.GetNeighborHMAC(this.GetSignedFieldsForNeighborHMAC); NeighborHMAC.Encode(writer); } return(ms.ToArray()); }
public byte[] Encode_SetP2pFields(ConnectionToNeighbor transmitToNeighbor) { PacketProcedures.CreateBinaryWriter(out var ms, out var w); w.Write((byte)PacketTypes.InviteReq); byte flags = 0; w.Write(flags); ReqP2pSeq16 = transmitToNeighbor.GetNewRequestP2pSeq16_P2P(); NeighborToken32 = transmitToNeighbor.RemoteNeighborToken32; NeighborToken32.Encode(w); GetSignedFieldsForNeighborHMAC(w); NeighborHMAC = transmitToNeighbor.GetNeighborHMAC(GetSignedFieldsForNeighborHMAC); NeighborHMAC.Encode(w); return(ms.ToArray()); }
/// <summary> /// creates a scanner that finds CFM that matches to REQ /// the scanner will verify CFM.NeighborHMAC /// </summary> /// <param name="connectionToNeighbor"> /// peer that responds with CFM /// </param> public static LowLevelUdpResponseScanner GetScanner(Logger logger, InviteRequestPacket req, ConnectionToNeighbor connectionToNeighbor) { PacketProcedures.CreateBinaryWriter(out var ms, out var w); w.Write((byte)PacketTypes.InviteCfm); w.Write((byte)0); // flags connectionToNeighbor.LocalNeighborToken32.Encode(w); w.Write(req.ReqTimestamp32S); req.RequesterRegistrationId.Encode(w); req.ResponderRegistrationId.Encode(w); var r = new LowLevelUdpResponseScanner { ResponseFirstBytes = ms.ToArray(), IgnoredByteAtOffset1 = 1 // ignore flags }; r.OptionalFilter = (responseData) => { if (connectionToNeighbor.IsDisposed) { logger.WriteToLog_needsAttention("ignoring CFM: connection is disposed"); return(false); } var cfm = Decode(responseData); if (cfm.NeighborHMAC.Equals(connectionToNeighbor.GetNeighborHMAC(cfm.GetSignedFieldsForNeighborHMAC)) == false) { logger.WriteToLog_attacks("ignoring CFM: received NeighborHMAC is invalid"); return(false); } return(true); }; return(r); }
/// <param name="newConnectionAtResponderToRequesterNullable"> /// direct P2P stream from N to A /// if newConnectionAtResponderToRequesterNullable is specified, the procedure /// verifies RequesterHMAC, decrypts endpoint of A (ToRequesterTxParametersEncrypted), initializes P2P stream /// </param> public static RegisterAck2Packet Decode_OptionallyVerify_InitializeP2pStreamAtResponder(Logger logger, byte[] registerAckPacketData, RegisterRequestPacket reqNullable, RegisterAck1Packet ack1Nullable, ConnectionToNeighbor newConnectionAtResponderToRequesterNullable ) { var reader = BinaryProcedures.CreateBinaryReader(registerAckPacketData, 1); var ack = new RegisterAck2Packet(); ack.DecodedUdpPayloadData = registerAckPacketData; ack.Flags = reader.ReadByte(); if ((ack.Flags & FlagsMask_MustBeZero) != 0) { throw new NotImplementedException(); } if ((ack.Flags & Flag_AtoEP) == 0) { ack.NeighborToken32 = NeighborToken32.Decode(reader); } ack.ReqTimestamp64 = reader.ReadInt64(); ack.RequesterRegistrationId = RegistrationId.Decode(reader); if (reqNullable != null) { ack.AssertMatchToSyn(reqNullable); } ack.ToRequesterTxParametersEncrypted = reader.ReadBytes(ToRequesterTxParametersEncryptedLength); if (newConnectionAtResponderToRequesterNullable != null) { newConnectionAtResponderToRequesterNullable.Decrypt_ack2_ToRequesterTxParametersEncrypted_AtResponder_InitializeP2pStream(logger, reqNullable, ack1Nullable, ack); } ack.RequesterSignature = RegistrationSignature.Decode(reader); if (newConnectionAtResponderToRequesterNullable != null) { if (reqNullable == null) { throw new ArgumentException(); } if (ack1Nullable == null) { throw new ArgumentException(); } if (!ack.RequesterSignature.Verify(newConnectionAtResponderToRequesterNullable.Engine.CryptoLibrary, w => { reqNullable.GetSharedSignedFields(w, true); ack1Nullable.GetSharedSignedFields(w, true, true); ack.GetSharedSignedFields(w, false, true); }, reqNullable.RequesterRegistrationId)) { throw new BadSignatureException("invalid REGISTER ACK2 RequesterSignature 6106"); } } ack.ReqP2pSeq16 = RequestP2pSequenceNumber16.Decode(reader); if ((ack.Flags & Flag_AtoEP) == 0) { ack.NeighborHMAC = HMAC.Decode(reader); // is verified by Filter } return(ack); }
/// <summary> /// creates a scanner that finds ACK1 that matches to REQ /// </summary> /// <param name="connectionToNeighborNullable"> /// peer that responds to REQ with ACK1 /// if not null - the scanner will verify ACK1.NeighborHMAC /// </param> public static LowLevelUdpResponseScanner GetScanner(Logger logger, RequestP2pSequenceNumber16 reqP2pSeq16, ConnectionToNeighbor connectionToNeighborNullable = null) { if (logger.WriteToLog_detail_enabled) { logger.WriteToLog_detail($">> FailurePacket.GetScanner() reqP2pSeq16={reqP2pSeq16}"); } BinaryProcedures.CreateBinaryWriter(out var ms, out var w); w.Write((byte)PacketTypes.Failure); w.Write((byte)0); if (connectionToNeighborNullable != null) { connectionToNeighborNullable.LocalNeighborToken32.Encode(w); } reqP2pSeq16.Encode(w); var r = new LowLevelUdpResponseScanner { ResponseFirstBytes = ms.ToArray(), IgnoredByteAtOffset1 = 1 // ignore flags }; if (connectionToNeighborNullable != null) { r.OptionalFilter = (responseData) => { if (logger.WriteToLog_detail_enabled) { logger.WriteToLog_detail($"filtering FAILURE @scanner: hash={MiscProcedures.GetArrayHashCodeString(responseData)}"); } if (connectionToNeighborNullable.IsDisposed) { logger.WriteToLog_needsAttention("ignoring FAILURE: connection is disposed"); return(false); } var failure = DecodeAndOptionallyVerify(responseData, reqP2pSeq16); if (failure.NeighborHMAC.Equals(connectionToNeighborNullable.GetNeighborHMAC(failure.GetSignedFieldsForNeighborHMAC)) == false) { logger.WriteToLog_attacks("ignoring FAILURE: received HMAC is invalid"); return(false); } return(true); }; } return(r); }
/// <param name="waitNpaFromNeighborNullable">is used to verify NPACK.NeighborHMAC</param> public static LowLevelUdpResponseScanner GetScanner(RequestP2pSequenceNumber16 reqP2pSeq16, ConnectionToNeighbor waitNpaFromNeighborNullable = null, Action <BinaryWriter> npaRequestFieldsForNeighborHmacNullable = null) { PacketProcedures.CreateBinaryWriter(out var ms, out var w); EncodeHeader(w, reqP2pSeq16); var r = new LowLevelUdpResponseScanner { ResponseFirstBytes = ms.ToArray() }; if (waitNpaFromNeighborNullable != null) { if (npaRequestFieldsForNeighborHmacNullable == null) { throw new ArgumentNullException(); } r.OptionalFilter = (responseData) => { if (waitNpaFromNeighborNullable.IsDisposed) { return(false); } var npack = new NeighborPeerAckPacket(responseData); if (npack.NeighborHMAC == null) { return(false); } if (!npack.NeighborHMAC.Equals(waitNpaFromNeighborNullable.GetNeighborHMAC(w2 => npack.GetSignedFieldsForNeighborHMAC(w2, npaRequestFieldsForNeighborHmacNullable)))) { return(false); } return(true); }; } return(r); }
/// <summary> /// when REQ is received from neighbor, verifies senderHMAC and NeighborToken32 /// </summary> /// <param name="receivedFromNeighborNullable">is NULL when decoding REQ from A at EP</param> public static RegisterRequestPacket Decode_OptionallyVerifyNeighborHMAC(byte[] udpData, ConnectionToNeighbor receivedFromNeighborNullable, int numberOfDimensions) { var r = new RegisterRequestPacket(); r.DecodedUdpPayloadData = udpData; var reader = PacketProcedures.CreateBinaryReader(udpData, 1); var flags = reader.ReadByte(); if ((flags & FlagsMask_MustBeZero) != 0) { throw new NotImplementedException(); } if ((flags & Flag_AtoEP) == 0) { if (receivedFromNeighborNullable == null) { throw new UnmatchedFieldsException(); } r.NeighborToken32 = NeighborToken32.Decode(reader); if (receivedFromNeighborNullable.LocalNeighborToken32.Equals(r.NeighborToken32) == false) { throw new UnmatchedFieldsException(); } } else { if (receivedFromNeighborNullable != null) { throw new UnmatchedFieldsException(); } } r.RequesterRegistrationId = RegistrationId.Decode(reader); r.RequesterNeighborsBusySectorIds = reader.ReadUInt16(); r.RequesterEcdhePublicKey = EcdhPublicKey.Decode(reader); r.ReqTimestamp64 = reader.ReadInt64(); r.MinimalDistanceToNeighbor = reader.ReadUInt32(); if ((flags & Flag_DirectionVectorExists) != 0) { r.DirectionVectorNullable = new sbyte[numberOfDimensions]; for (int i = 0; i < numberOfDimensions; i++) { r.DirectionVectorNullable[i] = reader.ReadSByte(); } } r.EpEndpoint = PacketProcedures.DecodeIPEndPoint(reader); r.RequesterSignature = RegistrationSignature.Decode(reader); if ((flags & Flag_AtoEP) != 0) { r.ProofOfWork2 = reader.ReadBytes(64); } r.NumberOfHopsRemaining = reader.ReadByte(); r.NumberOfRandomHopsRemaining = reader.ReadByte(); r.ReqP2pSeq16 = RequestP2pSequenceNumber16.Decode(reader); if ((flags & Flag_AtoEP) == 0) { r.NeighborHMAC = HMAC.Decode(reader); if (r.NeighborHMAC.Equals(receivedFromNeighborNullable.GetNeighborHMAC(r.GetSignedFieldsForNeighborHMAC)) == false) { throw new BadSignatureException("invalid REGISTER REQ NeighborHMAC 1573"); } } return(r); }
/// <summary> /// decodes the packet, decrypts ToNeighborTxParametersEncrypted, verifies NeighborSignature, verifies match to register REQ /// </summary> /// <param name="newConnectionToNeighborAtRequesterNullable">if not null (at requester) - this procedure verifies ResponderSignature</param> /// <param name="reader">is positioned after first byte = packet type</param> public static RegisterAck1Packet DecodeAndOptionallyVerify(Logger logger, byte[] ack1UdpData, RegisterRequestPacket reqNullable, ConnectionToNeighbor newConnectionToNeighborAtRequesterNullable) { var reader = BinaryProcedures.CreateBinaryReader(ack1UdpData, 1); var ack1 = new RegisterAck1Packet(); ack1.DecodedUdpPayloadData = ack1UdpData; ack1.Flags = reader.ReadByte(); if ((ack1.Flags & Flag_EPtoA) == 0) { ack1.NeighborToken32 = NeighborToken32.Decode(reader); } if ((ack1.Flags & FlagsMask_MustBeZero) != 0) { throw new NotImplementedException(); } ack1.RequesterRegistrationId = RegistrationId.Decode(reader); ack1.ReqTimestamp64 = reader.ReadInt64(); ack1.ResponderEcdhePublicKey = EcdhPublicKey.Decode(reader); ack1.ToResponderTxParametersEncrypted = reader.ReadBytes(ToResponderTxParametersEncryptedLength); ack1.ResponderRegistrationId = RegistrationId.Decode(reader); if (newConnectionToNeighborAtRequesterNullable != null) { if (reqNullable == null) { throw new ArgumentException(); } ack1.ResponderSignature = RegistrationSignature.DecodeAndVerify( reader, newConnectionToNeighborAtRequesterNullable.Engine.CryptoLibrary, w => { reqNullable.GetSharedSignedFields(w, true); ack1.GetSharedSignedFields(w, false, true); }, ack1.ResponderRegistrationId); } else { // at proxy we don't verify responder's signature, to avoid high spending of resources ack1.ResponderSignature = RegistrationSignature.Decode(reader); } if (reqNullable != null) { ack1.AssertMatchToRegisterReq(reqNullable); if (newConnectionToNeighborAtRequesterNullable != null) { newConnectionToNeighborAtRequesterNullable.Decrypt_ack1_ToResponderTxParametersEncrypted_AtRequester_DeriveSharedDhSecret(logger, reqNullable, ack1); } } if ((ack1.Flags & Flag_EPtoA) != 0) { ack1.RequesterEndpoint = BinaryProcedures.DecodeIPEndPoint(reader); } else { ack1.ReqP2pSeq16 = RequestP2pSequenceNumber16.Decode(reader); ack1.NeighborHMAC = HMAC.Decode(reader); } return(ack1); }
public static RegisterConfirmationPacket DecodeAndOptionallyVerify(byte[] regCfmUdpPayload, RegisterRequestPacket reqNullable, ConnectionToNeighbor newConnectionToRequesterAtResponderNullable) { var reader = BinaryProcedures.CreateBinaryReader(regCfmUdpPayload, 1); var cfm = new RegisterConfirmationPacket(); cfm.DecodedUdpPayloadData = regCfmUdpPayload; cfm.Flags = reader.ReadByte(); if ((cfm.Flags & FlagsMask_MustBeZero) != 0) { throw new NotImplementedException(); } if ((cfm.Flags & Flag_AtoEP) == 0) { cfm.NeighborToken32 = NeighborToken32.Decode(reader); } cfm.ReqTimestamp64 = reader.ReadInt64(); cfm.RequesterRegistrationId = RegistrationId.Decode(reader); if (reqNullable != null) { cfm.AssertMatchToRegisterReq(reqNullable); } if (newConnectionToRequesterAtResponderNullable != null) { cfm.ResponderRegistrationConfirmationSignature = RegistrationSignature.DecodeAndVerify(reader, newConnectionToRequesterAtResponderNullable.Engine.CryptoLibrary, w => newConnectionToRequesterAtResponderNullable.GetResponderRegistrationConfirmationSignatureFields(w), newConnectionToRequesterAtResponderNullable.LocalDrpPeer.Configuration.LocalPeerRegistrationId ); cfm.RequesterRegistrationConfirmationSignature = RegistrationSignature.DecodeAndVerify(reader, newConnectionToRequesterAtResponderNullable.Engine.CryptoLibrary, w => newConnectionToRequesterAtResponderNullable.GetRequesterRegistrationConfirmationSignatureFields(w, cfm.ResponderRegistrationConfirmationSignature), newConnectionToRequesterAtResponderNullable.RemoteRegistrationId ); } else { cfm.ResponderRegistrationConfirmationSignature = RegistrationSignature.Decode(reader); cfm.RequesterRegistrationConfirmationSignature = RegistrationSignature.Decode(reader); } cfm.ReqP2pSeq16 = RequestP2pSequenceNumber16.Decode(reader); if ((cfm.Flags & Flag_AtoEP) == 0) { cfm.NeighborHMAC = HMAC.Decode(reader); } return(cfm); }