mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 11:49:04 +01:00
Merge branch 'remove-old-bluetooth-code' into 'master'
Remove old Bluetooth code and location permission See merge request !584
This commit is contained in:
@@ -8,7 +8,6 @@ import org.briarproject.bramble.db.DatabaseExecutorModule;
|
||||
import org.briarproject.bramble.db.DatabaseModule;
|
||||
import org.briarproject.bramble.event.EventModule;
|
||||
import org.briarproject.bramble.identity.IdentityModule;
|
||||
import org.briarproject.bramble.invitation.InvitationModule;
|
||||
import org.briarproject.bramble.keyagreement.KeyAgreementModule;
|
||||
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
||||
import org.briarproject.bramble.plugin.PluginModule;
|
||||
@@ -32,7 +31,6 @@ import dagger.Module;
|
||||
DatabaseExecutorModule.class,
|
||||
EventModule.class,
|
||||
IdentityModule.class,
|
||||
InvitationModule.class,
|
||||
KeyAgreementModule.class,
|
||||
LifecycleModule.class,
|
||||
PluginModule.class,
|
||||
|
||||
@@ -80,7 +80,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
private volatile boolean alice;
|
||||
|
||||
@Inject
|
||||
public ContactExchangeTaskImpl(DatabaseComponent db,
|
||||
ContactExchangeTaskImpl(DatabaseComponent db,
|
||||
AuthorFactory authorFactory, BdfReaderFactory bdfReaderFactory,
|
||||
BdfWriterFactory bdfWriterFactory, Clock clock,
|
||||
ConnectionManager connectionManager, ContactManager contactManager,
|
||||
@@ -146,12 +146,12 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
|
||||
// Create the readers
|
||||
InputStream streamReader =
|
||||
streamReaderFactory.createInvitationStreamReader(in,
|
||||
streamReaderFactory.createContactExchangeStreamReader(in,
|
||||
alice ? bobHeaderKey : aliceHeaderKey);
|
||||
BdfReader r = bdfReaderFactory.createReader(streamReader);
|
||||
// Create the writers
|
||||
OutputStream streamWriter =
|
||||
streamWriterFactory.createInvitationStreamWriter(out,
|
||||
streamWriterFactory.createContactExchangeStreamWriter(out,
|
||||
alice ? aliceHeaderKey : bobHeaderKey);
|
||||
BdfWriter w = bdfWriterFactory.createWriter(streamWriter);
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||
import org.briarproject.bramble.api.crypto.KeyParser;
|
||||
import org.briarproject.bramble.api.crypto.PrivateKey;
|
||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
@@ -41,7 +40,6 @@ import java.util.logging.Logger;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static org.briarproject.bramble.api.invitation.InvitationConstants.CODE_BITS;
|
||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||
import static org.briarproject.bramble.crypto.EllipticCurveConstants.PARAMETERS;
|
||||
@@ -68,9 +66,6 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
return s.getBytes(Charset.forName("US-ASCII"));
|
||||
}
|
||||
|
||||
// KDF labels for bluetooth confirmation code derivation
|
||||
private static final byte[] BT_A_CONFIRM = ascii("ALICE_CONFIRMATION_CODE");
|
||||
private static final byte[] BT_B_CONFIRM = ascii("BOB_CONFIRMATION_CODE");
|
||||
// KDF labels for contact exchange stream header key derivation
|
||||
private static final byte[] A_INVITE = ascii("ALICE_INVITATION_KEY");
|
||||
private static final byte[] B_INVITE = ascii("BOB_INVITATION_KEY");
|
||||
@@ -171,14 +166,6 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
return new SecretKey(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PseudoRandom getPseudoRandom(int seed1, int seed2) {
|
||||
byte[] seed = new byte[INT_32_BYTES * 2];
|
||||
ByteUtils.writeUint32(seed1, seed, 0);
|
||||
ByteUtils.writeUint32(seed2, seed, INT_32_BYTES);
|
||||
return new PseudoRandomImpl(seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecureRandom getSecureRandom() {
|
||||
return secureRandom;
|
||||
@@ -250,20 +237,6 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
return messageEncrypter.getKeyParser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int generateBTInvitationCode() {
|
||||
int codeBytes = (CODE_BITS + 7) / 8;
|
||||
byte[] random = new byte[codeBytes];
|
||||
secureRandom.nextBytes(random);
|
||||
return ByteUtils.readUint(random, CODE_BITS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deriveBTConfirmationCode(SecretKey master, boolean alice) {
|
||||
byte[] b = macKdf(master, alice ? BT_A_CONFIRM : BT_B_CONFIRM);
|
||||
return ByteUtils.readUint(b, CODE_BITS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretKey deriveHeaderKey(SecretKey master,
|
||||
boolean alice) {
|
||||
|
||||
@@ -32,7 +32,7 @@ class StreamDecrypterFactoryImpl implements StreamDecrypterFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamDecrypter createInvitationStreamDecrypter(InputStream in,
|
||||
public StreamDecrypter createContactExchangeStreamDecrypter(InputStream in,
|
||||
SecretKey headerKey) {
|
||||
return new StreamDecrypterImpl(in, cipherProvider.get(), 0, headerKey);
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@ class StreamEncrypterFactoryImpl implements StreamEncrypterFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamEncrypter createInvitationStreamEncrypter(OutputStream out,
|
||||
SecretKey headerKey) {
|
||||
public StreamEncrypter createContactExchangeStreamDecrypter(
|
||||
OutputStream out, SecretKey headerKey) {
|
||||
AuthenticatedCipher cipher = cipherProvider.get();
|
||||
byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH];
|
||||
crypto.getSecureRandom().nextBytes(streamHeaderNonce);
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
package org.briarproject.bramble.invitation;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.data.BdfReader;
|
||||
import org.briarproject.bramble.api.data.BdfReaderFactory;
|
||||
import org.briarproject.bramble.api.data.BdfWriter;
|
||||
import org.briarproject.bramble.api.data.BdfWriterFactory;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
/**
|
||||
* A connection thread for the peer being Alice in the invitation protocol.
|
||||
*/
|
||||
@NotNullByDefault
|
||||
class AliceConnector extends Connector {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(AliceConnector.class.getName());
|
||||
|
||||
AliceConnector(CryptoComponent crypto, BdfReaderFactory bdfReaderFactory,
|
||||
BdfWriterFactory bdfWriterFactory,
|
||||
ContactExchangeTask contactExchangeTask, ConnectorGroup group,
|
||||
DuplexPlugin plugin, LocalAuthor localAuthor, PseudoRandom random) {
|
||||
super(crypto, bdfReaderFactory, bdfWriterFactory, contactExchangeTask,
|
||||
group, plugin, localAuthor, random);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// Create an incoming or outgoing connection
|
||||
DuplexTransportConnection conn = createInvitationConnection(true);
|
||||
if (conn == null) return;
|
||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " connected");
|
||||
// Don't proceed with more than one connection
|
||||
if (group.getAndSetConnected()) {
|
||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " redundant");
|
||||
tryToClose(conn, false);
|
||||
return;
|
||||
}
|
||||
// Carry out the key agreement protocol
|
||||
InputStream in;
|
||||
OutputStream out;
|
||||
BdfReader r;
|
||||
BdfWriter w;
|
||||
SecretKey master;
|
||||
try {
|
||||
in = conn.getReader().getInputStream();
|
||||
out = conn.getWriter().getOutputStream();
|
||||
r = bdfReaderFactory.createReader(in);
|
||||
w = bdfWriterFactory.createWriter(out);
|
||||
// Alice goes first
|
||||
sendPublicKeyHash(w);
|
||||
byte[] hash = receivePublicKeyHash(r);
|
||||
sendPublicKey(w);
|
||||
byte[] key = receivePublicKey(r);
|
||||
master = deriveMasterSecret(hash, key, true);
|
||||
} catch (IOException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
group.keyAgreementFailed();
|
||||
tryToClose(conn, true);
|
||||
return;
|
||||
} catch (GeneralSecurityException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
group.keyAgreementFailed();
|
||||
tryToClose(conn, true);
|
||||
return;
|
||||
}
|
||||
// The key agreement succeeded - derive the confirmation codes
|
||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " agreement succeeded");
|
||||
int aliceCode = crypto.deriveBTConfirmationCode(master, true);
|
||||
int bobCode = crypto.deriveBTConfirmationCode(master, false);
|
||||
group.keyAgreementSucceeded(aliceCode, bobCode);
|
||||
// Exchange confirmation results
|
||||
boolean localMatched, remoteMatched;
|
||||
try {
|
||||
localMatched = group.waitForLocalConfirmationResult();
|
||||
sendConfirmation(w, localMatched);
|
||||
remoteMatched = receiveConfirmation(r);
|
||||
} catch (IOException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
group.remoteConfirmationFailed();
|
||||
tryToClose(conn, true);
|
||||
return;
|
||||
} catch (InterruptedException e) {
|
||||
LOG.warning("Interrupted while waiting for confirmation");
|
||||
group.remoteConfirmationFailed();
|
||||
tryToClose(conn, true);
|
||||
Thread.currentThread().interrupt();
|
||||
return;
|
||||
}
|
||||
if (remoteMatched) group.remoteConfirmationSucceeded();
|
||||
else group.remoteConfirmationFailed();
|
||||
if (!(localMatched && remoteMatched)) {
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " confirmation failed");
|
||||
tryToClose(conn, false);
|
||||
return;
|
||||
}
|
||||
// Confirmation succeeded - upgrade to a secure connection
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " confirmation succeeded");
|
||||
contactExchangeTask.startExchange(group, localAuthor, master, conn,
|
||||
plugin.getId(), true);
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
package org.briarproject.bramble.invitation;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.data.BdfReader;
|
||||
import org.briarproject.bramble.api.data.BdfReaderFactory;
|
||||
import org.briarproject.bramble.api.data.BdfWriter;
|
||||
import org.briarproject.bramble.api.data.BdfWriterFactory;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
/**
|
||||
* A connection thread for the peer being Bob in the invitation protocol.
|
||||
*/
|
||||
@NotNullByDefault
|
||||
class BobConnector extends Connector {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(BobConnector.class.getName());
|
||||
|
||||
BobConnector(CryptoComponent crypto, BdfReaderFactory bdfReaderFactory,
|
||||
BdfWriterFactory bdfWriterFactory,
|
||||
ContactExchangeTask contactExchangeTask, ConnectorGroup group,
|
||||
DuplexPlugin plugin, LocalAuthor localAuthor, PseudoRandom random) {
|
||||
super(crypto, bdfReaderFactory, bdfWriterFactory, contactExchangeTask,
|
||||
group, plugin, localAuthor, random);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// Create an incoming or outgoing connection
|
||||
DuplexTransportConnection conn = createInvitationConnection(false);
|
||||
if (conn == null) return;
|
||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " connected");
|
||||
// Carry out the key agreement protocol
|
||||
InputStream in;
|
||||
OutputStream out;
|
||||
BdfReader r;
|
||||
BdfWriter w;
|
||||
SecretKey master;
|
||||
try {
|
||||
in = conn.getReader().getInputStream();
|
||||
out = conn.getWriter().getOutputStream();
|
||||
r = bdfReaderFactory.createReader(in);
|
||||
w = bdfWriterFactory.createWriter(out);
|
||||
// Alice goes first
|
||||
byte[] hash = receivePublicKeyHash(r);
|
||||
// Don't proceed with more than one connection
|
||||
if (group.getAndSetConnected()) {
|
||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " redundant");
|
||||
tryToClose(conn, false);
|
||||
return;
|
||||
}
|
||||
sendPublicKeyHash(w);
|
||||
byte[] key = receivePublicKey(r);
|
||||
sendPublicKey(w);
|
||||
master = deriveMasterSecret(hash, key, false);
|
||||
} catch (IOException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
group.keyAgreementFailed();
|
||||
tryToClose(conn, true);
|
||||
return;
|
||||
} catch (GeneralSecurityException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
group.keyAgreementFailed();
|
||||
tryToClose(conn, true);
|
||||
return;
|
||||
}
|
||||
// The key agreement succeeded - derive the confirmation codes
|
||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " agreement succeeded");
|
||||
int aliceCode = crypto.deriveBTConfirmationCode(master, true);
|
||||
int bobCode = crypto.deriveBTConfirmationCode(master, false);
|
||||
group.keyAgreementSucceeded(bobCode, aliceCode);
|
||||
// Exchange confirmation results
|
||||
boolean localMatched, remoteMatched;
|
||||
try {
|
||||
remoteMatched = receiveConfirmation(r);
|
||||
localMatched = group.waitForLocalConfirmationResult();
|
||||
sendConfirmation(w, localMatched);
|
||||
} catch (IOException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
group.remoteConfirmationFailed();
|
||||
tryToClose(conn, true);
|
||||
return;
|
||||
} catch (InterruptedException e) {
|
||||
LOG.warning("Interrupted while waiting for confirmation");
|
||||
group.remoteConfirmationFailed();
|
||||
tryToClose(conn, true);
|
||||
Thread.currentThread().interrupt();
|
||||
return;
|
||||
}
|
||||
if (remoteMatched) group.remoteConfirmationSucceeded();
|
||||
else group.remoteConfirmationFailed();
|
||||
if (!(localMatched && remoteMatched)) {
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " confirmation failed");
|
||||
tryToClose(conn, false);
|
||||
return;
|
||||
}
|
||||
// Confirmation succeeded - upgrade to a secure connection
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " confirmation succeeded");
|
||||
contactExchangeTask.startExchange(group, localAuthor, master, conn,
|
||||
plugin.getId(), false);
|
||||
}
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
package org.briarproject.bramble.invitation;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||
import org.briarproject.bramble.api.crypto.KeyParser;
|
||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.data.BdfReader;
|
||||
import org.briarproject.bramble.api.data.BdfReaderFactory;
|
||||
import org.briarproject.bramble.api.data.BdfWriter;
|
||||
import org.briarproject.bramble.api.data.BdfWriterFactory;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||
import static org.briarproject.bramble.api.invitation.InvitationConstants.CONNECTION_TIMEOUT;
|
||||
|
||||
// FIXME: This class has way too many dependencies
|
||||
@NotNullByDefault
|
||||
abstract class Connector extends Thread {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(Connector.class.getName());
|
||||
private static final String LABEL_PUBLIC_KEY =
|
||||
"org.briarproject.bramble.invitation.PUBLIC_KEY";
|
||||
|
||||
protected final CryptoComponent crypto;
|
||||
protected final BdfReaderFactory bdfReaderFactory;
|
||||
protected final BdfWriterFactory bdfWriterFactory;
|
||||
protected final ContactExchangeTask contactExchangeTask;
|
||||
protected final ConnectorGroup group;
|
||||
protected final DuplexPlugin plugin;
|
||||
protected final LocalAuthor localAuthor;
|
||||
protected final PseudoRandom random;
|
||||
protected final String pluginName;
|
||||
|
||||
private final KeyPair keyPair;
|
||||
private final KeyParser keyParser;
|
||||
|
||||
Connector(CryptoComponent crypto, BdfReaderFactory bdfReaderFactory,
|
||||
BdfWriterFactory bdfWriterFactory,
|
||||
ContactExchangeTask contactExchangeTask, ConnectorGroup group,
|
||||
DuplexPlugin plugin, LocalAuthor localAuthor, PseudoRandom random) {
|
||||
super("Connector");
|
||||
this.crypto = crypto;
|
||||
this.bdfReaderFactory = bdfReaderFactory;
|
||||
this.bdfWriterFactory = bdfWriterFactory;
|
||||
this.contactExchangeTask = contactExchangeTask;
|
||||
this.group = group;
|
||||
this.plugin = plugin;
|
||||
this.localAuthor = localAuthor;
|
||||
this.random = random;
|
||||
pluginName = plugin.getClass().getName();
|
||||
keyPair = crypto.generateAgreementKeyPair();
|
||||
keyParser = crypto.getAgreementKeyParser();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
DuplexTransportConnection createInvitationConnection(boolean alice) {
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " creating invitation connection");
|
||||
return plugin.createInvitationConnection(random, CONNECTION_TIMEOUT,
|
||||
alice);
|
||||
}
|
||||
|
||||
void sendPublicKeyHash(BdfWriter w) throws IOException {
|
||||
byte[] hash =
|
||||
crypto.hash(LABEL_PUBLIC_KEY, keyPair.getPublic().getEncoded());
|
||||
w.writeRaw(hash);
|
||||
w.flush();
|
||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " sent hash");
|
||||
}
|
||||
|
||||
byte[] receivePublicKeyHash(BdfReader r) throws IOException {
|
||||
int hashLength = crypto.getHashLength();
|
||||
byte[] b = r.readRaw(hashLength);
|
||||
if (b.length < hashLength) throw new FormatException();
|
||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " received hash");
|
||||
return b;
|
||||
}
|
||||
|
||||
void sendPublicKey(BdfWriter w) throws IOException {
|
||||
byte[] key = keyPair.getPublic().getEncoded();
|
||||
w.writeRaw(key);
|
||||
w.flush();
|
||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " sent key");
|
||||
}
|
||||
|
||||
byte[] receivePublicKey(BdfReader r)
|
||||
throws GeneralSecurityException, IOException {
|
||||
byte[] b = r.readRaw(MAX_PUBLIC_KEY_LENGTH);
|
||||
keyParser.parsePublicKey(b);
|
||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " received key");
|
||||
return b;
|
||||
}
|
||||
|
||||
SecretKey deriveMasterSecret(byte[] hash, byte[] key, boolean alice)
|
||||
throws GeneralSecurityException {
|
||||
// Check that the hash matches the key
|
||||
byte[] keyHash =
|
||||
crypto.hash(LABEL_PUBLIC_KEY, keyPair.getPublic().getEncoded());
|
||||
if (!Arrays.equals(hash, keyHash)) {
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " hash does not match key");
|
||||
throw new GeneralSecurityException();
|
||||
}
|
||||
// Derive the master secret
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " deriving master secret");
|
||||
return crypto.deriveMasterSecret(key, keyPair, alice);
|
||||
}
|
||||
|
||||
void sendConfirmation(BdfWriter w, boolean confirmed) throws IOException {
|
||||
w.writeBoolean(confirmed);
|
||||
w.flush();
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " sent confirmation: " + confirmed);
|
||||
}
|
||||
|
||||
boolean receiveConfirmation(BdfReader r) throws IOException {
|
||||
boolean confirmed = r.readBoolean();
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " received confirmation: " + confirmed);
|
||||
return confirmed;
|
||||
}
|
||||
|
||||
protected void tryToClose(DuplexTransportConnection conn,
|
||||
boolean exception) {
|
||||
try {
|
||||
LOG.info("Closing connection");
|
||||
conn.getReader().dispose(exception, true);
|
||||
conn.getWriter().dispose(exception);
|
||||
} catch (IOException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
package org.briarproject.bramble.invitation;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactExchangeListener;
|
||||
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
||||
import org.briarproject.bramble.api.data.BdfReaderFactory;
|
||||
import org.briarproject.bramble.api.data.BdfWriterFactory;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.invitation.InvitationListener;
|
||||
import org.briarproject.bramble.api.invitation.InvitationState;
|
||||
import org.briarproject.bramble.api.invitation.InvitationTask;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.PluginManager;
|
||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.api.invitation.InvitationConstants.CONFIRMATION_TIMEOUT;
|
||||
|
||||
/**
|
||||
* A task consisting of one or more parallel connection attempts.
|
||||
*/
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
class ConnectorGroup extends Thread implements InvitationTask,
|
||||
ContactExchangeListener {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ConnectorGroup.class.getName());
|
||||
|
||||
private final CryptoComponent crypto;
|
||||
private final BdfReaderFactory bdfReaderFactory;
|
||||
private final BdfWriterFactory bdfWriterFactory;
|
||||
private final ContactExchangeTask contactExchangeTask;
|
||||
private final IdentityManager identityManager;
|
||||
private final PluginManager pluginManager;
|
||||
private final int localInvitationCode, remoteInvitationCode;
|
||||
private final Collection<InvitationListener> listeners;
|
||||
private final AtomicBoolean connected;
|
||||
private final CountDownLatch localConfirmationLatch;
|
||||
private final Lock lock = new ReentrantLock();
|
||||
|
||||
// The following are locking: lock
|
||||
private int localConfirmationCode = -1, remoteConfirmationCode = -1;
|
||||
private boolean connectionFailed = false;
|
||||
private boolean localCompared = false, remoteCompared = false;
|
||||
private boolean localMatched = false, remoteMatched = false;
|
||||
private String remoteName = null;
|
||||
|
||||
ConnectorGroup(CryptoComponent crypto, BdfReaderFactory bdfReaderFactory,
|
||||
BdfWriterFactory bdfWriterFactory,
|
||||
ContactExchangeTask contactExchangeTask,
|
||||
IdentityManager identityManager, PluginManager pluginManager,
|
||||
int localInvitationCode, int remoteInvitationCode) {
|
||||
super("ConnectorGroup");
|
||||
this.crypto = crypto;
|
||||
this.bdfReaderFactory = bdfReaderFactory;
|
||||
this.bdfWriterFactory = bdfWriterFactory;
|
||||
this.contactExchangeTask = contactExchangeTask;
|
||||
this.identityManager = identityManager;
|
||||
this.pluginManager = pluginManager;
|
||||
this.localInvitationCode = localInvitationCode;
|
||||
this.remoteInvitationCode = remoteInvitationCode;
|
||||
listeners = new CopyOnWriteArrayList<InvitationListener>();
|
||||
connected = new AtomicBoolean(false);
|
||||
localConfirmationLatch = new CountDownLatch(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InvitationState addListener(InvitationListener l) {
|
||||
lock.lock();
|
||||
try {
|
||||
listeners.add(l);
|
||||
return new InvitationState(localInvitationCode,
|
||||
remoteInvitationCode, localConfirmationCode,
|
||||
remoteConfirmationCode, connected.get(), connectionFailed,
|
||||
localCompared, remoteCompared, localMatched, remoteMatched,
|
||||
remoteName);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(InvitationListener l) {
|
||||
listeners.remove(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() {
|
||||
start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
LocalAuthor localAuthor;
|
||||
// Load the local pseudonym
|
||||
try {
|
||||
localAuthor = identityManager.getLocalAuthor();
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
lock.lock();
|
||||
try {
|
||||
connectionFailed = true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
for (InvitationListener l : listeners) l.connectionFailed();
|
||||
return;
|
||||
}
|
||||
// Start the connection threads
|
||||
Collection<Connector> connectors = new ArrayList<Connector>();
|
||||
// Alice is the party with the smaller invitation code
|
||||
if (localInvitationCode < remoteInvitationCode) {
|
||||
for (DuplexPlugin plugin : pluginManager.getInvitationPlugins()) {
|
||||
Connector c = createAliceConnector(plugin, localAuthor);
|
||||
connectors.add(c);
|
||||
c.start();
|
||||
}
|
||||
} else {
|
||||
for (DuplexPlugin plugin : pluginManager.getInvitationPlugins()) {
|
||||
Connector c = createBobConnector(plugin, localAuthor);
|
||||
connectors.add(c);
|
||||
c.start();
|
||||
}
|
||||
}
|
||||
// Wait for the connection threads to finish
|
||||
try {
|
||||
for (Connector c : connectors) c.join();
|
||||
} catch (InterruptedException e) {
|
||||
LOG.warning("Interrupted while waiting for connectors");
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
// If none of the threads connected, inform the listeners
|
||||
if (!connected.get()) {
|
||||
lock.lock();
|
||||
try {
|
||||
connectionFailed = true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
for (InvitationListener l : listeners) l.connectionFailed();
|
||||
}
|
||||
}
|
||||
|
||||
private Connector createAliceConnector(DuplexPlugin plugin,
|
||||
LocalAuthor localAuthor) {
|
||||
PseudoRandom random = crypto.getPseudoRandom(localInvitationCode,
|
||||
remoteInvitationCode);
|
||||
return new AliceConnector(crypto, bdfReaderFactory, bdfWriterFactory,
|
||||
contactExchangeTask, this, plugin, localAuthor, random);
|
||||
}
|
||||
|
||||
private Connector createBobConnector(DuplexPlugin plugin,
|
||||
LocalAuthor localAuthor) {
|
||||
PseudoRandom random = crypto.getPseudoRandom(remoteInvitationCode,
|
||||
localInvitationCode);
|
||||
return new BobConnector(crypto, bdfReaderFactory, bdfWriterFactory,
|
||||
contactExchangeTask, this, plugin, localAuthor, random);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void localConfirmationSucceeded() {
|
||||
lock.lock();
|
||||
try {
|
||||
localCompared = true;
|
||||
localMatched = true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
localConfirmationLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void localConfirmationFailed() {
|
||||
lock.lock();
|
||||
try {
|
||||
localCompared = true;
|
||||
localMatched = false;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
localConfirmationLatch.countDown();
|
||||
}
|
||||
|
||||
boolean getAndSetConnected() {
|
||||
boolean redundant = connected.getAndSet(true);
|
||||
if (!redundant)
|
||||
for (InvitationListener l : listeners) l.connectionSucceeded();
|
||||
return redundant;
|
||||
}
|
||||
|
||||
void keyAgreementSucceeded(int localCode, int remoteCode) {
|
||||
lock.lock();
|
||||
try {
|
||||
localConfirmationCode = localCode;
|
||||
remoteConfirmationCode = remoteCode;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
for (InvitationListener l : listeners)
|
||||
l.keyAgreementSucceeded(localCode, remoteCode);
|
||||
}
|
||||
|
||||
void keyAgreementFailed() {
|
||||
for (InvitationListener l : listeners) l.keyAgreementFailed();
|
||||
}
|
||||
|
||||
boolean waitForLocalConfirmationResult() throws InterruptedException {
|
||||
localConfirmationLatch.await(CONFIRMATION_TIMEOUT, MILLISECONDS);
|
||||
lock.lock();
|
||||
try {
|
||||
return localMatched;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void remoteConfirmationSucceeded() {
|
||||
lock.lock();
|
||||
try {
|
||||
remoteCompared = true;
|
||||
remoteMatched = true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
for (InvitationListener l : listeners) l.remoteConfirmationSucceeded();
|
||||
}
|
||||
|
||||
void remoteConfirmationFailed() {
|
||||
lock.lock();
|
||||
try {
|
||||
remoteCompared = true;
|
||||
remoteMatched = false;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
for (InvitationListener l : listeners) l.remoteConfirmationFailed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contactExchangeSucceeded(Author remoteAuthor) {
|
||||
String name = remoteAuthor.getName();
|
||||
lock.lock();
|
||||
try {
|
||||
remoteName = name;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
for (InvitationListener l : listeners)
|
||||
l.pseudonymExchangeSucceeded(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void duplicateContact(Author remoteAuthor) {
|
||||
// TODO differentiate
|
||||
for (InvitationListener l : listeners) l.pseudonymExchangeFailed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contactExchangeFailed() {
|
||||
for (InvitationListener l : listeners) l.pseudonymExchangeFailed();
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package org.briarproject.bramble.invitation;
|
||||
|
||||
import org.briarproject.bramble.api.invitation.InvitationTaskFactory;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
@Module
|
||||
public class InvitationModule {
|
||||
|
||||
@Provides
|
||||
InvitationTaskFactory provideInvitationTaskFactory(
|
||||
InvitationTaskFactoryImpl invitationTaskFactory) {
|
||||
return invitationTaskFactory;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package org.briarproject.bramble.invitation;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.data.BdfReaderFactory;
|
||||
import org.briarproject.bramble.api.data.BdfWriterFactory;
|
||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
import org.briarproject.bramble.api.invitation.InvitationTask;
|
||||
import org.briarproject.bramble.api.invitation.InvitationTaskFactory;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.PluginManager;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
class InvitationTaskFactoryImpl implements InvitationTaskFactory {
|
||||
|
||||
private final CryptoComponent crypto;
|
||||
private final BdfReaderFactory bdfReaderFactory;
|
||||
private final BdfWriterFactory bdfWriterFactory;
|
||||
private final ContactExchangeTask contactExchangeTask;
|
||||
private final IdentityManager identityManager;
|
||||
private final PluginManager pluginManager;
|
||||
|
||||
@Inject
|
||||
InvitationTaskFactoryImpl(CryptoComponent crypto,
|
||||
BdfReaderFactory bdfReaderFactory,
|
||||
BdfWriterFactory bdfWriterFactory,
|
||||
ContactExchangeTask contactExchangeTask,
|
||||
IdentityManager identityManager, PluginManager pluginManager) {
|
||||
this.crypto = crypto;
|
||||
this.bdfReaderFactory = bdfReaderFactory;
|
||||
this.bdfWriterFactory = bdfWriterFactory;
|
||||
this.contactExchangeTask = contactExchangeTask;
|
||||
this.identityManager = identityManager;
|
||||
this.pluginManager = pluginManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InvitationTask createTask(int localCode, int remoteCode) {
|
||||
return new ConnectorGroup(crypto, bdfReaderFactory, bdfWriterFactory,
|
||||
contactExchangeTask, identityManager, pluginManager,
|
||||
localCode, remoteCode);
|
||||
}
|
||||
}
|
||||
@@ -164,14 +164,6 @@ class PluginManagerImpl implements PluginManager, Service {
|
||||
return new ArrayList<DuplexPlugin>(duplexPlugins);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<DuplexPlugin> getInvitationPlugins() {
|
||||
List<DuplexPlugin> supported = new ArrayList<DuplexPlugin>();
|
||||
for (DuplexPlugin d : duplexPlugins)
|
||||
if (d.supportsInvitations()) supported.add(d);
|
||||
return supported;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<DuplexPlugin> getKeyAgreementPlugins() {
|
||||
List<DuplexPlugin> supported = new ArrayList<DuplexPlugin>();
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.briarproject.bramble.plugin.tcp;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
||||
import org.briarproject.bramble.api.data.BdfList;
|
||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
@@ -281,17 +280,6 @@ abstract class TcpPlugin implements DuplexPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsInvitations() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
||||
long timeout, boolean alice) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsKeyAgreement() {
|
||||
return false;
|
||||
|
||||
@@ -29,10 +29,10 @@ class StreamReaderFactoryImpl implements StreamReaderFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream createInvitationStreamReader(InputStream in,
|
||||
public InputStream createContactExchangeStreamReader(InputStream in,
|
||||
SecretKey headerKey) {
|
||||
return new StreamReaderImpl(
|
||||
streamDecrypterFactory.createInvitationStreamDecrypter(in,
|
||||
streamDecrypterFactory.createContactExchangeStreamDecrypter(in,
|
||||
headerKey));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,10 +30,10 @@ class StreamWriterFactoryImpl implements StreamWriterFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream createInvitationStreamWriter(OutputStream out,
|
||||
public OutputStream createContactExchangeStreamWriter(OutputStream out,
|
||||
SecretKey headerKey) {
|
||||
return new StreamWriterImpl(
|
||||
streamEncrypterFactory.createInvitationStreamEncrypter(out,
|
||||
streamEncrypterFactory.createContactExchangeStreamDecrypter(out,
|
||||
headerKey));
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.briarproject.bramble.crypto;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.spongycastle.crypto.Digest;
|
||||
import org.spongycastle.crypto.engines.Salsa20Engine;
|
||||
@@ -11,11 +10,11 @@ import javax.annotation.concurrent.NotThreadSafe;
|
||||
|
||||
@NotThreadSafe
|
||||
@NotNullByDefault
|
||||
class PseudoRandomImpl implements PseudoRandom {
|
||||
class PseudoRandom {
|
||||
|
||||
private final Salsa20Engine cipher = new Salsa20Engine();
|
||||
|
||||
PseudoRandomImpl(byte[] seed) {
|
||||
PseudoRandom(byte[] seed) {
|
||||
// Hash the seed to produce a 32-byte key
|
||||
byte[] key = new byte[32];
|
||||
Digest digest = new Blake2sDigest();
|
||||
@@ -26,8 +25,7 @@ class PseudoRandomImpl implements PseudoRandom {
|
||||
cipher.init(true, new ParametersWithIV(new KeyParameter(key), nonce));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] nextBytes(int length) {
|
||||
byte[] nextBytes(int length) {
|
||||
byte[] in = new byte[length], out = new byte[length];
|
||||
cipher.processBytes(in, 0, length, out, 0);
|
||||
return out;
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.briarproject.bramble.crypto;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
||||
|
||||
import java.security.Provider;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.SecureRandomSpi;
|
||||
@@ -19,7 +17,7 @@ class PseudoSecureRandom extends SecureRandom {
|
||||
private final PseudoRandom pseudoRandom;
|
||||
|
||||
private PseudoSecureRandomSpi(byte[] seed) {
|
||||
pseudoRandom = new PseudoRandomImpl(seed);
|
||||
pseudoRandom = new PseudoRandom(seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user