From 87953c4b9374764d80d9843c3b5de65290bbd8b5 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Wed, 27 May 2009 16:59:38 +0000
Subject: [PATCH]     * Peer Selector: Make strict order opaque to hash value

---
 .../tunnel/pool/TunnelPeerSelector.java       | 24 +++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java
index 92e4545171..c515310051 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java
@@ -11,6 +11,7 @@ import java.util.Set;
 import java.util.StringTokenizer;
 
 import net.i2p.I2PAppContext;
+import net.i2p.crypto.SHA256Generator;
 import net.i2p.data.DataFormatException;
 import net.i2p.data.Hash;
 import net.i2p.data.RouterInfo;
@@ -477,6 +478,19 @@ public abstract class TunnelPeerSelector {
             Collections.sort(rv, new HashComparator(hash));
     }
 
+    /**
+     *  Implement a deterministic comparison that cannot be predicted by
+     *  others. A naive implementation (using the distance from a random key)
+     *  allows an attacker who runs two routers with hashes far apart
+     *  to maximize his chances of those two routers being at opposite
+     *  ends of a tunnel.
+     *
+     *  Previous:
+     *     d(l, h) - d(r, h)
+     *
+     *  Now:
+     *     d((H(l+h), h) - d(H(r+h), h)
+     */
     private class HashComparator implements Comparator {
         private Hash _hash;
 
@@ -484,8 +498,14 @@ public abstract class TunnelPeerSelector {
             _hash = h;
         }
         public int compare(Object l, Object r) {
-            BigInteger ll = PeerSelector.getDistance(_hash, (Hash) l);
-            BigInteger rr = PeerSelector.getDistance(_hash, (Hash) r);
+            byte[] data = new byte[2*Hash.HASH_LENGTH];
+            System.arraycopy(_hash.getData(), 0, data, Hash.HASH_LENGTH, Hash.HASH_LENGTH);
+            System.arraycopy(((Hash) l).getData(), 0, data, 0, Hash.HASH_LENGTH);
+            Hash lh = SHA256Generator.getInstance().calculateHash(data);
+            System.arraycopy(((Hash) r).getData(), 0, data, 0, Hash.HASH_LENGTH);
+            Hash rh = SHA256Generator.getInstance().calculateHash(data);
+            BigInteger ll = PeerSelector.getDistance(_hash, lh);
+            BigInteger rr = PeerSelector.getDistance(_hash, rh);
             return ll.compareTo(rr);
         }
     }
-- 
GitLab