diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/KeyTransferClientInteractor.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/KeyTransferClientInteractor.java index 69bf29e0b..48b652204 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/KeyTransferClientInteractor.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/KeyTransferClientInteractor.java @@ -22,19 +22,19 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.InetAddress; -import java.net.NetworkInterface; import java.net.Socket; import java.net.SocketTimeoutException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; -import java.util.Collections; -import java.util.List; +import java.util.Arrays; import android.net.PskKeyManager; +import android.net.Uri; import android.os.Build.VERSION_CODES; import android.os.Handler; import android.os.Looper; import android.support.annotation.RequiresApi; +import android.util.Base64; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; @@ -42,7 +42,6 @@ import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLServerSocket; -import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.Log; @@ -50,9 +49,8 @@ import org.sufficientlysecure.keychain.util.Log; @RequiresApi(api = VERSION_CODES.LOLLIPOP) public class KeyTransferClientInteractor { - private static final int SHOW_CONNECTION_DETAILS = 1; private static final int CONNECTION_ESTABLISHED = 2; - public static final int CONNECTION_LOST = 3; + private static final int CONNECTION_LOST = 3; private Thread socketThread; @@ -64,6 +62,11 @@ public class KeyTransferClientInteractor { public void connectToServer(final String connectionDetails, KeyTransferClientCallback callback) { this.callback = callback; + Uri uri = Uri.parse(connectionDetails); + final byte[] presharedKey = Base64.decode(uri.getUserInfo(), Base64.URL_SAFE | Base64.NO_PADDING); + final String host = uri.getHost(); + final int port = uri.getPort(); + handler = new Handler(Looper.getMainLooper()); socketThread = new Thread() { @Override @@ -72,13 +75,10 @@ public class KeyTransferClientInteractor { Socket socket = null; BufferedReader bufferedReader = null; try { - int port = 1336; - - PKM pskKeyManager = new PKM(); - SSLContext sslContext = null; - sslContext = SSLContext.getInstance("TLS"); + PKM pskKeyManager = new PKM(presharedKey); + SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(new KeyManager[] { pskKeyManager }, new TrustManager[0], null); - socket = sslContext.getSocketFactory().createSocket(InetAddress.getByName(connectionDetails), port); + socket = sslContext.getSocketFactory().createSocket(InetAddress.getByName(host), port); invokeListener(CONNECTION_ESTABLISHED, socket.getInetAddress().toString()); @@ -169,14 +169,20 @@ public class KeyTransferClientInteractor { } private static class PKM extends PskKeyManager implements KeyManager { + byte[] presharedKey; + + private PKM(byte[] presharedKey) { + this.presharedKey = presharedKey; + } + @Override public SecretKey getKey(String identityHint, String identity, Socket socket) { - return new SecretKeySpec("swag".getBytes(), "AES"); + return new SecretKeySpec(presharedKey, "AES"); } @Override public SecretKey getKey(String identityHint, String identity, SSLEngine engine) { - return new SecretKeySpec("swag".getBytes(), "AES"); + return new SecretKeySpec(presharedKey, "AES"); } } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/KeyTransferServerInteractor.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/KeyTransferServerInteractor.java index e0d27ffff..73fb5e536 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/KeyTransferServerInteractor.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/KeyTransferServerInteractor.java @@ -27,6 +27,8 @@ import java.net.Socket; import java.net.SocketTimeoutException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -35,6 +37,7 @@ import android.os.Build.VERSION_CODES; import android.os.Handler; import android.os.Looper; import android.support.annotation.RequiresApi; +import android.util.Base64; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; @@ -72,16 +75,20 @@ public class KeyTransferServerInteractor { try { int port = 1336; - PKM pskKeyManager = new PKM(); + byte[] presharedKey = generatePresharedKey(); + PKM pskKeyManager = new PKM(presharedKey); + SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(new KeyManager[] { pskKeyManager }, new TrustManager[0], null); serverSocket = (SSLServerSocket) sslContext.getServerSocketFactory().createServerSocket(port); - String qrCodeData = getIPAddress(true) + ":" + port + ":" + "swag"; + String presharedKeyEncoded = Base64.encodeToString(presharedKey, Base64.URL_SAFE | Base64.NO_PADDING); + String qrCodeData = presharedKeyEncoded + "@" + getIPAddress(true) + ":" + port; invokeListener(SHOW_CONNECTION_DETAILS, qrCodeData); socket = serverSocket.accept(); invokeListener(CONNECTION_ESTABLISHED, socket.getInetAddress().toString()); + Arrays.fill(presharedKey, (byte) 0); socket.setSoTimeout(500); bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); @@ -130,6 +137,12 @@ public class KeyTransferServerInteractor { socketThread.start(); } + public byte[] generatePresharedKey() { + byte[] presharedKey = new byte[16]; + new SecureRandom().nextBytes(presharedKey); + return presharedKey; + } + public void stopServer() { if (socketThread != null) { socketThread.interrupt(); @@ -156,6 +169,9 @@ public class KeyTransferServerInteractor { Runnable runnable = new Runnable() { @Override public void run() { + if (callback == null) { + return; + } switch (method) { case SHOW_CONNECTION_DETAILS: callback.onServerStarted(arg); @@ -216,14 +232,20 @@ public class KeyTransferServerInteractor { } private static class PKM extends PskKeyManager implements KeyManager { + byte[] presharedKey; + + private PKM(byte[] presharedKey) { + this.presharedKey = presharedKey; + } + @Override public SecretKey getKey(String identityHint, String identity, Socket socket) { - return new SecretKeySpec("swag".getBytes(), "AES"); + return new SecretKeySpec(presharedKey, "AES"); } @Override public SecretKey getKey(String identityHint, String identity, SSLEngine engine) { - return new SecretKeySpec("swag".getBytes(), "AES"); + return new SecretKeySpec(presharedKey, "AES"); } } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/transfer/presenter/TransferPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/transfer/presenter/TransferPresenter.java index b9d981c0a..f211bd7ec 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/transfer/presenter/TransferPresenter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/transfer/presenter/TransferPresenter.java @@ -51,8 +51,12 @@ public class TransferPresenter implements KeyTransferServerCallback, KeyTransfer public void onClickScan() { clearConnections(); + view.scanQrCode(); + } + + public void onQrCodeScanned(String qrCodeContent) { keyTransferClientInteractor = new KeyTransferClientInteractor(); - keyTransferClientInteractor.connectToServer("10.100.40.126", this); + keyTransferClientInteractor.connectToServer(qrCodeContent, this); } private void clearConnections() { @@ -73,7 +77,7 @@ public class TransferPresenter implements KeyTransferServerCallback, KeyTransfer @Override public void onServerStarted(String qrCodeData) { - Bitmap qrCodeBitmap = QrCodeUtils.getQRCodeBitmap(Uri.parse("pgp+transfer:" + qrCodeData), 0); + Bitmap qrCodeBitmap = QrCodeUtils.getQRCodeBitmap(Uri.parse("pgp+transfer://" + qrCodeData)); view.setQrImage(qrCodeBitmap); } @@ -93,5 +97,7 @@ public class TransferPresenter implements KeyTransferServerCallback, KeyTransfer void showWaitingForConnection(); void setQrImage(Bitmap qrCode); + + void scanQrCode(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/transfer/view/TransferFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/transfer/view/TransferFragment.java index 874eefd98..322df19a8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/transfer/view/TransferFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/transfer/view/TransferFragment.java @@ -18,6 +18,8 @@ package org.sufficientlysecure.keychain.ui.transfer.view; +import android.app.Activity; +import android.content.Intent; import android.graphics.Bitmap; import android.os.Build.VERSION_CODES; import android.os.Bundle; @@ -33,7 +35,9 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.ViewAnimator; +import com.google.zxing.client.android.Intents; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.QrCodeCaptureActivity; import org.sufficientlysecure.keychain.ui.transfer.presenter.TransferPresenter; import org.sufficientlysecure.keychain.ui.transfer.presenter.TransferPresenter.TransferMvpView; @@ -42,10 +46,10 @@ import org.sufficientlysecure.keychain.ui.transfer.presenter.TransferPresenter.T public class TransferFragment extends Fragment implements TransferMvpView { public static final int VIEW_WAITING = 0; public static final int VIEW_CONNECTED = 1; + public static final int REQUEST_CODE_SCAN = 1; private ImageView vQrCodeImage; - private View vScanButton; private TransferPresenter presenter; private ViewAnimator vTransferAnimator; private TextView vConnectionStatusText; @@ -60,8 +64,8 @@ public class TransferFragment extends Fragment implements TransferMvpView { vConnectionStatusText = (TextView) view.findViewById(R.id.connection_status); vQrCodeImage = (ImageView) view.findViewById(R.id.qr_code_image); - vScanButton = view.findViewById(R.id.button_scan); - vScanButton.setOnClickListener(new OnClickListener() { + + view.findViewById(R.id.button_scan).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (presenter != null) { @@ -121,4 +125,24 @@ public class TransferFragment extends Fragment implements TransferMvpView { }); vQrCodeImage.requestLayout(); } + + @Override + public void scanQrCode() { + Intent intent = new Intent(getActivity(), QrCodeCaptureActivity.class); + startActivityForResult(intent, REQUEST_CODE_SCAN); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case REQUEST_CODE_SCAN: + if (resultCode == Activity.RESULT_OK) { + String qrCodeData = data.getStringExtra(Intents.Scan.RESULT); + presenter.onQrCodeScanned(qrCodeData); + } + break; + default: + super.onActivityResult(requestCode, resultCode, data); + } + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/QrCodeUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/QrCodeUtils.java index a6394a3fb..dad6fe2c2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/QrCodeUtils.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/QrCodeUtils.java @@ -41,6 +41,10 @@ import java.util.Locale; */ public class QrCodeUtils { + public static Bitmap getQRCodeBitmap(final Uri uri) { + return getQRCodeBitmap(uri.toString(), 0); + } + public static Bitmap getQRCodeBitmap(final Uri uri, final int size) { // for URIs we want alphanumeric encoding to save space, thus make everything upper case! // zxing will then select Mode.ALPHANUMERIC internally