Anonymous allegation of I2P de-anonymization bug.
A user in IRC has been cross-posting a specific allegation from an anonymous TOR discussion board that I2P has an de-anonymization bug.
I felt it best to bring the issue up here, and we can either refute or address this claim.
The onion link for the this accusation comes from lambdaplusjs:
http://lambdaplusjs35padjaiz4jw2fugdoeutse262phqr72uf634s2wdbqd.onion/tech/34039#P37970
Here's their allegation:
P37855
>Do you have more info about this?
Yes. Look at InboundMessageDistributor on line 179.
https://github.com/i2p/i2p.i2p/blob/master/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java
>if ( (target == null) || ( (tunnel == null) && (_context.routerHash().equals(target) ) ) ) {
> // targetting us either implicitly (no target) or explicitly (no tunnel)
> // make sure we don't honor any remote requests directly (garlic instructions, etc)
This is a bug because in the case of a destination the true target should be the destination hash,
not the router hash. So when a destination's incoming I2NP message targets the router's
(and only the router's) hash then the destination processes the packet as if it was normal.
This provides a simple yes/no oracle that we can use to tie a destination to a router.
P37863
>Has this deanonymization bug been a part of I2P for ages?
Since Febuary 16, 2005. It's old jrandom code. I have no idea why he put spacing inside if statement parenthesis.
Another anonymous user adds this analysis:
P39096
The 'tunnel' variable is a TunnelId (line 52), which is the tunnel id from the delivery instructions. Same with 'target'.
https://geti2p.net/spec/tunnel-message#struct-tunnelmessagedeliveryinstructions
You can see this if you look down on line 376.
>distribute(data, instructions.getRouter(), instructions.getTunnelId());
so the code
>if ( (target == null) || ( (tunnel == null) && (_context.routerHash().equals(target) ) ) )
when handling the rogue packet with router delivery instructions (no tunnel, target hash present) is
>if ( false || ( true && (_context.routerHash().equals(target) ) ) )
which simplifies to
>if ( _context.routerHash().equals(target) )
P39114
You should be looking at the local delivery type case.
>case eDeliveryTypeLocal:
> i2p::HandleI2NPMessage (msg.data);
which hands off to https://github.com/PurpleI2P/i2pd/blob/openssl/libi2pd/I2NPProtocol.cpp#L779
>case eI2NPShortTunnelBuild:
>case eI2NPShortTunnelBuildReply:
> // forward to tunnel thread
> i2p::tunnel::tunnels.PostTunnelData (msg);
and in the tunnel thread
https://github.com/PurpleI2P/i2pd/blob/openssl/libi2pd/Tunnel.cpp#519
>case eI2NPShortTunnelBuild:
>case eI2NPShortTunnelBuildReply:
>case eI2NPTunnelBuild:
>case eI2NPTunnelBuildReply:
> HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
and in https://github.com/PurpleI2P/i2pd/blob/openssl/libi2pd/I2NPProtocol.cpp#736
>case eI2NPShortTunnelBuild:
> HandleShortTunnelBuildMsg (msgID, buf, size);
which sends the packet directly on
>transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
> CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len,
> bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
For my part, I think the original assertion is confusing an anonymous "destination", as represented by a lease set, and a router "destination". Of course the netdb already contains the information that there is an I2P router at internet address a.b.c.d. So there's no de-anonymization there. And I don't see how this method can be used to tie a lease set destination with a specific router. That's not what the 'target' is in the code (unless I'm mistaken).
But I didn't want to leave the allegation floating around out there without us addressing it.