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 765d9b703..4479d491d 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 @@ -3,6 +3,7 @@ package org.briarproject.bramble.plugin.tor; import android.app.Application; import org.briarproject.bramble.api.battery.BatteryManager; +import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.network.NetworkManager; @@ -60,6 +61,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory { private final File torDirectory; private int torSocksPort; private int torControlPort; + private final CryptoComponent crypto; @Inject AndroidTorPluginFactory(@IoExecutor Executor ioExecutor, @@ -77,7 +79,8 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory { Clock clock, @TorDirectory File torDirectory, @TorSocksPort int torSocksPort, - @TorControlPort int torControlPort) { + @TorControlPort int torControlPort, + CryptoComponent crypto) { this.ioExecutor = ioExecutor; this.wakefulIoExecutor = wakefulIoExecutor; this.app = app; @@ -94,6 +97,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory { this.torDirectory = torDirectory; this.torSocksPort = torSocksPort; this.torControlPort = torControlPort; + this.crypto = crypto; } @Override @@ -135,7 +139,8 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory { Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, MAX_POLLING_INTERVAL, BACKOFF_BASE); - TorRendezvousCrypto torRendezvousCrypto = new TorRendezvousCryptoImpl(); + TorRendezvousCrypto torRendezvousCrypto = + new TorRendezvousCryptoImpl(crypto); AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, wakefulIoExecutor, app, networkManager, locationUtils, torSocketFactory, clock, resourceProvider, diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java index 9c3a42514..feae36bbf 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java @@ -170,4 +170,11 @@ public interface CryptoComponent { * length. The line terminator is CRLF. */ String asciiArmour(byte[] b, int lineLength); + + /** + * Encode the onion/hidden service address given its public key. As + * specified here: https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt?id=29245fd5#n2135 + */ + String encodeOnionAddress(byte[] publicKey); + } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java index 2f3741826..39ecef7a3 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java @@ -7,6 +7,7 @@ import net.i2p.crypto.eddsa.KeyPairGenerator; import org.bouncycastle.crypto.CryptoException; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.Blake2bDigest; +import org.bouncycastle.crypto.digests.SHA3Digest; import org.briarproject.bramble.api.crypto.AgreementPrivateKey; import org.briarproject.bramble.api.crypto.AgreementPublicKey; import org.briarproject.bramble.api.crypto.CryptoComponent; @@ -21,11 +22,13 @@ import org.briarproject.bramble.api.crypto.SignaturePrivateKey; import org.briarproject.bramble.api.crypto.SignaturePublicKey; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.system.SecureRandomProvider; +import org.briarproject.bramble.util.Base32; import org.briarproject.bramble.util.ByteUtils; import org.briarproject.bramble.util.StringUtils; import org.whispersystems.curve25519.Curve25519; import org.whispersystems.curve25519.Curve25519KeyPair; +import java.nio.charset.Charset; import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; import java.security.Provider; @@ -58,6 +61,8 @@ class CryptoComponentImpl implements CryptoComponent { private static final int PBKDF_SALT_BYTES = 32; // 256 bits private static final byte PBKDF_FORMAT_SCRYPT = 0; private static final byte PBKDF_FORMAT_SCRYPT_STRENGTHENED = 1; + private static final byte ONION_HS_PROTOCOL_VERSION = 3; + private static final int ONION_CHECKSUM_BYTES = 2; private final SecureRandom secureRandom; private final PasswordBasedKdf passwordBasedKdf; @@ -442,4 +447,21 @@ class CryptoComponentImpl implements CryptoComponent { public String asciiArmour(byte[] b, int lineLength) { return AsciiArmour.wrap(b, lineLength); } + + @Override + public String encodeOnionAddress(byte[] publicKey) { + 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(ONION_HS_PROTOCOL_VERSION); + byte[] checksum = new byte[digest.getDigestSize()]; + digest.doFinal(checksum, 0); + byte[] address = new byte[publicKey.length + ONION_CHECKSUM_BYTES + 1]; + arraycopy(publicKey, 0, address, 0, publicKey.length); + arraycopy(checksum, 0, address, publicKey.length, ONION_CHECKSUM_BYTES); + address[address.length - 1] = ONION_HS_PROTOCOL_VERSION; + return Base32.encode(address).toLowerCase(); + } + } 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 76bfb5373..2b0b217ba 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 @@ -4,39 +4,26 @@ import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec; import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA3Digest; import org.bouncycastle.util.encoders.Base64; -import org.briarproject.bramble.util.Base32; +import org.briarproject.bramble.api.crypto.CryptoComponent; 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"); - private static final byte HS_PROTOCOL_VERSION = 3; - private static final int CHECKSUM_BYTES = 2; + private final CryptoComponent crypto; + + TorRendezvousCryptoImpl(CryptoComponent crypto) { + this.crypto = crypto; + } @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(HS_PROTOCOL_VERSION); - byte[] checksum = new byte[digest.getDigestSize()]; - digest.doFinal(checksum, 0); - byte[] address = new byte[publicKey.length + CHECKSUM_BYTES + 1]; - arraycopy(publicKey, 0, address, 0, publicKey.length); - arraycopy(checksum, 0, address, publicKey.length, CHECKSUM_BYTES); - address[address.length - 1] = HS_PROTOCOL_VERSION; - return Base32.encode(address).toLowerCase(); + return crypto.encodeOnionAddress(spec.getA().toByteArray()); } @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 4101fa394..8e3d05a71 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 @@ -1,6 +1,7 @@ package org.briarproject.bramble.plugin.tor; import org.briarproject.bramble.api.battery.BatteryManager; +import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.network.NetworkManager; @@ -58,6 +59,7 @@ public class UnixTorPluginFactory implements DuplexPluginFactory { private final File torDirectory; private int torSocksPort; private int torControlPort; + private final CryptoComponent crypto; @Inject UnixTorPluginFactory(@IoExecutor Executor ioExecutor, @@ -73,7 +75,8 @@ public class UnixTorPluginFactory implements DuplexPluginFactory { Clock clock, @TorDirectory File torDirectory, @TorSocksPort int torSocksPort, - @TorControlPort int torControlPort) { + @TorControlPort int torControlPort, + CryptoComponent crypto) { this.ioExecutor = ioExecutor; this.wakefulIoExecutor = wakefulIoExecutor; this.networkManager = networkManager; @@ -88,6 +91,7 @@ public class UnixTorPluginFactory implements DuplexPluginFactory { this.torDirectory = torDirectory; this.torSocksPort = torSocksPort; this.torControlPort = torControlPort; + this.crypto = crypto; } @Override @@ -128,7 +132,8 @@ public class UnixTorPluginFactory implements DuplexPluginFactory { Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, MAX_POLLING_INTERVAL, BACKOFF_BASE); - TorRendezvousCrypto torRendezvousCrypto = new TorRendezvousCryptoImpl(); + TorRendezvousCrypto torRendezvousCrypto = + new TorRendezvousCryptoImpl(crypto); UnixTorPlugin plugin = new UnixTorPlugin(ioExecutor, wakefulIoExecutor, networkManager, locationUtils, torSocketFactory, clock, resourceProvider, circumventionProvider, batteryManager, diff --git a/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/BridgeTest.java b/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/BridgeTest.java index a38ae29f8..04031f8c3 100644 --- a/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/BridgeTest.java +++ b/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/BridgeTest.java @@ -2,6 +2,7 @@ package org.briarproject.bramble.plugin.tor; import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons; import org.briarproject.bramble.api.battery.BatteryManager; +import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.network.NetworkManager; @@ -88,6 +89,8 @@ public class BridgeTest extends BrambleTestCase { BackoffFactory backoffFactory; @Inject Clock clock; + @Inject + CryptoComponent crypto; private final File torDir = getTestDirectory(); private final String bridge; @@ -142,7 +145,7 @@ public class BridgeTest extends BrambleTestCase { networkManager, locationUtils, eventBus, torSocketFactory, backoffFactory, resourceProvider, bridgeProvider, batteryManager, clock, torDir, DEFAULT_SOCKS_PORT, - DEFAULT_CONTROL_PORT); + DEFAULT_CONTROL_PORT, crypto); } @After