public static (GarlicAESBlock, I2PSessionKey) EGDecryptGarlic( GarlicMessage garlic, I2PPrivateKey privkey) { var cipher = new CbcBlockCipher(new AesEngine()); var egdata = garlic.EGData; var egbuf = new BufLen(egdata, 0, 514); var egheader = ElGamalCrypto.Decrypt(egbuf, privkey, true); var sessionkey = new I2PSessionKey(new BufLen(egheader, 0, 32)); var preiv = new BufLen(egheader, 32, 32); var egpadding = new BufLen(egheader, 64, 158); var aesbuf = new BufLen(egdata, 514); var pivh = I2PHashSHA256.GetHash(preiv); cipher.Init(false, sessionkey.Key.ToParametersWithIV(new BufLen(pivh, 0, 16))); cipher.ProcessBytes(aesbuf); GarlicAESBlock aesblock = new GarlicAESBlock(new BufRefLen(aesbuf)); if (!aesblock.VerifyPayloadHash()) { throw new ChecksumFailureException("AES block hash check failed!"); } return(aesblock, sessionkey); }
internal void Run() { Resend.Do(() => { try { List <KeyValuePair <II2NPHeader16, GarlicCreationInfo> > tosend = new List <KeyValuePair <II2NPHeader16, GarlicCreationInfo> >(); lock ( Window ) { var resend = Window.Where(gci => gci.Value.LastSend.DeltaToNow > GarlicTimeBetweenResends); if (WaitingForEGAck != null && WaitingForEGAck.DeltaToNow > GarlicTimeBetweenResends) { DebugUtils.LogDebug("TagsTransferWindow: Run: ElGamal message needs to be resent. Starting over."); Session.Reset(); } foreach (var one in resend.ToArray()) { var egmsg = Session.Encrypt(true, one.Value.TrackingId, one.Value.Cloves); var npmsg = new GarlicMessage(egmsg.Garlic).GetHeader16(I2NPHeader.GenerateMessageId()); one.Value.LastSend.SetNow(); tosend.Add(new KeyValuePair <II2NPHeader16, GarlicCreationInfo>(npmsg, egmsg)); if (WaitingForEGAck == null && !one.Value.AckMessageId.HasValue) { // Non explicit ack cloves that should not be retransmitted any more. Window.Remove(one.Key); } } } foreach (var pair in tosend) { DebugUtils.LogDebug(string.Format("TagsTransferWindow: Resend: ({0}) TrackingId: {1}, Ack MessageId: {2}.", pair.Value.KeyType, pair.Value.TrackingId, pair.Value.AckMessageId)); if (pair.Value.AckMessageId.HasValue) { lock ( OutstandingMessageIds ) { OutstandingMessageIds[pair.Value.AckMessageId.Value] = pair.Value; } } TunnelSelector(Session.LatestRemoteLeaseSet, pair.Key, pair.Value); } } catch (Exception ex) { Session.Reset(); DebugUtils.Log("TagsTransferWindow Run", ex); } }); }
private static void HandleGarlic(GarlicMessage garlicmsg) { try { // No sessions, just accept EG var(aesblock, sessionkey) = Garlic.EGDecryptGarlic( garlicmsg, RouterContext.Inst.PrivateKey); if (aesblock == null) { Logging.LogWarning($"Router: HandleGarlic: Failed to decrypt."); return; } var garlic = new Garlic((BufRefLen)aesblock.Payload); #if LOG_ALL_LEASE_MGMT Logging.LogDebug($"Router: HandleGarlic: {garlic}"); #endif foreach (var clove in garlic.Cloves) { try { // Only accept Local to not turn into a bot net. switch (clove.Delivery.Delivery) { case GarlicCloveDelivery.DeliveryMethod.Local: #if LOG_ALL_LEASE_MGMT Logging.LogDebug( $"Router: HandleGarlic: Delivered Local: {clove.Message}"); #endif TunnelProvider.Inst.DistributeIncomingMessage(null, clove.Message.CreateHeader16); break; default: Logging.LogDebug($"Router HandleGarlic: Dropped clove ({clove})"); break; } } catch (Exception ex) { Logging.Log("Router: HandleGarlic switch", ex); } } } catch (Exception ex) { Logging.Log("Router: HandleGarlic", ex); } }
// Returns a tracking id supplied with events internal GarlicCreationInfo Send(bool explack, params GarlicCloveDelivery[] cloves) { GarlicCreationInfo egmsg = null; try { egmsg = Session.Encrypt(explack, I2NPHeader.GenerateMessageId(), cloves); var npmsg = new GarlicMessage(egmsg.Garlic).GetHeader16(I2NPHeader.GenerateMessageId()); if (explack || WaitingForEGAck != null || egmsg.KeyType == GarlicCreationInfo.KeyUsed.ElGamal) { if (egmsg.KeyType == GarlicCreationInfo.KeyUsed.ElGamal) { LatestEGMessage = egmsg; WaitingForEGAck = TickCounter.Now; } egmsg.LastSend = TickCounter.Now; lock ( Window ) { Window[egmsg.TrackingId] = egmsg; } } if (egmsg.AckMessageId.HasValue) { lock ( OutstandingMessageIds ) { OutstandingMessageIds[egmsg.AckMessageId.Value] = egmsg; } } DebugUtils.LogDebug(string.Format("TagsTransferWindow: Send: ({0}) TrackingId: {1}, Ack MessageId: {2}.", egmsg.KeyType, egmsg.TrackingId, egmsg.AckMessageId)); TunnelSelector(Session.LatestRemoteLeaseSet, npmsg, egmsg); } catch (Exception ex) { Session.Reset(); DebugUtils.Log("TagsTransferWindow Send", ex); } return(egmsg); }
public Garlic DecryptMessage(GarlicMessage message) { var egdata = message.EGData; var(aesblock, sessionkey) = Garlic.RetrieveAESBlock( message, PrivateKey, (stag) => { return(SessionTags.TryRemove(stag, out var sessionkeyfound) ? sessionkeyfound : null); }); if (aesblock is null) { Logging.LogDebug($"{Owner} ReceivedSessions: Aes block decrypt failed."); return(null); } #if LOG_ALL_LEASE_MGMT Logging.LogDebug($"{Owner} ReceivedSessions: Working Aes block received. {SessionTags.Count()} tags available."); #endif if (sessionkey != null && aesblock.Tags.Count > 0) { #if LOG_ALL_LEASE_MGMT Logging.LogDebug($"{Owner} ReceivedSessions: {aesblock.Tags.Count} new tags received."); #endif foreach (var onetag in aesblock.Tags) { SessionTags[new I2PSessionTag(new BufRef(onetag))] = sessionkey; } } return(new Garlic((BufRefLen)aesblock.Payload)); }
void InboundTunnel_GarlicMessageReceived(GarlicMessage msg) { try { var decr = IncommingSessions.DecryptMessage(msg.Garlic); if (decr == null) { return; } #if LOG_ALL_TUNNEL_TRANSFER DebugUtils.LogDebug("ClientDestination: GarlicMessageReceived: " + decr.ToString()); #endif foreach (var clove in decr.Cloves) { try { switch (clove.Delivery.Delivery) { case GarlicCloveDelivery.DeliveryMethod.Local: #if LOG_ALL_TUNNEL_TRANSFER DebugUtils.LogDebug(() => string.Format( "ClientDestination: GarlicMessageReceived: Delivered Local: {0}", clove.Message)); #endif TunnelProvider.Inst.DistributeIncomingMessage(null, clove.Message.Header16); break; case GarlicCloveDelivery.DeliveryMethod.Router: var dest = ((GarlicCloveDeliveryRouter)clove.Delivery).Destination; #if LOG_ALL_TUNNEL_TRANSFER DebugUtils.LogDebug(() => string.Format( "ClientDestination: GarlicMessageReceived: Delivered Router: {0} {1}", dest.Id32Short, clove.Message)); #endif TransportProvider.Send(dest, clove.Message); break; case GarlicCloveDelivery.DeliveryMethod.Tunnel: var tone = (GarlicCloveDeliveryTunnel)clove.Delivery; #if LOG_ALL_TUNNEL_TRANSFER DebugUtils.LogDebug(() => string.Format( "ClientDestination: GarlicMessageReceived: Delivered Tunnel: {0} TunnelId: {1} {2}", tone.Destination.Id32Short, tone.Tunnel, clove.Message)); #endif TransportProvider.Send(tone.Destination, new TunnelGatewayMessage(clove.Message.Header16, tone.Tunnel)); break; case GarlicCloveDelivery.DeliveryMethod.Destination: #if LOG_ALL_TUNNEL_TRANSFER DebugUtils.LogDebug(() => string.Format( "ClientDestination: GarlicMessageReceived: Delivered Destination: {0}", clove.Message)); #endif DestinationMessageReceived(clove.Message); break; } } catch (Exception ex) { DebugUtils.Log("ClientDestination GarlicDecrypt Clove", ex); } } } catch (Exception ex) { DebugUtils.Log("ClientDestination GarlicDecrypt", ex); } }
void tunnel_GarlicMessageReceived(GarlicMessage msg) { }
public static (GarlicAESBlock, I2PSessionKey) RetrieveAESBlock( GarlicMessage garlic, I2PPrivateKey privatekey, Func <I2PSessionTag, I2PSessionKey> findsessionkey) { GarlicAESBlock result; var cipher = new CbcBlockCipher(new AesEngine()); var tag = new I2PSessionTag(new BufRefLen(garlic.EGData, 0, 32)); var sessionkey = findsessionkey?.Invoke(tag); #if LOG_ALL_LEASE_MGMT Logging.LogDebug($"Garlic: Session key found {sessionkey}"); #endif if (sessionkey != null) { var aesbuf = new BufLen(garlic.EGData, 32); var pivh = I2PHashSHA256.GetHash(tag.Value); cipher.Init(false, sessionkey.Key.ToParametersWithIV(new BufLen(pivh, 0, 16))); cipher.ProcessBytes(aesbuf); try { result = new GarlicAESBlock(new BufRefLen(aesbuf)); if (!result.VerifyPayloadHash()) { Logging.LogDebug("Garlic: DecryptMessage: AES block SHA256 check failed."); return(null, null); } return(result, sessionkey); } catch (ArgumentException ex) { Logging.Log("Garlic", ex); } catch (Exception ex) { Logging.Log("Garlic", ex); return(null, null); } } #if LOG_ALL_LEASE_MGMT Logging.LogDebug("Garlic: No session key. Using ElGamal to decrypt."); #endif try { (result, sessionkey) = Garlic.EGDecryptGarlic(garlic, privatekey); #if LOG_ALL_LEASE_MGMT Logging.LogDebug($"Garlic: EG session key {sessionkey}"); #endif } catch (Exception ex) { Logging.LogDebug("Garlic: ElGamal DecryptMessage failed"); Logging.LogDebugData($"ReceivedSessions {ex}"); return(null, null); } return(result, sessionkey); }
void GarlicMessageReceived(GarlicMessage msg) { }
public static I2NPMessage GetMessage( I2NPMessage.MessageTypes messagetype, BufRef reader, uint?msgid = null) { I2NPMessage result = null; try { switch (messagetype) { case I2NPMessage.MessageTypes.Garlic: result = new GarlicMessage(reader); break; case I2NPMessage.MessageTypes.Data: result = new DataMessage(reader); break; case I2NPMessage.MessageTypes.DatabaseSearchReply: result = new DatabaseSearchReplyMessage(reader); break; case I2NPMessage.MessageTypes.DatabaseStore: result = new DatabaseStoreMessage(reader); break; case I2NPMessage.MessageTypes.DeliveryStatus: result = new DeliveryStatusMessage(reader); break; case I2NPMessage.MessageTypes.TunnelData: result = new TunnelDataMessage(reader); break; case I2NPMessage.MessageTypes.TunnelGateway: result = new TunnelGatewayMessage(reader); break; case I2NPMessage.MessageTypes.DatabaseLookup: result = new DatabaseLookupMessage(reader); break; case I2NPMessage.MessageTypes.VariableTunnelBuild: result = new VariableTunnelBuildMessage(reader); break; case I2NPMessage.MessageTypes.TunnelBuild: result = new TunnelBuildMessage(reader); break; case I2NPMessage.MessageTypes.TunnelBuildReply: result = new TunnelBuildReplyMessage(reader); break; case I2NPMessage.MessageTypes.VariableTunnelBuildReply: result = new VariableTunnelBuildReplyMessage(reader); break; default: Logging.LogDebug($"GetMessage: '{messagetype}' is not a known message type!"); throw new NotImplementedException(); } } catch (Exception ex) { Logging.Log("GetMessage", ex); throw; } if (result != null && msgid.HasValue) { result.MessageId = msgid.Value; } return(result); }