From 1ec3fa3adeee46d3279df37c39442632349f1df0 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 5 Jun 2019 15:46:22 +0100 Subject: [PATCH 1/4] Implement Tor rendezvous crypto. --- .../bramble/plugin/tor/AndroidTorPlugin.java | 3 +- .../plugin/tor/AndroidTorPluginFactory.java | 4 +- .../bramble/plugin/tor/TorPlugin.java | 52 ++++++++++++++++++- .../plugin/tor/TorRendezvousCrypto.java | 8 +++ .../plugin/tor/TorRendezvousCryptoImpl.java | 46 ++++++++++++++++ .../bramble/plugin/tor/JavaTorPlugin.java | 5 +- .../bramble/plugin/tor/UnixTorPlugin.java | 5 +- .../plugin/tor/UnixTorPluginFactory.java | 6 ++- 8 files changed, 119 insertions(+), 10 deletions(-) create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorRendezvousCrypto.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorRendezvousCryptoImpl.java 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 ae68db6e1..f36773615 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 560072343..405354975 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 76d8f6109..70821a1ee 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 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 000000000..a7c2fe9f0 --- /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 000000000..aea31d84d --- /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 d08300b2a..9b213cba7 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 753840a76..e57ea83f3 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 0e8425712..07cbead56 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; } From 41deff1bf3bb7812b361315eb0953fa18f378057 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 5 Jun 2019 17:41:09 +0100 Subject: [PATCH 2/4] Suppress redundant enabled/disabled events. --- .../org/briarproject/bramble/plugin/PluginManagerImpl.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java index cbaac0943..d4d69ca56 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java @@ -250,6 +250,7 @@ class PluginManagerImpl implements PluginManager, Service { private class Callback implements PluginCallback { private final TransportId id; + private final AtomicBoolean enabled = new AtomicBoolean(false); private Callback(TransportId id) { this.id = id; @@ -295,12 +296,14 @@ class PluginManagerImpl implements PluginManager, Service { @Override public void transportEnabled() { - eventBus.broadcast(new TransportEnabledEvent(id)); + if (!enabled.getAndSet(true)) + eventBus.broadcast(new TransportEnabledEvent(id)); } @Override public void transportDisabled() { - eventBus.broadcast(new TransportDisabledEvent(id)); + if (enabled.getAndSet(false)) + eventBus.broadcast(new TransportDisabledEvent(id)); } @Override From ba19716e0ff2a027c0b8799745f649e5e8fe2ad8 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 5 Jun 2019 17:43:23 +0100 Subject: [PATCH 3/4] Don't broadcast disabled event whenever we close a socket. --- .../bramble/plugin/tor/TorPlugin.java | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) 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 70821a1ee..e5c35bf95 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 @@ -32,7 +32,6 @@ import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.api.system.ResourceProvider; -import org.briarproject.bramble.util.IoUtils; import java.io.EOFException; import java.io.File; @@ -55,7 +54,6 @@ import java.util.logging.Logger; import java.util.regex.Pattern; import java.util.zip.ZipInputStream; -import javax.annotation.Nullable; import javax.net.SocketFactory; import static java.util.Arrays.asList; @@ -79,6 +77,7 @@ import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT; import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V2; import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V3; import static org.briarproject.bramble.util.IoUtils.copyAndClose; +import static org.briarproject.bramble.util.IoUtils.tryToClose; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; @@ -314,8 +313,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { if (!doneFile.createNewFile()) LOG.warning("Failed to create done file"); } catch (IOException e) { - IoUtils.tryToClose(in, LOG, WARNING); - IoUtils.tryToClose(out, LOG, WARNING); + tryToClose(in, LOG, WARNING); + tryToClose(out, LOG, WARNING); throw new PluginException(e); } } @@ -374,7 +373,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } return b; } finally { - IoUtils.tryToClose(in, LOG, WARNING); + tryToClose(in, LOG, WARNING); } } @@ -392,11 +391,11 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { ss.bind(new InetSocketAddress("127.0.0.1", port)); } catch (IOException e) { logException(LOG, WARNING, e); - tryToClose(ss); + tryToClose(ss, LOG, WARNING); return; } if (!running) { - tryToClose(ss); + tryToClose(ss, LOG, WARNING); return; } socket = ss; @@ -413,11 +412,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { }); } - private void tryToClose(@Nullable ServerSocket ss) { - IoUtils.tryToClose(ss, LOG, WARNING); - callback.transportDisabled(); - } - private void publishHiddenService(String port) { if (!running) return; LOG.info("Creating hidden service"); @@ -502,7 +496,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @Override public void stop() { running = false; - tryToClose(socket); + tryToClose(socket, LOG, WARNING); + callback.transportDisabled(); if (controlSocket != null && controlConnection != null) { try { LOG.info("Stopping Tor"); @@ -589,7 +584,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { LOG.info("Could not connect to " + scrubOnion(bestOnion) + ": " + e.toString()); } - IoUtils.tryToClose(s, LOG, WARNING); + tryToClose(s, LOG, WARNING); return null; } } @@ -657,7 +652,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @Override public void close() throws IOException { controlConnection.delOnion(localOnion); - tryToClose(ss); + tryToClose(ss, LOG, WARNING); } }; } catch (IOException e) { From 60eefbf3e0496b8b3f861c848b010cab3ce829a3 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 7 Jun 2019 11:54:44 +0100 Subject: [PATCH 4/4] Use named constants. --- .../briarproject/bramble/plugin/tor/TorPlugin.java | 11 ++++++----- .../bramble/plugin/tor/TorRendezvousCrypto.java | 2 ++ .../bramble/plugin/tor/TorRendezvousCryptoImpl.java | 11 +++++++---- 3 files changed, 15 insertions(+), 9 deletions(-) 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 e5c35bf95..e2494e830 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 @@ -76,6 +76,7 @@ import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_ONLY_WHE import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT; import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V2; import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V3; +import static org.briarproject.bramble.plugin.tor.TorRendezvousCrypto.SEED_BYTES; import static org.briarproject.bramble.util.IoUtils.copyAndClose; import static org.briarproject.bramble.util.IoUtils.tryToClose; import static org.briarproject.bramble.util.LogUtils.logException; @@ -613,15 +614,15 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @Override public RendezvousEndpoint createRendezvousEndpoint(KeyMaterialSource k, boolean alice, ConnectionHandler incoming) { - byte[] aliceSeed = k.getKeyMaterial(32); - byte[] bobSeed = k.getKeyMaterial(32); + byte[] aliceSeed = k.getKeyMaterial(SEED_BYTES); + byte[] bobSeed = k.getKeyMaterial(SEED_BYTES); 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); + TransportProperties remoteProperties = new TransportProperties(); + remoteProperties.put(PROP_ONION_V3, remoteOnion); try { ServerSocket ss = new ServerSocket(); ss.bind(new InetSocketAddress("127.0.0.1", 0)); @@ -646,7 +647,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @Override public TransportProperties getRemoteTransportProperties() { - return remote; + return remoteProperties; } @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 index a7c2fe9f0..a5b32630e 100644 --- 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 @@ -2,6 +2,8 @@ package org.briarproject.bramble.plugin.tor; interface TorRendezvousCrypto { + static final int SEED_BYTES = 32; + 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 index aea31d84d..1545bcfba 100644 --- 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 @@ -18,6 +18,9 @@ public class TorRendezvousCryptoImpl implements TorRendezvousCrypto { private static final EdDSANamedCurveSpec CURVE_SPEC = EdDSANamedCurveTable.getByName("Ed25519"); + private static final byte HS_PROTOCOL_VERSION = 3; + private static final int CHECKSUM_BYTES = 2; + @Override public String getOnionAddress(byte[] seed) { EdDSAPrivateKeySpec spec = new EdDSAPrivateKeySpec(seed, CURVE_SPEC); @@ -26,13 +29,13 @@ public class TorRendezvousCryptoImpl implements TorRendezvousCrypto { 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); + digest.update(HS_PROTOCOL_VERSION); byte[] checksum = new byte[digest.getDigestSize()]; digest.doFinal(checksum, 0); - byte[] address = new byte[publicKey.length + 3]; + byte[] address = new byte[publicKey.length + CHECKSUM_BYTES + 1]; arraycopy(publicKey, 0, address, 0, publicKey.length); - arraycopy(checksum, 0, address, publicKey.length, 2); - address[address.length - 1] = 3; + arraycopy(checksum, 0, address, publicKey.length, CHECKSUM_BYTES); + address[address.length - 1] = HS_PROTOCOL_VERSION; return Base32.encode(address).toLowerCase(); }