Introduce constants in OpenPgpSignature and DecryptionResult for unsigned/unencrypted content, update API, introduce simple checks for insecure symmetric algos

This commit is contained in:
Dominik Schürmann
2015-07-25 14:32:47 +02:00
parent dc81e0254c
commit 57378be1c0
19 changed files with 430 additions and 279 deletions

View File

@@ -36,6 +36,7 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.ViewAnimator;
import org.openintents.openpgp.OpenPgpDecryptionResult;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
@@ -208,37 +209,50 @@ public abstract class DecryptFragment extends Fragment implements LoaderManager.
mDecryptVerifyResult = decryptVerifyResult;
mSignatureResult = decryptVerifyResult.getSignatureResult();
OpenPgpDecryptionResult decryptionResult = decryptVerifyResult.getDecryptionResult();
mResultLayout.setVisibility(View.VISIBLE);
// unsigned data
if (mSignatureResult == null) {
switch (decryptionResult.getResult()) {
case OpenPgpDecryptionResult.RESULT_ENCRYPTED: {
mEncryptionText.setText(R.string.decrypt_result_encrypted);
KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, State.ENCRYPTED);
break;
}
case OpenPgpDecryptionResult.RESULT_INSECURE: {
mEncryptionText.setText(R.string.decrypt_result_insecure);
KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, State.INSECURE);
break;
}
default:
case OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED: {
mEncryptionText.setText(R.string.decrypt_result_not_encrypted);
KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, State.NOT_ENCRYPTED);
break;
}
}
if (mSignatureResult.getResult() == OpenPgpSignatureResult.RESULT_NO_SIGNATURE) {
// no signature
setSignatureLayoutVisibility(View.GONE);
mSignatureText.setText(R.string.decrypt_result_no_signature);
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.NOT_SIGNED);
mEncryptionText.setText(R.string.decrypt_result_encrypted);
KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, State.ENCRYPTED);
getLoaderManager().destroyLoader(LOADER_ID_UNIFIED);
showErrorOverlay(false);
onVerifyLoaded(true);
return;
}
if (mSignatureResult.isSignatureOnly()) {
mEncryptionText.setText(R.string.decrypt_result_not_encrypted);
KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, State.NOT_ENCRYPTED);
} else {
mEncryptionText.setText(R.string.decrypt_result_encrypted);
KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, State.ENCRYPTED);
}
// signature present
getLoaderManager().restartLoader(LOADER_ID_UNIFIED, null, this);
// after loader is restarted signature results are checked
getLoaderManager().restartLoader(LOADER_ID_UNIFIED, null, this);
}
}
private void setSignatureLayoutVisibility(int visibility) {
@@ -313,8 +327,9 @@ public abstract class DecryptFragment extends Fragment implements LoaderManager.
// NOTE: Don't use revoked and expired fields from database, they don't show
// revoked/expired subkeys
boolean isRevoked = mSignatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED;
boolean isExpired = mSignatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED;
boolean isRevoked = mSignatureResult.getResult() == OpenPgpSignatureResult.RESULT_INVALID_KEY_REVOKED;
boolean isExpired = mSignatureResult.getResult() == OpenPgpSignatureResult.RESULT_INVALID_KEY_EXPIRED;
boolean isInsecure = mSignatureResult.getResult() == OpenPgpSignatureResult.RESULT_INVALID_INSECURE;
boolean isVerified = data.getInt(INDEX_VERIFIED) > 0;
boolean isYours = data.getInt(INDEX_HAS_ANY_SECRET) != 0;
@@ -338,6 +353,17 @@ public abstract class DecryptFragment extends Fragment implements LoaderManager.
onVerifyLoaded(true);
} else if (isInsecure) {
mSignatureText.setText(R.string.decrypt_result_insecure_cryptography);
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.INSECURE);
setSignatureLayoutVisibility(View.VISIBLE);
setShowAction(signatureKeyId);
showErrorOverlay(false);
onVerifyLoaded(true);
} else if (isYours) {
mSignatureText.setText(R.string.decrypt_result_signature_secret);
@@ -389,9 +415,9 @@ public abstract class DecryptFragment extends Fragment implements LoaderManager.
final long signatureKeyId = mSignatureResult.getKeyId();
int result = mSignatureResult.getStatus();
if (result != OpenPgpSignatureResult.SIGNATURE_KEY_MISSING
&& result != OpenPgpSignatureResult.SIGNATURE_ERROR) {
int result = mSignatureResult.getResult();
if (result != OpenPgpSignatureResult.RESULT_KEY_MISSING
&& result != OpenPgpSignatureResult.RESULT_INVALID_SIGNATURE) {
Log.e(Constants.TAG, "got missing status for non-missing key, shouldn't happen!");
}
@@ -409,9 +435,9 @@ public abstract class DecryptFragment extends Fragment implements LoaderManager.
getActivity(), mSignatureResult.getKeyId()));
}
switch (mSignatureResult.getStatus()) {
switch (mSignatureResult.getResult()) {
case OpenPgpSignatureResult.SIGNATURE_KEY_MISSING: {
case OpenPgpSignatureResult.RESULT_KEY_MISSING: {
mSignatureText.setText(R.string.decrypt_result_signature_missing_key);
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.UNKNOWN_KEY);
@@ -433,7 +459,7 @@ public abstract class DecryptFragment extends Fragment implements LoaderManager.
break;
}
case OpenPgpSignatureResult.SIGNATURE_ERROR: {
case OpenPgpSignatureResult.RESULT_INVALID_SIGNATURE: {
mSignatureText.setText(R.string.decrypt_result_invalid_signature);
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.INVALID);

View File

@@ -321,11 +321,11 @@ public class DecryptListFragment
protected Drawable doInBackground(Void... params) {
Context context = getActivity();
if (result.getDecryptMetadata() == null || context == null) {
if (result.getDecryptionMetadata() == null || context == null) {
return null;
}
String type = result.getDecryptMetadata().getMimeType();
String type = result.getDecryptionMetadata().getMimeType();
Uri outputUri = mOutputUris.get(uri);
if (type == null || outputUri == null) {
return null;
@@ -368,7 +368,7 @@ public class DecryptListFragment
OpenPgpSignatureResult sigResult = result.getSignatureResult();
if (sigResult != null) {
final long keyId = sigResult.getKeyId();
if (sigResult.getStatus() != OpenPgpSignatureResult.SIGNATURE_KEY_MISSING) {
if (sigResult.getResult() != OpenPgpSignatureResult.RESULT_KEY_MISSING) {
onKeyClick = new OnClickListener() {
@Override
public void onClick(View view) {
@@ -384,7 +384,7 @@ public class DecryptListFragment
}
}
if (result.success() && result.getDecryptMetadata() != null) {
if (result.success() && result.getDecryptionMetadata() != null) {
onFileClick = new OnClickListener() {
@Override
public void onClick(View view) {
@@ -425,7 +425,7 @@ public class DecryptListFragment
return;
}
final OpenPgpMetadata metadata = result.getDecryptMetadata();
final OpenPgpMetadata metadata = result.getDecryptionMetadata();
// text/plain is a special case where we extract the uri content into
// the EXTRA_TEXT extra ourselves, and display a chooser which includes
@@ -529,7 +529,7 @@ public class DecryptListFragment
activity.startActivity(intent);
return true;
case R.id.decrypt_save:
OpenPgpMetadata metadata = result.getDecryptMetadata();
OpenPgpMetadata metadata = result.getDecryptionMetadata();
if (metadata == null) {
return true;
}
@@ -724,7 +724,7 @@ public class DecryptListFragment
KeyFormattingUtils.setStatus(mContext, holder, model.mResult);
final OpenPgpMetadata metadata = model.mResult.getDecryptMetadata();
final OpenPgpMetadata metadata = model.mResult.getDecryptionMetadata();
String filename;
if (metadata == null) {

View File

@@ -553,14 +553,18 @@ public class EncryptFilesFragment
data.addInputUris(mFilesAdapter.getAsArrayList());
if (mUseCompression) {
data.setCompressionId(PgpConstants.sPreferredCompressionAlgorithms.get(0));
data.setCompressionAlgorithm(
PgpConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT);
} else {
data.setCompressionId(CompressionAlgorithmTags.UNCOMPRESSED);
data.setCompressionAlgorithm(
PgpConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED);
}
data.setHiddenRecipients(mHiddenRecipients);
data.setEnableAsciiArmorOutput(mAfterEncryptAction == AfterEncryptAction.COPY || mUseArmor);
data.setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED);
data.setSignatureHashAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED);
data.setSymmetricEncryptionAlgorithm(
PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT);
data.setSignatureHashAlgorithm(
PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT);
EncryptActivity encryptActivity = (EncryptActivity) getActivity();
EncryptModeFragment modeFragment = encryptActivity.getModeFragment();

View File

@@ -223,15 +223,17 @@ public class EncryptTextFragment
data.setCleartextSignature(true);
if (mUseCompression) {
data.setCompressionId(PgpConstants.sPreferredCompressionAlgorithms.get(0));
data.setCompressionAlgorithm(
PgpConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT);
} else {
data.setCompressionId(CompressionAlgorithmTags.UNCOMPRESSED);
data.setCompressionAlgorithm(
PgpConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED);
}
data.setHiddenRecipients(mHiddenRecipients);
data.setSymmetricEncryptionAlgorithm(
PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED);
PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT);
data.setSignatureHashAlgorithm(
PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED);
PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT);
// Always use armor for messages
data.setEnableAsciiArmorOutput(true);

View File

@@ -28,6 +28,7 @@ import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import org.openintents.openpgp.OpenPgpDecryptionResult;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.spongycastle.asn1.ASN1ObjectIdentifier;
import org.spongycastle.asn1.nist.NISTNamedCurves;
@@ -40,7 +41,6 @@ import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve;
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.util.Log;
import java.nio.ByteBuffer;
@@ -408,7 +408,8 @@ public class KeyFormattingUtils {
UNVERIFIED,
UNKNOWN_KEY,
INVALID,
NOT_SIGNED
NOT_SIGNED,
INSECURE
}
public static void setStatusImage(Context context, ImageView statusIcon, State state) {
@@ -443,18 +444,33 @@ public class KeyFormattingUtils {
@SuppressWarnings("deprecation") // context.getDrawable is api lvl 21, need to use deprecated
public static void setStatus(Context context, StatusHolder holder, DecryptVerifyResult result) {
OpenPgpSignatureResult signatureResult = result.getSignatureResult();
if (holder.hasEncrypt()) {
OpenPgpDecryptionResult decryptionResult = result.getDecryptionResult();
int encText, encIcon, encColor;
if (signatureResult != null && signatureResult.isSignatureOnly()) {
encIcon = R.drawable.status_lock_open_24dp;
encText = R.string.decrypt_result_not_encrypted;
encColor = R.color.key_flag_red;
} else {
encIcon = R.drawable.status_lock_closed_24dp;
encText = R.string.decrypt_result_encrypted;
encColor = R.color.key_flag_green;
switch (decryptionResult.getResult()) {
case OpenPgpDecryptionResult.RESULT_ENCRYPTED: {
encText = R.string.decrypt_result_encrypted;
encIcon = R.drawable.status_lock_closed_24dp;
encColor = R.color.key_flag_green;
break;
}
case OpenPgpDecryptionResult.RESULT_INSECURE: {
encText = R.string.decrypt_result_insecure;
encIcon = R.drawable.status_signature_invalid_cutout_24dp;
encColor = R.color.key_flag_red;
break;
}
default:
case OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED: {
encText = R.string.decrypt_result_not_encrypted;
encIcon = R.drawable.status_lock_open_24dp;
encColor = R.color.key_flag_red;
break;
}
}
int encColorRes = context.getResources().getColor(encColor);
@@ -464,22 +480,27 @@ public class KeyFormattingUtils {
holder.getEncryptionStatusText().setTextColor(encColorRes);
}
OpenPgpSignatureResult signatureResult = result.getSignatureResult();
int sigText, sigIcon, sigColor;
int sigActionText, sigActionIcon;
if (signatureResult == null) {
switch (signatureResult.getResult()) {
sigText = R.string.decrypt_result_no_signature;
sigIcon = R.drawable.status_signature_invalid_cutout_24dp;
sigColor = R.color.key_flag_gray;
case OpenPgpSignatureResult.RESULT_NO_SIGNATURE: {
// no signature
// won't be used, but makes compiler happy
sigActionText = 0;
sigActionIcon = 0;
sigText = R.string.decrypt_result_no_signature;
sigIcon = R.drawable.status_signature_invalid_cutout_24dp;
sigColor = R.color.key_flag_gray;
} else switch (signatureResult.getStatus()) {
// won't be used, but makes compiler happy
sigActionText = 0;
sigActionIcon = 0;
break;
}
case OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED: {
case OpenPgpSignatureResult.RESULT_VALID_CONFIRMED: {
sigText = R.string.decrypt_result_signature_certified;
sigIcon = R.drawable.status_signature_verified_cutout_24dp;
sigColor = R.color.key_flag_green;
@@ -489,7 +510,7 @@ public class KeyFormattingUtils {
break;
}
case OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED: {
case OpenPgpSignatureResult.RESULT_VALID_UNCONFIRMED: {
sigText = R.string.decrypt_result_signature_uncertified;
sigIcon = R.drawable.status_signature_unverified_cutout_24dp;
sigColor = R.color.key_flag_orange;
@@ -499,7 +520,7 @@ public class KeyFormattingUtils {
break;
}
case OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED: {
case OpenPgpSignatureResult.RESULT_INVALID_KEY_REVOKED: {
sigText = R.string.decrypt_result_signature_revoked_key;
sigIcon = R.drawable.status_signature_revoked_cutout_24dp;
sigColor = R.color.key_flag_red;
@@ -509,7 +530,7 @@ public class KeyFormattingUtils {
break;
}
case OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED: {
case OpenPgpSignatureResult.RESULT_INVALID_KEY_EXPIRED: {
sigText = R.string.decrypt_result_signature_expired_key;
sigIcon = R.drawable.status_signature_expired_cutout_24dp;
sigColor = R.color.key_flag_red;
@@ -519,7 +540,7 @@ public class KeyFormattingUtils {
break;
}
case OpenPgpSignatureResult.SIGNATURE_KEY_MISSING: {
case OpenPgpSignatureResult.RESULT_KEY_MISSING: {
sigText = R.string.decrypt_result_signature_missing_key;
sigIcon = R.drawable.status_signature_unknown_cutout_24dp;
sigColor = R.color.key_flag_red;
@@ -529,8 +550,18 @@ public class KeyFormattingUtils {
break;
}
case OpenPgpSignatureResult.RESULT_INVALID_INSECURE: {
sigText = R.string.decrypt_result_insecure_cryptography;
sigIcon = R.drawable.status_signature_invalid_cutout_24dp;
sigColor = R.color.key_flag_red;
sigActionText = R.string.decrypt_result_action_show;
sigActionIcon = R.drawable.ic_vpn_key_grey_24dp;
break;
}
default:
case OpenPgpSignatureResult.SIGNATURE_ERROR: {
case OpenPgpSignatureResult.RESULT_INVALID_SIGNATURE: {
sigText = R.string.decrypt_result_invalid_signature;
sigIcon = R.drawable.status_signature_invalid_cutout_24dp;
sigColor = R.color.key_flag_red;
@@ -548,7 +579,8 @@ public class KeyFormattingUtils {
holder.getSignatureStatusText().setText(sigText);
holder.getSignatureStatusText().setTextColor(sigColorRes);
if (signatureResult != null) {
if (signatureResult.getResult() != OpenPgpSignatureResult.RESULT_NO_SIGNATURE) {
// has a signature, thus display layouts
holder.getSignatureLayout().setVisibility(View.VISIBLE);
@@ -556,7 +588,7 @@ public class KeyFormattingUtils {
holder.getSignatureAction().setCompoundDrawablesWithIntrinsicBounds(
0, 0, sigActionIcon, 0);
String userId = signatureResult.getPrimaryUserId();
String userId = result.getSignatureResult().getPrimaryUserId();
KeyRing.UserId userIdSplit = KeyRing.splitUserId(userId);
if (userIdSplit.name != null) {
holder.getSignatureUserName().setText(userIdSplit.name);
@@ -687,6 +719,24 @@ public class KeyFormattingUtils {
}
break;
}
case INSECURE: {
if (big) {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout_96dp));
} else {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout_24dp));
}
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
color = R.color.key_flag_red;
}
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
if (statusText != null) {
statusText.setTextColor(context.getResources().getColor(color));
}
break;
}
case NOT_ENCRYPTED: {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_lock_open_24dp));