diff options
author | Vincent Breitmoser <valodim@mugenguild.com> | 2015-03-08 01:49:22 +0100 |
---|---|---|
committer | Vincent Breitmoser <valodim@mugenguild.com> | 2015-03-08 01:49:22 +0100 |
commit | 2b5023a75d0c98738ed1aea2ea89de007cf2e3d7 (patch) | |
tree | 8617aa8dcad7e32c9cb5b8483534d888aaf0c7d0 /OpenKeychain/src/main/java | |
parent | 581cad5b3f7b54fae652e2598b4e760eb19678d2 (diff) | |
parent | 4f11fb5a2f08ecf5fb81c86d590d04387cd1cd9a (diff) | |
download | open-keychain-2b5023a75d0c98738ed1aea2ea89de007cf2e3d7.tar.gz open-keychain-2b5023a75d0c98738ed1aea2ea89de007cf2e3d7.tar.bz2 open-keychain-2b5023a75d0c98738ed1aea2ea89de007cf2e3d7.zip |
Merge branch 'development' into linked-identities
Conflicts:
OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
Diffstat (limited to 'OpenKeychain/src/main/java')
32 files changed, 1154 insertions, 540 deletions
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); - } } } |