aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xGraphics/get-material-icons.sh1
-rw-r--r--OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java60
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java14
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java24
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java108
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java106
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java30
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java20
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java96
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInput.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java18
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java16
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java14
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java54
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java39
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java27
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java149
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java124
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java36
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java97
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordEditText.java101
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthBarView.java117
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthView.java360
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java97
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_action_accounts.pngbin669 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_vpn_key_grey_24dp.pngbin0 -> 391 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_action_accounts.pngbin499 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_vpn_key_grey_24dp.pngbin0 -> 301 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_action_accounts.pngbin827 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_vpn_key_grey_24dp.pngbin0 -> 463 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_accounts.pngbin1212 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_vpn_key_grey_24dp.pngbin0 -> 714 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_action_accounts.pngbin1663 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_vpn_key_grey_24dp.pngbin0 -> 825 bytes
-rw-r--r--OpenKeychain/src/main/res/layout/add_user_id_dialog.xml3
-rw-r--r--OpenKeychain/src/main/res/layout/create_key_input_fragment.xml36
-rw-r--r--OpenKeychain/src/main/res/layout/decrypt_result_include.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml35
-rw-r--r--OpenKeychain/src/main/res/menu/encrypt_file_activity.xml5
-rw-r--r--OpenKeychain/src/main/res/menu/encrypt_text_activity.xml5
-rw-r--r--OpenKeychain/src/main/res/values/attr.xml14
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml12
-rw-r--r--OpenKeychain/src/main/res/xml/adv_preferences.xml71
-rw-r--r--OpenKeychain/src/main/res/xml/preference_headers.xml2
54 files changed, 1317 insertions, 623 deletions
diff --git a/Graphics/get-material-icons.sh b/Graphics/get-material-icons.sh
index 95df5ca9d..d34e572fc 100755
--- a/Graphics/get-material-icons.sh
+++ b/Graphics/get-material-icons.sh
@@ -35,6 +35,7 @@ python copy OpenKeychain navigation grey close 24
python copy OpenKeychain social grey person 24
python copy OpenKeychain social grey person_add 24
python copy OpenKeychain social grey share 24
+python copy OpenKeychain communication grey vpn_key 24
# navigation drawer sections
python copy OpenKeychain communication black vpn_key 24
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java
index c05f4a029..0af87ada4 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java
@@ -38,6 +38,7 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing.IteratorWithIOThrow;
import org.sufficientlysecure.keychain.pgp.WrappedSignature;
+import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
@@ -54,14 +55,15 @@ import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.security.Security;
+import java.util.ArrayList;
import java.util.Iterator;
+import java.util.Random;
+
@RunWith(RobolectricTestRunner.class)
@org.robolectric.annotation.Config(emulateSdk = 18) // Robolectric doesn't yet support 19
public class CertifyOperationTest {
- static String mPassphrase = TestingUtils.genPassphrase(true);
-
static UncachedKeyRing mStaticRing1, mStaticRing2;
static String mKeyPhrase1 = TestingUtils.genPassphrase(true);
static String mKeyPhrase2 = TestingUtils.genPassphrase(true);
@@ -74,6 +76,8 @@ public class CertifyOperationTest {
oldShadowStream = ShadowLog.stream;
// ShadowLog.stream = System.out;
+ Random random = new Random();
+
PgpKeyOperation op = new PgpKeyOperation(null);
{
@@ -102,8 +106,14 @@ public class CertifyOperationTest {
Algorithm.DSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
Algorithm.ELGAMAL, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
+
parcel.mAddUserIds.add("ditz");
- parcel.mNewUnlock = new ChangeUnlockParcel(null, "1234");
+ byte[] uatdata = new byte[random.nextInt(150)+10];
+ random.nextBytes(uatdata);
+ parcel.mAddUserAttribute.add(
+ WrappedUserAttribute.fromSubpacket(random.nextInt(100)+1, uatdata));
+
+ parcel.mNewUnlock = new ChangeUnlockParcel(mKeyPhrase2);
PgpEditKeyResult result = op.createSecretKeyRing(parcel);
Assert.assertTrue("initial test key creation must succeed", result.success());
@@ -140,7 +150,7 @@ public class CertifyOperationTest {
}
@Test
- public void testCertify() throws Exception {
+ public void testCertifyId() throws Exception {
CertifyOperation op = operationWithFakePassphraseCache(
mStaticRing1.getMasterKeyId(), mStaticRing1.getMasterKeyId(), mKeyPhrase1);
@@ -152,7 +162,8 @@ public class CertifyOperationTest {
}
CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId());
- actions.add(new CertifyAction(mStaticRing2.getMasterKeyId()));
+ actions.add(new CertifyAction(mStaticRing2.getMasterKeyId(),
+ mStaticRing2.getPublicKey().getUnorderedUserIds()));
CertifyResult result = op.certify(actions, null);
Assert.assertTrue("certification must succeed", result.success());
@@ -167,12 +178,42 @@ public class CertifyOperationTest {
}
@Test
+ public void testCertifyAttribute() throws Exception {
+ CertifyOperation op = operationWithFakePassphraseCache(
+ mStaticRing1.getMasterKeyId(), mStaticRing1.getMasterKeyId(), mKeyPhrase1);
+
+ {
+ CanonicalizedPublicKeyRing ring = new ProviderHelper(Robolectric.application)
+ .getCanonicalizedPublicKeyRing(mStaticRing2.getMasterKeyId());
+ Assert.assertEquals("public key must not be marked verified prior to certification",
+ Certs.UNVERIFIED, ring.getVerified());
+ }
+
+ CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId());
+ actions.add(new CertifyAction(mStaticRing2.getMasterKeyId(), null,
+ mStaticRing2.getPublicKey().getUnorderedUserAttributes()));
+ CertifyResult result = op.certify(actions, null);
+
+ Assert.assertTrue("certification must succeed", result.success());
+
+ {
+ CanonicalizedPublicKeyRing ring = new ProviderHelper(Robolectric.application)
+ .getCanonicalizedPublicKeyRing(mStaticRing2.getMasterKeyId());
+ Assert.assertEquals("new key must be verified now",
+ Certs.VERIFIED_SECRET, ring.getVerified());
+ }
+
+ }
+
+
+ @Test
public void testCertifySelf() throws Exception {
CertifyOperation op = operationWithFakePassphraseCache(
mStaticRing1.getMasterKeyId(), mStaticRing1.getMasterKeyId(), mKeyPhrase1);
CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId());
- actions.add(new CertifyAction(mStaticRing1.getMasterKeyId()));
+ actions.add(new CertifyAction(mStaticRing1.getMasterKeyId(),
+ mStaticRing2.getPublicKey().getUnorderedUserIds()));
CertifyResult result = op.certify(actions, null);
@@ -188,7 +229,9 @@ public class CertifyOperationTest {
{
CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId());
- actions.add(new CertifyAction(1234L));
+ ArrayList<String> uids = new ArrayList<String>();
+ uids.add("nonexistent");
+ actions.add(new CertifyAction(1234L, uids));
CertifyResult result = op.certify(actions, null);
@@ -199,7 +242,8 @@ public class CertifyOperationTest {
{
CertifyActionsParcel actions = new CertifyActionsParcel(1234L);
- actions.add(new CertifyAction(mStaticRing1.getMasterKeyId()));
+ actions.add(new CertifyAction(mStaticRing1.getMasterKeyId(),
+ mStaticRing2.getPublicKey().getUnorderedUserIds()));
CertifyResult result = op.certify(actions, null);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
index 2d3ee6188..30d855a74 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
@@ -19,6 +19,8 @@ package org.sufficientlysecure.keychain;
import android.os.Environment;
+import org.spongycastle.bcpg.HashAlgorithmTags;
+import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import java.io.File;
@@ -26,6 +28,8 @@ import java.io.File;
public final class Constants {
public static final boolean DEBUG = BuildConfig.DEBUG;
+ public static final boolean DEBUG_LOG_DB_QUERIES = false;
+ public static final boolean DEBUG_SYNC_REMOVE_CONTACTS = false;
public static final String TAG = "Keychain";
@@ -60,24 +64,17 @@ public final class Constants {
}
public static final class Pref {
- public static final String DEFAULT_ENCRYPTION_ALGORITHM = "defaultEncryptionAlgorithm";
- public static final String DEFAULT_HASH_ALGORITHM = "defaultHashAlgorithm";
- public static final String DEFAULT_ASCII_ARMOR = "defaultAsciiArmor";
- public static final String DEFAULT_MESSAGE_COMPRESSION = "defaultMessageCompression";
- public static final String DEFAULT_FILE_COMPRESSION = "defaultFileCompression";
public static final String PASSPHRASE_CACHE_TTL = "passphraseCacheTtl";
public static final String PASSPHRASE_CACHE_SUBS = "passphraseCacheSubs";
public static final String LANGUAGE = "language";
public static final String KEY_SERVERS = "keyServers";
public static final String PREF_DEFAULT_VERSION = "keyServersDefaultVersion";
- public static final String WRITE_VERSION_HEADER = "writeVersionHeader";
public static final String FIRST_TIME = "firstTime";
- public static final String SHOW_ADVANCED_TABS = "showAdvancedTabs";
public static final String CACHED_CONSOLIDATE = "cachedConsolidate";
public static final String SEARCH_KEYSERVER = "search_keyserver_pref";
public static final String SEARCH_KEYBASE = "search_keybase_pref";
public static final String USE_DEFAULT_YUBIKEY_PIN = "useDefaultYubikeyPin";
- public static final String USE_NUMKEYPAD_FOR_YUBIKEY_PIN="useNumKeypadForYubikeyPin";
+ public static final String USE_NUMKEYPAD_FOR_YUBIKEY_PIN = "useNumKeypadForYubikeyPin";
}
public static final class Defaults {
@@ -89,4 +86,5 @@ public final class Constants {
public static final int none = 0;
public static final int symmetric = -1;
}
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
index 025f45f7f..2e9551826 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
@@ -101,18 +101,26 @@ public class CertifyOperation extends BaseOperation {
continue;
}
- if (action.mUserIds == null) {
- log.add(LogType.MSG_CRT_CERTIFY_ALL, 2,
- KeyFormattingUtils.convertKeyIdToHex(action.mMasterKeyId));
- } else {
- log.add(LogType.MSG_CRT_CERTIFY_SOME, 2, action.mUserIds.size(),
+ CanonicalizedPublicKeyRing publicRing =
+ mProviderHelper.getCanonicalizedPublicKeyRing(action.mMasterKeyId);
+
+ UncachedKeyRing certifiedKey = null;
+ if (action.mUserIds != null) {
+ log.add(LogType.MSG_CRT_CERTIFY_UIDS, 2, action.mUserIds.size(),
KeyFormattingUtils.convertKeyIdToHex(action.mMasterKeyId));
+
+ certifiedKey = certificationKey.certifyUserIds(
+ publicRing, action.mUserIds, null, null);
}
- CanonicalizedPublicKeyRing publicRing =
- mProviderHelper.getCanonicalizedPublicKeyRing(action.mMasterKeyId);
+ if (action.mUserAttributes != null) {
+ log.add(LogType.MSG_CRT_CERTIFY_UATS, 2, action.mUserAttributes.size(),
+ KeyFormattingUtils.convertKeyIdToHex(action.mMasterKeyId));
+
+ certifiedKey = certificationKey.certifyUserAttributes(
+ publicRing, action.mUserAttributes, null, null);
+ }
- UncachedKeyRing certifiedKey = certificationKey.certifyUserIds(publicRing, action.mUserIds, null, null);
if (certifiedKey == null) {
certifyError += 1;
log.add(LogType.MSG_CRT_WARN_CERT_FAILED, 3);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java
index 8f10377cd..20dba95e9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java
@@ -505,10 +505,6 @@ public class ImportExportOperation extends BaseOperation {
// Create an output stream
try {
arOutStream = new ArmoredOutputStream(outStream);
- String version = PgpHelper.getVersionForHeader(mContext);
- if (version != null) {
- arOutStream.setHeader("Version", version);
- }
log.add(LogType.MSG_EXPORT_PUBLIC, 1, KeyFormattingUtils.beautifyKeyId(keyId));
@@ -533,10 +529,6 @@ public class ImportExportOperation extends BaseOperation {
if (exportSecret && cursor.getInt(3) > 0) {
try {
arOutStream = new ArmoredOutputStream(outStream);
- String version = PgpHelper.getVersionForHeader(mContext);
- if (version != null) {
- arOutStream.setHeader("Version", version);
- }
// export secret key part
log.add(LogType.MSG_EXPORT_SECRET, 2, KeyFormattingUtils.beautifyKeyId(keyId));
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 a856a4fc3..7999af667 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
@@ -626,6 +626,7 @@ public abstract class OperationResult implements Parcelable {
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),
@@ -640,6 +641,7 @@ 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),
// verify signed literal data
MSG_VL (LogLevel.INFO, R.string.msg_vl),
@@ -689,8 +691,8 @@ public abstract class OperationResult implements Parcelable {
MSG_PSE_SYMMETRIC (LogLevel.INFO, R.string.msg_pse_symmetric),
MSG_CRT_CERTIFYING (LogLevel.DEBUG, R.string.msg_crt_certifying),
- MSG_CRT_CERTIFY_ALL (LogLevel.DEBUG, R.string.msg_crt_certify_all),
- MSG_CRT_CERTIFY_SOME (LogLevel.DEBUG, R.plurals.msg_crt_certify_some),
+ MSG_CRT_CERTIFY_UIDS (LogLevel.DEBUG, R.plurals.msg_crt_certify_uids),
+ MSG_CRT_CERTIFY_UATS (LogLevel.DEBUG, R.plurals.msg_crt_certify_uats),
MSG_CRT_ERROR_SELF (LogLevel.ERROR, R.string.msg_crt_error_self),
MSG_CRT_ERROR_MASTER_NOT_FOUND (LogLevel.ERROR, R.string.msg_crt_error_master_not_found),
MSG_CRT_ERROR_NOTHING (LogLevel.ERROR, R.string.msg_crt_error_nothing),
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 40f2f48ad..c3fccc789 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
@@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.pgp;
import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.bcpg.S2K;
+import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPPublicKey;
@@ -29,6 +30,7 @@ import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureGenerator;
import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
+import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector;
import org.spongycastle.openpgp.PGPUtil;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
@@ -44,6 +46,7 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
+import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
@@ -137,7 +140,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
// It means the passphrase is empty
return SecretKeyType.PASSPHRASE_EMPTY;
} catch (PGPException e) {
- HashMap<String,String> notation = getRing().getLocalNotationData();
+ HashMap<String, String> notation = getRing().getLocalNotationData();
if (notation.containsKey("unlock.pin@sufficientlysecure.org")
&& "1".equals(notation.get("unlock.pin@sufficientlysecure.org"))) {
return SecretKeyType.PIN;
@@ -176,33 +179,13 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
}
/**
- * Returns a list of all supported hash algorithms. This list is currently hardcoded to return
- * a limited set of algorithms supported by Yubikeys.
- *
- * @return
+ * Returns a list of all supported hash algorithms.
*/
- public LinkedList<Integer> getSupportedHashAlgorithms() {
- LinkedList<Integer> supported = new LinkedList<>();
-
- if (mPrivateKeyState == PRIVATE_KEY_STATE_DIVERT_TO_CARD) {
- // No support for MD5
- supported.add(HashAlgorithmTags.RIPEMD160);
- supported.add(HashAlgorithmTags.SHA1);
- supported.add(HashAlgorithmTags.SHA224);
- supported.add(HashAlgorithmTags.SHA256);
- supported.add(HashAlgorithmTags.SHA384);
- supported.add(HashAlgorithmTags.SHA512); // preferred is latest
- } else {
- supported.add(HashAlgorithmTags.MD5);
- supported.add(HashAlgorithmTags.RIPEMD160);
- supported.add(HashAlgorithmTags.SHA1);
- supported.add(HashAlgorithmTags.SHA224);
- supported.add(HashAlgorithmTags.SHA256);
- supported.add(HashAlgorithmTags.SHA384);
- supported.add(HashAlgorithmTags.SHA512); // preferred is latest
- }
+ public ArrayList<Integer> getSupportedHashAlgorithms() {
+ // TODO: intersection between preferred hash algos of this key and PgpConstants.PREFERRED_HASH_ALGORITHMS
+ // choose best algo
- return supported;
+ return PgpConstants.sPreferredHashAlgorithms;
}
private PGPContentSignerBuilder getContentSignerBuilder(int hashAlgo, byte[] nfcSignedHash,
@@ -286,7 +269,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
* Certify the given pubkeyid with the given masterkeyid.
*
* @param publicKeyRing Keyring to add certification to.
- * @param userIds User IDs to certify, or all if null
+ * @param userIds User IDs to certify
* @return A keyring with added certifications
*/
public UncachedKeyRing certifyUserIds(CanonicalizedPublicKeyRing publicKeyRing, List<String> userIds,
@@ -331,10 +314,8 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
PGPPublicKey publicKey = publicKeyRing.getPublicKey().getPublicKey();
// fetch public key ring, add the certification and return it
- Iterable<String> it = userIds != null ? userIds
- : new IterableIterator<String>(publicKey.getUserIDs());
try {
- for (String userId : it) {
+ for (String userId : userIds) {
PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey);
publicKey = PGPPublicKey.addCertification(publicKey, userId, sig);
}
@@ -348,6 +329,71 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
return new UncachedKeyRing(ring);
}
+ /**
+ * Certify the given user attributes with the given masterkeyid.
+ *
+ * @param publicKeyRing Keyring to add certification to.
+ * @param userAttributes User IDs to certify, or all if null
+ * @return A keyring with added certifications
+ */
+ public UncachedKeyRing certifyUserAttributes(CanonicalizedPublicKeyRing publicKeyRing,
+ List<WrappedUserAttribute> userAttributes, byte[] nfcSignedHash, Date nfcCreationTimestamp) {
+ if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {
+ throw new PrivateKeyNotUnlockedException();
+ }
+ if (!isMasterKey()) {
+ throw new AssertionError("tried to certify with non-master key, this is a programming error!");
+ }
+ if (publicKeyRing.getMasterKeyId() == getKeyId()) {
+ throw new AssertionError("key tried to self-certify, this is a programming error!");
+ }
+
+ // create a signatureGenerator from the supplied masterKeyId and passphrase
+ PGPSignatureGenerator signatureGenerator;
+ {
+ // TODO: SHA256 fixed?
+ PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(PGPUtil.SHA256,
+ nfcSignedHash, nfcCreationTimestamp);
+
+ signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
+ try {
+ signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, mPrivateKey);
+ } catch (PGPException e) {
+ Log.e(Constants.TAG, "signing error", e);
+ return null;
+ }
+ }
+
+ { // supply signatureGenerator with a SubpacketVector
+ PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+ if (nfcCreationTimestamp != null) {
+ spGen.setSignatureCreationTime(false, nfcCreationTimestamp);
+ Log.d(Constants.TAG, "For NFC: set sig creation time to " + nfcCreationTimestamp);
+ }
+ PGPSignatureSubpacketVector packetVector = spGen.generate();
+ signatureGenerator.setHashedSubpackets(packetVector);
+ }
+
+ // get the master subkey (which we certify for)
+ PGPPublicKey publicKey = publicKeyRing.getPublicKey().getPublicKey();
+
+ // fetch public key ring, add the certification and return it
+ try {
+ for (WrappedUserAttribute userAttribute : userAttributes) {
+ PGPUserAttributeSubpacketVector vector = userAttribute.getVector();
+ PGPSignature sig = signatureGenerator.generateCertification(vector, publicKey);
+ publicKey = PGPPublicKey.addCertification(publicKey, vector, sig);
+ }
+ } catch (PGPException e) {
+ Log.e(Constants.TAG, "signing error", e);
+ return null;
+ }
+
+ PGPPublicKeyRing ring = PGPPublicKeyRing.insertPublicKey(publicKeyRing.getRing(), publicKey);
+
+ return new UncachedKeyRing(ring);
+ }
+
static class PrivateKeyNotUnlockedException extends RuntimeException {
// this exception is a programming error which happens when an operation which requires
// the private key is called without a previous call to unlock()
@@ -358,7 +404,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
}
// HACK, for TESTING ONLY!!
- PGPPrivateKey getPrivateKey () {
+ PGPPrivateKey getPrivateKey() {
return mPrivateKey;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java
index b5f6a5b09..97b5fa6fe 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java
@@ -19,11 +19,11 @@
package org.sufficientlysecure.keychain.pgp;
import org.spongycastle.openpgp.PGPKeyRing;
-import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
+import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.util.IterableIterator;
@@ -45,7 +45,7 @@ public class CanonicalizedSecretKeyRing extends CanonicalizedKeyRing {
public CanonicalizedSecretKeyRing(byte[] blob, boolean isRevoked, int verified)
{
super(verified);
- PGPObjectFactory factory = new PGPObjectFactory(blob);
+ JcaPGPObjectFactory factory = new JcaPGPObjectFactory(blob);
PGPKeyRing keyRing = null;
try {
if ((keyRing = (PGPKeyRing) factory.nextObject()) == null) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java
new file mode 100644
index 000000000..90991ba15
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.pgp;
+
+import org.spongycastle.bcpg.CompressionAlgorithmTags;
+import org.spongycastle.bcpg.HashAlgorithmTags;
+import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
+
+import java.util.ArrayList;
+
+public class PgpConstants {
+
+ public static ArrayList<Integer> sPreferredSymmetricAlgorithms = new ArrayList<>();
+ public static ArrayList<Integer> sPreferredHashAlgorithms = new ArrayList<>();
+ public static ArrayList<Integer> sPreferredCompressionAlgorithms = new ArrayList<>();
+
+ // TODO: use hashmaps for contains in O(1) and intersections!
+
+ /*
+ * 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);
+
+ sPreferredCompressionAlgorithms.add(CompressionAlgorithmTags.ZLIB);
+ sPreferredCompressionAlgorithms.add(CompressionAlgorithmTags.BZIP2);
+ sPreferredCompressionAlgorithms.add(CompressionAlgorithmTags.ZIP);
+ }
+
+ /*
+ * 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.SHA256;
+ public static final int SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO = SymmetricKeyAlgorithmTags.AES_256;
+ public static final int SECRET_KEY_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<Integer> 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 2ba0b6231..14bc56538 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -563,6 +563,7 @@ public class PgpDecryptVerify extends BaseOperation {
log.add(LogType.MSG_DC_PREP_STREAMS, indent);
// we made sure above one of these two would be true
+ int symmetricEncryptionAlgo;
if (symmetricPacketFound) {
currentProgress += 2;
updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
@@ -576,6 +577,7 @@ public class PgpDecryptVerify extends BaseOperation {
clear = encryptedDataSymmetric.getDataStream(decryptorFactory);
encryptedData = encryptedDataSymmetric;
+ symmetricEncryptionAlgo = encryptedDataSymmetric.getSymmetricAlgorithm(decryptorFactory);
} else if (asymmetricPacketFound) {
currentProgress += 2;
updateProgress(R.string.progress_extracting_key, currentProgress, 100);
@@ -598,6 +600,8 @@ public class PgpDecryptVerify extends BaseOperation {
PublicKeyDataDecryptorFactory decryptorFactory
= secretEncryptionKey.getDecryptorFactory(mDecryptedSessionKey);
clear = encryptedDataAsymmetric.getDataStream(decryptorFactory);
+
+ symmetricEncryptionAlgo = encryptedDataAsymmetric.getSymmetricAlgorithm(decryptorFactory);
} catch (NfcSyncPublicKeyDataDecryptorFactoryBuilder.NfcInteractionNeeded e) {
log.add(LogType.MSG_DC_PENDING_NFC, indent + 1);
DecryptVerifyResult result =
@@ -614,6 +618,11 @@ public class PgpDecryptVerify extends BaseOperation {
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
}
+ // Warn about old encryption algorithms!
+ if (!PgpConstants.sPreferredSymmetricAlgorithms.contains(symmetricEncryptionAlgo)) {
+ log.add(LogType.MSG_DC_OLD_SYMMETRIC_ENCRYPTION_ALGO, indent + 1);
+ }
+
JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear);
Object dataChunk = plainFact.nextObject();
OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
@@ -811,6 +820,13 @@ public class PgpDecryptVerify extends BaseOperation {
} else {
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;
+ log.add(LogType.MSG_DC_ERROR_UNSUPPORTED_HASH_ALGO, indent + 1);
+ }
+
signatureResultBuilder.setValidSignature(validSignature);
}
@@ -936,6 +952,13 @@ public class PgpDecryptVerify extends BaseOperation {
} else {
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;
+ log.add(LogType.MSG_DC_ERROR_UNSUPPORTED_HASH_ALGO, indent + 1);
+ }
+
signatureResultBuilder.setValidSignature(validSignature);
} catch (SignatureException e) {
@@ -1024,6 +1047,13 @@ public class PgpDecryptVerify extends BaseOperation {
} else {
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;
+ log.add(LogType.MSG_DC_ERROR_UNSUPPORTED_HASH_ALGO, indent + 1);
+ }
+
signatureResultBuilder.setValidSignature(validSignature);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
index 12de2f637..d8b86a18c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
@@ -47,26 +47,6 @@ public class PgpHelper {
".*?(-----BEGIN PGP PUBLIC KEY BLOCK-----.*?-----END PGP PUBLIC KEY BLOCK-----).*",
Pattern.DOTALL);
- public static String getVersion(Context context) {
- String version;
- try {
- PackageInfo pi = context.getPackageManager().getPackageInfo(Constants.PACKAGE_NAME, 0);
- version = pi.versionName;
- return version;
- } catch (NameNotFoundException e) {
- Log.e(Constants.TAG, "Version could not be retrieved!", e);
- return "0.0";
- }
- }
-
- public static String getVersionForHeader(Context context) {
- if(Preferences.getPreferences(context).getWriteVersionHeader()){
- return "OpenKeychain v" + getVersion(context);
- } else {
- return null;
- }
- }
-
/**
* Deletes file securely by overwriting it with random data before deleting it.
* <p/>
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 da0394573..8fb5392e3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -18,9 +18,7 @@
package org.sufficientlysecure.keychain.pgp;
-import org.spongycastle.bcpg.CompressionAlgorithmTags;
import org.spongycastle.bcpg.HashAlgorithmTags;
-import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.spongycastle.bcpg.sig.Features;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.jce.spec.ElGamalParameterSpec;
@@ -90,49 +88,6 @@ public class PgpKeyOperation {
private Stack<Progressable> mProgress;
private AtomicBoolean mCancelled;
- // most preferred is first
- private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{
- SymmetricKeyAlgorithmTags.AES_256,
- SymmetricKeyAlgorithmTags.AES_192,
- SymmetricKeyAlgorithmTags.AES_128,
- SymmetricKeyAlgorithmTags.CAST5
- };
- private static final int[] PREFERRED_HASH_ALGORITHMS = new int[]{
- HashAlgorithmTags.SHA512,
- HashAlgorithmTags.SHA384,
- HashAlgorithmTags.SHA256,
- HashAlgorithmTags.SHA224,
- HashAlgorithmTags.RIPEMD160
- };
- private static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[]{
- CompressionAlgorithmTags.ZLIB,
- CompressionAlgorithmTags.BZIP2,
- CompressionAlgorithmTags.ZIP
- };
-
- /*
- * 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
- * we use 0x90, a good trade-off between usability and security against offline attacks
- */
- private static final int SECRET_KEY_ENCRYPTOR_S2K_COUNT = 0x90;
- private static final int SECRET_KEY_ENCRYPTOR_HASH_ALGO = HashAlgorithmTags.SHA256;
- private static final int SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO = SymmetricKeyAlgorithmTags.AES_256;
- private static final int SECRET_KEY_SIGNATURE_HASH_ALGO = HashAlgorithmTags.SHA256;
-
public PgpKeyOperation(Progressable progress) {
super();
if (progress != null) {
@@ -346,14 +301,14 @@ public class PgpKeyOperation {
// Build key encrypter and decrypter based on passphrase
PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder()
- .build().get(SECRET_KEY_ENCRYPTOR_HASH_ALGO);
+ .build().get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO);
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
- SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, SECRET_KEY_ENCRYPTOR_S2K_COUNT)
+ PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO,
+ encryptorHashCalc, PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
- // NOTE: only SHA1 is supported for key checksum calculations.
PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
- .build().get(HashAlgorithmTags.SHA1);
+ .build().get(PgpConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO);
PGPSecretKey masterSecretKey = new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(),
sha1Calc, true, keyEncryptor);
@@ -880,14 +835,14 @@ public class PgpKeyOperation {
PGPSecretKey sKey; {
// Build key encrypter and decrypter based on passphrase
PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder()
- .build().get(SECRET_KEY_ENCRYPTOR_HASH_ALGO);
+ .build().get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO);
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
- SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, SECRET_KEY_ENCRYPTOR_S2K_COUNT)
+ PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
+ PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
- // NOTE: only SHA1 is supported for key checksum calculations.
PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
- .build().get(HashAlgorithmTags.SHA1);
+ .build().get(PgpConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO);
sKey = new PGPSecretKey(keyPair.getPrivateKey(), pKey, sha1Calc, false, keyEncryptor);
}
@@ -1026,7 +981,8 @@ public class PgpKeyOperation {
// add packet with EMPTY notation data (updates old one, but will be stripped later)
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPrivateKey.getPublicKeyPacket().getAlgorithm(), SECRET_KEY_SIGNATURE_HASH_ALGO)
+ masterPrivateKey.getPublicKeyPacket().getAlgorithm(),
+ PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
{ // set subpackets
@@ -1052,7 +1008,8 @@ public class PgpKeyOperation {
// add packet with "pin" notation data
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPrivateKey.getPublicKeyPacket().getAlgorithm(), SECRET_KEY_SIGNATURE_HASH_ALGO)
+ masterPrivateKey.getPublicKeyPacket().getAlgorithm(),
+ PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
{ // set subpackets
@@ -1099,12 +1056,13 @@ public class PgpKeyOperation {
OperationLog log, int indent) throws PGPException {
PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build()
- .get(SECRET_KEY_ENCRYPTOR_HASH_ALGO);
+ .get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO);
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
// Build key encryptor based on new passphrase
PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder(
- SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, SECRET_KEY_ENCRYPTOR_S2K_COUNT)
+ PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
+ PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
newPassphrase.toCharArray());
@@ -1237,7 +1195,8 @@ public class PgpKeyOperation {
int flags, long expiry)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPrivateKey.getPublicKeyPacket().getAlgorithm(), SECRET_KEY_SIGNATURE_HASH_ALGO)
+ masterPrivateKey.getPublicKeyPacket().getAlgorithm(),
+ PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
@@ -1254,9 +1213,12 @@ public class PgpKeyOperation {
* error than be ignored.
*/
/* non-critical subpackets: */
- hashedPacketsGen.setPreferredSymmetricAlgorithms(false, PREFERRED_SYMMETRIC_ALGORITHMS);
- hashedPacketsGen.setPreferredHashAlgorithms(false, PREFERRED_HASH_ALGORITHMS);
- hashedPacketsGen.setPreferredCompressionAlgorithms(false, PREFERRED_COMPRESSION_ALGORITHMS);
+ hashedPacketsGen.setPreferredSymmetricAlgorithms(false,
+ PgpConstants.getAsArray(PgpConstants.sPreferredSymmetricAlgorithms));
+ hashedPacketsGen.setPreferredHashAlgorithms(false,
+ PgpConstants.getAsArray(PgpConstants.sPreferredHashAlgorithms));
+ hashedPacketsGen.setPreferredCompressionAlgorithms(false,
+ PgpConstants.getAsArray(PgpConstants.sPreferredCompressionAlgorithms));
hashedPacketsGen.setPrimaryUserID(false, primary);
/* critical subpackets: we consider those important for a modern pgp implementation */
@@ -1280,7 +1242,8 @@ public class PgpKeyOperation {
PGPUserAttributeSubpacketVector vector)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPrivateKey.getPublicKeyPacket().getAlgorithm(), SECRET_KEY_SIGNATURE_HASH_ALGO)
+ masterPrivateKey.getPublicKeyPacket().getAlgorithm(),
+ PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
@@ -1299,7 +1262,8 @@ public class PgpKeyOperation {
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPrivateKey.getPublicKeyPacket().getAlgorithm(), SECRET_KEY_SIGNATURE_HASH_ALGO)
+ masterPrivateKey.getPublicKeyPacket().getAlgorithm(),
+ PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
@@ -1313,7 +1277,7 @@ public class PgpKeyOperation {
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, PGPPublicKey pKey)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPublicKey.getAlgorithm(), SECRET_KEY_SIGNATURE_HASH_ALGO)
+ masterPublicKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
@@ -1357,7 +1321,7 @@ public class PgpKeyOperation {
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
subHashedPacketsGen.setSignatureCreationTime(false, creationTime);
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), SECRET_KEY_SIGNATURE_HASH_ALGO)
+ pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
sGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
@@ -1378,7 +1342,7 @@ public class PgpKeyOperation {
}
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPublicKey.getAlgorithm(), SECRET_KEY_SIGNATURE_HASH_ALGO)
+ masterPublicKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
sGen.init(PGPSignature.SUBKEY_BINDING, masterPrivateKey);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInput.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInput.java
index 9318be006..1ed0a4720 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInput.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInput.java
@@ -12,10 +12,10 @@ public class PgpSignEncryptInput {
protected int mCompressionId = CompressionAlgorithmTags.UNCOMPRESSED;
protected long[] mEncryptionMasterKeyIds = null;
protected String mSymmetricPassphrase = null;
- protected int mSymmetricEncryptionAlgorithm = 0;
+ protected int mSymmetricEncryptionAlgorithm = PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED;
protected long mSignatureMasterKeyId = Constants.key.none;
protected Long mSignatureSubKeyId = null;
- protected int mSignatureHashAlgorithm = 0;
+ protected int mSignatureHashAlgorithm = PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED;
protected String mSignaturePassphrase = null;
protected long mAdditionalEncryptId = Constants.key.none;
protected byte[] mNfcSignedHash = null;
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 2fa01d241..81cc2c847 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java
@@ -25,7 +25,6 @@ import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.bcpg.BCPGOutputStream;
import org.spongycastle.bcpg.CompressionAlgorithmTags;
import org.spongycastle.openpgp.PGPCompressedDataGenerator;
-import org.spongycastle.openpgp.PGPEncryptedData;
import org.spongycastle.openpgp.PGPEncryptedDataGenerator;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPLiteralData;
@@ -58,6 +57,7 @@ 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.LinkedList;
@@ -206,12 +206,12 @@ public class PgpSignEncryptOperation extends BaseOperation {
return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
}
- // check if hash algo is supported
+ // Use preferred hash algo
int requestedAlgorithm = input.getSignatureHashAlgorithm();
- LinkedList<Integer> supported = signingKey.getSupportedHashAlgorithms();
- if (requestedAlgorithm == 0) {
+ ArrayList<Integer> supported = signingKey.getSupportedHashAlgorithms();
+ if (requestedAlgorithm == PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED) {
// get most preferred
- input.setSignatureHashAlgorithm(supported.getLast());
+ 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);
@@ -222,9 +222,13 @@ public class PgpSignEncryptOperation extends BaseOperation {
/* Initialize PGPEncryptedDataGenerator for later usage */
PGPEncryptedDataGenerator cPk = null;
if (enableEncryption) {
+
+ // Use preferred encryption algo
int algo = input.getSymmetricEncryptionAlgorithm();
- if (algo == 0) {
- algo = PGPEncryptedData.AES_128;
+ if (algo == PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED) {
+ // get most preferred
+ // TODO: get from recipients
+ algo = PgpConstants.sPreferredSymmetricAlgorithms.get(0);
}
// has Integrity packet enabled!
JcePGPDataEncryptorBuilder encryptorBuilder =
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
index 31ed89d67..ac69ddd24 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
@@ -657,7 +657,7 @@ public class KeychainProvider extends ContentProvider {
cursor.setNotificationUri(getContext().getContentResolver(), uri);
}
- if (Constants.DEBUG) {
+ if (Constants.DEBUG && Constants.DEBUG_LOG_DB_QUERIES) {
Log.d(Constants.TAG,
"Query: "
+ qb.buildQuery(projection, selection, selectionArgs, null, null,
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 fc5275713..ffb812c32 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -1369,8 +1369,7 @@ public class ProviderHelper {
UncachedKeyRing keyRing = UncachedKeyRing.decodeFromData(data);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
- String version = PgpHelper.getVersionForHeader(mContext);
- keyRing.encodeArmored(bos, version);
+ keyRing.encodeArmored(bos, null);
String armoredKey = bos.toString("UTF-8");
Log.d(Constants.TAG, "armoredKey:" + armoredKey);
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 1a65b1bee..03fa41984 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -30,13 +30,16 @@ 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.spongycastle.util.encoders.Hex;
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.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
+import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInput;
import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
@@ -52,6 +55,7 @@ import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;
import org.sufficientlysecure.keychain.ui.ViewKeyActivity;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Preferences;
import java.io.IOException;
import java.io.InputStream;
@@ -258,8 +262,8 @@ public class OpenPgpService extends RemoteService {
.setEnableAsciiArmorOutput(asciiArmor)
.setCleartextSignature(cleartextSign)
.setDetachedSignature(!cleartextSign)
- .setVersionHeader(PgpHelper.getVersionForHeader(this))
- .setSignatureHashAlgorithm(accSettings.getHashAlgorithm())
+ .setVersionHeader(null)
+ .setSignatureHashAlgorithm(PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED)
.setSignatureMasterKeyId(accSettings.getKeyId())
.setNfcState(nfcSignedHash, nfcCreationDate);
@@ -356,9 +360,9 @@ public class OpenPgpService extends RemoteService {
PgpSignEncryptInput pseInput = new PgpSignEncryptInput();
pseInput.setEnableAsciiArmorOutput(asciiArmor)
- .setVersionHeader(PgpHelper.getVersionForHeader(this))
- .setCompressionId(accSettings.getCompression())
- .setSymmetricEncryptionAlgorithm(accSettings.getEncryptionAlgorithm())
+ .setVersionHeader(null)
+ .setCompressionId(CompressionAlgorithmTags.UNCOMPRESSED)
+ .setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED)
.setEncryptionMasterKeyIds(keyIds)
.setFailOnMissingEncryptionKeyIds(true)
.setAdditionalEncryptId(accSettings.getKeyId()); // add acc key for encryption
@@ -374,7 +378,7 @@ public class OpenPgpService extends RemoteService {
}
// sign and encrypt
- pseInput.setSignatureHashAlgorithm(accSettings.getHashAlgorithm())
+ pseInput.setSignatureHashAlgorithm(PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED)
.setSignatureMasterKeyId(accSettings.getKeyId())
.setNfcState(nfcSignedHash, nfcCreationDate);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java
index f0dbf0820..f4b941109 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java
@@ -24,6 +24,9 @@ import android.os.Parcelable;
import java.io.Serializable;
import java.util.ArrayList;
+import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
+
+
/**
* This class is a a transferable representation for a number of keyrings to
* be certified.
@@ -76,14 +79,19 @@ public class CertifyActionsParcel implements Parcelable {
final public long mMasterKeyId;
final public ArrayList<String> mUserIds;
+ final public ArrayList<WrappedUserAttribute> mUserAttributes;
- public CertifyAction(long masterKeyId) {
- this(masterKeyId, null);
+ public CertifyAction(long masterKeyId, ArrayList<String> userIds) {
+ mMasterKeyId = masterKeyId;
+ mUserIds = userIds;
+ mUserAttributes = null;
}
- public CertifyAction(long masterKeyId, ArrayList<String> userIds) {
+ public CertifyAction(long masterKeyId, ArrayList<String> userIds,
+ ArrayList<WrappedUserAttribute> attributes) {
mMasterKeyId = masterKeyId;
mUserIds = userIds;
+ mUserAttributes = attributes;
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java
index ac74e87ed..b496d40fd 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java
@@ -20,9 +20,6 @@ package org.sufficientlysecure.keychain.ui;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.Patterns;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -33,17 +30,19 @@ import android.widget.EditText;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
+import org.sufficientlysecure.keychain.ui.widget.EmailEditText;
+import org.sufficientlysecure.keychain.ui.widget.PasswordEditText;
+import org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator.PasswordStrengthView;
import org.sufficientlysecure.keychain.util.ContactHelper;
-import java.util.regex.Matcher;
-
public class CreateKeyInputFragment extends Fragment {
CreateKeyActivity mCreateKeyActivity;
+ PasswordStrengthView mPassphraseStrengthView;
AutoCompleteTextView mNameEdit;
- AutoCompleteTextView mEmailEdit;
- EditText mPassphraseEdit;
+ EmailEditText mEmailEdit;
+ PasswordEditText mPassphraseEdit;
EditText mPassphraseEditAgain;
View mCreateButton;
@@ -69,9 +68,11 @@ public class CreateKeyInputFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.create_key_input_fragment, container, false);
+ mPassphraseStrengthView = (PasswordStrengthView) view.findViewById(R.id
+ .create_key_passphrase_strength);
mNameEdit = (AutoCompleteTextView) view.findViewById(R.id.create_key_name);
- mEmailEdit = (AutoCompleteTextView) view.findViewById(R.id.create_key_email);
- mPassphraseEdit = (EditText) view.findViewById(R.id.create_key_passphrase);
+ mEmailEdit = (EmailEditText) view.findViewById(R.id.create_key_email);
+ mPassphraseEdit = (PasswordEditText) view.findViewById(R.id.create_key_passphrase);
mPassphraseEditAgain = (EditText) view.findViewById(R.id.create_key_passphrase_again);
mCreateButton = view.findViewById(R.id.create_key_button);
@@ -95,33 +96,7 @@ public class CreateKeyInputFragment extends Fragment {
ContactHelper.getPossibleUserEmails(getActivity())
)
);
- mEmailEdit.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
- }
- @Override
- public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
- }
-
- @Override
- public void afterTextChanged(Editable editable) {
- String email = editable.toString();
- if (email.length() > 0) {
- Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(email);
- if (emailMatcher.matches()) {
- mEmailEdit.setCompoundDrawablesWithIntrinsicBounds(0, 0,
- R.drawable.uid_mail_ok, 0);
- } else {
- mEmailEdit.setCompoundDrawablesWithIntrinsicBounds(0, 0,
- R.drawable.uid_mail_bad, 0);
- }
- } else {
- // remove drawable if email is empty
- mEmailEdit.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
- }
- }
- });
mNameEdit.setThreshold(1); // Start working from first character
mNameEdit.setAdapter(
@@ -131,6 +106,15 @@ public class CreateKeyInputFragment extends Fragment {
)
);
+ // Edit text padding doesn't work via xml (http://code.google.com/p/android/issues/detail?id=77982)
+ // so we set the right padding programmatically.
+ mPassphraseEdit.setPadding(mPassphraseEdit.getPaddingLeft(),
+ mPassphraseEdit.getPaddingTop(),
+ (int) (56 * getResources().getDisplayMetrics().density),
+ mPassphraseEdit.getPaddingBottom());
+
+ mPassphraseEdit.setPasswordStrengthView(mPassphraseStrengthView);
+
mCreateButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
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 7d8fd1388..60103f344 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java
@@ -243,7 +243,7 @@ public abstract class DecryptFragment extends Fragment {
private void setShowAction(final long signatureKeyId) {
mSignatureAction.setText(R.string.decrypt_result_action_show);
- mSignatureAction.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_action_accounts, 0);
+ mSignatureAction.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_vpn_key_grey_24dp, 0);
mSignatureLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java
index 54fe369a7..baf445293 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java
@@ -28,6 +28,7 @@ public interface EncryptActivityInterface {
}
public boolean isUseArmor();
+ public boolean isUseCompression();
public long getSignatureKey();
public long[] getEncryptionKeys();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java
index 1286617d3..11b596c24 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java
@@ -25,11 +25,13 @@ import android.support.v4.app.Fragment;
import android.view.Menu;
import android.view.MenuItem;
+import org.spongycastle.bcpg.CompressionAlgorithmTags;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.api.OpenKeychainIntents;
import org.sufficientlysecure.keychain.operations.results.SignEncryptResult;
import org.sufficientlysecure.keychain.pgp.KeyRing;
+import org.sufficientlysecure.keychain.pgp.PgpConstants;
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
import org.sufficientlysecure.keychain.ui.util.Notify;
@@ -66,6 +68,7 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
private long mSigningKeyId = Constants.key.none;
private String mPassphrase = "";
private boolean mUseArmor;
+ private boolean mUseCompression;
private boolean mDeleteAfterEncrypt = false;
private boolean mShareAfterEncrypt = false;
private ArrayList<Uri> mInputUris;
@@ -82,6 +85,11 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
}
@Override
+ public boolean isUseCompression() {
+ return mUseCompression;
+ }
+
+ @Override
public long getSignatureKey() {
return mSigningKeyId;
}
@@ -196,10 +204,13 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
data.addInputUris(mInputUris);
data.addOutputUris(mOutputUris);
- data.setCompressionId(Preferences.getPreferences(this).getDefaultMessageCompression());
-
- // Always use armor for messages
- data.setEnableAsciiArmorOutput(mUseArmor);
+ if (mUseCompression) {
+ data.setCompressionId(PgpConstants.sPreferredCompressionAlgorithms.get(0));
+ } else {
+ data.setCompressionId(CompressionAlgorithmTags.UNCOMPRESSED);
+ }
+ data.setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED);
+ data.setSignatureHashAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED);
if (isModeSymmetric()) {
Log.d(Constants.TAG, "Symmetric encryption enabled!");
@@ -315,8 +326,6 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
// Handle intent actions
handleActions(getIntent());
updateModeFragment();
-
- mUseArmor = Preferences.getPreferences(this).getDefaultAsciiArmor();
}
@Override
@@ -327,7 +336,6 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.encrypt_file_activity, menu);
- menu.findItem(R.id.check_use_armor).setChecked(mUseArmor);
return super.onCreateOptionsMenu(menu);
}
@@ -348,21 +356,30 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
item.setChecked(!item.isChecked());
}
switch (item.getItemId()) {
- case R.id.check_use_symmetric:
+ case R.id.check_use_symmetric: {
mCurrentMode = item.isChecked() ? MODE_SYMMETRIC : MODE_ASYMMETRIC;
updateModeFragment();
notifyUpdate();
break;
- case R.id.check_use_armor:
+ }
+ case R.id.check_use_armor: {
mUseArmor = item.isChecked();
notifyUpdate();
break;
- case R.id.check_delete_after_encrypt:
+ }
+ case R.id.check_delete_after_encrypt: {
mDeleteAfterEncrypt = item.isChecked();
notifyUpdate();
break;
- default:
+ }
+ case R.id.check_enable_compression: {
+ mUseCompression = item.isChecked();
+ notifyUpdate();
+ break;
+ }
+ default: {
return super.onOptionsItemSelected(item);
+ }
}
return true;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
index 2dd861d07..08ff5b962 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
@@ -25,12 +25,14 @@ import android.support.v4.app.Fragment;
import android.view.Menu;
import android.view.MenuItem;
+import org.spongycastle.bcpg.CompressionAlgorithmTags;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.api.OpenKeychainIntents;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.operations.results.SignEncryptResult;
import org.sufficientlysecure.keychain.pgp.KeyRing;
+import org.sufficientlysecure.keychain.pgp.PgpConstants;
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log;
@@ -70,6 +72,7 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv
private ArrayList<Uri> mInputUris;
private ArrayList<Uri> mOutputUris;
private String mMessage = "";
+ private boolean mUseCompression;
public boolean isModeSymmetric() {
return MODE_SYMMETRIC == mCurrentMode;
@@ -81,6 +84,11 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv
}
@Override
+ public boolean isUseCompression() {
+ return mUseCompression;
+ }
+
+ @Override
public long getSignatureKey() {
return mSigningKeyId;
}
@@ -189,7 +197,13 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv
data.setBytes(mMessage.getBytes());
data.setCleartextSignature(true);
- data.setCompressionId(Preferences.getPreferences(this).getDefaultMessageCompression());
+ if (mUseCompression) {
+ data.setCompressionId(PgpConstants.sPreferredCompressionAlgorithms.get(0));
+ } else {
+ data.setCompressionId(CompressionAlgorithmTags.UNCOMPRESSED);
+ }
+ data.setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED);
+ data.setSignatureHashAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED);
// Always use armor for messages
data.setEnableAsciiArmorOutput(true);
@@ -328,13 +342,20 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv
item.setChecked(!item.isChecked());
}
switch (item.getItemId()) {
- case R.id.check_use_symmetric:
+ case R.id.check_use_symmetric: {
mCurrentMode = item.isChecked() ? MODE_SYMMETRIC : MODE_ASYMMETRIC;
updateModeFragment();
notifyUpdate();
break;
- default:
+ }
+ case R.id.check_enable_compression: {
+ mUseCompression = item.isChecked();
+ notifyUpdate();
+ break;
+ }
+ default: {
return super.onOptionsItemSelected(item);
+ }
}
return true;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
index a44eef216..43d893fa6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -678,9 +678,6 @@ public class KeyListFragment extends LoaderFragment
/**
* Bind cursor data to the item list view
- * <p/>
- * NOTE: CursorAdapter already implements the ViewHolder pattern in its getView() method.
- * Thus no ViewHolder is required here.
*/
@Override
public void bindView(View view, Context context, Cursor cursor) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java
index 53986a392..210960b65 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java
@@ -33,8 +33,6 @@ import android.view.ViewGroup;
import android.widget.LinearLayout;
import org.spongycastle.bcpg.CompressionAlgorithmTags;
-import org.spongycastle.bcpg.HashAlgorithmTags;
-import org.spongycastle.openpgp.PGPEncryptedData;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference;
@@ -93,12 +91,6 @@ public class SettingsActivity extends PreferenceActivity {
initializePassphraseCacheTtl(
(IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL));
- initializeEncryptionAlgorithm(
- (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM));
-
- initializeHashAlgorithm(
- (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_HASH_ALGORITHM));
-
int[] valueIds = new int[]{
CompressionAlgorithmTags.UNCOMPRESSED,
CompressionAlgorithmTags.ZIP,
@@ -115,20 +107,6 @@ public class SettingsActivity extends PreferenceActivity {
values[i] = "" + valueIds[i];
}
- initializeMessageCompression(
- (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION),
- entries, values);
-
- initializeFileCompression(
- (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_FILE_COMPRESSION),
- entries, values);
-
- initializeAsciiArmor(
- (CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOR));
-
- initializeWriteVersionHeader(
- (CheckBoxPreference) findPreference(Constants.Pref.WRITE_VERSION_HEADER));
-
initializeUseDefaultYubikeyPin(
(CheckBoxPreference) findPreference(Constants.Pref.USE_DEFAULT_YUBIKEY_PIN));
@@ -265,12 +243,6 @@ public class SettingsActivity extends PreferenceActivity {
initializePassphraseCacheTtl(
(IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL));
- initializeEncryptionAlgorithm(
- (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM));
-
- initializeHashAlgorithm(
- (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_HASH_ALGORITHM));
-
int[] valueIds = new int[]{
CompressionAlgorithmTags.UNCOMPRESSED,
CompressionAlgorithmTags.ZIP,
@@ -290,20 +262,6 @@ public class SettingsActivity extends PreferenceActivity {
values[i] = "" + valueIds[i];
}
- initializeMessageCompression(
- (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION),
- entries, values);
-
- initializeFileCompression(
- (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_FILE_COMPRESSION),
- entries, values);
-
- initializeAsciiArmor(
- (CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOR));
-
- initializeWriteVersionHeader(
- (CheckBoxPreference) findPreference(Constants.Pref.WRITE_VERSION_HEADER));
-
initializeUseDefaultYubikeyPin(
(CheckBoxPreference) findPreference(Constants.Pref.USE_DEFAULT_YUBIKEY_PIN));
@@ -344,113 +302,6 @@ public class SettingsActivity extends PreferenceActivity {
});
}
- private static void initializeEncryptionAlgorithm(final IntegerListPreference mEncryptionAlgorithm) {
- int valueIds[] = {PGPEncryptedData.AES_128, PGPEncryptedData.AES_192,
- PGPEncryptedData.AES_256, PGPEncryptedData.BLOWFISH, PGPEncryptedData.TWOFISH,
- PGPEncryptedData.CAST5, PGPEncryptedData.DES, PGPEncryptedData.TRIPLE_DES,
- PGPEncryptedData.IDEA,};
- String entries[] = {"AES-128", "AES-192", "AES-256", "Blowfish", "Twofish", "CAST5",
- "DES", "Triple DES", "IDEA",};
- String values[] = new String[valueIds.length];
- for (int i = 0; i < values.length; ++i) {
- values[i] = "" + valueIds[i];
- }
- mEncryptionAlgorithm.setEntries(entries);
- mEncryptionAlgorithm.setEntryValues(values);
- mEncryptionAlgorithm.setValue("" + sPreferences.getDefaultEncryptionAlgorithm());
- mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry());
- mEncryptionAlgorithm
- .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- mEncryptionAlgorithm.setValue(newValue.toString());
- mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry());
- sPreferences.setDefaultEncryptionAlgorithm(Integer.parseInt(newValue
- .toString()));
- return false;
- }
- });
- }
-
- private static void initializeHashAlgorithm(final IntegerListPreference mHashAlgorithm) {
- int[] valueIds = new int[]{HashAlgorithmTags.RIPEMD160,
- HashAlgorithmTags.SHA1, HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256,
- HashAlgorithmTags.SHA384, HashAlgorithmTags.SHA512,};
- String[] entries = new String[]{"RIPEMD-160", "SHA-1", "SHA-224", "SHA-256", "SHA-384",
- "SHA-512",};
- String[] values = new String[valueIds.length];
- for (int i = 0; i < values.length; ++i) {
- values[i] = "" + valueIds[i];
- }
- mHashAlgorithm.setEntries(entries);
- mHashAlgorithm.setEntryValues(values);
- mHashAlgorithm.setValue("" + sPreferences.getDefaultHashAlgorithm());
- mHashAlgorithm.setSummary(mHashAlgorithm.getEntry());
- mHashAlgorithm.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- mHashAlgorithm.setValue(newValue.toString());
- mHashAlgorithm.setSummary(mHashAlgorithm.getEntry());
- sPreferences.setDefaultHashAlgorithm(Integer.parseInt(newValue.toString()));
- return false;
- }
- });
- }
-
- private static void initializeMessageCompression(final IntegerListPreference mMessageCompression,
- String[] entries, String[] values) {
- mMessageCompression.setEntries(entries);
- mMessageCompression.setEntryValues(values);
- mMessageCompression.setValue("" + sPreferences.getDefaultMessageCompression());
- mMessageCompression.setSummary(mMessageCompression.getEntry());
- mMessageCompression
- .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- mMessageCompression.setValue(newValue.toString());
- mMessageCompression.setSummary(mMessageCompression.getEntry());
- sPreferences.setDefaultMessageCompression(Integer.parseInt(newValue
- .toString()));
- return false;
- }
- });
- }
-
- private static void initializeFileCompression
- (final IntegerListPreference mFileCompression, String[] entries, String[] values) {
- mFileCompression.setEntries(entries);
- mFileCompression.setEntryValues(values);
- mFileCompression.setValue("" + sPreferences.getDefaultFileCompression());
- mFileCompression.setSummary(mFileCompression.getEntry());
- mFileCompression.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- mFileCompression.setValue(newValue.toString());
- mFileCompression.setSummary(mFileCompression.getEntry());
- sPreferences.setDefaultFileCompression(Integer.parseInt(newValue.toString()));
- return false;
- }
- });
- }
-
- private static void initializeAsciiArmor(final CheckBoxPreference mAsciiArmor) {
- mAsciiArmor.setChecked(sPreferences.getDefaultAsciiArmor());
- mAsciiArmor.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- mAsciiArmor.setChecked((Boolean) newValue);
- sPreferences.setDefaultAsciiArmor((Boolean) newValue);
- return false;
- }
- });
- }
-
- private static void initializeWriteVersionHeader(final CheckBoxPreference mWriteVersionHeader) {
- mWriteVersionHeader.setChecked(sPreferences.getWriteVersionHeader());
- mWriteVersionHeader.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- mWriteVersionHeader.setChecked((Boolean) newValue);
- sPreferences.setWriteVersionHeader((Boolean) newValue);
- return false;
- }
- });
- }
-
private static void initializeSearchKeyserver(final CheckBoxPreference mSearchKeyserver) {
Preferences.CloudSearchPrefs prefs = sPreferences.getCloudSearchPrefs();
mSearchKeyserver.setChecked(prefs.searchKeyserver);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index be1e0a4c1..c936fb6cc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -90,6 +90,8 @@ public class ViewKeyActivity extends BaseActivity implements
LoaderManager.LoaderCallbacks<Cursor> {
static final int REQUEST_QR_FINGERPRINT = 1;
+ static final int REQUEST_DELETE= 2;
+ static final int REQUEST_EXPORT= 3;
ExportHelper mExportHelper;
ProviderHelper mProviderHelper;
@@ -278,54 +280,69 @@ public class ViewKeyActivity extends BaseActivity implements
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- try {
- switch (item.getItemId()) {
- case android.R.id.home: {
- Intent homeIntent = new Intent(this, MainActivity.class);
- homeIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(homeIntent);
- return true;
- }
- case R.id.menu_key_view_export_file: {
- exportToFile(mDataUri, mExportHelper, mProviderHelper);
- return true;
- }
- case R.id.menu_key_view_delete: {
- deleteKey(mDataUri, mExportHelper);
- return true;
- }
- case R.id.menu_key_view_advanced: {
- Intent advancedIntent = new Intent(this, ViewKeyAdvActivity.class);
- advancedIntent.setData(mDataUri);
- startActivity(advancedIntent);
- return true;
- }
- case R.id.menu_key_view_refresh: {
- try {
- updateFromKeyserver(mDataUri, mProviderHelper);
- } catch (ProviderHelper.NotFoundException e) {
- Notify.showNotify(this, R.string.error_key_not_found, Notify.Style.ERROR);
- }
- return true;
- }
- case R.id.menu_key_view_edit: {
- editKey(mDataUri);
- return true;
+ switch (item.getItemId()) {
+ case android.R.id.home: {
+ Intent homeIntent = new Intent(this, MainActivity.class);
+ homeIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(homeIntent);
+ return true;
+ }
+ case R.id.menu_key_view_export_file: {
+ Intent mIntent = new Intent(this,PassphraseDialogActivity.class);
+ long keyId=0;
+ try {
+ keyId = new ProviderHelper(this)
+ .getCachedPublicKeyRing(mDataUri)
+ .extractOrGetMasterKeyId();
+ } catch (PgpKeyNotFoundException e) {
+ e.printStackTrace();
}
- case R.id.menu_key_view_certify_fingerprint: {
- certifyFingeprint(mDataUri);
- return true;
+ mIntent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID,keyId);
+ startActivityForResult(mIntent,REQUEST_EXPORT);
+ return true;
+ }
+ case R.id.menu_key_view_delete: {
+ Intent mIntent = new Intent(this,PassphraseDialogActivity.class);
+ long keyId=0;
+ try {
+ keyId = new ProviderHelper(this)
+ .getCachedPublicKeyRing(mDataUri)
+ .extractOrGetMasterKeyId();
+ } catch (PgpKeyNotFoundException e) {
+ e.printStackTrace();
}
- case R.id.menu_key_view_add_linked_identity: {
- Intent intent = new Intent(this, LinkedIdWizard.class);
- intent.setData(mDataUri);
- startActivity(intent);
- return true;
+ mIntent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID,keyId);
+ startActivityForResult(mIntent,REQUEST_DELETE);
+ return true;
+ }
+ case R.id.menu_key_view_advanced: {
+ Intent advancedIntent = new Intent(this, ViewKeyAdvActivity.class);
+ advancedIntent.setData(mDataUri);
+ startActivity(advancedIntent);
+ return true;
+ }
+ case R.id.menu_key_view_refresh: {
+ try {
+ updateFromKeyserver(mDataUri, mProviderHelper);
+ } catch (ProviderHelper.NotFoundException e) {
+ Notify.showNotify(this, R.string.error_key_not_found, Notify.Style.ERROR);
}
+ return true;
+ }
+ case R.id.menu_key_view_add_linked_identity: {
+ Intent intent = new Intent(this, LinkedIdWizard.class);
+ intent.setData(mDataUri);
+ startActivity(intent);
+ return true;
+ }
+ case R.id.menu_key_view_edit: {
+ editKey(mDataUri);
+ return true;
+ }
+ case R.id.menu_key_view_certify_fingerprint: {
+ certifyFingeprint(mDataUri);
+ return true;
}
- } catch (ProviderHelper.NotFoundException e) {
- Notify.showNotify(this, R.string.error_key_not_found, Notify.Style.ERROR);
- Log.e(Constants.TAG, "Key not found", e);
}
return super.onOptionsItemSelected(item);
}
@@ -417,6 +434,12 @@ public class ViewKeyActivity extends BaseActivity implements
startActivityForResult(intent, 0);
}
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ //Note:-Done due to the same weird crashes as for commitAllowingStateLoss()
+ //super.onSaveInstanceState(outState);
+ }
+
private void showQrCodeDialog() {
Intent qrCodeIntent = new Intent(this, QrCodeViewActivity.class);
@@ -490,6 +513,19 @@ public class ViewKeyActivity extends BaseActivity implements
return;
}
+ if (requestCode == REQUEST_DELETE && resultCode == Activity.RESULT_OK){
+ deleteKey(mDataUri, mExportHelper);
+ }
+ if (requestCode == REQUEST_EXPORT && resultCode == Activity.RESULT_OK){
+ try {
+ exportToFile(mDataUri, mExportHelper, mProviderHelper);
+ } catch (ProviderHelper.NotFoundException e) {
+ Notify.showNotify(this, R.string.error_key_not_found, Notify.Style.ERROR);
+ Log.e(Constants.TAG, "Key not found", e);
+ }
+ }
+
+
if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
result.createNotify(this).show();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java
index 094c4d8a9..ee4af8cbe 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java
@@ -28,9 +28,6 @@ import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v4.app.DialogFragment;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.Patterns;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
@@ -46,11 +43,10 @@ import android.widget.TextView.OnEditorActionListener;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.KeyRing;
+import org.sufficientlysecure.keychain.ui.widget.EmailEditText;
import org.sufficientlysecure.keychain.util.ContactHelper;
import org.sufficientlysecure.keychain.util.Log;
-import java.util.regex.Matcher;
-
public class AddUserIdDialogFragment extends DialogFragment implements OnEditorActionListener {
private static final String ARG_MESSENGER = "messenger";
private static final String ARG_NAME = "name";
@@ -62,7 +58,7 @@ public class AddUserIdDialogFragment extends DialogFragment implements OnEditorA
private Messenger mMessenger;
private AutoCompleteTextView mName;
- private AutoCompleteTextView mEmail;
+ private EmailEditText mEmail;
private EditText mComment;
public static AddUserIdDialogFragment newInstance(Messenger messenger, String predefinedName) {
@@ -99,38 +95,12 @@ public class AddUserIdDialogFragment extends DialogFragment implements OnEditorA
alert.setView(view);
mName = (AutoCompleteTextView) view.findViewById(R.id.add_user_id_name);
- mEmail = (AutoCompleteTextView) view.findViewById(R.id.add_user_id_address);
+ mEmail = (EmailEditText) view.findViewById(R.id.add_user_id_address);
mComment = (EditText) view.findViewById(R.id.add_user_id_comment);
mName.setText(predefinedName);
- mEmail.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
- @Override
- public void afterTextChanged(Editable editable) {
- String email = editable.toString();
- if (email.length() > 0) {
- Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(email);
- if (emailMatcher.matches()) {
- mEmail.setCompoundDrawablesWithIntrinsicBounds(0, 0,
- R.drawable.uid_mail_ok, 0);
- } else {
- mEmail.setCompoundDrawablesWithIntrinsicBounds(0, 0,
- R.drawable.uid_mail_bad, 0);
- }
- } else {
- // remove drawable if email is empty
- mEmail.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
- }
- }
- });
mEmail.setThreshold(1); // Start working from first character
mEmail.setAdapter(autoCompleteEmailAdapter);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java
index a3ffe250b..9e1f21f60 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java
@@ -43,6 +43,8 @@ import android.widget.Toast;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.widget.PasswordEditText;
+import org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator.PasswordStrengthView;
import org.sufficientlysecure.keychain.util.Log;
public class SetPassphraseDialogFragment extends DialogFragment implements OnEditorActionListener {
@@ -55,9 +57,10 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
public static final String MESSAGE_NEW_PASSPHRASE = "new_passphrase";
private Messenger mMessenger;
- private EditText mPassphraseEditText;
+ private PasswordEditText mPassphraseEditText;
private EditText mPassphraseAgainEditText;
private CheckBox mNoPassphraseCheckBox;
+ private PasswordStrengthView mPassphraseStrengthView;
/**
* Creates new instance of this dialog fragment
@@ -97,9 +100,12 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
View view = inflater.inflate(R.layout.passphrase_repeat_dialog, null);
alert.setView(view);
- mPassphraseEditText = (EditText) view.findViewById(R.id.passphrase_passphrase);
+ mPassphraseEditText = (PasswordEditText) view.findViewById(R.id.passphrase_passphrase);
mPassphraseAgainEditText = (EditText) view.findViewById(R.id.passphrase_passphrase_again);
mNoPassphraseCheckBox = (CheckBox) view.findViewById(R.id.passphrase_no_passphrase);
+ mPassphraseStrengthView = (PasswordStrengthView) view.findViewById(R.id.passphrase_repeat_passphrase_strength);
+ mPassphraseEditText.setPasswordStrengthView(mPassphraseStrengthView);
+
if (TextUtils.isEmpty(oldPassphrase)) {
mNoPassphraseCheckBox.setChecked(true);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java
new file mode 100644
index 000000000..697f5a61e
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.ui.widget;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextWatcher;
+import android.util.AttributeSet;
+import android.util.Patterns;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.util.ContactHelper;
+
+import java.util.regex.Matcher;
+
+public class EmailEditText extends AutoCompleteTextView {
+ EmailEditText emailEditText;
+
+ public EmailEditText(Context context) {
+ super(context);
+ emailEditText = this;
+ this.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
+ this.addTextChangedListener(textWatcher);
+ }
+
+ public EmailEditText(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ emailEditText = this;
+ this.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
+ this.addTextChangedListener(textWatcher);
+ }
+
+ public EmailEditText(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ emailEditText = this;
+ this.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
+ this.addTextChangedListener(textWatcher);
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public EmailEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ emailEditText = this;
+ this.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
+ this.addTextChangedListener(textWatcher);
+ }
+
+ TextWatcher textWatcher = new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ String email = editable.toString();
+ if (email.length() > 0) {
+ Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(email);
+ if (emailMatcher.matches()) {
+ emailEditText.setCompoundDrawablesWithIntrinsicBounds(0, 0,
+ R.drawable.uid_mail_ok, 0);
+ } else {
+ emailEditText.setCompoundDrawablesWithIntrinsicBounds(0, 0,
+ R.drawable.uid_mail_bad, 0);
+ }
+ } else {
+ // remove drawable if email is empty
+ emailEditText.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
+ }
+ }
+ };
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordEditText.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordEditText.java
new file mode 100644
index 000000000..04c48922b
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordEditText.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.ui.widget;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextWatcher;
+import android.util.AttributeSet;
+import android.widget.EditText;
+
+import org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator.PasswordStrengthView;
+
+/**
+ * Developer: chipset
+ * Package : org.sufficientlysecure.keychain.layouts
+ * Project : open-keychain
+ * Date : 6/3/15
+ */
+public class PasswordEditText extends EditText {
+
+ PasswordEditText passwordEditText;
+ PasswordStrengthView passwordStrengthView;
+
+ public PasswordEditText(Context context) {
+ super(context);
+ passwordEditText = this;
+ this.setInputType(InputType.TYPE_CLASS_TEXT |
+ InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ this.addTextChangedListener(textWatcher);
+ }
+
+ public PasswordEditText(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ passwordEditText = this;
+ this.setInputType(InputType.TYPE_CLASS_TEXT |
+ InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ this.addTextChangedListener(textWatcher);
+ }
+
+ public PasswordEditText(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ passwordEditText = this;
+ this.setInputType(InputType.TYPE_CLASS_TEXT |
+ InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ this.addTextChangedListener(textWatcher);
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public PasswordEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ passwordEditText = this;
+ this.setInputType(InputType.TYPE_CLASS_TEXT |
+ InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ this.addTextChangedListener(textWatcher);
+ }
+
+
+ TextWatcher textWatcher = new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ String passphrase = editable.toString();
+ passwordStrengthView.setPassword(passphrase);
+ }
+ };
+
+// public PasswordStrengthView getPasswordStrengthView() {
+// return passwordStrengthView;
+// }
+
+ public void setPasswordStrengthView(PasswordStrengthView mPasswordStrengthView) {
+ this.passwordStrengthView = mPasswordStrengthView;
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthBarView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthBarView.java
new file mode 100644
index 000000000..9e06c4cce
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthBarView.java
@@ -0,0 +1,117 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Matt Allen
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.util.AttributeSet;
+
+/**
+ * Created by matt on 04/07/2014.
+ * https://github.com/matt-allen/android-password-strength-indicator
+ */
+public class PasswordStrengthBarView extends PasswordStrengthView {
+
+ public PasswordStrengthBarView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mMinHeight = 80;
+ mMinWidth = 300;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ generateIndicatorColor();
+ // Default to full width
+ int indWidth = mIndicatorWidth;
+ // If score, leave it as full - can cause it to become
+ // less than full width in this calculation
+ if (mCurrentScore < 20) indWidth = (mIndicatorWidth / 20) * mCurrentScore;
+ // Draw indicator
+ canvas.drawRect(
+ getPaddingLeft(),
+ getPaddingTop(),
+ indWidth,
+ mIndicatorHeight,
+ mIndicatorPaint
+ );
+ // Draw guides if true
+ if (mShowGuides) {
+ // TODO: Try and do this with a loop, for efficiency
+ // Draw bottom guide border
+ float positionY = getHeight() - getPaddingBottom() - getPaddingTop();
+ float notchHeight = (float) (positionY * 0.8);
+ canvas.drawLine(
+ getPaddingLeft(),
+ positionY,
+ getWidth() - getPaddingRight(),
+ positionY,
+ mGuidePaint);
+ // Show left-most notch
+ canvas.drawLine(
+ getPaddingLeft(),
+ positionY,
+ getPaddingLeft(),
+ notchHeight,
+ mGuidePaint
+ );
+ // Show middle-left notch
+ canvas.drawLine(
+ (float) (mIndicatorWidth * 0.25) + getPaddingLeft(),
+ positionY,
+ (float) (mIndicatorWidth * 0.25) + getPaddingLeft(),
+ notchHeight,
+ mGuidePaint
+ );
+ // Show the middle notch
+ canvas.drawLine(
+ (float) (mIndicatorWidth * 0.5) + getPaddingLeft(),
+ positionY,
+ (float) (mIndicatorWidth * 0.5) + getPaddingLeft(),
+ notchHeight,
+ mGuidePaint
+ );
+ // Show the middle-right notch
+ canvas.drawLine(
+ (float) (mIndicatorWidth * 0.75) + getPaddingLeft(),
+ positionY,
+ (float) (mIndicatorWidth * 0.75) + getPaddingLeft(),
+ notchHeight,
+ mGuidePaint
+ );
+ // Show the right-most notch
+ canvas.drawLine(
+ mIndicatorWidth + getPaddingLeft(),
+ positionY,
+ mIndicatorWidth + getPaddingLeft(),
+ notchHeight,
+ mGuidePaint
+ );
+ }
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthView.java
new file mode 100644
index 000000000..d7270ff58
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthView.java
@@ -0,0 +1,360 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Matt Allen
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+
+import org.sufficientlysecure.keychain.R;
+
+/**
+ * Created by Matt Allen
+ * 01/07/14
+ * http://www.mattallensoftware.co.uk
+ * mattallen092@gmail.com
+ * <p/>
+ * https://github.com/matt-allen/android-password-strength-indicator
+ * <p/>
+ * <p>
+ * This View is designed to indicate how secure a user-entered password is in a visual way to
+ * relay to the user if they need to make it stronger. The strength of the password can be set
+ * at creation (or after) which will decide whether their password is strong enough.
+ * </p>
+ * <p/>
+ * <p>
+ * The password strength is decided by an index of 20. The minimum score needed to pass is 10
+ * which means the String has met the conditions imposed by the strength test, but can be improved.
+ * If the password scores 10-19 it is considered weak, and only if it scores 20 will it be
+ * considered strong.
+ * </p>
+ */
+public class PasswordStrengthView extends View {
+
+ protected static final int COLOR_FAIL = Color.parseColor("#e74c3c");
+ protected static final int COLOR_WEAK = Color.parseColor("#e67e22");
+ protected static final int COLOR_STRONG = Color.parseColor("#2ecc71");
+
+ protected int mMinWidth;
+ protected int mMinHeight;
+
+ protected Paint mIndicatorPaint;
+ protected Paint mGuidePaint;
+
+ protected int mIndicatorHeight;
+ protected int mIndicatorWidth;
+ protected int mCurrentScore;
+
+ protected int mColorFail;
+ protected int mColorWeak;
+ protected int mColorStrong;
+
+ protected boolean mShowGuides = true;
+
+ /**
+ * Used to define that the indicator should only be looking
+ * for a weak password. The bare minimum is used here to let
+ * the user continue.
+ */
+ public static final int STRENGTH_WEAK = 0;
+
+ /**
+ * A fairly strict rule for generating a password. It encourages a password that is
+ * less easy to crack.
+ */
+ public static final int STRENGTH_MEDIUM = 1;
+
+ /**
+ * A strong algorithm that encourages very strong passwords that should be fairly long, with
+ * non-alphanumeric, numbers, and upper case.
+ */
+ public static final int STRENGTH_STRONG = 2;
+
+ private int mStrengthRequirement = -1;
+ protected String mPassword;
+
+ public PasswordStrengthView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ TypedArray style = context.getTheme().obtainStyledAttributes(
+ attrs,
+ R.styleable.PasswordStrengthView,
+ 0, 0);
+
+ try {
+ mStrengthRequirement = style.getInteger(R.styleable.PasswordStrengthView_strength,
+ STRENGTH_MEDIUM);
+ mShowGuides = style.getBoolean(R.styleable.PasswordStrengthView_showGuides, true);
+ mColorFail = style.getColor(R.styleable.PasswordStrengthView_color_fail, COLOR_FAIL);
+ mColorWeak = style.getColor(R.styleable.PasswordStrengthView_color_weak, COLOR_WEAK);
+ mColorStrong = style.getColor(R.styleable.PasswordStrengthView_color_strong,
+ COLOR_STRONG);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ // Create and style the paint used for drawing the guide on the indicator
+ mGuidePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mGuidePaint.setStyle(Paint.Style.FILL_AND_STROKE);
+ mGuidePaint.setColor(Color.BLACK);
+ // Create and style paint for indicator
+ mIndicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mIndicatorPaint.setStyle(Paint.Style.FILL);
+ }
+
+ /**
+ * This view can determine if the password entered by the user is acceptable for
+ * use by your use case. This is based on the strength requirement you have set.
+ *
+ * @return True if requirement has been met
+ */
+ public boolean isStrengthRequirementMet() {
+ return (mCurrentScore >= 10);
+ }
+
+ /**
+ * Change the strength requirement of the password entered by the user. This will also
+ * re-check the password already entered against these new requirements.
+ *
+ * @param requiredStrength Use the public constants of this class to set
+ */
+ public void setStrengthRequirement(int requiredStrength) {
+ if (requiredStrength >= 0 && requiredStrength <= 2) {
+ mStrengthRequirement = requiredStrength;
+ if (mPassword != null && mPassword.length() > 0) {
+ generatePasswordScore();
+ // Update view with new score
+ invalidate();
+ requestLayout();
+ }
+ } else {
+ throw new IndexOutOfBoundsException("Input out of expected range");
+ }
+ }
+
+ /**
+ * Update the password string to check strength of
+ *
+ * @param passwordString String representation of user-input
+ */
+ public void setPassword(String passwordString) {
+ if (passwordString != null && passwordString.length() > 0) {
+ mPassword = passwordString;
+ generatePasswordScore();
+ } else {
+ mPassword = "";
+ mCurrentScore = 0;
+ }
+
+ // Update view with new score
+ invalidate();
+ requestLayout();
+ }
+
+ /**
+ * Private convenience method for adding to the password score
+ *
+ * @param score Amount to be added to current score
+ */
+ protected void addToPasswordScore(int score) {
+ int newScore = mCurrentScore + score;
+
+ // Limit max score
+ if (newScore > 20) {
+ mCurrentScore = 20;
+ } else {
+ mCurrentScore = newScore;
+ }
+ }
+
+ /**
+ * Call this to determine the current strength requirement set on the algorithm
+ *
+ * @return Int representation of the current strength set for the indicator
+ */
+ public int getStrengthRequirement() {
+ return mStrengthRequirement;
+ }
+
+ /**
+ * Generate a score based on the password. The password will already need to be stored
+ * as a class member before running this.
+ */
+ protected void generatePasswordScore() {
+ mCurrentScore = 0;
+ int upperCase = getUppercaseCount(mPassword);
+ int nonAlpha = getNonAlphanumericCount(mPassword);
+ int numbers = getNumberCount(mPassword);
+ switch (mStrengthRequirement) {
+ case STRENGTH_WEAK:
+ addToPasswordScore(mPassword.length() * 2);
+ addToPasswordScore(upperCase * 2);
+ addToPasswordScore(nonAlpha * 2);
+ addToPasswordScore(numbers * 2);
+ break;
+
+ case STRENGTH_MEDIUM:
+ addToPasswordScore(mPassword.length());
+ addToPasswordScore(upperCase);
+ addToPasswordScore(nonAlpha * 2);
+ addToPasswordScore(numbers);
+ break;
+
+ case STRENGTH_STRONG:
+ addToPasswordScore(mPassword.length() / 2);
+ // Cut the score in half to make this a very high requirement
+ addToPasswordScore(upperCase);
+ addToPasswordScore(nonAlpha);
+ addToPasswordScore(numbers);
+ break;
+ }
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldW, int oldH) {
+ super.onSizeChanged(w, h, oldW, oldH);
+ int paddingX = getPaddingLeft();
+ int paddingY = getPaddingTop();
+ mIndicatorHeight = h - paddingY;
+ mIndicatorWidth = w - paddingX;
+ }
+
+ /**
+ * The standard parts of the onMeasure needed to create the password strength
+ * indicator. Subclasses should call super.onMeasure, but also need to set
+ * the minimum height and width in the constructor.
+ *
+ * @param widthMeasureSpec The measurement given by the system
+ * @param heightMeasureSpec The measurement given by the system
+ */
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // Set minimum space for the view to do it's thing
+ int minW = getPaddingLeft() + getPaddingRight() + mMinWidth;
+ int w = resolveSizeAndState(minW, widthMeasureSpec, 1);
+ // And give it enough height so it's visible
+ int minH = mMinHeight + getPaddingBottom() + getPaddingTop();
+ int h = resolveSizeAndState(minH, heightMeasureSpec, 0);
+ // Feed these back into UIKit
+ setMeasuredDimension(w, h);
+ }
+
+ /**
+ * Set the colour of the indicator {@code Paint} to one that is appropriate
+ * for the strength of the password.
+ */
+ protected void generateIndicatorColor() {
+ int color = mColorFail;
+ if (mCurrentScore >= 18) {
+ color = mColorStrong;
+ } else if (mCurrentScore >= 10) {
+ color = mColorWeak;
+ }
+ mIndicatorPaint.setColor(color);
+ }
+
+ /**
+ * Quick method to determine how many of the characters in a given string are upper case
+ *
+ * @param stringToCheck The string to examine
+ * @return Number of upper case characters
+ */
+ protected int getUppercaseCount(String stringToCheck) {
+ int score = 0;
+ int loops = stringToCheck.length() - 1;
+ for (int i = 0; i <= loops; i++) {
+ if (Character.isUpperCase(stringToCheck.charAt(i))) {
+ score++;
+ }
+ }
+ return score;
+ }
+
+ /**
+ * A convenience method to determine how many characters in the given String aren't
+ * letters or numbers.
+ *
+ * @param stringToCheck
+ * @return Number of characters that aren't numbers or letters
+ */
+ protected int getNonAlphanumericCount(String stringToCheck) {
+ int score = 0;
+ int loops = stringToCheck.length() - 1;
+ for (int i = 0; i <= loops; i++) {
+ if (!Character.isLetter(stringToCheck.charAt(i)) &&
+ !Character.isDigit(stringToCheck.charAt(i))) {
+ score++;
+ }
+ }
+ return score;
+ }
+
+ /**
+ * A convenience method for returning the count of numbers in a given String.
+ *
+ * @param stringToCheck
+ * @return The numbers of digits in the String
+ */
+ protected int getNumberCount(String stringToCheck) {
+ int score = 0;
+ int loops = stringToCheck.length() - 1;
+ for (int i = 0; i <= loops; i++) {
+ if (Character.isDigit(stringToCheck.charAt(i))) {
+ score++;
+ }
+ }
+ return score;
+ }
+
+ /**
+ * Set the guides to show on the view.<br />
+ * On the line style, the guides will show underneath<br />
+ * On the rounded style, the guides will be shown on the outer edges.<br />
+ * The view will be redrawn after the method is called.
+ *
+ * @param showGuides True if you want the guides to be shown
+ */
+ public void setShowGuides(boolean showGuides) {
+ mShowGuides = showGuides;
+ if (mPassword != null && mPassword.length() > 0) {
+ generatePasswordScore();
+ } else {
+ mCurrentScore = 0;
+ }
+
+ invalidate();
+ requestLayout();
+ }
+
+ /**
+ * Determine whether the view is showing the guides for the password score
+ *
+ * @return True if the guides are being shown
+ */
+ public boolean isShowingGuides() {
+ return mShowGuides;
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java
index 44bcc52a5..c66dc04d0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java
@@ -296,7 +296,9 @@ public class ContactHelper {
ContentResolver resolver = context.getContentResolver();
Set<Long> deletedKeys = getRawContactMasterKeyIds(resolver);
-// debugDeleteRawContacts(resolver);
+ if (Constants.DEBUG_SYNC_REMOVE_CONTACTS) {
+ debugDeleteRawContacts(resolver);
+ }
// ContentProviderClient client = resolver.acquireContentProviderClient(ContactsContract.AUTHORITY_URI);
// ContentValues values = new ContentValues();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java
index a36af5c87..44c1e6b6c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java
@@ -20,11 +20,7 @@ package org.sufficientlysecure.keychain.util;
import android.content.Context;
import android.content.SharedPreferences;
-import android.os.Build;
-import org.spongycastle.bcpg.CompressionAlgorithmTags;
-import org.spongycastle.bcpg.HashAlgorithmTags;
-import org.spongycastle.openpgp.PGPEncryptedData;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Constants.Pref;
@@ -59,12 +55,8 @@ public class Preferences {
}
public void updateSharedPreferences(Context context) {
- // multi-process preferences
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
- mSharedPreferences = context.getSharedPreferences("APG.main", Context.MODE_MULTI_PROCESS);
- } else {
- mSharedPreferences = context.getSharedPreferences("APG.main", Context.MODE_PRIVATE);
- }
+ // multi-process safe preferences
+ mSharedPreferences = context.getSharedPreferences("APG.main", Context.MODE_MULTI_PROCESS);
}
public String getLanguage() {
@@ -103,60 +95,6 @@ public class Preferences {
editor.commit();
}
- public int getDefaultEncryptionAlgorithm() {
- return mSharedPreferences.getInt(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM,
- PGPEncryptedData.AES_256);
- }
-
- public void setDefaultEncryptionAlgorithm(int value) {
- SharedPreferences.Editor editor = mSharedPreferences.edit();
- editor.putInt(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM, value);
- editor.commit();
- }
-
- public int getDefaultHashAlgorithm() {
- return mSharedPreferences.getInt(Constants.Pref.DEFAULT_HASH_ALGORITHM,
- HashAlgorithmTags.SHA256);
- }
-
- public void setDefaultHashAlgorithm(int value) {
- SharedPreferences.Editor editor = mSharedPreferences.edit();
- editor.putInt(Constants.Pref.DEFAULT_HASH_ALGORITHM, value);
- editor.commit();
- }
-
- public int getDefaultMessageCompression() {
- return mSharedPreferences.getInt(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION,
- CompressionAlgorithmTags.ZLIB);
- }
-
- public void setDefaultMessageCompression(int value) {
- SharedPreferences.Editor editor = mSharedPreferences.edit();
- editor.putInt(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION, value);
- editor.commit();
- }
-
- public int getDefaultFileCompression() {
- return mSharedPreferences.getInt(Constants.Pref.DEFAULT_FILE_COMPRESSION,
- CompressionAlgorithmTags.UNCOMPRESSED);
- }
-
- public void setDefaultFileCompression(int value) {
- SharedPreferences.Editor editor = mSharedPreferences.edit();
- editor.putInt(Constants.Pref.DEFAULT_FILE_COMPRESSION, value);
- editor.commit();
- }
-
- public boolean getDefaultAsciiArmor() {
- return mSharedPreferences.getBoolean(Constants.Pref.DEFAULT_ASCII_ARMOR, false);
- }
-
- public void setDefaultAsciiArmor(boolean value) {
- SharedPreferences.Editor editor = mSharedPreferences.edit();
- editor.putBoolean(Constants.Pref.DEFAULT_ASCII_ARMOR, value);
- editor.commit();
- }
-
public boolean getCachedConsolidate() {
return mSharedPreferences.getBoolean(Pref.CACHED_CONSOLIDATE, false);
}
@@ -210,6 +148,7 @@ public class Preferences {
}
return servers.toArray(chunks);
}
+
public String getPreferredKeyserver() {
return getKeyServers()[0];
}
@@ -231,21 +170,12 @@ public class Preferences {
editor.commit();
}
- public void setWriteVersionHeader(boolean conceal) {
- SharedPreferences.Editor editor = mSharedPreferences.edit();
- editor.putBoolean(Constants.Pref.WRITE_VERSION_HEADER, conceal);
- editor.commit();
- }
-
- public boolean getWriteVersionHeader() {
- return mSharedPreferences.getBoolean(Constants.Pref.WRITE_VERSION_HEADER, false);
- }
-
public void setSearchKeyserver(boolean searchKeyserver) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putBoolean(Pref.SEARCH_KEYSERVER, searchKeyserver);
editor.commit();
}
+
public void setSearchKeybase(boolean searchKeybase) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putBoolean(Pref.SEARCH_KEYBASE, searchKeybase);
@@ -253,7 +183,7 @@ public class Preferences {
}
public CloudSearchPrefs getCloudSearchPrefs() {
- return new CloudSearchPrefs(mSharedPreferences.getBoolean(Pref.SEARCH_KEYSERVER, true),
+ return new CloudSearchPrefs(mSharedPreferences.getBoolean(Pref.SEARCH_KEYSERVER, true),
mSharedPreferences.getBoolean(Pref.SEARCH_KEYBASE, true),
getPreferredKeyserver());
}
@@ -301,26 +231,9 @@ public class Preferences {
}
setKeyServers(servers.toArray(new String[servers.size()]));
-
- // migrate old uncompressed constant to new one
- if (mSharedPreferences.getInt(Constants.Pref.DEFAULT_FILE_COMPRESSION, 0)
- == 0x21070001) {
- setDefaultFileCompression(CompressionAlgorithmTags.UNCOMPRESSED);
- }
-
- // migrate away from MD5
- if (mSharedPreferences.getInt(Constants.Pref.DEFAULT_HASH_ALGORITHM, 0)
- == HashAlgorithmTags.MD5) {
- setDefaultHashAlgorithm(HashAlgorithmTags.SHA256);
- }
}
// fall through
case 4: {
- // for compatibility: change from SHA512 to SHA256
- if (mSharedPreferences.getInt(Constants.Pref.DEFAULT_HASH_ALGORITHM, 0)
- == HashAlgorithmTags.SHA512) {
- setDefaultHashAlgorithm(HashAlgorithmTags.SHA256);
- }
}
}
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_action_accounts.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_accounts.png
deleted file mode 100644
index 10c77d07d..000000000
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_action_accounts.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_vpn_key_grey_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_vpn_key_grey_24dp.png
new file mode 100644
index 000000000..cbc93ca36
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_vpn_key_grey_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_action_accounts.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_accounts.png
deleted file mode 100644
index 41b89b5b6..000000000
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_action_accounts.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_vpn_key_grey_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_vpn_key_grey_24dp.png
new file mode 100644
index 000000000..7acfab4f4
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_vpn_key_grey_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_accounts.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_accounts.png
deleted file mode 100644
index ee8067c7d..000000000
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_accounts.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_vpn_key_grey_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_vpn_key_grey_24dp.png
new file mode 100644
index 000000000..49a44704c
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_vpn_key_grey_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_accounts.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_accounts.png
deleted file mode 100644
index d9b5cc007..000000000
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_accounts.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_vpn_key_grey_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_vpn_key_grey_24dp.png
new file mode 100644
index 000000000..6e1aa32c4
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_vpn_key_grey_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_action_accounts.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_action_accounts.png
deleted file mode 100644
index be1bc9ef4..000000000
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_action_accounts.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_vpn_key_grey_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_vpn_key_grey_24dp.png
new file mode 100644
index 000000000..2ea2bf77c
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_vpn_key_grey_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml b/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml
index 79137bf51..c1b97b02c 100644
--- a/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml
+++ b/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml
@@ -8,13 +8,12 @@
android:paddingLeft="24dp"
android:paddingRight="24dp">
- <org.sufficientlysecure.keychain.ui.widget.AutoCorrectAutoCompleteTextView
+ <org.sufficientlysecure.keychain.ui.widget.EmailEditText
android:id="@+id/add_user_id_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/label_email"
android:imeOptions="actionNext"
- android:inputType="textAutoCorrect|textEmailAddress"
android:textAppearance="?android:attr/textAppearanceMedium" />
<org.sufficientlysecure.keychain.ui.widget.AutoCorrectAutoCompleteTextView
diff --git a/OpenKeychain/src/main/res/layout/create_key_input_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_input_fragment.xml
index d817f9269..b320885d0 100644
--- a/OpenKeychain/src/main/res/layout/create_key_input_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_key_input_fragment.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -42,13 +43,12 @@
android:hint="@string/create_key_hint_full_name"
android:ems="10" />
- <org.sufficientlysecure.keychain.ui.widget.AutoCorrectAutoCompleteTextView
+ <org.sufficientlysecure.keychain.ui.widget.EmailEditText
android:id="@+id/create_key_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:imeOptions="actionNext"
- android:inputType="textAutoCorrect|textEmailAddress"
android:hint="@string/label_email"
android:ems="10" />
@@ -58,17 +58,33 @@
android:layout_height="wrap_content"
android:text="@string/label_passphrase" />
- <EditText
- android:id="@+id/create_key_passphrase"
+ <FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
- android:layout_marginBottom="8dp"
- android:imeOptions="actionNext"
- android:inputType="textPassword"
- android:hint="@string/label_passphrase"
- android:ems="10"
- android:layout_gravity="center_horizontal" />
+ android:layout_marginBottom="8dp">
+
+ <org.sufficientlysecure.keychain.ui.widget.PasswordEditText
+ android:id="@+id/create_key_passphrase"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="actionNext"
+ android:hint="@string/label_passphrase"
+ android:ems="10"
+ android:layout_gravity="center_horizontal" />
+
+ <org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator.PasswordStrengthBarView
+ android:id="@+id/create_key_passphrase_strength"
+ android:layout_width="48dp"
+ android:layout_height="8dp"
+ android:layout_gravity="end|center_vertical"
+ custom:strength="medium"
+ custom:showGuides="false"
+ custom:color_fail="@color/android_red_light"
+ custom:color_weak="@color/android_orange_light"
+ custom:color_strong="@color/android_green_light" />
+
+ </FrameLayout>
<EditText
android:id="@+id/create_key_passphrase_again"
diff --git a/OpenKeychain/src/main/res/layout/decrypt_result_include.xml b/OpenKeychain/src/main/res/layout/decrypt_result_include.xml
index 7317e7742..9d47009b9 100644
--- a/OpenKeychain/src/main/res/layout/decrypt_result_include.xml
+++ b/OpenKeychain/src/main/res/layout/decrypt_result_include.xml
@@ -118,7 +118,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="Show"
- android:drawableRight="@drawable/ic_action_accounts"
+ android:drawableRight="@drawable/ic_vpn_key_grey_24dp"
android:drawablePadding="8dp"
android:gravity="center_vertical"
style="@style/SelectableItem" />
diff --git a/OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml b/OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml
index 09e37ee56..11355bbc0 100644
--- a/OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml
+++ b/OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
@@ -14,17 +15,35 @@
android:layout_height="wrap_content"
android:text="@string/label_no_passphrase" />
- <EditText
- android:id="@+id/passphrase_passphrase"
+ <FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
- android:layout_marginBottom="8dp"
- android:imeOptions="actionNext"
- android:inputType="textPassword"
- android:hint="@string/label_passphrase"
- android:ems="10"
- android:layout_gravity="center_horizontal" />
+ android:layout_marginBottom="8dp">
+
+ <org.sufficientlysecure.keychain.ui.widget.PasswordEditText
+ android:id="@+id/passphrase_passphrase"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
+ android:imeOptions="actionNext"
+ android:hint="@string/label_passphrase"
+ android:ems="10"
+ android:layout_gravity="center_horizontal" />
+
+ <org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator.PasswordStrengthBarView
+ android:id="@+id/passphrase_repeat_passphrase_strength"
+ android:layout_width="48dp"
+ android:layout_height="8dp"
+ android:layout_gravity="end|center_vertical"
+ custom:strength="medium"
+ custom:showGuides="false"
+ custom:color_fail="@color/android_red_light"
+ custom:color_weak="@color/android_orange_light"
+ custom:color_strong="@color/android_green_light" />
+
+ </FrameLayout>
<EditText
android:id="@+id/passphrase_passphrase_again"
diff --git a/OpenKeychain/src/main/res/menu/encrypt_file_activity.xml b/OpenKeychain/src/main/res/menu/encrypt_file_activity.xml
index fd0a85d6c..9a26d1757 100644
--- a/OpenKeychain/src/main/res/menu/encrypt_file_activity.xml
+++ b/OpenKeychain/src/main/res/menu/encrypt_file_activity.xml
@@ -12,4 +12,9 @@
android:id="@+id/check_delete_after_encrypt"
android:title="@string/label_delete_after_encryption"
android:checkable="true" />
+ <item
+ android:id="@+id/check_enable_compression"
+ android:title="@string/label_enable_compression"
+ android:checked="true"
+ android:checkable="true" />
</menu> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/menu/encrypt_text_activity.xml b/OpenKeychain/src/main/res/menu/encrypt_text_activity.xml
index 8deb59514..71d254bb9 100644
--- a/OpenKeychain/src/main/res/menu/encrypt_text_activity.xml
+++ b/OpenKeychain/src/main/res/menu/encrypt_text_activity.xml
@@ -4,4 +4,9 @@
android:id="@+id/check_use_symmetric"
android:title="@string/label_symmetric"
android:checkable="true" />
+ <item
+ android:id="@+id/check_enable_compression"
+ android:title="@string/label_enable_compression"
+ android:checked="true"
+ android:checkable="true" />
</menu> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/values/attr.xml b/OpenKeychain/src/main/res/values/attr.xml
index 98ce1c364..7a2f3054e 100644
--- a/OpenKeychain/src/main/res/values/attr.xml
+++ b/OpenKeychain/src/main/res/values/attr.xml
@@ -15,4 +15,18 @@
</attr>
</declare-styleable>
+ <!-- Taken from Matt Allen Password Strength View
+ https://github.com/matt-allen/android-password-strength-indicator -->
+ <declare-styleable name="PasswordStrengthView">
+ <attr name="strength" format="enum">
+ <enum name="weak" value="0" />
+ <enum name="medium" value="1" />
+ <enum name="strong" value="2" />
+ </attr>
+ <attr name="showGuides" format="boolean" />
+ <attr name="color_fail" format="color" />
+ <attr name="color_weak" format="color" />
+ <attr name="color_strong" format="color" />
+ </declare-styleable>
+
</resources> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 799008a2d..4a2be2eb8 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -162,6 +162,7 @@
<string name="expiry_date_dialog_title">"Set expiry date"</string>
<string name="label_first_keyserver_is_used">"(First keyserver listed is preferred)"</string>
<string name="label_preferred">"preferred"</string>
+ <string name="label_enable_compression">"Enable compression"</string>
<string name="user_id_no_name">"&lt;no name&gt;"</string>
<string name="none">"&lt;none&gt;"</string>
@@ -988,6 +989,7 @@
<string name="msg_dc_clear_meta_size_unknown">"File size is unknown"</string>
<string name="msg_dc_clear_meta_time">"Modification time: %s"</string>
<string name="msg_dc_clear_signature_bad">"Signature check NOT OK!"</string>
+ <string name="msg_dc_error_unsupported_hash_algo">"Unsupported and potentially insecure hash algorithm!"</string>
<string name="msg_dc_clear_signature_check">"Verifying signature data"</string>
<string name="msg_dc_clear_signature_ok">"Signature check OK"</string>
<string name="msg_dc_clear_signature">"Saving signature data for later"</string>
@@ -1003,7 +1005,7 @@
<string name="msg_dc_error_pgp_exception">"Encountered OpenPGP Exception during operation!"</string>
<string name="msg_dc_integrity_check_ok">"Integrity check OK!"</string>
<string name="msg_dc_ok_meta_only">"Only metadata was requested, skipping decryption"</string>
- <string name="msg_dc_ok">"OK"</string>
+ <string name="msg_dc_ok">"Decryption/Verification finished"</string>
<string name="msg_dc_pass_cached">"Using passphrase from cache"</string>
<string name="msg_dc_pending_nfc">"NFC token required, requesting user input…"</string>
<string name="msg_dc_pending_passphrase">"Passphrase required, requesting user input…"</string>
@@ -1015,6 +1017,7 @@
<string name="msg_dc_trail_sym">"Encountered trailing, symmetrically encrypted data"</string>
<string name="msg_dc_trail_unknown">"Encountered trailing data of unknown type"</string>
<string name="msg_dc_unlocking">"Unlocking secret key"</string>
+ <string name="msg_dc_old_symmetric_encryption_algo">"Potentially insecure encryption algorithm has been used!"</string>
<!-- Messages for VerifySignedLiteralData operation -->
<string name="msg_vl">"Starting signature check"</string>
@@ -1069,11 +1072,14 @@
<string name="msg_pse_symmetric">"Preparing symmetric encryption"</string>
<string name="msg_crt_certifying">"Generating certifications"</string>
- <string name="msg_crt_certify_all">"Certifying all user IDs for key %s"</string>
- <plurals name="msg_crt_certify_some">
+ <plurals name="msg_crt_certify_uids">
<item quantity="one">"Certifying one user ID for key %2$s"</item>
<item quantity="other">"Certifying %1$d user IDs for key %2$s"</item>
</plurals>
+ <plurals name="msg_crt_certify_uats">
+ <item quantity="one">"Certifying one user attribute for key %2$s"</item>
+ <item quantity="other">"Certifying %1$d user attributes for key %2$s"</item>
+ </plurals>
<string name="msg_crt_error_self">"Cannot issue self-certificate like this!"</string>
<string name="msg_crt_error_master_not_found">"Master key not found!"</string>
<string name="msg_crt_error_nothing">"No keys certified!"</string>
diff --git a/OpenKeychain/src/main/res/xml/adv_preferences.xml b/OpenKeychain/src/main/res/xml/adv_preferences.xml
index 02986bdad..7dd649e5d 100644
--- a/OpenKeychain/src/main/res/xml/adv_preferences.xml
+++ b/OpenKeychain/src/main/res/xml/adv_preferences.xml
@@ -1,52 +1,23 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
- <PreferenceCategory android:title="@string/section_defaults">
- <CheckBoxPreference
- android:key="writeVersionHeader"
- android:persistent="false"
- android:title="@string/label_write_version_header"
- android:summary="@string/label_write_version_header_summary" />
- <org.sufficientlysecure.keychain.ui.widget.IntegerListPreference
- android:key="defaultEncryptionAlgorithm"
- android:persistent="false"
- android:title="@string/label_encryption_algorithm" />
- <org.sufficientlysecure.keychain.ui.widget.IntegerListPreference
- android:key="defaultHashAlgorithm"
- android:persistent="false"
- android:title="@string/label_hash_algorithm" />
- <org.sufficientlysecure.keychain.ui.widget.IntegerListPreference
- android:key="defaultMessageCompression"
- android:persistent="false"
- android:title="@string/label_message_compression" />
- <org.sufficientlysecure.keychain.ui.widget.IntegerListPreference
- android:key="defaultFileCompression"
- android:persistent="false"
- android:title="@string/label_file_compression" />
- <CheckBoxPreference
- android:key="defaultAsciiArmor"
- android:persistent="false"
- android:title="@string/label_ascii_armor" />
- </PreferenceCategory>
- <PreferenceCategory android:title="@string/section_passphrase_cache">
- <org.sufficientlysecure.keychain.ui.widget.IntegerListPreference
- android:entries="@array/passphrase_cache_ttl_entries"
- android:entryValues="@array/passphrase_cache_ttl_values"
- android:key="passphraseCacheTtl"
- android:persistent="false"
- android:title="@string/label_passphrase_cache_ttl" />
- <CheckBoxPreference
- android:key="passphraseCacheSubs"
- android:persistent="false"
- android:title="@string/label_passphrase_cache_subs" />
- <CheckBoxPreference
- android:key="useDefaultYubikeyPin"
- android:persistent="false"
- android:defaultValue="true"
- android:title="@string/label_use_default_yubikey_pin"
- android:summary="@string/label_label_use_default_yubikey_pin_summary" />
- <CheckBoxPreference
- android:key="useNumKeypadForYubikeyPin"
- android:persistent="false"
- android:defaultValue="false"
- android:title="@string/label_use_num_keypad_for_yubikey_pin" />
- </PreferenceCategory>
+ <org.sufficientlysecure.keychain.ui.widget.IntegerListPreference
+ android:entries="@array/passphrase_cache_ttl_entries"
+ android:entryValues="@array/passphrase_cache_ttl_values"
+ android:key="passphraseCacheTtl"
+ android:persistent="false"
+ android:title="@string/label_passphrase_cache_ttl" />
+ <CheckBoxPreference
+ android:key="passphraseCacheSubs"
+ android:persistent="false"
+ android:title="@string/label_passphrase_cache_subs" />
+ <CheckBoxPreference
+ android:key="useDefaultYubikeyPin"
+ android:persistent="false"
+ android:defaultValue="true"
+ android:title="@string/label_use_default_yubikey_pin"
+ android:summary="@string/label_label_use_default_yubikey_pin_summary" />
+ <CheckBoxPreference
+ android:key="useNumKeypadForYubikeyPin"
+ android:persistent="false"
+ android:defaultValue="false"
+ android:title="@string/label_use_num_keypad_for_yubikey_pin" />
</PreferenceScreen>
diff --git a/OpenKeychain/src/main/res/xml/preference_headers.xml b/OpenKeychain/src/main/res/xml/preference_headers.xml
index 347394b06..e3447ff48 100644
--- a/OpenKeychain/src/main/res/xml/preference_headers.xml
+++ b/OpenKeychain/src/main/res/xml/preference_headers.xml
@@ -4,5 +4,5 @@
android:title="@string/section_cloud_search" />
<header
android:fragment="org.sufficientlysecure.keychain.ui.SettingsActivity$AdvancedPrefsFragment"
- android:title="@string/section_advanced" />
+ android:title="@string/section_passphrase_cache" />
</preference-headers>