diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java index ae68db6e1c5e500601984a861e27f24a2c72ba5b..f367736152b0d494f1283eff97254c29857346b9 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java @@ -41,11 +41,12 @@ class AndroidTorPlugin extends TorPlugin { Clock clock, ResourceProvider resourceProvider, CircumventionProvider circumventionProvider, BatteryManager batteryManager, Backoff backoff, + TorRendezvousCrypto torRendezvousCrypto, PluginCallback callback, String architecture, int maxLatency, int maxIdleTime) { super(ioExecutor, networkManager, locationUtils, torSocketFactory, clock, resourceProvider, circumventionProvider, batteryManager, - backoff, callback, architecture, maxLatency, maxIdleTime, + backoff, torRendezvousCrypto, callback, architecture, maxLatency, maxIdleTime, appContext.getDir("tor", MODE_PRIVATE)); this.appContext = appContext; PowerManager pm = (PowerManager) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPluginFactory.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPluginFactory.java index 560072343a52cb2d4f084248ad9f3805a29cdac8..40535497588885bbb11f2515aa01079d191f21c6 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPluginFactory.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPluginFactory.java @@ -106,10 +106,12 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory { Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, MAX_POLLING_INTERVAL, BACKOFF_BASE); + TorRendezvousCrypto torRendezvousCrypto = new TorRendezvousCryptoImpl(); AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler, appContext, networkManager, locationUtils, torSocketFactory, clock, resourceProvider, circumventionProvider, batteryManager, - backoff, callback, architecture, MAX_LATENCY, MAX_IDLE_TIME); + backoff, torRendezvousCrypto, callback, architecture, + MAX_LATENCY, MAX_IDLE_TIME); eventBus.addListener(plugin); return plugin; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index 76d8f6109a99bf7913cbde2809ef8cafad325862..70821a1eed5ff95592c20bc13d79c70193f98a49 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -105,6 +105,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { private final Clock clock; private final BatteryManager batteryManager; private final Backoff backoff; + private final TorRendezvousCrypto torRendezvousCrypto; private final PluginCallback callback; private final String architecture; private final CircumventionProvider circumventionProvider; @@ -131,6 +132,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { Clock clock, ResourceProvider resourceProvider, CircumventionProvider circumventionProvider, BatteryManager batteryManager, Backoff backoff, + TorRendezvousCrypto torRendezvousCrypto, PluginCallback callback, String architecture, int maxLatency, int maxIdleTime, File torDirectory) { this.ioExecutor = ioExecutor; @@ -142,6 +144,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { this.circumventionProvider = circumventionProvider; this.batteryManager = batteryManager; this.backoff = backoff; + this.torRendezvousCrypto = torRendezvousCrypto; this.callback = callback; this.architecture = architecture; this.maxLatency = maxLatency; @@ -609,13 +612,58 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @Override public boolean supportsRendezvous() { - return false; + return true; } @Override public RendezvousEndpoint createRendezvousEndpoint(KeyMaterialSource k, boolean alice, ConnectionHandler incoming) { - throw new UnsupportedOperationException(); + byte[] aliceSeed = k.getKeyMaterial(32); + byte[] bobSeed = k.getKeyMaterial(32); + byte[] localSeed = alice ? aliceSeed : bobSeed; + byte[] remoteSeed = alice ? bobSeed : aliceSeed; + String blob = torRendezvousCrypto.getPrivateKeyBlob(localSeed); + String localOnion = torRendezvousCrypto.getOnionAddress(localSeed); + String remoteOnion = torRendezvousCrypto.getOnionAddress(remoteSeed); + TransportProperties remote = new TransportProperties(); + remote.put(PROP_ONION_V3, remoteOnion); + try { + ServerSocket ss = new ServerSocket(); + ss.bind(new InetSocketAddress("127.0.0.1", 0)); + int port = ss.getLocalPort(); + ioExecutor.execute(() -> { + try { + //noinspection InfiniteLoopStatement + while (true) { + Socket s = ss.accept(); + incoming.handleConnection( + new TorTransportConnection(this, s)); + } + } catch (IOException e) { + // This is expected when the socket is closed + if (LOG.isLoggable(INFO)) LOG.info(e.toString()); + } + }); + Map<Integer, String> portLines = + singletonMap(80, "127.0.0.1:" + port); + controlConnection.addOnion(blob, portLines); + return new RendezvousEndpoint() { + + @Override + public TransportProperties getRemoteTransportProperties() { + return remote; + } + + @Override + public void close() throws IOException { + controlConnection.delOnion(localOnion); + tryToClose(ss); + } + }; + } catch (IOException e) { + logException(LOG, WARNING, e); + return null; + } } @Override diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorRendezvousCrypto.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorRendezvousCrypto.java new file mode 100644 index 0000000000000000000000000000000000000000..a7c2fe9f01e3a8fa62ebbeeb7d18d95e9cf723a0 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorRendezvousCrypto.java @@ -0,0 +1,8 @@ +package org.briarproject.bramble.plugin.tor; + +interface TorRendezvousCrypto { + + String getOnionAddress(byte[] seed); + + String getPrivateKeyBlob(byte[] seed); +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorRendezvousCryptoImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorRendezvousCryptoImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..aea31d84dc1b9f391424119c906ba0fd1a4c40fb --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorRendezvousCryptoImpl.java @@ -0,0 +1,46 @@ +package org.briarproject.bramble.plugin.tor; + +import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec; +import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; +import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec; + +import org.briarproject.bramble.util.Base32; +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.SHA3Digest; +import org.spongycastle.util.encoders.Base64; + +import java.nio.charset.Charset; + +import static java.lang.System.arraycopy; + +public class TorRendezvousCryptoImpl implements TorRendezvousCrypto { + + private static final EdDSANamedCurveSpec CURVE_SPEC = + EdDSANamedCurveTable.getByName("Ed25519"); + + @Override + public String getOnionAddress(byte[] seed) { + EdDSAPrivateKeySpec spec = new EdDSAPrivateKeySpec(seed, CURVE_SPEC); + byte[] publicKey = spec.getA().toByteArray(); + Digest digest = new SHA3Digest(256); + byte[] label = ".onion checksum".getBytes(Charset.forName("US-ASCII")); + digest.update(label, 0, label.length); + digest.update(publicKey, 0, publicKey.length); + digest.update((byte) 3); + byte[] checksum = new byte[digest.getDigestSize()]; + digest.doFinal(checksum, 0); + byte[] address = new byte[publicKey.length + 3]; + arraycopy(publicKey, 0, address, 0, publicKey.length); + arraycopy(checksum, 0, address, publicKey.length, 2); + address[address.length - 1] = 3; + return Base32.encode(address).toLowerCase(); + } + + @Override + public String getPrivateKeyBlob(byte[] seed) { + EdDSAPrivateKeySpec spec = new EdDSAPrivateKeySpec(seed, CURVE_SPEC); + byte[] hash = spec.getH(); + byte[] base64 = Base64.encode(hash); + return "ED25519-V3:" + new String(base64, Charset.forName("US-ASCII")); + } +} diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/JavaTorPlugin.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/JavaTorPlugin.java index d08300b2af61e796ad668f21482b299512bb4c1d..9b213cba7e332eff85d3a0ed887bf3a7bb386dbc 100644 --- a/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/JavaTorPlugin.java +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/JavaTorPlugin.java @@ -25,12 +25,13 @@ abstract class JavaTorPlugin extends TorPlugin { Clock clock, ResourceProvider resourceProvider, CircumventionProvider circumventionProvider, BatteryManager batteryManager, Backoff backoff, + TorRendezvousCrypto torRendezvousCrypto, PluginCallback callback, String architecture, int maxLatency, int maxIdleTime, File torDirectory) { super(ioExecutor, networkManager, locationUtils, torSocketFactory, clock, resourceProvider, circumventionProvider, batteryManager, - backoff, callback, architecture, maxLatency, maxIdleTime, - torDirectory); + backoff, torRendezvousCrypto, callback, architecture, + maxLatency, maxIdleTime, torDirectory); } @Override diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/UnixTorPlugin.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/UnixTorPlugin.java index 753840a76b53acc27ae83da5c20e967b10473bbf..e57ea83f3e806cbb80acf77c87730628d6db13ed 100644 --- a/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/UnixTorPlugin.java +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/UnixTorPlugin.java @@ -25,12 +25,13 @@ class UnixTorPlugin extends JavaTorPlugin { Clock clock, ResourceProvider resourceProvider, CircumventionProvider circumventionProvider, BatteryManager batteryManager, Backoff backoff, + TorRendezvousCrypto torRendezvousCrypto, PluginCallback callback, String architecture, int maxLatency, int maxIdleTime, File torDirectory) { super(ioExecutor, networkManager, locationUtils, torSocketFactory, clock, resourceProvider, circumventionProvider, batteryManager, - backoff, callback, architecture, maxLatency, maxIdleTime, - torDirectory); + backoff, torRendezvousCrypto, callback, architecture, + maxLatency, maxIdleTime, torDirectory); } @Override diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/UnixTorPluginFactory.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/UnixTorPluginFactory.java index 0e84257129a805cc4a87bf7e2f306102c9b28240..07cbead567577ad9da962c9584f08e101ee0dab8 100644 --- a/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/UnixTorPluginFactory.java +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/UnixTorPluginFactory.java @@ -96,10 +96,12 @@ public class UnixTorPluginFactory implements DuplexPluginFactory { Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, MAX_POLLING_INTERVAL, BACKOFF_BASE); + TorRendezvousCrypto torRendezvousCrypto = new TorRendezvousCryptoImpl(); UnixTorPlugin plugin = new UnixTorPlugin(ioExecutor, networkManager, locationUtils, torSocketFactory, clock, resourceProvider, - circumventionProvider, batteryManager, backoff, callback, - architecture, MAX_LATENCY, MAX_IDLE_TIME, torDirectory); + circumventionProvider, batteryManager, backoff, + torRendezvousCrypto, callback, architecture, MAX_LATENCY, + MAX_IDLE_TIME, torDirectory); eventBus.addListener(plugin); return plugin; }