private SSUState AssembleFragments(SSUHeader header, BufRefLen reader, byte info, ushort cursize) { var fragnr = info >> 4; var fragcount = info & 0x0f; if (fragnr == fragcount - 1) { ASignonTime = reader.Read32(); reader.Seek(reader.Length - Session.RemoteRouter.Certificate.SignatureLength); ASign = new I2PSignature(reader, Session.RemoteRouter.Certificate); } else { Fragments[fragnr] = reader.ReadBufLen(cursize); } if (Fragments.Any(f => f == null)) { return(this); } Session.RemoteRouter = new I2PRouterIdentity(new BufRefLen(Fragments.SelectMany(f => f.ToByteArray()).ToArray())); return(VerifyRemoteSignature()); }
public virtual SSUState DatagramReceived(BufRefLen recv, IPEndPoint RemoteEP) { // Verify the MAC var reader = new BufRefLen(recv); var header = new SSUHeader(reader); var recvencr = header.EncryptedBuf; var macstate = VerifyMAC(header, CurrentMACKey); var usekey = CurrentPayloadKey; switch (macstate) { case MACHealth.AbandonSession: return(null); case MACHealth.Missmatch: return(this); case MACHealth.UseOurIntroKey: usekey = Session.MyRouterContext.IntroKey; break; } // Decrypt Cipher.Init(false, usekey.ToParametersWithIV(header.IV)); Cipher.ProcessBytes(recvencr); header.SkipExtendedHeaders(reader); return(HandleMessage(header, reader)); }
internal void ReportRelayResponse(SSUHeader header, RelayResponse response, IPEndPoint ep) { if (RelayResponseReceived != null) { lock ( RelayResponseReceivedLock ) { RelayResponseReceived(header, response, ep); } } }
protected MACHealth VerifyMAC(SSUHeader header, BufLen key) { var macdata = new BufLen[] { header.MACDataBuf, header.IV, BufUtils.Flip16BL((ushort)((ushort)header.MACDataBuf.Length ^ I2PConstants.SSU_PROTOCOL_VERSION)) }; var recvhash = I2PHMACMD5Digest.Generate(macdata, key, MACBuf); var ok = header.MAC.Equals(recvhash); if (ok) { IntroMACsReceived = 0; } else { DebugUtils.LogDebug(() => string.Format("SSU {0}: {1} Current MAC check fail. Payload {2} bytes. ", this, Session.DebugId, header.MACDataBuf.Length)); if ((int)DebugUtils.LogLevel <= (int)DebugUtils.LogLevels.Debug) { if (Session.IntroKey != null) { var recvhashi = I2PHMACMD5Digest.Generate(macdata, new BufLen(Session.IntroKey), MACBuf); var oki = header.MAC.Equals(recvhashi); DebugUtils.Log("SSU " + this.ToString() + ": " + Session.DebugId + ". " + "Session Intro key match: " + oki.ToString()); } } var recvhash2 = I2PHMACMD5Digest.Generate(macdata, new BufLen(Session.MyRouterContext.IntroKey), MACBuf); var ok2 = header.MAC.Equals(recvhash2); DebugUtils.LogDebug(() => string.Format("SSU {0}: {1} My intro MAC key match: {3}. Payload {2} bytes. ", this, Session.DebugId, header.MACDataBuf.Length, ok2)); if (ok2) { if (++IntroMACsReceived > 5) { var reason = string.Format("SSU {0}: {1}. {2} intro key matches in a row. The other side seems to have started a new session.", this, Session.DebugId, IntroMACsReceived); DebugUtils.Log(reason); return(MACHealth.AbandonSession); } return(MACHealth.UseOurIntroKey); } } return(ok ? MACHealth.Match : MACHealth.Missmatch); }
public override SSUState HandleMessage(SSUHeader header, BufRefLen reader) { #if LOG_ALL_TRANSPORT Logging.LogTransport($"SSU RelayRequestState: {Session.DebugId} Received {header.MessageType}"); #endif if (header.MessageType == SSUHeader.MessageTypes.RelayResponse) { var response = new RelayResponse(reader); return(HandleRelayResponse(response)); } return(this); }
public override SSUState HandleMessage(SSUHeader header, BufRefLen reader) { switch (header.MessageType) { case SSUHeader.MessageTypes.SessionRequest: var req = new SessionRequest(reader, I2PPublicKey.DefaultAsymetricKeyCert); DebugUtils.Log("SSU SessionCreatedState " + Session.DebugId + " : OK SessionRequest received."); BufUtils.DHI2PToSessionAndMAC(out Session.SharedKey, out Session.MACKey, req.XKey.ModPow(PrivateKey.ToBigInteger(), I2PConstants.ElGamalP)); Session.Host.ReportedAddress(new IPAddress(req.Address.ToByteArray())); // TODO: Remove comment when relaying is implemented /* * if ( header.ExtendedOptions != null ) * { * if ( header.ExtendedOptions.Length == 2 && ( ( header.ExtendedOptions[0] & 0x01 ) != 0 ) ) * { * RelayTag = BufUtils.RandomUint(); * } * }*/ Request = req; SendSessionCreated(); return(this); case SSUHeader.MessageTypes.RelayResponse: DebugUtils.LogDebug(() => string.Format("SSU SessionCreatedState {0}: RelayResponse received from {1}.", Session.DebugId, (Session.RemoteEP == null ? "<null>" : Session.RemoteEP.ToString()))); var response = new RelayResponse(reader); Session.Host.ReportRelayResponse(header, response, Session.RemoteEP); break; case SSUHeader.MessageTypes.SessionConfirmed: return(ParseSessionConfirmed(header, reader)); case SSUHeader.MessageTypes.PeerTest: HandleIncomingPeerTestPackage(reader); break; default: DebugUtils.Log("SSU SessionCreatedState: Session " + Session.DebugId + " Unexpected Message: " + header.MessageType.ToString()); break; } return(this); }
void Host_RelayResponseReceived(SSUHeader header, RelayResponse response, IPEndPoint ep) { if (header.MessageType == SSUHeader.MessageTypes.RelayResponse) { if (ep.Address.Equals(CurrentIntroducer.EndPoint.Address)) { HandleRelayResponse(response); } else { Logging.LogTransport( $"SSU RelayRequestState: {Session.DebugId} RelayResponse from {ep.Address} received. Waiting for response from {CurrentIntroducer.EndPoint.Address}."); } } }
public override SSUState HandleMessage(SSUHeader header, BufRefLen reader) { if (header.MessageType == SSUHeader.MessageTypes.SessionCreated) { #if LOG_ALL_TRANSPORT Logging.LogTransport("SSU SessionConfirmedState " + Session.DebugId + ": Unexpected message received: " + header.MessageType.ToString()); #endif return(this); } Logging.LogTransport("SSU SessionConfirmedState: Session " + Session.DebugId + " established. " + header.MessageType.ToString() + " received. Moving to Established state."); var next = new EstablishedState(Session); Session.ReportConnectionEstablished(); return(next.HandleMessage(header, reader)); }
private SSUState ParseSessionConfirmed(SSUHeader header, BufRefLen reader) { var info = reader.Read8(); var cursize = reader.ReadFlip16(); if (Fragments != null) { return(AssembleFragments(header, reader, info, cursize)); } if ((info & 0x0f) == 1) { var cursizedata = reader.ReadBufRefLen(cursize); Session.RemoteRouter = new I2PRouterIdentity(cursizedata); ASignonTime = reader.Read32(); reader.Seek(reader.Length - Session.RemoteRouter.Certificate.SignatureLength); ASign = new I2PSignature(reader, Session.RemoteRouter.Certificate); return(VerifyRemoteSignature()); } Fragments = new List <BufLen>(new BufLen[info & 0x0f]); return(AssembleFragments(header, reader, info, cursize)); }
public override SSUState HandleMessage(SSUHeader header, BufRefLen reader) { var tstime = SSUHost.SSUDateTime(header.TimeStamp); if (header.MessageType != SSUHeader.MessageTypes.SessionCreated) { #if LOG_ALL_TRANSPORT Logging.LogTransport("SSU SessionRequestState: Received unexpected message " + tstime.ToString() + " : " + header.Flag.ToString()); #endif return(this); } SCMessage = new SessionCreated(reader, Session.RemoteRouter.Certificate); Session.RelayTag = SCMessage.RelayTag; Y = new I2PPublicKey((BufRefLen)SCMessage.Y, Session.RemoteRouter.Certificate); BufUtils.DHI2PToSessionAndMAC(out Session.SharedKey, out Session.MACKey, Y.ToBigInteger().ModPow(PrivateKey.ToBigInteger(), I2PConstants.ElGamalP)); var ipaddr = new IPAddress(SCMessage.Address.ToByteArray()); ushort port = SCMessage.Port.PeekFlip16(0); Session.SignOnTimeB = SCMessage.SignOnTime.Peek32(0); var btime = SSUHost.SSUDateTime(BufUtils.Flip32(Session.SignOnTimeB)); #if LOG_ALL_TRANSPORT Logging.LogTransport("SSU SessionRequestState " + Session.DebugId + " : Received SessionCreated. " + tstime.ToString() + " : " + btime.ToString()); #endif Session.Host.ReportedAddress(ipaddr); if (!I2PSignature.SupportedSignatureType(Session.RemoteRouter.Certificate.SignatureType)) { throw new SignatureCheckFailureException("SSU SessionRequestState " + Session.DebugId + " : " + "Received non supported signature type: " + Session.RemoteRouter.Certificate.SignatureType.ToString()); } var cipher = new CbcBlockCipher(new AesEngine()); cipher.Init(false, Session.SharedKey.ToParametersWithIV(header.IV)); cipher.ProcessBytes(SCMessage.SignatureEncrBuf); var baddr = new BufLen(Session.RemoteEP.Address.GetAddressBytes()); var sign = new I2PSignature((BufRefLen)SCMessage.Signature, Session.RemoteRouter.Certificate); var sok = I2PSignature.DoVerify( Session.RemoteRouter.SigningPublicKey, sign, X.Key, Y.Key, SCMessage.Address, SCMessage.Port, baddr, BufUtils.Flip16BL((ushort)Session.RemoteEP.Port), SCMessage.RelayTag, SCMessage.SignOnTime); #if LOG_ALL_TRANSPORT Logging.LogTransport("SSU SessionRequestState: Signature check: " + sok.ToString() + ". " + Session.RemoteRouter.Certificate.SignatureType.ToString()); #endif if (!sok) { throw new SignatureCheckFailureException("SSU SessionRequestState " + Session.DebugId + ": Received SessionCreated signature check failed." + Session.RemoteRouter.Certificate.ToString()); } var relaytag = SCMessage.RelayTag.PeekFlip32(0); if (relaytag != 0) { Session.Host.IntroductionRelayOffered( new IntroducerInfo( Session.RemoteEP.Address, (ushort)Session.RemoteEP.Port, Session.IntroKey, relaytag)); } Logging.LogTransport("SSU SessionRequestState: Session " + Session.DebugId + " created. Moving to SessionConfirmedState."); Session.ReportConnectionEstablished(); return(new SessionConfirmedState(Session, this)); }
// MAC verified and packet dectrypted public abstract SSUState HandleMessage(SSUHeader header, BufRefLen reader);
/** * From PacketBuilder.java * -----8<----- * @param packet prepared packet with the first 32 bytes empty and a length * whose size is mod 16. * As of 0.9.7, length non-mod-16 is allowed; the * last 1-15 bytes are included in the MAC calculation but are not encrypted. * -----8<----- */ protected void SendMessage( IPEndPoint dest, SSUHeader.MessageTypes message, BufLen mackey, BufLen cryptokey, SendMessageGenerator gen, SendMessageGenerator genextrapadding) { var start = Session.Host.SendBuffers.Pop(); var writer = new BufRefLen(start); var header = new SSUHeader(writer, message); if (!gen(start, writer)) { return; } // Do not cut to datalen & ~0xf as that might make data at the end unencrypted var datapadding = BufUtils.Get16BytePadding(writer - start); writer.Write(BufUtils.Random(datapadding)); var datalen = writer - start; var encryptedbuf = new BufLen(start, 32, datalen - 32); // TODO: Adding extra padding does not seem to work if (genextrapadding != null) { if (!genextrapadding(start, writer)) { return; } } var packetlen = writer - start; var data = new BufLen(start, 0, packetlen); var hmac = new BufLen(data, 32); SendMessageCipher.Init(true, cryptokey.ToParametersWithIV(header.IV)); SendMessageCipher.ProcessBytes(encryptedbuf); I2PHMACMD5Digest.Generate(new BufLen[] { hmac, header.IV, BufUtils.Flip16BL((ushort)((ushort)hmac.Length ^ I2PConstants.SSU_PROTOCOL_VERSION)) }, mackey, header.MAC); #if LOG_ALL_TRANSPORT DebugUtils.Log(string.Format("SSUState SendMessage {0}: encrlen {1} bytes [0x{1:X}] (padding {2} bytes [0x{2:X}]), " + "hmac {3} bytes [0x{3:X}], sendlen {4} bytes [0x{4:X}]", Session.DebugId, encryptedbuf.Length, datapadding, hmac.Length, data.Length)); #endif DataSent(); Session.Host.Send(dest, data); }
public override SSUState HandleMessage(SSUHeader header, BufRefLen reader) { DataSent(); #if LOG_ALL_TRANSPORT DebugUtils.Log("SSU EstablishedState +" + Session.TransportInstance.ToString() + "+ received: " + header.MessageType.ToString() + ": " + SSUHost.SSUDateTime(header.TimeStamp).ToString()); #endif switch (header.MessageType) { case SSUHeader.MessageTypes.Data: try { var datamsg = new SSUDataMessage(reader, Session.Defragmenter); if (datamsg.ExplicitAcks != null) { Session.Fragmenter.GotAck(datamsg.ExplicitAcks); } if (datamsg.AckBitfields != null) { Session.Fragmenter.GotAck(datamsg.AckBitfields); } if (datamsg.NewMessages != null) { foreach (var msg in datamsg.NewMessages) { var i2npmsg = I2NPMessage.ReadHeader5((BufRefLen)msg.GetPayload()); #if LOG_ALL_TRANSPORT DebugUtils.Log("SSU EstablishedState +" + Session.TransportInstance.ToString() + "+ complete message " + msg.MessageId.ToString() + ": " + i2npmsg.Expiration.ToString()); #endif if (i2npmsg.MessageType == I2PCore.Tunnel.I2NP.Messages.I2NPMessage.MessageTypes.DeliveryStatus) { if (((DeliveryStatusMessage)i2npmsg.Message).IsNetworkId((ulong)I2PConstants.I2P_NETWORK_ID)) { continue; } } Session.MessageReceived(i2npmsg); } } } catch (Exception ex) { DebugUtils.Log("EstablishedState: SSUHost.SSUMessageTypes.Data", ex); } break; case SSUHeader.MessageTypes.SessionDestroyed: DebugUtils.LogDebug(() => string.Format("SSU EstablishedState {0}: SessionDestroyed received.", Session.DebugId)); SendSessionDestroyed(); return(null); case SSUHeader.MessageTypes.PeerTest: HandleIncomingPeerTestPackage(reader); break; case SSUHeader.MessageTypes.RelayResponse: DebugUtils.LogDebug(() => string.Format("SSU EstablishedState {0}: RelayResponse received from {1}.", Session.DebugId, Session.RemoteEP)); var response = new RelayResponse(reader); Session.Host.ReportRelayResponse(header, response, Session.RemoteEP); break; case SSUHeader.MessageTypes.RelayIntro: var intro = new RelayIntro(reader); DebugUtils.LogDebug(() => $"SSU EstablishedState {Session.DebugId}: RelayIntro received from {Session.RemoteEP} for {intro.AliceEndpoint}."); Session.Host.Send(intro.AliceEndpoint, new BufLen(new byte[0])); break; case SSUHeader.MessageTypes.RelayRequest: // if ( !SSUHost.IntroductionSupported ) throw new Exception( "SSU relay introduction not supported" ); DebugUtils.LogDebug(() => string.Format("SSU EstablishedState {0}: Relay introduction not supported.", Session.DebugId)); break; case SSUHeader.MessageTypes.SessionRequest: DebugUtils.LogDebug(() => string.Format("SSU EstablishedState {0}: SessionRequest received. Ending session.", Session.DebugId)); SendSessionDestroyed(); return(null); default: DebugUtils.LogDebug(() => string.Format("SSU EstablishedState {0}: Unexpected message received: {1}.", Session.DebugId, header.MessageType)); break; } return(this); }