2
0
mirror of https://github.com/KDE/kdeconnect-android synced 2025-08-29 13:17:43 +00:00

Moved cryptography layer down from Device to Backend

Matching KDED structure
This commit is contained in:
Albert Vaca 2013-09-16 17:36:26 +02:00
parent 63f0458096
commit e735e0ecf3
11 changed files with 177 additions and 120 deletions

View File

@ -1,17 +1,26 @@
package org.kde.kdeconnect.Backends;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Base64;
import org.kde.kdeconnect.NetworkPackage;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
public abstract class BaseComputerLink {
public abstract class BaseLink {
private BaseLinkProvider linkProvider;
private String deviceId;
private ArrayList<PackageReceiver> receivers = new ArrayList<PackageReceiver>();
protected PrivateKey privateKey;
protected BaseComputerLink(String deviceId, BaseLinkProvider linkProvider) {
protected BaseLink(String deviceId, BaseLinkProvider linkProvider) {
this.linkProvider = linkProvider;
this.deviceId = deviceId;
}
@ -20,6 +29,10 @@ public abstract class BaseComputerLink {
return deviceId;
}
public void setPrivateKey(PrivateKey key) {
privateKey = key;
}
public BaseLinkProvider getLinkProvider() {
return linkProvider;
}
@ -45,5 +58,6 @@ public abstract class BaseComputerLink {
//TO OVERRIDE
public abstract boolean sendPackage(NetworkPackage np);
public abstract boolean sendPackageEncrypted(NetworkPackage np, PublicKey key);
}

View File

@ -2,7 +2,6 @@ package org.kde.kdeconnect.Backends;
import android.util.Log;
import org.kde.kdeconnect.Backends.BaseComputerLink;
import org.kde.kdeconnect.NetworkPackage;
import java.util.ArrayList;
@ -12,8 +11,8 @@ public abstract class BaseLinkProvider {
private ArrayList<ConnectionReceiver> connectionReceivers = new ArrayList<ConnectionReceiver>();
public interface ConnectionReceiver {
public void onConnectionReceived(NetworkPackage identityPackage, BaseComputerLink link);
public void onConnectionLost(BaseComputerLink link);
public void onConnectionReceived(NetworkPackage identityPackage, BaseLink link);
public void onConnectionLost(BaseLink link);
}
public void addConnectionReceiver(ConnectionReceiver cr) {
@ -25,13 +24,13 @@ public abstract class BaseLinkProvider {
}
//These two should be called when the provider links to a new computer
protected void connectionAccepted(NetworkPackage identityPackage, BaseComputerLink link) {
protected void connectionAccepted(NetworkPackage identityPackage, BaseLink link) {
Log.i("LinkProvider", "connectionAccepted");
for(ConnectionReceiver cr : connectionReceivers) {
cr.onConnectionReceived(identityPackage, link);
}
}
protected void connectionLost(BaseComputerLink link) {
protected void connectionLost(BaseLink link) {
Log.i("LinkProvider", "connectionLost");
for(ConnectionReceiver cr : connectionReceivers) {
cr.onConnectionLost(link);

View File

@ -1,38 +0,0 @@
package org.kde.kdeconnect.Backends.LanBackend;
import android.util.Log;
import org.apache.mina.core.session.IoSession;
import org.kde.kdeconnect.Backends.BaseComputerLink;
import org.kde.kdeconnect.Backends.BaseLinkProvider;
import org.kde.kdeconnect.NetworkPackage;
public class LanComputerLink extends BaseComputerLink {
private IoSession session = null;
public void disconnect() {
Log.i("LanComputerLink","Disconnect: "+session.getRemoteAddress().toString());
session.close(true);
}
public LanComputerLink(IoSession session, String deviceId, BaseLinkProvider linkProvider) {
super(deviceId, linkProvider);
this.session = session;
}
@Override
public boolean sendPackage(NetworkPackage np) {
if (session == null) {
Log.e("LanComputerLink","sendPackage failed: not yet connected");
return false;
} else {
session.write(np.serialize());
return true;
}
}
public void injectNetworkPackage(NetworkPackage np) {
packageReceived(np);
}
}

View File

@ -0,0 +1,70 @@
package org.kde.kdeconnect.Backends.LanBackend;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Base64;
import android.util.Log;
import org.apache.mina.core.session.IoSession;
import org.kde.kdeconnect.Backends.BaseLink;
import org.kde.kdeconnect.Backends.BaseLinkProvider;
import org.kde.kdeconnect.NetworkPackage;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
public class LanLink extends BaseLink {
private IoSession session = null;
public void disconnect() {
Log.i("LanLink","Disconnect: "+session.getRemoteAddress().toString());
session.close(true);
}
public LanLink(IoSession session, String deviceId, BaseLinkProvider linkProvider) {
super(deviceId, linkProvider);
this.session = session;
}
@Override
public boolean sendPackage(NetworkPackage np) {
if (session == null) {
Log.e("LanLink","sendPackage failed: not yet connected");
return false;
} else {
session.write(np.serialize());
return true;
}
}
@Override
public boolean sendPackageEncrypted(NetworkPackage np, PublicKey key) {
try {
np.encrypt(key);
return sendPackage(np);
} catch (Exception e) {
e.printStackTrace();
Log.e("LanLink", "Encryption exception");
}
return false;
}
public void injectNetworkPackage(NetworkPackage np) {
if (np.getType().equals(NetworkPackage.PACKAGE_TYPE_ENCRYPTED)) {
try {
np = np.decrypt(privateKey);
} catch(Exception e) {
e.printStackTrace();
Log.e("onPackageReceived","Exception reading the key needed to decrypt the package");
}
}
packageReceived(np);
}
}

View File

@ -31,8 +31,8 @@ public class LanLinkProvider extends BaseLinkProvider {
private final static int port = 1714;
private Context context;
private HashMap<String, LanComputerLink> visibleComputers = new HashMap<String, LanComputerLink>();
private HashMap<Long, LanComputerLink> nioSessions = new HashMap<Long, LanComputerLink>();
private HashMap<String, LanLink> visibleComputers = new HashMap<String, LanLink>();
private HashMap<Long, LanLink> nioSessions = new HashMap<Long, LanLink>();
private NioSocketAcceptor tcpAcceptor = null;
private NioDatagramAcceptor udpAcceptor = null;
@ -41,7 +41,7 @@ public class LanLinkProvider extends BaseLinkProvider {
@Override
public void sessionClosed(IoSession session) throws Exception {
LanComputerLink brokenLink = nioSessions.remove(session.getId());
LanLink brokenLink = nioSessions.remove(session.getId());
if (brokenLink != null) {
connectionLost(brokenLink);
brokenLink.disconnect();
@ -62,14 +62,14 @@ public class LanLinkProvider extends BaseLinkProvider {
String theMessage = (String) message;
NetworkPackage np = NetworkPackage.unserialize(theMessage);
LanComputerLink prevLink = nioSessions.get(session.getId());
LanLink prevLink = nioSessions.get(session.getId());
if (np.getType().equals(NetworkPackage.PACKAGE_TYPE_IDENTITY)) {
String myId = NetworkPackage.createIdentityPackage(context).getString("deviceId");
if (np.getString("deviceId").equals(myId)) {
return;
}
LanComputerLink link = new LanComputerLink(session, np.getString("deviceId"), LanLinkProvider.this);
LanLink link = new LanLink(session, np.getString("deviceId"), LanLinkProvider.this);
nioSessions.put(session.getId(),link);
addLink(np, link);
} else {
@ -138,7 +138,7 @@ public class LanLinkProvider extends BaseLinkProvider {
Log.i("LanLinkProvider", "Connection successful: " + session.isConnected());
LanComputerLink link = new LanComputerLink(session, identityPackage.getString("deviceId"), LanLinkProvider.this);
LanLink link = new LanLink(session, identityPackage.getString("deviceId"), LanLinkProvider.this);
NetworkPackage np2 = NetworkPackage.createIdentityPackage(context);
link.sendPackage(np2);
@ -157,10 +157,10 @@ public class LanLinkProvider extends BaseLinkProvider {
}
};
private void addLink(NetworkPackage identityPackage, LanComputerLink link) {
private void addLink(NetworkPackage identityPackage, LanLink link) {
String deviceId = identityPackage.getString("deviceId");
Log.i("LanLinkProvider","addLink to "+deviceId);
LanComputerLink oldLink = visibleComputers.get(deviceId);
LanLink oldLink = visibleComputers.get(deviceId);
visibleComputers.put(deviceId, link);
connectionAccepted(identityPackage, link);
if (oldLink != null) {

View File

@ -1,21 +0,0 @@
package org.kde.kdeconnect.Backends.LoopbackBackend;
import org.kde.kdeconnect.Backends.BaseComputerLink;
import org.kde.kdeconnect.Backends.BaseLinkProvider;
import org.kde.kdeconnect.NetworkPackage;
public class LoopbackComputerLink extends BaseComputerLink {
public LoopbackComputerLink(BaseLinkProvider linkProvider) {
super("loopback", linkProvider);
}
@Override
public boolean sendPackage(NetworkPackage in) {
String s = in.serialize();
NetworkPackage out= NetworkPackage.unserialize(s);
packageReceived(out);
return true;
}
}

View File

@ -0,0 +1,41 @@
package org.kde.kdeconnect.Backends.LoopbackBackend;
import android.util.Log;
import org.kde.kdeconnect.Backends.BaseLink;
import org.kde.kdeconnect.Backends.BaseLinkProvider;
import org.kde.kdeconnect.NetworkPackage;
import java.security.PublicKey;
public class LoopbackLink extends BaseLink {
public LoopbackLink(BaseLinkProvider linkProvider) {
super("loopback", linkProvider);
}
@Override
public boolean sendPackage(NetworkPackage in) {
String s = in.serialize();
NetworkPackage out= NetworkPackage.unserialize(s);
packageReceived(out);
return true;
}
@Override
public boolean sendPackageEncrypted(NetworkPackage in, PublicKey key) {
try {
in.encrypt(key);
String s = in.serialize();
NetworkPackage out= NetworkPackage.unserialize(s);
out.decrypt(privateKey);
packageReceived(out);
return true;
} catch(Exception e) {
e.printStackTrace();
Log.e("LoopbackLink", "Encryption exception");
return false;
}
}
}

View File

@ -27,7 +27,7 @@ public class LoopbackLinkProvider extends BaseLinkProvider {
public void onNetworkChange() {
NetworkPackage np = NetworkPackage.createIdentityPackage(context);
connectionAccepted(np, new LoopbackComputerLink(this));
connectionAccepted(np, new LoopbackLink(this));
}

View File

@ -11,7 +11,7 @@ import android.preference.PreferenceManager;
import android.util.Base64;
import android.util.Log;
import org.kde.kdeconnect.Backends.BaseComputerLink;
import org.kde.kdeconnect.Backends.BaseLink;
import org.kde.kdeconnect.Backends.BaseLinkProvider;
import org.kde.kdeconnect.Backends.LanBackend.LanLinkProvider;
import org.kde.kdeconnect.Backends.LoopbackBackend.LoopbackLinkProvider;
@ -81,7 +81,7 @@ public class BackgroundService extends Service {
private BaseLinkProvider.ConnectionReceiver deviceListener = new BaseLinkProvider.ConnectionReceiver() {
@Override
public void onConnectionReceived(final NetworkPackage identityPackage, final BaseComputerLink link) {
public void onConnectionReceived(final NetworkPackage identityPackage, final BaseLink link) {
Log.i("BackgroundService", "Connection accepted!");
@ -104,7 +104,7 @@ public class BackgroundService extends Service {
}
@Override
public void onConnectionLost(BaseComputerLink link) {
public void onConnectionLost(BaseLink link) {
Device d = devices.get(link.getDeviceId());
Log.i("onConnectionLost", "removeLink, deviceId: " + link.getDeviceId());
if (d != null) {

View File

@ -15,7 +15,7 @@ import android.support.v4.app.NotificationCompat;
import android.util.Base64;
import android.util.Log;
import org.kde.kdeconnect.Backends.BaseComputerLink;
import org.kde.kdeconnect.Backends.BaseLink;
import org.kde.kdeconnect.Plugins.Plugin;
import org.kde.kdeconnect.Plugins.PluginFactory;
import org.kde.kdeconnect.UserInterface.PairActivity;
@ -34,7 +34,7 @@ import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
public class Device implements BaseComputerLink.PackageReceiver {
public class Device implements BaseLink.PackageReceiver {
private Context context;
@ -61,7 +61,7 @@ public class Device implements BaseComputerLink.PackageReceiver {
private ArrayList<PairingCallback> pairingCallback = new ArrayList<PairingCallback>();
private Timer pairingTimer;
private ArrayList<BaseComputerLink> links = new ArrayList<BaseComputerLink>();
private ArrayList<BaseLink> links = new ArrayList<BaseLink>();
private HashMap<String, Plugin> plugins = new HashMap<String, Plugin>();
private HashMap<String, Plugin> failedPlugins = new HashMap<String, Plugin>();
@ -90,7 +90,7 @@ public class Device implements BaseComputerLink.PackageReceiver {
}
//Device known via an incoming connection sent to us via a devicelink, we know everything but we don't trust it yet
Device(Context context, String deviceId, String name, BaseComputerLink dl) {
Device(Context context, String deviceId, String name, BaseLink dl) {
settings = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE);
//Log.e("Device","Constructor B");
@ -255,15 +255,25 @@ public class Device implements BaseComputerLink.PackageReceiver {
return !links.isEmpty();
}
public void addLink(BaseComputerLink link) {
public void addLink(BaseLink link) {
links.add(link);
try {
SharedPreferences globalSettings = PreferenceManager.getDefaultSharedPreferences(context);
byte[] privateKeyBytes = Base64.decode(globalSettings.getString("privateKey", ""), 0);
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
link.setPrivateKey(privateKey);
} catch (Exception e) {
e.printStackTrace();
Log.e("Device", "Exception reading our own private key"); //Should not happen
}
Log.i("Device","addLink "+link.getLinkProvider().getName()+" -> "+getName() + " active links: "+ links.size());
Collections.sort(links, new Comparator<BaseComputerLink>() {
Collections.sort(links, new Comparator<BaseLink>() {
@Override
public int compare(BaseComputerLink o, BaseComputerLink o2) {
public int compare(BaseLink o, BaseLink o2) {
return o2.getLinkProvider().getPriority() - o.getLinkProvider().getPriority();
}
});
@ -275,7 +285,7 @@ public class Device implements BaseComputerLink.PackageReceiver {
}
}
public void removeLink(BaseComputerLink link) {
public void removeLink(BaseLink link) {
link.removePackageReceiver(this);
links.remove(link);
Log.i("Device","removeLink: "+link.getLinkProvider().getName() + " -> "+getName() + " active links: "+ links.size());
@ -398,23 +408,6 @@ public class Device implements BaseComputerLink.PackageReceiver {
Log.e("onPackageReceived","Device not paired, ignoring package!");
} else {
if (np.getType().equals(NetworkPackage.PACKAGE_TYPE_ENCRYPTED)) {
try {
//TODO: Do not read the key every time
SharedPreferences globalSettings = PreferenceManager.getDefaultSharedPreferences(context);
byte[] privateKeyBytes = Base64.decode(globalSettings.getString("privateKey",""), 0);
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
np = np.decrypt(privateKey);
} catch(Exception e) {
e.printStackTrace();
Log.e("onPackageReceived","Exception reading the key needed to decrypt the package");
}
} else {
//TODO: The other side doesn't know that we are already paired, do something
Log.e("onPackageReceived","WARNING: Received unencrypted package from paired device!");
}
for (Plugin plugin : plugins.values()) {
plugin.onPackageReceived(np);
@ -426,27 +419,26 @@ public class Device implements BaseComputerLink.PackageReceiver {
public boolean sendPackage(final NetworkPackage np) {
if (!np.getType().equals(NetworkPackage.PACKAGE_TYPE_PAIR) && isPaired()) {
try {
np.encrypt(publicKey);
} catch(Exception e) {
e.printStackTrace();
Log.e("Device","sendPackage exception - could not encrypt");
}
}
new AsyncTask<Void,Void,Void>() {
@Override
protected Void doInBackground(Void... voids) {
for(BaseComputerLink link : links) {
//Log.e("sendPackage","Trying "+link.getLinkProvider().getName());
if (link.sendPackage(np)) {
//Log.e("sent using", link.getLinkProvider().getName());
return null;
boolean useEncryption = (!np.getType().equals(NetworkPackage.PACKAGE_TYPE_PAIR) && isPaired());
for(BaseLink link : links) {
if (useEncryption) {
if (link.sendPackageEncrypted(np, publicKey)) return null;
} else {
if (link.sendPackage(np)) return null;
}
}
Log.e("sendPackage","Error: Package could not be sent ("+links.size()+" links available)");
return null;
}
}.execute();

View File

@ -13,8 +13,8 @@ import android.widget.SeekBar;
import android.widget.Spinner;
import android.widget.TextView;
import org.kde.kdeconnect.Backends.BaseLink;
import org.kde.kdeconnect.BackgroundService;
import org.kde.kdeconnect.Backends.BaseComputerLink;
import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.Backends.BaseLinkProvider;
import org.kde.kdeconnect.NetworkPackage;
@ -121,12 +121,12 @@ public class MprisActivity extends Activity {
BaseLinkProvider.ConnectionReceiver connectionReceiver = new BaseLinkProvider.ConnectionReceiver() {
@Override
public void onConnectionReceived(NetworkPackage identityPackage, BaseComputerLink link) {
public void onConnectionReceived(NetworkPackage identityPackage, BaseLink link) {
connectToPlugin();
}
@Override
public void onConnectionLost(BaseComputerLink link) {
public void onConnectionLost(BaseLink link) {
}
};