From 57378be1c07893e2231e485d6289d53d522aa7d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 25 Jul 2015 14:32:47 +0200 Subject: Introduce constants in OpenPgpSignature and DecryptionResult for unsigned/unencrypted content, update API, introduce simple checks for insecure symmetric algos --- .../operations/results/DecryptVerifyResult.java | 32 +++-- .../keychain/pgp/CanonicalizedSecretKey.java | 2 +- .../pgp/OpenPgpSignatureResultBuilder.java | 91 ++++++++------- .../keychain/pgp/PgpConstants.java | 130 ++++++++++++--------- .../keychain/pgp/PgpDecryptVerify.java | 68 +++++------ .../keychain/pgp/PgpKeyOperation.java | 14 +-- .../keychain/pgp/PgpSignEncryptInputParcel.java | 18 +-- .../keychain/pgp/PgpSignEncryptOperation.java | 22 ++-- .../keychain/provider/ProviderHelper.java | 4 +- .../keychain/remote/OpenPgpService.java | 86 ++++++++------ .../keychain/ui/DecryptFragment.java | 72 ++++++++---- .../keychain/ui/DecryptListFragment.java | 14 +-- .../keychain/ui/EncryptFilesFragment.java | 12 +- .../keychain/ui/EncryptTextFragment.java | 10 +- .../keychain/ui/util/KeyFormattingUtils.java | 106 ++++++++++++----- OpenKeychain/src/main/res/values/strings.xml | 4 +- 16 files changed, 418 insertions(+), 267 deletions(-) (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java index f9a738d56..e8be9fa78 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Dominik Schürmann + * Copyright (C) 2014-2015 Dominik Schürmann * Copyright (C) 2014 Vincent Breitmoser * * This program is free software: you can redistribute it and/or modify @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.operations.results; import android.os.Parcel; +import org.openintents.openpgp.OpenPgpDecryptionResult; import org.openintents.openpgp.OpenPgpMetadata; import org.openintents.openpgp.OpenPgpSignatureResult; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; @@ -31,7 +32,8 @@ public class DecryptVerifyResult extends InputPendingResult { public static final int RESULT_KEY_DISALLOWED = RESULT_ERROR + 32; OpenPgpSignatureResult mSignatureResult; - OpenPgpMetadata mDecryptMetadata; + OpenPgpDecryptionResult mDecryptionResult; + OpenPgpMetadata mDecryptionMetadata; // This holds the charset which was specified in the ascii armor, if specified // https://tools.ietf.org/html/rfc4880#page56 String mCharset; @@ -52,7 +54,8 @@ public class DecryptVerifyResult extends InputPendingResult { public DecryptVerifyResult(Parcel source) { super(source); mSignatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader()); - mDecryptMetadata = source.readParcelable(OpenPgpMetadata.class.getClassLoader()); + mDecryptionResult = source.readParcelable(OpenPgpDecryptionResult.class.getClassLoader()); + mDecryptionMetadata = source.readParcelable(OpenPgpMetadata.class.getClassLoader()); mCachedCryptoInputParcel = source.readParcelable(CryptoInputParcel.class.getClassLoader()); } @@ -69,6 +72,14 @@ public class DecryptVerifyResult extends InputPendingResult { mSignatureResult = signatureResult; } + public OpenPgpDecryptionResult getDecryptionResult() { + return mDecryptionResult; + } + + public void setDecryptionResult(OpenPgpDecryptionResult decryptionResult) { + mDecryptionResult = decryptionResult; + } + public CryptoInputParcel getCachedCryptoInputParcel() { return mCachedCryptoInputParcel; } @@ -77,12 +88,12 @@ public class DecryptVerifyResult extends InputPendingResult { mCachedCryptoInputParcel = cachedCryptoInputParcel; } - public OpenPgpMetadata getDecryptMetadata() { - return mDecryptMetadata; + public OpenPgpMetadata getDecryptionMetadata() { + return mDecryptionMetadata; } - public void setDecryptMetadata(OpenPgpMetadata decryptMetadata) { - mDecryptMetadata = decryptMetadata; + public void setDecryptionMetadata(OpenPgpMetadata decryptMetadata) { + mDecryptionMetadata = decryptMetadata; } public String getCharset () { @@ -107,9 +118,10 @@ public class DecryptVerifyResult extends InputPendingResult { public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); - dest.writeParcelable(mSignatureResult, 0); - dest.writeParcelable(mDecryptMetadata, 0); - dest.writeParcelable(mCachedCryptoInputParcel, 0); + dest.writeParcelable(mSignatureResult, flags); + dest.writeParcelable(mDecryptionResult, flags); + dest.writeParcelable(mDecryptionMetadata, flags); + dest.writeParcelable(mCachedCryptoInputParcel, flags); } public static final Creator CREATOR = new Creator() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java index 31a3925da..4aa05c9f8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -184,7 +184,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { // TODO: intersection between preferred hash algos of this key and PgpConstants.PREFERRED_HASH_ALGORITHMS // choose best algo - return PgpConstants.sPreferredHashAlgorithms; + return new ArrayList<>(); } private PGPContentSignerBuilder getContentSignerBuilder(int hashAlgo, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java index ed4715681..9d059b58f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java @@ -30,7 +30,6 @@ import java.util.ArrayList; */ public class OpenPgpSignatureResultBuilder { // OpenPgpSignatureResult - private boolean mSignatureOnly = false; private String mPrimaryUserId; private ArrayList mUserIds = new ArrayList<>(); private long mKeyId; @@ -42,10 +41,7 @@ public class OpenPgpSignatureResultBuilder { private boolean mIsSignatureKeyCertified = false; private boolean mIsKeyRevoked = false; private boolean mIsKeyExpired = false; - - public void setSignatureOnly(boolean signatureOnly) { - this.mSignatureOnly = signatureOnly; - } + private boolean mInsecure = false; public void setPrimaryUserId(String userId) { this.mPrimaryUserId = userId; @@ -63,6 +59,10 @@ public class OpenPgpSignatureResultBuilder { this.mValidSignature = validSignature; } + public void setInsecure(boolean insecure) { + this.mInsecure = insecure; + } + public void setSignatureKeyCertified(boolean isSignatureKeyCertified) { this.mIsSignatureKeyCertified = isSignatureKeyCertified; } @@ -87,6 +87,10 @@ public class OpenPgpSignatureResultBuilder { return mValidSignature; } + public boolean isInsecure() { + return mInsecure; + } + public void initValid(CanonicalizedPublicKeyRing signingRing, CanonicalizedPublicKey signingKey) { setSignatureAvailable(true); @@ -109,47 +113,50 @@ public class OpenPgpSignatureResultBuilder { } public OpenPgpSignatureResult build() { - if (mSignatureAvailable) { - OpenPgpSignatureResult result = new OpenPgpSignatureResult(); - result.setSignatureOnly(mSignatureOnly); - - // valid sig! - if (mKnownKey) { - if (mValidSignature) { - result.setKeyId(mKeyId); - result.setPrimaryUserId(mPrimaryUserId); - result.setUserIds(mUserIds); - - if (mIsKeyRevoked) { - Log.d(Constants.TAG, "SIGNATURE_KEY_REVOKED"); - result.setStatus(OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED); - } else if (mIsKeyExpired) { - Log.d(Constants.TAG, "SIGNATURE_KEY_EXPIRED"); - result.setStatus(OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED); - } else if (mIsSignatureKeyCertified) { - Log.d(Constants.TAG, "SIGNATURE_SUCCESS_CERTIFIED"); - result.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED); - } else { - Log.d(Constants.TAG, "SIGNATURE_SUCCESS_UNCERTIFIED"); - result.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED); - } - } else { - Log.d(Constants.TAG, "Error! Invalid signature."); - result.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR); - } - } else { - result.setKeyId(mKeyId); - - Log.d(Constants.TAG, "SIGNATURE_KEY_MISSING"); - result.setStatus(OpenPgpSignatureResult.SIGNATURE_KEY_MISSING); - } + OpenPgpSignatureResult result = new OpenPgpSignatureResult(); + if (!mSignatureAvailable) { + Log.d(Constants.TAG, "RESULT_NO_SIGNATURE"); + result.setResult(OpenPgpSignatureResult.RESULT_NO_SIGNATURE); return result; - } else { - Log.d(Constants.TAG, "no signature found!"); + } + + if (!mKnownKey) { + result.setKeyId(mKeyId); - return null; + Log.d(Constants.TAG, "RESULT_KEY_MISSING"); + result.setResult(OpenPgpSignatureResult.RESULT_KEY_MISSING); + return result; + } + + if (!mValidSignature) { + Log.d(Constants.TAG, "RESULT_INVALID_SIGNATURE"); + result.setResult(OpenPgpSignatureResult.RESULT_INVALID_SIGNATURE); + return result; } + + result.setKeyId(mKeyId); + result.setPrimaryUserId(mPrimaryUserId); + result.setUserIds(mUserIds); + + if (mIsKeyRevoked) { + Log.d(Constants.TAG, "RESULT_INVALID_KEY_REVOKED"); + result.setResult(OpenPgpSignatureResult.RESULT_INVALID_KEY_REVOKED); + } else if (mIsKeyExpired) { + Log.d(Constants.TAG, "RESULT_INVALID_KEY_EXPIRED"); + result.setResult(OpenPgpSignatureResult.RESULT_INVALID_KEY_EXPIRED); + } else if (mInsecure) { + Log.d(Constants.TAG, "RESULT_INVALID_INSECURE"); + result.setResult(OpenPgpSignatureResult.RESULT_INVALID_INSECURE); + } else if (mIsSignatureKeyCertified) { + Log.d(Constants.TAG, "RESULT_VALID_CONFIRMED"); + result.setResult(OpenPgpSignatureResult.RESULT_VALID_CONFIRMED); + } else { + Log.d(Constants.TAG, "RESULT_VALID_UNCONFIRMED"); + result.setResult(OpenPgpSignatureResult.RESULT_VALID_UNCONFIRMED); + } + + return result; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java index f739b1e6d..7c009921d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java @@ -21,51 +21,96 @@ import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.spongycastle.bcpg.HashAlgorithmTags; import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; -import java.util.ArrayList; +import java.util.HashSet; +/** + * NIST requirements for 2011-2030 (http://www.keylength.com/en/4/): + * - RSA: 2048 bit + * - ECC: 224 bit + * - Symmetric: 3TDEA + * - Digital Signature (hash A): SHA-224 - SHA-512 + */ public class PgpConstants { - public static ArrayList sPreferredSymmetricAlgorithms = new ArrayList<>(); - public static ArrayList sPreferredHashAlgorithms = new ArrayList<>(); - public static ArrayList sPreferredCompressionAlgorithms = new ArrayList<>(); +// public interface MIN_REQUIREMENT { +// int MIN_BITS; +// int BINDING_SIGNATURE_HASH_ALGO; // for User IDs, subkeys,... +// int SYMMETRIC_ALGO; +// } + // https://tools.ietf.org/html/rfc6637#section-13 + - // TODO: use hashmaps for contains in O(1) and intersections! + // PgpDecryptVerify: Secure Algorithms Whitelist + // all other algorithms will be rejected with OpenPgpDecryptionResult.RESULT_INSECURE + public static HashSet sSymmetricAlgorithmsWhitelist = new HashSet<>(); + static { + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_256); + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_192); + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_128); + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.TWOFISH); + } + + // all other algorithms will be rejected with OpenPgpSignatureResult.RESULT_INVALID_INSECURE + public static HashSet sHashAlgorithmsWhitelist = new HashSet<>(); + static { + sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA256); + sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA512); + sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA384); + sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA224); + sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA1); + sHashAlgorithmsWhitelist.add(HashAlgorithmTags.RIPEMD160); + } /* * Most preferred is first * These arrays are written as preferred algorithms into the keys on creation. * Other implementations may choose to honor this selection. - * - * These lists also define the only algorithms which are used in OpenKeychain. - * We do not support algorithms such as MD5 */ - static { - sPreferredSymmetricAlgorithms.add(SymmetricKeyAlgorithmTags.AES_256); - sPreferredSymmetricAlgorithms.add(SymmetricKeyAlgorithmTags.AES_192); - sPreferredSymmetricAlgorithms.add(SymmetricKeyAlgorithmTags.AES_128); - sPreferredSymmetricAlgorithms.add(SymmetricKeyAlgorithmTags.TWOFISH); - - // NOTE: some implementations do not support SHA512, thus we choose SHA256 as default (Mailvelope?) - sPreferredHashAlgorithms.add(HashAlgorithmTags.SHA256); - sPreferredHashAlgorithms.add(HashAlgorithmTags.SHA512); - sPreferredHashAlgorithms.add(HashAlgorithmTags.SHA384); - sPreferredHashAlgorithms.add(HashAlgorithmTags.SHA224); - sPreferredHashAlgorithms.add(HashAlgorithmTags.SHA1); - sPreferredHashAlgorithms.add(HashAlgorithmTags.RIPEMD160); - - /* - * Prefer ZIP - * "ZLIB provides no benefit over ZIP and is more malleable" - * - (OpenPGP WG mailinglist: "[openpgp] Intent to deprecate: Insecure primitives") - * BZIP2: very slow - */ - sPreferredCompressionAlgorithms.add(CompressionAlgorithmTags.ZIP); - sPreferredCompressionAlgorithms.add(CompressionAlgorithmTags.ZLIB); - sPreferredCompressionAlgorithms.add(CompressionAlgorithmTags.BZIP2); - } + public static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{ + SymmetricKeyAlgorithmTags.AES_256, + SymmetricKeyAlgorithmTags.AES_192, + SymmetricKeyAlgorithmTags.AES_128, + SymmetricKeyAlgorithmTags.TWOFISH + }; + + // NOTE: some implementations do not support SHA512, thus we choose SHA256 as default (Mailvelope?) + public static final int[] PREFERRED_HASH_ALGORITHMS = new int[]{ + HashAlgorithmTags.SHA256, + HashAlgorithmTags.SHA512, + HashAlgorithmTags.SHA384, + HashAlgorithmTags.SHA224, + }; + + /* + * Prefer ZIP + * "ZLIB provides no benefit over ZIP and is more malleable" + * - (OpenPGP WG mailinglist: "[openpgp] Intent to deprecate: Insecure primitives") + * BZIP2: very slow + */ + public static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[]{ + CompressionAlgorithmTags.ZIP, + CompressionAlgorithmTags.ZLIB, + CompressionAlgorithmTags.BZIP2 + }; public static final int CERTIFY_HASH_ALGO = HashAlgorithmTags.SHA256; + + public static final int DEFAULT_SYMMETRIC_ALGORITHM = SymmetricKeyAlgorithmTags.AES_256; + public interface OpenKeychainSymmetricKeyAlgorithmTags extends SymmetricKeyAlgorithmTags { + int USE_DEFAULT = -1; + } + + public static final int DEFAULT_HASH_ALGORITHM = HashAlgorithmTags.SHA256; + public interface OpenKeychainHashAlgorithmTags extends HashAlgorithmTags { + int USE_DEFAULT = -1; + } + + public static final int DEFAULT_COMPRESSION_ALGORITHM = CompressionAlgorithmTags.ZIP; + public interface OpenKeychainCompressionAlgorithmTags extends CompressionAlgorithmTags { + int USE_DEFAULT = -1; + } + /* * Note: s2kcount is a number between 0 and 0xff that controls the * number of times to iterate the password hash before use. More @@ -87,28 +132,9 @@ public class PgpConstants { public static final int SECRET_KEY_ENCRYPTOR_S2K_COUNT = 0x90; public static final int SECRET_KEY_ENCRYPTOR_HASH_ALGO = HashAlgorithmTags.SHA256; public static final int SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO = SymmetricKeyAlgorithmTags.AES_256; - public static final int SECRET_KEY_SIGNATURE_HASH_ALGO = HashAlgorithmTags.SHA256; + public static final int SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO = HashAlgorithmTags.SHA256; // NOTE: only SHA1 is supported for key checksum calculations in OpenPGP, // see http://tools.ietf.org/html/rfc488 0#section-5.5.3 public static final int SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO = HashAlgorithmTags.SHA1; - public static interface OpenKeychainSymmetricKeyAlgorithmTags extends SymmetricKeyAlgorithmTags { - public static final int USE_PREFERRED = -1; - } - - public static interface OpenKeychainHashAlgorithmTags extends HashAlgorithmTags { - public static final int USE_PREFERRED = -1; - } - - public static interface OpenKeychainCompressionAlgorithmTags extends CompressionAlgorithmTags { - public static final int USE_PREFERRED = -1; - } - - public static int[] getAsArray(ArrayList list) { - int[] array = new int[list.size()]; - for (int i = 0; i < list.size(); i++) { - array[i] = list.get(i); - } - return array; - } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index e264b4678..d40bad3aa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -22,6 +22,7 @@ import android.content.Context; import android.support.annotation.NonNull; import android.webkit.MimeTypeMap; +import org.openintents.openpgp.OpenPgpDecryptionResult; import org.openintents.openpgp.OpenPgpMetadata; import org.openintents.openpgp.OpenPgpSignatureResult; import org.spongycastle.bcpg.ArmoredInputStream; @@ -283,10 +284,6 @@ public class PgpDecryptVerify extends BaseOperation PGPSignatureList signatureList = (PGPSignatureList) pgpF.nextObject(); PGPSignature messageSignature = signatureList.get(signatureIndex); - // these are not cleartext signatures! - // TODO: what about binary signatures? - signatureResultBuilder.setSignatureOnly(false); - // Verify signature and check binding signatures boolean validSignature = signature.verify(messageSignature); if (validSignature) { @@ -298,8 +295,8 @@ public class PgpDecryptVerify extends BaseOperation OpenPgpSignatureResult signatureResult = signatureResultBuilder.build(); - if (signatureResult.getStatus() != OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED - && signatureResult.getStatus() != OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED) { + if (signatureResult.getResult() != OpenPgpSignatureResult.RESULT_VALID_CONFIRMED + && signatureResult.getResult() != OpenPgpSignatureResult.RESULT_VALID_UNCONFIRMED) { log.add(LogType.MSG_VL_ERROR_INTEGRITY_CHECK, indent); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } @@ -309,9 +306,10 @@ public class PgpDecryptVerify extends BaseOperation log.add(LogType.MSG_VL_OK, indent); // Return a positive result, with metadata and verification info - DecryptVerifyResult result = - new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); + DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); result.setSignatureResult(signatureResult); + result.setDecryptionResult( + new OpenPgpDecryptionResult(OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED)); return result; } @@ -322,6 +320,8 @@ public class PgpDecryptVerify extends BaseOperation PgpDecryptVerifyInputParcel input, CryptoInputParcel cryptoInput, InputStream in, OutputStream out, int indent) throws IOException, PGPException { + OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); + OpenPgpDecryptionResult decryptionResult = new OpenPgpDecryptionResult(); OperationLog log = new OperationLog(); log.add(LogType.MSG_DC, indent); @@ -614,15 +614,16 @@ public class PgpDecryptVerify extends BaseOperation log.add(LogType.MSG_DC_ERROR_NO_KEY, indent + 1); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } + decryptionResult.setResult(OpenPgpDecryptionResult.RESULT_ENCRYPTED); - // Warn about old encryption algorithms! - if (!PgpConstants.sPreferredSymmetricAlgorithms.contains(symmetricEncryptionAlgo)) { + // Check for insecure encryption algorithms! + if (!PgpConstants.sSymmetricAlgorithmsWhitelist.contains(symmetricEncryptionAlgo)) { log.add(LogType.MSG_DC_OLD_SYMMETRIC_ENCRYPTION_ALGO, indent + 1); + decryptionResult.setResult(OpenPgpDecryptionResult.RESULT_INSECURE); } JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear); Object dataChunk = plainFact.nextObject(); - OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); int signatureIndex = -1; CanonicalizedPublicKeyRing signingRing = null; CanonicalizedPublicKey signingKey = null; @@ -752,7 +753,7 @@ public class PgpDecryptVerify extends BaseOperation DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); result.setCharset(charset); - result.setDecryptMetadata(metadata); + result.setDecryptionMetadata(metadata); return result; } @@ -809,11 +810,9 @@ public class PgpDecryptVerify extends BaseOperation PGPSignatureList signatureList = (PGPSignatureList) plainFact.nextObject(); PGPSignature messageSignature = signatureList.get(signatureIndex); - // these are not cleartext signatures! // TODO: what about binary signatures? - signatureResultBuilder.setSignatureOnly(false); - // Verify signature and check binding signatures + // Verify signature boolean validSignature = signature.verify(messageSignature); if (validSignature) { log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1); @@ -821,10 +820,10 @@ public class PgpDecryptVerify extends BaseOperation log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1); } - // Don't allow verification of old hash algorithms! - if (!PgpConstants.sPreferredHashAlgorithms.contains(signature.getHashAlgorithm())) { - validSignature = false; + // check for insecure hash algorithms + if (!PgpConstants.sHashAlgorithmsWhitelist.contains(signature.getHashAlgorithm())) { log.add(LogType.MSG_DC_ERROR_UNSUPPORTED_HASH_ALGO, indent + 1); + signatureResultBuilder.setInsecure(true); } signatureResultBuilder.setValidSignature(validSignature); @@ -852,7 +851,7 @@ public class PgpDecryptVerify extends BaseOperation Log.d(Constants.TAG, "MDC fail"); if (!signatureResultBuilder.isValidSignature()) { log.add(LogType.MSG_DC_ERROR_INTEGRITY_MISSING, indent); - return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); + decryptionResult.setResult(OpenPgpDecryptionResult.RESULT_INSECURE); } } @@ -861,12 +860,12 @@ public class PgpDecryptVerify extends BaseOperation log.add(LogType.MSG_DC_OK, indent); // Return a positive result, with metadata and verification info - DecryptVerifyResult result = - new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); + DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); result.setCachedCryptoInputParcel(cryptoInput); - result.setDecryptMetadata(metadata); result.setSignatureResult(signatureResultBuilder.build()); result.setCharset(charset); + result.setDecryptionResult(decryptionResult); + result.setDecryptionMetadata(metadata); return result; } @@ -885,8 +884,6 @@ public class PgpDecryptVerify extends BaseOperation OperationLog log = new OperationLog(); OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); - // cleartext signatures are never encrypted ;) - signatureResultBuilder.setSignatureOnly(true); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -956,10 +953,10 @@ public class PgpDecryptVerify extends BaseOperation log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1); } - // Don't allow verification of old hash algorithms! - if (!PgpConstants.sPreferredHashAlgorithms.contains(signature.getHashAlgorithm())) { - validSignature = false; + // check for insecure hash algorithms + if (!PgpConstants.sHashAlgorithmsWhitelist.contains(signature.getHashAlgorithm())) { log.add(LogType.MSG_DC_ERROR_UNSUPPORTED_HASH_ALGO, indent + 1); + signatureResultBuilder.setInsecure(true); } signatureResultBuilder.setValidSignature(validSignature); @@ -981,8 +978,10 @@ public class PgpDecryptVerify extends BaseOperation clearText.length); DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); - result.setDecryptMetadata(metadata); result.setSignatureResult(signatureResultBuilder.build()); + result.setDecryptionResult( + new OpenPgpDecryptionResult(OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED)); + result.setDecryptionMetadata(metadata); return result; } @@ -994,8 +993,6 @@ public class PgpDecryptVerify extends BaseOperation OperationLog log = new OperationLog(); OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); - // detached signatures are never encrypted - signatureResultBuilder.setSignatureOnly(true); updateProgress(R.string.progress_processing_signature, 0, 100); InputStream detachedSigIn = new ByteArrayInputStream(input.getDetachedSignature()); @@ -1050,9 +1047,6 @@ public class PgpDecryptVerify extends BaseOperation updateProgress(R.string.progress_verifying_signature, 90, 100); log.add(LogType.MSG_DC_CLEAR_SIGNATURE_CHECK, indent); - // these are not cleartext signatures! - signatureResultBuilder.setSignatureOnly(false); - // Verify signature and check binding signatures boolean validSignature = signature.verify(); if (validSignature) { @@ -1061,10 +1055,10 @@ public class PgpDecryptVerify extends BaseOperation log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1); } - // Don't allow verification of old hash algorithms! - if (!PgpConstants.sPreferredHashAlgorithms.contains(signature.getHashAlgorithm())) { - validSignature = false; + // check for insecure hash algorithms + if (!PgpConstants.sHashAlgorithmsWhitelist.contains(signature.getHashAlgorithm())) { log.add(LogType.MSG_DC_ERROR_UNSUPPORTED_HASH_ALGO, indent + 1); + signatureResultBuilder.setInsecure(true); } signatureResultBuilder.setValidSignature(validSignature); @@ -1076,6 +1070,8 @@ public class PgpDecryptVerify extends BaseOperation DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); result.setSignatureResult(signatureResultBuilder.build()); + result.setDecryptionResult( + new OpenPgpDecryptionResult(OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED)); return result; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index c82cbce8f..a7eead939 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -1206,7 +1206,7 @@ public class PgpKeyOperation { // add packet with EMPTY notation data (updates old one, but will be stripped later) PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( masterPrivateKey.getPublicKeyPacket().getAlgorithm(), - PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO) + PgpConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); { // set subpackets @@ -1233,7 +1233,7 @@ public class PgpKeyOperation { // add packet with "pin" notation data PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( masterPrivateKey.getPublicKeyPacket().getAlgorithm(), - PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO) + PgpConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); { // set subpackets @@ -1440,13 +1440,13 @@ public class PgpKeyOperation { if (divertToCard) { // use synchronous "NFC based" SignerBuilder builder = new NfcSyncPGPContentSignerBuilder( - pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO, + pKey.getAlgorithm(), PgpConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO, pKey.getKeyID(), cryptoInput.getCryptoData()) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); } else { // content signer based on signing key algorithm and chosen hash algorithm builder = new JcaPGPContentSignerBuilder( - pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO) + pKey.getAlgorithm(), PgpConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); } @@ -1472,11 +1472,11 @@ public class PgpKeyOperation { */ /* non-critical subpackets: */ hashedPacketsGen.setPreferredSymmetricAlgorithms(false, - PgpConstants.getAsArray(PgpConstants.sPreferredSymmetricAlgorithms)); + PgpConstants.PREFERRED_SYMMETRIC_ALGORITHMS); hashedPacketsGen.setPreferredHashAlgorithms(false, - PgpConstants.getAsArray(PgpConstants.sPreferredHashAlgorithms)); + PgpConstants.PREFERRED_HASH_ALGORITHMS); hashedPacketsGen.setPreferredCompressionAlgorithms(false, - PgpConstants.getAsArray(PgpConstants.sPreferredCompressionAlgorithms)); + PgpConstants.PREFERRED_COMPRESSION_ALGORITHMS); hashedPacketsGen.setPrimaryUserID(false, primary); /* critical subpackets: we consider those important for a modern pgp implementation */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java index fa6268758..44e4b9221 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java @@ -30,13 +30,13 @@ public class PgpSignEncryptInputParcel implements Parcelable { protected String mVersionHeader = null; protected boolean mEnableAsciiArmorOutput = false; - protected int mCompressionId = CompressionAlgorithmTags.UNCOMPRESSED; + protected int mCompressionAlgorithm = CompressionAlgorithmTags.UNCOMPRESSED; protected long[] mEncryptionMasterKeyIds = null; protected Passphrase mSymmetricPassphrase = null; - protected int mSymmetricEncryptionAlgorithm = PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED; + protected int mSymmetricEncryptionAlgorithm = PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT; protected long mSignatureMasterKeyId = Constants.key.none; protected Long mSignatureSubKeyId = null; - protected int mSignatureHashAlgorithm = PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED; + protected int mSignatureHashAlgorithm = PgpConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT; protected long mAdditionalEncryptId = Constants.key.none; protected boolean mFailOnMissingEncryptionKeyIds = false; protected String mCharset; @@ -55,7 +55,7 @@ public class PgpSignEncryptInputParcel implements Parcelable { // we do all of those here, so the PgpSignEncryptInput class doesn't have to be parcelable mVersionHeader = source.readString(); mEnableAsciiArmorOutput = source.readInt() == 1; - mCompressionId = source.readInt(); + mCompressionAlgorithm = source.readInt(); mEncryptionMasterKeyIds = source.createLongArray(); mSymmetricPassphrase = source.readParcelable(loader); mSymmetricEncryptionAlgorithm = source.readInt(); @@ -79,7 +79,7 @@ public class PgpSignEncryptInputParcel implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeString(mVersionHeader); dest.writeInt(mEnableAsciiArmorOutput ? 1 : 0); - dest.writeInt(mCompressionId); + dest.writeInt(mCompressionAlgorithm); dest.writeLongArray(mEncryptionMasterKeyIds); dest.writeParcelable(mSymmetricPassphrase, 0); dest.writeInt(mSymmetricEncryptionAlgorithm); @@ -174,12 +174,12 @@ public class PgpSignEncryptInputParcel implements Parcelable { return this; } - public int getCompressionId() { - return mCompressionId; + public int getCompressionAlgorithm() { + return mCompressionAlgorithm; } - public PgpSignEncryptInputParcel setCompressionId(int compressionId) { - mCompressionId = compressionId; + public PgpSignEncryptInputParcel setCompressionAlgorithm(int compressionAlgorithm) { + mCompressionAlgorithm = compressionAlgorithm; return this; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java index 8fb41a909..a2c5fa30d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java @@ -124,7 +124,7 @@ public class PgpSignEncryptOperation extends BaseOperation { boolean enableSignature = input.getSignatureMasterKeyId() != Constants.key.none; boolean enableEncryption = ((input.getEncryptionMasterKeyIds() != null && input.getEncryptionMasterKeyIds().length > 0) || input.getSymmetricPassphrase() != null); - boolean enableCompression = (input.getCompressionId() != CompressionAlgorithmTags.UNCOMPRESSED); + boolean enableCompression = (input.getCompressionAlgorithm() != CompressionAlgorithmTags.UNCOMPRESSED); Log.d(Constants.TAG, "enableSignature:" + enableSignature + "\nenableEncryption:" + enableEncryption @@ -229,9 +229,11 @@ public class PgpSignEncryptOperation extends BaseOperation { // Use preferred hash algo int requestedAlgorithm = input.getSignatureHashAlgorithm(); ArrayList supported = signingKey.getSupportedHashAlgorithms(); - if (requestedAlgorithm == PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED) { + if (requestedAlgorithm == PgpConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT) { + input.setSignatureHashAlgorithm(PgpConstants.DEFAULT_HASH_ALGORITHM); + // TODO // get most preferred - input.setSignatureHashAlgorithm(supported.get(0)); +// input.setSignatureHashAlgorithm(supported.get(0)); } else if (!supported.contains(requestedAlgorithm)) { log.add(LogType.MSG_PSE_ERROR_HASH_ALGO, indent); return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); @@ -245,10 +247,10 @@ public class PgpSignEncryptOperation extends BaseOperation { // Use preferred encryption algo int algo = input.getSymmetricEncryptionAlgorithm(); - if (algo == PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED) { + if (algo == PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT) { // get most preferred // TODO: get from recipients - algo = PgpConstants.sPreferredSymmetricAlgorithms.get(0); + algo = PgpConstants.DEFAULT_SYMMETRIC_ALGORITHM; } // has Integrity packet enabled! JcePGPDataEncryptorBuilder encryptorBuilder = @@ -341,7 +343,13 @@ public class PgpSignEncryptOperation extends BaseOperation { if (enableCompression) { log.add(LogType.MSG_PSE_COMPRESSING, indent); - compressGen = new PGPCompressedDataGenerator(input.getCompressionId()); + + // Use preferred compression algo + int algo = input.getCompressionAlgorithm(); + if (algo == PgpConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT) { + algo = PgpConstants.DEFAULT_COMPRESSION_ALGORITHM; + } + compressGen = new PGPCompressedDataGenerator(algo); bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut)); } else { bcpgOut = new BCPGOutputStream(encryptionOut); @@ -464,7 +472,7 @@ public class PgpSignEncryptOperation extends BaseOperation { InputStream in = inputData.getInputStream(); if (enableCompression) { - compressGen = new PGPCompressedDataGenerator(input.getCompressionId()); + compressGen = new PGPCompressedDataGenerator(input.getCompressionAlgorithm()); bcpgOut = new BCPGOutputStream(compressGen.open(out)); } else { bcpgOut = new BCPGOutputStream(out); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index ed17de4ab..9abdbf8be 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -1434,9 +1434,9 @@ public class ProviderHelper { // DEPRECATED and thus hardcoded values.put(KeychainContract.ApiAccounts.COMPRESSION, CompressionAlgorithmTags.ZLIB); values.put(KeychainContract.ApiAccounts.ENCRYPTION_ALGORITHM, - PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); + PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); values.put(KeychainContract.ApiAccounts.HASH_ALORITHM, - PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED); + PgpConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT); return values; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index 2568d68b9..6f841fea2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 Dominik Schürmann + * Copyright (C) 2013-2015 Dominik Schürmann * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,9 +24,11 @@ import android.database.Cursor; import android.net.Uri; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.Parcelable; import android.text.TextUtils; import org.openintents.openpgp.IOpenPgpService; +import org.openintents.openpgp.OpenPgpDecryptionResult; import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpMetadata; import org.openintents.openpgp.OpenPgpSignatureResult; @@ -247,7 +249,7 @@ public class OpenPgpService extends RemoteService { .setCleartextSignature(cleartextSign) .setDetachedSignature(!cleartextSign) .setVersionHeader(null) - .setSignatureHashAlgorithm(PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED); + .setSignatureHashAlgorithm(PgpConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT); Intent signKeyIdIntent = getSignKeyMasterId(data); // NOTE: Fallback to return account settings (Old API) @@ -390,8 +392,8 @@ public class OpenPgpService extends RemoteService { PgpSignEncryptInputParcel pseInput = new PgpSignEncryptInputParcel(); pseInput.setEnableAsciiArmorOutput(asciiArmor) .setVersionHeader(null) - .setCompressionId(compressionId) - .setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED) + .setCompressionAlgorithm(compressionId) + .setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT) .setEncryptionMasterKeyIds(keyIds) .setFailOnMissingEncryptionKeyIds(true); @@ -420,7 +422,7 @@ public class OpenPgpService extends RemoteService { } // sign and encrypt - pseInput.setSignatureHashAlgorithm(PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED) + pseInput.setSignatureHashAlgorithm(PgpConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT) .setAdditionalEncryptId(signKeyId); // add sign key for encryption } @@ -540,10 +542,10 @@ public class OpenPgpService extends RemoteService { // allow only private keys associated with accounts of this app // no support for symmetric encryption PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel() - .setAllowSymmetricDecryption(false) - .setAllowedKeyIds(allowedKeyIds) - .setDecryptMetadataOnly(decryptMetadataOnly) - .setDetachedSignature(detachedSignature); + .setAllowSymmetricDecryption(false) + .setAllowedKeyIds(allowedKeyIds) + .setDecryptMetadataOnly(decryptMetadataOnly) + .setDetachedSignature(detachedSignature); DecryptVerifyResult pgpResult = op.execute(input, cryptoInput, inputData, outputStream); @@ -562,40 +564,55 @@ public class OpenPgpService extends RemoteService { Intent result = new Intent(); OpenPgpSignatureResult signatureResult = pgpResult.getSignatureResult(); - // TODO: currently RESULT_TYPE_UNENCRYPTED_UNSIGNED is never returned - // instead an error is returned when no pgp data has been found - int resultType = OpenPgpApi.RESULT_TYPE_UNENCRYPTED_UNSIGNED; - if (signatureResult != null) { - resultType |= OpenPgpApi.RESULT_TYPE_SIGNED; - if (!signatureResult.isSignatureOnly()) { - resultType |= OpenPgpApi.RESULT_TYPE_ENCRYPTED; + + result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult); + + if (signatureResult.getResult() == OpenPgpSignatureResult.RESULT_KEY_MISSING) { + // If signature is unknown we return an _additional_ PendingIntent + // to retrieve the missing key + result.putExtra(OpenPgpApi.RESULT_INTENT, getKeyserverPendingIntent(data, signatureResult.getKeyId())); + } else { + // If signature key is known, return PendingIntent to show key + result.putExtra(OpenPgpApi.RESULT_INTENT, getShowKeyPendingIntent(signatureResult.getKeyId())); + } + + if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 5) { + // RESULT_INVALID_KEY_REVOKED and RESULT_INVALID_KEY_EXPIRED have been added in version 5 + if (signatureResult.getResult() == OpenPgpSignatureResult.RESULT_INVALID_KEY_REVOKED + || signatureResult.getResult() == OpenPgpSignatureResult.RESULT_INVALID_KEY_EXPIRED) { + signatureResult.setResult(OpenPgpSignatureResult.RESULT_INVALID_SIGNATURE); + } + } + + if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 6) { + // RESULT_INVALID_INSECURE has been added in version 6, fallback to RESULT_INVALID_SIGNATURE + if (signatureResult.getResult() == OpenPgpSignatureResult.RESULT_INVALID_INSECURE) { + signatureResult.setResult(OpenPgpSignatureResult.RESULT_INVALID_SIGNATURE); } - result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult); + // RESULT_NO_SIGNATURE has been added in version 6, before the signatureResult was null + if (signatureResult.getResult() == OpenPgpSignatureResult.RESULT_NO_SIGNATURE) { + result.putExtra(OpenPgpApi.RESULT_SIGNATURE, (Parcelable[]) null); + } - if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 5) { - // SIGNATURE_KEY_REVOKED and SIGNATURE_KEY_EXPIRED have been added in version 5 - if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED - || signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED) { - signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR); - } + OpenPgpDecryptionResult decryptionResult = pgpResult.getDecryptionResult(); + if (decryptionResult.getResult() != OpenPgpDecryptionResult.RESULT_ENCRYPTED + && signatureResult.getResult() != OpenPgpSignatureResult.RESULT_NO_SIGNATURE) { + // not encrypted and signed, set deprecated signatureOnly variable + signatureResult.setSignatureOnly(true); } + } - if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_MISSING) { - // If signature is unknown we return an _additional_ PendingIntent - // to retrieve the missing key - result.putExtra(OpenPgpApi.RESULT_INTENT, getKeyserverPendingIntent(data, signatureResult.getKeyId())); - } else { - // If signature key is known, return PendingIntent to show key - result.putExtra(OpenPgpApi.RESULT_INTENT, getShowKeyPendingIntent(signatureResult.getKeyId())); + if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) >= 6) { + OpenPgpDecryptionResult decryptionResult = pgpResult.getDecryptionResult(); + if (decryptionResult != null) { + result.putExtra(OpenPgpApi.RESULT_DECRYPTION, decryptionResult); } - } else { - resultType |= OpenPgpApi.RESULT_TYPE_ENCRYPTED; } - result.putExtra(OpenPgpApi.RESULT_TYPE, resultType); + if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) >= 4) { - OpenPgpMetadata metadata = pgpResult.getDecryptMetadata(); + OpenPgpMetadata metadata = pgpResult.getDecryptionMetadata(); if (metadata != null) { result.putExtra(OpenPgpApi.RESULT_METADATA, metadata); } @@ -647,6 +664,7 @@ public class OpenPgpService extends RemoteService { } } } + } private Intent getKeyImpl(Intent data) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java index aaf337f42..37dd6afad 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -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); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java index 567589821..f57d2d056 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java @@ -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) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index 3dc93872d..7bf662da3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -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(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java index 32257eba5..60a2c9905 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -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); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java index 224e0085b..9984c245e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java @@ -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)); diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index ddf10c988..144617cd2 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -343,6 +343,7 @@ "Not Signed" "Invalid signature!" + "Invalid signature (Insecure Cryptography)!" "Signed by unconfirmed key" "Signed by your key" "Signed by confirmed key" @@ -351,6 +352,7 @@ "Signed by unknown public key" "Encrypted" "Not Encrypted" + "Insecure Encryption" "Show" "Lookup" "Either the signature is invalid or the key has been revoked. You cannot be sure who wrote the text. Do you still want to display it?" @@ -1163,7 +1165,7 @@ "Encountered trailing, symmetrically encrypted data" "Encountered trailing data of unknown type" "Unlocking secret key" - "Potentially insecure encryption algorithm has been used!" + "Insecure encryption algorithm has been used!" "Starting signature check" -- cgit v1.2.3 From dba145f5dfb7f7a43be41b3d01eeb68c4253ae7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 30 Jul 2015 22:46:36 +0200 Subject: Follow some of coorus recommendations: better selection of algo whitelist, ignore recipients preferred algos --- .../operations/results/OperationResult.java | 1 - .../keychain/pgp/CanonicalizedSecretKey.java | 10 ---- .../keychain/pgp/PgpConstants.java | 68 ++++++++++++++++------ .../keychain/pgp/PgpSignEncryptOperation.java | 13 +---- OpenKeychain/src/main/res/values/strings.xml | 1 - 5 files changed, 53 insertions(+), 40 deletions(-) (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index 04013e9ed..b063e1e74 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -660,7 +660,6 @@ public abstract class OperationResult implements Parcelable { MSG_PSE_COMPRESSING (LogLevel.DEBUG, R.string.msg_pse_compressing), MSG_PSE_ENCRYPTING (LogLevel.DEBUG, R.string.msg_pse_encrypting), MSG_PSE_ERROR_BAD_PASSPHRASE (LogLevel.ERROR, R.string.msg_pse_error_bad_passphrase), - MSG_PSE_ERROR_HASH_ALGO (LogLevel.ERROR, R.string.msg_pse_error_hash_algo), MSG_PSE_ERROR_IO (LogLevel.ERROR, R.string.msg_pse_error_io), MSG_PSE_ERROR_SIGN_KEY(LogLevel.ERROR, R.string.msg_pse_error_sign_key), MSG_PSE_ERROR_KEY_SIGN (LogLevel.ERROR, R.string.msg_pse_error_key_sign), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java index 4aa05c9f8..23f02ac08 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -177,16 +177,6 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { return true; } - /** - * Returns a list of all supported hash algorithms. - */ - public ArrayList getSupportedHashAlgorithms() { - // TODO: intersection between preferred hash algos of this key and PgpConstants.PREFERRED_HASH_ALGORITHMS - // choose best algo - - return new ArrayList<>(); - } - private PGPContentSignerBuilder getContentSignerBuilder(int hashAlgo, Map signedHashes) { if (mPrivateKeyState == PRIVATE_KEY_STATE_DIVERT_TO_CARD) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java index 7c009921d..7162a3366 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java @@ -29,6 +29,8 @@ import java.util.HashSet; * - ECC: 224 bit * - Symmetric: 3TDEA * - Digital Signature (hash A): SHA-224 - SHA-512 + * + * Many decisions are based on https://gist.github.com/coruus/68a8c65571e2b4225a69 */ public class PgpConstants { @@ -39,26 +41,36 @@ public class PgpConstants { // } // https://tools.ietf.org/html/rfc6637#section-13 + /* + PgpDecryptVerify: Secure Algorithms Whitelist + all other algorithms will be rejected with OpenPgpDecryptionResult.RESULT_INSECURE - // PgpDecryptVerify: Secure Algorithms Whitelist - // all other algorithms will be rejected with OpenPgpDecryptionResult.RESULT_INSECURE + No broken ciphers or ciphers with key length smaller than 128 bit are allowed! + */ public static HashSet sSymmetricAlgorithmsWhitelist = new HashSet<>(); static { sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_256); sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_192); sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_128); - sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.TWOFISH); + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.TWOFISH); // 128 bit } // all other algorithms will be rejected with OpenPgpSignatureResult.RESULT_INVALID_INSECURE public static HashSet sHashAlgorithmsWhitelist = new HashSet<>(); static { - sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA256); sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA512); sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA384); + /* + TODO: SHA256 and SHA224 are still allowed even though + coruus advises against it, to enable better backward compatibility + + coruus: + Implementations MUST NOT sign SHA-224 hashes. They SHOULD NOT accept signatures over SHA-224 hashes. + ((collision resistance of 112-bits)) + Implementations SHOULD NOT sign SHA-256 hashes. They MUST NOT default to signing SHA-256 hashes. + */ + sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA256); sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA224); - sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA1); - sHashAlgorithmsWhitelist.add(HashAlgorithmTags.RIPEMD160); } /* @@ -70,15 +82,15 @@ public class PgpConstants { SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192, SymmetricKeyAlgorithmTags.AES_128, - SymmetricKeyAlgorithmTags.TWOFISH }; - // NOTE: some implementations do not support SHA512, thus we choose SHA256 as default (Mailvelope?) + /* + coorus: + Implementations SHOULD use SHA-512 for RSA or DSA signatures. They SHOULD NOT use SHA-384. + ((cite to affine padding attacks; unproven status of RSA-PKCSv15)) + */ public static final int[] PREFERRED_HASH_ALGORITHMS = new int[]{ - HashAlgorithmTags.SHA256, HashAlgorithmTags.SHA512, - HashAlgorithmTags.SHA384, - HashAlgorithmTags.SHA224, }; /* @@ -89,19 +101,41 @@ public class PgpConstants { */ public static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[]{ CompressionAlgorithmTags.ZIP, - CompressionAlgorithmTags.ZLIB, - CompressionAlgorithmTags.BZIP2 }; - public static final int CERTIFY_HASH_ALGO = HashAlgorithmTags.SHA256; + public static final int CERTIFY_HASH_ALGO = HashAlgorithmTags.SHA512; + + /* + Always use AES-256! Ignore the preferred encryption algos of the recipient! + + coorus: + Implementations SHOULD ignore the symmetric algorithm preferences of a recipient's public key; + in particular, implementations MUST NOT choose an algorithm forbidden by this + document because a recipient prefers it. + NEEDCITE downgrade attacks on TLS, other protocols + */ public static final int DEFAULT_SYMMETRIC_ALGORITHM = SymmetricKeyAlgorithmTags.AES_256; public interface OpenKeychainSymmetricKeyAlgorithmTags extends SymmetricKeyAlgorithmTags { int USE_DEFAULT = -1; } - public static final int DEFAULT_HASH_ALGORITHM = HashAlgorithmTags.SHA256; + /* + Always use SHA-512! Ignore the preferred hash algos of the recipient! + + coorus: + Implementations MUST ignore the hash algorithm preferences of a recipient when signing + a message to a recipient. The difficulty of forging a signature under a given key, + using generic attacks on hash functions, is the difficulty of the weakest hash signed by that key. + + Implementations MUST default to using SHA-512 for RSA signatures, + + and either SHA-512 or the matched instance of SHA-2 for ECDSA signatures. + TODO: Ed25519 + CITE: zooko's hash function table CITE: distinguishers on SHA-256 + */ + public static final int DEFAULT_HASH_ALGORITHM = HashAlgorithmTags.SHA512; public interface OpenKeychainHashAlgorithmTags extends HashAlgorithmTags { int USE_DEFAULT = -1; } @@ -130,9 +164,9 @@ public class PgpConstants { * OpenKeychain: 0x90 */ public static final int SECRET_KEY_ENCRYPTOR_S2K_COUNT = 0x90; - public static final int SECRET_KEY_ENCRYPTOR_HASH_ALGO = HashAlgorithmTags.SHA256; + public static final int SECRET_KEY_ENCRYPTOR_HASH_ALGO = HashAlgorithmTags.SHA512; public static final int SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO = SymmetricKeyAlgorithmTags.AES_256; - public static final int SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO = HashAlgorithmTags.SHA256; + public static final int SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO = HashAlgorithmTags.SHA512; // NOTE: only SHA1 is supported for key checksum calculations in OpenPGP, // see http://tools.ietf.org/html/rfc488 0#section-5.5.3 public static final int SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO = HashAlgorithmTags.SHA1; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java index a2c5fa30d..8701c27dc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java @@ -226,17 +226,10 @@ public class PgpSignEncryptOperation extends BaseOperation { return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); } - // Use preferred hash algo + // Use requested hash algo int requestedAlgorithm = input.getSignatureHashAlgorithm(); - ArrayList supported = signingKey.getSupportedHashAlgorithms(); if (requestedAlgorithm == PgpConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT) { input.setSignatureHashAlgorithm(PgpConstants.DEFAULT_HASH_ALGORITHM); - // TODO - // get most preferred -// input.setSignatureHashAlgorithm(supported.get(0)); - } else if (!supported.contains(requestedAlgorithm)) { - log.add(LogType.MSG_PSE_ERROR_HASH_ALGO, indent); - return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); } } updateProgress(R.string.progress_preparing_streams, 2, 100); @@ -245,11 +238,9 @@ public class PgpSignEncryptOperation extends BaseOperation { PGPEncryptedDataGenerator cPk = null; if (enableEncryption) { - // Use preferred encryption algo + // Use requested encryption algo int algo = input.getSymmetricEncryptionAlgorithm(); if (algo == PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT) { - // get most preferred - // TODO: get from recipients algo = PgpConstants.DEFAULT_SYMMETRIC_ALGORITHM; } // has Integrity packet enabled! diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 144617cd2..071e085f3 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -1196,7 +1196,6 @@ "Preparing compression" "Encrypting data" "Bad password!" - "Requested hashing algorithm is not supported by this key!" "Encountered IO Exception during operation!" "Selected signing key cannot sign data!" "Error fetching signing key!" -- cgit v1.2.3 From 7c40d89eeaf1d50b00a3c6a901894a1db64c0142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sun, 2 Aug 2015 20:38:30 +0200 Subject: Use default compression in OpenPgpService --- .../java/org/sufficientlysecure/keychain/remote/OpenPgpService.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index 6f841fea2..10a7e1a88 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -33,7 +33,6 @@ import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpMetadata; import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.util.OpenPgpApi; -import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel; @@ -360,9 +359,9 @@ public class OpenPgpService extends RemoteService { boolean enableCompression = data.getBooleanExtra(OpenPgpApi.EXTRA_ENABLE_COMPRESSION, true); int compressionId; if (enableCompression) { - compressionId = CompressionAlgorithmTags.ZLIB; + compressionId = PgpConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT; } else { - compressionId = CompressionAlgorithmTags.UNCOMPRESSED; + compressionId = PgpConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED; } // first try to get key ids from non-ambiguous key id extra -- cgit v1.2.3 From 3d8eda6e3e3748e32e4c47a405cd8c6962e28a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sun, 2 Aug 2015 23:34:00 +0200 Subject: Improve comments and reasons in PgpConstants, simple checks for insecure asymmetric keys --- .../operations/results/OperationResult.java | 7 +- .../keychain/pgp/CanonicalizedSecretKey.java | 3 +- .../pgp/OpenPgpDecryptionResultBuilder.java | 59 +++++ .../keychain/pgp/PgpConstants.java | 174 ------------- .../keychain/pgp/PgpDecryptVerify.java | 55 ++-- .../keychain/pgp/PgpKeyOperation.java | 36 +-- .../keychain/pgp/PgpSecurityConstants.java | 282 +++++++++++++++++++++ .../keychain/pgp/PgpSignEncryptInputParcel.java | 4 +- .../keychain/pgp/PgpSignEncryptOperation.java | 13 +- .../keychain/pgp/UncachedPublicKey.java | 9 +- .../keychain/provider/ProviderHelper.java | 6 +- .../keychain/remote/OpenPgpService.java | 12 +- .../keychain/ui/EncryptFilesFragment.java | 11 +- .../keychain/ui/EncryptTextFragment.java | 11 +- OpenKeychain/src/main/res/values-de/strings.xml | 6 +- OpenKeychain/src/main/res/values-es/strings.xml | 6 +- OpenKeychain/src/main/res/values-eu/strings.xml | 4 +- OpenKeychain/src/main/res/values-fr/strings.xml | 6 +- OpenKeychain/src/main/res/values-ja/strings.xml | 6 +- OpenKeychain/src/main/res/values-nl/strings.xml | 6 +- OpenKeychain/src/main/res/values-ru/strings.xml | 4 +- OpenKeychain/src/main/res/values-sr/strings.xml | 2 +- OpenKeychain/src/main/res/values/strings.xml | 7 +- 23 files changed, 461 insertions(+), 268 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpDecryptionResultBuilder.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index b063e1e74..d498bd9a1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -611,14 +611,12 @@ public abstract class OperationResult implements Parcelable { MSG_DC_ERROR_CORRUPT_DATA (LogLevel.ERROR, R.string.msg_dc_error_corrupt_data), MSG_DC_ERROR_EXTRACT_KEY (LogLevel.ERROR, R.string.msg_dc_error_extract_key), MSG_DC_ERROR_INTEGRITY_CHECK (LogLevel.ERROR, R.string.msg_dc_error_integrity_check), - MSG_DC_ERROR_INTEGRITY_MISSING (LogLevel.ERROR, R.string.msg_dc_error_integrity_missing), MSG_DC_ERROR_INVALID_DATA (LogLevel.ERROR, R.string.msg_dc_error_invalid_data), MSG_DC_ERROR_IO (LogLevel.ERROR, R.string.msg_dc_error_io), MSG_DC_ERROR_INPUT (LogLevel.ERROR, R.string.msg_dc_error_input), MSG_DC_ERROR_NO_DATA (LogLevel.ERROR, R.string.msg_dc_error_no_data), MSG_DC_ERROR_NO_KEY (LogLevel.ERROR, R.string.msg_dc_error_no_key), MSG_DC_ERROR_PGP_EXCEPTION (LogLevel.ERROR, R.string.msg_dc_error_pgp_exception), - MSG_DC_ERROR_UNSUPPORTED_HASH_ALGO (LogLevel.ERROR, R.string.msg_dc_error_unsupported_hash_algo), MSG_DC_INTEGRITY_CHECK_OK (LogLevel.INFO, R.string.msg_dc_integrity_check_ok), MSG_DC_OK_META_ONLY (LogLevel.OK, R.string.msg_dc_ok_meta_only), MSG_DC_OK (LogLevel.OK, R.string.msg_dc_ok), @@ -633,7 +631,10 @@ public abstract class OperationResult implements Parcelable { MSG_DC_TRAIL_SYM (LogLevel.DEBUG, R.string.msg_dc_trail_sym), MSG_DC_TRAIL_UNKNOWN (LogLevel.DEBUG, R.string.msg_dc_trail_unknown), MSG_DC_UNLOCKING (LogLevel.INFO, R.string.msg_dc_unlocking), - MSG_DC_OLD_SYMMETRIC_ENCRYPTION_ALGO (LogLevel.WARN, R.string.msg_dc_old_symmetric_encryption_algo), + MSG_DC_INSECURE_SYMMETRIC_ENCRYPTION_ALGO(LogLevel.WARN, R.string.msg_dc_insecure_symmetric_encryption_algo), + MSG_DC_INSECURE_HASH_ALGO(LogLevel.ERROR, R.string.msg_dc_insecure_hash_algo), + MSG_DC_INSECURE_MDC_MISSING(LogLevel.ERROR, R.string.msg_dc_insecure_mdc_missing), + MSG_DC_INSECURE_KEY(LogLevel.ERROR, R.string.msg_dc_insecure_key), // verify signed literal data MSG_VL (LogLevel.INFO, R.string.msg_vl), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java index 23f02ac08..7394c07c3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -43,7 +43,6 @@ import org.sufficientlysecure.keychain.util.Passphrase; import java.nio.ByteBuffer; import java.security.PrivateKey; import java.security.interfaces.RSAPrivateCrtKey; -import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -195,7 +194,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { public PGPSignatureGenerator getCertSignatureGenerator(Map signedHashes) { PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder( - PgpConstants.CERTIFY_HASH_ALGO, signedHashes); + PgpSecurityConstants.CERTIFY_HASH_ALGO, signedHashes); if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) { throw new PrivateKeyNotUnlockedException(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpDecryptionResultBuilder.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpDecryptionResultBuilder.java new file mode 100644 index 000000000..c4525e5cd --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpDecryptionResultBuilder.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.pgp; + +import org.openintents.openpgp.OpenPgpDecryptionResult; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.util.Log; + +public class OpenPgpDecryptionResultBuilder { + + // builder + private boolean mInsecure = false; + private boolean mEncrypted = false; + + public void setInsecure(boolean insecure) { + this.mInsecure = insecure; + } + + public void setEncrypted(boolean encrypted) { + this.mEncrypted = encrypted; + } + + public OpenPgpDecryptionResult build() { + OpenPgpDecryptionResult result = new OpenPgpDecryptionResult(); + + if (mInsecure) { + Log.d(Constants.TAG, "RESULT_INSECURE"); + result.setResult(OpenPgpDecryptionResult.RESULT_INSECURE); + return result; + } + + if (mEncrypted) { + Log.d(Constants.TAG, "RESULT_ENCRYPTED"); + result.setResult(OpenPgpDecryptionResult.RESULT_ENCRYPTED); + } else { + Log.d(Constants.TAG, "RESULT_NOT_ENCRYPTED"); + result.setResult(OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED); + } + + return result; + } + + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java deleted file mode 100644 index 7162a3366..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2015 Dominik Schürmann - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.sufficientlysecure.keychain.pgp; - -import org.spongycastle.bcpg.CompressionAlgorithmTags; -import org.spongycastle.bcpg.HashAlgorithmTags; -import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; - -import java.util.HashSet; - -/** - * NIST requirements for 2011-2030 (http://www.keylength.com/en/4/): - * - RSA: 2048 bit - * - ECC: 224 bit - * - Symmetric: 3TDEA - * - Digital Signature (hash A): SHA-224 - SHA-512 - * - * Many decisions are based on https://gist.github.com/coruus/68a8c65571e2b4225a69 - */ -public class PgpConstants { - -// public interface MIN_REQUIREMENT { -// int MIN_BITS; -// int BINDING_SIGNATURE_HASH_ALGO; // for User IDs, subkeys,... -// int SYMMETRIC_ALGO; -// } - // https://tools.ietf.org/html/rfc6637#section-13 - - /* - PgpDecryptVerify: Secure Algorithms Whitelist - all other algorithms will be rejected with OpenPgpDecryptionResult.RESULT_INSECURE - - No broken ciphers or ciphers with key length smaller than 128 bit are allowed! - */ - public static HashSet sSymmetricAlgorithmsWhitelist = new HashSet<>(); - static { - sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_256); - sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_192); - sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_128); - sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.TWOFISH); // 128 bit - } - - // all other algorithms will be rejected with OpenPgpSignatureResult.RESULT_INVALID_INSECURE - public static HashSet sHashAlgorithmsWhitelist = new HashSet<>(); - static { - sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA512); - sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA384); - /* - TODO: SHA256 and SHA224 are still allowed even though - coruus advises against it, to enable better backward compatibility - - coruus: - Implementations MUST NOT sign SHA-224 hashes. They SHOULD NOT accept signatures over SHA-224 hashes. - ((collision resistance of 112-bits)) - Implementations SHOULD NOT sign SHA-256 hashes. They MUST NOT default to signing SHA-256 hashes. - */ - sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA256); - sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA224); - } - - /* - * Most preferred is first - * These arrays are written as preferred algorithms into the keys on creation. - * Other implementations may choose to honor this selection. - */ - public static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{ - SymmetricKeyAlgorithmTags.AES_256, - SymmetricKeyAlgorithmTags.AES_192, - SymmetricKeyAlgorithmTags.AES_128, - }; - - /* - coorus: - Implementations SHOULD use SHA-512 for RSA or DSA signatures. They SHOULD NOT use SHA-384. - ((cite to affine padding attacks; unproven status of RSA-PKCSv15)) - */ - public static final int[] PREFERRED_HASH_ALGORITHMS = new int[]{ - HashAlgorithmTags.SHA512, - }; - - /* - * Prefer ZIP - * "ZLIB provides no benefit over ZIP and is more malleable" - * - (OpenPGP WG mailinglist: "[openpgp] Intent to deprecate: Insecure primitives") - * BZIP2: very slow - */ - public static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[]{ - CompressionAlgorithmTags.ZIP, - }; - - public static final int CERTIFY_HASH_ALGO = HashAlgorithmTags.SHA512; - - - /* - Always use AES-256! Ignore the preferred encryption algos of the recipient! - - coorus: - Implementations SHOULD ignore the symmetric algorithm preferences of a recipient's public key; - in particular, implementations MUST NOT choose an algorithm forbidden by this - document because a recipient prefers it. - - NEEDCITE downgrade attacks on TLS, other protocols - */ - public static final int DEFAULT_SYMMETRIC_ALGORITHM = SymmetricKeyAlgorithmTags.AES_256; - public interface OpenKeychainSymmetricKeyAlgorithmTags extends SymmetricKeyAlgorithmTags { - int USE_DEFAULT = -1; - } - - /* - Always use SHA-512! Ignore the preferred hash algos of the recipient! - - coorus: - Implementations MUST ignore the hash algorithm preferences of a recipient when signing - a message to a recipient. The difficulty of forging a signature under a given key, - using generic attacks on hash functions, is the difficulty of the weakest hash signed by that key. - - Implementations MUST default to using SHA-512 for RSA signatures, - - and either SHA-512 or the matched instance of SHA-2 for ECDSA signatures. - TODO: Ed25519 - CITE: zooko's hash function table CITE: distinguishers on SHA-256 - */ - public static final int DEFAULT_HASH_ALGORITHM = HashAlgorithmTags.SHA512; - public interface OpenKeychainHashAlgorithmTags extends HashAlgorithmTags { - int USE_DEFAULT = -1; - } - - public static final int DEFAULT_COMPRESSION_ALGORITHM = CompressionAlgorithmTags.ZIP; - public interface OpenKeychainCompressionAlgorithmTags extends CompressionAlgorithmTags { - int USE_DEFAULT = -1; - } - - /* - * Note: s2kcount is a number between 0 and 0xff that controls the - * number of times to iterate the password hash before use. More - * iterations are useful against offline attacks, as it takes more - * time to check each password. The actual number of iterations is - * rather complex, and also depends on the hash function in use. - * Refer to Section 3.7.1.3 in rfc4880.txt. Bigger numbers give - * you more iterations. As a rough rule of thumb, when using - * SHA256 as the hashing function, 0x10 gives you about 64 - * iterations, 0x20 about 128, 0x30 about 256 and so on till 0xf0, - * or about 1 million iterations. The maximum you can go to is - * 0xff, or about 2 million iterations. - * from http://kbsriram.com/2013/01/generating-rsa-keys-with-bouncycastle.html - * - * Bouncy Castle default: 0x60 - * kbsriram proposes: 0xc0 - * OpenKeychain: 0x90 - */ - public static final int SECRET_KEY_ENCRYPTOR_S2K_COUNT = 0x90; - public static final int SECRET_KEY_ENCRYPTOR_HASH_ALGO = HashAlgorithmTags.SHA512; - public static final int SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO = SymmetricKeyAlgorithmTags.AES_256; - public static final int SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO = HashAlgorithmTags.SHA512; - // NOTE: only SHA1 is supported for key checksum calculations in OpenPGP, - // see http://tools.ietf.org/html/rfc488 0#section-5.5.3 - public static final int SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO = HashAlgorithmTags.SHA1; - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index d40bad3aa..1e51403fc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -321,7 +321,7 @@ public class PgpDecryptVerify extends BaseOperation InputStream in, OutputStream out, int indent) throws IOException, PGPException { OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); - OpenPgpDecryptionResult decryptionResult = new OpenPgpDecryptionResult(); + OpenPgpDecryptionResultBuilder decryptionResultBuilder = new OpenPgpDecryptionResultBuilder(); OperationLog log = new OperationLog(); log.add(LogType.MSG_DC, indent); @@ -464,6 +464,12 @@ public class PgpDecryptVerify extends BaseOperation } } + // check for insecure encryption key + if ( ! PgpSecurityConstants.isSecureKey(secretEncryptionKey)) { + log.add(LogType.MSG_DC_INSECURE_KEY, indent + 1); + decryptionResultBuilder.setInsecure(true); + } + // break out of while, only decrypt the first packet where we have a key break; @@ -614,12 +620,12 @@ public class PgpDecryptVerify extends BaseOperation log.add(LogType.MSG_DC_ERROR_NO_KEY, indent + 1); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } - decryptionResult.setResult(OpenPgpDecryptionResult.RESULT_ENCRYPTED); + decryptionResultBuilder.setEncrypted(true); // Check for insecure encryption algorithms! - if (!PgpConstants.sSymmetricAlgorithmsWhitelist.contains(symmetricEncryptionAlgo)) { - log.add(LogType.MSG_DC_OLD_SYMMETRIC_ENCRYPTION_ALGO, indent + 1); - decryptionResult.setResult(OpenPgpDecryptionResult.RESULT_INSECURE); + if (!PgpSecurityConstants.isSecureSymmetricAlgorithm(symmetricEncryptionAlgo)) { + log.add(LogType.MSG_DC_INSECURE_SYMMETRIC_ENCRYPTION_ALGO, indent + 1); + decryptionResultBuilder.setInsecure(true); } JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear); @@ -687,6 +693,13 @@ public class PgpDecryptVerify extends BaseOperation } } + // check for insecure signing key + // TODO: checks on signingRing ? + if (signingKey != null && ! PgpSecurityConstants.isSecureKey(signingKey)) { + log.add(LogType.MSG_DC_INSECURE_KEY, indent + 1); + signatureResultBuilder.setInsecure(true); + } + dataChunk = plainFact.nextObject(); } @@ -821,8 +834,8 @@ public class PgpDecryptVerify extends BaseOperation } // check for insecure hash algorithms - if (!PgpConstants.sHashAlgorithmsWhitelist.contains(signature.getHashAlgorithm())) { - log.add(LogType.MSG_DC_ERROR_UNSUPPORTED_HASH_ALGO, indent + 1); + if (!PgpSecurityConstants.isSecureHashAlgorithm(signature.getHashAlgorithm())) { + log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1); signatureResultBuilder.setInsecure(true); } @@ -850,8 +863,8 @@ public class PgpDecryptVerify extends BaseOperation // The MDC packet can be stripped by an attacker! Log.d(Constants.TAG, "MDC fail"); if (!signatureResultBuilder.isValidSignature()) { - log.add(LogType.MSG_DC_ERROR_INTEGRITY_MISSING, indent); - decryptionResult.setResult(OpenPgpDecryptionResult.RESULT_INSECURE); + log.add(LogType.MSG_DC_INSECURE_MDC_MISSING, indent); + decryptionResultBuilder.setInsecure(true); } } @@ -864,7 +877,7 @@ public class PgpDecryptVerify extends BaseOperation result.setCachedCryptoInputParcel(cryptoInput); result.setSignatureResult(signatureResultBuilder.build()); result.setCharset(charset); - result.setDecryptionResult(decryptionResult); + result.setDecryptionResult(decryptionResultBuilder.build()); result.setDecryptionMetadata(metadata); return result; @@ -921,7 +934,7 @@ public class PgpDecryptVerify extends BaseOperation return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } - PGPSignature signature = processPGPSignatureList(sigList, signatureResultBuilder); + PGPSignature signature = processPGPSignatureList(sigList, signatureResultBuilder, log, indent); if (signature != null) { try { @@ -954,8 +967,8 @@ public class PgpDecryptVerify extends BaseOperation } // check for insecure hash algorithms - if (!PgpConstants.sHashAlgorithmsWhitelist.contains(signature.getHashAlgorithm())) { - log.add(LogType.MSG_DC_ERROR_UNSUPPORTED_HASH_ALGO, indent + 1); + if (!PgpSecurityConstants.isSecureHashAlgorithm(signature.getHashAlgorithm())) { + log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1); signatureResultBuilder.setInsecure(true); } @@ -1013,7 +1026,7 @@ public class PgpDecryptVerify extends BaseOperation return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } - PGPSignature signature = processPGPSignatureList(sigList, signatureResultBuilder); + PGPSignature signature = processPGPSignatureList(sigList, signatureResultBuilder, log, indent); if (signature != null) { updateProgress(R.string.progress_reading_data, 60, 100); @@ -1056,8 +1069,8 @@ public class PgpDecryptVerify extends BaseOperation } // check for insecure hash algorithms - if (!PgpConstants.sHashAlgorithmsWhitelist.contains(signature.getHashAlgorithm())) { - log.add(LogType.MSG_DC_ERROR_UNSUPPORTED_HASH_ALGO, indent + 1); + if (!PgpSecurityConstants.isSecureHashAlgorithm(signature.getHashAlgorithm())) { + log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1); signatureResultBuilder.setInsecure(true); } @@ -1076,7 +1089,8 @@ public class PgpDecryptVerify extends BaseOperation } private PGPSignature processPGPSignatureList( - PGPSignatureList sigList, OpenPgpSignatureResultBuilder signatureResultBuilder) + PGPSignatureList sigList, OpenPgpSignatureResultBuilder signatureResultBuilder, + OperationLog log, int indent) throws PGPException { CanonicalizedPublicKeyRing signingRing = null; CanonicalizedPublicKey signingKey = null; @@ -1118,6 +1132,13 @@ public class PgpDecryptVerify extends BaseOperation } } + // check for insecure signing key + // TODO: checks on signingRing ? + if (signingKey != null && ! PgpSecurityConstants.isSecureKey(signingKey)) { + log.add(LogType.MSG_DC_INSECURE_KEY, indent + 1); + signatureResultBuilder.setInsecure(true); + } + return signature; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index a7eead939..6f156c201 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -316,14 +316,14 @@ public class PgpKeyOperation { // Build key encrypter and decrypter based on passphrase PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder() - .build().get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO); + .build().get(PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO); PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( - PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, - encryptorHashCalc, PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT) + PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, + encryptorHashCalc, PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray()); PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder() - .build().get(PgpConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO); + .build().get(PgpSecurityConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO); PGPSecretKey masterSecretKey = new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(), sha1Calc, true, keyEncryptor); @@ -1021,15 +1021,15 @@ public class PgpKeyOperation { PGPSecretKey sKey; { // Build key encrypter and decrypter based on passphrase PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder() - .build().get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO); + .build().get(PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO); PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( - PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, - PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT) + PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, + PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( cryptoInput.getPassphrase().getCharArray()); PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder() - .build().get(PgpConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO); + .build().get(PgpSecurityConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO); sKey = new PGPSecretKey(keyPair.getPrivateKey(), pKey, sha1Calc, false, keyEncryptor); } @@ -1206,7 +1206,7 @@ public class PgpKeyOperation { // add packet with EMPTY notation data (updates old one, but will be stripped later) PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( masterPrivateKey.getPublicKeyPacket().getAlgorithm(), - PgpConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO) + PgpSecurityConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); { // set subpackets @@ -1233,7 +1233,7 @@ public class PgpKeyOperation { // add packet with "pin" notation data PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( masterPrivateKey.getPublicKeyPacket().getAlgorithm(), - PgpConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO) + PgpSecurityConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); { // set subpackets @@ -1280,13 +1280,13 @@ public class PgpKeyOperation { OperationLog log, int indent) throws PGPException { PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build() - .get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO); + .get(PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO); PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray()); // Build key encryptor based on new passphrase PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder( - PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, - PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT) + PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, + PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(newPassphrase.getCharArray()); // noinspection unchecked @@ -1440,13 +1440,13 @@ public class PgpKeyOperation { if (divertToCard) { // use synchronous "NFC based" SignerBuilder builder = new NfcSyncPGPContentSignerBuilder( - pKey.getAlgorithm(), PgpConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO, + pKey.getAlgorithm(), PgpSecurityConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO, pKey.getKeyID(), cryptoInput.getCryptoData()) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); } else { // content signer based on signing key algorithm and chosen hash algorithm builder = new JcaPGPContentSignerBuilder( - pKey.getAlgorithm(), PgpConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO) + pKey.getAlgorithm(), PgpSecurityConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); } @@ -1472,11 +1472,11 @@ public class PgpKeyOperation { */ /* non-critical subpackets: */ hashedPacketsGen.setPreferredSymmetricAlgorithms(false, - PgpConstants.PREFERRED_SYMMETRIC_ALGORITHMS); + PgpSecurityConstants.PREFERRED_SYMMETRIC_ALGORITHMS); hashedPacketsGen.setPreferredHashAlgorithms(false, - PgpConstants.PREFERRED_HASH_ALGORITHMS); + PgpSecurityConstants.PREFERRED_HASH_ALGORITHMS); hashedPacketsGen.setPreferredCompressionAlgorithms(false, - PgpConstants.PREFERRED_COMPRESSION_ALGORITHMS); + PgpSecurityConstants.PREFERRED_COMPRESSION_ALGORITHMS); hashedPacketsGen.setPrimaryUserID(false, primary); /* critical subpackets: we consider those important for a modern pgp implementation */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java new file mode 100644 index 000000000..8762cde00 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.asn1.nist.NISTNamedCurves; +import org.spongycastle.bcpg.CompressionAlgorithmTags; +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.bcpg.PublicKeyAlgorithmTags; +import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; + +import java.util.HashSet; + +/** + * NIST requirements for 2011-2030 (http://www.keylength.com/en/4/): + * - RSA: 2048 bit + * - ECC: 224 bit + * - Symmetric: 3TDEA + * - Digital Signature (hash A): SHA-224 - SHA-512 + * + * Extreme Decisions for Yahoo's End-to-End: + * https://github.com/yahoo/end-to-end/issues/31 + * https://gist.github.com/coruus/68a8c65571e2b4225a69 + */ +public class PgpSecurityConstants { + + /* + * TODO: + * 1. Check binding signatures for requirements on import! throw out binding signatures with insecure + * signatures (bit length, hash algo) + * + * - put checks for curve OIDs and algorithm tags into import instead of PgpDecryptVerify? + * - check signingRing in PgpDecryptVerify? + * - ECC checks https://tools.ietf.org/html/rfc6637#section-13 + * - check encryption algo used for encrypting secret keys? + * - check S2K security? + * - check for min rsa/dsa/elgamal/ecc requirements in key creation backend + */ + + /** + * Whitelist of accepted symmetric encryption algorithms + * all other algorithms are rejected with OpenPgpDecryptionResult.RESULT_INSECURE + */ + private static HashSet sSymmetricAlgorithmsWhitelist = new HashSet<>(); + static { + // General remarks: We try to keep the whitelist short to reduce attack surface + // TODO: block IDEA?: Bad key schedule (weak keys), implementation difficulties (easy to make errors) + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.IDEA); + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.TRIPLE_DES); // a MUST in RFC + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.CAST5); // default in many gpg, pgp versions, 128 bit key + // BLOWFISH: Twofish is the successor + // SAFER: not used widely + // DES: < 128 bit security + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_128); + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_192); + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_256); + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.TWOFISH); // 128 bit + // CAMELLIA_128: not used widely + // CAMELLIA_192: not used widely + // CAMELLIA_256: not used widely + } + + public static boolean isSecureSymmetricAlgorithm(int id) { + return sSymmetricAlgorithmsWhitelist.contains(id); + } + + /** + * Whitelist of accepted hash algorithms + * all other algorithms are rejected with OpenPgpSignatureResult.RESULT_INSECURE + * + * coorus: + * Implementations SHOULD use SHA-512 for RSA or DSA signatures. They SHOULD NOT use SHA-384. + * ((cite to affine padding attacks; unproven status of RSA-PKCSv15)) + * + * Implementations MUST NOT sign SHA-224 hashes. They SHOULD NOT accept signatures over SHA-224 hashes. + * ((collision resistance of 112-bits)) + * Implementations SHOULD NOT sign SHA-256 hashes. They MUST NOT default to signing SHA-256 hashes. + */ + private static HashSet sHashAlgorithmsWhitelist = new HashSet<>(); + static { + // MD5: broken + // SHA1: broken + // RIPEMD160: same security properties as SHA1 + // DOUBLE_SHA: not used widely + // MD2: not used widely + // TIGER_192: not used widely + // HAVAL_5_160: not used widely + sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA256); // compatibility for old Mailvelope versions + sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA384); + sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA512); + // SHA224: Not used widely, Yahoo argues against it + } + + public static boolean isSecureHashAlgorithm(int id) { + return sHashAlgorithmsWhitelist.contains(id); + } + + /** + * Whitelist of accepted asymmetric algorithms in switch statement + * all other algorithms are rejected with OpenPgpSignatureResult.RESULT_INSECURE or + * OpenPgpDecryptionResult.RESULT_INSECURE + * + * REASON: + * Don't allow ELGAMAL_GENERAL (20), reason in RFC + * + * coorus: + * Implementations MUST NOT accept, or treat any signature as valid, by an RSA key with + * bitlength less than 1023 bits. + * Implementations MUST NOT accept any RSA keys with bitlength less than 2047 bits after January 1, 2016. + */ + private static HashSet sCurveWhitelist = new HashSet<>(); + static { + sCurveWhitelist.add(NISTNamedCurves.getOID("P-256").getId()); + sCurveWhitelist.add(NISTNamedCurves.getOID("P-384").getId()); + sCurveWhitelist.add(NISTNamedCurves.getOID("P-521").getId()); + } + + public static boolean isSecureKey(CanonicalizedPublicKey key) { + switch (key.getAlgorithm()) { + case PublicKeyAlgorithmTags.RSA_GENERAL: + case PublicKeyAlgorithmTags.RSA_ENCRYPT: + case PublicKeyAlgorithmTags.RSA_SIGN: { + return (key.getBitStrength() >= 2048); + } + + case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: { + return (key.getBitStrength() >= 2048); + } + + case PublicKeyAlgorithmTags.DSA: { + return (key.getBitStrength() >= 2048); + } + + case PublicKeyAlgorithmTags.ECDH: + case PublicKeyAlgorithmTags.ECDSA: { + return PgpSecurityConstants.sCurveWhitelist.contains(key.getCurveOid()); + } + // ELGAMAL_GENERAL: Must not be used, use ELGAMAL_ENCRYPT + // DIFFIE_HELLMAN: unsure + default: + return false; + } + } + + /** + * These array is written as a list of preferred encryption algorithms into keys created by us. + * Other implementations may choose to honor this selection. + * (Most preferred is first) + * + * REASON: See corresponding whitelist. AES received most cryptanalysis over the years + * and is still secure! + */ + public static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{ + SymmetricKeyAlgorithmTags.AES_256, + SymmetricKeyAlgorithmTags.AES_192, + SymmetricKeyAlgorithmTags.AES_128, + }; + + /** + * These array is written as a list of preferred hash algorithms into keys created by us. + * Other implementations may choose to honor this selection. + * (Most preferred is first) + * + * REASON: See corresponding whitelist. If possible use SHA-512, this is state of the art! + */ + public static final int[] PREFERRED_HASH_ALGORITHMS = new int[]{ + HashAlgorithmTags.SHA512, + }; + + /** + * These array is written as a list of preferred compression algorithms into keys created by us. + * Other implementations may choose to honor this selection. + * (Most preferred is first) + * + * REASON: See DEFAULT_COMPRESSION_ALGORITHM + */ + public static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[]{ + CompressionAlgorithmTags.ZIP, + }; + + /** + * Hash algorithm used to certify public keys + */ + public static final int CERTIFY_HASH_ALGO = HashAlgorithmTags.SHA512; + + + /** + * Always use AES-256! We always ignore the preferred encryption algos of the recipient! + * + * coorus: + * Implementations SHOULD ignore the symmetric algorithm preferences of a recipient's public key; + * in particular, implementations MUST NOT choose an algorithm forbidden by this + * document because a recipient prefers it. + * + * NEEDCITE downgrade attacks on TLS, other protocols + */ + public static final int DEFAULT_SYMMETRIC_ALGORITHM = SymmetricKeyAlgorithmTags.AES_256; + + public interface OpenKeychainSymmetricKeyAlgorithmTags extends SymmetricKeyAlgorithmTags { + int USE_DEFAULT = -1; + } + + /** + * Always use SHA-512! We always ignore the preferred hash algos of the recipient! + * + * coorus: + * Implementations MUST ignore the hash algorithm preferences of a recipient when signing + * a message to a recipient. The difficulty of forging a signature under a given key, + * using generic attacks on hash functions, is the difficulty of the weakest hash signed by that key. + * + * Implementations MUST default to using SHA-512 for RSA signatures, + * + * and either SHA-512 or the matched instance of SHA-2 for ECDSA signatures. + * TODO: Ed25519 + * CITE: zooko's hash function table CITE: distinguishers on SHA-256 + */ + public static final int DEFAULT_HASH_ALGORITHM = HashAlgorithmTags.SHA512; + + public interface OpenKeychainHashAlgorithmTags extends HashAlgorithmTags { + int USE_DEFAULT = -1; + } + + /** + * Compression is disabled by default. + * + * The default compression algorithm is only used if explicitly enabled in the activity's + * overflow menu or via the OpenPGP API's extra OpenPgpApi.EXTRA_ENABLE_COMPRESSION + * + * REASON: Enabling compression can lead to a sidechannel. Consider a voting that is done via + * OpenPGP. Compression can lead to different ciphertext lengths based on the user's voting. + * This has happened in a voting done by Wikipedia (Google it). + * + * ZLIB: the format provides no benefits over DEFLATE, and is more malleable + * BZIP2: very slow + */ + public static final int DEFAULT_COMPRESSION_ALGORITHM = CompressionAlgorithmTags.ZIP; + + public interface OpenKeychainCompressionAlgorithmTags extends CompressionAlgorithmTags { + int USE_DEFAULT = -1; + } + + /** + * Note: s2kcount is a number between 0 and 0xff that controls the + * number of times to iterate the password hash before use. More + * iterations are useful against offline attacks, as it takes more + * time to check each password. The actual number of iterations is + * rather complex, and also depends on the hash function in use. + * Refer to Section 3.7.1.3 in rfc4880.txt. Bigger numbers give + * you more iterations. As a rough rule of thumb, when using + * SHA256 as the hashing function, 0x10 gives you about 64 + * iterations, 0x20 about 128, 0x30 about 256 and so on till 0xf0, + * or about 1 million iterations. The maximum you can go to is + * 0xff, or about 2 million iterations. + * from http://kbsriram.com/2013/01/generating-rsa-keys-with-bouncycastle.html + * + * Bouncy Castle default: 0x60 + * kbsriram proposes: 0xc0 + * Yahoo's End-to-End: 96 (65536 iterations) (https://github.com/yahoo/end-to-end/blob/master/src/javascript/crypto/e2e/openpgp/keyring.js) + */ + public static final int SECRET_KEY_ENCRYPTOR_S2K_COUNT = 96; + public static final int SECRET_KEY_ENCRYPTOR_HASH_ALGO = HashAlgorithmTags.SHA512; + public static final int SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO = SymmetricKeyAlgorithmTags.AES_256; + public static final int SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO = HashAlgorithmTags.SHA512; + // NOTE: only SHA1 is supported for key checksum calculations in OpenPGP, + // see http://tools.ietf.org/html/rfc488 0#section-5.5.3 + public static final int SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO = HashAlgorithmTags.SHA1; + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java index 44e4b9221..7ae3f50aa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java @@ -33,10 +33,10 @@ public class PgpSignEncryptInputParcel implements Parcelable { protected int mCompressionAlgorithm = CompressionAlgorithmTags.UNCOMPRESSED; protected long[] mEncryptionMasterKeyIds = null; protected Passphrase mSymmetricPassphrase = null; - protected int mSymmetricEncryptionAlgorithm = PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT; + protected int mSymmetricEncryptionAlgorithm = PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT; protected long mSignatureMasterKeyId = Constants.key.none; protected Long mSignatureSubKeyId = null; - protected int mSignatureHashAlgorithm = PgpConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT; + protected int mSignatureHashAlgorithm = PgpSecurityConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT; protected long mAdditionalEncryptId = Constants.key.none; protected boolean mFailOnMissingEncryptionKeyIds = false; protected String mCharset; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java index 8701c27dc..1798baa8e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java @@ -62,7 +62,6 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.security.SignatureException; -import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.Set; @@ -228,8 +227,8 @@ public class PgpSignEncryptOperation extends BaseOperation { // Use requested hash algo int requestedAlgorithm = input.getSignatureHashAlgorithm(); - if (requestedAlgorithm == PgpConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT) { - input.setSignatureHashAlgorithm(PgpConstants.DEFAULT_HASH_ALGORITHM); + if (requestedAlgorithm == PgpSecurityConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT) { + input.setSignatureHashAlgorithm(PgpSecurityConstants.DEFAULT_HASH_ALGORITHM); } } updateProgress(R.string.progress_preparing_streams, 2, 100); @@ -240,8 +239,8 @@ public class PgpSignEncryptOperation extends BaseOperation { // Use requested encryption algo int algo = input.getSymmetricEncryptionAlgorithm(); - if (algo == PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT) { - algo = PgpConstants.DEFAULT_SYMMETRIC_ALGORITHM; + if (algo == PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT) { + algo = PgpSecurityConstants.DEFAULT_SYMMETRIC_ALGORITHM; } // has Integrity packet enabled! JcePGPDataEncryptorBuilder encryptorBuilder = @@ -337,8 +336,8 @@ public class PgpSignEncryptOperation extends BaseOperation { // Use preferred compression algo int algo = input.getCompressionAlgorithm(); - if (algo == PgpConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT) { - algo = PgpConstants.DEFAULT_COMPRESSION_ALGORITHM; + if (algo == PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT) { + algo = PgpSecurityConstants.DEFAULT_COMPRESSION_ALGORITHM; } compressGen = new PGPCompressedDataGenerator(algo); bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java index 9276cba10..26f046372 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -211,12 +211,19 @@ public class UncachedPublicKey { return getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT; } + public boolean isRSA() { + return getAlgorithm() == PGPPublicKey.RSA_GENERAL + || getAlgorithm() == PGPPublicKey.RSA_ENCRYPT + || getAlgorithm() == PGPPublicKey.RSA_SIGN; + } + public boolean isDSA() { return getAlgorithm() == PGPPublicKey.DSA; } public boolean isEC() { - return getAlgorithm() == PGPPublicKey.ECDH || getAlgorithm() == PGPPublicKey.ECDSA; + return getAlgorithm() == PGPPublicKey.ECDH + || getAlgorithm() == PGPPublicKey.ECDSA; } public byte[] getFingerprint() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 9abdbf8be..0c37bfc2a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -45,7 +45,7 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.pgp.PgpConstants; +import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedPublicKey; @@ -1434,9 +1434,9 @@ public class ProviderHelper { // DEPRECATED and thus hardcoded values.put(KeychainContract.ApiAccounts.COMPRESSION, CompressionAlgorithmTags.ZLIB); values.put(KeychainContract.ApiAccounts.ENCRYPTION_ALGORITHM, - PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); + PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); values.put(KeychainContract.ApiAccounts.HASH_ALORITHM, - PgpConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT); + PgpSecurityConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT); return values; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index 10a7e1a88..e1d7c0bc9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -37,7 +37,7 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel; import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; -import org.sufficientlysecure.keychain.pgp.PgpConstants; +import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel; import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInputParcel; @@ -248,7 +248,7 @@ public class OpenPgpService extends RemoteService { .setCleartextSignature(cleartextSign) .setDetachedSignature(!cleartextSign) .setVersionHeader(null) - .setSignatureHashAlgorithm(PgpConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT); + .setSignatureHashAlgorithm(PgpSecurityConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT); Intent signKeyIdIntent = getSignKeyMasterId(data); // NOTE: Fallback to return account settings (Old API) @@ -359,9 +359,9 @@ public class OpenPgpService extends RemoteService { boolean enableCompression = data.getBooleanExtra(OpenPgpApi.EXTRA_ENABLE_COMPRESSION, true); int compressionId; if (enableCompression) { - compressionId = PgpConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT; + compressionId = PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT; } else { - compressionId = PgpConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED; + compressionId = PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED; } // first try to get key ids from non-ambiguous key id extra @@ -392,7 +392,7 @@ public class OpenPgpService extends RemoteService { pseInput.setEnableAsciiArmorOutput(asciiArmor) .setVersionHeader(null) .setCompressionAlgorithm(compressionId) - .setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT) + .setSymmetricEncryptionAlgorithm(PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT) .setEncryptionMasterKeyIds(keyIds) .setFailOnMissingEncryptionKeyIds(true); @@ -421,7 +421,7 @@ public class OpenPgpService extends RemoteService { } // sign and encrypt - pseInput.setSignatureHashAlgorithm(PgpConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT) + pseInput.setSignatureHashAlgorithm(PgpSecurityConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT) .setAdditionalEncryptId(signKeyId); // add sign key for encryption } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index 7bf662da3..63d37f296 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -50,12 +50,11 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; -import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.pgp.PgpConstants; +import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; @@ -554,17 +553,17 @@ public class EncryptFilesFragment if (mUseCompression) { data.setCompressionAlgorithm( - PgpConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT); + PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT); } else { data.setCompressionAlgorithm( - PgpConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED); + PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED); } data.setHiddenRecipients(mHiddenRecipients); data.setEnableAsciiArmorOutput(mAfterEncryptAction == AfterEncryptAction.COPY || mUseArmor); data.setSymmetricEncryptionAlgorithm( - PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); + PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); data.setSignatureHashAlgorithm( - PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); + PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); EncryptActivity encryptActivity = (EncryptActivity) getActivity(); EncryptModeFragment modeFragment = encryptActivity.getModeFragment(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java index 60a2c9905..ab676285e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -33,12 +33,11 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.pgp.PgpConstants; +import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment; @@ -224,16 +223,16 @@ public class EncryptTextFragment if (mUseCompression) { data.setCompressionAlgorithm( - PgpConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT); + PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT); } else { data.setCompressionAlgorithm( - PgpConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED); + PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED); } data.setHiddenRecipients(mHiddenRecipients); data.setSymmetricEncryptionAlgorithm( - PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); + PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); data.setSignatureHashAlgorithm( - PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); + PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); // Always use armor for messages data.setEnableAsciiArmorOutput(true); diff --git a/OpenKeychain/src/main/res/values-de/strings.xml b/OpenKeychain/src/main/res/values-de/strings.xml index fe9963a91..084216301 100644 --- a/OpenKeychain/src/main/res/values-de/strings.xml +++ b/OpenKeychain/src/main/res/values-de/strings.xml @@ -953,7 +953,7 @@ Dateigröße unbekannt Änderungszeit: %s Signaturprüfung NICHT OK! - Nicht unterstützter und potentiell unsicherer Hash-Algorithmus! + Nicht unterstützter und potentiell unsicherer Hash-Algorithmus! Signaturdaten werden überprüft Signaturprüfung OK Speichere Signatur für später @@ -962,7 +962,7 @@ Daten beschädigt! Unbekannter Fehler bei Schlüsselentsperrung! Integritätsprüfungsfehler! - Fehlende Integritätsprüfung Dies kann passieren, wenn die Verschlüsselungsanwendung veraltet ist oder durch einen Downgrade-Angriff. + Fehlende Integritätsprüfung Dies kann passieren, wenn die Verschlüsselungsanwendung veraltet ist oder durch einen Downgrade-Angriff. Kein gültiger OpenPGP-verschlüsselter oder -signierter Inhalt! Keine verschlüsselten Daten in Datenstrom gefunden! Keine verschlüsselten Daten mit bekanntem geheimen Schlüssel in Datenstrom gefunden! @@ -981,7 +981,7 @@ Anhang gefunden, symmetrisch verschlüsselte Daten Anhängende Daten unbekannter Art gefunden Geheimer Schlüssel wird entsperrt - Ein potentiell unsicherer Verschlüsselungsalgorithmus wurde verwendet! + Ein potentiell unsicherer Verschlüsselungsalgorithmus wurde verwendet! Starte Signaturprüfung Keine Signaturliste in signierten Literaldaten diff --git a/OpenKeychain/src/main/res/values-es/strings.xml b/OpenKeychain/src/main/res/values-es/strings.xml index 2287ac121..a86e576ec 100644 --- a/OpenKeychain/src/main/res/values-es/strings.xml +++ b/OpenKeychain/src/main/res/values-es/strings.xml @@ -1007,7 +1007,7 @@ Tamaño de fichero desconocido Hora de la modificación: %s ¡Comprobación de firma NO CORRECTA! - ¡Algoritmo de identificador criptográfico (hash) no soportado y potencialmente inseguro! + ¡Algoritmo de identificador criptográfico (hash) no soportado y potencialmente inseguro! Verificando datos de firma Comprobación de firma CORRECTA Guardando datos de firma para más tarde @@ -1016,7 +1016,7 @@ ¡Los datos están corruptos! ¡Error desconocido al desbloquear clave! ¡Error de comprobación de integridad! - ¡Verificación de integridad ausente! Esto puede ocurrir porque la aplicación de cifrado no está actualizada, o debido a un ataque desactualización. + ¡Verificación de integridad ausente! Esto puede ocurrir porque la aplicación de cifrado no está actualizada, o debido a un ataque desactualización. ¡No se encontraron datos firmados o cifrados con OpenPGP válidos! ¡Se encontró un error al leer los datos de entrada! ¡Error al abrir el flujo de datos de entrada! @@ -1037,7 +1037,7 @@ Se encontró huella, datos cifrados simétricamente Se encontró huella, datos de tipo desconocido Desbloqueando clave secreta (privada) - ¡Se ha usado un algoritmo de cifrado potencialmente inseguro! + ¡Se ha usado un algoritmo de cifrado potencialmente inseguro! Comenzando comprobación de firma No hay lista de firmas en los datos literales firmados diff --git a/OpenKeychain/src/main/res/values-eu/strings.xml b/OpenKeychain/src/main/res/values-eu/strings.xml index ca17e0d61..d591d93e4 100644 --- a/OpenKeychain/src/main/res/values-eu/strings.xml +++ b/OpenKeychain/src/main/res/values-eu/strings.xml @@ -841,7 +841,7 @@ Agiri neurria ezezaguna da Aldaketa ordua: %s Sinadura egiaztapena EZ ONGI! - Hash algoritmo sostengatu gabea eta potentzialki segurtasun gabea! + Hash algoritmo sostengatu gabea eta potentzialki segurtasun gabea! Sinadura datuak egiaztatzen Sinadura egiaztapena ONGI Sinadura datuak gerorako gordetzen @@ -864,7 +864,7 @@ Dekriptaketa eragiketa abiatzen... Datu simetrikoak ez daude ahalbidetuta, jauzi egiten... Giltza sekretua desblokeatzen - Potentzialki segurtasun gabea den enkriptaketa algoritmoa erabili da! + Potentzialki segurtasun gabea den enkriptaketa algoritmoa erabili da! Sinadura egiaztapena abiatzen Mezua ez dago giltza zuzenarekin sinatuta diff --git a/OpenKeychain/src/main/res/values-fr/strings.xml b/OpenKeychain/src/main/res/values-fr/strings.xml index 96e7b9aba..fad65f955 100644 --- a/OpenKeychain/src/main/res/values-fr/strings.xml +++ b/OpenKeychain/src/main/res/values-fr/strings.xml @@ -981,7 +981,7 @@ La taille du fichier est inconnue Heure de modification : %s La vérification de la signature n\'est PAS CORRECTE ! - Algorithme de hachage non pris en charge et potentiellement non sécurisé ! + Algorithme de hachage non pris en charge et potentiellement non sécurisé ! Vérification des données de signature La vérification de la signature OK Enregistrement des données de signature pour plus tard @@ -990,7 +990,7 @@ Les données sont corrompues ! Erreur inconnue de déverrouillage de la clef ! Erreur de vérification de l\'intégrité ! - Vérification de l\'intégrité absente ! Ceci peut arriver car l\'application n\'est pas à jour, ou à cause d\'une attaque par mise à niveau inférieur. + Vérification de l\'intégrité absente ! Ceci peut arriver car l\'application n\'est pas à jour, ou à cause d\'une attaque par mise à niveau inférieur. Aucune donnée OpenPGP valide chiffrée ou signée n\'a été trouvée ! Aucune donnée chiffrée n\'a été trouvée dans le flux ! Aucune donnée chiffrée avec une clef secrète connue n\'a été trouvée dans le flux ! @@ -1009,7 +1009,7 @@ Des données traînantes chiffrées symétriquement ont été rencontrées Des données traînantes de type inconnu ont été rencontrées Déverrouillage de la clef secrète - Un algorithme de chiffrement possiblement non sécurisé à été utilisé ! + Un algorithme de chiffrement possiblement non sécurisé à été utilisé ! Lancement de la vérification de la signature Aucune liste de signatures dans les données littérales signées diff --git a/OpenKeychain/src/main/res/values-ja/strings.xml b/OpenKeychain/src/main/res/values-ja/strings.xml index 690fa0134..5de95f3c1 100644 --- a/OpenKeychain/src/main/res/values-ja/strings.xml +++ b/OpenKeychain/src/main/res/values-ja/strings.xml @@ -905,7 +905,7 @@ ファイルサイズが不明 更新日時: %s 署名の確認がOKではありません! - サポート外かつセキュアでない可能性があるハッシュアルゴリズム! + サポート外かつセキュアでない可能性があるハッシュアルゴリズム! 署名データの検証中 署名の確認はOKです 後程署名データを保存します @@ -913,7 +913,7 @@ 鍵のロック解除エラー、パスフレーズに問題があります! 鍵のロック解除で不明なエラー! 完全性チェックエラー! - 完全聖チェックの欠落!これは暗号化アプリケーションが期限切れになった場合、もしくは暗号強度低下攻撃がある場合に発生します。 + 完全聖チェックの欠落!これは暗号化アプリケーションが期限切れになった場合、もしくは暗号強度低下攻撃がある場合に発生します。 正常な署名データが見付からなかった! 操作中にIO例外に当たりました! ストリーム中に暗号化されたデータが見付からなかった! @@ -933,7 +933,7 @@ 追跡で遭遇、対称暗号化されたデータ 追跡で未知のタイプのデータに遭遇 秘密鍵のロック解除 - セキュアでない可能性がある暗号化アルゴリズムが利用されています! + セキュアでない可能性がある暗号化アルゴリズムが利用されています! 署名の確認開始 署名済み固定データに署名リストがありません diff --git a/OpenKeychain/src/main/res/values-nl/strings.xml b/OpenKeychain/src/main/res/values-nl/strings.xml index cc00ebd63..15c3f12d2 100644 --- a/OpenKeychain/src/main/res/values-nl/strings.xml +++ b/OpenKeychain/src/main/res/values-nl/strings.xml @@ -1007,7 +1007,7 @@ Bestandsgrootte onbekend Wijzigingstijd: %s Ondertekeningscontrole NIET OKÉ! - Niet ondersteund en mogelijk onveilig hash-algoritme! + Niet ondersteund en mogelijk onveilig hash-algoritme! Bezig met verifiëren van ondertekeningsgegevens Ondertekeningscontrole OKÉ Bezig met opslaan van ondertekeningsgegevens voor later @@ -1016,7 +1016,7 @@ Gegevens zijn corrupt! Onbekende fout bij ontgrendelen van sleutel! Fout bij integriteitscontrole! - Integriteitscheck ontbreekt! Dit kan gebeuren omdat de versleutelingsapplicatie verouderd is, of door een downgrade-aanval. + Integriteitscheck ontbreekt! Dit kan gebeuren omdat de versleutelingsapplicatie verouderd is, of door een downgrade-aanval. Geen geldige OpenPGP-versleutelde of ondertekende inhoud gevonden! Geen versleutelde gegevens gevonden! Geen versleutelde gegevens met bekende geheime sleutel gevonden! @@ -1035,7 +1035,7 @@ Achterlopende, symmetrisch versleutelde gegevens tegengekomen Achterlopende gegevens van onbekend type tegengekomen Bezig met ontgrendelen van geheime sleutel - Mogelijk onveilig versleutelingsalgoritme gebruikt! + Mogelijk onveilig versleutelingsalgoritme gebruikt! Ondertekeningscontrole wordt gestart Geen ondertekeningslijst in ondertekende letterlijke gegevens diff --git a/OpenKeychain/src/main/res/values-ru/strings.xml b/OpenKeychain/src/main/res/values-ru/strings.xml index c13796795..47c171728 100644 --- a/OpenKeychain/src/main/res/values-ru/strings.xml +++ b/OpenKeychain/src/main/res/values-ru/strings.xml @@ -726,7 +726,7 @@ Распаковка сжатых данных Неизвестный размер файла Проверка подписи НЕ ПРОЙДЕНА! - Неподдерживаемый, и потенциально небезопасный алгоритм хэширования! + Неподдерживаемый, и потенциально небезопасный алгоритм хэширования! Проверка подписи данных Проверка подписи ПРОЙДЕНА Сохранение данных подписи @@ -737,7 +737,7 @@ Расшифрование/проверка закончена Использование фразы-пароля из кэша Разблокировка секретного ключа - Был использован потенциально небезопасный алгоритм шифрования! + Был использован потенциально небезопасный алгоритм шифрования! Проверка подписи данных ОК diff --git a/OpenKeychain/src/main/res/values-sr/strings.xml b/OpenKeychain/src/main/res/values-sr/strings.xml index ed385c9c2..9d5121c44 100644 --- a/OpenKeychain/src/main/res/values-sr/strings.xml +++ b/OpenKeychain/src/main/res/values-sr/strings.xml @@ -915,7 +915,7 @@ Грешка откључавања кључа, погрешна лозинка! Непозната грешка откључавања кључа! Грешка провере интегритета! - Недостаје провера интегритета! Ово може да се деси ако је апликација за шифровање застарела, или услед напада старијег издања. + Недостаје провера интегритета! Ово може да се деси ако је апликација за шифровање застарела, или услед напада старијег издања. Нису нађени исправни подаци потписа! Наиђох на У/И изузетак током радње! Шифровани подаци нису нађени у току! diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 071e085f3..72406aaab 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -1134,7 +1134,6 @@ "File size is unknown" "Modification time: %s" "Signature check NOT OK!" - "Unsupported and potentially insecure hash algorithm!" "Verifying signature data" "Signature check OK" "Saving signature data for later" @@ -1144,7 +1143,6 @@ "Data is corrupt!" "Unknown error unlocking key!" "Integrity check error!" - "Missing integrity check! This can happen because the encrypting application is out of date, or from a downgrade attack." "No valid OpenPGP encrypted or signed data found!" "Encountered an error reading input data!" "Error opening input data stream!" @@ -1165,7 +1163,10 @@ "Encountered trailing, symmetrically encrypted data" "Encountered trailing data of unknown type" "Unlocking secret key" - "Insecure encryption algorithm has been used!" + "Insecure encryption algorithm has been used! This can happen because the application is out of date, or from an attack." + "Insecure hash algorithm has been used! This can happen because the application is out of date, or from an attack." + "Missing the Modification Detection Code (MDC) packet! This can happen because the encrypting application is out of date, or from a downgrade attack." + "Insecure key: Either the bit length of RSA/DSA/ElGamal is too short or the ECC curve/algorithm is considered insecure! This can happen because the application is out of date, or from an attack." "Starting signature check" -- cgit v1.2.3 From 87199383061208b30a312e12aca2b9b4efc7ec33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 10 Aug 2015 10:26:58 +0200 Subject: Move TODOs into issue --- .../keychain/pgp/PgpSecurityConstants.java | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java index 8762cde00..755899297 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java @@ -38,19 +38,6 @@ import java.util.HashSet; */ public class PgpSecurityConstants { - /* - * TODO: - * 1. Check binding signatures for requirements on import! throw out binding signatures with insecure - * signatures (bit length, hash algo) - * - * - put checks for curve OIDs and algorithm tags into import instead of PgpDecryptVerify? - * - check signingRing in PgpDecryptVerify? - * - ECC checks https://tools.ietf.org/html/rfc6637#section-13 - * - check encryption algo used for encrypting secret keys? - * - check S2K security? - * - check for min rsa/dsa/elgamal/ecc requirements in key creation backend - */ - /** * Whitelist of accepted symmetric encryption algorithms * all other algorithms are rejected with OpenPgpDecryptionResult.RESULT_INSECURE -- cgit v1.2.3 From 74c80d4a9d1cc6218c8fd0bfbe1243d30808f842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 10 Aug 2015 13:54:25 +0200 Subject: Dont allow RSA_SIGN, RSA_ENCRYPT, deprecated in RFC --- .../keychain/pgp/PgpSecurityConstants.java | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java index 755899297..94fb2d877 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java @@ -101,9 +101,6 @@ public class PgpSecurityConstants { * all other algorithms are rejected with OpenPgpSignatureResult.RESULT_INSECURE or * OpenPgpDecryptionResult.RESULT_INSECURE * - * REASON: - * Don't allow ELGAMAL_GENERAL (20), reason in RFC - * * coorus: * Implementations MUST NOT accept, or treat any signature as valid, by an RSA key with * bitlength less than 1023 bits. @@ -118,25 +115,21 @@ public class PgpSecurityConstants { public static boolean isSecureKey(CanonicalizedPublicKey key) { switch (key.getAlgorithm()) { - case PublicKeyAlgorithmTags.RSA_GENERAL: - case PublicKeyAlgorithmTags.RSA_ENCRYPT: - case PublicKeyAlgorithmTags.RSA_SIGN: { + case PublicKeyAlgorithmTags.RSA_GENERAL: { return (key.getBitStrength() >= 2048); } - + // RSA_ENCRYPT, RSA_SIGN: deprecated in RFC 4880, use RSA_GENERAL with key flags case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: { return (key.getBitStrength() >= 2048); } - case PublicKeyAlgorithmTags.DSA: { return (key.getBitStrength() >= 2048); } - case PublicKeyAlgorithmTags.ECDH: case PublicKeyAlgorithmTags.ECDSA: { return PgpSecurityConstants.sCurveWhitelist.contains(key.getCurveOid()); } - // ELGAMAL_GENERAL: Must not be used, use ELGAMAL_ENCRYPT + // ELGAMAL_GENERAL: deprecated in RFC 4880, use ELGAMAL_ENCRYPT // DIFFIE_HELLMAN: unsure default: return false; -- cgit v1.2.3 From acbb3edf9b3154d3e2e360aa7b8059ad9c9d77d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 10 Aug 2015 13:54:41 +0200 Subject: Fix test cases, add test cases (still 1 failing) --- .../keychain/pgp/PgpSignEncryptInputParcel.java | 15 +++++++++++++++ .../keychain/pgp/PgpSignEncryptOperation.java | 3 +-- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java index 7ae3f50aa..36d1a07cb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java @@ -43,6 +43,7 @@ public class PgpSignEncryptInputParcel implements Parcelable { protected boolean mCleartextSignature; protected boolean mDetachedSignature = false; protected boolean mHiddenRecipients = false; + protected boolean mIntegrityProtected = true; public PgpSignEncryptInputParcel() { @@ -68,6 +69,7 @@ public class PgpSignEncryptInputParcel implements Parcelable { mCleartextSignature = source.readInt() == 1; mDetachedSignature = source.readInt() == 1; mHiddenRecipients = source.readInt() == 1; + mIntegrityProtected = source.readInt() == 1; } @Override @@ -97,6 +99,7 @@ public class PgpSignEncryptInputParcel implements Parcelable { dest.writeInt(mCleartextSignature ? 1 : 0); dest.writeInt(mDetachedSignature ? 1 : 0); dest.writeInt(mHiddenRecipients ? 1 : 0); + dest.writeInt(mIntegrityProtected ? 1 : 0); } public String getCharset() { @@ -229,6 +232,18 @@ public class PgpSignEncryptInputParcel implements Parcelable { return this; } + public boolean isIntegrityProtected() { + return mIntegrityProtected; + } + + /** + * Only use for testing! Never disable integrity protection! + */ + public PgpSignEncryptInputParcel setIntegrityProtected(boolean integrityProtected) { + this.mIntegrityProtected = integrityProtected; + return this; + } + public boolean isHiddenRecipients() { return mHiddenRecipients; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java index 1798baa8e..29b2ef727 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java @@ -242,11 +242,10 @@ public class PgpSignEncryptOperation extends BaseOperation { if (algo == PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT) { algo = PgpSecurityConstants.DEFAULT_SYMMETRIC_ALGORITHM; } - // has Integrity packet enabled! JcePGPDataEncryptorBuilder encryptorBuilder = new JcePGPDataEncryptorBuilder(algo) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME) - .setWithIntegrityPacket(true); + .setWithIntegrityPacket(input.isIntegrityProtected()); cPk = new PGPEncryptedDataGenerator(encryptorBuilder); -- cgit v1.2.3 From ec76d56b82dbfabf30d14eff44b1f995b062c148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 10 Aug 2015 14:18:15 +0200 Subject: Fix API backward compat --- .../org/sufficientlysecure/keychain/remote/OpenPgpService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index e1d7c0bc9..ff49a2991 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -583,13 +583,13 @@ public class OpenPgpService extends RemoteService { } } - if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 6) { - // RESULT_INVALID_INSECURE has been added in version 6, fallback to RESULT_INVALID_SIGNATURE + if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 8) { + // RESULT_INVALID_INSECURE has been added in version 8, fallback to RESULT_INVALID_SIGNATURE if (signatureResult.getResult() == OpenPgpSignatureResult.RESULT_INVALID_INSECURE) { signatureResult.setResult(OpenPgpSignatureResult.RESULT_INVALID_SIGNATURE); } - // RESULT_NO_SIGNATURE has been added in version 6, before the signatureResult was null + // RESULT_NO_SIGNATURE has been added in version 8, before the signatureResult was null if (signatureResult.getResult() == OpenPgpSignatureResult.RESULT_NO_SIGNATURE) { result.putExtra(OpenPgpApi.RESULT_SIGNATURE, (Parcelable[]) null); } @@ -602,7 +602,7 @@ public class OpenPgpService extends RemoteService { } } - if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) >= 6) { + if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) >= 8) { OpenPgpDecryptionResult decryptionResult = pgpResult.getDecryptionResult(); if (decryptionResult != null) { result.putExtra(OpenPgpApi.RESULT_DECRYPTION, decryptionResult); -- cgit v1.2.3