diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteSecurityProblemDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteSecurityProblemDialogActivity.java
index b03c693b5..2426e572e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteSecurityProblemDialogActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteSecurityProblemDialogActivity.java
@@ -18,10 +18,228 @@
package org.sufficientlysecure.keychain.remote.ui;
+import java.io.Serializable;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.StringRes;
+import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.remote.ui.SecurityProblemPresenter.RemoteSecurityProblemView;
+import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
+import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
+import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
public class RemoteSecurityProblemDialogActivity extends FragmentActivity {
public static final String EXTRA_PACKAGE_NAME = "package_name";
public static final String EXTRA_SECURITY_PROBLEM = "security_problem";
+
+
+ private SecurityProblemPresenter presenter;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ this.presenter = new SecurityProblemPresenter(getBaseContext());
+
+ if (savedInstanceState == null) {
+ RemoteRegisterDialogFragment frag = new RemoteRegisterDialogFragment();
+ frag.show(getSupportFragmentManager(), "requestKeyDialog");
+ }
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ Intent intent = getIntent();
+ String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
+ Serializable keySecurityProblem = intent.getSerializableExtra(EXTRA_SECURITY_PROBLEM);
+
+ presenter.setupFromIntentData(packageName, keySecurityProblem);
+ }
+
+ public static class RemoteRegisterDialogFragment extends DialogFragment {
+ private SecurityProblemPresenter presenter;
+ private RemoteSecurityProblemView mvpView;
+
+ private Button buttonGotIt;
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Activity activity = getActivity();
+
+ ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity);
+ CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme);
+
+ @SuppressLint("InflateParams")
+ View view = LayoutInflater.from(theme).inflate(R.layout.remote_security_issue_dialog, null, false);
+ alert.setView(view);
+
+ buttonGotIt = (Button) view.findViewById(R.id.button_allow);
+
+ setupListenersForPresenter();
+ mvpView = createMvpView(view);
+
+ return alert.create();
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ presenter = ((RemoteSecurityProblemDialogActivity) getActivity()).presenter;
+ presenter.setView(mvpView);
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ super.onCancel(dialog);
+
+ if (presenter != null) {
+ presenter.onCancel();
+ }
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+
+ if (presenter != null) {
+ presenter.setView(null);
+ presenter = null;
+ }
+ }
+
+ @NonNull
+ private RemoteSecurityProblemView createMvpView(View view) {
+ final LinearLayout insecureWarningLayout = (LinearLayout) view.findViewById(R.id.insecure_warning_layout);
+ final ImageView iconClientApp = (ImageView) view.findViewById(R.id.icon_client_app);
+ final TextView explanationText = (TextView) insecureWarningLayout.findViewById(R.id.dialog_insecure_text);
+ final TextView recommendText = (TextView) insecureWarningLayout.findViewById(R.id.dialog_insecure_recommend_text);
+ final View recommendLayout = insecureWarningLayout.findViewById(R.id.dialog_insecure_recommend_layout);
+
+ return new RemoteSecurityProblemView() {
+ @Override
+ public void finishAsCancelled() {
+ FragmentActivity activity = getActivity();
+ if (activity == null) {
+ return;
+ }
+
+ activity.setResult(RESULT_CANCELED);
+ activity.finish();
+ }
+
+ @Override
+ public void setTitleClientIcon(Drawable drawable) {
+ iconClientApp.setImageDrawable(drawable);
+ }
+
+ /* specialized layouts, for later?
+ private void inflateWarningContentLayout(int dialog_insecure_mdc) {
+ insecureWarningLayout.removeAllViews();
+ getLayoutInflater(null).inflate(dialog_insecure_mdc, insecureWarningLayout);
+ }
+ */
+
+ private void showGeneric(@StringRes int explanationStringRes) {
+ explanationText.setText(explanationStringRes);
+ recommendLayout.setVisibility(View.GONE);
+ }
+
+ private void showGenericWithRecommendation(
+ @StringRes int explanationStringRes, @StringRes int recommendationStringRes) {
+ explanationText.setText(explanationStringRes);
+ recommendText.setText(recommendationStringRes);
+ recommendLayout.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void showLayoutMissingMdc() {
+ showGenericWithRecommendation(R.string.insecure_msg_mdc, R.string.insecure_recom_mdc);
+ }
+
+ @Override
+ public void showLayoutInsecureSymmetric(int symmetricAlgorithm) {
+ showGeneric(R.string.insecure_msg_unidentified_key);
+ }
+
+ @Override
+ public void showLayoutInsecureHashAlgorithm(int hashAlgorithm) {
+ showGeneric(R.string.insecure_msg_unidentified_key);
+ }
+
+ @Override
+ public void showLayoutEncryptInsecureBitsize(int algorithmId, int bitStrength) {
+ String algorithmName = KeyFormattingUtils.getAlgorithmInfo(algorithmId, null, null);
+ explanationText.setText(
+ getString(R.string.insecure_msg_bitstrength, algorithmName,
+ Integer.toString(bitStrength), "2010"));
+ recommendText.setText(R.string.insecure_recom_new_key);
+ recommendText.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void showLayoutSignInsecureBitsize(int algorithmId, int bitStrength) {
+ String algorithmName = KeyFormattingUtils.getAlgorithmInfo(algorithmId, null, null);
+ explanationText.setText(
+ getString(R.string.insecure_msg_bitstrength, algorithmName,
+ Integer.toString(bitStrength), "2010"));
+ recommendText.setText(R.string.insecure_recom_new_key);
+ recommendText.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void showLayoutEncryptNotWhitelistedCurve(String curveOid) {
+ showGeneric(R.string.insecure_msg_not_whitelisted_curve);
+ }
+
+ @Override
+ public void showLayoutSignNotWhitelistedCurve(String curveOid) {
+ showGeneric(R.string.insecure_msg_not_whitelisted_curve);
+ }
+
+ @Override
+ public void showLayoutEncryptUnidentifiedKeyProblem() {
+ showGeneric(R.string.insecure_msg_unidentified_key);
+ }
+
+ @Override
+ public void showLayoutSignUnidentifiedKeyProblem() {
+ showGeneric(R.string.insecure_msg_unidentified_key);
+ }
+ };
+ }
+
+ private void setupListenersForPresenter() {
+ buttonGotIt.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ presenter.onClickGotIt();
+ }
+ });
+ }
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/SecurityProblemPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/SecurityProblemPresenter.java
new file mode 100644
index 000000000..bbc5786a5
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/SecurityProblemPresenter.java
@@ -0,0 +1,140 @@
+package org.sufficientlysecure.keychain.remote.ui;
+
+
+import java.io.Serializable;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.drawable.Drawable;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.pgp.SecurityProblem.InsecureBitStrength;
+import org.sufficientlysecure.keychain.pgp.SecurityProblem.InsecureHashAlgorithm;
+import org.sufficientlysecure.keychain.pgp.SecurityProblem.InsecureSymmetricAlgorithm;
+import org.sufficientlysecure.keychain.pgp.SecurityProblem.KeySecurityProblem;
+import org.sufficientlysecure.keychain.pgp.SecurityProblem.MissingMdc;
+import org.sufficientlysecure.keychain.pgp.SecurityProblem.NotWhitelistedCurve;
+import org.sufficientlysecure.keychain.pgp.SecurityProblem.SymmetricAlgorithmProblem;
+import org.sufficientlysecure.keychain.pgp.SecurityProblem.UnidentifiedKeyProblem;
+import org.sufficientlysecure.keychain.pgp.SecurityProblem.UsageType;
+import org.sufficientlysecure.keychain.util.Log;
+
+
+class SecurityProblemPresenter {
+ private final PackageManager packageManager;
+
+
+ private RemoteSecurityProblemView view;
+
+
+ SecurityProblemPresenter(Context context) {
+ packageManager = context.getPackageManager();
+ }
+
+ public void setView(RemoteSecurityProblemView view) {
+ this.view = view;
+ }
+
+ void setupFromIntentData(String packageName, Serializable securityProblem) {
+
+ if (securityProblem instanceof KeySecurityProblem) {
+// setupFromKeySecurityProblem((KeySecurityProblem) securityProblem);
+ } else if (securityProblem instanceof SymmetricAlgorithmProblem) {
+ setupFromNonKeySecurityProblem((SymmetricAlgorithmProblem) securityProblem);
+ } else if (securityProblem instanceof InsecureHashAlgorithm) {
+ setupFromInsecureHashAlgorithm((InsecureHashAlgorithm) securityProblem);
+ } else {
+ throw new IllegalArgumentException("Unhandled security problem type!");
+ }
+
+ try {
+ setPackageInfo(packageName);
+ } catch (NameNotFoundException e) {
+ throw new IllegalStateException("Unable to find info of calling app!", e);
+ }
+ }
+
+ /*
+ private void setupFromKeySecurityProblem(KeySecurityProblem keySecurityProblem) {
+ if (keySecurityProblem instanceof InsecureBitStrength) {
+ InsecureBitStrength problem = (InsecureBitStrength) keySecurityProblem;
+ if (problem.usageType == UsageType.ENCRYPT) {
+ view.showLayoutEncryptInsecureBitsize(problem.algorithm, problem.bitStrength);
+ } else if (problem.usageType == UsageType.SIGN) {
+ view.showLayoutSignInsecureBitsize(problem.algorithm, problem.bitStrength);
+ } else {
+ throw new IllegalStateException("Should never happen here!");
+ }
+ } else if (keySecurityProblem instanceof NotWhitelistedCurve) {
+ NotWhitelistedCurve problem = (NotWhitelistedCurve) keySecurityProblem;
+ if (problem.usageType == UsageType.ENCRYPT) {
+ view.showLayoutEncryptNotWhitelistedCurve(problem.curveOid);
+ } else if (problem.usageType == UsageType.SIGN) {
+ view.showLayoutSignNotWhitelistedCurve(problem.curveOid);
+ } else {
+ throw new IllegalStateException("Should never happen here!");
+ }
+ } else if (keySecurityProblem instanceof UnidentifiedKeyProblem) {
+ if (keySecurityProblem.usageType == UsageType.ENCRYPT) {
+ view.showLayoutEncryptUnidentifiedKeyProblem();
+ } else if (keySecurityProblem.usageType == UsageType.SIGN) {
+ view.showLayoutSignUnidentifiedKeyProblem();
+ } else {
+ throw new IllegalStateException("Should never happen here!");
+ }
+ } else {
+ throw new IllegalArgumentException("Unhandled key security problem type!");
+ }
+ }
+ */
+
+ private void setupFromNonKeySecurityProblem(SymmetricAlgorithmProblem securityProblem) {
+ if (securityProblem instanceof MissingMdc) {
+ view.showLayoutMissingMdc();
+ } else if (securityProblem instanceof InsecureSymmetricAlgorithm) {
+ InsecureSymmetricAlgorithm insecureSymmetricAlgorithm = (InsecureSymmetricAlgorithm) securityProblem;
+ view.showLayoutInsecureSymmetric(insecureSymmetricAlgorithm.symmetricAlgorithm);
+ } else {
+ throw new IllegalArgumentException("Unhandled symmetric algorithm problem type!");
+ }
+ }
+
+ private void setupFromInsecureHashAlgorithm(InsecureHashAlgorithm securityProblem) {
+ view.showLayoutInsecureHashAlgorithm(securityProblem.hashAlgorithm);
+ }
+
+ private void setPackageInfo(String packageName) throws NameNotFoundException {
+ ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 0);
+ Drawable appIcon = packageManager.getApplicationIcon(applicationInfo);
+ // CharSequence appName = packageManager.getApplicationLabel(applicationInfo);
+
+ view.setTitleClientIcon(appIcon);
+ }
+
+ void onClickGotIt() {
+ view.finishAsCancelled();
+ }
+
+ void onCancel() {
+ view.finishAsCancelled();
+ }
+
+ interface RemoteSecurityProblemView {
+ void finishAsCancelled();
+ void setTitleClientIcon(Drawable drawable);
+
+ void showLayoutEncryptInsecureBitsize(int algorithmId, int bitStrength);
+ void showLayoutEncryptNotWhitelistedCurve(String curveOid);
+ void showLayoutEncryptUnidentifiedKeyProblem();
+ void showLayoutSignInsecureBitsize(int algorithmId, int bitStrength);
+ void showLayoutSignNotWhitelistedCurve(String curveOid);
+ void showLayoutSignUnidentifiedKeyProblem();
+
+ void showLayoutMissingMdc();
+ void showLayoutInsecureSymmetric(int symmetricAlgorithm);
+
+ void showLayoutInsecureHashAlgorithm(int hashAlgorithm);
+ }
+}
diff --git a/OpenKeychain/src/main/res/layout/dialog_insecure_bitsize.xml b/OpenKeychain/src/main/res/layout/dialog_insecure_bitsize.xml
new file mode 100644
index 000000000..e913e04ab
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/dialog_insecure_bitsize.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OpenKeychain/src/main/res/layout/dialog_insecure_generic.xml b/OpenKeychain/src/main/res/layout/dialog_insecure_generic.xml
new file mode 100644
index 000000000..a9d9400f4
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/dialog_insecure_generic.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OpenKeychain/src/main/res/layout/remote_security_issue_dialog.xml b/OpenKeychain/src/main/res/layout/remote_security_issue_dialog.xml
new file mode 100644
index 000000000..1eeef98c8
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/remote_security_issue_dialog.xml
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index a112bc9b4..4299ad096 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -1853,4 +1853,12 @@
"This key expired on %1$s."
+ Security Warning
+ Recommended Action
+ "The key this message was sent from is using an outdated algorithm, that is no longer considered secure!\n\nThe algorithm in use is %1$s with %2$s bitstrength, which has been considered insecure since %3$s."
+ The key in use is insecure, and cannot be updated. To communicate securely, the sender must create a new key!
+ "This "
+ "The key used to "
+ The sender of this message should update their OpenPGP software.
+ This message was encrypted with an insecure encryption mechanism. The encrypted message did not include a Modification Detection Code (MDC), which is necessary to ensure message integrity.