mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 21:59:54 +01:00
Encode transport properties more compactly in QR codes.
This commit is contained in:
@@ -11,12 +11,13 @@ import android.content.IntentFilter;
|
|||||||
|
|
||||||
import org.briarproject.android.api.AndroidExecutor;
|
import org.briarproject.android.api.AndroidExecutor;
|
||||||
import org.briarproject.android.util.AndroidUtils;
|
import org.briarproject.android.util.AndroidUtils;
|
||||||
|
import org.briarproject.api.FormatException;
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
@@ -44,6 +45,8 @@ import java.util.concurrent.Future;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
|
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
|
||||||
import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
|
import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
|
||||||
import static android.bluetooth.BluetoothAdapter.EXTRA_SCAN_MODE;
|
import static android.bluetooth.BluetoothAdapter.EXTRA_SCAN_MODE;
|
||||||
@@ -57,6 +60,7 @@ import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
|
|||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
||||||
import static org.briarproject.util.PrivacyUtils.scrubMacAddress;
|
import static org.briarproject.util.PrivacyUtils.scrubMacAddress;
|
||||||
|
|
||||||
class DroidtoothPlugin implements DuplexPlugin {
|
class DroidtoothPlugin implements DuplexPlugin {
|
||||||
@@ -466,23 +470,25 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
TransportProperties p = new TransportProperties();
|
BdfList descriptor = new BdfList();
|
||||||
|
descriptor.add(TRANSPORT_ID_BLUETOOTH);
|
||||||
String address = AndroidUtils.getBluetoothAddress(appContext, adapter);
|
String address = AndroidUtils.getBluetoothAddress(appContext, adapter);
|
||||||
if (!StringUtils.isNullOrEmpty(address))
|
if (!address.isEmpty()) descriptor.add(StringUtils.macToBytes(address));
|
||||||
p.put(PROP_ADDRESS, address);
|
return new BluetoothKeyAgreementListener(descriptor, ss);
|
||||||
TransportDescriptor d = new TransportDescriptor(ID, p);
|
|
||||||
return new BluetoothKeyAgreementListener(d, ss);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, BdfList descriptor, long timeout) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
if (!ID.equals(d.getIdentifier())) return null;
|
String address;
|
||||||
TransportProperties p = d.getProperties();
|
try {
|
||||||
if (p == null) return null;
|
address = parseAddress(descriptor);
|
||||||
String address = p.get(PROP_ADDRESS);
|
} catch (FormatException e) {
|
||||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
LOG.info("Invalid address in key agreement descriptor");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (address == null) return null;
|
||||||
// No truncation necessary because COMMIT_LENGTH = 16
|
// No truncation necessary because COMMIT_LENGTH = 16
|
||||||
UUID uuid = UUID.nameUUIDFromBytes(commitment);
|
UUID uuid = UUID.nameUUIDFromBytes(commitment);
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
@@ -492,6 +498,14 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
return new DroidtoothTransportConnection(this, s);
|
return new DroidtoothTransportConnection(this, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private String parseAddress(BdfList descriptor) throws FormatException {
|
||||||
|
if (descriptor.size() < 2) return null;
|
||||||
|
byte[] mac = descriptor.getRaw(1);
|
||||||
|
if (mac.length != 6) throw new FormatException();
|
||||||
|
return StringUtils.macToString(mac);
|
||||||
|
}
|
||||||
|
|
||||||
private class BluetoothStateReceiver extends BroadcastReceiver {
|
private class BluetoothStateReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -626,7 +640,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
private final BluetoothServerSocket ss;
|
private final BluetoothServerSocket ss;
|
||||||
|
|
||||||
BluetoothKeyAgreementListener(TransportDescriptor descriptor,
|
BluetoothKeyAgreementListener(BdfList descriptor,
|
||||||
BluetoothServerSocket ss) {
|
BluetoothServerSocket ss) {
|
||||||
super(descriptor);
|
super(descriptor);
|
||||||
this.ss = ss;
|
this.ss = ss;
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ import org.briarproject.android.util.AndroidUtils;
|
|||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.event.Event;
|
import org.briarproject.api.event.Event;
|
||||||
import org.briarproject.api.event.EventListener;
|
import org.briarproject.api.event.EventListener;
|
||||||
import org.briarproject.api.event.SettingsUpdatedEvent;
|
import org.briarproject.api.event.SettingsUpdatedEvent;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.TorConstants;
|
import org.briarproject.api.plugins.TorConstants;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
@@ -574,7 +574,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, BdfList descriptor, long timeout) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ package org.briarproject.api.keyagreement;
|
|||||||
public interface KeyAgreementConstants {
|
public interface KeyAgreementConstants {
|
||||||
|
|
||||||
/** The current version of the BQP protocol. */
|
/** The current version of the BQP protocol. */
|
||||||
byte PROTOCOL_VERSION = 1;
|
byte PROTOCOL_VERSION = 2;
|
||||||
|
|
||||||
/** The length of the record header in bytes. */
|
/** The length of the record header in bytes. */
|
||||||
int RECORD_HEADER_LENGTH = 4;
|
int RECORD_HEADER_LENGTH = 4;
|
||||||
@@ -16,4 +16,10 @@ public interface KeyAgreementConstants {
|
|||||||
int COMMIT_LENGTH = 16;
|
int COMMIT_LENGTH = 16;
|
||||||
|
|
||||||
long CONNECTION_TIMEOUT = 20 * 1000; // Milliseconds
|
long CONNECTION_TIMEOUT = 20 * 1000; // Milliseconds
|
||||||
|
|
||||||
|
/** The transport identifier for Bluetooth. */
|
||||||
|
int TRANSPORT_ID_BLUETOOTH = 0;
|
||||||
|
|
||||||
|
/** The transport identifier for LAN. */
|
||||||
|
int TRANSPORT_ID_LAN = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.briarproject.api.keyagreement;
|
package org.briarproject.api.keyagreement;
|
||||||
|
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -7,9 +9,9 @@ import java.util.concurrent.Callable;
|
|||||||
*/
|
*/
|
||||||
public abstract class KeyAgreementListener {
|
public abstract class KeyAgreementListener {
|
||||||
|
|
||||||
private final TransportDescriptor descriptor;
|
private final BdfList descriptor;
|
||||||
|
|
||||||
public KeyAgreementListener(TransportDescriptor descriptor) {
|
public KeyAgreementListener(BdfList descriptor) {
|
||||||
this.descriptor = descriptor;
|
this.descriptor = descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,7 +19,7 @@ public abstract class KeyAgreementListener {
|
|||||||
* Returns the descriptor that a remote peer can use to connect to this
|
* Returns the descriptor that a remote peer can use to connect to this
|
||||||
* listener.
|
* listener.
|
||||||
*/
|
*/
|
||||||
public TransportDescriptor getDescriptor() {
|
public BdfList getDescriptor() {
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,40 @@
|
|||||||
package org.briarproject.api.keyagreement;
|
package org.briarproject.api.keyagreement;
|
||||||
|
|
||||||
import org.briarproject.api.Bytes;
|
import org.briarproject.api.Bytes;
|
||||||
|
import org.briarproject.api.TransportId;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A BQP payload.
|
* A BQP payload.
|
||||||
*/
|
*/
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
public class Payload implements Comparable<Payload> {
|
public class Payload implements Comparable<Payload> {
|
||||||
|
|
||||||
private final Bytes commitment;
|
private final Bytes commitment;
|
||||||
private final List<TransportDescriptor> descriptors;
|
private final Map<TransportId, BdfList> descriptors;
|
||||||
|
|
||||||
public Payload(byte[] commitment, List<TransportDescriptor> descriptors) {
|
public Payload(byte[] commitment, Map<TransportId, BdfList> descriptors) {
|
||||||
this.commitment = new Bytes(commitment);
|
this.commitment = new Bytes(commitment);
|
||||||
this.descriptors = descriptors;
|
this.descriptors = descriptors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the commitment contained in this payload. */
|
/**
|
||||||
|
* Returns the commitment contained in this payload.
|
||||||
|
*/
|
||||||
public byte[] getCommitment() {
|
public byte[] getCommitment() {
|
||||||
return commitment.getBytes();
|
return commitment.getBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the transport descriptors contained in this payload. */
|
/**
|
||||||
public List<TransportDescriptor> getTransportDescriptors() {
|
* Returns the transport descriptors contained in this payload.
|
||||||
|
*/
|
||||||
|
public Map<TransportId, BdfList> getTransportDescriptors() {
|
||||||
return descriptors;
|
return descriptors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package org.briarproject.api.keyagreement;
|
package org.briarproject.api.keyagreement;
|
||||||
|
|
||||||
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
public interface PayloadParser {
|
public interface PayloadParser {
|
||||||
|
|
||||||
Payload parse(byte[] raw) throws IOException;
|
Payload parse(byte[] raw) throws IOException;
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
package org.briarproject.api.keyagreement;
|
|
||||||
|
|
||||||
import org.briarproject.api.TransportId;
|
|
||||||
import org.briarproject.api.properties.TransportProperties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Describes how to connect to a device over a short-range transport.
|
|
||||||
*/
|
|
||||||
public class TransportDescriptor {
|
|
||||||
|
|
||||||
private final TransportId id;
|
|
||||||
private final TransportProperties properties;
|
|
||||||
|
|
||||||
public TransportDescriptor(TransportId id, TransportProperties properties) {
|
|
||||||
this.id = id;
|
|
||||||
this.properties = properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the transport identifier. */
|
|
||||||
public TransportId getIdentifier() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the transport properties. */
|
|
||||||
public TransportProperties getProperties() {
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +1,26 @@
|
|||||||
package org.briarproject.api.plugins;
|
package org.briarproject.api.plugins;
|
||||||
|
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsible for starting transport plugins at startup and stopping them at
|
* Responsible for starting transport plugins at startup and stopping them at
|
||||||
* shutdown.
|
* shutdown.
|
||||||
*/
|
*/
|
||||||
|
@NotNullByDefault
|
||||||
public interface PluginManager {
|
public interface PluginManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the plugin for the given transport, or null if no such plugin
|
* Returns the plugin for the given transport, or null if no such plugin
|
||||||
* has been created.
|
* has been created.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
Plugin getPlugin(TransportId t);
|
Plugin getPlugin(TransportId t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package org.briarproject.api.plugins.duplex;
|
|||||||
|
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
|
||||||
import org.briarproject.api.plugins.Plugin;
|
import org.briarproject.api.plugins.Plugin;
|
||||||
|
|
||||||
/** An interface for transport plugins that support duplex communication. */
|
/** An interface for transport plugins that support duplex communication. */
|
||||||
@@ -40,5 +40,5 @@ public interface DuplexPlugin extends Plugin {
|
|||||||
* Returns null if no connection can be established within the given time.
|
* Returns null if no connection can be established within the given time.
|
||||||
*/
|
*/
|
||||||
DuplexTransportConnection createKeyAgreementConnection(
|
DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] remoteCommitment, TransportDescriptor d, long timeout);
|
byte[] remoteCommitment, BdfList descriptor, long timeout);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package org.briarproject.keyagreement;
|
package org.briarproject.keyagreement;
|
||||||
|
|
||||||
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.crypto.CryptoComponent;
|
import org.briarproject.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.api.crypto.KeyPair;
|
import org.briarproject.api.crypto.KeyPair;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.Payload;
|
import org.briarproject.api.keyagreement.Payload;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
import org.briarproject.api.plugins.Plugin;
|
||||||
import org.briarproject.api.plugins.PluginManager;
|
import org.briarproject.api.plugins.PluginManager;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||||
@@ -14,7 +16,10 @@ import org.briarproject.api.system.Clock;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.CompletionService;
|
import java.util.concurrent.CompletionService;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
@@ -68,14 +73,13 @@ class KeyAgreementConnector {
|
|||||||
byte[] commitment = crypto.deriveKeyCommitment(
|
byte[] commitment = crypto.deriveKeyCommitment(
|
||||||
localKeyPair.getPublic().getEncoded());
|
localKeyPair.getPublic().getEncoded());
|
||||||
// Start all listeners and collect their descriptors
|
// Start all listeners and collect their descriptors
|
||||||
List<TransportDescriptor> descriptors =
|
Map<TransportId, BdfList> descriptors =
|
||||||
new ArrayList<TransportDescriptor>();
|
new HashMap<TransportId, BdfList>();
|
||||||
for (DuplexPlugin plugin : pluginManager.getKeyAgreementPlugins()) {
|
for (DuplexPlugin plugin : pluginManager.getKeyAgreementPlugins()) {
|
||||||
KeyAgreementListener l = plugin.createKeyAgreementListener(
|
KeyAgreementListener l =
|
||||||
commitment);
|
plugin.createKeyAgreementListener(commitment);
|
||||||
if (l != null) {
|
if (l != null) {
|
||||||
TransportDescriptor d = l.getDescriptor();
|
descriptors.put(plugin.getId(), l.getDescriptor());
|
||||||
descriptors.add(d);
|
|
||||||
pending.add(connect.submit(new ReadableTask(l.listen())));
|
pending.add(connect.submit(new ReadableTask(l.listen())));
|
||||||
listeners.add(l);
|
listeners.add(l);
|
||||||
}
|
}
|
||||||
@@ -100,13 +104,16 @@ class KeyAgreementConnector {
|
|||||||
|
|
||||||
// Start connecting over supported transports
|
// Start connecting over supported transports
|
||||||
LOG.info("Starting outgoing BQP connections");
|
LOG.info("Starting outgoing BQP connections");
|
||||||
for (TransportDescriptor d : remotePayload.getTransportDescriptors()) {
|
Map<TransportId, BdfList> descriptors =
|
||||||
DuplexPlugin plugin = (DuplexPlugin) pluginManager.getPlugin(
|
remotePayload.getTransportDescriptors();
|
||||||
d.getIdentifier());
|
for (Entry<TransportId, BdfList> e : descriptors.entrySet()) {
|
||||||
if (plugin != null)
|
Plugin p = pluginManager.getPlugin(e.getKey());
|
||||||
|
if (p instanceof DuplexPlugin) {
|
||||||
|
DuplexPlugin plugin = (DuplexPlugin) p;
|
||||||
pending.add(connect.submit(new ReadableTask(
|
pending.add(connect.submit(new ReadableTask(
|
||||||
new ConnectorTask(plugin, remotePayload.getCommitment(),
|
new ConnectorTask(plugin, remotePayload.getCommitment(),
|
||||||
d, end))));
|
e.getValue(), end))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get chosen connection
|
// Get chosen connection
|
||||||
@@ -170,12 +177,12 @@ class KeyAgreementConnector {
|
|||||||
private class ConnectorTask implements Callable<KeyAgreementConnection> {
|
private class ConnectorTask implements Callable<KeyAgreementConnection> {
|
||||||
|
|
||||||
private final byte[] commitment;
|
private final byte[] commitment;
|
||||||
private final TransportDescriptor descriptor;
|
private final BdfList descriptor;
|
||||||
private final long end;
|
private final long end;
|
||||||
private final DuplexPlugin plugin;
|
private final DuplexPlugin plugin;
|
||||||
|
|
||||||
private ConnectorTask(DuplexPlugin plugin, byte[] commitment,
|
private ConnectorTask(DuplexPlugin plugin, byte[] commitment,
|
||||||
TransportDescriptor descriptor, long end) {
|
BdfList descriptor, long end) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.commitment = commitment;
|
this.commitment = commitment;
|
||||||
this.descriptor = descriptor;
|
this.descriptor = descriptor;
|
||||||
|
|||||||
@@ -1,24 +1,30 @@
|
|||||||
package org.briarproject.keyagreement;
|
package org.briarproject.keyagreement;
|
||||||
|
|
||||||
|
import org.briarproject.api.TransportId;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.data.BdfWriter;
|
import org.briarproject.api.data.BdfWriter;
|
||||||
import org.briarproject.api.data.BdfWriterFactory;
|
import org.briarproject.api.data.BdfWriterFactory;
|
||||||
import org.briarproject.api.keyagreement.Payload;
|
import org.briarproject.api.keyagreement.Payload;
|
||||||
import org.briarproject.api.keyagreement.PayloadEncoder;
|
import org.briarproject.api.keyagreement.PayloadEncoder;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
class PayloadEncoderImpl implements PayloadEncoder {
|
class PayloadEncoderImpl implements PayloadEncoder {
|
||||||
|
|
||||||
private final BdfWriterFactory bdfWriterFactory;
|
private final BdfWriterFactory bdfWriterFactory;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public PayloadEncoderImpl(BdfWriterFactory bdfWriterFactory) {
|
PayloadEncoderImpl(BdfWriterFactory bdfWriterFactory) {
|
||||||
this.bdfWriterFactory = bdfWriterFactory;
|
this.bdfWriterFactory = bdfWriterFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,18 +36,13 @@ class PayloadEncoderImpl implements PayloadEncoder {
|
|||||||
w.writeListStart(); // Payload start
|
w.writeListStart(); // Payload start
|
||||||
w.writeLong(PROTOCOL_VERSION);
|
w.writeLong(PROTOCOL_VERSION);
|
||||||
w.writeRaw(p.getCommitment());
|
w.writeRaw(p.getCommitment());
|
||||||
w.writeListStart(); // Descriptors start
|
Map<TransportId, BdfList> descriptors = p.getTransportDescriptors();
|
||||||
for (TransportDescriptor d : p.getTransportDescriptors()) {
|
for (BdfList descriptor : descriptors.values())
|
||||||
w.writeListStart();
|
w.writeList(descriptor);
|
||||||
w.writeString(d.getIdentifier().getString());
|
|
||||||
w.writeDictionary(d.getProperties());
|
|
||||||
w.writeListEnd();
|
|
||||||
}
|
|
||||||
w.writeListEnd(); // Descriptors end
|
|
||||||
w.writeListEnd(); // Payload end
|
w.writeListEnd(); // Payload end
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Shouldn't happen with ByteArrayOutputStream
|
// Shouldn't happen with ByteArrayOutputStream
|
||||||
throw new RuntimeException(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
return out.toByteArray();
|
return out.toByteArray();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,30 +2,34 @@ package org.briarproject.keyagreement;
|
|||||||
|
|
||||||
import org.briarproject.api.FormatException;
|
import org.briarproject.api.FormatException;
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.data.BdfReader;
|
import org.briarproject.api.data.BdfReader;
|
||||||
import org.briarproject.api.data.BdfReaderFactory;
|
import org.briarproject.api.data.BdfReaderFactory;
|
||||||
import org.briarproject.api.keyagreement.Payload;
|
import org.briarproject.api.keyagreement.Payload;
|
||||||
import org.briarproject.api.keyagreement.PayloadParser;
|
import org.briarproject.api.keyagreement.PayloadParser;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.api.properties.TransportProperties;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
||||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
||||||
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
class PayloadParserImpl implements PayloadParser {
|
class PayloadParserImpl implements PayloadParser {
|
||||||
|
|
||||||
private final BdfReaderFactory bdfReaderFactory;
|
private final BdfReaderFactory bdfReaderFactory;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public PayloadParserImpl(BdfReaderFactory bdfReaderFactory) {
|
PayloadParserImpl(BdfReaderFactory bdfReaderFactory) {
|
||||||
this.bdfReaderFactory = bdfReaderFactory;
|
this.bdfReaderFactory = bdfReaderFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,36 +37,28 @@ class PayloadParserImpl implements PayloadParser {
|
|||||||
public Payload parse(byte[] raw) throws IOException {
|
public Payload parse(byte[] raw) throws IOException {
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(raw);
|
ByteArrayInputStream in = new ByteArrayInputStream(raw);
|
||||||
BdfReader r = bdfReaderFactory.createReader(in);
|
BdfReader r = bdfReaderFactory.createReader(in);
|
||||||
r.readListStart(); // Payload start
|
// The payload is a BDF list with two or more elements
|
||||||
int proto = (int) r.readLong();
|
BdfList payload = r.readList();
|
||||||
if (proto != PROTOCOL_VERSION)
|
if (payload.size() < 2) throw new FormatException();
|
||||||
throw new FormatException();
|
if (!r.eof()) throw new FormatException();
|
||||||
byte[] commitment = r.readRaw(COMMIT_LENGTH);
|
// First element: the protocol version
|
||||||
if (commitment.length != COMMIT_LENGTH)
|
long protocolVersion = payload.getLong(0);
|
||||||
throw new FormatException();
|
if (protocolVersion != PROTOCOL_VERSION) throw new FormatException();
|
||||||
List<TransportDescriptor> descriptors = new ArrayList<TransportDescriptor>();
|
// Second element: the public key commitment
|
||||||
r.readListStart(); // Descriptors start
|
byte[] commitment = payload.getRaw(1);
|
||||||
while (r.hasList()) {
|
if (commitment.length != COMMIT_LENGTH) throw new FormatException();
|
||||||
r.readListStart();
|
// Remaining elements: transport descriptors
|
||||||
while (!r.hasListEnd()) {
|
Map<TransportId, BdfList> recognised =
|
||||||
TransportId id =
|
new HashMap<TransportId, BdfList>();
|
||||||
new TransportId(r.readString(MAX_PROPERTY_LENGTH));
|
for (int i = 2; i < payload.size(); i++) {
|
||||||
TransportProperties p = new TransportProperties();
|
BdfList descriptor = payload.getList(i);
|
||||||
r.readDictionaryStart();
|
long transportId = descriptor.getLong(0);
|
||||||
while (!r.hasDictionaryEnd()) {
|
if (transportId == TRANSPORT_ID_BLUETOOTH) {
|
||||||
String key = r.readString(MAX_PROPERTY_LENGTH);
|
recognised.put(new TransportId("bt"), descriptor);
|
||||||
String value = r.readString(MAX_PROPERTY_LENGTH);
|
} else if (transportId == TRANSPORT_ID_LAN) {
|
||||||
p.put(key, value);
|
recognised.put(new TransportId("lan"), descriptor);
|
||||||
}
|
|
||||||
r.readDictionaryEnd();
|
|
||||||
descriptors.add(new TransportDescriptor(id, p));
|
|
||||||
}
|
}
|
||||||
r.readListEnd();
|
|
||||||
}
|
}
|
||||||
r.readListEnd(); // Descriptors end
|
return new Payload(commitment, recognised);
|
||||||
r.readListEnd(); // Payload end
|
|
||||||
if (!r.eof())
|
|
||||||
throw new FormatException();
|
|
||||||
return new Payload(commitment, descriptors);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.briarproject.api.event.TransportEnabledEvent;
|
|||||||
import org.briarproject.api.lifecycle.IoExecutor;
|
import org.briarproject.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.api.lifecycle.Service;
|
import org.briarproject.api.lifecycle.Service;
|
||||||
import org.briarproject.api.lifecycle.ServiceException;
|
import org.briarproject.api.lifecycle.ServiceException;
|
||||||
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.api.plugins.ConnectionManager;
|
import org.briarproject.api.plugins.ConnectionManager;
|
||||||
import org.briarproject.api.plugins.Plugin;
|
import org.briarproject.api.plugins.Plugin;
|
||||||
import org.briarproject.api.plugins.PluginCallback;
|
import org.briarproject.api.plugins.PluginCallback;
|
||||||
@@ -42,11 +43,14 @@ import java.util.concurrent.Executor;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
|
@ThreadSafe
|
||||||
|
@NotNullByDefault
|
||||||
class PluginManagerImpl implements PluginManager, Service {
|
class PluginManagerImpl implements PluginManager, Service {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package org.briarproject.plugins.tcp;
|
package org.briarproject.plugins.tcp;
|
||||||
|
|
||||||
|
import org.briarproject.api.FormatException;
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||||
@@ -19,6 +20,7 @@ import java.net.InetSocketAddress;
|
|||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@@ -27,8 +29,12 @@ import java.util.concurrent.Callable;
|
|||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN;
|
||||||
|
import static org.briarproject.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
||||||
import static org.briarproject.util.PrivacyUtils.scrubSocketAddress;
|
import static org.briarproject.util.PrivacyUtils.scrubSocketAddress;
|
||||||
|
|
||||||
class LanTcpPlugin extends TcpPlugin {
|
class LanTcpPlugin extends TcpPlugin {
|
||||||
@@ -40,7 +46,6 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
|
|
||||||
private static final int MAX_ADDRESSES = 5;
|
private static final int MAX_ADDRESSES = 5;
|
||||||
private static final String PROP_IP_PORTS = "ipPorts";
|
private static final String PROP_IP_PORTS = "ipPorts";
|
||||||
private static final String PROP_IP_PORT = "ipPort";
|
|
||||||
private static final String SEPARATOR = ",";
|
private static final String SEPARATOR = ",";
|
||||||
|
|
||||||
LanTcpPlugin(Executor ioExecutor, Backoff backoff,
|
LanTcpPlugin(Executor ioExecutor, Backoff backoff,
|
||||||
@@ -186,22 +191,26 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
LOG.info("Could not bind server socket for key agreement");
|
LOG.info("Could not bind server socket for key agreement");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
TransportProperties p = new TransportProperties();
|
BdfList descriptor = new BdfList();
|
||||||
SocketAddress local = ss.getLocalSocketAddress();
|
descriptor.add(TRANSPORT_ID_LAN);
|
||||||
p.put(PROP_IP_PORT, getIpPortString((InetSocketAddress) local));
|
InetSocketAddress local =
|
||||||
TransportDescriptor d = new TransportDescriptor(ID, p);
|
(InetSocketAddress) ss.getLocalSocketAddress();
|
||||||
return new LanKeyAgreementListener(d, ss);
|
descriptor.add(local.getAddress().getAddress());
|
||||||
|
descriptor.add(local.getPort());
|
||||||
|
return new LanKeyAgreementListener(descriptor, ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, BdfList descriptor, long timeout) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
if (!ID.equals(d.getIdentifier())) return null;
|
InetSocketAddress remote;
|
||||||
TransportProperties p = d.getProperties();
|
try {
|
||||||
if (p == null) return null;
|
remote = parseSocketAddress(descriptor);
|
||||||
String ipPort = p.get(PROP_IP_PORT);
|
} catch (FormatException e) {
|
||||||
InetSocketAddress remote = parseSocketAddress(ipPort);
|
LOG.info("Invalid IP/port in key agreement descriptor");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (remote == null) return null;
|
if (remote == null) return null;
|
||||||
if (!isConnectable(remote)) {
|
if (!isConnectable(remote)) {
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
@@ -228,11 +237,27 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private InetSocketAddress parseSocketAddress(BdfList descriptor)
|
||||||
|
throws FormatException {
|
||||||
|
if (descriptor.size() < 3) return null;
|
||||||
|
byte[] address = descriptor.getRaw(1);
|
||||||
|
int port = descriptor.getLong(2).intValue();
|
||||||
|
if (port < 1 || port > MAX_16_BIT_UNSIGNED) throw new FormatException();
|
||||||
|
try {
|
||||||
|
InetAddress addr = InetAddress.getByAddress(address);
|
||||||
|
return new InetSocketAddress(addr, port);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
// Invalid address length
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class LanKeyAgreementListener extends KeyAgreementListener {
|
private class LanKeyAgreementListener extends KeyAgreementListener {
|
||||||
|
|
||||||
private final ServerSocket ss;
|
private final ServerSocket ss;
|
||||||
|
|
||||||
public LanKeyAgreementListener(TransportDescriptor descriptor,
|
private LanKeyAgreementListener(BdfList descriptor,
|
||||||
ServerSocket ss) {
|
ServerSocket ss) {
|
||||||
super(descriptor);
|
super(descriptor);
|
||||||
this.ss = ss;
|
this.ss = ss;
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package org.briarproject.plugins.tcp;
|
|||||||
|
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
@@ -298,7 +298,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, BdfList descriptor, long timeout) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,34 @@
|
|||||||
package org.briarproject.util;
|
package org.briarproject.util;
|
||||||
|
|
||||||
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.CharacterCodingException;
|
import java.nio.charset.CharacterCodingException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.CharsetDecoder;
|
import java.nio.charset.CharsetDecoder;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.nio.charset.CodingErrorAction.IGNORE;
|
import static java.nio.charset.CodingErrorAction.IGNORE;
|
||||||
|
import static java.util.regex.Pattern.CASE_INSENSITIVE;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
public class StringUtils {
|
public class StringUtils {
|
||||||
|
|
||||||
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||||
|
private static Pattern MAC = Pattern.compile("[0-9a-f]{2}:[0-9a-f]{2}:" +
|
||||||
|
"[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}",
|
||||||
|
CASE_INSENSITIVE);
|
||||||
|
|
||||||
private static final char[] HEX = new char[] {
|
private static final char[] HEX = new char[] {
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||||
};
|
};
|
||||||
|
|
||||||
public static boolean isNullOrEmpty(String s) {
|
public static boolean isNullOrEmpty(@Nullable String s) {
|
||||||
return s == null || s.length() == 0;
|
return s == null || s.length() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +71,9 @@ public class StringUtils {
|
|||||||
return fromUtf8(utf8, 0, maxUtf8Length);
|
return fromUtf8(utf8, 0, maxUtf8Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts the given byte array to a hex character array. */
|
/**
|
||||||
|
* Converts the given byte array to a hex character array.
|
||||||
|
*/
|
||||||
private static char[] toHexChars(byte[] bytes) {
|
private static char[] toHexChars(byte[] bytes) {
|
||||||
char[] hex = new char[bytes.length * 2];
|
char[] hex = new char[bytes.length * 2];
|
||||||
for (int i = 0, j = 0; i < bytes.length; i++) {
|
for (int i = 0, j = 0; i < bytes.length; i++) {
|
||||||
@@ -71,12 +83,16 @@ public class StringUtils {
|
|||||||
return hex;
|
return hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts the given byte array to a hex string. */
|
/**
|
||||||
|
* Converts the given byte array to a hex string.
|
||||||
|
*/
|
||||||
public static String toHexString(byte[] bytes) {
|
public static String toHexString(byte[] bytes) {
|
||||||
return new String(toHexChars(bytes));
|
return new String(toHexChars(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts the given hex string to a byte array. */
|
/**
|
||||||
|
* Converts the given hex string to a byte array.
|
||||||
|
*/
|
||||||
public static byte[] fromHexString(String hex) {
|
public static byte[] fromHexString(String hex) {
|
||||||
int len = hex.length();
|
int len = hex.length();
|
||||||
if (len % 2 != 0)
|
if (len % 2 != 0)
|
||||||
@@ -107,4 +123,20 @@ public class StringUtils {
|
|||||||
public static boolean utf8IsTooLong(String s, int maxLength) {
|
public static boolean utf8IsTooLong(String s, int maxLength) {
|
||||||
return toUtf8(s).length > maxLength;
|
return toUtf8(s).length > maxLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] macToBytes(String mac) {
|
||||||
|
if (!MAC.matcher(mac).matches()) throw new IllegalArgumentException();
|
||||||
|
return fromHexString(mac.replaceAll(":", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String macToString(byte[] mac) {
|
||||||
|
if (mac.length != 6) throw new IllegalArgumentException();
|
||||||
|
StringBuilder s = new StringBuilder();
|
||||||
|
for (byte b : mac) {
|
||||||
|
if (s.length() > 0) s.append(':');
|
||||||
|
s.append(HEX[(b >> 4) & 0xF]);
|
||||||
|
s.append(HEX[b & 0xF]);
|
||||||
|
}
|
||||||
|
return s.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package org.briarproject.plugins.bluetooth;
|
package org.briarproject.plugins.bluetooth;
|
||||||
|
|
||||||
|
import org.briarproject.api.FormatException;
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
@@ -33,6 +34,7 @@ import java.util.concurrent.Semaphore;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.bluetooth.BluetoothStateException;
|
import javax.bluetooth.BluetoothStateException;
|
||||||
import javax.bluetooth.DiscoveryAgent;
|
import javax.bluetooth.DiscoveryAgent;
|
||||||
import javax.bluetooth.LocalDevice;
|
import javax.bluetooth.LocalDevice;
|
||||||
@@ -44,6 +46,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
|||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static javax.bluetooth.DiscoveryAgent.GIAC;
|
import static javax.bluetooth.DiscoveryAgent.GIAC;
|
||||||
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
||||||
|
|
||||||
class BluetoothPlugin implements DuplexPlugin {
|
class BluetoothPlugin implements DuplexPlugin {
|
||||||
|
|
||||||
@@ -382,21 +385,25 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
tryToClose(ss);
|
tryToClose(ss);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
TransportProperties p = new TransportProperties();
|
BdfList descriptor = new BdfList();
|
||||||
p.put(PROP_ADDRESS, localDevice.getBluetoothAddress());
|
descriptor.add(TRANSPORT_ID_BLUETOOTH);
|
||||||
TransportDescriptor d = new TransportDescriptor(ID, p);
|
String address = localDevice.getBluetoothAddress();
|
||||||
return new BluetoothKeyAgreementListener(d, ss);
|
if (!address.isEmpty()) descriptor.add(StringUtils.macToBytes(address));
|
||||||
|
return new BluetoothKeyAgreementListener(descriptor, ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, BdfList descriptor, long timeout) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
if (!ID.equals(d.getIdentifier())) return null;
|
String address;
|
||||||
TransportProperties p = d.getProperties();
|
try {
|
||||||
if (p == null) return null;
|
address = parseAddress(descriptor);
|
||||||
String address = p.get(PROP_ADDRESS);
|
} catch (FormatException e) {
|
||||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
LOG.info("Invalid address in key agreement descriptor");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (address == null) return null;
|
||||||
// No truncation necessary because COMMIT_LENGTH = 16
|
// No truncation necessary because COMMIT_LENGTH = 16
|
||||||
String uuid = UUID.nameUUIDFromBytes(commitment).toString();
|
String uuid = UUID.nameUUIDFromBytes(commitment).toString();
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
@@ -407,6 +414,14 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
return new BluetoothTransportConnection(this, s);
|
return new BluetoothTransportConnection(this, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private String parseAddress(BdfList descriptor) throws FormatException {
|
||||||
|
if (descriptor.size() < 2) return null;
|
||||||
|
byte[] mac = descriptor.getRaw(1);
|
||||||
|
if (mac.length != 6) throw new FormatException();
|
||||||
|
return StringUtils.macToString(mac);
|
||||||
|
}
|
||||||
|
|
||||||
private void makeDeviceDiscoverable() {
|
private void makeDeviceDiscoverable() {
|
||||||
// Try to make the device discoverable (requires root on Linux)
|
// Try to make the device discoverable (requires root on Linux)
|
||||||
try {
|
try {
|
||||||
@@ -491,7 +506,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
private final StreamConnectionNotifier ss;
|
private final StreamConnectionNotifier ss;
|
||||||
|
|
||||||
BluetoothKeyAgreementListener(TransportDescriptor descriptor,
|
BluetoothKeyAgreementListener(BdfList descriptor,
|
||||||
StreamConnectionNotifier ss) {
|
StreamConnectionNotifier ss) {
|
||||||
super(descriptor);
|
super(descriptor);
|
||||||
this.ss = ss;
|
this.ss = ss;
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package org.briarproject.plugins.modem;
|
|||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
|
||||||
import org.briarproject.api.plugins.duplex.AbstractDuplexTransportConnection;
|
import org.briarproject.api.plugins.duplex.AbstractDuplexTransportConnection;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
@@ -114,7 +114,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
|||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean resetModem() {
|
private boolean resetModem() {
|
||||||
if (!running) return false;
|
if (!running) return false;
|
||||||
for (String portName : serialPortList.getPortNames()) {
|
for (String portName : serialPortList.getPortNames()) {
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
@@ -184,7 +184,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, BdfList descriptor, long timeout) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package org.briarproject.plugins.tcp;
|
|||||||
|
|
||||||
import org.briarproject.BriarTestCase;
|
import org.briarproject.BriarTestCase;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
@@ -27,11 +27,11 @@ import java.util.concurrent.Callable;
|
|||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.FutureTask;
|
import java.util.concurrent.FutureTask;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
@@ -193,18 +193,15 @@ public class LanTcpPluginTest extends BriarTestCase {
|
|||||||
FutureTask<KeyAgreementConnection> f = new FutureTask<>(c);
|
FutureTask<KeyAgreementConnection> f = new FutureTask<>(c);
|
||||||
new Thread(f).start();
|
new Thread(f).start();
|
||||||
// The plugin should have bound a socket and stored the port number
|
// The plugin should have bound a socket and stored the port number
|
||||||
TransportDescriptor d = kal.getDescriptor();
|
BdfList descriptor = kal.getDescriptor();
|
||||||
TransportProperties p = d.getProperties();
|
assertEquals(3, descriptor.size());
|
||||||
String ipPort = p.get("ipPort");
|
assertEquals(TRANSPORT_ID_LAN, descriptor.getLong(0).longValue());
|
||||||
assertNotNull(ipPort);
|
byte[] address = descriptor.getRaw(1);
|
||||||
String[] split = ipPort.split(":");
|
InetAddress addr = InetAddress.getByAddress(address);
|
||||||
assertEquals(2, split.length);
|
|
||||||
String addrString = split[0], portString = split[1];
|
|
||||||
InetAddress addr = InetAddress.getByName(addrString);
|
|
||||||
assertTrue(addr instanceof Inet4Address);
|
assertTrue(addr instanceof Inet4Address);
|
||||||
assertFalse(addr.isLoopbackAddress());
|
assertFalse(addr.isLoopbackAddress());
|
||||||
assertTrue(addr.isLinkLocalAddress() || addr.isSiteLocalAddress());
|
assertTrue(addr.isLinkLocalAddress() || addr.isSiteLocalAddress());
|
||||||
int port = Integer.parseInt(portString);
|
int port = descriptor.getLong(2).intValue();
|
||||||
assertTrue(port > 0 && port < 65536);
|
assertTrue(port > 0 && port < 65536);
|
||||||
// The plugin should be listening on the port
|
// The plugin should be listening on the port
|
||||||
InetSocketAddress socketAddr = new InetSocketAddress(addr, port);
|
InetSocketAddress socketAddr = new InetSocketAddress(addr, port);
|
||||||
@@ -240,7 +237,6 @@ public class LanTcpPluginTest extends BriarTestCase {
|
|||||||
// Listen on the same interface as the plugin
|
// Listen on the same interface as the plugin
|
||||||
final ServerSocket ss = new ServerSocket();
|
final ServerSocket ss = new ServerSocket();
|
||||||
ss.bind(new InetSocketAddress(addrString, 0), 10);
|
ss.bind(new InetSocketAddress(addrString, 0), 10);
|
||||||
int port = ss.getLocalPort();
|
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
final AtomicBoolean error = new AtomicBoolean(false);
|
final AtomicBoolean error = new AtomicBoolean(false);
|
||||||
new Thread() {
|
new Thread() {
|
||||||
@@ -255,12 +251,15 @@ public class LanTcpPluginTest extends BriarTestCase {
|
|||||||
}
|
}
|
||||||
}.start();
|
}.start();
|
||||||
// Tell the plugin about the port
|
// Tell the plugin about the port
|
||||||
TransportProperties p = new TransportProperties();
|
BdfList descriptor = new BdfList();
|
||||||
p.put("ipPort", addrString + ":" + port);
|
descriptor.add(TRANSPORT_ID_LAN);
|
||||||
TransportDescriptor desc = new TransportDescriptor(plugin.getId(), p);
|
InetSocketAddress local =
|
||||||
|
(InetSocketAddress) ss.getLocalSocketAddress();
|
||||||
|
descriptor.add(local.getAddress().getAddress());
|
||||||
|
descriptor.add(local.getPort());
|
||||||
// Connect to the port
|
// Connect to the port
|
||||||
DuplexTransportConnection d =
|
DuplexTransportConnection d =
|
||||||
plugin.createKeyAgreementConnection(null, desc, 5000);
|
plugin.createKeyAgreementConnection(null, descriptor, 5000);
|
||||||
assertNotNull(d);
|
assertNotNull(d);
|
||||||
// Check that the connection was accepted
|
// Check that the connection was accepted
|
||||||
assertTrue(latch.await(5, SECONDS));
|
assertTrue(latch.await(5, SECONDS));
|
||||||
@@ -291,61 +290,76 @@ public class LanTcpPluginTest extends BriarTestCase {
|
|||||||
private final CountDownLatch connectionsLatch = new CountDownLatch(1);
|
private final CountDownLatch connectionsLatch = new CountDownLatch(1);
|
||||||
private final TransportProperties local = new TransportProperties();
|
private final TransportProperties local = new TransportProperties();
|
||||||
|
|
||||||
|
@Override
|
||||||
public Settings getSettings() {
|
public Settings getSettings() {
|
||||||
return new Settings();
|
return new Settings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public TransportProperties getLocalProperties() {
|
public TransportProperties getLocalProperties() {
|
||||||
return local;
|
return local;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Map<ContactId, TransportProperties> getRemoteProperties() {
|
public Map<ContactId, TransportProperties> getRemoteProperties() {
|
||||||
return remote;
|
return remote;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void mergeSettings(Settings s) {
|
public void mergeSettings(Settings s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void mergeLocalProperties(TransportProperties p) {
|
public void mergeLocalProperties(TransportProperties p) {
|
||||||
local.putAll(p);
|
local.putAll(p);
|
||||||
propertiesLatch.countDown();
|
propertiesLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int showChoice(String[] options, String... message) {
|
public int showChoice(String[] options, String... message) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean showConfirmationMessage(String... message) {
|
public boolean showConfirmationMessage(String... message) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void showMessage(String... message) {
|
public void showMessage(String... message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void incomingConnectionCreated(DuplexTransportConnection d) {
|
public void incomingConnectionCreated(DuplexTransportConnection d) {
|
||||||
connectionsLatch.countDown();
|
connectionsLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void outgoingConnectionCreated(ContactId c,
|
public void outgoingConnectionCreated(ContactId c,
|
||||||
DuplexTransportConnection d) {
|
DuplexTransportConnection d) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void transportEnabled() {
|
public void transportEnabled() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void transportDisabled() {
|
public void transportDisabled() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TestBackoff implements Backoff {
|
private static class TestBackoff implements Backoff {
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getPollingInterval() {
|
public int getPollingInterval() {
|
||||||
return 60 * 1000;
|
return 60 * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void increment() {
|
public void increment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void reset() {
|
public void reset() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,4 +173,55 @@ public class StringUtilsTest extends BriarTestCase {
|
|||||||
public void testTruncateUtf8EmptyInput() {
|
public void testTruncateUtf8EmptyInput() {
|
||||||
assertEquals("", StringUtils.truncateUtf8("", 123));
|
assertEquals("", StringUtils.truncateUtf8("", 123));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testMacToBytesRejectsShortMac() {
|
||||||
|
StringUtils.macToBytes("00:00:00:00:00");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testMacToBytesRejectsLongMac() {
|
||||||
|
StringUtils.macToBytes("00:00:00:00:00:00:00");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testMacToBytesRejectsInvalidCharacter() {
|
||||||
|
StringUtils.macToBytes("00:00:00:00:00:0g");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testMacToBytesRejectsInvalidFormat() {
|
||||||
|
StringUtils.macToBytes("0:000:00:00:00:00");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMacToBytesUpperCase() {
|
||||||
|
byte[] expected = new byte[] {0x0A, 0x1B, 0x2C, 0x3D, 0x4E, 0x5F};
|
||||||
|
String mac = "0A:1B:2C:3D:4E:5F";
|
||||||
|
assertArrayEquals(expected, StringUtils.macToBytes(mac));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMacToBytesLowerCase() {
|
||||||
|
byte[] expected = new byte[] {0x0A, 0x1B, 0x2C, 0x3D, 0x4E, 0x5F};
|
||||||
|
String mac = "0a:1b:2c:3d:4e:5f";
|
||||||
|
assertArrayEquals(expected, StringUtils.macToBytes(mac));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testMacToStringRejectsShortMac() {
|
||||||
|
StringUtils.macToString(new byte[5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testMacToStringRejectsLongMac() {
|
||||||
|
StringUtils.macToString(new byte[7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMacToString() {
|
||||||
|
byte[] mac = new byte[] {0x0a, 0x1b, 0x2c, 0x3d, 0x4e, 0x5f};
|
||||||
|
String expected = "0A:1B:2C:3D:4E:5F";
|
||||||
|
assertEquals(expected, StringUtils.macToString(mac));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user