2
0
mirror of https://github.com/KDE/kdeconnect-android synced 2025-08-22 09:58:08 +00:00

Remove compat with protocol 6 with RSA encryption

Since we already removed compat with protocol 7 ^.^u
This commit is contained in:
Albert Vaca Cintora 2019-04-17 20:24:50 +02:00
parent 9a8ae36ef6
commit 168b16527c
18 changed files with 64 additions and 292 deletions

View File

@ -26,7 +26,6 @@ import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.NetworkPacket; import org.kde.kdeconnect.NetworkPacket;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList; import java.util.ArrayList;
@ -90,6 +89,4 @@ public abstract class BaseLink {
//TO OVERRIDE, should be sync //TO OVERRIDE, should be sync
public abstract boolean sendPacket(NetworkPacket np, Device.SendPacketStatusCallback callback); public abstract boolean sendPacket(NetworkPacket np, Device.SendPacketStatusCallback callback);
@Deprecated
public abstract boolean sendPacketEncrypted(NetworkPacket np, Device.SendPacketStatusCallback callback, PublicKey key);
} }

View File

@ -32,7 +32,6 @@ import org.json.JSONObject;
import org.kde.kdeconnect.Backends.BaseLink; import org.kde.kdeconnect.Backends.BaseLink;
import org.kde.kdeconnect.Backends.BasePairingHandler; import org.kde.kdeconnect.Backends.BasePairingHandler;
import org.kde.kdeconnect.Device; import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.Helpers.SecurityHelpers.RsaHelper;
import org.kde.kdeconnect.NetworkPacket; import org.kde.kdeconnect.NetworkPacket;
import java.io.IOException; import java.io.IOException;
@ -41,7 +40,6 @@ import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.Reader; import java.io.Reader;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.security.PublicKey;
import java.util.UUID; import java.util.UUID;
public class BluetoothLink extends BaseLink { public class BluetoothLink extends BaseLink {
@ -87,14 +85,6 @@ public class BluetoothLink extends BaseLink {
return; return;
} }
if (np.getType().equals(NetworkPacket.PACKET_TYPE_ENCRYPTED)) {
try {
np = RsaHelper.decrypt(np, privateKey);
} catch (Exception e) {
Log.e("BluetoothLink/receiving", "Exception decrypting the package", e);
}
}
if (np.hasPayloadTransferInfo()) { if (np.hasPayloadTransferInfo()) {
BluetoothSocket transferSocket = null; BluetoothSocket transferSocket = null;
try { try {
@ -158,16 +148,7 @@ public class BluetoothLink extends BaseLink {
} }
@Override @Override
public boolean sendPacket(NetworkPacket np, Device.SendPacketStatusCallback callback) { public boolean sendPacket(NetworkPacket np, final Device.SendPacketStatusCallback callback) {
return sendPacketInternal(np, callback, null);
}
@Override
public boolean sendPacketEncrypted(NetworkPacket np, Device.SendPacketStatusCallback callback, PublicKey key) {
return sendPacketInternal(np, callback, key);
}
private boolean sendPacketInternal(NetworkPacket np, final Device.SendPacketStatusCallback callback, PublicKey key) {
/*if (!isConnected()) { /*if (!isConnected()) {
Log.e("BluetoothLink", "sendPacketEncrypted failed: not connected"); Log.e("BluetoothLink", "sendPacketEncrypted failed: not connected");
@ -186,15 +167,6 @@ public class BluetoothLink extends BaseLink {
np.setPayloadTransferInfo(payloadTransferInfo); np.setPayloadTransferInfo(payloadTransferInfo);
} }
if (key != null) {
try {
np = RsaHelper.encrypt(np, key);
} catch (Exception e) {
callback.onFailure(e);
return false;
}
}
sendMessage(np); sendMessage(np);
if (serverSocket != null) { if (serverSocket != null) {

View File

@ -52,7 +52,7 @@ public class BluetoothPairingHandler extends BasePairingHandler {
} }
@Override @Override
public void packageReceived(NetworkPacket np) throws Exception { public void packageReceived(NetworkPacket np) {
boolean wantsPair = np.getBoolean("pair"); boolean wantsPair = np.getBoolean("pair");

View File

@ -27,7 +27,6 @@ import org.json.JSONObject;
import org.kde.kdeconnect.Backends.BaseLink; import org.kde.kdeconnect.Backends.BaseLink;
import org.kde.kdeconnect.Backends.BasePairingHandler; import org.kde.kdeconnect.Backends.BasePairingHandler;
import org.kde.kdeconnect.Device; import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.Helpers.SecurityHelpers.RsaHelper;
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper; import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
import org.kde.kdeconnect.Helpers.StringsHelper; import org.kde.kdeconnect.Helpers.StringsHelper;
import org.kde.kdeconnect.NetworkPacket; import org.kde.kdeconnect.NetworkPacket;
@ -42,7 +41,6 @@ import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.nio.channels.NotYetConnectedException; import java.nio.channels.NotYetConnectedException;
import java.security.PublicKey;
import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocket;
@ -61,7 +59,7 @@ public class LanLink extends BaseLink {
// because it's probably trying to find me and // because it's probably trying to find me and
// potentially ask for pairing. // potentially ask for pairing.
private volatile Socket socket = null; private volatile SSLSocket socket = null;
private final LinkDisconnectedCallback callback; private final LinkDisconnectedCallback callback;
@ -76,9 +74,9 @@ public class LanLink extends BaseLink {
} }
//Returns the old socket //Returns the old socket
public Socket reset(final Socket newSocket, ConnectionStarted connectionSource) throws IOException { public SSLSocket reset(final SSLSocket newSocket, ConnectionStarted connectionSource) throws IOException {
Socket oldSocket = socket; SSLSocket oldSocket = socket;
socket = newSocket; socket = newSocket;
this.connectionSource = connectionSource; this.connectionSource = connectionSource;
@ -121,7 +119,7 @@ public class LanLink extends BaseLink {
return oldSocket; return oldSocket;
} }
public LanLink(Context context, String deviceId, LanLinkProvider linkProvider, Socket socket, ConnectionStarted connectionSource) throws IOException { public LanLink(Context context, String deviceId, LanLinkProvider linkProvider, SSLSocket socket, ConnectionStarted connectionSource) throws IOException {
super(context, deviceId, linkProvider); super(context, deviceId, linkProvider);
callback = linkProvider; callback = linkProvider;
reset(socket, connectionSource); reset(socket, connectionSource);
@ -139,7 +137,8 @@ public class LanLink extends BaseLink {
} }
//Blocking, do not call from main thread //Blocking, do not call from main thread
private boolean sendPacketInternal(NetworkPacket np, final Device.SendPacketStatusCallback callback, PublicKey key) { @Override
public boolean sendPacket(NetworkPacket np, final Device.SendPacketStatusCallback callback) {
if (socket == null) { if (socket == null) {
Log.e("KDE/sendPacket", "Not yet connected"); Log.e("KDE/sendPacket", "Not yet connected");
callback.onFailure(new NotYetConnectedException()); callback.onFailure(new NotYetConnectedException());
@ -159,11 +158,6 @@ public class LanLink extends BaseLink {
server = null; server = null;
} }
//Encrypt if key provided
if (key != null) {
np = RsaHelper.encrypt(np, key);
}
//Log.e("LanLink/sendPacket", np.getType()); //Log.e("LanLink/sendPacket", np.getType());
//Send body of the network package //Send body of the network package
@ -188,9 +182,7 @@ public class LanLink extends BaseLink {
payloadSocket = server.accept(); payloadSocket = server.accept();
//Convert to SSL if needed //Convert to SSL if needed
if (socket instanceof SSLSocket) { payloadSocket = SslHelper.convertToSslSocket(context, payloadSocket, getDeviceId(), true, false);
payloadSocket = SslHelper.convertToSslSocket(context, payloadSocket, getDeviceId(), true, false);
}
outputStream = payloadSocket.getOutputStream(); outputStream = payloadSocket.getOutputStream();
inputStream = np.getPayload().getInputStream(); inputStream = np.getPayload().getInputStream();
@ -240,39 +232,15 @@ public class LanLink extends BaseLink {
} }
} }
//Blocking, do not call from main thread
@Override
public boolean sendPacket(NetworkPacket np, Device.SendPacketStatusCallback callback) {
return sendPacketInternal(np, callback, null);
}
//Blocking, do not call from main thread
@Override
public boolean sendPacketEncrypted(NetworkPacket np, Device.SendPacketStatusCallback callback, PublicKey key) {
return sendPacketInternal(np, callback, key);
}
private void receivedNetworkPacket(NetworkPacket np) { private void receivedNetworkPacket(NetworkPacket np) {
if (np.getType().equals(NetworkPacket.PACKET_TYPE_ENCRYPTED)) {
try {
np = RsaHelper.decrypt(np, privateKey);
} catch(Exception e) {
Log.e("KDE/onPacketReceived","Exception decrypting the package", e);
}
}
if (np.hasPayloadTransferInfo()) { if (np.hasPayloadTransferInfo()) {
Socket payloadSocket = new Socket(); Socket payloadSocket = new Socket();
try { try {
int tcpPort = np.getPayloadTransferInfo().getInt("port"); int tcpPort = np.getPayloadTransferInfo().getInt("port");
InetSocketAddress deviceAddress = (InetSocketAddress) socket.getRemoteSocketAddress(); InetSocketAddress deviceAddress = (InetSocketAddress) socket.getRemoteSocketAddress();
payloadSocket.connect(new InetSocketAddress(deviceAddress.getAddress(), tcpPort)); payloadSocket.connect(new InetSocketAddress(deviceAddress.getAddress(), tcpPort));
// Use ssl if existing link is on ssl payloadSocket = SslHelper.convertToSslSocket(context, payloadSocket, getDeviceId(), true, true);
if (socket instanceof SSLSocket) {
payloadSocket = SslHelper.convertToSslSocket(context, payloadSocket, getDeviceId(), true, true);
}
np.setPayload(new NetworkPacket.Payload(payloadSocket, np.getPayloadSize())); np.setPayload(new NetworkPacket.Payload(payloadSocket, np.getPayloadSize()));
} catch (Exception e) { } catch (Exception e) {
try { payloadSocket.close(); } catch(Exception ignored) { } try { payloadSocket.close(); } catch(Exception ignored) { }

View File

@ -66,9 +66,6 @@ import javax.net.ssl.SSLSocket;
*/ */
public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDisconnectedCallback { public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDisconnectedCallback {
public static final int MIN_VERSION_WITH_SSL_SUPPORT = 6;
private static final int MIN_VERSION_WITH_NEW_PORT_SUPPORT = 7;
private final static int MIN_PORT = 1716; private final static int MIN_PORT = 1716;
private final static int MAX_PORT = 1764; private final static int MAX_PORT = 1764;
final static int PAYLOAD_TRANSFER_MIN_PORT = 1739; final static int PAYLOAD_TRANSFER_MIN_PORT = 1739;
@ -93,7 +90,7 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
} }
//They received my UDP broadcast and are connecting to me. The first thing they sned should be their identity. //They received my UDP broadcast and are connecting to me. The first thing they sned should be their identity.
private void tcpPacketReceived(Socket socket) throws Exception { private void tcpPacketReceived(Socket socket) {
NetworkPacket networkPacket; NetworkPacket networkPacket;
try { try {
@ -116,7 +113,7 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
} }
//I've received their broadcast and should connect to their TCP socket and send my identity. //I've received their broadcast and should connect to their TCP socket and send my identity.
private void udpPacketReceived(DatagramPacket packet) throws Exception { private void udpPacketReceived(DatagramPacket packet) {
final InetAddress address = packet.getAddress(); final InetAddress address = packet.getAddress();
@ -136,11 +133,6 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
} }
} }
if (identityPacket.getInt("protocolVersion") >= MIN_VERSION_WITH_NEW_PORT_SUPPORT && identityPacket.getInt("tcpPort") < MIN_PORT) {
Log.w("KDE/LanLinkProvider", "Ignoring a udp broadcast from legacy port because it comes from a device which knows about the new port.");
return;
}
Log.i("KDE/LanLinkProvider", "Broadcast identity package received from " + identityPacket.getString("deviceName")); Log.i("KDE/LanLinkProvider", "Broadcast identity package received from " + identityPacket.getString("deviceName"));
int tcpPort = identityPacket.getInt("tcpPort", MIN_PORT); int tcpPort = identityPacket.getInt("tcpPort", MIN_PORT);
@ -206,61 +198,56 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
// If I'm the TCP server I will be the SSL client and viceversa. // If I'm the TCP server I will be the SSL client and viceversa.
final boolean clientMode = (connectionStarted == LanLink.ConnectionStarted.Locally); final boolean clientMode = (connectionStarted == LanLink.ConnectionStarted.Locally);
// Add ssl handler if device uses new protocol // Do the SSL handshake
try { try {
if (identityPacket.getInt("protocolVersion") >= MIN_VERSION_WITH_SSL_SUPPORT) { SharedPreferences preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE);
boolean isDeviceTrusted = preferences.getBoolean(deviceId, false);
SharedPreferences preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE); if (isDeviceTrusted && !SslHelper.isCertificateStored(context, deviceId)) {
boolean isDeviceTrusted = preferences.getBoolean(deviceId, false); //Device paired with and old version, we can't use it as we lack the certificate
BackgroundService.RunCommand(context, service -> {
Device device = service.getDevice(deviceId);
if (device == null) return;
device.unpair();
//Retry as unpaired
identityPacketReceived(identityPacket, socket, connectionStarted);
});
}
if (isDeviceTrusted && !SslHelper.isCertificateStored(context, deviceId)) { Log.i("KDE/LanLinkProvider", "Starting SSL handshake with " + identityPacket.getString("deviceName") + " trusted:" + isDeviceTrusted);
//Device paired with and old version, we can't use it as we lack the certificate
final SSLSocket sslsocket = SslHelper.convertToSslSocket(context, socket, deviceId, isDeviceTrusted, clientMode);
sslsocket.addHandshakeCompletedListener(event -> {
String mode = clientMode ? "client" : "server";
try {
Certificate certificate = event.getPeerCertificates()[0];
identityPacket.set("certificate", Base64.encodeToString(certificate.getEncoded(), 0));
Log.i("KDE/LanLinkProvider", "Handshake as " + mode + " successful with " + identityPacket.getString("deviceName") + " secured with " + event.getCipherSuite());
addLink(identityPacket, sslsocket, connectionStarted);
} catch (Exception e) {
Log.e("KDE/LanLinkProvider", "Handshake as " + mode + " failed with " + identityPacket.getString("deviceName"), e);
BackgroundService.RunCommand(context, service -> { BackgroundService.RunCommand(context, service -> {
Device device = service.getDevice(deviceId); Device device = service.getDevice(deviceId);
if (device == null) return; if (device == null) return;
device.unpair(); device.unpair();
//Retry as unpaired
identityPacketReceived(identityPacket, socket, connectionStarted);
}); });
} }
});
Log.i("KDE/LanLinkProvider", "Starting SSL handshake with " + identityPacket.getString("deviceName") + " trusted:" + isDeviceTrusted); //Handshake is blocking, so do it on another thread and free this thread to keep receiving new connection
new Thread(() -> {
final SSLSocket sslsocket = SslHelper.convertToSslSocket(context, socket, deviceId, isDeviceTrusted, clientMode); try {
sslsocket.addHandshakeCompletedListener(event -> { synchronized (this) {
String mode = clientMode ? "client" : "server"; sslsocket.startHandshake();
try {
Certificate certificate = event.getPeerCertificates()[0];
identityPacket.set("certificate", Base64.encodeToString(certificate.getEncoded(), 0));
Log.i("KDE/LanLinkProvider", "Handshake as " + mode + " successful with " + identityPacket.getString("deviceName") + " secured with " + event.getCipherSuite());
addLink(identityPacket, sslsocket, connectionStarted);
} catch (Exception e) {
Log.e("KDE/LanLinkProvider", "Handshake as " + mode + " failed with " + identityPacket.getString("deviceName"), e);
BackgroundService.RunCommand(context, service -> {
Device device = service.getDevice(deviceId);
if (device == null) return;
device.unpair();
});
} }
}); } catch (Exception e) {
//Handshake is blocking, so do it on another thread and free this thread to keep receiving new connection Log.e("KDE/LanLinkProvider", "Handshake failed with " + identityPacket.getString("deviceName"), e);
new Thread(() -> {
try {
synchronized (this) {
sslsocket.startHandshake();
}
} catch (Exception e) {
Log.e("KDE/LanLinkProvider", "Handshake failed with " + identityPacket.getString("deviceName"), e);
//String[] ciphers = sslsocket.getSupportedCipherSuites(); //String[] ciphers = sslsocket.getSupportedCipherSuites();
//for (String cipher : ciphers) { //for (String cipher : ciphers) {
// Log.i("SupportedCiphers","cipher: " + cipher); // Log.i("SupportedCiphers","cipher: " + cipher);
//} //}
} }
}).start(); }).start();
} else {
addLink(identityPacket, socket, connectionStarted);
}
} catch (Exception e) { } catch (Exception e) {
Log.e("LanLink", "Exception", e); Log.e("LanLink", "Exception", e);
} }
@ -280,7 +267,7 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
* @param connectionOrigin which side started this connection * @param connectionOrigin which side started this connection
* @throws IOException if an exception is thrown by {@link LanLink#reset(Socket, LanLink.ConnectionStarted)} * @throws IOException if an exception is thrown by {@link LanLink#reset(Socket, LanLink.ConnectionStarted)}
*/ */
private void addLink(final NetworkPacket identityPacket, Socket socket, LanLink.ConnectionStarted connectionOrigin) throws IOException { private void addLink(final NetworkPacket identityPacket, SSLSocket socket, LanLink.ConnectionStarted connectionOrigin) throws IOException {
String deviceId = identityPacket.getString("deviceId"); String deviceId = identityPacket.getString("deviceId");
LanLink currentLink = visibleComputers.get(deviceId); LanLink currentLink = visibleComputers.get(deviceId);

View File

@ -22,7 +22,6 @@ package org.kde.kdeconnect.Backends.LanBackend;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
@ -31,9 +30,7 @@ import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.NetworkPacket; import org.kde.kdeconnect.NetworkPacket;
import org.kde.kdeconnect_tp.R; import org.kde.kdeconnect_tp.R;
import java.security.KeyFactory;
import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateEncodingException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
@ -54,14 +51,11 @@ public class LanPairingHandler extends BasePairingHandler {
private NetworkPacket createPairPacket() { private NetworkPacket createPairPacket() {
NetworkPacket np = new NetworkPacket(NetworkPacket.PACKET_TYPE_PAIR); NetworkPacket np = new NetworkPacket(NetworkPacket.PACKET_TYPE_PAIR);
np.set("pair", true); np.set("pair", true);
SharedPreferences globalSettings = PreferenceManager.getDefaultSharedPreferences(mDevice.getContext());
String publicKey = "-----BEGIN PUBLIC KEY-----\n" + globalSettings.getString("publicKey", "").trim()+ "\n-----END PUBLIC KEY-----\n";
np.set("publicKey", publicKey);
return np; return np;
} }
@Override @Override
public void packageReceived(NetworkPacket np) throws Exception{ public void packageReceived(NetworkPacket np) {
boolean wantsPair = np.getBoolean("pair"); boolean wantsPair = np.getBoolean("pair");
@ -77,15 +71,6 @@ public class LanPairingHandler extends BasePairingHandler {
if (wantsPair) { if (wantsPair) {
//Retrieve their public key
try {
String publicKeyContent = np.getString("publicKey").replace("-----BEGIN PUBLIC KEY-----\n","").replace("-----END PUBLIC KEY-----\n", "");
byte[] publicKeyBytes = Base64.decode(publicKeyContent, 0);
mDevice.publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKeyBytes));
} catch (Exception e) {
//IGNORE
}
if (mPairStatus == PairStatus.Requested) { //We started pairing if (mPairStatus == PairStatus.Requested) { //We started pairing
hidePairingNotification(); hidePairingNotification();
@ -204,15 +189,6 @@ public class LanPairingHandler extends BasePairingHandler {
//Log.e("KDE/PairingDone", "Pairing Done"); //Log.e("KDE/PairingDone", "Pairing Done");
SharedPreferences.Editor editor = mDevice.getContext().getSharedPreferences(mDevice.getDeviceId(), Context.MODE_PRIVATE).edit(); SharedPreferences.Editor editor = mDevice.getContext().getSharedPreferences(mDevice.getDeviceId(), Context.MODE_PRIVATE).edit();
if (mDevice.publicKey != null) {
try {
String encodedPublicKey = Base64.encodeToString(mDevice.publicKey.getEncoded(), 0);
editor.putString("publicKey", encodedPublicKey);
} catch (Exception e) {
Log.e("KDE/PairingDone", "Error encoding public key", e);
}
}
try { try {
String encodedCertificate = Base64.encodeToString(mDevice.certificate.getEncoded(), 0); String encodedCertificate = Base64.encodeToString(mDevice.certificate.getEncoded(), 0);
editor.putString("certificate", encodedCertificate); editor.putString("certificate", encodedCertificate);

View File

@ -28,8 +28,6 @@ import org.kde.kdeconnect.Backends.BasePairingHandler;
import org.kde.kdeconnect.Device; import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.NetworkPacket; import org.kde.kdeconnect.NetworkPacket;
import java.security.PublicKey;
public class LoopbackLink extends BaseLink { public class LoopbackLink extends BaseLink {
public LoopbackLink(Context context, BaseLinkProvider linkProvider) { public LoopbackLink(Context context, BaseLinkProvider linkProvider) {
@ -58,8 +56,4 @@ public class LoopbackLink extends BaseLink {
return true; return true;
} }
@Override
public boolean sendPacketEncrypted(NetworkPacket np, Device.SendPacketStatusCallback callback, PublicKey key) {
return sendPacket(np, callback);
}
} }

View File

@ -33,7 +33,7 @@ public class LoopbackPairingHandler extends BasePairingHandler {
} }
@Override @Override
public void packageReceived(NetworkPacket np) throws Exception { public void packageReceived(NetworkPacket np) {
} }

View File

@ -35,7 +35,6 @@ import android.util.Log;
import org.kde.kdeconnect.Backends.BaseLink; import org.kde.kdeconnect.Backends.BaseLink;
import org.kde.kdeconnect.Backends.BasePairingHandler; import org.kde.kdeconnect.Backends.BasePairingHandler;
import org.kde.kdeconnect.Backends.LanBackend.LanLinkProvider;
import org.kde.kdeconnect.Helpers.NotificationHelper; import org.kde.kdeconnect.Helpers.NotificationHelper;
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper; import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
import org.kde.kdeconnect.Plugins.Plugin; import org.kde.kdeconnect.Plugins.Plugin;
@ -45,10 +44,8 @@ import org.kde.kdeconnect_tp.R;
import java.security.KeyFactory; import java.security.KeyFactory;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
@ -68,7 +65,6 @@ public class Device implements BaseLink.PacketReceiver {
private final String deviceId; private final String deviceId;
private String name; private String name;
public PublicKey publicKey;
public Certificate certificate; public Certificate certificate;
private int notificationId; private int notificationId;
private int protocolVersion; private int protocolVersion;
@ -150,16 +146,6 @@ public class Device implements BaseLink.PacketReceiver {
this.protocolVersion = NetworkPacket.ProtocolVersion; //We don't know it yet this.protocolVersion = NetworkPacket.ProtocolVersion; //We don't know it yet
this.deviceType = DeviceType.FromString(settings.getString("deviceType", "desktop")); this.deviceType = DeviceType.FromString(settings.getString("deviceType", "desktop"));
try {
String publicKeyStr = settings.getString("publicKey", null);
if (publicKeyStr != null) {
byte[] publicKeyBytes = Base64.decode(publicKeyStr, 0);
publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKeyBytes));
}
} catch (Exception e) {
Log.e("KDE/Device", "Exception deserializing stored public key for device", e);
}
//Assume every plugin is supported until addLink is called and we can get the actual list //Assume every plugin is supported until addLink is called and we can get the actual list
m_supportedPlugins = new Vector<>(PluginFactory.getAvailablePlugins()); m_supportedPlugins = new Vector<>(PluginFactory.getAvailablePlugins());
@ -178,7 +164,6 @@ public class Device implements BaseLink.PacketReceiver {
this.pairStatus = PairStatus.NotPaired; this.pairStatus = PairStatus.NotPaired;
this.protocolVersion = 0; this.protocolVersion = 0;
this.deviceType = DeviceType.Computer; this.deviceType = DeviceType.Computer;
this.publicKey = null;
settings = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE); settings = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE);
@ -546,8 +531,6 @@ public class Device implements BaseLink.PacketReceiver {
@Override @Override
public void onPacketReceived(NetworkPacket np) { public void onPacketReceived(NetworkPacket np) {
hackToMakeRetrocompatiblePacketTypes(np);
if (NetworkPacket.PACKET_TYPE_PAIR.equals(np.getType())) { if (NetworkPacket.PACKET_TYPE_PAIR.equals(np.getType())) {
Log.i("KDE/Device", "Pair package"); Log.i("KDE/Device", "Pair package");
@ -651,20 +634,12 @@ public class Device implements BaseLink.PacketReceiver {
} }
*/ */
hackToMakeRetrocompatiblePacketTypes(np);
boolean useEncryption = (protocolVersion < LanLinkProvider.MIN_VERSION_WITH_SSL_SUPPORT && (!np.getType().equals(NetworkPacket.PACKET_TYPE_PAIR) && isPaired()));
boolean success = false; boolean success = false;
//Make a copy to avoid concurrent modification exception if the original list changes //Make a copy to avoid concurrent modification exception if the original list changes
for (final BaseLink link : links) { for (final BaseLink link : links) {
if (link == null) if (link == null)
continue; //Since we made a copy, maybe somebody destroyed the link in the meanwhile continue; //Since we made a copy, maybe somebody destroyed the link in the meanwhile
if (useEncryption) { success = link.sendPacket(np, callback);
success = link.sendPacketEncrypted(np, callback, publicKey);
} else {
success = link.sendPacket(np, callback);
}
if (success) break; //If the link didn't call sendSuccess(), try the next one if (success) break; //If the link didn't call sendSuccess(), try the next one
} }
@ -796,7 +771,6 @@ public class Device implements BaseLink.PacketReceiver {
boolean success = addPlugin(pluginKey); boolean success = addPlugin(pluginKey);
if (success) { if (success) {
for (String packageType : pluginInfo.getSupportedPacketTypes()) { for (String packageType : pluginInfo.getSupportedPacketTypes()) {
packageType = hackToMakeRetrocompatiblePacketTypes(packageType);
ArrayList<String> plugins = newPluginsByIncomingInterface.get(packageType); ArrayList<String> plugins = newPluginsByIncomingInterface.get(packageType);
if (plugins == null) plugins = new ArrayList<>(); if (plugins == null) plugins = new ArrayList<>();
plugins.add(pluginKey); plugins.add(pluginKey);
@ -866,14 +840,4 @@ public class Device implements BaseLink.PacketReceiver {
return m_supportedPlugins; return m_supportedPlugins;
} }
private void hackToMakeRetrocompatiblePacketTypes(NetworkPacket np) {
if (protocolVersion >= 6) return;
np.mType = np.getType().replace(".request", "");
}
private String hackToMakeRetrocompatiblePacketTypes(String type) {
if (protocolVersion >= 6) return type;
return type.replace(".request", "");
}
} }

View File

@ -26,11 +26,6 @@ import android.preference.PreferenceManager;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.kde.kdeconnect.NetworkPacket;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.KeyFactory; import java.security.KeyFactory;
import java.security.KeyPair; import java.security.KeyPair;
@ -40,8 +35,6 @@ import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec; import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
public class RsaHelper { public class RsaHelper {
public static void initialiseRsaKeys(Context context) { public static void initialiseRsaKeys(Context context) {
@ -77,67 +70,12 @@ public class RsaHelper {
return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKeyBytes)); return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKeyBytes));
} }
public static PublicKey getPublicKey(Context context, String deviceId) throws GeneralSecurityException {
SharedPreferences settings = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE);
byte[] publicKeyBytes = Base64.decode(settings.getString("publicKey", ""), 0);
return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKeyBytes));
}
public static PrivateKey getPrivateKey(Context context) throws GeneralSecurityException { public static PrivateKey getPrivateKey(Context context) throws GeneralSecurityException {
SharedPreferences globalSettings = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences globalSettings = PreferenceManager.getDefaultSharedPreferences(context);
byte[] privateKeyBytes = Base64.decode(globalSettings.getString("privateKey", ""), 0); byte[] privateKeyBytes = Base64.decode(globalSettings.getString("privateKey", ""), 0);
return KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes)); return KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
} }
public static NetworkPacket encrypt(NetworkPacket np, PublicKey publicKey) throws GeneralSecurityException, JSONException {
String serialized = np.serialize();
int chunkSize = 128;
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
JSONArray chunks = new JSONArray();
while (serialized.length() > 0) {
if (serialized.length() < chunkSize) {
chunkSize = serialized.length();
}
String chunk = serialized.substring(0, chunkSize);
serialized = serialized.substring(chunkSize);
byte[] chunkBytes = chunk.getBytes(Charset.defaultCharset());
byte[] encryptedChunk;
encryptedChunk = cipher.doFinal(chunkBytes);
chunks.put(Base64.encodeToString(encryptedChunk, Base64.NO_WRAP));
}
//Log.i("NetworkPacket", "Encrypted " + chunks.length()+" chunks");
NetworkPacket encrypted = new NetworkPacket(NetworkPacket.PACKET_TYPE_ENCRYPTED);
encrypted.set("data", chunks);
encrypted.setPayload(np.getPayload());
return encrypted;
}
public static NetworkPacket decrypt(NetworkPacket np, PrivateKey privateKey) throws GeneralSecurityException, JSONException {
JSONArray chunks = np.getJSONArray("data");
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
StringBuilder decryptedJson = new StringBuilder();
for (int i = 0; i < chunks.length(); i++) {
byte[] encryptedChunk = Base64.decode(chunks.getString(i), Base64.NO_WRAP);
String decryptedChunk = new String(cipher.doFinal(encryptedChunk));
decryptedJson.append(decryptedChunk);
}
NetworkPacket decrypted = NetworkPacket.unserialize(decryptedJson.toString());
decrypted.setPayload(np.getPayload());
return decrypted;
}
} }

View File

@ -65,11 +65,6 @@ import javax.net.ssl.X509TrustManager;
public class SslHelper { public class SslHelper {
public enum SslMode {
Client,
Server
}
public static X509Certificate certificate; //my device's certificate public static X509Certificate certificate; //my device's certificate
public static final BouncyCastleProvider BC = new BouncyCastleProvider(); public static final BouncyCastleProvider BC = new BouncyCastleProvider();

View File

@ -44,12 +44,10 @@ public class NetworkPacket {
public final static String PACKET_TYPE_IDENTITY = "kdeconnect.identity"; public final static String PACKET_TYPE_IDENTITY = "kdeconnect.identity";
public final static String PACKET_TYPE_PAIR = "kdeconnect.pair"; public final static String PACKET_TYPE_PAIR = "kdeconnect.pair";
public final static String PACKET_TYPE_ENCRYPTED = "kdeconnect.encrypted";
public static Set<String> protocolPacketTypes = new HashSet<String>() {{ public static Set<String> protocolPacketTypes = new HashSet<String>() {{
add(PACKET_TYPE_IDENTITY); add(PACKET_TYPE_IDENTITY);
add(PACKET_TYPE_PAIR); add(PACKET_TYPE_PAIR);
add(PACKET_TYPE_ENCRYPTED);
}}; }};
private long mId; private long mId;

View File

@ -25,7 +25,6 @@ import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.widget.Button;
import org.kde.kdeconnect.Device; import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.NetworkPacket; import org.kde.kdeconnect.NetworkPacket;
@ -185,21 +184,6 @@ public abstract class Plugin {
*/ */
public abstract String[] getOutgoingPacketTypes(); public abstract String[] getOutgoingPacketTypes();
/**
* Creates a button that will be displayed in the user interface
* It can open an activity or perform any other action that the
* plugin would wants to expose to the user. Return null if no
* button should be displayed.
*/
@Deprecated
public Button getInterfaceButton(final Activity activity) {
if (!hasMainActivity()) return null;
Button b = new Button(activity);
b.setText(getActionName());
b.setOnClickListener(view -> startMainActivity(activity));
return b;
}
protected String[] getRequiredPermissions() { protected String[] getRequiredPermissions() {
return new String[0]; return new String[0];
} }

View File

@ -310,7 +310,7 @@ public class AndroidSafSshFile implements SshFile {
} }
@Override @Override
public Map<Attribute, Object> getAttributes(boolean followLinks) throws IOException { public Map<Attribute, Object> getAttributes(boolean followLinks) {
Map<SshFile.Attribute, Object> attributes = new HashMap<>(); Map<SshFile.Attribute, Object> attributes = new HashMap<>();
for (SshFile.Attribute attr : SshFile.Attribute.values()) { for (SshFile.Attribute attr : SshFile.Attribute.values()) {
switch (attr) { switch (attr) {

View File

@ -53,7 +53,7 @@ class RootFile implements SshFile {
return "/"; return "/";
} }
public Map<Attribute, Object> getAttributes(boolean followLinks) throws IOException { public Map<Attribute, Object> getAttributes(boolean followLinks) {
Map<Attribute, Object> attrs = new HashMap<>(); Map<Attribute, Object> attrs = new HashMap<>();
attrs.put(Attribute.Size, 0); attrs.put(Attribute.Size, 0);

View File

@ -95,11 +95,8 @@ class SimpleSftpServer {
sshd.setCommandFactory(new ScpCommandFactory()); sshd.setCommandFactory(new ScpCommandFactory());
sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystem.Factory())); sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystem.Factory()));
if (device.publicKey != null) { keyAuth.deviceKey = device.certificate.getPublicKey();
keyAuth.deviceKey = device.publicKey;
} else {
keyAuth.deviceKey = device.certificate.getPublicKey();
}
sshd.setPublickeyAuthenticator(keyAuth); sshd.setPublickeyAuthenticator(keyAuth);
sshd.setPasswordAuthenticator(passwordAuth); sshd.setPasswordAuthenticator(passwordAuth);
} }

View File

@ -195,7 +195,7 @@ public class DeviceTest {
} }
@Test @Test
public void testPairingDoneWithCertificate() throws Exception { public void testPairingDoneWithCertificate() {
KeyPair keyPair = null; KeyPair keyPair = null;
try { try {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");

View File

@ -43,6 +43,8 @@ import java.io.OutputStream;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import javax.net.ssl.SSLSocket;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@RunWith(PowerMockRunner.class) @RunWith(PowerMockRunner.class)
@ -71,11 +73,11 @@ public class LanLinkTest {
Mockito.doThrow(new IOException("AAA")).when(badOutputStream).write(Mockito.any(byte[].class)); Mockito.doThrow(new IOException("AAA")).when(badOutputStream).write(Mockito.any(byte[].class));
Socket socketMock = Mockito.mock(Socket.class); SSLSocket socketMock = Mockito.mock(SSLSocket.class);
Mockito.when(socketMock.getRemoteSocketAddress()).thenReturn(new InetSocketAddress(5000)); Mockito.when(socketMock.getRemoteSocketAddress()).thenReturn(new InetSocketAddress(5000));
Mockito.when(socketMock.getOutputStream()).thenReturn(goodOutputStream); Mockito.when(socketMock.getOutputStream()).thenReturn(goodOutputStream);
Socket socketBadMock = Mockito.mock(Socket.class); SSLSocket socketBadMock = Mockito.mock(SSLSocket.class);
Mockito.when(socketBadMock.getRemoteSocketAddress()).thenReturn(new InetSocketAddress(5000)); Mockito.when(socketBadMock.getRemoteSocketAddress()).thenReturn(new InetSocketAddress(5000));
Mockito.when(socketBadMock.getOutputStream()).thenReturn(badOutputStream); Mockito.when(socketBadMock.getOutputStream()).thenReturn(badOutputStream);