From e72e47d92ec957d42c04bf8b1e0dd8e8b641cd7b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Thu, 14 Aug 2014 15:24:37 +0200
Subject: [PATCH 001/142] Remove support for v3 sig generation
---
.../keychain/Constants.java | 1 -
.../keychain/helper/Preferences.java | 10 ---
.../keychain/pgp/PgpSignEncrypt.java | 90 +++----------------
.../keychain/remote/OpenPgpService.java | 2 -
.../service/KeychainIntentService.java | 1 -
.../keychain/ui/PreferencesActivity.java | 18 ----
OpenKeychain/src/main/res/values/strings.xml | 1 -
.../src/main/res/xml/adv_preferences.xml | 12 +--
8 files changed, 13 insertions(+), 122 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
index f240b5cc2..755d74ac2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
@@ -64,7 +64,6 @@ public final class Constants {
public static final String DEFAULT_FILE_COMPRESSION = "defaultFileCompression";
public static final String PASSPHRASE_CACHE_TTL = "passphraseCacheTtl";
public static final String LANGUAGE = "language";
- public static final String FORCE_V3_SIGNATURES = "forceV3Signatures";
public static final String KEY_SERVERS = "keyServers";
public static final String KEY_SERVERS_DEFAULT_VERSION = "keyServersDefaultVersion";
public static final String WRITE_VERSION_HEADER = "writeVersionHeader";
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
index a0bac80aa..72e88d793 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
@@ -130,16 +130,6 @@ public class Preferences {
editor.commit();
}
- public boolean getForceV3Signatures() {
- return mSharedPreferences.getBoolean(Constants.Pref.FORCE_V3_SIGNATURES, false);
- }
-
- public void setForceV3Signatures(boolean value) {
- SharedPreferences.Editor editor = mSharedPreferences.edit();
- editor.putBoolean(Constants.Pref.FORCE_V3_SIGNATURES, value);
- editor.commit();
- }
-
public boolean isFirstTime() {
return mSharedPreferences.getBoolean(Constants.Pref.FIRST_TIME, true);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
index b0e546662..263b0c5bb 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
@@ -27,7 +27,6 @@ import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPLiteralData;
import org.spongycastle.openpgp.PGPLiteralDataGenerator;
import org.spongycastle.openpgp.PGPSignatureGenerator;
-import org.spongycastle.openpgp.PGPV3SignatureGenerator;
import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator;
import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.sufficientlysecure.keychain.Constants;
@@ -68,7 +67,6 @@ public class PgpSignEncrypt {
private int mSymmetricEncryptionAlgorithm;
private long mSignatureMasterKeyId;
private int mSignatureHashAlgorithm;
- private boolean mSignatureForceV3;
private String mSignaturePassphrase;
private boolean mEncryptToSigner;
private boolean mCleartextInput;
@@ -99,7 +97,6 @@ public class PgpSignEncrypt {
this.mSymmetricEncryptionAlgorithm = builder.mSymmetricEncryptionAlgorithm;
this.mSignatureMasterKeyId = builder.mSignatureMasterKeyId;
this.mSignatureHashAlgorithm = builder.mSignatureHashAlgorithm;
- this.mSignatureForceV3 = builder.mSignatureForceV3;
this.mSignaturePassphrase = builder.mSignaturePassphrase;
this.mEncryptToSigner = builder.mEncryptToSigner;
this.mCleartextInput = builder.mCleartextInput;
@@ -122,7 +119,6 @@ public class PgpSignEncrypt {
private int mSymmetricEncryptionAlgorithm = 0;
private long mSignatureMasterKeyId = Constants.key.none;
private int mSignatureHashAlgorithm = 0;
- private boolean mSignatureForceV3 = false;
private String mSignaturePassphrase = null;
private boolean mEncryptToSigner = false;
private boolean mCleartextInput = false;
@@ -179,11 +175,6 @@ public class PgpSignEncrypt {
return this;
}
- public Builder setSignatureForceV3(boolean signatureForceV3) {
- mSignatureForceV3 = signatureForceV3;
- return this;
- }
-
public Builder setSignaturePassphrase(String signaturePassphrase) {
mSignaturePassphrase = signaturePassphrase;
return this;
@@ -349,19 +340,13 @@ public class PgpSignEncrypt {
/* Initialize signature generator object for later usage */
PGPSignatureGenerator signatureGenerator = null;
- PGPV3SignatureGenerator signatureV3Generator = null;
if (enableSignature) {
updateProgress(R.string.progress_preparing_signature, 4, 100);
try {
boolean cleartext = mCleartextInput && mEnableAsciiArmorOutput && !enableEncryption;
- if (mSignatureForceV3) {
- signatureV3Generator = signingKey.getV3SignatureGenerator(
- mSignatureHashAlgorithm, cleartext);
- } else {
- signatureGenerator = signingKey.getSignatureGenerator(
- mSignatureHashAlgorithm, cleartext);
- }
+ signatureGenerator = signingKey.getSignatureGenerator(
+ mSignatureHashAlgorithm, cleartext);
} catch (PgpGeneralException e) {
// TODO throw correct type of exception (which shouldn't be PGPException)
throw new KeyExtractionException();
@@ -388,11 +373,7 @@ public class PgpSignEncrypt {
}
if (enableSignature) {
- if (mSignatureForceV3) {
- signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut);
- } else {
- signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
- }
+ signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
}
PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
@@ -408,11 +389,7 @@ public class PgpSignEncrypt {
// update signature buffer if signature is requested
if (enableSignature) {
- if (mSignatureForceV3) {
- signatureV3Generator.update(buffer, 0, length);
- } else {
- signatureGenerator.update(buffer, 0, length);
- }
+ signatureGenerator.update(buffer, 0, length);
}
alreadyWritten += length;
@@ -435,11 +412,7 @@ public class PgpSignEncrypt {
final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
// update signature buffer with first line
- if (mSignatureForceV3) {
- processLineV3(reader.readLine(), armorOut, signatureV3Generator);
- } else {
- processLine(reader.readLine(), armorOut, signatureGenerator);
- }
+ processLine(reader.readLine(), armorOut, signatureGenerator);
// TODO: progress: fake annealing?
while (true) {
@@ -454,13 +427,8 @@ public class PgpSignEncrypt {
armorOut.write(NEW_LINE);
// update signature buffer with input line
- if (mSignatureForceV3) {
- signatureV3Generator.update(NEW_LINE);
- processLineV3(line, armorOut, signatureV3Generator);
- } else {
- signatureGenerator.update(NEW_LINE);
- processLine(line, armorOut, signatureGenerator);
- }
+ signatureGenerator.update(NEW_LINE);
+ processLine(line, armorOut, signatureGenerator);
}
armorOut.endClearText();
@@ -480,11 +448,7 @@ public class PgpSignEncrypt {
bcpgOut = new BCPGOutputStream(out);
}
- if (mSignatureForceV3) {
- signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut);
- } else {
- signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
- }
+ signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, mOriginalFilename, new Date(),
@@ -496,11 +460,7 @@ public class PgpSignEncrypt {
while ((length = in.read(buffer)) > 0) {
pOut.write(buffer, 0, length);
- if (mSignatureForceV3) {
- signatureV3Generator.update(buffer, 0, length);
- } else {
- signatureGenerator.update(buffer, 0, length);
- }
+ signatureGenerator.update(buffer, 0, length);
alreadyWritten += length;
if (mData.getSize() > 0) {
@@ -517,11 +477,7 @@ public class PgpSignEncrypt {
if (enableSignature) {
updateProgress(R.string.progress_generating_signature, 95, 100);
- if (mSignatureForceV3) {
- signatureV3Generator.generate().encode(pOut);
- } else {
- signatureGenerator.generate().encode(pOut);
- }
+ signatureGenerator.generate().encode(pOut);
}
// closing outputs
@@ -570,30 +526,4 @@ public class PgpSignEncrypt {
pSignatureGenerator.update(data);
}
- private static void processLineV3(final String pLine, final ArmoredOutputStream pArmoredOutput,
- final PGPV3SignatureGenerator pSignatureGenerator)
- throws IOException, SignatureException {
-
- if (pLine == null) {
- return;
- }
-
- final char[] chars = pLine.toCharArray();
- int len = chars.length;
-
- while (len > 0) {
- if (!Character.isWhitespace(chars[len - 1])) {
- break;
- }
- len--;
- }
-
- final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
-
- if (pArmoredOutput != null) {
- pArmoredOutput.write(data);
- }
- pSignatureGenerator.update(data);
- }
-
}
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 492ade7c3..3541dad98 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -191,7 +191,6 @@ public class OpenPgpService extends RemoteService {
builder.setEnableAsciiArmorOutput(asciiArmor)
.setVersionHeader(PgpHelper.getVersionForHeader(this))
.setSignatureHashAlgorithm(accSettings.getHashAlgorithm())
- .setSignatureForceV3(false)
.setSignatureMasterKeyId(accSettings.getKeyId())
.setSignaturePassphrase(passphrase);
@@ -299,7 +298,6 @@ public class OpenPgpService extends RemoteService {
// sign and encrypt
builder.setSignatureHashAlgorithm(accSettings.getHashAlgorithm())
- .setSignatureForceV3(false)
.setSignatureMasterKeyId(accSettings.getKeyId())
.setSignaturePassphrase(passphrase);
} else {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index d1d848066..d6c470e11 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -257,7 +257,6 @@ public class KeychainIntentService extends IntentService
.setCompressionId(compressionId)
.setSymmetricEncryptionAlgorithm(
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
- .setSignatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
.setEncryptionMasterKeyIds(encryptionKeyIds)
.setSymmetricPassphrase(symmetricPassphrase)
.setSignatureMasterKeyId(signatureKeyId)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java
index 5bef6cc9f..de3236d35 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java
@@ -119,9 +119,6 @@ public class PreferencesActivity extends PreferenceActivity {
initializeAsciiArmor(
(CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOR));
- initializeForceV3Signatures(
- (CheckBoxPreference) findPreference(Constants.Pref.FORCE_V3_SIGNATURES));
-
initializeWriteVersionHeader(
(CheckBoxPreference) findPreference(Constants.Pref.WRITE_VERSION_HEADER));
@@ -266,9 +263,6 @@ public class PreferencesActivity extends PreferenceActivity {
initializeAsciiArmor(
(CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOR));
- initializeForceV3Signatures(
- (CheckBoxPreference) findPreference(Constants.Pref.FORCE_V3_SIGNATURES));
-
initializeWriteVersionHeader(
(CheckBoxPreference) findPreference(Constants.Pref.WRITE_VERSION_HEADER));
}
@@ -392,18 +386,6 @@ public class PreferencesActivity extends PreferenceActivity {
});
}
- private static void initializeForceV3Signatures(final CheckBoxPreference mForceV3Signatures) {
- mForceV3Signatures.setChecked(sPreferences.getForceV3Signatures());
- mForceV3Signatures
- .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- mForceV3Signatures.setChecked((Boolean) newValue);
- sPreferences.setForceV3Signatures((Boolean) newValue);
- return false;
- }
- });
- }
-
private static void initializeWriteVersionHeader(final CheckBoxPreference mWriteVersionHeader) {
mWriteVersionHeader.setChecked(sPreferences.getWriteVersionHeader());
mWriteVersionHeader.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 8ccb92854..09a434d5d 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -103,7 +103,6 @@
Passphrase Cache
Message Compression
File Compression
- Force old OpenPGPv3 Signatures
Keyservers
Key ID
Creation
diff --git a/OpenKeychain/src/main/res/xml/adv_preferences.xml b/OpenKeychain/src/main/res/xml/adv_preferences.xml
index 588a6e62d..49f241ffe 100644
--- a/OpenKeychain/src/main/res/xml/adv_preferences.xml
+++ b/OpenKeychain/src/main/res/xml/adv_preferences.xml
@@ -16,7 +16,7 @@
-->
-
+
-
-
+
+
-
-
-
From 225e2482935fbe93147303654f09536b605eac96 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Thu, 14 Aug 2014 15:30:08 +0200
Subject: [PATCH 002/142] Remove MD5 support
---
.../org/sufficientlysecure/keychain/helper/Preferences.java | 5 +++++
.../sufficientlysecure/keychain/ui/PreferencesActivity.java | 4 ++--
.../org/sufficientlysecure/keychain/util/AlgorithmNames.java | 1 -
3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
index 72e88d793..80b047530 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
@@ -193,6 +193,11 @@ public class Preferences {
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.SHA512);
+ }
}
public void setWriteVersionHeader(boolean conceal) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java
index de3236d35..64c1e16be 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java
@@ -317,10 +317,10 @@ public class PreferencesActivity extends PreferenceActivity {
private static void initializeHashAlgorithm
(final IntegerListPreference mHashAlgorithm, int[] valueIds, String[] entries, String[] values) {
- valueIds = new int[]{HashAlgorithmTags.MD5, HashAlgorithmTags.RIPEMD160,
+ valueIds = new int[]{HashAlgorithmTags.RIPEMD160,
HashAlgorithmTags.SHA1, HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256,
HashAlgorithmTags.SHA384, HashAlgorithmTags.SHA512,};
- entries = new String[]{"MD5", "RIPEMD-160", "SHA-1", "SHA-224", "SHA-256", "SHA-384",
+ entries = new String[]{"RIPEMD-160", "SHA-1", "SHA-224", "SHA-256", "SHA-384",
"SHA-512",};
values = new String[valueIds.length];
for (int i = 0; i < values.length; ++i) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java
index 9acc7a73b..99db634ac 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java
@@ -50,7 +50,6 @@ public class AlgorithmNames {
mEncryptionNames.put(PGPEncryptedData.TRIPLE_DES, "Triple DES");
mEncryptionNames.put(PGPEncryptedData.IDEA, "IDEA");
- mHashNames.put(HashAlgorithmTags.MD5, "MD5");
mHashNames.put(HashAlgorithmTags.RIPEMD160, "RIPEMD-160");
mHashNames.put(HashAlgorithmTags.SHA1, "SHA-1");
mHashNames.put(HashAlgorithmTags.SHA224, "SHA-224");
From 0a1de8deeaa543f3a0658c3927fd632d115e34fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Thu, 14 Aug 2014 15:42:02 +0200
Subject: [PATCH 003/142] Do not import v3 keys, they are insecure!
---
.../keychain/pgp/UncachedKeyRing.java | 4 ++++
.../keychain/provider/ProviderHelper.java | 10 ++++++++++
.../keychain/service/OperationResultParcel.java | 1 +
OpenKeychain/src/main/res/values/strings.xml | 3 ++-
4 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
index 73a51942d..18f27cbff 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -118,6 +118,10 @@ public class UncachedKeyRing {
return mRing.getPublicKey().getFingerprint();
}
+ public int getVersion() {
+ return mRing.getPublicKey().getVersion();
+ }
+
public static UncachedKeyRing decodeFromData(byte[] data)
throws PgpGeneralException, IOException {
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 a13bb9c98..f8b2e549f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -642,6 +642,11 @@ public class ProviderHelper {
log(LogLevel.START, LogType.MSG_IP, PgpKeyHelper.convertKeyIdToHex(masterKeyId));
mIndent += 1;
+ if (publicRing.getVersion() <= 3) {
+ log(LogLevel.ERROR, LogType.MSG_IP_V3_KEY);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ }
+
if (publicRing.isSecret()) {
log(LogLevel.ERROR, LogType.MSG_IP_BAD_TYPE_SECRET);
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
@@ -734,6 +739,11 @@ public class ProviderHelper {
log(LogLevel.START, LogType.MSG_IS, PgpKeyHelper.convertKeyIdToHex(masterKeyId));
mIndent += 1;
+ if (secretRing.getVersion() <= 3) {
+ log(LogLevel.ERROR, LogType.MSG_IP_V3_KEY);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ }
+
if ( ! secretRing.isSecret()) {
log(LogLevel.ERROR, LogType.MSG_IS_BAD_TYPE_PUBLIC);
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index d7d98fd68..93c3fc42b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -231,6 +231,7 @@ public class OperationResultParcel implements Parcelable {
MSG_IP(R.string.msg_ip),
MSG_IP_APPLY_BATCH (R.string.msg_ip_apply_batch),
MSG_IP_BAD_TYPE_SECRET (R.string.msg_ip_bad_type_secret),
+ MSG_IP_V3_KEY (R.string.msg_ip_v3_key),
MSG_IP_DELETE_OLD_FAIL (R.string.msg_ip_delete_old_fail),
MSG_IP_DELETE_OLD_OK (R.string.msg_ip_delete_old_ok),
MSG_IP_ENCODE_FAIL (R.string.msg_ip_encode_fail),
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 09a434d5d..75175212c 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -433,7 +433,7 @@
Verified
This identity has been verified.
Not verified
- This identity has not been verified yet. You can not be sure if the identity really corresponds to a specific person.
+ This identity has not been verified yet. You cannot be sure if the identity really corresponds to a specific person.
Invalid
Something is wrong with this identity!
@@ -497,6 +497,7 @@
Applying insert batch operation.
Tried to import secret keyring as public. This is a bug, please file a report!
+ This key is an OpenPGP version 3 key and thus insecure. It has not been imported.
No old key deleted (creating a new one?)
Deleted old key from database
Operation failed due to encoding error
From 62f7bf62150b460ee2dfa14f2c45f6df40d55cc9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Thu, 14 Aug 2014 15:58:26 +0200
Subject: [PATCH 004/142] move v3 key import prevention into canonicalization
method
---
.../keychain/pgp/UncachedKeyRing.java | 7 +++++++
.../keychain/provider/ProviderHelper.java | 10 ----------
.../keychain/service/OperationResultParcel.java | 2 +-
OpenKeychain/src/main/res/values/strings.xml | 2 +-
4 files changed, 9 insertions(+), 12 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
index 18f27cbff..5c8a85de9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
+import org.sufficientlysecure.keychain.service.OperationResults;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
@@ -245,6 +246,12 @@ public class UncachedKeyRing {
indent, PgpKeyHelper.convertKeyIdToHex(getMasterKeyId()));
indent += 1;
+ // do not accept v3 keys
+ if (getVersion() <= 3) {
+ log.add(LogLevel.ERROR, LogType.MSG_KC_V3_KEY, indent);
+ return null;
+ }
+
final Date now = new Date();
int redundantCerts = 0, badCerts = 0;
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 f8b2e549f..a13bb9c98 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -642,11 +642,6 @@ public class ProviderHelper {
log(LogLevel.START, LogType.MSG_IP, PgpKeyHelper.convertKeyIdToHex(masterKeyId));
mIndent += 1;
- if (publicRing.getVersion() <= 3) {
- log(LogLevel.ERROR, LogType.MSG_IP_V3_KEY);
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
- }
-
if (publicRing.isSecret()) {
log(LogLevel.ERROR, LogType.MSG_IP_BAD_TYPE_SECRET);
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
@@ -739,11 +734,6 @@ public class ProviderHelper {
log(LogLevel.START, LogType.MSG_IS, PgpKeyHelper.convertKeyIdToHex(masterKeyId));
mIndent += 1;
- if (secretRing.getVersion() <= 3) {
- log(LogLevel.ERROR, LogType.MSG_IP_V3_KEY);
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
- }
-
if ( ! secretRing.isSecret()) {
log(LogLevel.ERROR, LogType.MSG_IS_BAD_TYPE_PUBLIC);
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index 93c3fc42b..25dac2139 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -231,7 +231,6 @@ public class OperationResultParcel implements Parcelable {
MSG_IP(R.string.msg_ip),
MSG_IP_APPLY_BATCH (R.string.msg_ip_apply_batch),
MSG_IP_BAD_TYPE_SECRET (R.string.msg_ip_bad_type_secret),
- MSG_IP_V3_KEY (R.string.msg_ip_v3_key),
MSG_IP_DELETE_OLD_FAIL (R.string.msg_ip_delete_old_fail),
MSG_IP_DELETE_OLD_OK (R.string.msg_ip_delete_old_ok),
MSG_IP_ENCODE_FAIL (R.string.msg_ip_encode_fail),
@@ -290,6 +289,7 @@ public class OperationResultParcel implements Parcelable {
MSG_IS_SUCCESS (R.string.msg_is_success),
// keyring canonicalization
+ MSG_KC_V3_KEY (R.string.msg_kc_v3_key),
MSG_KC_PUBLIC (R.string.msg_kc_public),
MSG_KC_SECRET (R.string.msg_kc_secret),
MSG_KC_FATAL_NO_UID (R.string.msg_kc_fatal_no_uid),
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 75175212c..d491723fd 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -497,7 +497,7 @@
Applying insert batch operation.
Tried to import secret keyring as public. This is a bug, please file a report!
- This key is an OpenPGP version 3 key and thus insecure. It has not been imported.
+ This key is an OpenPGP version 3 key and thus insecure. It has not been imported.
No old key deleted (creating a new one?)
Deleted old key from database
Operation failed due to encoding error
From ef2449917e53e312ebc2eb4bea7e3149ba9db137 Mon Sep 17 00:00:00 2001
From: mar-v-in
Date: Thu, 14 Aug 2014 12:22:02 +0200
Subject: [PATCH 005/142] factor KeySpinner out
---
.../ui/EncryptAsymmetricFragment.java | 142 +--------------
.../ui/widget/EncryptKeyCompletionView.java | 4 +-
.../keychain/ui/widget/KeySpinner.java | 171 ++++++++++++++++++
.../keychain/ui/widget/SignKeySpinner.java | 48 +++++
.../layout/encrypt_asymmetric_fragment.xml | 2 +-
...mmetric_signkey.xml => keyspinner_key.xml} | 0
6 files changed, 230 insertions(+), 137 deletions(-)
create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java
rename OpenKeychain/src/main/res/layout/{encrypt_asymmetric_signkey.xml => keyspinner_key.xml} (100%)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
index a402b6f68..41566cffc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
@@ -47,6 +47,7 @@ import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.widget.EncryptKeyCompletionView;
+import org.sufficientlysecure.keychain.ui.widget.KeySpinner;
import org.sufficientlysecure.keychain.util.Log;
import java.util.ArrayList;
@@ -54,22 +55,20 @@ import java.util.Iterator;
import java.util.List;
public class EncryptAsymmetricFragment extends Fragment implements EncryptActivityInterface.UpdateListener {
- public static final String ARG_SIGNATURE_KEY_ID = "signature_key_id";
- public static final String ARG_ENCRYPTION_KEY_IDS = "encryption_key_ids";
-
ProviderHelper mProviderHelper;
// view
- private Spinner mSign;
+ private KeySpinner mSign;
private EncryptKeyCompletionView mEncryptKeyView;
- private SelectSignKeyCursorAdapter mSignAdapter = new SelectSignKeyCursorAdapter();
// model
private EncryptActivityInterface mEncryptInterface;
@Override
public void onNotifyUpdate() {
-
+ if (mSign != null) {
+ mSign.setSelectedKeyId(mEncryptInterface.getSignatureKey());
+ }
}
@Override
@@ -101,8 +100,7 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.encrypt_asymmetric_fragment, container, false);
- mSign = (Spinner) view.findViewById(R.id.sign);
- mSign.setAdapter(mSignAdapter);
+ mSign = (KeySpinner) view.findViewById(R.id.sign);
mSign.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
@@ -128,42 +126,6 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi
// preselect keys given
preselectKeys();
- getLoaderManager().initLoader(1, null, new LoaderManager.LoaderCallbacks() {
- @Override
- public Loader onCreateLoader(int id, Bundle args) {
- // This is called when a new Loader needs to be created. This
- // sample only has one Loader, so we don't care about the ID.
- Uri baseUri = KeyRings.buildUnifiedKeyRingsUri();
-
- // These are the rows that we will retrieve.
- String[] projection = new String[]{
- KeyRings._ID,
- KeyRings.MASTER_KEY_ID,
- KeyRings.KEY_ID,
- KeyRings.USER_ID,
- KeyRings.IS_EXPIRED,
- KeyRings.HAS_SIGN,
- KeyRings.HAS_ANY_SECRET
- };
-
- String where = KeyRings.HAS_ANY_SECRET + " = 1 AND " + KeyRings.HAS_SIGN + " NOT NULL AND "
- + KeyRings.IS_REVOKED + " = 0 AND " + KeyRings.IS_EXPIRED + " = 0";
-
- // Now create and return a CursorLoader that will take care of
- // creating a Cursor for the data being displayed.
- return new CursorLoader(getActivity(), baseUri, projection, where, null, null);
- }
-
- @Override
- public void onLoadFinished(Loader loader, Cursor data) {
- mSignAdapter.swapCursor(data);
- }
-
- @Override
- public void onLoaderReset(Loader loader) {
- mSignAdapter.swapCursor(null);
- }
- });
mEncryptKeyView.setTokenListener(new TokenCompleteTextView.TokenListener() {
@Override
public void onTokenAdded(Object token) {
@@ -194,6 +156,7 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi
KeyRings.buildUnifiedKeyRingUri(signatureKey));
if(keyring.hasAnySecret()) {
setSignatureKeyId(keyring.getMasterKeyId());
+ mSign.setSelectedKeyId(mEncryptInterface.getSignatureKey());
}
} catch (PgpGeneralException e) {
Log.e(Constants.TAG, "key not found!", e);
@@ -233,95 +196,4 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi
setEncryptionKeyIds(keyIdsArr);
setEncryptionUserIds(userIds.toArray(new String[userIds.size()]));
}
-
- private class SelectSignKeyCursorAdapter extends BaseAdapter implements SpinnerAdapter {
- private CursorAdapter inner;
- private int mIndexUserId;
- private int mIndexKeyId;
- private int mIndexMasterKeyId;
-
- public SelectSignKeyCursorAdapter() {
- inner = new CursorAdapter(null, null, 0) {
- @Override
- public View newView(Context context, Cursor cursor, ViewGroup parent) {
- return getActivity().getLayoutInflater().inflate(R.layout.encrypt_asymmetric_signkey, null);
- }
-
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
- String[] userId = KeyRing.splitUserId(cursor.getString(mIndexUserId));
- ((TextView) view.findViewById(android.R.id.title)).setText(userId[2] == null ? userId[0] : (userId[0] + " (" + userId[2] + ")"));
- ((TextView) view.findViewById(android.R.id.text1)).setText(userId[1]);
- ((TextView) view.findViewById(android.R.id.text2)).setText(PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId)));
- }
-
- @Override
- public long getItemId(int position) {
- mCursor.moveToPosition(position);
- return mCursor.getLong(mIndexMasterKeyId);
- }
- };
- }
-
- public Cursor swapCursor(Cursor newCursor) {
- if (newCursor == null) return inner.swapCursor(null);
-
- mIndexKeyId = newCursor.getColumnIndex(KeyRings.KEY_ID);
- mIndexUserId = newCursor.getColumnIndex(KeyRings.USER_ID);
- mIndexMasterKeyId = newCursor.getColumnIndex(KeyRings.MASTER_KEY_ID);
- if (newCursor.moveToFirst()) {
- do {
- if (newCursor.getLong(mIndexMasterKeyId) == mEncryptInterface.getSignatureKey()) {
- mSign.setSelection(newCursor.getPosition() + 1);
- }
- } while (newCursor.moveToNext());
- }
- return inner.swapCursor(newCursor);
- }
-
- @Override
- public int getCount() {
- return inner.getCount() + 1;
- }
-
- @Override
- public Object getItem(int position) {
- if (position == 0) return null;
- return inner.getItem(position - 1);
- }
-
- @Override
- public long getItemId(int position) {
- if (position == 0) return Constants.key.none;
- return inner.getItemId(position - 1);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = getDropDownView(position, convertView, parent);
- v.findViewById(android.R.id.text1).setVisibility(View.GONE);
- return v;
- }
-
- @Override
- public View getDropDownView(int position, View convertView, ViewGroup parent) {
- View v;
- if (position == 0) {
- if (convertView == null) {
- v = inner.newView(null, null, parent);
- } else {
- v = convertView;
- }
- ((TextView) v.findViewById(android.R.id.title)).setText("None");
- v.findViewById(android.R.id.text1).setVisibility(View.GONE);
- v.findViewById(android.R.id.text2).setVisibility(View.GONE);
- } else {
- v = inner.getView(position - 1, convertView, parent);
- v.findViewById(android.R.id.text1).setVisibility(View.VISIBLE);
- v.findViewById(android.R.id.text2).setVisibility(View.VISIBLE);
- }
- return v;
- }
- }
-
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java
index 20b9570bb..ceb3f665f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java
@@ -111,7 +111,7 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (getContext() instanceof FragmentActivity) {
- ((FragmentActivity) getContext()).getSupportLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks() {
+ ((FragmentActivity) getContext()).getSupportLoaderManager().initLoader(hashCode(), null, new LoaderManager.LoaderCallbacks() {
@Override
public Loader onCreateLoader(int id, Bundle args) {
// These are the rows that we will retrieve.
@@ -143,6 +143,8 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
swapCursor(null);
}
});
+ } else {
+ Log.e(Constants.TAG, "EncryptKeyCompletionView must be attached to a FragmentActivity, this is " + getContext().getClass());
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
new file mode 100644
index 000000000..b8d83311a
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
@@ -0,0 +1,171 @@
+package org.sufficientlysecure.keychain.ui.widget;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.Loader;
+import android.support.v4.widget.CursorAdapter;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.Spinner;
+import android.widget.SpinnerAdapter;
+import android.widget.TextView;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.KeyRing;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.util.Log;
+
+public abstract class KeySpinner extends Spinner {
+ private long mSelectedKeyId;
+ private SelectKeyAdapter mAdapter = new SelectKeyAdapter();
+
+ public KeySpinner(Context context) {
+ super(context);
+ }
+
+ public KeySpinner(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public KeySpinner(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public abstract Loader onCreateLoader();
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ setAdapter(mAdapter);
+ if (getContext() instanceof FragmentActivity) {
+ ((FragmentActivity) getContext()).getSupportLoaderManager().initLoader(hashCode(), null, new LoaderManager.LoaderCallbacks() {
+ @Override
+ public Loader onCreateLoader(int id, Bundle args) {
+ return KeySpinner.this.onCreateLoader();
+ }
+
+ @Override
+ public void onLoadFinished(Loader loader, Cursor data) {
+ mAdapter.swapCursor(data);
+ }
+
+ @Override
+ public void onLoaderReset(Loader loader) {
+ mAdapter.swapCursor(null);
+ }
+ });
+ } else {
+ Log.e(Constants.TAG, "KeySpinner must be attached to FragmentActivity, this is " + getContext().getClass());
+ }
+ }
+
+ public long getSelectedKeyId() {
+ return mSelectedKeyId;
+ }
+
+ public void setSelectedKeyId(long selectedKeyId) {
+ this.mSelectedKeyId = selectedKeyId;
+ }
+
+ private class SelectKeyAdapter extends BaseAdapter implements SpinnerAdapter {
+ private CursorAdapter inner;
+ private int mIndexUserId;
+ private int mIndexKeyId;
+ private int mIndexMasterKeyId;
+
+ public SelectKeyAdapter() {
+ inner = new CursorAdapter(null, null, 0) {
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ return View.inflate(getContext(), R.layout.keyspinner_key, null);
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ String[] userId = KeyRing.splitUserId(cursor.getString(mIndexUserId));
+ ((TextView) view.findViewById(android.R.id.title)).setText(userId[2] == null ? userId[0] : (userId[0] + " (" + userId[2] + ")"));
+ ((TextView) view.findViewById(android.R.id.text1)).setText(userId[1]);
+ ((TextView) view.findViewById(android.R.id.text2)).setText(PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId)));
+ }
+
+ @Override
+ public long getItemId(int position) {
+ mCursor.moveToPosition(position);
+ return mCursor.getLong(mIndexMasterKeyId);
+ }
+ };
+ }
+
+ public Cursor swapCursor(Cursor newCursor) {
+ if (newCursor == null) return inner.swapCursor(null);
+
+ mIndexKeyId = newCursor.getColumnIndex(KeychainContract.KeyRings.KEY_ID);
+ mIndexUserId = newCursor.getColumnIndex(KeychainContract.KeyRings.USER_ID);
+ mIndexMasterKeyId = newCursor.getColumnIndex(KeychainContract.KeyRings.MASTER_KEY_ID);
+ if (newCursor.moveToFirst()) {
+ do {
+ if (newCursor.getLong(mIndexMasterKeyId) == mSelectedKeyId) {
+ setSelection(newCursor.getPosition() + 1);
+ }
+ } while (newCursor.moveToNext());
+ }
+ return inner.swapCursor(newCursor);
+ }
+
+ @Override
+ public int getCount() {
+ return inner.getCount() + 1;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ if (position == 0) return null;
+ return inner.getItem(position - 1);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ if (position == 0) return Constants.key.none;
+ return inner.getItemId(position - 1);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ try {
+ View v = getDropDownView(position, convertView, parent);
+ v.findViewById(android.R.id.text1).setVisibility(View.GONE);
+ return v;
+ } catch (NullPointerException e) {
+ // This is for the preview...
+ return View.inflate(getContext(), android.R.layout.simple_list_item_1, null);
+ }
+ }
+
+ @Override
+ public View getDropDownView(int position, View convertView, ViewGroup parent) {
+ View v;
+ if (position == 0) {
+ if (convertView == null) {
+ v = inner.newView(null, null, parent);
+ } else {
+ v = convertView;
+ }
+ ((TextView) v.findViewById(android.R.id.title)).setText("None");
+ v.findViewById(android.R.id.text1).setVisibility(View.GONE);
+ v.findViewById(android.R.id.text2).setVisibility(View.GONE);
+ } else {
+ v = inner.getView(position - 1, convertView, parent);
+ v.findViewById(android.R.id.text1).setVisibility(View.VISIBLE);
+ v.findViewById(android.R.id.text2).setVisibility(View.VISIBLE);
+ }
+ return v;
+ }
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java
new file mode 100644
index 000000000..cbec7f920
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java
@@ -0,0 +1,48 @@
+package org.sufficientlysecure.keychain.ui.widget;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.util.AttributeSet;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+
+public class SignKeySpinner extends KeySpinner {
+ public SignKeySpinner(Context context) {
+ super(context);
+ }
+
+ public SignKeySpinner(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public SignKeySpinner(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public Loader onCreateLoader() {
+ // This is called when a new Loader needs to be created. This
+ // sample only has one Loader, so we don't care about the ID.
+ Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingsUri();
+
+ // These are the rows that we will retrieve.
+ String[] projection = new String[]{
+ KeychainContract.KeyRings._ID,
+ KeychainContract.KeyRings.MASTER_KEY_ID,
+ KeychainContract.KeyRings.KEY_ID,
+ KeychainContract.KeyRings.USER_ID,
+ KeychainContract.KeyRings.IS_EXPIRED,
+ KeychainContract.KeyRings.HAS_SIGN,
+ KeychainContract.KeyRings.HAS_ANY_SECRET
+ };
+
+ String where = KeychainContract.KeyRings.HAS_ANY_SECRET + " = 1 AND " + KeychainContract.KeyRings.HAS_SIGN + " NOT NULL AND "
+ + KeychainContract.KeyRings.IS_REVOKED + " = 0 AND " + KeychainContract.KeyRings.IS_EXPIRED + " = 0";
+
+ // Now create and return a CursorLoader that will take care of
+ // creating a Cursor for the data being displayed.
+ return new CursorLoader(getContext(), baseUri, projection, where, null, null);
+ }
+}
diff --git a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml
index 4d82477bc..2189a1f34 100644
--- a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml
@@ -24,7 +24,7 @@
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/label_asymmetric_from" />
-
Date: Thu, 14 Aug 2014 12:22:44 +0200
Subject: [PATCH 006/142] add HAS_CERTIFY (not sure why it's missing)
---
.../keychain/provider/KeychainContract.java | 1 +
.../keychain/provider/KeychainProvider.java | 11 +++++++++++
2 files changed, 12 insertions(+)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java
index dd59f8603..c239ea7f7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java
@@ -111,6 +111,7 @@ public class KeychainContract {
public static final String HAS_ANY_SECRET = "has_any_secret";
public static final String HAS_ENCRYPT = "has_encrypt";
public static final String HAS_SIGN = "has_sign";
+ public static final String HAS_CERTIFY = "has_certify";
public static final String PUBKEY_DATA = "pubkey_data";
public static final String PRIVKEY_DATA = "privkey_data";
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 c914cb5b7..ed12fb94a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
@@ -271,6 +271,8 @@ public class KeychainProvider extends ContentProvider {
"kE." + Keys.KEY_ID + " AS " + KeyRings.HAS_ENCRYPT);
projectionMap.put(KeyRings.HAS_SIGN,
"kS." + Keys.KEY_ID + " AS " + KeyRings.HAS_SIGN);
+ projectionMap.put(KeyRings.HAS_CERTIFY,
+ "kC." + Keys.KEY_ID + " AS " + KeyRings.HAS_SIGN);
projectionMap.put(KeyRings.IS_EXPIRED,
"(" + Tables.KEYS + "." + Keys.EXPIRY + " IS NOT NULL AND " + Tables.KEYS + "." + Keys.EXPIRY
+ " < " + new Date().getTime() / 1000 + ") AS " + KeyRings.IS_EXPIRED);
@@ -324,6 +326,15 @@ public class KeychainProvider extends ContentProvider {
+ " AND ( kS." + Keys.EXPIRY + " IS NULL OR kS." + Keys.EXPIRY
+ " >= " + new Date().getTime() / 1000 + " )"
+ ")" : "")
+ + (plist.contains(KeyRings.HAS_CERTIFY) ?
+ " LEFT JOIN " + Tables.KEYS + " AS kC ON ("
+ +"kC." + Keys.MASTER_KEY_ID
+ + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
+ + " AND kC." + Keys.IS_REVOKED + " = 0"
+ + " AND kC." + Keys.CAN_CERTIFY + " = 1"
+ + " AND ( kC." + Keys.EXPIRY + " IS NULL OR kC." + Keys.EXPIRY
+ + " >= " + new Date().getTime() / 1000 + " )"
+ + ")" : "")
);
qb.appendWhere(Tables.KEYS + "." + Keys.RANK + " = 0");
// in case there are multiple verifying certificates
From 07d6a26778b69c5340f5bbf11dcab970c63783d4 Mon Sep 17 00:00:00 2001
From: mar-v-in
Date: Thu, 14 Aug 2014 15:23:12 +0200
Subject: [PATCH 007/142] add OnKeyChangedListener to KeySpinner
---
.../ui/EncryptAsymmetricFragment.java | 11 ++---
.../keychain/ui/widget/KeySpinner.java | 41 +++++++++++++++++--
2 files changed, 41 insertions(+), 11 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
index 41566cffc..748cbca14 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
@@ -101,15 +101,10 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi
View view = inflater.inflate(R.layout.encrypt_asymmetric_fragment, container, false);
mSign = (KeySpinner) view.findViewById(R.id.sign);
- mSign.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ mSign.setOnKeyChangedListener(new KeySpinner.OnKeyChangedListener() {
@Override
- public void onItemSelected(AdapterView> parent, View view, int position, long id) {
- setSignatureKeyId(parent.getAdapter().getItemId(position));
- }
-
- @Override
- public void onNothingSelected(AdapterView> parent) {
- setSignatureKeyId(Constants.key.none);
+ public void onKeyChanged(long masterKeyId) {
+ setSignatureKeyId(masterKeyId);
}
});
mEncryptKeyView = (EncryptKeyCompletionView) view.findViewById(R.id.recipient_list);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
index b8d83311a..fe3c61197 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
@@ -10,6 +10,7 @@ import android.support.v4.widget.CursorAdapter;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
@@ -23,27 +24,62 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.util.Log;
public abstract class KeySpinner extends Spinner {
+ public interface OnKeyChangedListener {
+ public void onKeyChanged(long masterKeyId);
+ }
+
private long mSelectedKeyId;
private SelectKeyAdapter mAdapter = new SelectKeyAdapter();
+ private OnKeyChangedListener mListener;
public KeySpinner(Context context) {
super(context);
+ initView();
}
public KeySpinner(Context context, AttributeSet attrs) {
super(context, attrs);
+ initView();
}
public KeySpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+ initView();
+ }
+
+ private void initView() {
+ setAdapter(mAdapter);
+ super.setOnItemSelectedListener(new OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ if (mListener != null) {
+ mListener.onKeyChanged(id);
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parent) {
+ if (mListener != null) {
+ mListener.onKeyChanged(Constants.key.none);
+ }
+ }
+ });
}
public abstract Loader onCreateLoader();
+ @Override
+ public void setOnItemSelectedListener(OnItemSelectedListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setOnKeyChangedListener(OnKeyChangedListener listener) {
+ mListener = listener;
+ }
+
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- setAdapter(mAdapter);
if (getContext() instanceof FragmentActivity) {
((FragmentActivity) getContext()).getSupportLoaderManager().initLoader(hashCode(), null, new LoaderManager.LoaderCallbacks() {
@Override
@@ -97,8 +133,7 @@ public abstract class KeySpinner extends Spinner {
@Override
public long getItemId(int position) {
- mCursor.moveToPosition(position);
- return mCursor.getLong(mIndexMasterKeyId);
+ return ((Cursor) getItem(position)).getLong(mIndexMasterKeyId);
}
};
}
From 00286744f232bec569b46411db7be62e40c534d0 Mon Sep 17 00:00:00 2001
From: mar-v-in
Date: Thu, 14 Aug 2014 15:44:54 +0200
Subject: [PATCH 008/142] small bug in has_certify
---
.../sufficientlysecure/keychain/provider/KeychainProvider.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 ed12fb94a..2c552a060 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
@@ -272,7 +272,7 @@ public class KeychainProvider extends ContentProvider {
projectionMap.put(KeyRings.HAS_SIGN,
"kS." + Keys.KEY_ID + " AS " + KeyRings.HAS_SIGN);
projectionMap.put(KeyRings.HAS_CERTIFY,
- "kC." + Keys.KEY_ID + " AS " + KeyRings.HAS_SIGN);
+ "kC." + Keys.KEY_ID + " AS " + KeyRings.HAS_CERTIFY);
projectionMap.put(KeyRings.IS_EXPIRED,
"(" + Tables.KEYS + "." + Keys.EXPIRY + " IS NOT NULL AND " + Tables.KEYS + "." + Keys.EXPIRY
+ " < " + new Date().getTime() / 1000 + ") AS " + KeyRings.IS_EXPIRED);
From a6118877ff1b096925c908583985889d30087e24 Mon Sep 17 00:00:00 2001
From: mar-v-in
Date: Thu, 14 Aug 2014 16:00:07 +0200
Subject: [PATCH 009/142] Add and use CertifyKeySpinner
---
.../keychain/ui/CertifyKeyActivity.java | 32 ++++++-------
.../keychain/ui/widget/CertifyKeySpinner.java | 48 +++++++++++++++++++
.../main/res/layout/certify_key_activity.xml | 12 ++---
3 files changed, 66 insertions(+), 26 deletions(-)
create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
index c1986825c..d1e8a80dc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
@@ -34,6 +34,7 @@ import android.support.v7.app.ActionBarActivity;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
+import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
@@ -56,6 +57,8 @@ import org.sufficientlysecure.keychain.service.OperationResultParcel;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
+import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner;
+import org.sufficientlysecure.keychain.ui.widget.KeySpinner;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Notify;
@@ -64,18 +67,17 @@ import java.util.ArrayList;
/**
* Signs the specified public key with the specified secret master key
*/
-public class CertifyKeyActivity extends ActionBarActivity implements
- SelectSecretKeyLayoutFragment.SelectSecretKeyCallback, LoaderManager.LoaderCallbacks {
+public class CertifyKeyActivity extends ActionBarActivity implements LoaderManager.LoaderCallbacks {
private View mCertifyButton;
private ImageView mActionCertifyImage;
private CheckBox mUploadKeyCheckbox;
private Spinner mSelectKeyserverSpinner;
- private SelectSecretKeyLayoutFragment mSelectKeyFragment;
+ private CertifyKeySpinner mCertifyKeySpinner;
private Uri mDataUri;
- private long mPubKeyId = 0;
- private long mMasterKeyId = 0;
+ private long mPubKeyId = Constants.key.none;
+ private long mMasterKeyId = Constants.key.none;
private ListView mUserIds;
private UserIdsAdapter mUserIdsAdapter;
@@ -89,8 +91,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements
setContentView(R.layout.certify_key_activity);
- mSelectKeyFragment = (SelectSecretKeyLayoutFragment) getSupportFragmentManager()
- .findFragmentById(R.id.sign_key_select_key_fragment);
+ mCertifyKeySpinner = (CertifyKeySpinner) findViewById(R.id.certify_key_spinner);
mSelectKeyserverSpinner = (Spinner) findViewById(R.id.upload_key_keyserver);
mUploadKeyCheckbox = (CheckBox) findViewById(R.id.sign_key_upload_checkbox);
mCertifyButton = findViewById(R.id.certify_key_certify_button);
@@ -101,8 +102,12 @@ public class CertifyKeyActivity extends ActionBarActivity implements
mActionCertifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light),
PorterDuff.Mode.SRC_IN);
- mSelectKeyFragment.setCallback(this);
- mSelectKeyFragment.setFilterCertify(true);
+ mCertifyKeySpinner.setOnKeyChangedListener(new KeySpinner.OnKeyChangedListener() {
+ @Override
+ public void onKeyChanged(long masterKeyId) {
+ mMasterKeyId = masterKeyId;
+ }
+ });
ArrayAdapter adapter = new ArrayAdapter(this,
android.R.layout.simple_spinner_item, Preferences.getPreferences(this)
@@ -135,7 +140,6 @@ public class CertifyKeyActivity extends ActionBarActivity implements
public void onClick(View v) {
if (mPubKeyId != 0) {
if (mMasterKeyId == 0) {
- mSelectKeyFragment.setError(getString(R.string.select_key_to_certify));
Notify.showNotify(CertifyKeyActivity.this, getString(R.string.select_key_to_certify),
Notify.Style.ERROR);
} else {
@@ -367,14 +371,6 @@ public class CertifyKeyActivity extends ActionBarActivity implements
startService(intent);
}
- /**
- * callback from select key fragment
- */
- @Override
- public void onKeySelected(long secretKeyId) {
- mMasterKeyId = secretKeyId;
- }
-
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java
new file mode 100644
index 000000000..b686d108b
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java
@@ -0,0 +1,48 @@
+package org.sufficientlysecure.keychain.ui.widget;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.util.AttributeSet;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+
+public class CertifyKeySpinner extends KeySpinner {
+ public CertifyKeySpinner(Context context) {
+ super(context);
+ }
+
+ public CertifyKeySpinner(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CertifyKeySpinner(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public Loader onCreateLoader() {
+ // This is called when a new Loader needs to be created. This
+ // sample only has one Loader, so we don't care about the ID.
+ Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingsUri();
+
+ // These are the rows that we will retrieve.
+ String[] projection = new String[]{
+ KeychainContract.KeyRings._ID,
+ KeychainContract.KeyRings.MASTER_KEY_ID,
+ KeychainContract.KeyRings.KEY_ID,
+ KeychainContract.KeyRings.USER_ID,
+ KeychainContract.KeyRings.IS_EXPIRED,
+ KeychainContract.KeyRings.HAS_CERTIFY,
+ KeychainContract.KeyRings.HAS_ANY_SECRET
+ };
+
+ String where = KeychainContract.KeyRings.HAS_ANY_SECRET + " = 1 AND " + KeychainContract.KeyRings.HAS_CERTIFY + " NOT NULL AND "
+ + KeychainContract.KeyRings.IS_REVOKED + " = 0 AND " + KeychainContract.KeyRings.IS_EXPIRED + " = 0";
+
+ // Now create and return a CursorLoader that will take care of
+ // creating a Cursor for the data being displayed.
+ return new CursorLoader(getContext(), baseUri, projection, where, null, null);
+ }
+}
diff --git a/OpenKeychain/src/main/res/layout/certify_key_activity.xml b/OpenKeychain/src/main/res/layout/certify_key_activity.xml
index 34d4dbd57..bce194438 100644
--- a/OpenKeychain/src/main/res/layout/certify_key_activity.xml
+++ b/OpenKeychain/src/main/res/layout/certify_key_activity.xml
@@ -26,14 +26,10 @@
android:layout_marginTop="14dp"
android:text="@string/section_certification_key" />
-
+
Date: Thu, 14 Aug 2014 16:12:42 +0200
Subject: [PATCH 010/142] Automcomplete names and emails in keyserver tab
---
.../keychain/helper/ContactHelper.java | 18 ++++++++++++++++++
.../keychain/ui/ImportKeysServerFragment.java | 18 ++++++++++++++++--
.../res/layout/import_keys_server_fragment.xml | 2 +-
3 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java
index 8697e49f7..96e1b25af 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java
@@ -234,6 +234,24 @@ public class ContactHelper {
return new ArrayList(mails);
}
+ public static List getContactNames(Context context) {
+ ContentResolver resolver = context.getContentResolver();
+ Cursor cursor = resolver.query(ContactsContract.Contacts.CONTENT_URI,
+ new String[]{ContactsContract.Contacts.DISPLAY_NAME},
+ null, null, null);
+ if (cursor == null) return null;
+
+ Set names = new HashSet();
+ while (cursor.moveToNext()) {
+ String name = cursor.getString(0);
+ if (name != null) {
+ names.add(name);
+ }
+ }
+ cursor.close();
+ return new ArrayList(names);
+ }
+
public static Uri dataUriFromContactUri(Context context, Uri contactUri) {
Cursor contactMasterKey = context.getContentResolver().query(contactUri,
new String[]{ContactsContract.Data.DATA2}, null, null, null, null);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java
index d339bc132..88caebc32 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java
@@ -29,15 +29,19 @@ import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.ContactHelper;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.util.Log;
+import java.util.List;
+
public class ImportKeysServerFragment extends Fragment {
public static final String ARG_QUERY = "query";
public static final String ARG_KEYSERVER = "keyserver";
@@ -46,7 +50,7 @@ public class ImportKeysServerFragment extends Fragment {
private ImportKeysActivity mImportActivity;
private View mSearchButton;
- private EditText mQueryEditText;
+ private AutoCompleteTextView mQueryEditText;
private View mConfigButton;
private View mConfigLayout;
private Spinner mServerSpinner;
@@ -75,7 +79,7 @@ public class ImportKeysServerFragment extends Fragment {
View view = inflater.inflate(R.layout.import_keys_server_fragment, container, false);
mSearchButton = view.findViewById(R.id.import_server_search);
- mQueryEditText = (EditText) view.findViewById(R.id.import_server_query);
+ mQueryEditText = (AutoCompleteTextView) view.findViewById(R.id.import_server_query);
mConfigButton = view.findViewById(R.id.import_server_config_button);
mConfigLayout = view.findViewById(R.id.import_server_config);
mServerSpinner = (Spinner) view.findViewById(R.id.import_server_spinner);
@@ -93,6 +97,16 @@ public class ImportKeysServerFragment extends Fragment {
mSearchButton.setEnabled(false);
}
+ List namesAndEmails = ContactHelper.getContactNames(getActivity());
+ namesAndEmails.addAll(ContactHelper.getContactMails(getActivity()));
+ mQueryEditText.setThreshold(3);
+ mQueryEditText.setAdapter(
+ new ArrayAdapter
+ (getActivity(), android.R.layout.simple_spinner_dropdown_item,
+ namesAndEmails
+ )
+ );
+
mSearchButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
diff --git a/OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml b/OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml
index 47c354c53..fde90b81f 100644
--- a/OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml
@@ -10,7 +10,7 @@
android:layout_height="?android:attr/listPreferredItemHeight"
android:orientation="horizontal">
-
Date: Thu, 14 Aug 2014 16:14:16 +0200
Subject: [PATCH 011/142] Fix KeySpinner on cursor change
---
.../sufficientlysecure/keychain/ui/widget/KeySpinner.java | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
index fe3c61197..380361fc0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
@@ -133,7 +133,12 @@ public abstract class KeySpinner extends Spinner {
@Override
public long getItemId(int position) {
- return ((Cursor) getItem(position)).getLong(mIndexMasterKeyId);
+ try {
+ return ((Cursor) getItem(position)).getLong(mIndexMasterKeyId);
+ } catch (Exception e) {
+ // This can happen on concurrent modification :(
+ return Constants.key.none;
+ }
}
};
}
From 05da0f4328580fe9b2a164a61e39fb49fb1adef1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Thu, 14 Aug 2014 16:20:24 +0200
Subject: [PATCH 012/142] change keybase hint following pull request #755
---
.../src/main/res/layout/import_keys_keybase_fragment.xml | 2 +-
.../src/main/res/layout/import_keys_server_fragment.xml | 2 +-
OpenKeychain/src/main/res/values-cs/strings.xml | 2 +-
OpenKeychain/src/main/res/values-de/strings.xml | 4 ++--
OpenKeychain/src/main/res/values-es/strings.xml | 4 ++--
OpenKeychain/src/main/res/values-fr/strings.xml | 4 ++--
OpenKeychain/src/main/res/values-it/strings.xml | 4 ++--
OpenKeychain/src/main/res/values-ja/strings.xml | 4 ++--
OpenKeychain/src/main/res/values-ru/strings.xml | 2 +-
OpenKeychain/src/main/res/values-sl/strings.xml | 4 ++--
OpenKeychain/src/main/res/values-uk/strings.xml | 2 +-
OpenKeychain/src/main/res/values/strings.xml | 4 ++--
12 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/OpenKeychain/src/main/res/layout/import_keys_keybase_fragment.xml b/OpenKeychain/src/main/res/layout/import_keys_keybase_fragment.xml
index 062289688..c70236e07 100644
--- a/OpenKeychain/src/main/res/layout/import_keys_keybase_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/import_keys_keybase_fragment.xml
@@ -11,7 +11,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="top|left"
- android:hint="@string/hint_keybase_search"
+ android:hint="@string/hint_keybase_search_hint"
android:imeOptions="actionSearch"
android:inputType="textNoSuggestions"
android:singleLine="true"
diff --git a/OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml b/OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml
index fde90b81f..62e7d740c 100644
--- a/OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml
@@ -16,7 +16,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="top|left"
- android:hint="@string/hint_public_keys"
+ android:hint="@string/hint_keyserver_search_hint"
android:imeOptions="actionSearch"
android:inputType="textNoSuggestions"
android:singleLine="true"
diff --git a/OpenKeychain/src/main/res/values-cs/strings.xml b/OpenKeychain/src/main/res/values-cs/strings.xml
index 19e94b4b8..dd4d41650 100644
--- a/OpenKeychain/src/main/res/values-cs/strings.xml
+++ b/OpenKeychain/src/main/res/values-cs/strings.xml
@@ -184,7 +184,7 @@
verifikuji integritu...
mažu \'%s\' bezpečně...
- Jméno/Email/ID klíče
+ Jméno/Email/ID klíče
512
768
diff --git a/OpenKeychain/src/main/res/values-de/strings.xml b/OpenKeychain/src/main/res/values-de/strings.xml
index a843a154a..74282fd29 100644
--- a/OpenKeychain/src/main/res/values-de/strings.xml
+++ b/OpenKeychain/src/main/res/values-de/strings.xml
@@ -270,8 +270,8 @@
Integrität wird überprüft…
\'%s\' wird sicher gelöscht…
- Name/Email/Schlüssel ID...
- Name/Keybase.io Benutzername...
+ Name/Email/Schlüssel ID...
+ Name/Keybase.io Benutzername...
512
768
diff --git a/OpenKeychain/src/main/res/values-es/strings.xml b/OpenKeychain/src/main/res/values-es/strings.xml
index 80c2060d1..8b8af788d 100644
--- a/OpenKeychain/src/main/res/values-es/strings.xml
+++ b/OpenKeychain/src/main/res/values-es/strings.xml
@@ -276,8 +276,8 @@
verificando la integridad...
borrando \'%s\' de forma segura…
- Identidad de Nombre/Correo/Clave...
- Nombre de usuario de Nombre/Keybase.io...
+ Identidad de Nombre/Correo/Clave...
+ Nombre de usuario de Nombre/Keybase.io...
512
768
diff --git a/OpenKeychain/src/main/res/values-fr/strings.xml b/OpenKeychain/src/main/res/values-fr/strings.xml
index e30ebb883..35e4c5766 100644
--- a/OpenKeychain/src/main/res/values-fr/strings.xml
+++ b/OpenKeychain/src/main/res/values-fr/strings.xml
@@ -276,8 +276,8 @@
vérification de l\'intégrité...
suppression sûre de « %s »...
- Nom/courriel/ ID clef...
- Nom/nom d\'utilisateur keybase.io...
+ Nom/courriel/ ID clef...
+ Nom/nom d\'utilisateur keybase.io...
512
768
diff --git a/OpenKeychain/src/main/res/values-it/strings.xml b/OpenKeychain/src/main/res/values-it/strings.xml
index 89e09783b..2a5131bcf 100644
--- a/OpenKeychain/src/main/res/values-it/strings.xml
+++ b/OpenKeychain/src/main/res/values-it/strings.xml
@@ -236,8 +236,8 @@
verifica integrita\'...
eliminazione sicura di \'%s\'...
- Nome/Email/ID Chiave...
- Nome/Keybase.io nome utente...
+ Nome/Email/ID Chiave...
+ Nome/Keybase.io nome utente...
512
768
diff --git a/OpenKeychain/src/main/res/values-ja/strings.xml b/OpenKeychain/src/main/res/values-ja/strings.xml
index dbb52d208..f0cb9d47b 100644
--- a/OpenKeychain/src/main/res/values-ja/strings.xml
+++ b/OpenKeychain/src/main/res/values-ja/strings.xml
@@ -271,8 +271,8 @@
完全性の検証中...
\'%s\' を完全に削除中…
- 名前/メール/鍵ID...
- 名前/Keybase.io名...
+ 名前/メール/鍵ID...
+ 名前/Keybase.io名...
512
768
diff --git a/OpenKeychain/src/main/res/values-ru/strings.xml b/OpenKeychain/src/main/res/values-ru/strings.xml
index fd2c0312d..4f32bea3a 100644
--- a/OpenKeychain/src/main/res/values-ru/strings.xml
+++ b/OpenKeychain/src/main/res/values-ru/strings.xml
@@ -238,7 +238,7 @@
проверка целостности...
безопасное удаление \'%s\'...
- Имя/Email/ID ключа…
+ Имя/Email/ID ключа…
512
768
diff --git a/OpenKeychain/src/main/res/values-sl/strings.xml b/OpenKeychain/src/main/res/values-sl/strings.xml
index 0a7b4713e..0de5e97ea 100644
--- a/OpenKeychain/src/main/res/values-sl/strings.xml
+++ b/OpenKeychain/src/main/res/values-sl/strings.xml
@@ -243,8 +243,8 @@
preverjam neokrnjenost...
varno brišem \'%s\'…
- Ime/e-pošta/ID ključa
- Ime/Keybase.io uporabniško ime...
+ Ime/e-pošta/ID ključa
+ Ime/Keybase.io uporabniško ime...
512
768
diff --git a/OpenKeychain/src/main/res/values-uk/strings.xml b/OpenKeychain/src/main/res/values-uk/strings.xml
index 42ac94c32..7a4c79ddb 100644
--- a/OpenKeychain/src/main/res/values-uk/strings.xml
+++ b/OpenKeychain/src/main/res/values-uk/strings.xml
@@ -238,7 +238,7 @@
перевірка цілісності…
вилучення безпечно \'%s\'…
- Назва/Ел. пошта/ІД ключа…
+ Назва/Ел. пошта/ІД ключа…
512
768
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index d491723fd..20a149956 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -303,8 +303,8 @@
deleting \'%s\' securely…
- Name/Email/Key ID…
- Name/Keybase.io username…
+ Name/Email/Key ID…
+ Name/Email/Proof/Key…
512
From d2b9e95c8089520411792028717ebd4b0d105764 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Thu, 14 Aug 2014 15:59:03 +0200
Subject: [PATCH 013/142] tests: cleaner code in PgpKeyOperationTest
---
.../keychain/pgp/PgpKeyOperationTest.java | 123 +++++++++++-------
1 file changed, 73 insertions(+), 50 deletions(-)
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index 8e7d395fd..93aaf05c5 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -18,8 +18,8 @@ import org.spongycastle.bcpg.UserIDPacket;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
-import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
+import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
@@ -78,9 +78,11 @@ public class PgpKeyOperationTest {
parcel.mNewPassphrase = passphrase;
PgpKeyOperation op = new PgpKeyOperation(null);
- staticRing = op.createSecretKeyRing(parcel).getRing();
+ EditKeyResult result = op.createSecretKeyRing(parcel);
+ Assert.assertTrue("initial test key creation must succeed", result.success());
+ Assert.assertNotNull("initial test key creation must succeed", result.getRing());
- Assert.assertNotNull("initial test key creation must succeed", staticRing);
+ staticRing = result.getRing();
// we sleep here for a second, to make sure all new certificates have different timestamps
Thread.sleep(1000);
@@ -111,9 +113,7 @@ public class PgpKeyOperationTest {
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- UncachedKeyRing ring = op.createSecretKeyRing(parcel).getRing();
-
- Assert.assertNull("creating ring with < 512 bytes keysize should fail", ring);
+ assertFailure("creating ring with < 512 bytes keysize should fail", parcel);
}
{
@@ -123,9 +123,7 @@ public class PgpKeyOperationTest {
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- UncachedKeyRing ring = op.createSecretKeyRing(parcel).getRing();
-
- Assert.assertNull("creating ring with ElGamal master key should fail", ring);
+ assertFailure("creating ring with ElGamal master key should fail", parcel);
}
{
@@ -135,8 +133,7 @@ public class PgpKeyOperationTest {
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- UncachedKeyRing ring = op.createSecretKeyRing(parcel).getRing();
- Assert.assertNull("creating ring with bad algorithm choice should fail", ring);
+ assertFailure("creating ring with bad algorithm choice should fail", parcel);
}
{
@@ -146,8 +143,7 @@ public class PgpKeyOperationTest {
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- UncachedKeyRing ring = op.createSecretKeyRing(parcel).getRing();
- Assert.assertNull("creating ring with non-certifying master key should fail", ring);
+ assertFailure("creating ring with non-certifying master key should fail", parcel);
}
{
@@ -156,8 +152,7 @@ public class PgpKeyOperationTest {
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
parcel.mNewPassphrase = passphrase;
- UncachedKeyRing ring = op.createSecretKeyRing(parcel).getRing();
- Assert.assertNull("creating ring without user ids should fail", ring);
+ assertFailure("creating ring without user ids should fail", parcel);
}
{
@@ -165,8 +160,7 @@ public class PgpKeyOperationTest {
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- UncachedKeyRing ring = op.createSecretKeyRing(parcel).getRing();
- Assert.assertNull("creating ring without subkeys should fail", ring);
+ assertFailure("creating ring without subkeys should fail", parcel);
}
}
@@ -179,7 +173,7 @@ public class PgpKeyOperationTest {
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA, null));
parcel.mAddUserIds.add("luna");
- ring = op.createSecretKeyRing(parcel).getRing();
+ ring = assertCreateSuccess("creating ring with master key flags must succeed", parcel);
Assert.assertEquals("the keyring should contain only the master key",
1, KeyringTestingHelper.itToList(ring.getPublicKeys()).size());
@@ -240,9 +234,9 @@ public class PgpKeyOperationTest {
parcel.mFingerprint = ring.getFingerprint();
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- UncachedKeyRing modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
- Assert.assertNull("keyring modification with bad master key id should fail", modified);
+ assertModifyFailure("keyring modification with bad master key id should fail",
+ secretRing, parcel);
}
{
@@ -252,9 +246,9 @@ public class PgpKeyOperationTest {
parcel.mFingerprint = ring.getFingerprint();
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- UncachedKeyRing modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
- Assert.assertNull("keyring modification with null master key id should fail", modified);
+ assertModifyFailure("keyring modification with null master key id should fail",
+ secretRing, parcel);
}
{
@@ -265,9 +259,9 @@ public class PgpKeyOperationTest {
parcel.mFingerprint[5] += 1;
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- UncachedKeyRing modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
- Assert.assertNull("keyring modification with bad fingerprint should fail", modified);
+ assertModifyFailure("keyring modification with bad fingerprint should fail",
+ secretRing, parcel);
}
{
@@ -276,9 +270,9 @@ public class PgpKeyOperationTest {
parcel.mFingerprint = null;
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- UncachedKeyRing modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
- Assert.assertNull("keyring modification with null fingerprint should fail", modified);
+ assertModifyFailure("keyring modification with null fingerprint should fail",
+ secretRing, parcel);
}
{
@@ -287,9 +281,9 @@ public class PgpKeyOperationTest {
badphrase = "a";
}
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- UncachedKeyRing modified = op.modifySecretKeyRing(secretRing, parcel, badphrase).getRing();
- Assert.assertNull("keyring modification with bad passphrase should fail", modified);
+ assertModifyFailure("keyring modification with bad passphrase should fail",
+ secretRing, parcel, badphrase);
}
}
@@ -344,9 +338,8 @@ public class PgpKeyOperationTest {
PublicKeyAlgorithmTags.RSA_GENERAL, new Random().nextInt(512), KeyFlags.SIGN_DATA, null));
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
+ assertModifyFailure("creating a subkey with keysize < 512 should fail", secretRing, parcel);
- Assert.assertNull("creating a subkey with keysize < 512 should fail", modified);
}
{ // a past expiry should fail
@@ -355,9 +348,7 @@ public class PgpKeyOperationTest {
new Date().getTime()/1000-10));
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
-
- Assert.assertNull("creating subkey with past expiry date should fail", modified);
+ assertModifyFailure("creating subkey with past expiry date should fail", secretRing, parcel);
}
}
@@ -423,9 +414,7 @@ public class PgpKeyOperationTest {
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, new Date().getTime()/1000-10));
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
-
- Assert.assertNull("setting subkey expiry to a past date should fail", modified);
+ assertModifyFailure("setting subkey expiry to a past date should fail", secretRing, parcel);
}
{ // modifying nonexistent keyring should fail
@@ -433,9 +422,7 @@ public class PgpKeyOperationTest {
parcel.mChangeSubKeys.add(new SubkeyChange(123, null, null));
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
-
- Assert.assertNull("modifying non-existent subkey should fail", modified);
+ assertModifyFailure("modifying non-existent subkey should fail", secretRing, parcel);
}
}
@@ -556,9 +543,7 @@ public class PgpKeyOperationTest {
parcel.mChangePrimaryUserId = uid;
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(modified.getEncoded(), false, 0);
- UncachedKeyRing otherModified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
-
- Assert.assertNull("setting primary user id to a revoked user id should fail", otherModified);
+ assertModifyFailure("setting primary user id to a revoked user id should fail", secretRing, parcel);
}
@@ -604,8 +589,7 @@ public class PgpKeyOperationTest {
{
parcel.mAddUserIds.add("");
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- UncachedKeyRing modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
- Assert.assertNull("adding an empty user id should fail", modified);
+ assertModifyFailure("adding an empty user id should fail", secretRing, parcel);
}
parcel.reset();
@@ -674,9 +658,8 @@ public class PgpKeyOperationTest {
}
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
-
- Assert.assertNull("changing primary user id to a non-existent one should fail", modified);
+ assertModifyFailure("changing primary user id to a non-existent one should fail",
+ secretRing, parcel);
}
// check for revoked primary user id already done in revoke test
@@ -705,8 +688,10 @@ public class PgpKeyOperationTest {
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
PgpKeyOperation op = new PgpKeyOperation(null);
- UncachedKeyRing rawModified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
- Assert.assertNotNull("key modification failed", rawModified);
+ EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, passphrase);
+ Assert.assertTrue("key modification must succeed", result.success());
+ UncachedKeyRing rawModified = result.getRing();
+ Assert.assertNotNull("key modification must not return null", rawModified);
if (!canonicalize) {
Assert.assertTrue("keyring must differ from original", KeyringTestingHelper.diffKeyrings(
@@ -753,10 +738,48 @@ public class PgpKeyOperationTest {
*/
@Test
public void testConcat() throws Exception {
- byte[] actual = TestDataUtil.concatAll(new byte[]{1}, new byte[]{2,-2}, new byte[]{5},new byte[]{3});
+ byte[] actual = TestDataUtil.concatAll(new byte[]{1}, new byte[]{2, -2}, new byte[]{5}, new byte[]{3});
byte[] expected = new byte[]{1,2,-2,5,3};
Assert.assertEquals(java.util.Arrays.toString(expected), java.util.Arrays.toString(actual));
}
+ private void assertFailure(String reason, SaveKeyringParcel parcel) {
+
+ EditKeyResult result = op.createSecretKeyRing(parcel);
+
+ Assert.assertFalse(reason, result.success());
+ Assert.assertNull(reason, result.getRing());
+
+ }
+
+ private void assertModifyFailure(String reason, CanonicalizedSecretKeyRing secretRing,
+ SaveKeyringParcel parcel, String passphrase) {
+
+ EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, passphrase);
+
+ Assert.assertFalse(reason, result.success());
+ Assert.assertNull(reason, result.getRing());
+
+ }
+
+ private void assertModifyFailure(String reason, CanonicalizedSecretKeyRing secretRing, SaveKeyringParcel parcel) {
+
+ EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, passphrase);
+
+ Assert.assertFalse(reason, result.success());
+ Assert.assertNull(reason, result.getRing());
+
+ }
+
+ private UncachedKeyRing assertCreateSuccess(String reason, SaveKeyringParcel parcel) {
+
+ EditKeyResult result = op.createSecretKeyRing(parcel);
+
+ Assert.assertTrue(reason, result.success());
+ Assert.assertNotNull(reason, result.getRing());
+
+ return result.getRing();
+
+ }
}
From a19784ed7e930055a6a1d0a537f2f4f1d3ea1f21 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Thu, 14 Aug 2014 16:27:50 +0200
Subject: [PATCH 014/142] merge: check fingerprints on merge operation! (this
needs a testcase!)
---
.../org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java | 4 +++-
OpenKeychain/src/main/res/values/strings.xml | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
index 5c8a85de9..20e78d7fa 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -45,6 +45,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
@@ -692,7 +693,8 @@ public class UncachedKeyRing {
long masterKeyId = other.getMasterKeyId();
- if (getMasterKeyId() != masterKeyId) {
+ if (getMasterKeyId() != masterKeyId
+ || Arrays.equals(getFingerprint(), other.getFingerprint())) {
log.add(LogLevel.ERROR, LogType.MSG_MG_HETEROGENEOUS, indent);
return null;
}
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 20a149956..0da651b03 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -616,7 +616,7 @@
Merging into public keyring %s
Merging into secret keyring %s
Fatal error encoding signature
- Tried to consolidate heterogeneous keyrings
+ Tried to merge keyrings with differing fingerprints!
Adding new subkey %s
Found %s new certificates in keyring
No new certificates
From 2c408f679c691a29814ef7d53de7130e3aa22dfc Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Thu, 14 Aug 2014 16:34:57 +0200
Subject: [PATCH 015/142] dem logix
---
.../org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
index 20e78d7fa..83c244d52 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -694,7 +694,7 @@ public class UncachedKeyRing {
long masterKeyId = other.getMasterKeyId();
if (getMasterKeyId() != masterKeyId
- || Arrays.equals(getFingerprint(), other.getFingerprint())) {
+ || !Arrays.equals(getFingerprint(), other.getFingerprint())) {
log.add(LogLevel.ERROR, LogType.MSG_MG_HETEROGENEOUS, indent);
return null;
}
From 110f8c4d5287e2603041c6ccc099ba18327d5043 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Thu, 14 Aug 2014 17:00:36 +0200
Subject: [PATCH 016/142] Update sticky list headers
---
extern/StickyListHeaders | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extern/StickyListHeaders b/extern/StickyListHeaders
index 706c0e447..67e757703 160000
--- a/extern/StickyListHeaders
+++ b/extern/StickyListHeaders
@@ -1 +1 @@
-Subproject commit 706c0e447229226b6edc82ab10630d39fd0f6c38
+Subproject commit 67e7577033e488701e7d03767d13656735015e4b
From 9c0388939076c0d15de01941a41ab8428df5c668 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Thu, 14 Aug 2014 17:10:08 +0200
Subject: [PATCH 017/142] tests: add ProviderHelperSaveTest, with long key id
collision test
---
.../provider/ProviderHelperSaveTest.java | 55 +++++++++++++++++++
...669861368BCA0BE42DAF7DDDA252EBB8EBE1AF.asc | 29 ++++++++++
...5120427374F3F7AA5F1166DDA252EBB8EBE1AF.asc | 29 ++++++++++
.../src/test/resources/cooperpair/readme | 3 +
.../keychain/provider/KeychainDatabase.java | 5 ++
5 files changed, 121 insertions(+)
create mode 100644 OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/provider/ProviderHelperSaveTest.java
create mode 100644 OpenKeychain-Test/src/test/resources/cooperpair/9E669861368BCA0BE42DAF7DDDA252EBB8EBE1AF.asc
create mode 100644 OpenKeychain-Test/src/test/resources/cooperpair/A55120427374F3F7AA5F1166DDA252EBB8EBE1AF.asc
create mode 100644 OpenKeychain-Test/src/test/resources/cooperpair/readme
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/provider/ProviderHelperSaveTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/provider/ProviderHelperSaveTest.java
new file mode 100644
index 000000000..7a5afcc3a
--- /dev/null
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/provider/ProviderHelperSaveTest.java
@@ -0,0 +1,55 @@
+package org.sufficientlysecure.keychain.provider;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowLog;
+import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
+import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+@RunWith(RobolectricTestRunner.class)
+@org.robolectric.annotation.Config(emulateSdk = 18) // Robolectric doesn't yet support 19
+public class ProviderHelperSaveTest {
+
+ @BeforeClass
+ public static void setUpOnce() throws Exception {
+ ShadowLog.stream = System.out;
+ }
+
+ @Test
+ public void testLongKeyIdCollision() throws Exception {
+
+ UncachedKeyRing first =
+ readRingFromResource("/cooperpair/9E669861368BCA0BE42DAF7DDDA252EBB8EBE1AF.asc");
+ UncachedKeyRing second =
+ readRingFromResource("/cooperpair/A55120427374F3F7AA5F1166DDA252EBB8EBE1AF.asc");
+
+ SaveKeyringResult result;
+
+ // insert both keys, second should fail
+ result = new ProviderHelper(Robolectric.application).savePublicKeyRing(first);
+ Assert.assertTrue("first keyring import should succeed", result.success());
+ result = new ProviderHelper(Robolectric.application).savePublicKeyRing(second);
+ Assert.assertFalse("second keyring import should fail", result.success());
+
+ new KeychainDatabase(Robolectric.application).clearDatabase();
+
+ // and the other way around
+ result = new ProviderHelper(Robolectric.application).savePublicKeyRing(second);
+ Assert.assertTrue("first keyring import should succeed", result.success());
+ result = new ProviderHelper(Robolectric.application).savePublicKeyRing(first);
+ Assert.assertFalse("second keyring import should fail", result.success());
+
+ }
+
+ UncachedKeyRing readRingFromResource(String name) throws Exception {
+ return UncachedKeyRing.fromStream(ProviderHelperSaveTest.class.getResourceAsStream(name)).next();
+ }
+
+}
\ No newline at end of file
diff --git a/OpenKeychain-Test/src/test/resources/cooperpair/9E669861368BCA0BE42DAF7DDDA252EBB8EBE1AF.asc b/OpenKeychain-Test/src/test/resources/cooperpair/9E669861368BCA0BE42DAF7DDDA252EBB8EBE1AF.asc
new file mode 100644
index 000000000..4f51252da
--- /dev/null
+++ b/OpenKeychain-Test/src/test/resources/cooperpair/9E669861368BCA0BE42DAF7DDDA252EBB8EBE1AF.asc
@@ -0,0 +1,29 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+
+mQINBFJtd/UBEACpw/psXoGNM8RHczviD7FnGdjMQPEJQ+nuWQ2AEGYouulg5hFv
+0ChuSQVLiqQht2k5K2liyW1MeXoJ8tr9nSn/Zi9nttc0Wo6K7pvrDD40r2HNg305
+qLCzItr5st3x8cq2cIXvN4LOm2rqpBLZ/sqMmNiW2Y7/aAQqV1xtR35joHqamWHD
+UPOmzBMs07YSUjXgC1EMx8kWQSV6cuARj93kxWj8R6eoYHHfrWCEGR313wov6QST
+zIfVU7FqQqOmdLW3LaPHxcrI/TjsnkUN99qdlpjJH/YW925LDPJHAkliqPP5AvhU
+F9KbY2F8mcIZBCDd8TH+xXynuN3BbIU4kCwVbdx/tcpO1npuJcKB1Go/udyow/Ei
+Z3nHzJsCVkezvopek77wnwPaP0nAb7f4iIY3gJCoGirOx6N075TgF6MBe00q9oFE
+y4rvnUnU9/QzOOes95eUMhM+9eK1cuLFEV5t47DfxRdq+fQip3FJ2l6v19sZvQ0G
+j06pjYqg0of273rG8oXcDrFjb1Zqhj8x1mLl6u7d/ide5wTm9HylBWcYKQjIJJAi
+WIScxEPIOINDJKgsKTuKtoyNvISJ3xUeS1yzxiIb3YGLIyPgFFx0vFyqJfbkXq70
+m1n2xnJlkTidfzbZvc6EA7vRGSDYK6FqqhlGhc7UypUEVW8FM/jZNAOS6QARAUGt
+tCg5RTY2OTg2MTM2OEJDQTBCRTQyREFGN0REREEyNTJFQkI4RUJFMUFGiQI3BBMB
+CgAhBQJSg/uTAhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEN2iUuu46+Gv
++Z0P+wQhkLwm+WGcEsS98Lei9O7hit/k4g/VkLUUQV7BOR3n8uRZIFkdOtpvrFU3
+aKf246uCy6GM48Oh+1U2cv5InX/WEuKaFo5uF6t79wyt18BUn1weDcU+DQdOSG4f
+fSnNa55wkN0l0svW4fGIthjmDTz6HZFntYD+9A20wZAqpPIs+vyG9Jp+e9E9Y/W/
+EFQbNlxHHb9+BMT2+DtNP+HSl3MPFlQPKOLZxyLAU5uzT0Sa0LxhrQy5FgkW6Jog
+sbAJVM9z0pZw+grzGPciM66ZW1rxeICvbYsdWLytRjqxpY8GS8XudyseUGd+dZim
+ptarsrE5yfSMg2gW5Z1PTc0tEMXJLUwtpyzQjpFpbb7dPuo2TUp09LgZKX63WCbS
+Nb1RTaGfkeYudOTo2rh4Jfg+Tb/JRpO6clo0rxAq8nPH2WmG+9TB8Zbb7YRzGWuV
+/e5SeVNR+zY8tXZKnmUIH1HIprc+BtT6Bupdvd0CT14Mg9MmsFvUXofwHLa4gahr
+8/iG9y3uHSA6Rhz++yOpyOmNvO1LDxsYNaRCIXQJbqgNwF5YNYlMPsEeY/CG7FOb
+Afv7rHiYtRRQfz2P4OF900DJO7QL9gdNXJ1+Hajy/5Lvvl7qwqMG4GvVQEsgFc5O
+jjFCUhE2i20j2kEMxvA5RLBH/fOoGARn87tiKSfb+pqLNZQb
+=fDJ8
+-----END PGP PUBLIC KEY BLOCK-----
\ No newline at end of file
diff --git a/OpenKeychain-Test/src/test/resources/cooperpair/A55120427374F3F7AA5F1166DDA252EBB8EBE1AF.asc b/OpenKeychain-Test/src/test/resources/cooperpair/A55120427374F3F7AA5F1166DDA252EBB8EBE1AF.asc
new file mode 100644
index 000000000..549bc51a2
--- /dev/null
+++ b/OpenKeychain-Test/src/test/resources/cooperpair/A55120427374F3F7AA5F1166DDA252EBB8EBE1AF.asc
@@ -0,0 +1,29 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+
+mQINBFKD+38BEADSv5l4xOx9hCRJVcybq6yK5hTpGSFf3xo1bkhoMvyC62ehb4jD
+MDLwwNRyzCBEWQJLbq/LLizPFN2qXFJpXJcsuqsHNYRtDqDBEjtriRQwSqHnqTXt
+c0K46FYHldCJQ4/tBXxPI+WwtXjcNRWaV7n2BvR/Jk+B5e4Zz3LPnN0C4w5vORHs
+hN1jil8A3Hs/F+OmlQYrU8ZtNwTpSo2EXxe2fVgSDCsKRyNsPZj++OyujPzW+yaN
+lJ9I/q6s9gvX9o9o7nwZbqBETipWsdRK6RfBdTKpnyLNordbWwWTk6GxN8T5Ppit
+P6a3UlQ71VuflcswCTmEQ1pEfZrlRFKa9psBOW+cZLNxT9h0jGFMh6/B3w48Sag+
+cFcPBFWParC+cAXBIURDxT9G6bzNLogg7YKoaPsyiXnLDH2VJUCXs27D2wPJL24Q
+S7npvsg63MPPssWgG5cauLznmNR4y5pQi6oH/C10v0zrUJy6FPJzQhYRhWOvhtz6
+j88RGMrFNNCdB2VACtn699D+ixu3nRlXHIKCT+xLSfgslVYifmJOCNljBLGHOQ1e
+FJxQuNVpmmxjvk/8kqK+pHLB9Qn6M1ZYzip7OyUL3OAWabCabgEw2bQmUhiBWD3u
+buv0WAVOJEAFvBCAeYNQzrQMY+Rc3RnvynG4pI6Tbo8wC6/IJcDOw516JwARASB3
+tChBNTUxMjA0MjczNzRGM0Y3QUE1RjExNjZEREEyNTJFQkI4RUJFMUFGiQI3BBMB
+CgAhBQJSg/uTAhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEN2iUuu46+Gv
+9L0P/3tFu0LOZ/dAPjUNfKJCZqcIuVnD5xShMTsUbVx+QoXMy7rt4iRLD7ofGi/I
+vTAZehxk3sk/Slx5nbews+3NItyw6mcaP9HlmwKNr6k7BC2kJHcCxH4DNzhmIx1H
+3T/CggtHX42JBYKlGf22y+M8jAbvsPOUfTznx96mYNrOY6s1dJyn0kRleqJ8+tGj
+/5+0y90iZnGCa0FtacQkKUPkXwVodeZVxk8z5OEipShYKc+8dl+5WsvOzHqLC/KY
+xCGRb4JaqEMwouLNg8dTNAXXUvFGqJNDX4+andggogmI1hdD9xExfSU9cAGegg2t
+vvveC4S+CCHd+zt88iK5ze6F61RxwYhhNbkuFGjdgNGCpHtG/BQhKnYJuKEbq3oi
+mgNyxJERlfgaWXveiMG0AmACXN+jCkTtqZjQnsg2N2QDL3tjY7usmuiwRL1aVOFG
+Kw5/Cc+2nDeANS3Xi1403Ni269b1c6kNSoLe4zd0WsbO3Kouds8F8EQfeheXQe97
+ZxuvBOMsR9wHC3f0sl/vfxCGdUC+khmKk5taKnUeUFJmVmh5ghlVy8FySHGB0QHO
+zd8GUl59rFpQJNpNFQW2YKDhrcjxIr2AeJrdoDI6NsQ02+Qtep/bbq53hqtAD4jF
+t3S8vBbTXtRk6g2qn4ojF4SOIc8SAiZcURgVFuSJX8ngFbO4
+=OEw/
+-----END PGP PUBLIC KEY BLOCK-----
\ No newline at end of file
diff --git a/OpenKeychain-Test/src/test/resources/cooperpair/readme b/OpenKeychain-Test/src/test/resources/cooperpair/readme
new file mode 100644
index 000000000..fecb372d9
--- /dev/null
+++ b/OpenKeychain-Test/src/test/resources/cooperpair/readme
@@ -0,0 +1,3 @@
+"Cooperpair" testcase under public domain license, by @coruus:
+
+https://github.com/coruus/cooperpair/tree/master/pgpv4
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
index 3a859f505..a90c88c3e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
@@ -349,4 +349,9 @@ public class KeychainDatabase extends SQLiteOpenHelper {
copy(in, out);
}
+ // for test cases ONLY!!
+ public void clearDatabase() {
+ getWritableDatabase().execSQL("delete from " + Tables.KEY_RINGS_PUBLIC);
+ }
+
}
From 9af301ec7750e33f687de3e3cdbfceae5551451c Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Thu, 14 Aug 2014 17:12:17 +0200
Subject: [PATCH 018/142] handle modify and save errors in KeychainIntentResult
---
.../keychain/provider/ProviderHelper.java | 4 +++
.../service/KeychainIntentService.java | 30 ++++++++++++++-----
.../keychain/ui/EditKeyFragment.java | 15 +++++-----
3 files changed, 33 insertions(+), 16 deletions(-)
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 a13bb9c98..960c508f8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -86,6 +86,10 @@ public class ProviderHelper {
this(context, new OperationLog(), 0);
}
+ public ProviderHelper(Context context, OperationLog log) {
+ this(context, log, 0);
+ }
+
public ProviderHelper(Context context, OperationLog log, int indent) {
mContext = context;
mContentResolver = context.getContentResolver();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index d6c470e11..0fdc62633 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -54,6 +54,7 @@ import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult;
+import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult;
import org.sufficientlysecure.keychain.util.FileImportCache;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
@@ -391,23 +392,36 @@ public class KeychainIntentService extends IntentService
}
/* Operation */
- ProviderHelper providerHelper = new ProviderHelper(this);
PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 10, 60, 100));
- EditKeyResult result;
+ EditKeyResult modifyResult;
if (saveParcel.mMasterKeyId != null) {
String passphrase = data.getString(SAVE_KEYRING_PASSPHRASE);
CanonicalizedSecretKeyRing secRing =
- providerHelper.getCanonicalizedSecretKeyRing(saveParcel.mMasterKeyId);
+ new ProviderHelper(this).getCanonicalizedSecretKeyRing(saveParcel.mMasterKeyId);
- result = keyOperations.modifySecretKeyRing(secRing, saveParcel, passphrase);
+ modifyResult = keyOperations.modifySecretKeyRing(secRing, saveParcel, passphrase);
} else {
- result = keyOperations.createSecretKeyRing(saveParcel);
+ modifyResult = keyOperations.createSecretKeyRing(saveParcel);
}
- UncachedKeyRing ring = result.getRing();
+ // If the edit operation didn't succeed, exit here
+ if ( ! modifyResult.success()) {
+ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, modifyResult);
+ return;
+ }
- providerHelper.saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100));
+ UncachedKeyRing ring = modifyResult.getRing();
+
+ // Save the keyring. The ProviderHelper is initialized with the previous log
+ SaveKeyringResult saveResult = new ProviderHelper(this, modifyResult.getLog())
+ .saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100));
+
+ // If the edit operation didn't succeed, exit here
+ if ( ! saveResult.success()) {
+ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, saveResult);
+ return;
+ }
// cache new passphrase
if (saveParcel.mNewPassphrase != null) {
@@ -418,7 +432,7 @@ public class KeychainIntentService extends IntentService
setProgress(R.string.progress_done, 100, 100);
/* Output */
- sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
+ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, saveResult);
} catch (Exception e) {
sendErrorToHandler(e);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
index 03074bb6a..b18d1626a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
@@ -48,8 +48,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
-import org.sufficientlysecure.keychain.service.OperationResults;
-import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
+import org.sufficientlysecure.keychain.service.OperationResultParcel;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter;
@@ -408,9 +407,9 @@ public class EditKeyFragment extends LoaderFragment implements
public void handleMessage(Message message) {
switch (message.what) {
case EditSubkeyExpiryDialogFragment.MESSAGE_NEW_EXPIRY_DATE:
- Long expiry = (Long) message.getData().
- getSerializable(EditSubkeyExpiryDialogFragment.MESSAGE_DATA_EXPIRY_DATE);
- mSaveKeyringParcel.getOrCreateSubkeyChange(keyId).mExpiry = expiry;
+ mSaveKeyringParcel.getOrCreateSubkeyChange(keyId).mExpiry =
+ (Long) message.getData().getSerializable(
+ EditSubkeyExpiryDialogFragment.MESSAGE_DATA_EXPIRY_DATE);
break;
}
getLoaderManager().getLoader(LOADER_ID_SUBKEYS).forceLoad();
@@ -520,8 +519,8 @@ public class EditKeyFragment extends LoaderFragment implements
if (returnData == null) {
return;
}
- final OperationResults.EditKeyResult result =
- returnData.getParcelable(EditKeyResult.EXTRA_RESULT);
+ final OperationResultParcel result =
+ returnData.getParcelable(OperationResultParcel.EXTRA_RESULT);
if (result == null) {
return;
}
@@ -534,7 +533,7 @@ public class EditKeyFragment extends LoaderFragment implements
// if good -> finish, return result to showkey and display there!
Intent intent = new Intent();
- intent.putExtra(EditKeyResult.EXTRA_RESULT, result);
+ intent.putExtra(OperationResultParcel.EXTRA_RESULT, result);
getActivity().setResult(EditKeyActivity.RESULT_OK, intent);
getActivity().finish();
From e1958009bd022021971c1fd2f81557fb4fe99e4e Mon Sep 17 00:00:00 2001
From: mar-v-in
Date: Thu, 14 Aug 2014 18:10:22 +0200
Subject: [PATCH 019/142] Do not allow self certifying
---
.../keychain/ui/CertifyKeyActivity.java | 2 +-
.../keychain/ui/widget/CertifyKeySpinner.java | 16 ++++++++++++++--
.../keychain/ui/widget/KeySpinner.java | 6 +++++-
3 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
index d1e8a80dc..7c6e94d5e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
@@ -34,7 +34,6 @@ import android.support.v7.app.ActionBarActivity;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
-import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
@@ -203,6 +202,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements LoaderManag
if (data.moveToFirst()) {
// TODO: put findViewById in onCreate!
mPubKeyId = data.getLong(INDEX_MASTER_KEY_ID);
+ mCertifyKeySpinner.setHiddenMasterKeyId(mPubKeyId);
String keyIdStr = PgpKeyHelper.convertKeyIdToHex(mPubKeyId);
((TextView) findViewById(R.id.key_id)).setText(keyIdStr);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java
index b686d108b..030a76136 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java
@@ -6,9 +6,13 @@ import android.net.Uri;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.util.AttributeSet;
+import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.KeychainDatabase;
public class CertifyKeySpinner extends KeySpinner {
+ private long mHiddenMasterKeyId = Constants.key.none;
+
public CertifyKeySpinner(Context context) {
super(context);
}
@@ -21,6 +25,11 @@ public class CertifyKeySpinner extends KeySpinner {
super(context, attrs, defStyle);
}
+ public void setHiddenMasterKeyId(long hiddenMasterKeyId) {
+ this.mHiddenMasterKeyId = hiddenMasterKeyId;
+ reload();
+ }
+
@Override
public Loader onCreateLoader() {
// This is called when a new Loader needs to be created. This
@@ -38,8 +47,11 @@ public class CertifyKeySpinner extends KeySpinner {
KeychainContract.KeyRings.HAS_ANY_SECRET
};
- String where = KeychainContract.KeyRings.HAS_ANY_SECRET + " = 1 AND " + KeychainContract.KeyRings.HAS_CERTIFY + " NOT NULL AND "
- + KeychainContract.KeyRings.IS_REVOKED + " = 0 AND " + KeychainContract.KeyRings.IS_EXPIRED + " = 0";
+ String where = KeychainContract.KeyRings.HAS_ANY_SECRET + " = 1 AND "
+ + KeychainContract.KeyRings.HAS_CERTIFY + " NOT NULL AND "
+ + KeychainContract.KeyRings.IS_REVOKED + " = 0 AND "
+ + KeychainContract.KeyRings.IS_EXPIRED + " = 0 AND " + KeychainDatabase.Tables.KEYS + "."
+ + KeychainContract.KeyRings.MASTER_KEY_ID + " != " + mHiddenMasterKeyId;
// Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed.
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
index 380361fc0..b12029239 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
@@ -80,8 +80,12 @@ public abstract class KeySpinner extends Spinner {
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
+ reload();
+ }
+
+ public void reload() {
if (getContext() instanceof FragmentActivity) {
- ((FragmentActivity) getContext()).getSupportLoaderManager().initLoader(hashCode(), null, new LoaderManager.LoaderCallbacks() {
+ ((FragmentActivity) getContext()).getSupportLoaderManager().restartLoader(hashCode(), null, new LoaderManager.LoaderCallbacks() {
@Override
public Loader onCreateLoader(int id, Bundle args) {
return KeySpinner.this.onCreateLoader();
From 65e76f6e4465324af59a305c87c745fbedcaac46 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Thu, 14 Aug 2014 18:51:35 +0200
Subject: [PATCH 020/142] hacky fix to prevent key list from scrolling to top
when opening nav drawer
---
.../keychain/ui/KeyListFragment.java | 22 +++++++++++++------
1 file changed, 15 insertions(+), 7 deletions(-)
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 3c97b1128..e7b7d2efc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -330,12 +330,12 @@ public class KeyListFragment extends LoaderFragment
* Show dialog to delete key
*
* @param masterKeyIds
- * @param hasSecret must contain whether the list of masterKeyIds contains a secret key or not
+ * @param hasSecret must contain whether the list of masterKeyIds contains a secret key or not
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void showDeleteKeyDialog(final ActionMode mode, long[] masterKeyIds, boolean hasSecret) {
// Can only work on singular secret keys
- if(hasSecret && masterKeyIds.length > 1) {
+ if (hasSecret && masterKeyIds.length > 1) {
Notify.showNotify(getActivity(), R.string.secret_cannot_multiple,
Notify.Style.ERROR);
return;
@@ -365,6 +365,7 @@ public class KeyListFragment extends LoaderFragment
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
// Get the searchview
MenuItem searchItem = menu.findItem(R.id.menu_key_list_search);
+
mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem);
// Execute this when searching
@@ -383,7 +384,6 @@ public class KeyListFragment extends LoaderFragment
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
mQuery = null;
- mSearchView.setQuery("", true);
getLoaderManager().restartLoader(0, null, KeyListFragment.this);
return true;
}
@@ -399,11 +399,18 @@ public class KeyListFragment extends LoaderFragment
@Override
public boolean onQueryTextChange(String s) {
+ Log.d(Constants.TAG, "onQueryTextChange s:" + s);
// Called when the action bar search text has changed. Update
// the search filter, and restart the loader to do a new query
// with this filter.
- mQuery = !TextUtils.isEmpty(s) ? s : null;
- getLoaderManager().restartLoader(0, null, this);
+ // If the nav drawer is opened, onQueryTextChange("") is executed.
+ // This hack prevents restarting the loader.
+ // TODO: better way to fix this?
+ String tmp = (mQuery == null) ? "" : mQuery;
+ if (!s.equals(tmp)) {
+ mQuery = s;
+ getLoaderManager().restartLoader(0, null, this);
+ }
return true;
}
@@ -479,7 +486,7 @@ public class KeyListFragment extends LoaderFragment
boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
boolean isExpired = !cursor.isNull(INDEX_EXPIRY)
- && new Date(cursor.getLong(INDEX_EXPIRY)*1000).before(new Date());
+ && new Date(cursor.getLong(INDEX_EXPIRY) * 1000).before(new Date());
boolean isVerified = cursor.getInt(INDEX_VERIFIED) > 0;
// Note: order is important!
@@ -521,6 +528,7 @@ public class KeyListFragment extends LoaderFragment
return mCursor.getInt(INDEX_HAS_ANY_SECRET) != 0;
}
+
public long getMasterKeyId(int id) {
if (!mCursor.moveToPosition(id)) {
throw new IllegalStateException("couldn't move cursor to position " + id);
@@ -625,7 +633,7 @@ public class KeyListFragment extends LoaderFragment
public boolean isAnySecretSelected() {
for (int pos : mSelection.keySet()) {
- if(mAdapter.isSecretAvailable(pos))
+ if (mAdapter.isSecretAvailable(pos))
return true;
}
return false;
From 6e7b99940964e162d9b1134bc1607b8084bc2dcc Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Thu, 14 Aug 2014 18:56:08 +0200
Subject: [PATCH 021/142] fix subkey certification canonicalization (why did
the test not catch this?!)
---
.../org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
index 83c244d52..0a59ba9f8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -593,7 +593,7 @@ public class UncachedKeyRing {
}
// if we already have a cert, and this one is not newer: skip it
- if (selfCert != null && selfCert.getCreationTime().before(cert.getCreationTime())) {
+ if (selfCert != null && cert.getCreationTime().before(selfCert.getCreationTime())) {
log.add(LogLevel.DEBUG, LogType.MSG_KC_SUB_DUP, indent);
redundantCerts += 1;
continue;
From 48935557e89051fb905f20690522632f39b1406a Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Thu, 14 Aug 2014 19:12:29 +0200
Subject: [PATCH 022/142] support changing expiry of subkeys to none
---
.../keychain/pgp/PgpKeyOperationTest.java | 18 ++++++++++++++++++
.../keychain/pgp/PgpKeyOperation.java | 3 ++-
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index 93aaf05c5..2f32677f2 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -409,6 +409,24 @@ public class PgpKeyOperationTest {
expiry, modified.getPublicKey(keyId).getExpiryTime().getTime()/1000);
}
+ { // expiry of 0 should be "no expiry"
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, 0L));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ Assert.assertEquals("old packet must be signature",
+ PacketTags.SIGNATURE, onlyA.get(0).tag);
+
+ Packet p = new BCPGInputStream(new ByteArrayInputStream(onlyB.get(0).buf)).readPacket();
+ Assert.assertTrue("first new packet must be signature", p instanceof SignaturePacket);
+ Assert.assertEquals("signature type must be subkey binding certificate",
+ PGPSignature.SUBKEY_BINDING, ((SignaturePacket) p).getSignatureType());
+ Assert.assertEquals("signature must have been created by master key",
+ ring.getMasterKeyId(), ((SignaturePacket) p).getKeyID());
+
+ Assert.assertNull("key must not expire anymore", modified.getPublicKey(keyId).getExpiryTime());
+ }
+
{ // a past expiry should fail
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, new Date().getTime()/1000-10));
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 bb692555e..fe84b3802 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -543,7 +543,8 @@ public class PgpKeyOperation {
PGPPublicKey pKey = sKey.getPublicKey();
// expiry must not be in the past
- if (change.mExpiry != null && new Date(change.mExpiry*1000).before(new Date())) {
+ if (change.mExpiry != null && change.mExpiry != 0 &&
+ new Date(change.mExpiry*1000).before(new Date())) {
log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_PAST_EXPIRY,
indent + 1, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
From 621978a7f501197d7f662c657f4bd6813391bab0 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Thu, 14 Aug 2014 19:13:18 +0200
Subject: [PATCH 023/142] explicitly add BouncyCastleProvider (fixes travis?)
---
.../sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index 2f32677f2..f37f11d87 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -16,6 +16,7 @@ import org.spongycastle.bcpg.SecretSubkeyPacket;
import org.spongycastle.bcpg.SignaturePacket;
import org.spongycastle.bcpg.UserIDPacket;
import org.spongycastle.bcpg.sig.KeyFlags;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
@@ -31,6 +32,7 @@ import org.sufficientlysecure.keychain.util.ProgressScaler;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.security.Security;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
@@ -51,6 +53,8 @@ public class PgpKeyOperationTest {
ArrayList onlyB = new ArrayList();
@BeforeClass public static void setUpOnce() throws Exception {
+ Security.insertProviderAt(new BouncyCastleProvider(), 1);
+
ShadowLog.stream = System.out;
{
From 0f60bcbc3d2438a8822e9bc1c6d80f8d0b743e3d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Thu, 14 Aug 2014 19:25:39 +0200
Subject: [PATCH 024/142] Pass through of master key id in SaveKeyringResult
---
.../keychain/provider/ProviderHelper.java | 38 +++++++++----------
.../keychain/service/OperationResults.java | 37 ++++++++++++++++--
.../keychain/ui/CreateKeyFinalFragment.java | 4 +-
3 files changed, 54 insertions(+), 25 deletions(-)
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 960c508f8..ac6ea015a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -648,7 +648,7 @@ public class ProviderHelper {
if (publicRing.isSecret()) {
log(LogLevel.ERROR, LogType.MSG_IP_BAD_TYPE_SECRET);
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
CanonicalizedPublicKeyRing canPublicRing;
@@ -662,20 +662,20 @@ public class ProviderHelper {
// If this is null, there is an error in the log so we can just return
if (publicRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
// Canonicalize this keyring, to assert a number of assumptions made about it.
canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent);
if (canPublicRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
// Early breakout if nothing changed
if (Arrays.hashCode(publicRing.getEncoded())
== Arrays.hashCode(oldPublicRing.getEncoded())) {
log(LogLevel.OK, LogType.MSG_IP_SUCCESS_IDENTICAL);
- return new SaveKeyringResult(SaveKeyringResult.UPDATED, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.UPDATED, mLog, null);
}
} catch (NotFoundException e) {
// Not an issue, just means we are dealing with a new keyring.
@@ -683,7 +683,7 @@ public class ProviderHelper {
// Canonicalize this keyring, to assert a number of assumptions made about it.
canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent);
if (canPublicRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
}
@@ -696,12 +696,12 @@ public class ProviderHelper {
// Merge data from new public ring into secret one
secretRing = secretRing.merge(publicRing, mLog, mIndent);
if (secretRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
// This has always been a secret key ring, this is a safe cast
canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent);
if (canSecretRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
} catch (NotFoundException e) {
@@ -720,11 +720,11 @@ public class ProviderHelper {
}
}
- return new SaveKeyringResult(result, mLog);
+ return new SaveKeyringResult(result, mLog, canSecretRing);
} catch (IOException e) {
log(LogLevel.ERROR, LogType.MSG_IP_FAIL_IO_EXC);
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
} finally {
mIndent -= 1;
}
@@ -740,7 +740,7 @@ public class ProviderHelper {
if ( ! secretRing.isSecret()) {
log(LogLevel.ERROR, LogType.MSG_IS_BAD_TYPE_PUBLIC);
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
CanonicalizedSecretKeyRing canSecretRing;
@@ -754,14 +754,14 @@ public class ProviderHelper {
// If this is null, there is an error in the log so we can just return
if (secretRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
// Canonicalize this keyring, to assert a number of assumptions made about it.
// This is a safe cast, because we made sure this is a secret ring above
canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent);
if (canSecretRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
// Early breakout if nothing changed
@@ -769,7 +769,7 @@ public class ProviderHelper {
== Arrays.hashCode(oldSecretRing.getEncoded())) {
log(LogLevel.OK, LogType.MSG_IS_SUCCESS_IDENTICAL,
PgpKeyHelper.convertKeyIdToHex(masterKeyId) );
- return new SaveKeyringResult(SaveKeyringResult.UPDATED, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.UPDATED, mLog, null);
}
} catch (NotFoundException e) {
// Not an issue, just means we are dealing with a new keyring
@@ -778,7 +778,7 @@ public class ProviderHelper {
// This is a safe cast, because we made sure this is a secret ring above
canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent);
if (canSecretRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
}
@@ -791,7 +791,7 @@ public class ProviderHelper {
// Merge data from new secret ring into public one
publicRing = oldPublicRing.merge(secretRing, mLog, mIndent);
if (publicRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
} catch (NotFoundException e) {
@@ -801,24 +801,24 @@ public class ProviderHelper {
CanonicalizedPublicKeyRing canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent);
if (canPublicRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
int result;
result = saveCanonicalizedPublicKeyRing(canPublicRing, progress, true);
if ((result & SaveKeyringResult.RESULT_ERROR) == SaveKeyringResult.RESULT_ERROR) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100);
result = saveCanonicalizedSecretKeyRing(canSecretRing);
- return new SaveKeyringResult(result, mLog);
+ return new SaveKeyringResult(result, mLog, canSecretRing);
} catch (IOException e) {
log(LogLevel.ERROR, LogType.MSG_IS_FAIL_IO_EXC);
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
} finally {
mIndent -= 1;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
index 543b83edb..d58392d77 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
@@ -29,6 +29,8 @@ import com.github.johnpersano.supertoasts.util.OnClickWrapper;
import com.github.johnpersano.supertoasts.util.Style;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
+import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.ui.LogDisplayActivity;
import org.sufficientlysecure.keychain.ui.LogDisplayFragment;
@@ -49,18 +51,21 @@ public abstract class OperationResults {
public static final int RESULT_WITH_WARNINGS = 16;
// No keys to import...
- public static final int RESULT_FAIL_NOTHING = 32 +1;
+ public static final int RESULT_FAIL_NOTHING = 32 + 1;
public boolean isOkBoth() {
return (mResult & (RESULT_OK_NEWKEYS | RESULT_OK_UPDATED))
== (RESULT_OK_NEWKEYS | RESULT_OK_UPDATED);
}
+
public boolean isOkNew() {
return (mResult & RESULT_OK_NEWKEYS) == RESULT_OK_NEWKEYS;
}
+
public boolean isOkUpdated() {
return (mResult & RESULT_OK_UPDATED) == RESULT_OK_UPDATED;
}
+
public boolean isFailNothing() {
return (mResult & RESULT_FAIL_NOTHING) == RESULT_FAIL_NOTHING;
}
@@ -124,7 +129,7 @@ public abstract class OperationResults {
if (this.isOkBoth()) {
str = activity.getResources().getQuantityString(
R.plurals.import_keys_added_and_updated_1, mNewKeys, mNewKeys);
- str += " "+ activity.getResources().getQuantityString(
+ str += " " + activity.getResources().getQuantityString(
R.plurals.import_keys_added_and_updated_2, mUpdatedKeys, mUpdatedKeys, withWarnings);
} else if (isOkUpdated()) {
str = activity.getResources().getQuantityString(
@@ -188,7 +193,7 @@ public abstract class OperationResults {
public final Long mRingMasterKeyId;
public EditKeyResult(int result, OperationLog log,
- UncachedKeyRing ring) {
+ UncachedKeyRing ring) {
super(result, log);
mRing = ring;
mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : null;
@@ -224,8 +229,12 @@ public abstract class OperationResults {
public static class SaveKeyringResult extends OperationResultParcel {
- public SaveKeyringResult(int result, OperationLog log) {
+ public final Long mRingMasterKeyId;
+
+ public SaveKeyringResult(int result, OperationLog log,
+ CanonicalizedKeyRing ring) {
super(result, log);
+ mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : null;
}
// Some old key was updated
@@ -240,6 +249,26 @@ public abstract class OperationResults {
return (mResult & UPDATED) == UPDATED;
}
+ public SaveKeyringResult(Parcel source) {
+ super(source);
+ mRingMasterKeyId = source.readLong();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeLong(mRingMasterKeyId);
+ }
+
+ public static Creator CREATOR = new Creator() {
+ public SaveKeyringResult createFromParcel(final Parcel source) {
+ return new SaveKeyringResult(source);
+ }
+
+ public SaveKeyringResult[] newArray(final int size) {
+ return new SaveKeyringResult[size];
+ }
+ };
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
index 773be816a..3fc9e7f31 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
@@ -140,7 +140,7 @@ public class CreateKeyFinalFragment extends Fragment {
if (returnData == null) {
return;
}
- final OperationResults.EditKeyResult result =
+ final OperationResults.SaveKeyringResult result =
returnData.getParcelable(OperationResultParcel.EXTRA_RESULT);
if (result == null) {
return;
@@ -191,7 +191,7 @@ public class CreateKeyFinalFragment extends Fragment {
getActivity().startService(intent);
}
- private void uploadKey(final OperationResults.EditKeyResult editKeyResult) {
+ private void uploadKey(final OperationResults.SaveKeyringResult editKeyResult) {
// Send all information needed to service to upload key in other thread
final Intent intent = new Intent(getActivity(), KeychainIntentService.class);
From bc76941bc1e47bc3919f58e29436f8d2a77f3258 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Thu, 14 Aug 2014 19:30:59 +0200
Subject: [PATCH 025/142] Fix sticky list headers lib, fix travis
---
extern/StickyListHeaders | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extern/StickyListHeaders b/extern/StickyListHeaders
index 67e757703..911f8ddfd 160000
--- a/extern/StickyListHeaders
+++ b/extern/StickyListHeaders
@@ -1 +1 @@
-Subproject commit 67e7577033e488701e7d03767d13656735015e4b
+Subproject commit 911f8ddfd007ce65aededae7e7b79e5a8d903a43
From 09d37a5fa6b431bd7be91aca9a7bbae5af928453 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Thu, 14 Aug 2014 22:12:07 +0200
Subject: [PATCH 026/142] fix keys with no expiry in ui code
---
.../keychain/service/OperationResults.java | 9 +++++++--
.../keychain/ui/adapter/SubkeysAdapter.java | 2 +-
.../ui/dialog/EditSubkeyExpiryDialogFragment.java | 2 +-
3 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
index d58392d77..1c83873be 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
@@ -205,13 +205,18 @@ public abstract class OperationResults {
public EditKeyResult(Parcel source) {
super(source);
- mRingMasterKeyId = source.readLong();
+ mRingMasterKeyId = source.readInt() != 0 ? source.readLong() : null;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
- dest.writeLong(mRingMasterKeyId);
+ if (mRingMasterKeyId == null) {
+ dest.writeInt(0);
+ } else {
+ dest.writeInt(1);
+ dest.writeLong(mRingMasterKeyId);
+ }
}
public static Creator CREATOR = new Creator() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
index d457e75bd..6df84a056 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
@@ -183,7 +183,7 @@ public class SubkeysAdapter extends CursorAdapter {
SaveKeyringParcel.SubkeyChange subkeyChange = mSaveKeyringParcel.getSubkeyChange(keyId);
if (subkeyChange != null) {
- if (subkeyChange.mExpiry == null) {
+ if (subkeyChange.mExpiry == null || subkeyChange.mExpiry == 0L) {
expiryDate = null;
} else {
expiryDate = new Date(subkeyChange.mExpiry * 1000);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
index aa63f9944..276ad15fc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
@@ -141,7 +141,7 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
dismiss();
Bundle data = new Bundle();
- data.putSerializable(MESSAGE_DATA_EXPIRY_DATE, null);
+ data.putSerializable(MESSAGE_DATA_EXPIRY_DATE, 0L);
sendMessageToHandler(MESSAGE_NEW_EXPIRY_DATE, data);
}
});
From cf450d24fbcbbd9bc56959e387bd52141004bde1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Fri, 15 Aug 2014 10:19:46 +0200
Subject: [PATCH 027/142] Remove subkeys.pgp.net keyserver, often down and no
hkps
---
.../keychain/Constants.java | 2 +-
.../keychain/helper/Preferences.java | 27 ++++++++++++++-----
2 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
index 755d74ac2..7cfc11bc6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
@@ -72,7 +72,7 @@ public final class Constants {
public static final class Defaults {
public static final String KEY_SERVERS = "hkps://hkps.pool.sks-keyservers.net, subkeys.pgp.net, hkps://pgp.mit.edu";
- public static final int KEY_SERVERS_VERSION = 2;
+ public static final int KEY_SERVERS_VERSION = 3;
}
public static final class DrawerItems {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
index 80b047530..14ae46840 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
@@ -26,6 +26,10 @@ import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.openpgp.PGPEncryptedData;
import org.sufficientlysecure.keychain.Constants;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.ListIterator;
import java.util.Vector;
/**
@@ -175,15 +179,24 @@ public class Preferences {
// migrate keyserver to hkps
if (mSharedPreferences.getInt(Constants.Pref.KEY_SERVERS_DEFAULT_VERSION, 0) !=
Constants.Defaults.KEY_SERVERS_VERSION) {
- String[] servers = getKeyServers();
- for (int i = 0; i < servers.length; i++) {
- if (servers[i].equals("pool.sks-keyservers.net")) {
- servers[i] = "hkps://hkps.pool.sks-keyservers.net";
- } else if (servers[i].equals("pgp.mit.edu")) {
- servers[i] = "hkps://pgp.mit.edu";
+ String[] serversArray = getKeyServers();
+ ArrayList servers = new ArrayList(Arrays.asList(serversArray));
+ ListIterator it = servers.listIterator();
+ while (it.hasNext()) {
+ String server = it.next();
+ if (server.equals("pool.sks-keyservers.net")) {
+ // use HKPS!
+ it.set("hkps://hkps.pool.sks-keyservers.net");
+ } else if (server.equals("pgp.mit.edu")) {
+ // use HKPS!
+ it.set("hkps://pgp.mit.edu");
+ } else if (server.equals("subkeys.pgp.net")) {
+ // remove, because often down and no HKPS!
+ it.remove();
}
+
}
- setKeyServers(servers);
+ setKeyServers(servers.toArray(new String[servers.size()]));
mSharedPreferences.edit()
.putInt(Constants.Pref.KEY_SERVERS_DEFAULT_VERSION, Constants.Defaults.KEY_SERVERS_VERSION)
.commit();
From b1fa5d992268642adf8e860812027aa0a24f3617 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Fri, 15 Aug 2014 11:00:45 +0200
Subject: [PATCH 028/142] Remove subkeys.pgp.net keyserver from defaults
---
.../main/java/org/sufficientlysecure/keychain/Constants.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
index 7cfc11bc6..bce093427 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
@@ -71,7 +71,7 @@ public final class Constants {
}
public static final class Defaults {
- public static final String KEY_SERVERS = "hkps://hkps.pool.sks-keyservers.net, subkeys.pgp.net, hkps://pgp.mit.edu";
+ public static final String KEY_SERVERS = "hkps://hkps.pool.sks-keyservers.net, hkps://pgp.mit.edu";
public static final int KEY_SERVERS_VERSION = 3;
}
From b1dc6639300c7ecafea2ac8f26d624e0275aa780 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Fri, 15 Aug 2014 11:07:21 +0200
Subject: [PATCH 029/142] Remove old_apg
---
.../keychain/provider/KeychainDatabase.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
index a90c88c3e..1536c21fc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
@@ -227,7 +227,8 @@ public class KeychainDatabase extends SQLiteOpenHelper {
if (db.equals("apg.db")) {
hasApgDb = true;
} else if (db.equals("apg_old.db")) {
- Log.d(Constants.TAG, "Found apg_old.db");
+ Log.d(Constants.TAG, "Found apg_old.db, delete it!");
+ context.getDatabasePath("apg_old.db").delete();
}
}
}
@@ -310,9 +311,8 @@ public class KeychainDatabase extends SQLiteOpenHelper {
}
}
- // Move to a different file (but don't delete, just to be safe)
- Log.d(Constants.TAG, "All done - moving apg.db to apg_old.db");
- context.getDatabasePath("apg.db").renameTo(context.getDatabasePath("apg_old.db"));
+ // delete old database
+ context.getDatabasePath("apg.db").delete();
}
private static void copy(File in, File out) throws IOException {
From 8d60d9f1031c7a2ad4d1484291497c1dff197e12 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Sat, 16 Aug 2014 03:59:58 +0200
Subject: [PATCH 030/142] Fix encrypt only
---
.../keychain/pgp/PgpSignEncrypt.java | 20 +++++------
.../keychain/remote/OpenPgpService.java | 11 ++----
.../service/KeychainIntentService.java | 34 +++++++++++--------
.../service/PassphraseCacheService.java | 6 ++--
4 files changed, 34 insertions(+), 37 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
index 263b0c5bb..1784ae063 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
@@ -68,7 +68,7 @@ public class PgpSignEncrypt {
private long mSignatureMasterKeyId;
private int mSignatureHashAlgorithm;
private String mSignaturePassphrase;
- private boolean mEncryptToSigner;
+ private long mAdditionalEncryptId;
private boolean mCleartextInput;
private String mOriginalFilename;
@@ -98,7 +98,7 @@ public class PgpSignEncrypt {
this.mSignatureMasterKeyId = builder.mSignatureMasterKeyId;
this.mSignatureHashAlgorithm = builder.mSignatureHashAlgorithm;
this.mSignaturePassphrase = builder.mSignaturePassphrase;
- this.mEncryptToSigner = builder.mEncryptToSigner;
+ this.mAdditionalEncryptId = builder.mAdditionalEncryptId;
this.mCleartextInput = builder.mCleartextInput;
this.mOriginalFilename = builder.mOriginalFilename;
}
@@ -120,7 +120,7 @@ public class PgpSignEncrypt {
private long mSignatureMasterKeyId = Constants.key.none;
private int mSignatureHashAlgorithm = 0;
private String mSignaturePassphrase = null;
- private boolean mEncryptToSigner = false;
+ private long mAdditionalEncryptId = Constants.key.none;
private boolean mCleartextInput = false;
private String mOriginalFilename = "";
@@ -166,7 +166,7 @@ public class PgpSignEncrypt {
}
public Builder setSignatureMasterKeyId(long signatureMasterKeyId) {
- this.mSignatureMasterKeyId = signatureMasterKeyId;
+ mSignatureMasterKeyId = signatureMasterKeyId;
return this;
}
@@ -183,11 +183,11 @@ public class PgpSignEncrypt {
/**
* Also encrypt with the signing keyring
*
- * @param encryptToSigner
+ * @param additionalEncryptId
* @return
*/
- public Builder setEncryptToSigner(boolean encryptToSigner) {
- mEncryptToSigner = encryptToSigner;
+ public Builder setAdditionalEncryptId(long additionalEncryptId) {
+ mAdditionalEncryptId = additionalEncryptId;
return this;
}
@@ -256,10 +256,10 @@ public class PgpSignEncrypt {
+ "\nenableCompression:" + enableCompression
+ "\nenableAsciiArmorOutput:" + mEnableAsciiArmorOutput);
- // add signature key id to encryption ids (self-encrypt)
- if (enableEncryption && enableSignature && mEncryptToSigner) {
+ // add additional key id to encryption ids (mostly to do self-encryption)
+ if (enableEncryption && mAdditionalEncryptId != Constants.key.none) {
mEncryptionMasterKeyIds = Arrays.copyOf(mEncryptionMasterKeyIds, mEncryptionMasterKeyIds.length + 1);
- mEncryptionMasterKeyIds[mEncryptionMasterKeyIds.length - 1] = mSignatureMasterKeyId;
+ mEncryptionMasterKeyIds[mEncryptionMasterKeyIds.length - 1] = mAdditionalEncryptId;
}
ArmoredOutputStream armorOut = null;
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 3541dad98..93cc08081 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -29,7 +29,6 @@ import org.openintents.openpgp.OpenPgpMetadata;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.openintents.openpgp.util.OpenPgpApi;
-import org.spongycastle.util.Arrays;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
@@ -261,10 +260,6 @@ public class OpenPgpService extends RemoteService {
return result;
}
- // add own key for encryption
- keyIds = Arrays.copyOf(keyIds, keyIds.length + 1);
- keyIds[keyIds.length - 1] = accSettings.getKeyId();
-
// build InputData and write into OutputStream
// Get Input- and OutputStream from ParcelFileDescriptor
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
@@ -281,7 +276,8 @@ public class OpenPgpService extends RemoteService {
.setCompressionId(accSettings.getCompression())
.setSymmetricEncryptionAlgorithm(accSettings.getEncryptionAlgorithm())
.setEncryptionMasterKeyIds(keyIds)
- .setOriginalFilename(originalFilename);
+ .setOriginalFilename(originalFilename)
+ .setAdditionalEncryptId(accSettings.getKeyId()); // add acc key for encryption
if (sign) {
String passphrase;
@@ -300,9 +296,6 @@ public class OpenPgpService extends RemoteService {
builder.setSignatureHashAlgorithm(accSettings.getHashAlgorithm())
.setSignatureMasterKeyId(accSettings.getKeyId())
.setSignaturePassphrase(passphrase);
- } else {
- // encrypt only
- builder.setSignatureMasterKeyId(Constants.key.none);
}
try {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index 0fdc62633..83ade9b9b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -247,27 +247,31 @@ public class KeychainIntentService extends IntentService
String originalFilename = getOriginalFilename(data);
/* Operation */
- PgpSignEncrypt.Builder builder =
- new PgpSignEncrypt.Builder(
- new ProviderHelper(this),
- inputData, outStream);
- builder.setProgressable(this);
-
- builder.setEnableAsciiArmorOutput(useAsciiArmor)
+ PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
+ new ProviderHelper(this),
+ inputData, outStream
+ );
+ builder.setProgressable(this)
+ .setEnableAsciiArmorOutput(useAsciiArmor)
.setVersionHeader(PgpHelper.getVersionForHeader(this))
.setCompressionId(compressionId)
.setSymmetricEncryptionAlgorithm(
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
.setEncryptionMasterKeyIds(encryptionKeyIds)
.setSymmetricPassphrase(symmetricPassphrase)
- .setSignatureMasterKeyId(signatureKeyId)
- .setEncryptToSigner(true)
- .setSignatureHashAlgorithm(
- Preferences.getPreferences(this).getDefaultHashAlgorithm())
- .setSignaturePassphrase(
- PassphraseCacheService.getCachedPassphrase(this, signatureKeyId))
.setOriginalFilename(originalFilename);
+ try {
+ builder.setSignatureMasterKeyId(signatureKeyId)
+ .setSignaturePassphrase(
+ PassphraseCacheService.getCachedPassphrase(this, signatureKeyId))
+ .setSignatureHashAlgorithm(
+ Preferences.getPreferences(this).getDefaultHashAlgorithm())
+ .setAdditionalEncryptId(signatureKeyId);
+ } catch (PassphraseCacheService.KeyNotFoundException e) {
+ // encrypt-only
+ }
+
// this assumes that the bytes are cleartext (valid for current implementation!)
if (source == IO_BYTES) {
builder.setCleartextInput(true);
@@ -406,7 +410,7 @@ public class KeychainIntentService extends IntentService
}
// If the edit operation didn't succeed, exit here
- if ( ! modifyResult.success()) {
+ if (!modifyResult.success()) {
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, modifyResult);
return;
}
@@ -418,7 +422,7 @@ public class KeychainIntentService extends IntentService
.saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100));
// If the edit operation didn't succeed, exit here
- if ( ! saveResult.success()) {
+ if (!saveResult.success()) {
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, saveResult);
return;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
index ae1b026a5..3707fdebf 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
@@ -77,7 +77,7 @@ public class PassphraseCacheService extends Service {
private static final int NOTIFICATION_ID = 1;
private static final int MSG_PASSPHRASE_CACHE_GET_OKAY = 1;
- private static final int MSG_PASSPHRASE_CACHE_GET_KEY_NO_FOUND = 2;
+ private static final int MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND = 2;
private BroadcastReceiver mIntentReceiver;
@@ -169,7 +169,7 @@ public class PassphraseCacheService extends Service {
switch (returnMessage.what) {
case MSG_PASSPHRASE_CACHE_GET_OKAY:
return returnMessage.getData().getString(EXTRA_PASSPHRASE);
- case MSG_PASSPHRASE_CACHE_GET_KEY_NO_FOUND:
+ case MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND:
throw new KeyNotFoundException();
default:
throw new KeyNotFoundException("should not happen!");
@@ -313,7 +313,7 @@ public class PassphraseCacheService extends Service {
msg.setData(bundle);
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "PassphraseCacheService: Passphrase for unknown key was requested!");
- msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NO_FOUND;
+ msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND;
}
try {
From 443170b876751739df7249f0c497fdec6f6f892f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Sat, 16 Aug 2014 04:11:39 +0200
Subject: [PATCH 031/142] do not pre-select revoked or expired keys
---
.../keychain/remote/OpenPgpService.java | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
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 93cc08081..93c71f5d0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
@@ -53,11 +54,16 @@ import java.util.Set;
public class OpenPgpService extends RemoteService {
- static final String[] KEYRING_PROJECTION =
- new String[]{
- KeyRings._ID,
- KeyRings.MASTER_KEY_ID,
- };
+ static final String[] EMAIL_SEARCH_PROJECTION = new String[]{
+ KeyRings._ID,
+ KeyRings.MASTER_KEY_ID,
+ KeyRings.IS_EXPIRED,
+ KeyRings.IS_REVOKED,
+ };
+
+ // do not pre-select revoked or expired keys
+ static final String EMAIL_SEARCH_WHERE = KeychainContract.KeyRings.IS_REVOKED + " = 0 AND "
+ + KeychainContract.KeyRings.IS_EXPIRED + " = 0";
/**
* Search database for key ids based on emails.
@@ -76,7 +82,7 @@ public class OpenPgpService extends RemoteService {
for (String email : encryptionUserIds) {
Uri uri = KeyRings.buildUnifiedKeyRingsFindByEmailUri(email);
- Cursor cursor = getContentResolver().query(uri, KEYRING_PROJECTION, null, null, null);
+ Cursor cursor = getContentResolver().query(uri, EMAIL_SEARCH_PROJECTION, EMAIL_SEARCH_WHERE, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
long id = cursor.getLong(cursor.getColumnIndex(KeyRings.MASTER_KEY_ID));
From bbe986743c9e6c2a22df95e0fbde0de2340bf467 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Sat, 16 Aug 2014 05:28:51 +0200
Subject: [PATCH 032/142] API: Allow ACTION_SIGN_AND_ENCRYPT with no key ids or
user ids extras, fix pre-selection of key ids (no revoked or expired ones,
also select duplicates), refactor text using spannables
---
.../keychain/remote/OpenPgpService.java | 98 ++++++++++---------
.../remote/ui/RemoteServiceActivity.java | 56 +++++++----
.../res/layout/api_remote_select_pub_keys.xml | 10 +-
OpenKeychain/src/main/res/values/strings.xml | 5 +-
4 files changed, 95 insertions(+), 74 deletions(-)
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 93c71f5d0..e2d809d9e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -72,52 +72,61 @@ public class OpenPgpService extends RemoteService {
* @return
*/
private Intent getKeyIdsFromEmails(Intent data, String[] encryptionUserIds) {
- // find key ids to given emails in database
- ArrayList keyIds = new ArrayList();
-
+ boolean noUserIdsCheck = (encryptionUserIds == null || encryptionUserIds.length == 0);
boolean missingUserIdsCheck = false;
boolean duplicateUserIdsCheck = false;
+
+ ArrayList keyIds = new ArrayList();
ArrayList missingUserIds = new ArrayList();
ArrayList duplicateUserIds = new ArrayList();
+ if (!noUserIdsCheck) {
+ for (String email : encryptionUserIds) {
+ // try to find the key for this specific email
+ Uri uri = KeyRings.buildUnifiedKeyRingsFindByEmailUri(email);
+ Cursor cursor = getContentResolver().query(uri, EMAIL_SEARCH_PROJECTION, EMAIL_SEARCH_WHERE, null, null);
+ try {
+ // result should be one entry containing the key id
+ if (cursor != null && cursor.moveToFirst()) {
+ long id = cursor.getLong(cursor.getColumnIndex(KeyRings.MASTER_KEY_ID));
+ keyIds.add(id);
+ } else {
+ missingUserIdsCheck = true;
+ missingUserIds.add(email);
+ Log.d(Constants.TAG, "user id missing");
+ }
+ // another entry for this email -> too keys with the same email inside user id
+ if (cursor != null && cursor.moveToNext()) {
+ duplicateUserIdsCheck = true;
+ duplicateUserIds.add(email);
- for (String email : encryptionUserIds) {
- Uri uri = KeyRings.buildUnifiedKeyRingsFindByEmailUri(email);
- Cursor cursor = getContentResolver().query(uri, EMAIL_SEARCH_PROJECTION, EMAIL_SEARCH_WHERE, null, null);
- try {
- if (cursor != null && cursor.moveToFirst()) {
- long id = cursor.getLong(cursor.getColumnIndex(KeyRings.MASTER_KEY_ID));
- keyIds.add(id);
- } else {
- missingUserIdsCheck = true;
- missingUserIds.add(email);
- Log.d(Constants.TAG, "user id missing");
- }
- if (cursor != null && cursor.moveToNext()) {
- duplicateUserIdsCheck = true;
- duplicateUserIds.add(email);
- Log.d(Constants.TAG, "more than one user id with the same email");
- }
- } finally {
- if (cursor != null) {
- cursor.close();
+ // also pre-select
+ long id = cursor.getLong(cursor.getColumnIndex(KeyRings.MASTER_KEY_ID));
+ keyIds.add(id);
+ Log.d(Constants.TAG, "more than one user id with the same email");
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
}
}
- // convert to long[]
+ // convert ArrayList to long[]
long[] keyIdsArray = new long[keyIds.size()];
for (int i = 0; i < keyIdsArray.length; i++) {
keyIdsArray[i] = keyIds.get(i);
}
- // allow the user to verify pub key selection
- if (missingUserIdsCheck || duplicateUserIdsCheck) {
- // build PendingIntent
+ if (noUserIdsCheck || missingUserIdsCheck || duplicateUserIdsCheck) {
+ // allow the user to verify pub key selection
+
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS);
intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray);
+ intent.putExtra(RemoteServiceActivity.EXTRA_NO_USER_IDS_CHECK, noUserIdsCheck);
intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds);
- intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, duplicateUserIds);
+ intent.putExtra(RemoteServiceActivity.EXTRA_DUPLICATE_USER_IDS, duplicateUserIds);
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
@@ -129,16 +138,18 @@ public class OpenPgpService extends RemoteService {
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
return result;
- }
+ } else {
+ // everything was easy, we have exactly one key for every email
- if (keyIdsArray.length == 0) {
- return null;
- }
+ if (keyIdsArray.length == 0) {
+ Log.e(Constants.TAG, "keyIdsArray.length == 0, should never happen!");
+ }
- Intent result = new Intent();
- result.putExtra(OpenPgpApi.RESULT_KEY_IDS, keyIdsArray);
- result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
- return result;
+ Intent result = new Intent();
+ result.putExtra(OpenPgpApi.RESULT_KEY_IDS, keyIdsArray);
+ result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
+ return result;
+ }
}
private Intent getPassphraseBundleIntent(Intent data, long keyId) {
@@ -241,10 +252,9 @@ public class OpenPgpService extends RemoteService {
originalFilename = "";
}
- long[] keyIds;
- if (data.hasExtra(OpenPgpApi.EXTRA_KEY_IDS)) {
- keyIds = data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS);
- } else if (data.hasExtra(OpenPgpApi.EXTRA_USER_IDS)) {
+ // first try to get key ids from non-ambiguous key id extra
+ long[] keyIds = data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS);
+ if (keyIds == null) {
// get key ids based on given user ids
String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS);
// give params through to activity...
@@ -256,14 +266,6 @@ public class OpenPgpService extends RemoteService {
// if not success -> result contains a PendingIntent for user interaction
return result;
}
- } else {
- Intent result = new Intent();
- result.putExtra(OpenPgpApi.RESULT_ERROR,
- new OpenPgpError(OpenPgpError.GENERIC_ERROR,
- "Missing parameter user_ids or key_ids!")
- );
- result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
- return result;
}
// build InputData and write into OutputStream
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java
index 48c76d561..4b27e115b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java
@@ -18,11 +18,20 @@
package org.sufficientlysecure.keychain.remote.ui;
import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.Typeface;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.ActionBarActivity;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.SpannedString;
+import android.text.TextUtils;
+import android.text.style.BulletSpan;
+import android.text.style.StyleSpan;
import android.view.View;
import android.widget.TextView;
@@ -39,7 +48,6 @@ import org.sufficientlysecure.keychain.ui.SelectPublicKeyFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
-import java.security.Provider;
import java.util.ArrayList;
public class RemoteServiceActivity extends ActionBarActivity {
@@ -68,7 +76,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
// select pub keys action
public static final String EXTRA_SELECTED_MASTER_KEY_IDS = "master_key_ids";
public static final String EXTRA_MISSING_USER_IDS = "missing_user_ids";
- public static final String EXTRA_DUBLICATE_USER_IDS = "dublicate_user_ids";
+ public static final String EXTRA_DUPLICATE_USER_IDS = "dublicate_user_ids";
+ public static final String EXTRA_NO_USER_IDS_CHECK = "no_user_ids";
// error message
public static final String EXTRA_ERROR_MESSAGE = "error_message";
@@ -229,32 +238,41 @@ public class RemoteServiceActivity extends ActionBarActivity {
} else if (ACTION_SELECT_PUB_KEYS.equals(action)) {
long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS);
+ boolean noUserIdsCheck = intent.getBooleanExtra(EXTRA_NO_USER_IDS_CHECK, true);
ArrayList missingUserIds = intent
.getStringArrayListExtra(EXTRA_MISSING_USER_IDS);
ArrayList dublicateUserIds = intent
- .getStringArrayListExtra(EXTRA_DUBLICATE_USER_IDS);
+ .getStringArrayListExtra(EXTRA_DUPLICATE_USER_IDS);
+
+ SpannableStringBuilder ssb = new SpannableStringBuilder();
+ final SpannableString textIntro = new SpannableString(
+ noUserIdsCheck ? getString(R.string.api_select_pub_keys_text_no_user_ids)
+ : getString(R.string.api_select_pub_keys_text)
+ );
+ textIntro.setSpan(new StyleSpan(Typeface.BOLD), 0, textIntro.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ ssb.append(textIntro);
- // TODO: do this with spannable instead of HTML to prevent parsing failures with weird user ids
- String text = "" + getString(R.string.api_select_pub_keys_text) + "";
- text += "
";
if (missingUserIds != null && missingUserIds.size() > 0) {
- text += getString(R.string.api_select_pub_keys_missing_text);
- text += "
";
- text += "";
+ ssb.append("\n\n");
+ ssb.append(getString(R.string.api_select_pub_keys_missing_text));
+ ssb.append("\n");
for (String userId : missingUserIds) {
- text += "- " + userId + "
";
+ SpannableString ss = new SpannableString(userId + "\n");
+ ss.setSpan(new BulletSpan(15, Color.BLACK), 0, ss.length(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ ssb.append(ss);
}
- text += "
";
- text += "
";
}
if (dublicateUserIds != null && dublicateUserIds.size() > 0) {
- text += getString(R.string.api_select_pub_keys_dublicates_text);
- text += "
";
- text += "";
+ ssb.append("\n\n");
+ ssb.append(getString(R.string.api_select_pub_keys_dublicates_text));
+ ssb.append("\n");
for (String userId : dublicateUserIds) {
- text += "- " + userId + "
";
+ SpannableString ss = new SpannableString(userId + "\n");
+ ss.setSpan(new BulletSpan(15, Color.BLACK), 0, ss.length(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ ssb.append(ss);
}
- text += "
";
}
// Inflate a "Done"/"Cancel" custom action bar view
@@ -284,8 +302,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
setContentView(R.layout.api_remote_select_pub_keys);
// set text on view
- HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_select_pub_keys_text);
- textView.setHtmlFromString(text, true);
+ TextView textView = (TextView) findViewById(R.id.api_select_pub_keys_text);
+ textView.setText(ssb, TextView.BufferType.SPANNABLE);
/* Load select pub keys fragment */
// Check that the activity is using the layout version with
diff --git a/OpenKeychain/src/main/res/layout/api_remote_select_pub_keys.xml b/OpenKeychain/src/main/res/layout/api_remote_select_pub_keys.xml
index a10592607..bf4d0a70d 100644
--- a/OpenKeychain/src/main/res/layout/api_remote_select_pub_keys.xml
+++ b/OpenKeychain/src/main/res/layout/api_remote_select_pub_keys.xml
@@ -4,13 +4,13 @@
android:layout_height="fill_parent"
android:orientation="vertical" >
-
Allow access
Disallow access
Please select a key!
- No public keys were found for these identities:
- More than one public key exist for these identities:
+ No keys were found for these identities:
+ More than one key exist for these identities:
Please review the list of recipients!
+ Please select the recipients!
Signature check failed! Have you installed this app from a different source? If you are sure that this is not an attack, revoke this app\'s registration in OpenKeychain and then register the app again.
From 0708b573fc7a058d08840b8ce256cb103a0eeafa Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Sat, 16 Aug 2014 03:48:13 +0200
Subject: [PATCH 033/142] test: even nicer code
---
.../keychain/pgp/PgpKeyOperationTest.java | 45 +++++++------------
1 file changed, 16 insertions(+), 29 deletions(-)
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index f37f11d87..91c95a873 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -237,10 +237,8 @@ public class PgpKeyOperationTest {
parcel.mMasterKeyId = ring.getMasterKeyId() -1;
parcel.mFingerprint = ring.getFingerprint();
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
-
assertModifyFailure("keyring modification with bad master key id should fail",
- secretRing, parcel);
+ ring, parcel);
}
{
@@ -249,10 +247,8 @@ public class PgpKeyOperationTest {
parcel.mMasterKeyId = null;
parcel.mFingerprint = ring.getFingerprint();
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
-
assertModifyFailure("keyring modification with null master key id should fail",
- secretRing, parcel);
+ ring, parcel);
}
{
@@ -262,10 +258,8 @@ public class PgpKeyOperationTest {
// some byte, off by one
parcel.mFingerprint[5] += 1;
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
-
assertModifyFailure("keyring modification with bad fingerprint should fail",
- secretRing, parcel);
+ ring, parcel);
}
{
@@ -273,10 +267,8 @@ public class PgpKeyOperationTest {
parcel.mMasterKeyId = ring.getMasterKeyId();
parcel.mFingerprint = null;
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
-
assertModifyFailure("keyring modification with null fingerprint should fail",
- secretRing, parcel);
+ ring, parcel);
}
{
@@ -284,10 +276,9 @@ public class PgpKeyOperationTest {
if (badphrase.equals(passphrase)) {
badphrase = "a";
}
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
assertModifyFailure("keyring modification with bad passphrase should fail",
- secretRing, parcel, badphrase);
+ ring, parcel, badphrase);
}
}
@@ -340,9 +331,7 @@ public class PgpKeyOperationTest {
parcel.reset();
parcel.mAddSubKeys.add(new SubkeyAdd(
PublicKeyAlgorithmTags.RSA_GENERAL, new Random().nextInt(512), KeyFlags.SIGN_DATA, null));
-
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- assertModifyFailure("creating a subkey with keysize < 512 should fail", secretRing, parcel);
+ assertModifyFailure("creating a subkey with keysize < 512 should fail", ring, parcel);
}
@@ -350,9 +339,7 @@ public class PgpKeyOperationTest {
parcel.reset();
parcel.mAddSubKeys.add(new SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA,
new Date().getTime()/1000-10));
-
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- assertModifyFailure("creating subkey with past expiry date should fail", secretRing, parcel);
+ assertModifyFailure("creating subkey with past expiry date should fail", ring, parcel);
}
}
@@ -564,8 +551,7 @@ public class PgpKeyOperationTest {
parcel.reset();
parcel.mChangePrimaryUserId = uid;
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(modified.getEncoded(), false, 0);
- assertModifyFailure("setting primary user id to a revoked user id should fail", secretRing, parcel);
+ assertModifyFailure("setting primary user id to a revoked user id should fail", modified, parcel);
}
@@ -610,8 +596,7 @@ public class PgpKeyOperationTest {
{
parcel.mAddUserIds.add("");
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- assertModifyFailure("adding an empty user id should fail", secretRing, parcel);
+ assertModifyFailure("adding an empty user id should fail", ring, parcel);
}
parcel.reset();
@@ -679,9 +664,8 @@ public class PgpKeyOperationTest {
parcel.mChangePrimaryUserId += "A";
}
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
assertModifyFailure("changing primary user id to a non-existent one should fail",
- secretRing, parcel);
+ ring, parcel);
}
// check for revoked primary user id already done in revoke test
@@ -774,9 +758,10 @@ public class PgpKeyOperationTest {
}
- private void assertModifyFailure(String reason, CanonicalizedSecretKeyRing secretRing,
- SaveKeyringParcel parcel, String passphrase) {
+ private void assertModifyFailure(String reason, UncachedKeyRing ring,
+ SaveKeyringParcel parcel, String passphrase) throws Exception {
+ CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, passphrase);
Assert.assertFalse(reason, result.success());
@@ -784,8 +769,10 @@ public class PgpKeyOperationTest {
}
- private void assertModifyFailure(String reason, CanonicalizedSecretKeyRing secretRing, SaveKeyringParcel parcel) {
+ private void assertModifyFailure(String reason, UncachedKeyRing ring, SaveKeyringParcel parcel)
+ throws Exception {
+ CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, passphrase);
Assert.assertFalse(reason, result.success());
From c54fe21f44f118c59874fe97b662b3faea6ebc48 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Sat, 16 Aug 2014 05:13:09 +0200
Subject: [PATCH 034/142] modifySecretKey: err out on revocation of nonexistent
user id
---
.../keychain/pgp/PgpKeyOperationTest.java | 7 +++++++
.../keychain/pgp/PgpKeyOperation.java | 12 ++++++++++++
.../keychain/service/OperationResultParcel.java | 1 +
OpenKeychain/src/main/res/values/strings.xml | 1 +
4 files changed, 21 insertions(+)
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index 91c95a873..9d4aa7dba 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -589,6 +589,13 @@ public class PgpKeyOperationTest {
ring.getMasterKeyId(), ((SignaturePacket) p).getKeyID());
}
+ { // revocation of non-existent user id should fail
+ parcel.reset();
+ parcel.mRevokeUserIds.add("nonexistent");
+
+ assertModifyFailure("revocation of nonexistent user id should fail", modified, parcel);
+ }
+
}
@Test
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 fe84b3802..06d8dff69 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -403,6 +403,18 @@ public class PgpKeyOperation {
progress(R.string.progress_modify_revokeuid, (i-1) * (100 / saveParcel.mRevokeUserIds.size()));
String userId = saveParcel.mRevokeUserIds.get(i);
log.add(LogLevel.INFO, LogType.MSG_MF_UID_REVOKE, indent, userId);
+ // Make sure the user id exists (yes these are 10 LoC in Java!)
+ boolean exists = false;
+ for (String uid : new IterableIterator(modifiedPublicKey.getUserIDs())) {
+ if (userId.equals(uid)) {
+ exists = true;
+ break;
+ }
+ }
+ if (!exists) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NOEXIST_REVOKE, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
// a duplicate revocation will be removed during canonicalization, so no need to
// take care of that here.
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index 25dac2139..4c93e2a91 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -359,6 +359,7 @@ public class OperationResultParcel implements Parcelable {
MSG_MF_ERROR_KEYID (R.string.msg_mf_error_keyid),
MSG_MF_ERROR_INTEGRITY (R.string.msg_mf_error_integrity),
MSG_MF_ERROR_NOEXIST_PRIMARY (R.string.msg_mf_error_noexist_primary),
+ MSG_MF_ERROR_NOEXIST_REVOKE (R.string.msg_mf_error_noexist_revoke),
MSG_MF_ERROR_REVOKED_PRIMARY (R.string.msg_mf_error_revoked_primary),
MSG_MF_ERROR_PGP (R.string.msg_mf_error_pgp),
MSG_MF_ERROR_SIG (R.string.msg_mf_error_sig),
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 6f77be78f..5eb594163 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -639,6 +639,7 @@
No key ID. This is an internal error, please file a bug report!
Internal error, integrity check failed!
Bad primary user id specified!
+ Bad user id for revocation specified!
Revoked user ids cannot be primary!
PGP internal exception!
Signature exception!
From 1fa77d57d2bb0e82291364a046ddce0e17fa393f Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Sat, 16 Aug 2014 05:15:12 +0200
Subject: [PATCH 035/142] modifySecretKey: err out on "use previous" expiry
date for (sub)key creation
---
.../keychain/pgp/PgpKeyOperationTest.java | 20 +++++++++----------
.../keychain/pgp/PgpKeyOperation.java | 8 +++++++-
.../service/OperationResultParcel.java | 2 ++
OpenKeychain/src/main/res/values/strings.xml | 2 ++
4 files changed, 21 insertions(+), 11 deletions(-)
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index 9d4aa7dba..08c29bc2c 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -71,11 +71,11 @@ public class PgpKeyOperationTest {
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("twi");
parcel.mAddUserIds.add("pink");
@@ -113,7 +113,7 @@ public class PgpKeyOperationTest {
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, new Random().nextInt(256)+255, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, new Random().nextInt(256)+255, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
@@ -123,7 +123,7 @@ public class PgpKeyOperationTest {
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, 1024, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
@@ -133,7 +133,7 @@ public class PgpKeyOperationTest {
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- 12345, 1024, KeyFlags.CERTIFY_OTHER, null));
+ 12345, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
@@ -143,7 +143,7 @@ public class PgpKeyOperationTest {
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
@@ -153,7 +153,7 @@ public class PgpKeyOperationTest {
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mNewPassphrase = passphrase;
assertFailure("creating ring without user ids should fail", parcel);
@@ -175,7 +175,7 @@ public class PgpKeyOperationTest {
public void testMasterFlags() throws Exception {
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA, 0L));
parcel.mAddUserIds.add("luna");
ring = assertCreateSuccess("creating ring with master key flags must succeed", parcel);
@@ -330,7 +330,7 @@ public class PgpKeyOperationTest {
{ // bad keysize should fail
parcel.reset();
parcel.mAddSubKeys.add(new SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, new Random().nextInt(512), KeyFlags.SIGN_DATA, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, new Random().nextInt(512), KeyFlags.SIGN_DATA, 0L));
assertModifyFailure("creating a subkey with keysize < 512 should fail", ring, parcel);
}
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 06d8dff69..d7658efef 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -218,6 +218,11 @@ public class PgpKeyOperation {
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
+ if (add.mExpiry == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NULL_EXPIRY, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+
if (add.mAlgorithm == PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT) {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_MASTER_ELGAMAL, indent);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
@@ -638,7 +643,8 @@ public class PgpKeyOperation {
);
PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize, log, indent);
subProgressPop();
- if(keyPair == null) {
+ if (keyPair == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PGP, indent +1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index 4c93e2a91..01c7611ff 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -347,6 +347,7 @@ public class OperationResultParcel implements Parcelable {
MSG_CR_ERROR_NO_MASTER (R.string.msg_cr_error_no_master),
MSG_CR_ERROR_NO_USER_ID (R.string.msg_cr_error_no_user_id),
MSG_CR_ERROR_NO_CERTIFY (R.string.msg_cr_error_no_certify),
+ MSG_CR_ERROR_NULL_EXPIRY(R.string.msg_cr_error_null_expiry),
MSG_CR_ERROR_KEYSIZE_512 (R.string.msg_cr_error_keysize_512),
MSG_CR_ERROR_UNKNOWN_ALGO (R.string.msg_cr_error_unknown_algo),
MSG_CR_ERROR_INTERNAL_PGP (R.string.msg_cr_error_internal_pgp),
@@ -360,6 +361,7 @@ public class OperationResultParcel implements Parcelable {
MSG_MF_ERROR_INTEGRITY (R.string.msg_mf_error_integrity),
MSG_MF_ERROR_NOEXIST_PRIMARY (R.string.msg_mf_error_noexist_primary),
MSG_MF_ERROR_NOEXIST_REVOKE (R.string.msg_mf_error_noexist_revoke),
+ MSG_MF_ERROR_NULL_EXPIRY (R.string.msg_mf_error_null_expiry),
MSG_MF_ERROR_REVOKED_PRIMARY (R.string.msg_mf_error_revoked_primary),
MSG_MF_ERROR_PGP (R.string.msg_mf_error_pgp),
MSG_MF_ERROR_SIG (R.string.msg_mf_error_sig),
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 5eb594163..f603663e8 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -627,6 +627,7 @@
No master key options specified!
Keyrings must be created with at least one user id!
Master key must have certify flag!
+ Expiry time cannot be "same as before" on key creation. This is a programming error, please file a bug report!
Key size must be greater or equal 512!
Internal PGP error!
Bad algorithm choice!
@@ -641,6 +642,7 @@
Bad primary user id specified!
Bad user id for revocation specified!
Revoked user ids cannot be primary!
+ Expiry time cannot be "same as before" on subkey creation. This is a programming error, please file a bug report!
PGP internal exception!
Signature exception!
Changing passphrase
From a943bebfdf063700c01170ea264e342283e5d6b3 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Sat, 16 Aug 2014 06:24:40 +0200
Subject: [PATCH 036/142] support for master key modifications, among other
stuff
---
.../keychain/pgp/PgpKeyOperationTest.java | 122 ++++-
.../pgp/UncachedKeyringCanonicalizeTest.java | 8 +-
.../pgp/UncachedKeyringMergeTest.java | 8 +-
.../keychain/pgp/UncachedKeyringTest.java | 6 +-
.../keychain/pgp/PgpKeyOperation.java | 505 +++++++++++-------
.../service/OperationResultParcel.java | 13 +-
.../src/main/res/values-es/strings.xml | 2 +-
.../src/main/res/values-fr/strings.xml | 2 +-
.../src/main/res/values-it/strings.xml | 2 +-
.../src/main/res/values-ja/strings.xml | 2 +-
.../src/main/res/values-ru/strings.xml | 2 +-
OpenKeychain/src/main/res/values/strings.xml | 4 +-
12 files changed, 459 insertions(+), 217 deletions(-)
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index 08c29bc2c..c46e3ee15 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -376,6 +376,20 @@ public class PgpKeyOperationTest {
ring.getPublicKey(keyId).getKeyUsage(), modified.getPublicKey(keyId).getKeyUsage());
}
+ { // change expiry
+ expiry += 60*60*24;
+
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, expiry));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ Assert.assertNotNull("modified key must have an expiry date",
+ modified.getPublicKey(keyId).getExpiryTime());
+ Assert.assertEquals("modified key must have expected expiry date",
+ expiry, modified.getPublicKey(keyId).getExpiryTime().getTime()/1000);
+ Assert.assertEquals("modified key must have same flags as before",
+ ring.getPublicKey(keyId).getKeyUsage(), modified.getPublicKey(keyId).getKeyUsage());
+ }
+
{
int flags = KeyFlags.SIGN_DATA | KeyFlags.ENCRYPT_COMMS;
parcel.reset();
@@ -422,16 +436,114 @@ public class PgpKeyOperationTest {
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, new Date().getTime()/1000-10));
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- assertModifyFailure("setting subkey expiry to a past date should fail", secretRing, parcel);
+ assertModifyFailure("setting subkey expiry to a past date should fail", ring, parcel);
}
- { // modifying nonexistent keyring should fail
+ { // modifying nonexistent subkey should fail
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(123, null, null));
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- assertModifyFailure("modifying non-existent subkey should fail", secretRing, parcel);
+ assertModifyFailure("modifying non-existent subkey should fail", ring, parcel);
+ }
+
+ }
+
+ @Test
+ public void testMasterModify() throws Exception {
+
+ long expiry = new Date().getTime()/1000 + 1024;
+ long keyId = ring.getMasterKeyId();
+
+ UncachedKeyRing modified = ring;
+
+ // to make this check less trivial, we add a user id, change the primary one and revoke one
+ parcel.mAddUserIds.add("aloe");
+ parcel.mChangePrimaryUserId = "aloe";
+ parcel.mRevokeUserIds.add("pink");
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ {
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, expiry));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ // this implies that only the two non-revoked signatures were changed!
+ Assert.assertEquals("two extra packets in original", 2, onlyA.size());
+ Assert.assertEquals("two extra packets in modified", 2, onlyB.size());
+
+ Assert.assertEquals("first original packet must be a signature",
+ PacketTags.SIGNATURE, onlyA.get(0).tag);
+ Assert.assertEquals("second original packet must be a signature",
+ PacketTags.SIGNATURE, onlyA.get(1).tag);
+ Assert.assertEquals("first new packet must be signature",
+ PacketTags.SIGNATURE, onlyB.get(0).tag);
+ Assert.assertEquals("first new packet must be signature",
+ PacketTags.SIGNATURE, onlyB.get(1).tag);
+
+ Assert.assertNotNull("modified key must have an expiry date",
+ modified.getPublicKey().getExpiryTime());
+ Assert.assertEquals("modified key must have expected expiry date",
+ expiry, modified.getPublicKey().getExpiryTime().getTime() / 1000);
+ Assert.assertEquals("modified key must have same flags as before",
+ ring.getPublicKey().getKeyUsage(), modified.getPublicKey().getKeyUsage());
+ }
+
+ { // change expiry
+ expiry += 60*60*24;
+
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, expiry));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ Assert.assertNotNull("modified key must have an expiry date",
+ modified.getPublicKey(keyId).getExpiryTime());
+ Assert.assertEquals("modified key must have expected expiry date",
+ expiry, modified.getPublicKey(keyId).getExpiryTime().getTime()/1000);
+ Assert.assertEquals("modified key must have same flags as before",
+ ring.getPublicKey(keyId).getKeyUsage(), modified.getPublicKey(keyId).getKeyUsage());
+ }
+
+ {
+ int flags = KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA;
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, flags, null));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ Assert.assertEquals("modified key must have expected flags",
+ flags, modified.getPublicKey(keyId).getKeyUsage());
+ Assert.assertNotNull("key must retain its expiry",
+ modified.getPublicKey(keyId).getExpiryTime());
+ Assert.assertEquals("key expiry must be unchanged",
+ expiry, modified.getPublicKey(keyId).getExpiryTime().getTime()/1000);
+ }
+
+ { // expiry of 0 should be "no expiry"
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, 0L));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ Assert.assertNull("key must not expire anymore", modified.getPublicKey(keyId).getExpiryTime());
+ }
+
+ { // if we revoke everything, nothing is left to properly sign...
+ parcel.reset();
+ parcel.mRevokeUserIds.add("twi");
+ parcel.mRevokeUserIds.add("pink");
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, KeyFlags.CERTIFY_OTHER, null));
+
+ assertModifyFailure("master key modification with all user ids revoked should fail", ring, parcel);
+ }
+
+ { // any flag not including CERTIFY_OTHER should fail
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, KeyFlags.SIGN_DATA, null));
+
+ assertModifyFailure("setting master key flags without certify should fail", ring, parcel);
+ }
+
+ { // a past expiry should fail
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, new Date().getTime()/1000-10));
+
+ assertModifyFailure("setting subkey expiry to a past date should fail", ring, parcel);
}
}
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
index 535e9d01a..588dac17b 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
@@ -64,11 +64,11 @@ public class UncachedKeyringCanonicalizeTest {
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("twi");
parcel.mAddUserIds.add("pink");
@@ -277,7 +277,7 @@ public class UncachedKeyringCanonicalizeTest {
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddUserIds.add("trix");
PgpKeyOperation op = new PgpKeyOperation(null);
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
index 6e9381c06..603b1e6d1 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
@@ -64,9 +64,9 @@ public class UncachedKeyringMergeTest {
{
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
parcel.mAddUserIds.add("twi");
parcel.mAddUserIds.add("pink");
@@ -83,7 +83,7 @@ public class UncachedKeyringMergeTest {
{
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddUserIds.add("shy");
// passphrase is tested in PgpKeyOperationTest, just use empty here
@@ -189,7 +189,7 @@ public class UncachedKeyringMergeTest {
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
modifiedA = op.modifySecretKeyRing(secretRing, parcel, "").getRing();
modifiedB = op.modifySecretKeyRing(secretRing, parcel, "").getRing();
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java
index cbd1bc502..581e315a0 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java
@@ -37,11 +37,11 @@ public class UncachedKeyringTest {
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("twi");
parcel.mAddUserIds.add("pink");
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 d7658efef..710bd42c6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -253,7 +253,7 @@ public class PgpKeyOperation {
masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator());
subProgressPush(50, 100);
- return internal(sKR, masterSecretKey, add.mFlags, saveParcel, "", log);
+ return internal(sKR, masterSecretKey, add.mFlags, add.mExpiry, saveParcel, "", log);
} catch (PGPException e) {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_INTERNAL_PGP, indent);
@@ -319,14 +319,17 @@ public class PgpKeyOperation {
// read masterKeyFlags, and use the same as before.
// since this is the master key, this contains at least CERTIFY_OTHER
- int masterKeyFlags = readKeyFlags(masterSecretKey.getPublicKey()) | KeyFlags.CERTIFY_OTHER;
+ PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
+ int masterKeyFlags = readKeyFlags(masterPublicKey) | KeyFlags.CERTIFY_OTHER;
+ long masterKeyExpiry = masterPublicKey.getValidSeconds() == 0L ? 0L :
+ masterPublicKey.getCreationTime().getTime() / 1000 + masterPublicKey.getValidSeconds();
- return internal(sKR, masterSecretKey, masterKeyFlags, saveParcel, passphrase, log);
+ return internal(sKR, masterSecretKey, masterKeyFlags, masterKeyExpiry, saveParcel, passphrase, log);
}
private EditKeyResult internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey,
- int masterKeyFlags,
+ int masterKeyFlags, long masterKeyExpiry,
SaveKeyringParcel saveParcel, String passphrase,
OperationLog log) {
@@ -351,189 +354,196 @@ public class PgpKeyOperation {
}
}
- // work on master secret key
try {
- PGPPublicKey modifiedPublicKey = masterPublicKey;
+ { // work on master secret key
- // 2a. Add certificates for new user ids
- subProgressPush(15, 25);
- for (int i = 0; i < saveParcel.mAddUserIds.size(); i++) {
+ PGPPublicKey modifiedPublicKey = masterPublicKey;
- progress(R.string.progress_modify_adduid, (i-1) * (100 / saveParcel.mAddUserIds.size()));
- String userId = saveParcel.mAddUserIds.get(i);
- log.add(LogLevel.INFO, LogType.MSG_MF_UID_ADD, indent, userId);
+ // 2a. Add certificates for new user ids
+ subProgressPush(15, 25);
+ for (int i = 0; i < saveParcel.mAddUserIds.size(); i++) {
- if (userId.equals("")) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_UID_ERROR_EMPTY, indent+1);
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
- }
+ progress(R.string.progress_modify_adduid, (i - 1) * (100 / saveParcel.mAddUserIds.size()));
+ String userId = saveParcel.mAddUserIds.get(i);
+ log.add(LogLevel.INFO, LogType.MSG_MF_UID_ADD, indent, userId);
- // this operation supersedes all previous binding and revocation certificates,
- // so remove those to retain assertions from canonicalization for later operations
- @SuppressWarnings("unchecked")
- Iterator it = modifiedPublicKey.getSignaturesForID(userId);
- if (it != null) {
- for (PGPSignature cert : new IterableIterator(it)) {
- if (cert.getKeyID() != masterPublicKey.getKeyID()) {
- // foreign certificate?! error error error
- log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
- }
- if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION
- || cert.getSignatureType() == PGPSignature.NO_CERTIFICATION
- || cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION
- || cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION
- || cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
- modifiedPublicKey = PGPPublicKey.removeCertification(
- modifiedPublicKey, userId, cert);
- }
- }
- }
-
- // if it's supposed to be primary, we can do that here as well
- boolean isPrimary = saveParcel.mChangePrimaryUserId != null
- && userId.equals(saveParcel.mChangePrimaryUserId);
- // generate and add new certificate
- PGPSignature cert = generateUserIdSignature(masterPrivateKey,
- masterPublicKey, userId, isPrimary, masterKeyFlags);
- modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
- }
- subProgressPop();
-
- // 2b. Add revocations for revoked user ids
- subProgressPush(25, 40);
- for (int i = 0; i < saveParcel.mRevokeUserIds.size(); i++) {
-
- progress(R.string.progress_modify_revokeuid, (i-1) * (100 / saveParcel.mRevokeUserIds.size()));
- String userId = saveParcel.mRevokeUserIds.get(i);
- log.add(LogLevel.INFO, LogType.MSG_MF_UID_REVOKE, indent, userId);
- // Make sure the user id exists (yes these are 10 LoC in Java!)
- boolean exists = false;
- for (String uid : new IterableIterator(modifiedPublicKey.getUserIDs())) {
- if (userId.equals(uid)) {
- exists = true;
- break;
- }
- }
- if (!exists) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NOEXIST_REVOKE, indent);
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
- }
-
- // a duplicate revocation will be removed during canonicalization, so no need to
- // take care of that here.
- PGPSignature cert = generateRevocationSignature(masterPrivateKey,
- masterPublicKey, userId);
- modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
- }
- subProgressPop();
-
- // 3. If primary user id changed, generate new certificates for both old and new
- if (saveParcel.mChangePrimaryUserId != null) {
- progress(R.string.progress_modify_primaryuid, 40);
-
- // keep track if we actually changed one
- boolean ok = false;
- log.add(LogLevel.INFO, LogType.MSG_MF_UID_PRIMARY, indent);
- indent += 1;
-
- // we work on the modifiedPublicKey here, to respect new or newly revoked uids
- // noinspection unchecked
- for (String userId : new IterableIterator(modifiedPublicKey.getUserIDs())) {
- boolean isRevoked = false;
- PGPSignature currentCert = null;
- // noinspection unchecked
- for (PGPSignature cert : new IterableIterator(
- modifiedPublicKey.getSignaturesForID(userId))) {
- if (cert.getKeyID() != masterPublicKey.getKeyID()) {
- // foreign certificate?! error error error
- log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
- }
- // we know from canonicalization that if there is any revocation here, it
- // is valid and not superseded by a newer certification.
- if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
- isRevoked = true;
- continue;
- }
- // we know from canonicalization that there is only one binding
- // certification here, so we can just work with the first one.
- if (cert.getSignatureType() == PGPSignature.NO_CERTIFICATION ||
- cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION ||
- cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION ||
- cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
- currentCert = cert;
- }
- }
-
- if (currentCert == null) {
- // no certificate found?! error error error
- log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ if (userId.equals("")) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_UID_ERROR_EMPTY, indent + 1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
- // we definitely should not update certifications of revoked keys, so just leave it.
- if (isRevoked) {
- // revoked user ids cannot be primary!
- if (userId.equals(saveParcel.mChangePrimaryUserId)) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_REVOKED_PRIMARY, indent);
+ // this operation supersedes all previous binding and revocation certificates,
+ // so remove those to retain assertions from canonicalization for later operations
+ @SuppressWarnings("unchecked")
+ Iterator it = modifiedPublicKey.getSignaturesForID(userId);
+ if (it != null) {
+ for (PGPSignature cert : new IterableIterator(it)) {
+ if (cert.getKeyID() != masterPublicKey.getKeyID()) {
+ // foreign certificate?! error error error
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+ if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION
+ || cert.getSignatureType() == PGPSignature.NO_CERTIFICATION
+ || cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION
+ || cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION
+ || cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
+ modifiedPublicKey = PGPPublicKey.removeCertification(
+ modifiedPublicKey, userId, cert);
+ }
+ }
+ }
+
+ // if it's supposed to be primary, we can do that here as well
+ boolean isPrimary = saveParcel.mChangePrimaryUserId != null
+ && userId.equals(saveParcel.mChangePrimaryUserId);
+ // generate and add new certificate
+ PGPSignature cert = generateUserIdSignature(masterPrivateKey,
+ masterPublicKey, userId, isPrimary, masterKeyFlags, masterKeyExpiry);
+ modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
+ }
+ subProgressPop();
+
+ // 2b. Add revocations for revoked user ids
+ subProgressPush(25, 40);
+ for (int i = 0; i < saveParcel.mRevokeUserIds.size(); i++) {
+
+ progress(R.string.progress_modify_revokeuid, (i - 1) * (100 / saveParcel.mRevokeUserIds.size()));
+ String userId = saveParcel.mRevokeUserIds.get(i);
+ log.add(LogLevel.INFO, LogType.MSG_MF_UID_REVOKE, indent, userId);
+
+ // Make sure the user id exists (yes these are 10 LoC in Java!)
+ boolean exists = false;
+ //noinspection unchecked
+ for (String uid : new IterableIterator(modifiedPublicKey.getUserIDs())) {
+ if (userId.equals(uid)) {
+ exists = true;
+ break;
+ }
+ }
+ if (!exists) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NOEXIST_REVOKE, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+
+ // a duplicate revocation will be removed during canonicalization, so no need to
+ // take care of that here.
+ PGPSignature cert = generateRevocationSignature(masterPrivateKey,
+ masterPublicKey, userId);
+ modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
+ }
+ subProgressPop();
+
+ // 3. If primary user id changed, generate new certificates for both old and new
+ if (saveParcel.mChangePrimaryUserId != null) {
+ progress(R.string.progress_modify_primaryuid, 40);
+
+ // keep track if we actually changed one
+ boolean ok = false;
+ log.add(LogLevel.INFO, LogType.MSG_MF_UID_PRIMARY, indent);
+ indent += 1;
+
+ // we work on the modifiedPublicKey here, to respect new or newly revoked uids
+ // noinspection unchecked
+ for (String userId : new IterableIterator(modifiedPublicKey.getUserIDs())) {
+ boolean isRevoked = false;
+ PGPSignature currentCert = null;
+ // noinspection unchecked
+ for (PGPSignature cert : new IterableIterator(
+ modifiedPublicKey.getSignaturesForID(userId))) {
+ if (cert.getKeyID() != masterPublicKey.getKeyID()) {
+ // foreign certificate?! error error error
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+ // we know from canonicalization that if there is any revocation here, it
+ // is valid and not superseded by a newer certification.
+ if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
+ isRevoked = true;
+ continue;
+ }
+ // we know from canonicalization that there is only one binding
+ // certification here, so we can just work with the first one.
+ if (cert.getSignatureType() == PGPSignature.NO_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
+ currentCert = cert;
+ }
+ }
+
+ if (currentCert == null) {
+ // no certificate found?! error error error
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
- continue;
- }
- // if this is~ the/a primary user id
- if (currentCert.getHashedSubPackets() != null
- && currentCert.getHashedSubPackets().isPrimaryUserID()) {
- // if it's the one we want, just leave it as is
- if (userId.equals(saveParcel.mChangePrimaryUserId)) {
- ok = true;
+ // we definitely should not update certifications of revoked keys, so just leave it.
+ if (isRevoked) {
+ // revoked user ids cannot be primary!
+ if (userId.equals(saveParcel.mChangePrimaryUserId)) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_REVOKED_PRIMARY, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
continue;
}
- // otherwise, generate new non-primary certification
- log.add(LogLevel.DEBUG, LogType.MSG_MF_PRIMARY_REPLACE_OLD, indent);
- modifiedPublicKey = PGPPublicKey.removeCertification(
- modifiedPublicKey, userId, currentCert);
- PGPSignature newCert = generateUserIdSignature(
- masterPrivateKey, masterPublicKey, userId, false, masterKeyFlags);
- modifiedPublicKey = PGPPublicKey.addCertification(
- modifiedPublicKey, userId, newCert);
- continue;
+
+ // if this is~ the/a primary user id
+ if (currentCert.getHashedSubPackets() != null
+ && currentCert.getHashedSubPackets().isPrimaryUserID()) {
+ // if it's the one we want, just leave it as is
+ if (userId.equals(saveParcel.mChangePrimaryUserId)) {
+ ok = true;
+ continue;
+ }
+ // otherwise, generate new non-primary certification
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_PRIMARY_REPLACE_OLD, indent);
+ modifiedPublicKey = PGPPublicKey.removeCertification(
+ modifiedPublicKey, userId, currentCert);
+ PGPSignature newCert = generateUserIdSignature(
+ masterPrivateKey, masterPublicKey, userId, false,
+ masterKeyFlags, masterKeyExpiry);
+ modifiedPublicKey = PGPPublicKey.addCertification(
+ modifiedPublicKey, userId, newCert);
+ continue;
+ }
+
+ // if we are here, this is not currently a primary user id
+
+ // if it should be
+ if (userId.equals(saveParcel.mChangePrimaryUserId)) {
+ // add shiny new primary user id certificate
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_PRIMARY_NEW, indent);
+ modifiedPublicKey = PGPPublicKey.removeCertification(
+ modifiedPublicKey, userId, currentCert);
+ PGPSignature newCert = generateUserIdSignature(
+ masterPrivateKey, masterPublicKey, userId, true,
+ masterKeyFlags, masterKeyExpiry);
+ modifiedPublicKey = PGPPublicKey.addCertification(
+ modifiedPublicKey, userId, newCert);
+ ok = true;
+ }
+
+ // user id is not primary and is not supposed to be - nothing to do here.
+
}
- // if we are here, this is not currently a primary user id
+ indent -= 1;
- // if it should be
- if (userId.equals(saveParcel.mChangePrimaryUserId)) {
- // add shiny new primary user id certificate
- log.add(LogLevel.DEBUG, LogType.MSG_MF_PRIMARY_NEW, indent);
- modifiedPublicKey = PGPPublicKey.removeCertification(
- modifiedPublicKey, userId, currentCert);
- PGPSignature newCert = generateUserIdSignature(
- masterPrivateKey, masterPublicKey, userId, true, masterKeyFlags);
- modifiedPublicKey = PGPPublicKey.addCertification(
- modifiedPublicKey, userId, newCert);
- ok = true;
+ if (!ok) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NOEXIST_PRIMARY, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
-
- // user id is not primary and is not supposed to be - nothing to do here.
-
}
- indent -= 1;
-
- if (!ok) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NOEXIST_PRIMARY, indent);
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ // Update the secret key ring
+ if (modifiedPublicKey != masterPublicKey) {
+ masterSecretKey = PGPSecretKey.replacePublicKey(masterSecretKey, modifiedPublicKey);
+ masterPublicKey = modifiedPublicKey;
+ sKR = PGPSecretKeyRing.insertSecretKey(sKR, masterSecretKey);
}
- }
- // Update the secret key ring
- if (modifiedPublicKey != masterPublicKey) {
- masterSecretKey = PGPSecretKey.replacePublicKey(masterSecretKey, modifiedPublicKey);
- masterPublicKey = modifiedPublicKey;
- sKR = PGPSecretKeyRing.insertSecretKey(sKR, masterSecretKey);
}
// 4a. For each subkey change, generate new subkey binding certificate
@@ -545,28 +555,47 @@ public class PgpKeyOperation {
log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_CHANGE,
indent, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
- // TODO allow changes in master key? this implies generating new user id certs...
- if (change.mKeyId == masterPublicKey.getKeyID()) {
- Log.e(Constants.TAG, "changing the master key not supported");
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
- }
-
PGPSecretKey sKey = sKR.getSecretKey(change.mKeyId);
if (sKey == null) {
log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_MISSING,
indent + 1, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
- PGPPublicKey pKey = sKey.getPublicKey();
// expiry must not be in the past
if (change.mExpiry != null && change.mExpiry != 0 &&
new Date(change.mExpiry*1000).before(new Date())) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_PAST_EXPIRY,
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PAST_EXPIRY,
indent + 1, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
+ // if this is the master key, update uid certificates instead
+ if (change.mKeyId == masterPublicKey.getKeyID()) {
+ int flags = change.mFlags == null ? masterKeyFlags : change.mFlags;
+ long expiry = change.mExpiry == null ? masterKeyExpiry : change.mExpiry;
+
+ if ((flags & KeyFlags.CERTIFY_OTHER) != KeyFlags.CERTIFY_OTHER) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NO_CERTIFY, indent + 1);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+
+ PGPPublicKey pKey =
+ updateMasterCertificates(masterPrivateKey, masterPublicKey,
+ flags, expiry, indent, log);
+ if (pKey == null) {
+ // error log entry has already been added by updateMasterCertificates itself
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+ masterSecretKey = PGPSecretKey.replacePublicKey(masterSecretKey, pKey);
+ masterPublicKey = pKey;
+ sKR = PGPSecretKeyRing.insertSecretKey(sKR, masterSecretKey);
+ continue;
+ }
+
+ // otherwise, continue working on the public key
+ PGPPublicKey pKey = sKey.getPublicKey();
+
// keep old flags, or replace with new ones
int flags = change.mFlags == null ? readKeyFlags(pKey) : change.mFlags;
long expiry;
@@ -583,7 +612,7 @@ public class PgpKeyOperation {
//noinspection unchecked
for (PGPSignature sig : new IterableIterator(pKey.getSignatures())) {
// special case: if there is a revocation, don't use expiry from before
- if (change.mExpiry == null
+ if ( (change.mExpiry == null || change.mExpiry == 0L)
&& sig.getSignatureType() == PGPSignature.SUBKEY_REVOCATION) {
expiry = 0;
}
@@ -631,8 +660,13 @@ public class PgpKeyOperation {
SaveKeyringParcel.SubkeyAdd add = saveParcel.mAddSubKeys.get(i);
log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent);
- if (add.mExpiry != null && new Date(add.mExpiry*1000).before(new Date())) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_PAST_EXPIRY, indent +1);
+ if (add.mExpiry == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NULL_EXPIRY, indent +1);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+
+ if (add.mExpiry > 0L && new Date(add.mExpiry*1000).before(new Date())) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PAST_EXPIRY, indent +1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
@@ -652,7 +686,7 @@ public class PgpKeyOperation {
PGPPublicKey pKey = keyPair.getPublicKey();
PGPSignature cert = generateSubkeyBindingSignature(
masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey,
- add.mFlags, add.mExpiry == null ? 0 : add.mExpiry);
+ add.mFlags, add.mExpiry);
pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
PGPSecretKey sKey; {
@@ -713,21 +747,104 @@ public class PgpKeyOperation {
}
+ /** Update all (non-revoked) uid signatures with new flags and expiry time. */
+ private static PGPPublicKey updateMasterCertificates(
+ PGPPrivateKey masterPrivateKey, PGPPublicKey masterPublicKey,
+ int flags, long expiry, int indent, OperationLog log)
+ throws PGPException, IOException, SignatureException {
+
+ // keep track if we actually changed one
+ boolean ok = false;
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_MASTER, indent);
+ indent += 1;
+
+ PGPPublicKey modifiedPublicKey = masterPublicKey;
+
+ // we work on the modifiedPublicKey here, to respect new or newly revoked uids
+ // noinspection unchecked
+ for (String userId : new IterableIterator(modifiedPublicKey.getUserIDs())) {
+ boolean isRevoked = false;
+ PGPSignature currentCert = null;
+ // noinspection unchecked
+ for (PGPSignature cert : new IterableIterator(
+ modifiedPublicKey.getSignaturesForID(userId))) {
+ if (cert.getKeyID() != masterPublicKey.getKeyID()) {
+ // foreign certificate?! error error error
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ return null;
+ }
+ // we know from canonicalization that if there is any revocation here, it
+ // is valid and not superseded by a newer certification.
+ if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
+ isRevoked = true;
+ continue;
+ }
+ // we know from canonicalization that there is only one binding
+ // certification here, so we can just work with the first one.
+ if (cert.getSignatureType() == PGPSignature.NO_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
+ currentCert = cert;
+ }
+ }
+
+ if (currentCert == null) {
+ // no certificate found?! error error error
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ return null;
+ }
+
+ // we definitely should not update certifications of revoked keys, so just leave it.
+ if (isRevoked) {
+ continue;
+ }
+
+ // add shiny new user id certificate
+ modifiedPublicKey = PGPPublicKey.removeCertification(
+ modifiedPublicKey, userId, currentCert);
+ PGPSignature newCert = generateUserIdSignature(
+ masterPrivateKey, masterPublicKey, userId, true, flags, expiry);
+ modifiedPublicKey = PGPPublicKey.addCertification(
+ modifiedPublicKey, userId, newCert);
+ ok = true;
+
+ }
+
+ if (!ok) {
+ // might happen, theoretically, if there is a key with no uid..
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ return null;
+ }
+
+ return modifiedPublicKey;
+
+ }
+
private static PGPSignature generateUserIdSignature(
- PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId, boolean primary, int flags)
+ PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId, boolean primary,
+ int flags, long expiry)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
pKey.getAlgorithm(), PGPUtil.SHA1)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
- PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
- subHashedPacketsGen.setSignatureCreationTime(false, new Date());
- subHashedPacketsGen.setPreferredSymmetricAlgorithms(true, PREFERRED_SYMMETRIC_ALGORITHMS);
- subHashedPacketsGen.setPreferredHashAlgorithms(true, PREFERRED_HASH_ALGORITHMS);
- subHashedPacketsGen.setPreferredCompressionAlgorithms(true, PREFERRED_COMPRESSION_ALGORITHMS);
- subHashedPacketsGen.setPrimaryUserID(false, primary);
- subHashedPacketsGen.setKeyFlags(false, flags);
- sGen.setHashedSubpackets(subHashedPacketsGen.generate());
+
+ PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator();
+ {
+ hashedPacketsGen.setSignatureCreationTime(false, new Date());
+ hashedPacketsGen.setPreferredSymmetricAlgorithms(true, PREFERRED_SYMMETRIC_ALGORITHMS);
+ hashedPacketsGen.setPreferredHashAlgorithms(true, PREFERRED_HASH_ALGORITHMS);
+ hashedPacketsGen.setPreferredCompressionAlgorithms(true, PREFERRED_COMPRESSION_ALGORITHMS);
+ hashedPacketsGen.setPrimaryUserID(false, primary);
+ hashedPacketsGen.setKeyFlags(false, flags);
+ if (expiry > 0) {
+ hashedPacketsGen.setKeyExpirationTime(
+ false, expiry - pKey.getCreationTime().getTime() / 1000);
+ }
+ }
+
+ sGen.setHashedSubpackets(hashedPacketsGen.generate());
sGen.init(PGPSignature.POSITIVE_CERTIFICATION, masterPrivateKey);
return sGen.generateCertification(userId, pKey);
}
@@ -784,14 +901,15 @@ public class PgpKeyOperation {
throws IOException, PGPException, SignatureException {
// date for signing
- Date todayDate = new Date();
+ Date creationTime = new Date();
+
PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator();
// If this key can sign, we need a primary key binding signature
if ((flags & KeyFlags.SIGN_DATA) > 0) {
// cross-certify signing keys
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
- subHashedPacketsGen.setSignatureCreationTime(false, todayDate);
+ subHashedPacketsGen.setSignatureCreationTime(false, creationTime);
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
pKey.getAlgorithm(), PGPUtil.SHA1)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
@@ -805,13 +923,12 @@ public class PgpKeyOperation {
PGPSignatureSubpacketGenerator hashedPacketsGen;
{
hashedPacketsGen = new PGPSignatureSubpacketGenerator();
- hashedPacketsGen.setSignatureCreationTime(false, todayDate);
+ hashedPacketsGen.setSignatureCreationTime(false, creationTime);
hashedPacketsGen.setKeyFlags(false, flags);
- }
-
- if (expiry > 0) {
- long creationTime = pKey.getCreationTime().getTime() / 1000;
- hashedPacketsGen.setKeyExpirationTime(false, expiry - creationTime);
+ if (expiry > 0) {
+ hashedPacketsGen.setKeyExpirationTime(false,
+ expiry - pKey.getCreationTime().getTime() / 1000);
+ }
}
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index 01c7611ff..138283b81 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -359,12 +359,15 @@ public class OperationResultParcel implements Parcelable {
MSG_MF_ERROR_FINGERPRINT (R.string.msg_mf_error_fingerprint),
MSG_MF_ERROR_KEYID (R.string.msg_mf_error_keyid),
MSG_MF_ERROR_INTEGRITY (R.string.msg_mf_error_integrity),
+ MSG_MF_ERROR_NO_CERTIFY (R.string.msg_cr_error_no_certify),
MSG_MF_ERROR_NOEXIST_PRIMARY (R.string.msg_mf_error_noexist_primary),
MSG_MF_ERROR_NOEXIST_REVOKE (R.string.msg_mf_error_noexist_revoke),
MSG_MF_ERROR_NULL_EXPIRY (R.string.msg_mf_error_null_expiry),
+ MSG_MF_ERROR_PAST_EXPIRY(R.string.msg_mf_error_past_expiry),
MSG_MF_ERROR_REVOKED_PRIMARY (R.string.msg_mf_error_revoked_primary),
MSG_MF_ERROR_PGP (R.string.msg_mf_error_pgp),
MSG_MF_ERROR_SIG (R.string.msg_mf_error_sig),
+ MSG_MF_MASTER (R.string.msg_mf_master),
MSG_MF_PASSPHRASE (R.string.msg_mf_passphrase),
MSG_MF_PRIMARY_REPLACE_OLD (R.string.msg_mf_primary_replace_old),
MSG_MF_PRIMARY_NEW (R.string.msg_mf_primary_new),
@@ -372,7 +375,6 @@ public class OperationResultParcel implements Parcelable {
MSG_MF_SUBKEY_MISSING (R.string.msg_mf_subkey_missing),
MSG_MF_SUBKEY_NEW_ID (R.string.msg_mf_subkey_new_id),
MSG_MF_SUBKEY_NEW (R.string.msg_mf_subkey_new),
- MSG_MF_SUBKEY_PAST_EXPIRY (R.string.msg_mf_subkey_past_expiry),
MSG_MF_SUBKEY_REVOKE (R.string.msg_mf_subkey_revoke),
MSG_MF_SUCCESS (R.string.msg_mf_success),
MSG_MF_UID_ADD (R.string.msg_mf_uid_add),
@@ -436,6 +438,15 @@ public class OperationResultParcel implements Parcelable {
mParcels.add(new OperationResultParcel.LogEntryParcel(level, type, indent, (Object[]) null));
}
+ public boolean containsType(LogType type) {
+ for(LogEntryParcel entry : new IterableIterator(mParcels.iterator())) {
+ if (entry.mType == type) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public boolean containsWarnings() {
for(LogEntryParcel entry : new IterableIterator(mParcels.iterator())) {
if (entry.mLevel == LogLevel.WARN || entry.mLevel == LogLevel.ERROR) {
diff --git a/OpenKeychain/src/main/res/values-es/strings.xml b/OpenKeychain/src/main/res/values-es/strings.xml
index 8b8af788d..0bd3a48c5 100644
--- a/OpenKeychain/src/main/res/values-es/strings.xml
+++ b/OpenKeychain/src/main/res/values-es/strings.xml
@@ -588,7 +588,7 @@
¡Intentó operar sobre una subclave ausente %s!
Generando nueva subclave %2$s de %1$s bits
Nueva identidad de subclave: %s
- ¡La fecha de expiración no puede ser del pasado!
+ ¡La fecha de expiración no puede ser del pasado!
Revocando subclave %s
Juego de claves modificado con éxito
Añadiendo identidad de usuario %s
diff --git a/OpenKeychain/src/main/res/values-fr/strings.xml b/OpenKeychain/src/main/res/values-fr/strings.xml
index 35e4c5766..3f570d144 100644
--- a/OpenKeychain/src/main/res/values-fr/strings.xml
+++ b/OpenKeychain/src/main/res/values-fr/strings.xml
@@ -588,7 +588,7 @@
Une action a été tentée sur la sous-clef manquante %s !
Génération d\'une nouvelle sous-clef %2$s de %1$s bit
ID de la nouvelle sous-clef : %s
- La date d\'expiration ne peut pas être dans le passé !
+ La date d\'expiration ne peut pas être dans le passé !
Révocation de la sous-clef %s
Trousseau modifié avec succès
Ajout de l\'ID d\'utilisateur %s
diff --git a/OpenKeychain/src/main/res/values-it/strings.xml b/OpenKeychain/src/main/res/values-it/strings.xml
index 2a5131bcf..590532d4d 100644
--- a/OpenKeychain/src/main/res/values-it/strings.xml
+++ b/OpenKeychain/src/main/res/values-it/strings.xml
@@ -528,7 +528,7 @@
Tentativo di operare su sottochiave mancante %s!
Generazione nuovi %1$s bit %2$s sottochiave
Nuovo ID sottochiave: %s
- La data di scadenza non può essere passata!
+ La data di scadenza non può essere passata!
Revoca sottochiave %s
Portachiavi modificato con successo
Aggiunta id utente %s
diff --git a/OpenKeychain/src/main/res/values-ja/strings.xml b/OpenKeychain/src/main/res/values-ja/strings.xml
index f0cb9d47b..6794deba9 100644
--- a/OpenKeychain/src/main/res/values-ja/strings.xml
+++ b/OpenKeychain/src/main/res/values-ja/strings.xml
@@ -574,7 +574,7 @@
遺失した副鍵 %s の操作をしようとした!
新しい %1$s ビットの %2$s 副鍵の生成中
新しい副鍵 ID: %s
- 期限切れ日を過去にはできません!
+ 期限切れ日を過去にはできません!
副鍵 %s を破棄中
鍵輪の変更に成功
ユーザID %s を追加中
diff --git a/OpenKeychain/src/main/res/values-ru/strings.xml b/OpenKeychain/src/main/res/values-ru/strings.xml
index 4f32bea3a..2ac766466 100644
--- a/OpenKeychain/src/main/res/values-ru/strings.xml
+++ b/OpenKeychain/src/main/res/values-ru/strings.xml
@@ -384,7 +384,7 @@
Внутренняя ошибка PGP!
Ошибка подписи!
Изменение пароля
- Срок годности не может быть в прошлом!
+ Срок годности не может быть в прошлом!
Связка успешно изменена
Добавление id %s
Изменение основного uid на %s
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index f603663e8..8aa10943d 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -639,12 +639,14 @@
Actual key fingerprint does not match the expected one!
No key ID. This is an internal error, please file a bug report!
Internal error, integrity check failed!
+ No master certificate found to modify!
Bad primary user id specified!
Bad user id for revocation specified!
Revoked user ids cannot be primary!
Expiry time cannot be "same as before" on subkey creation. This is a programming error, please file a bug report!
PGP internal exception!
Signature exception!
+ Modifying master certifications
Changing passphrase
Replacing certificate of previous primary user id
Generating new certificate for new primary user id
@@ -652,7 +654,7 @@
Tried to operate on missing subkey %s!
Generating new %1$s bit %2$s subkey
New subkey ID: %s
- Expiry date cannot be in the past!
+ Expiry date cannot be in the past!
Revoking subkey %s
Keyring successfully modified
Adding user id %s
From de0d95432e40b9ed436c3509364ba49d2e487723 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Sat, 16 Aug 2014 06:40:03 +0200
Subject: [PATCH 037/142] typed expected failures and a couple minor things
---
.../keychain/pgp/PgpKeyOperationTest.java | 71 ++++++++++++-------
.../keychain/pgp/PgpKeyOperation.java | 6 +-
.../service/OperationResultParcel.java | 5 +-
.../src/main/res/values-cs/strings.xml | 1 -
.../src/main/res/values-de/strings.xml | 1 -
.../src/main/res/values-es/strings.xml | 3 +-
.../src/main/res/values-fr/strings.xml | 3 +-
.../src/main/res/values-it/strings.xml | 3 +-
.../src/main/res/values-ja/strings.xml | 3 +-
.../src/main/res/values-nl/strings.xml | 1 -
.../src/main/res/values-pl/strings.xml | 1 -
.../src/main/res/values-ru/strings.xml | 1 -
.../src/main/res/values-sl/strings.xml | 1 -
.../src/main/res/values-uk/strings.xml | 1 -
OpenKeychain/src/main/res/values/strings.xml | 4 +-
15 files changed, 56 insertions(+), 49 deletions(-)
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index c46e3ee15..88cf260fb 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -19,6 +19,7 @@ import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
+import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
@@ -238,7 +239,7 @@ public class PgpKeyOperationTest {
parcel.mFingerprint = ring.getFingerprint();
assertModifyFailure("keyring modification with bad master key id should fail",
- ring, parcel);
+ ring, parcel, LogType.MSG_MF_ERROR_KEYID);
}
{
@@ -248,7 +249,7 @@ public class PgpKeyOperationTest {
parcel.mFingerprint = ring.getFingerprint();
assertModifyFailure("keyring modification with null master key id should fail",
- ring, parcel);
+ ring, parcel, LogType.MSG_MF_ERROR_KEYID);
}
{
@@ -259,7 +260,7 @@ public class PgpKeyOperationTest {
parcel.mFingerprint[5] += 1;
assertModifyFailure("keyring modification with bad fingerprint should fail",
- ring, parcel);
+ ring, parcel, LogType.MSG_MF_ERROR_FINGERPRINT);
}
{
@@ -268,7 +269,7 @@ public class PgpKeyOperationTest {
parcel.mFingerprint = null;
assertModifyFailure("keyring modification with null fingerprint should fail",
- ring, parcel);
+ ring, parcel, LogType.MSG_MF_ERROR_FINGERPRINT);
}
{
@@ -278,7 +279,7 @@ public class PgpKeyOperationTest {
}
assertModifyFailure("keyring modification with bad passphrase should fail",
- ring, parcel, badphrase);
+ ring, parcel, badphrase, LogType.MSG_MF_UNLOCK_ERROR);
}
}
@@ -331,7 +332,8 @@ public class PgpKeyOperationTest {
parcel.reset();
parcel.mAddSubKeys.add(new SubkeyAdd(
PublicKeyAlgorithmTags.RSA_GENERAL, new Random().nextInt(512), KeyFlags.SIGN_DATA, 0L));
- assertModifyFailure("creating a subkey with keysize < 512 should fail", ring, parcel);
+ assertModifyFailure("creating a subkey with keysize < 512 should fail", ring, parcel,
+ LogType.MSG_CR_ERROR_KEYSIZE_512);
}
@@ -339,7 +341,8 @@ public class PgpKeyOperationTest {
parcel.reset();
parcel.mAddSubKeys.add(new SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA,
new Date().getTime()/1000-10));
- assertModifyFailure("creating subkey with past expiry date should fail", ring, parcel);
+ assertModifyFailure("creating subkey with past expiry date should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_PAST_EXPIRY);
}
}
@@ -436,14 +439,16 @@ public class PgpKeyOperationTest {
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, new Date().getTime()/1000-10));
- assertModifyFailure("setting subkey expiry to a past date should fail", ring, parcel);
+ assertModifyFailure("setting subkey expiry to a past date should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_PAST_EXPIRY);
}
{ // modifying nonexistent subkey should fail
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(123, null, null));
- assertModifyFailure("modifying non-existent subkey should fail", ring, parcel);
+ assertModifyFailure("modifying non-existent subkey should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_SUBKEY_MISSING);
}
}
@@ -529,21 +534,24 @@ public class PgpKeyOperationTest {
parcel.mRevokeUserIds.add("pink");
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, KeyFlags.CERTIFY_OTHER, null));
- assertModifyFailure("master key modification with all user ids revoked should fail", ring, parcel);
+ assertModifyFailure("master key modification with all user ids revoked should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_MASTER_NONE);
}
{ // any flag not including CERTIFY_OTHER should fail
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, KeyFlags.SIGN_DATA, null));
- assertModifyFailure("setting master key flags without certify should fail", ring, parcel);
+ assertModifyFailure("setting master key flags without certify should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_NO_CERTIFY);
}
{ // a past expiry should fail
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, new Date().getTime()/1000-10));
- assertModifyFailure("setting subkey expiry to a past date should fail", ring, parcel);
+ assertModifyFailure("setting subkey expiry to a past date should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_PAST_EXPIRY);
}
}
@@ -663,7 +671,8 @@ public class PgpKeyOperationTest {
parcel.reset();
parcel.mChangePrimaryUserId = uid;
- assertModifyFailure("setting primary user id to a revoked user id should fail", modified, parcel);
+ assertModifyFailure("setting primary user id to a revoked user id should fail", modified, parcel,
+ LogType.MSG_MF_ERROR_REVOKED_PRIMARY);
}
@@ -705,7 +714,8 @@ public class PgpKeyOperationTest {
parcel.reset();
parcel.mRevokeUserIds.add("nonexistent");
- assertModifyFailure("revocation of nonexistent user id should fail", modified, parcel);
+ assertModifyFailure("revocation of nonexistent user id should fail", modified, parcel,
+ LogType.MSG_MF_ERROR_NOEXIST_REVOKE);
}
}
@@ -715,7 +725,8 @@ public class PgpKeyOperationTest {
{
parcel.mAddUserIds.add("");
- assertModifyFailure("adding an empty user id should fail", ring, parcel);
+ assertModifyFailure("adding an empty user id should fail", ring, parcel,
+ LogType.MSG_MF_UID_ERROR_EMPTY);
}
parcel.reset();
@@ -784,7 +795,7 @@ public class PgpKeyOperationTest {
}
assertModifyFailure("changing primary user id to a non-existent one should fail",
- ring, parcel);
+ ring, parcel, LogType.MSG_MF_ERROR_NOEXIST_PRIMARY);
}
// check for revoked primary user id already done in revoke test
@@ -878,17 +889,7 @@ public class PgpKeyOperationTest {
}
private void assertModifyFailure(String reason, UncachedKeyRing ring,
- SaveKeyringParcel parcel, String passphrase) throws Exception {
-
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, passphrase);
-
- Assert.assertFalse(reason, result.success());
- Assert.assertNull(reason, result.getRing());
-
- }
-
- private void assertModifyFailure(String reason, UncachedKeyRing ring, SaveKeyringParcel parcel)
+ SaveKeyringParcel parcel, String passphrase, LogType expected)
throws Exception {
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
@@ -896,6 +897,22 @@ public class PgpKeyOperationTest {
Assert.assertFalse(reason, result.success());
Assert.assertNull(reason, result.getRing());
+ Assert.assertTrue(reason + "(with correct error)",
+ result.getLog().containsType(expected));
+
+ }
+
+ private void assertModifyFailure(String reason, UncachedKeyRing ring, SaveKeyringParcel parcel,
+ LogType expected)
+ throws Exception {
+
+ CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
+ EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, passphrase);
+
+ Assert.assertFalse(reason, result.success());
+ Assert.assertNull(reason, result.getRing());
+ Assert.assertTrue(reason + "(with correct error)",
+ result.getLog().containsType(expected));
}
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 710bd42c6..3fcabf636 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -557,7 +557,7 @@ public class PgpKeyOperation {
PGPSecretKey sKey = sKR.getSecretKey(change.mKeyId);
if (sKey == null) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_MISSING,
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_SUBKEY_MISSING,
indent + 1, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
@@ -638,7 +638,7 @@ public class PgpKeyOperation {
PGPSecretKey sKey = sKR.getSecretKey(revocation);
if (sKey == null) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_MISSING,
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_SUBKEY_MISSING,
indent+1, PgpKeyHelper.convertKeyIdToHex(revocation));
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
@@ -813,7 +813,7 @@ public class PgpKeyOperation {
if (!ok) {
// might happen, theoretically, if there is a key with no uid..
- log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_MASTER_NONE, indent);
return null;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index 138283b81..8e7dcd4aa 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -359,20 +359,21 @@ public class OperationResultParcel implements Parcelable {
MSG_MF_ERROR_FINGERPRINT (R.string.msg_mf_error_fingerprint),
MSG_MF_ERROR_KEYID (R.string.msg_mf_error_keyid),
MSG_MF_ERROR_INTEGRITY (R.string.msg_mf_error_integrity),
+ MSG_MF_ERROR_MASTER_NONE(R.string.msg_mf_error_master_none),
MSG_MF_ERROR_NO_CERTIFY (R.string.msg_cr_error_no_certify),
MSG_MF_ERROR_NOEXIST_PRIMARY (R.string.msg_mf_error_noexist_primary),
MSG_MF_ERROR_NOEXIST_REVOKE (R.string.msg_mf_error_noexist_revoke),
MSG_MF_ERROR_NULL_EXPIRY (R.string.msg_mf_error_null_expiry),
MSG_MF_ERROR_PAST_EXPIRY(R.string.msg_mf_error_past_expiry),
- MSG_MF_ERROR_REVOKED_PRIMARY (R.string.msg_mf_error_revoked_primary),
MSG_MF_ERROR_PGP (R.string.msg_mf_error_pgp),
+ MSG_MF_ERROR_REVOKED_PRIMARY (R.string.msg_mf_error_revoked_primary),
MSG_MF_ERROR_SIG (R.string.msg_mf_error_sig),
+ MSG_MF_ERROR_SUBKEY_MISSING(R.string.msg_mf_error_subkey_missing),
MSG_MF_MASTER (R.string.msg_mf_master),
MSG_MF_PASSPHRASE (R.string.msg_mf_passphrase),
MSG_MF_PRIMARY_REPLACE_OLD (R.string.msg_mf_primary_replace_old),
MSG_MF_PRIMARY_NEW (R.string.msg_mf_primary_new),
MSG_MF_SUBKEY_CHANGE (R.string.msg_mf_subkey_change),
- MSG_MF_SUBKEY_MISSING (R.string.msg_mf_subkey_missing),
MSG_MF_SUBKEY_NEW_ID (R.string.msg_mf_subkey_new_id),
MSG_MF_SUBKEY_NEW (R.string.msg_mf_subkey_new),
MSG_MF_SUBKEY_REVOKE (R.string.msg_mf_subkey_revoke),
diff --git a/OpenKeychain/src/main/res/values-cs/strings.xml b/OpenKeychain/src/main/res/values-cs/strings.xml
index dd4d41650..c9e7875d8 100644
--- a/OpenKeychain/src/main/res/values-cs/strings.xml
+++ b/OpenKeychain/src/main/res/values-cs/strings.xml
@@ -62,7 +62,6 @@
Cache hesel
Komprimovat zprávu
Komprimovat soubor
- Vynutit staré OpenPGPv3 podpisy
ID klíče
Vytvořeno
Expirace
diff --git a/OpenKeychain/src/main/res/values-de/strings.xml b/OpenKeychain/src/main/res/values-de/strings.xml
index 74282fd29..18e6cf585 100644
--- a/OpenKeychain/src/main/res/values-de/strings.xml
+++ b/OpenKeychain/src/main/res/values-de/strings.xml
@@ -94,7 +94,6 @@
Passwort-Cache
Nachrichten-Komprimierung
Datei-Komprimierung
- Erzwinge alte OpenPGPv3-Signaturen
Schlüsselserver
Schlüssel-ID
Erstellungsdatum
diff --git a/OpenKeychain/src/main/res/values-es/strings.xml b/OpenKeychain/src/main/res/values-es/strings.xml
index 0bd3a48c5..1770ec896 100644
--- a/OpenKeychain/src/main/res/values-es/strings.xml
+++ b/OpenKeychain/src/main/res/values-es/strings.xml
@@ -97,7 +97,6 @@
Caché de frase de contraseña
Compresión de mensaje
Compresión de archivo
- Forzar firmas OpenPGPv3 antiguas
Servidores de claves
ID de clave
Creación
@@ -585,7 +584,7 @@
Reemplazando certificado de la anterior identidad de usuario primaria
Generando nuevo certificado para nueva identidad de usuario primaria
Modificando subclave %s
- ¡Intentó operar sobre una subclave ausente %s!
+ ¡Intentó operar sobre una subclave ausente %s!
Generando nueva subclave %2$s de %1$s bits
Nueva identidad de subclave: %s
¡La fecha de expiración no puede ser del pasado!
diff --git a/OpenKeychain/src/main/res/values-fr/strings.xml b/OpenKeychain/src/main/res/values-fr/strings.xml
index 3f570d144..3b356fd18 100644
--- a/OpenKeychain/src/main/res/values-fr/strings.xml
+++ b/OpenKeychain/src/main/res/values-fr/strings.xml
@@ -97,7 +97,6 @@
Cache de la phrase de passe
Compression des messages
Compression des fichiers
- Forcer les anciennes signatures OpenPGP v3
Serveurs de clefs
ID de le clef
Création
@@ -585,7 +584,7 @@
Remplacement du certificat de l\'ID d\'utilisateur principal précédent
Génération d\'un nouveau certificat pour le nouvel ID d\'utilisateur principal
Modification de la sous-clef %s
- Une action a été tentée sur la sous-clef manquante %s !
+ Une action a été tentée sur la sous-clef manquante %s !
Génération d\'une nouvelle sous-clef %2$s de %1$s bit
ID de la nouvelle sous-clef : %s
La date d\'expiration ne peut pas être dans le passé !
diff --git a/OpenKeychain/src/main/res/values-it/strings.xml b/OpenKeychain/src/main/res/values-it/strings.xml
index 590532d4d..33bb4ce9d 100644
--- a/OpenKeychain/src/main/res/values-it/strings.xml
+++ b/OpenKeychain/src/main/res/values-it/strings.xml
@@ -77,7 +77,6 @@
Cache Frase di Accesso
Compressione Messaggio
Compressione File
- Forza vecchie Firme OpenPGPv3
Server Chiavi
ID Chiave
Creazione
@@ -525,7 +524,7 @@
Sostituzione certificato del ID utente primario precedente
Generazione di un nuovo certificato per il nuovo ID utente primario
Modifica sottochiave %s
- Tentativo di operare su sottochiave mancante %s!
+ Tentativo di operare su sottochiave mancante %s!
Generazione nuovi %1$s bit %2$s sottochiave
Nuovo ID sottochiave: %s
La data di scadenza non può essere passata!
diff --git a/OpenKeychain/src/main/res/values-ja/strings.xml b/OpenKeychain/src/main/res/values-ja/strings.xml
index 6794deba9..deb7715e1 100644
--- a/OpenKeychain/src/main/res/values-ja/strings.xml
+++ b/OpenKeychain/src/main/res/values-ja/strings.xml
@@ -97,7 +97,6 @@
パスフレーズキャッシュ
メッセージの圧縮
ファイルの圧縮
- 強制的に古いOpenPGPV3形式の署名にする
鍵サーバ
鍵ID
生成
@@ -571,7 +570,7 @@
以前の主ユーザIDで証明を入れ替え中
新しい主ユーザIDで新しい証明を生成中
副鍵 %s を変更中
- 遺失した副鍵 %s の操作をしようとした!
+ 遺失した副鍵 %s の操作をしようとした!
新しい %1$s ビットの %2$s 副鍵の生成中
新しい副鍵 ID: %s
期限切れ日を過去にはできません!
diff --git a/OpenKeychain/src/main/res/values-nl/strings.xml b/OpenKeychain/src/main/res/values-nl/strings.xml
index f225e204a..a49a51671 100644
--- a/OpenKeychain/src/main/res/values-nl/strings.xml
+++ b/OpenKeychain/src/main/res/values-nl/strings.xml
@@ -71,7 +71,6 @@
Wachtwoordcache
Berichtcompressie
Bestandscompressie
- Forceer oude OpenPGPv3 Handtekeningen
Sleutelservers
Sleutel-id
Aanmaak
diff --git a/OpenKeychain/src/main/res/values-pl/strings.xml b/OpenKeychain/src/main/res/values-pl/strings.xml
index a4a66e30c..7b12653c6 100644
--- a/OpenKeychain/src/main/res/values-pl/strings.xml
+++ b/OpenKeychain/src/main/res/values-pl/strings.xml
@@ -59,7 +59,6 @@
Bufor haseł
Kompresja wiadomości
Kompresja plików
- Wymuś stare podpisy OpenPGPv3
Serwery kluczy
Identyfikator klucza
Utworzenia
diff --git a/OpenKeychain/src/main/res/values-ru/strings.xml b/OpenKeychain/src/main/res/values-ru/strings.xml
index 2ac766466..1b2aa7dc6 100644
--- a/OpenKeychain/src/main/res/values-ru/strings.xml
+++ b/OpenKeychain/src/main/res/values-ru/strings.xml
@@ -74,7 +74,6 @@
Помнить пароль
Сжатие сообщения
Сжатие файла
- Использовать OpenPGPv3 подписи (устар.)
Серверы ключей
ID ключа
Создан
diff --git a/OpenKeychain/src/main/res/values-sl/strings.xml b/OpenKeychain/src/main/res/values-sl/strings.xml
index 0de5e97ea..e98e207b5 100644
--- a/OpenKeychain/src/main/res/values-sl/strings.xml
+++ b/OpenKeychain/src/main/res/values-sl/strings.xml
@@ -74,7 +74,6 @@
Hranjenje gesla v spominu
Stiskanje sporočil
Stiskanje datotek
- Vsili stare podpise OpenPGPv3
Strežniki
ID ključa
Ustvarjanje
diff --git a/OpenKeychain/src/main/res/values-uk/strings.xml b/OpenKeychain/src/main/res/values-uk/strings.xml
index 7a4c79ddb..401b8ae83 100644
--- a/OpenKeychain/src/main/res/values-uk/strings.xml
+++ b/OpenKeychain/src/main/res/values-uk/strings.xml
@@ -74,7 +74,6 @@
Кеш парольної фрази
Стиснення повідомлення
Стиснення файлу
- Примусово старі підписи OpenPGPv3
Сервери ключів
ІД ключа
Створення
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 8aa10943d..f6c208ca0 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -639,7 +639,7 @@
Actual key fingerprint does not match the expected one!
No key ID. This is an internal error, please file a bug report!
Internal error, integrity check failed!
- No master certificate found to modify!
+ No master certificate found to operate on! (All revoked?)
Bad primary user id specified!
Bad user id for revocation specified!
Revoked user ids cannot be primary!
@@ -651,7 +651,7 @@
Replacing certificate of previous primary user id
Generating new certificate for new primary user id
Modifying subkey %s
- Tried to operate on missing subkey %s!
+ Tried to operate on missing subkey %s!
Generating new %1$s bit %2$s subkey
New subkey ID: %s
Expiry date cannot be in the past!
From 6e84c728011cebe44c3b2ef6c6cacee64098c16a Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Sat, 16 Aug 2014 06:49:46 +0200
Subject: [PATCH 038/142] tests: more expected error types
---
.../keychain/pgp/PgpKeyOperationTest.java | 42 +++++++++++++++----
.../keychain/pgp/PgpKeyOperation.java | 3 +-
2 files changed, 37 insertions(+), 8 deletions(-)
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index 88cf260fb..10a42b80f 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -118,7 +118,8 @@ public class PgpKeyOperationTest {
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- assertFailure("creating ring with < 512 bytes keysize should fail", parcel);
+ assertFailure("creating ring with < 512 bytes keysize should fail", parcel,
+ LogType.MSG_CR_ERROR_KEYSIZE_512);
}
{
@@ -128,7 +129,19 @@ public class PgpKeyOperationTest {
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- assertFailure("creating ring with ElGamal master key should fail", parcel);
+ assertFailure("creating ring with ElGamal master key should fail", parcel,
+ LogType.MSG_CR_ERROR_MASTER_ELGAMAL);
+ }
+
+ {
+ parcel.reset();
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ parcel.mAddUserIds.add("lotus");
+ parcel.mNewPassphrase = passphrase;
+
+ assertFailure("creating master key with null expiry should fail", parcel,
+ LogType.MSG_CR_ERROR_NULL_EXPIRY);
}
{
@@ -138,7 +151,8 @@ public class PgpKeyOperationTest {
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- assertFailure("creating ring with bad algorithm choice should fail", parcel);
+ assertFailure("creating ring with bad algorithm choice should fail", parcel,
+ LogType.MSG_CR_ERROR_UNKNOWN_ALGO);
}
{
@@ -148,7 +162,8 @@ public class PgpKeyOperationTest {
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- assertFailure("creating ring with non-certifying master key should fail", parcel);
+ assertFailure("creating ring with non-certifying master key should fail", parcel,
+ LogType.MSG_CR_ERROR_NO_CERTIFY);
}
{
@@ -157,7 +172,8 @@ public class PgpKeyOperationTest {
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mNewPassphrase = passphrase;
- assertFailure("creating ring without user ids should fail", parcel);
+ assertFailure("creating ring without user ids should fail", parcel,
+ LogType.MSG_CR_ERROR_NO_USER_ID);
}
{
@@ -165,7 +181,8 @@ public class PgpKeyOperationTest {
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- assertFailure("creating ring without subkeys should fail", parcel);
+ assertFailure("creating ring with no master key should fail", parcel,
+ LogType.MSG_CR_ERROR_NO_MASTER);
}
}
@@ -337,6 +354,15 @@ public class PgpKeyOperationTest {
}
+ {
+ parcel.reset();
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+
+ assertModifyFailure("creating master key with null expiry should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_NULL_EXPIRY);
+ }
+
{ // a past expiry should fail
parcel.reset();
parcel.mAddSubKeys.add(new SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA,
@@ -879,12 +905,14 @@ public class PgpKeyOperationTest {
Assert.assertEquals(java.util.Arrays.toString(expected), java.util.Arrays.toString(actual));
}
- private void assertFailure(String reason, SaveKeyringParcel parcel) {
+ private void assertFailure(String reason, SaveKeyringParcel parcel, LogType expected) {
EditKeyResult result = op.createSecretKeyRing(parcel);
Assert.assertFalse(reason, result.success());
Assert.assertNull(reason, result.getRing());
+ Assert.assertTrue(reason + "(with correct error)",
+ result.getLog().containsType(expected));
}
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 3fcabf636..26ad69eb7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -728,8 +728,8 @@ public class PgpKeyOperation {
sKR = PGPSecretKeyRing.copyWithNewPassword(sKR, keyDecryptor, keyEncryptorNew);
}
- // This one must only be thrown by
} catch (IOException e) {
+ Log.e(Constants.TAG, "encountered IOException while modifying key", e);
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_ENCODE, indent+1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
} catch (PGPException e) {
@@ -737,6 +737,7 @@ public class PgpKeyOperation {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PGP, indent+1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
} catch (SignatureException e) {
+ Log.e(Constants.TAG, "encountered SignatureException while modifying key", e);
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_SIG, indent+1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
From 7c7ba217148d0560744fd417c4e76726df3ffec7 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Sat, 16 Aug 2014 07:06:07 +0200
Subject: [PATCH 039/142] tests: add test for master key revocation
---
.../keychain/pgp/PgpKeyOperationTest.java | 25 +++++++++++++++++++
.../keychain/pgp/UncachedKeyRing.java | 3 +--
2 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index 10a42b80f..deec1cf3a 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -582,6 +582,31 @@ public class PgpKeyOperationTest {
}
+ @Test
+ public void testMasterRevoke() throws Exception {
+
+ parcel.reset();
+ parcel.mRevokeSubKeys.add(ring.getMasterKeyId());
+
+ UncachedKeyRing modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB);
+
+ Assert.assertEquals("no extra packets in original", 0, onlyA.size());
+ Assert.assertEquals("exactly one extra packet in modified", 1, onlyB.size());
+
+ Packet p;
+
+ p = new BCPGInputStream(new ByteArrayInputStream(onlyB.get(0).buf)).readPacket();
+ Assert.assertTrue("first new packet must be secret subkey", p instanceof SignaturePacket);
+ Assert.assertEquals("signature type must be subkey binding certificate",
+ PGPSignature.KEY_REVOCATION, ((SignaturePacket) p).getSignatureType());
+ Assert.assertEquals("signature must have been created by master key",
+ ring.getMasterKeyId(), ((SignaturePacket) p).getKeyID());
+
+ Assert.assertTrue("subkey must actually be revoked",
+ modified.getPublicKey().isRevoked());
+
+ }
+
@Test
public void testSubkeyRevoke() throws Exception {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
index 0a59ba9f8..ababd39e0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -271,13 +271,12 @@ public class UncachedKeyRing {
for (PGPSignature zert : new IterableIterator(masterKey.getKeySignatures())) {
int type = zert.getSignatureType();
- // Disregard certifications on user ids, we will deal with those later
+ // These should most definitely not be here...
if (type == PGPSignature.NO_CERTIFICATION
|| type == PGPSignature.DEFAULT_CERTIFICATION
|| type == PGPSignature.CASUAL_CERTIFICATION
|| type == PGPSignature.POSITIVE_CERTIFICATION
|| type == PGPSignature.CERTIFICATION_REVOCATION) {
- // These should not be here...
log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_TYPE_UID, indent);
modified = PGPPublicKey.removeCertification(modified, zert);
badCerts += 1;
From 2497722b48561ac1031f7ed9c0cb0526f694b1b3 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Sat, 16 Aug 2014 07:12:37 +0200
Subject: [PATCH 040/142] fix travis tests (more), minor comment edits
---
.../keychain/pgp/PgpKeyOperationTest.java | 4 ++--
.../keychain/pgp/UncachedKeyringCanonicalizeTest.java | 3 +++
.../keychain/pgp/UncachedKeyringMergeTest.java | 3 +++
.../sufficientlysecure/keychain/pgp/UncachedKeyRing.java | 7 +++----
4 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index deec1cf3a..fef325a1a 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -53,9 +53,9 @@ public class PgpKeyOperationTest {
ArrayList onlyA = new ArrayList();
ArrayList onlyB = new ArrayList();
- @BeforeClass public static void setUpOnce() throws Exception {
+ @BeforeClass
+ public static void setUpOnce() throws Exception {
Security.insertProviderAt(new BouncyCastleProvider(), 1);
-
ShadowLog.stream = System.out;
{
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
index 588dac17b..6e3a9814e 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
@@ -13,6 +13,7 @@ import org.spongycastle.bcpg.PacketTags;
import org.spongycastle.bcpg.UserIDPacket;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSecretKey;
@@ -34,6 +35,7 @@ import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
import java.io.ByteArrayInputStream;
+import java.security.Security;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
@@ -60,6 +62,7 @@ public class UncachedKeyringCanonicalizeTest {
@BeforeClass
public static void setUpOnce() throws Exception {
+ Security.insertProviderAt(new BouncyCastleProvider(), 1);
ShadowLog.stream = System.out;
SaveKeyringParcel parcel = new SaveKeyringParcel();
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
index 603b1e6d1..428206c97 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
@@ -10,6 +10,7 @@ import org.robolectric.shadows.ShadowLog;
import org.spongycastle.bcpg.PacketTags;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.service.OperationResultParcel;
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
@@ -18,6 +19,7 @@ import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
import org.sufficientlysecure.keychain.util.ProgressScaler;
+import java.security.Security;
import java.util.ArrayList;
import java.util.Iterator;
@@ -59,6 +61,7 @@ public class UncachedKeyringMergeTest {
@BeforeClass
public static void setUpOnce() throws Exception {
+ Security.insertProviderAt(new BouncyCastleProvider(), 1);
ShadowLog.stream = System.out;
{
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
index ababd39e0..90abf05f5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -217,8 +217,7 @@ public class UncachedKeyRing {
aos.close();
}
- /** "Canonicalizes" a public key, removing inconsistencies in the process. This variant can be
- * applied to public keyrings only.
+ /** "Canonicalizes" a public key, removing inconsistencies in the process.
*
* More specifically:
* - Remove all non-verifying self-certificates
@@ -235,9 +234,9 @@ public class UncachedKeyRing {
* - If the key is a secret key, remove all certificates by foreign keys
* - If no valid user id remains, log an error and return null
*
- * This operation writes an OperationLog which can be used as part of a OperationResultParcel.
+ * This operation writes an OperationLog which can be used as part of an OperationResultParcel.
*
- * @return A canonicalized key, or null on fatal error
+ * @return A canonicalized key, or null on fatal error (log will include a message in this case)
*
*/
@SuppressWarnings("ConstantConditions")
From 188eeb79c9f2eb536d73efee09a3698750c87dab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Sat, 16 Aug 2014 12:13:30 +0200
Subject: [PATCH 041/142] Fix and simplify in OperationResultParcel
---
.../keychain/service/OperationResults.java | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
index 1c83873be..1fc496082 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
@@ -28,6 +28,7 @@ import com.github.johnpersano.supertoasts.SuperToast;
import com.github.johnpersano.supertoasts.util.OnClickWrapper;
import com.github.johnpersano.supertoasts.util.Style;
+import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
import org.sufficientlysecure.keychain.pgp.KeyRing;
@@ -190,13 +191,13 @@ public abstract class OperationResults {
public static class EditKeyResult extends OperationResultParcel {
private transient UncachedKeyRing mRing;
- public final Long mRingMasterKeyId;
+ public final long mRingMasterKeyId;
public EditKeyResult(int result, OperationLog log,
UncachedKeyRing ring) {
super(result, log);
mRing = ring;
- mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : null;
+ mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : Constants.key.none;
}
public UncachedKeyRing getRing() {
@@ -205,18 +206,13 @@ public abstract class OperationResults {
public EditKeyResult(Parcel source) {
super(source);
- mRingMasterKeyId = source.readInt() != 0 ? source.readLong() : null;
+ mRingMasterKeyId = source.readLong();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
- if (mRingMasterKeyId == null) {
- dest.writeInt(0);
- } else {
- dest.writeInt(1);
- dest.writeLong(mRingMasterKeyId);
- }
+ dest.writeLong(mRingMasterKeyId);
}
public static Creator CREATOR = new Creator() {
@@ -234,12 +230,12 @@ public abstract class OperationResults {
public static class SaveKeyringResult extends OperationResultParcel {
- public final Long mRingMasterKeyId;
+ public final long mRingMasterKeyId;
public SaveKeyringResult(int result, OperationLog log,
CanonicalizedKeyRing ring) {
super(result, log);
- mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : null;
+ mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : Constants.key.none;
}
// Some old key was updated
From 474fc50b80ae57e3434c2d748895eda28d2ef548 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Sat, 16 Aug 2014 12:24:46 +0200
Subject: [PATCH 042/142] Always return a SaveKeyringResult from saving
---
.../keychain/service/KeychainIntentService.java | 7 ++++++-
.../keychain/ui/CreateKeyFinalFragment.java | 4 +---
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index 83ade9b9b..036251cd6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -411,7 +411,12 @@ public class KeychainIntentService extends IntentService
// If the edit operation didn't succeed, exit here
if (!modifyResult.success()) {
- sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, modifyResult);
+ // always return SaveKeyringResult, so create one out of the EditKeyResult
+ SaveKeyringResult saveResult = new SaveKeyringResult(
+ SaveKeyringResult.RESULT_ERROR,
+ modifyResult.getLog(),
+ null);
+ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, saveResult);
return;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
index 3fc9e7f31..461d25928 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
@@ -125,10 +125,9 @@ public class CreateKeyFinalFragment extends Fragment {
Intent intent = new Intent(getActivity(), KeychainIntentService.class);
intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING);
- // Message is received after importing is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
getActivity(),
- getString(R.string.progress_importing),
+ getString(R.string.progress_building_key),
ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
@@ -211,7 +210,6 @@ public class CreateKeyFinalFragment extends Fragment {
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
- // Message is received after uploading is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(),
getString(R.string.progress_uploading), ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) {
From 4d698c896a69148fbae4cccf7528ed9974449482 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Sat, 16 Aug 2014 12:28:49 +0200
Subject: [PATCH 043/142] Fix expiry when adding subkeys
---
.../keychain/ui/CreateKeyFinalFragment.java | 6 +++---
.../org/sufficientlysecure/keychain/ui/EditKeyFragment.java | 1 -
.../keychain/ui/dialog/AddSubkeyDialogFragment.java | 4 ++--
3 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
index 461d25928..22c0f7767 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
@@ -168,9 +168,9 @@ public class CreateKeyFinalFragment extends Fragment {
Bundle data = new Bundle();
SaveKeyringParcel parcel = new SaveKeyringParcel();
- parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 4096, KeyFlags.CERTIFY_OTHER, null));
- parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 4096, KeyFlags.SIGN_DATA, null));
- parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 4096, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, null));
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 4096, KeyFlags.CERTIFY_OTHER, 0L));
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 4096, KeyFlags.SIGN_DATA, 0L));
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 4096, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, 0L));
String userId = KeyRing.createUserId(mName, mEmail, null);
parcel.mAddUserIds.add(userId);
parcel.mChangePrimaryUserId = userId;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
index b18d1626a..409953ad5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
@@ -503,7 +503,6 @@ public class EditKeyFragment extends LoaderFragment implements
private void save(String passphrase) {
Log.d(Constants.TAG, "mSaveKeyringParcel:\n" + mSaveKeyringParcel.toString());
- // Message is received after importing is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
getActivity(),
getString(R.string.progress_saving),
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
index cb31978e9..2b8768596 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
@@ -183,9 +183,9 @@ public class AddSubkeyDialogFragment extends DialogFragment {
flags |= KeyFlags.AUTHENTICATION;
}
- Long expiry;
+ long expiry;
if (mNoExpiryCheckBox.isChecked()) {
- expiry = null;
+ expiry = 0L;
} else {
Calendar selectedCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
//noinspection ResourceType
From c1f9c5e4b5378f6c98f96e85ae82137c93f5009f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Sat, 16 Aug 2014 13:30:13 +0200
Subject: [PATCH 044/142] Fix ElGamal key creation, SUBKEY_BINDING cert must
use algo of master key
---
.../org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 26ad69eb7..ccd83c334 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -933,7 +933,7 @@ public class PgpKeyOperation {
}
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PGPUtil.SHA1)
+ masterPrivateKey.getPublicKeyPacket().getAlgorithm(), PGPUtil.SHA1)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
sGen.init(PGPSignature.SUBKEY_BINDING, masterPrivateKey);
From ccf58a92fa915f948709fffde17f834bb1a88cdd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Sat, 16 Aug 2014 13:42:55 +0200
Subject: [PATCH 045/142] Fix flags UI in add subkey dialog
---
.../ui/adapter/SubkeysAddedAdapter.java | 2 +-
.../ui/dialog/AddSubkeyDialogFragment.java | 47 +++++++++++++++++--
2 files changed, 44 insertions(+), 5 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java
index be2e17c63..7e0027ddc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java
@@ -106,7 +106,7 @@ public class SubkeysAddedAdapter extends ArrayAdapter choices = new ArrayList();
choices.add(new Choice(PublicKeyAlgorithmTags.DSA, getResources().getString(
R.string.dsa)));
- if (!willBeMasterKey) {
+ if (!mWillBeMasterKey) {
choices.add(new Choice(PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, getResources().getString(
R.string.elgamal)));
}
@@ -246,7 +248,7 @@ public class AddSubkeyDialogFragment extends DialogFragment {
mAlgorithmSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
- setKeyLengthSpinnerValuesForAlgorithm(((Choice) parent.getSelectedItem()).getId());
+ updateUiForAlgorithm(((Choice) parent.getSelectedItem()).getId());
setCustomKeyVisibility();
setOkButtonAvailability(alertDialog);
@@ -348,7 +350,7 @@ public class AddSubkeyDialogFragment extends DialogFragment {
}
}
- private void setKeyLengthSpinnerValuesForAlgorithm(int algorithmId) {
+ private void updateUiForAlgorithm(int algorithmId) {
final ArrayAdapter keySizeAdapter = (ArrayAdapter) mKeySizeSpinner.getAdapter();
final Object selectedItem = mKeySizeSpinner.getSelectedItem();
keySizeAdapter.clear();
@@ -356,14 +358,51 @@ public class AddSubkeyDialogFragment extends DialogFragment {
case PublicKeyAlgorithmTags.RSA_GENERAL:
replaceArrayAdapterContent(keySizeAdapter, R.array.rsa_key_size_spinner_values);
mCustomKeyInfoTextView.setText(getResources().getString(R.string.key_size_custom_info_rsa));
+ // allowed flags:
+ mFlagSign.setEnabled(true);
+ mFlagEncrypt.setEnabled(true);
+ mFlagAuthenticate.setEnabled(true);
+
+ if (mWillBeMasterKey) {
+ mFlagCertify.setEnabled(true);
+
+ mFlagCertify.setChecked(true);
+ mFlagSign.setChecked(false);
+ mFlagEncrypt.setChecked(false);
+ } else {
+ mFlagCertify.setEnabled(false);
+
+ mFlagCertify.setChecked(false);
+ mFlagSign.setChecked(true);
+ mFlagEncrypt.setChecked(true);
+ }
+ mFlagAuthenticate.setChecked(false);
break;
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
replaceArrayAdapterContent(keySizeAdapter, R.array.elgamal_key_size_spinner_values);
mCustomKeyInfoTextView.setText(""); // ElGamal does not support custom key length
+ // allowed flags:
+ mFlagCertify.setChecked(false);
+ mFlagCertify.setEnabled(false);
+ mFlagSign.setChecked(false);
+ mFlagSign.setEnabled(false);
+ mFlagEncrypt.setChecked(true);
+ mFlagEncrypt.setEnabled(true);
+ mFlagAuthenticate.setChecked(false);
+ mFlagAuthenticate.setEnabled(false);
break;
case PublicKeyAlgorithmTags.DSA:
replaceArrayAdapterContent(keySizeAdapter, R.array.dsa_key_size_spinner_values);
mCustomKeyInfoTextView.setText(getResources().getString(R.string.key_size_custom_info_dsa));
+ // allowed flags:
+ mFlagCertify.setChecked(false);
+ mFlagCertify.setEnabled(false);
+ mFlagSign.setChecked(true);
+ mFlagSign.setEnabled(true);
+ mFlagEncrypt.setChecked(false);
+ mFlagEncrypt.setEnabled(false);
+ mFlagAuthenticate.setChecked(false);
+ mFlagAuthenticate.setEnabled(false);
break;
}
keySizeAdapter.notifyDataSetChanged();
From f2069020029f138ae02a7a9f2697f5737f568268 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Sat, 16 Aug 2014 16:17:46 +0200
Subject: [PATCH 046/142] Fixing date picker issues
---
.../ui/dialog/AddSubkeyDialogFragment.java | 5 +-
.../EditSubkeyExpiryDialogFragment.java | 64 +++++++++++++------
2 files changed, 47 insertions(+), 22 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
index c35afd4fe..56c004f97 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
@@ -189,10 +189,13 @@ public class AddSubkeyDialogFragment extends DialogFragment {
if (mNoExpiryCheckBox.isChecked()) {
expiry = 0L;
} else {
- Calendar selectedCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ Calendar selectedCal = Calendar.getInstance(TimeZone.getDefault());
//noinspection ResourceType
selectedCal.set(mExpiryDatePicker.getYear(),
mExpiryDatePicker.getMonth(), mExpiryDatePicker.getDayOfMonth());
+ // date picker uses default time zone, we need to convert to UTC
+ selectedCal.setTimeZone(TimeZone.getTimeZone("UTC"));
+
expiry = selectedCal.getTime().getTime() / 1000;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
index 276ad15fc..fde8a3477 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
@@ -48,7 +48,6 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
public static final String MESSAGE_DATA_EXPIRY_DATE = "expiry_date";
private Messenger mMessenger;
- private Calendar mExpiryCal;
private DatePicker mDatePicker;
@@ -75,15 +74,17 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Activity activity = getActivity();
mMessenger = getArguments().getParcelable(ARG_MESSENGER);
- Date creationDate = new Date(getArguments().getLong(ARG_CREATION_DATE) * 1000);
- Date expiryDate = new Date(getArguments().getLong(ARG_EXPIRY_DATE) * 1000);
+ long creationDate = getArguments().getLong(ARG_CREATION_DATE);
+ long expiryDate = getArguments().getLong(ARG_EXPIRY_DATE);
Calendar creationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- creationCal.setTime(creationDate);
- mExpiryCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- mExpiryCal.setTime(expiryDate);
+ creationCal.setTime(new Date(creationDate * 1000));
+ final Calendar expiryCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ expiryCal.setTime(new Date(expiryDate * 1000));
- Log.d(Constants.TAG, "onCreateDialog");
+ // date picker works with default time zone, we need to convert from UTC to default timezone
+ creationCal.setTimeZone(TimeZone.getDefault());
+ expiryCal.setTimeZone(TimeZone.getDefault());
// Explicitly not using DatePickerDialog here!
// DatePickerDialog is difficult to customize and has many problems (see old git versions)
@@ -97,15 +98,40 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
mDatePicker = (DatePicker) view.findViewById(R.id.edit_subkey_expiry_date_picker);
+ // set default date
+ if (expiryDate == 0L) {
+ // if key has no expiry, set it to creation date +1 day
+
+ Calendar creationCalPlusOne = (Calendar) creationCal.clone();
+ creationCalPlusOne.add(Calendar.DAY_OF_MONTH, 1);
+ mDatePicker.init(
+ creationCalPlusOne.get(Calendar.YEAR),
+ creationCalPlusOne.get(Calendar.MONTH),
+ creationCalPlusOne.get(Calendar.DAY_OF_MONTH),
+ null
+ );
+ } else {
+ // set date picker to current expiry date +1 day
+
+ Calendar expiryCalPlusOne = (Calendar) expiryCal.clone();
+ expiryCalPlusOne.add(Calendar.DAY_OF_MONTH, 1);
+ mDatePicker.init(
+ expiryCalPlusOne.get(Calendar.YEAR),
+ expiryCalPlusOne.get(Calendar.MONTH),
+ expiryCalPlusOne.get(Calendar.DAY_OF_MONTH),
+ null
+ );
+ }
+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
// will crash with IllegalArgumentException if we set a min date
- // that is not before expiry
- if (creationCal.before(mExpiryCal)) {
+ // that is before creation date
+ if (expiryDate == 0L || creationCal.before(expiryCal)) {
mDatePicker.setMinDate(creationCal.getTime().getTime()
+ DateUtils.DAY_IN_MILLIS);
} else {
- // when creation date isn't available
- mDatePicker.setMinDate(mExpiryCal.getTime().getTime()
+ // set min to expiry date
+ mDatePicker.setMinDate(expiryCal.getTime().getTime()
+ DateUtils.DAY_IN_MILLIS);
}
}
@@ -115,19 +141,15 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
public void onClick(DialogInterface dialog, int id) {
dismiss();
- Calendar selectedCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ Calendar selectedCal = Calendar.getInstance(TimeZone.getDefault());
//noinspection ResourceType
selectedCal.set(mDatePicker.getYear(), mDatePicker.getMonth(), mDatePicker.getDayOfMonth());
+ // date picker uses default time zone, we need to convert to UTC
+ selectedCal.setTimeZone(TimeZone.getTimeZone("UTC"));
- if (mExpiryCal != null) {
- long numDays = (selectedCal.getTimeInMillis() / 86400000)
- - (mExpiryCal.getTimeInMillis() / 86400000);
- if (numDays > 0) {
- Bundle data = new Bundle();
- data.putSerializable(MESSAGE_DATA_EXPIRY_DATE, selectedCal.getTime().getTime() / 1000);
- sendMessageToHandler(MESSAGE_NEW_EXPIRY_DATE, data);
- }
- } else {
+ long numDays = (selectedCal.getTimeInMillis() / 86400000)
+ - (expiryCal.getTimeInMillis() / 86400000);
+ if (numDays > 0) {
Bundle data = new Bundle();
data.putSerializable(MESSAGE_DATA_EXPIRY_DATE, selectedCal.getTime().getTime() / 1000);
sendMessageToHandler(MESSAGE_NEW_EXPIRY_DATE, data);
From 62b7d2d7d80f7ecfa17d6a8484fecae21f42a92d Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Sat, 16 Aug 2014 19:30:32 +0200
Subject: [PATCH 047/142] fix small log format string mistake for adding
subkeys
closes #768
---
.../org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
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 ccd83c334..5da8c5f6a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -658,7 +658,8 @@ public class PgpKeyOperation {
progress(R.string.progress_modify_subkeyadd, (i-1) * (100 / saveParcel.mAddSubKeys.size()));
SaveKeyringParcel.SubkeyAdd add = saveParcel.mAddSubKeys.get(i);
- log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent);
+ log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent, add.mKeysize,
+ PgpKeyHelper.getAlgorithmInfo(add.mAlgorithm) );
if (add.mExpiry == null) {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NULL_EXPIRY, indent +1);
From e38f6a2a46c5b246f2f6a60d497f85f95c10908a Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Sat, 16 Aug 2014 19:45:14 +0200
Subject: [PATCH 048/142] use correct algorithm for signatures (actually fix
heterogeneous subkeys)
---
.../keychain/pgp/PgpKeyOperationTest.java | 4 ++--
.../sufficientlysecure/keychain/pgp/PgpKeyOperation.java | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index fef325a1a..00bbafed1 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -74,9 +74,9 @@ public class PgpKeyOperationTest {
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
+ PublicKeyAlgorithmTags.DSA, 1024, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, 0L));
+ PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, 1024, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("twi");
parcel.mAddUserIds.add("pink");
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 5da8c5f6a..222c47215 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -828,7 +828,7 @@ public class PgpKeyOperation {
int flags, long expiry)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PGPUtil.SHA1)
+ masterPrivateKey.getPublicKeyPacket().getAlgorithm(), PGPUtil.SHA1)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
@@ -855,7 +855,7 @@ public class PgpKeyOperation {
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PGPUtil.SHA1)
+ masterPrivateKey.getPublicKeyPacket().getAlgorithm(), PGPUtil.SHA1)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
@@ -869,7 +869,7 @@ public class PgpKeyOperation {
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, PGPPublicKey pKey)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PGPUtil.SHA1)
+ masterPublicKey.getAlgorithm(), PGPUtil.SHA1)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
@@ -934,7 +934,7 @@ public class PgpKeyOperation {
}
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPrivateKey.getPublicKeyPacket().getAlgorithm(), PGPUtil.SHA1)
+ masterPublicKey.getAlgorithm(), PGPUtil.SHA1)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
sGen.init(PGPSignature.SUBKEY_BINDING, masterPrivateKey);
From c00343d516f1afc2d4e062d30eba07689fc3092a Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Sat, 16 Aug 2014 21:04:43 +0200
Subject: [PATCH 049/142] modify*Key: improve handling of passphrase
modification (add tests, too)
---
.../keychain/pgp/PgpKeyOperationTest.java | 100 +++++++++++++++---
.../keychain/pgp/PgpKeyOperation.java | 50 ++++++++-
.../service/OperationResultParcel.java | 4 +
OpenKeychain/src/main/res/values/strings.xml | 6 +-
4 files changed, 143 insertions(+), 17 deletions(-)
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index 00bbafed1..964512617 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -45,7 +45,7 @@ import java.util.Random;
public class PgpKeyOperationTest {
static UncachedKeyRing staticRing;
- static String passphrase;
+ final static String passphrase = genPassphrase();
UncachedKeyRing ring;
PgpKeyOperation op;
@@ -58,18 +58,6 @@ public class PgpKeyOperationTest {
Security.insertProviderAt(new BouncyCastleProvider(), 1);
ShadowLog.stream = System.out;
- {
- String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789!@#$%^&*()-_=";
- Random r = new Random();
- StringBuilder passbuilder = new StringBuilder();
- // 20% chance for an empty passphrase
- for(int i = 0, j = r.nextInt(10) > 2 ? r.nextInt(20) : 0; i < j; i++) {
- passbuilder.append(chars.charAt(r.nextInt(chars.length())));
- }
- passphrase = passbuilder.toString();
- System.out.println("Passphrase is '" + passphrase + "'");
- }
-
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
@@ -853,12 +841,79 @@ public class PgpKeyOperationTest {
}
+ @Test
+ public void testPassphraseChange() throws Exception {
+
+ // change passphrase to empty
+ parcel.mNewPassphrase = "";
+ UncachedKeyRing modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB);
+
+ Assert.assertEquals("exactly three packets should have been modified (the secret keys)",
+ 3, onlyB.size());
+
+ // remember secret key packet with no passphrase for later
+ RawPacket sKeyNoPassphrase = onlyB.get(1);
+ Assert.assertEquals("extracted packet should be a secret subkey",
+ PacketTags.SECRET_SUBKEY, sKeyNoPassphrase.tag);
+
+ // modify keyring, change to non-empty passphrase
+ String otherPassphrase = genPassphrase(true);
+ parcel.mNewPassphrase = otherPassphrase;
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB, "");
+
+ RawPacket sKeyWithPassphrase = onlyB.get(1);
+ Assert.assertEquals("extracted packet should be a secret subkey",
+ PacketTags.SECRET_SUBKEY, sKeyNoPassphrase.tag);
+
+ String otherPassphrase2 = genPassphrase(true);
+ parcel.mNewPassphrase = otherPassphrase2;
+ {
+ // if we replace a secret key with one without passphrase
+ modified = KeyringTestingHelper.removePacket(modified, sKeyNoPassphrase.position);
+ modified = KeyringTestingHelper.injectPacket(modified, sKeyNoPassphrase.buf, sKeyNoPassphrase.position);
+
+ // we should still be able to modify it (and change its passphrase) without errors
+ PgpKeyOperation op = new PgpKeyOperation(null);
+ CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(modified.getEncoded(), false, 0);
+ EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, otherPassphrase);
+ Assert.assertTrue("key modification must succeed", result.success());
+ Assert.assertFalse("log must not contain a warning",
+ result.getLog().containsWarnings());
+ Assert.assertTrue("log must contain an empty passphrase retry notice",
+ result.getLog().containsType(LogType.MSG_MF_PASSPHRASE_EMPTY_RETRY));
+ modified = result.getRing();
+ }
+
+ {
+ // if we add one subkey with a different passphrase, that should produce a warning but also work
+ modified = KeyringTestingHelper.removePacket(modified, sKeyWithPassphrase.position);
+ modified = KeyringTestingHelper.injectPacket(modified, sKeyWithPassphrase.buf, sKeyWithPassphrase.position);
+
+ PgpKeyOperation op = new PgpKeyOperation(null);
+ CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(modified.getEncoded(), false, 0);
+ EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, otherPassphrase2);
+ Assert.assertTrue("key modification must succeed", result.success());
+ Assert.assertTrue("log must contain a warning",
+ result.getLog().containsWarnings());
+ Assert.assertTrue("log must contain a failed passphrase change warning",
+ result.getLog().containsType(LogType.MSG_MF_PASSPHRASE_FAIL));
+ }
+
+ }
private static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
UncachedKeyRing ring,
ArrayList onlyA,
ArrayList onlyB) {
- return applyModificationWithChecks(parcel, ring, onlyA, onlyB, true, true);
+ return applyModificationWithChecks(parcel, ring, onlyA, onlyB, passphrase, true, true);
+ }
+
+ private static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
+ UncachedKeyRing ring,
+ ArrayList onlyA,
+ ArrayList onlyB,
+ String passphrase) {
+ return applyModificationWithChecks(parcel, ring, onlyA, onlyB, passphrase, true, true);
}
// applies a parcel modification while running some integrity checks
@@ -866,6 +921,7 @@ public class PgpKeyOperationTest {
UncachedKeyRing ring,
ArrayList onlyA,
ArrayList onlyB,
+ String passphrase,
boolean canonicalize,
boolean constantCanonicalize) {
@@ -980,4 +1036,20 @@ public class PgpKeyOperationTest {
}
+ private static String genPassphrase() {
+ return genPassphrase(false);
+ }
+
+ private static String genPassphrase(boolean noEmpty) {
+ String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789!@#$%^&*()-_=";
+ Random r = new Random();
+ StringBuilder passbuilder = new StringBuilder();
+ // 20% chance for an empty passphrase
+ for(int i = 0, j = noEmpty || r.nextInt(10) > 2 ? r.nextInt(20)+1 : 0; i < j; i++) {
+ passbuilder.append(chars.charAt(r.nextInt(chars.length())));
+ }
+ System.out.println("Generated passphrase: '" + passbuilder.toString() + "'");
+ return passbuilder.toString();
+ }
+
}
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 222c47215..cdd2eacc0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -698,7 +698,7 @@ public class PgpKeyOperation {
// Build key encrypter and decrypter based on passphrase
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
PGPEncryptedData.CAST5, sha1Calc)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
sKey = new PGPSecretKey(keyPair.getPrivateKey(), pKey,
sha1Calc, false, keyEncryptor);
@@ -716,6 +716,8 @@ public class PgpKeyOperation {
if (saveParcel.mNewPassphrase != null) {
progress(R.string.progress_modify_passphrase, 90);
log.add(LogLevel.INFO, LogType.MSG_MF_PASSPHRASE, indent);
+ indent += 1;
+
PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build()
.get(HashAlgorithmTags.SHA1);
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
@@ -726,7 +728,51 @@ public class PgpKeyOperation {
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
saveParcel.mNewPassphrase.toCharArray());
- sKR = PGPSecretKeyRing.copyWithNewPassword(sKR, keyDecryptor, keyEncryptorNew);
+ // noinspection unchecked
+ for (PGPSecretKey sKey : new IterableIterator(sKR.getSecretKeys())) {
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_PASSPHRASE_KEY, indent,
+ PgpKeyHelper.convertKeyIdToHex(sKey.getKeyID()));
+
+ boolean ok = false;
+
+ try {
+ // try to set new passphrase
+ sKey = PGPSecretKey.copyWithNewPassword(sKey, keyDecryptor, keyEncryptorNew);
+ ok = true;
+ } catch (PGPException e) {
+
+ // if this is the master key, error!
+ if (sKey.getKeyID() == masterPublicKey.getKeyID()) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PASSPHRASE_MASTER, indent+1);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+
+ // being in here means decrypt failed, likely due to a bad passphrase try
+ // again with an empty passphrase, maybe we can salvage this
+ try {
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_PASSPHRASE_EMPTY_RETRY, indent+1);
+ PBESecretKeyDecryptor emptyDecryptor =
+ new JcePBESecretKeyDecryptorBuilder().setProvider(
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
+ sKey = PGPSecretKey.copyWithNewPassword(sKey, emptyDecryptor, keyEncryptorNew);
+ ok = true;
+ } catch (PGPException e2) {
+ // non-fatal but not ok, handled below
+ }
+ }
+
+ if (!ok) {
+ // for a subkey, it's merely a warning
+ log.add(LogLevel.WARN, LogType.MSG_MF_PASSPHRASE_FAIL, indent+1,
+ PgpKeyHelper.convertKeyIdToHex(sKey.getKeyID()));
+ continue;
+ }
+
+ sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);
+
+ }
+
+ indent -= 1;
}
} catch (IOException e) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index 8e7dcd4aa..26fe63550 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -364,6 +364,7 @@ public class OperationResultParcel implements Parcelable {
MSG_MF_ERROR_NOEXIST_PRIMARY (R.string.msg_mf_error_noexist_primary),
MSG_MF_ERROR_NOEXIST_REVOKE (R.string.msg_mf_error_noexist_revoke),
MSG_MF_ERROR_NULL_EXPIRY (R.string.msg_mf_error_null_expiry),
+ MSG_MF_ERROR_PASSPHRASE_MASTER(R.string.msg_mf_error_passphrase_master),
MSG_MF_ERROR_PAST_EXPIRY(R.string.msg_mf_error_past_expiry),
MSG_MF_ERROR_PGP (R.string.msg_mf_error_pgp),
MSG_MF_ERROR_REVOKED_PRIMARY (R.string.msg_mf_error_revoked_primary),
@@ -371,6 +372,9 @@ public class OperationResultParcel implements Parcelable {
MSG_MF_ERROR_SUBKEY_MISSING(R.string.msg_mf_error_subkey_missing),
MSG_MF_MASTER (R.string.msg_mf_master),
MSG_MF_PASSPHRASE (R.string.msg_mf_passphrase),
+ MSG_MF_PASSPHRASE_KEY (R.string.msg_mf_passphrase_key),
+ MSG_MF_PASSPHRASE_EMPTY_RETRY (R.string.msg_mf_passphrase_empty_retry),
+ MSG_MF_PASSPHRASE_FAIL (R.string.msg_mf_passphrase_fail),
MSG_MF_PRIMARY_REPLACE_OLD (R.string.msg_mf_primary_replace_old),
MSG_MF_PRIMARY_NEW (R.string.msg_mf_primary_new),
MSG_MF_SUBKEY_CHANGE (R.string.msg_mf_subkey_change),
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index f6c208ca0..5259336ec 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -644,10 +644,14 @@
Bad user id for revocation specified!
Revoked user ids cannot be primary!
Expiry time cannot be "same as before" on subkey creation. This is a programming error, please file a bug report!
+ Fatal error decrypting master key! This is likely a programming error, please file a bug report!
PGP internal exception!
Signature exception!
Modifying master certifications
- Changing passphrase
+ Changing passphrase for keyring…
+ Changing passphrase for subkey %s
+ Setting new passphrase failed, trying again with empty old passphrase
+ Passphrase for subkey could not be changed! (Does it have a different one from the other keys?)
Replacing certificate of previous primary user id
Generating new certificate for new primary user id
Modifying subkey %s
From aa625d4fbf8cf97de5a81675d55e4ac004ef5f11 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Sun, 17 Aug 2014 00:49:14 +0200
Subject: [PATCH 050/142] parametrize FileImportCache for filename
---
.../keychain/util/FileImportCacheTest.java | 2 +-
.../keychain/service/KeychainIntentService.java | 2 +-
.../keychain/ui/ImportKeysActivity.java | 3 ++-
.../keychain/util/FileImportCache.java | 11 ++++++-----
4 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java
index b5708b46f..11bc05c9e 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java
@@ -25,7 +25,7 @@ public class FileImportCacheTest {
@Test
public void testInputOutput() throws Exception {
- FileImportCache cache = new FileImportCache(Robolectric.application);
+ FileImportCache cache = new FileImportCache(Robolectric.application, "test.pcl");
ArrayList list = new ArrayList();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index 036251cd6..0505a6339 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -477,7 +477,7 @@ public class KeychainIntentService extends IntentService
} else {
// get entries from cached file
FileImportCache cache =
- new FileImportCache(this);
+ new FileImportCache(this, "key_import.pcl");
entries = cache.readCacheIntoList();
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
index 255290de3..7df180296 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
@@ -503,7 +503,8 @@ public class ImportKeysActivity extends ActionBarActivity {
// to prevent Java Binder problems on heavy imports
// read FileImportCache for more info.
try {
- FileImportCache cache = new FileImportCache(this);
+ FileImportCache cache =
+ new FileImportCache(this, "key_import.pcl");
cache.writeCache(selectedEntries);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java
index 5a4bf5311..35833adc6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java
@@ -46,10 +46,11 @@ public class FileImportCache {
private Context mContext;
- private static final String FILENAME = "key_import.pcl";
+ private final String mFilename;
- public FileImportCache(Context context) {
- this.mContext = context;
+ public FileImportCache(Context context, String filename) {
+ mContext = context;
+ mFilename = filename;
}
public void writeCache(ArrayList selectedEntries) throws IOException {
@@ -64,7 +65,7 @@ public class FileImportCache {
throw new IOException("cache dir is null!");
}
- File tempFile = new File(mContext.getCacheDir(), FILENAME);
+ File tempFile = new File(mContext.getCacheDir(), mFilename);
DataOutputStream oos = new DataOutputStream(new FileOutputStream(tempFile));
@@ -98,7 +99,7 @@ public class FileImportCache {
throw new IOException("cache dir is null!");
}
- final File tempFile = new File(cacheDir, FILENAME);
+ final File tempFile = new File(cacheDir, mFilename);
final DataInputStream ois = new DataInputStream(new FileInputStream(tempFile));
return new Iterator() {
From 14290c3ce9a1cfcf2b45c47198ba44737bd5d996 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Sun, 17 Aug 2014 03:29:03 +0200
Subject: [PATCH 051/142] consolidate: working implementation, lacking ui
---
.../keychain/pgp/PgpImportExport.java | 21 +-
.../keychain/provider/KeychainDatabase.java | 2 +-
.../keychain/provider/ProviderHelper.java | 181 +++++++++++++++++-
.../service/KeychainIntentService.java | 15 ++
.../service/OperationResultParcel.java | 9 +
.../keychain/service/OperationResults.java | 8 +
.../keychain/ui/KeyListActivity.java | 60 ++++++
OpenKeychain/src/main/res/menu/key_list.xml | 6 +
OpenKeychain/src/main/res/values/strings.xml | 15 ++
9 files changed, 302 insertions(+), 15 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
index f14eacda2..fd37112a5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
@@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult;
import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult;
+import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressScaler;
@@ -43,6 +44,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
public class PgpImportExport {
@@ -60,10 +62,14 @@ public class PgpImportExport {
private ProviderHelper mProviderHelper;
public PgpImportExport(Context context, Progressable progressable) {
+ this(context, new ProviderHelper(context), progressable);
+ }
+
+ public PgpImportExport(Context context, ProviderHelper providerHelper, Progressable progressable) {
super();
this.mContext = context;
this.mProgressable = progressable;
- this.mProviderHelper = new ProviderHelper(context);
+ this.mProviderHelper = providerHelper;
}
public PgpImportExport(Context context,
@@ -124,11 +130,14 @@ public class PgpImportExport {
/** Imports keys from given data. If keyIds is given only those are imported */
public ImportKeyResult importKeyRings(List entries) {
+ return importKeyRings(entries.iterator(), entries.size());
+ }
+ public ImportKeyResult importKeyRings(Iterator entries, int num) {
updateProgress(R.string.progress_importing, 0, 100);
// If there aren't even any keys, do nothing here.
- if (entries == null || entries.size() == 0) {
+ if (entries == null || !entries.hasNext()) {
return new ImportKeyResult(
ImportKeyResult.RESULT_FAIL_NOTHING, mProviderHelper.getLog(), 0, 0, 0);
}
@@ -136,8 +145,8 @@ public class PgpImportExport {
int newKeys = 0, oldKeys = 0, badKeys = 0;
int position = 0;
- int progSteps = 100 / entries.size();
- for (ParcelableKeyRing entry : entries) {
+ double progSteps = 100.0 / num;
+ for (ParcelableKeyRing entry : new IterableIterator(entries)) {
try {
UncachedKeyRing key = UncachedKeyRing.decodeFromData(entry.getBytes());
@@ -157,10 +166,10 @@ public class PgpImportExport {
SaveKeyringResult result;
if (key.isSecret()) {
result = mProviderHelper.saveSecretKeyRing(key,
- new ProgressScaler(mProgressable, position, (position+1)*progSteps, 100));
+ new ProgressScaler(mProgressable, (int)(position*progSteps), (int)((position+1)*progSteps), 100));
} else {
result = mProviderHelper.savePublicKeyRing(key,
- new ProgressScaler(mProgressable, position, (position+1)*progSteps, 100));
+ new ProgressScaler(mProgressable, (int)(position*progSteps), (int)((position+1)*progSteps), 100));
}
if (!result.success()) {
badKeys += 1;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
index 1536c21fc..560eb9ef8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
@@ -349,7 +349,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
copy(in, out);
}
- // for test cases ONLY!!
+ // DANGEROUS
public void clearDatabase() {
getWritableDatabase().execSQL("delete from " + Tables.KEY_RINGS_PUBLIC);
}
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 ac6ea015a..3594ded51 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -28,12 +28,14 @@ import android.os.RemoteException;
import android.support.v4.util.LongSparseArray;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.NullProgressable;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
+import org.sufficientlysecure.keychain.pgp.PgpImportExport;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
@@ -51,9 +53,12 @@ import org.sufficientlysecure.keychain.remote.AppSettings;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
+import org.sufficientlysecure.keychain.service.OperationResults.ConsolidateResult;
import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult;
+import org.sufficientlysecure.keychain.util.FileImportCache;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.ProgressScaler;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -63,6 +68,7 @@ import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -97,14 +103,6 @@ public class ProviderHelper {
mIndent = indent;
}
- public void resetLog() {
- if(mLog != null) {
- // Start a new log (leaving the old one intact)
- mLog = new OperationLog();
- mIndent = 0;
- }
- }
-
public OperationLog getLog() {
return mLog;
}
@@ -825,6 +823,173 @@ public class ProviderHelper {
}
+ public ConsolidateResult consolidateDatabase(Progressable progress) {
+
+ // 1a. fetch all secret keyrings into a cache file
+ int numSecrets, numPublics;
+
+ log(LogLevel.START, LogType.MSG_CON, mIndent);
+ mIndent += 1;
+
+ try {
+
+ log(LogLevel.DEBUG, LogType.MSG_CON_SAVE_SECRET, mIndent);
+ mIndent += 1;
+
+ final Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[] {
+ KeyRings.PRIVKEY_DATA, KeyRings.FINGERPRINT, KeyRings.HAS_ANY_SECRET
+ }, KeyRings.HAS_ANY_SECRET + " = 1", null, null);
+
+ if (cursor == null || !cursor.moveToFirst()) {
+ return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
+ }
+
+ numSecrets = cursor.getCount();
+
+ FileImportCache cache =
+ new FileImportCache(mContext, "consolidate_secret.pcl");
+ cache.writeCache(new Iterator() {
+ ParcelableKeyRing ring;
+
+ @Override
+ public boolean hasNext() {
+ if (ring != null) {
+ return true;
+ }
+ if (cursor.isAfterLast()) {
+ return false;
+ }
+ ring = new ParcelableKeyRing(cursor.getBlob(0),
+ PgpKeyHelper.convertFingerprintToHex(cursor.getBlob(1)));
+ cursor.moveToNext();
+ return true;
+ }
+
+ @Override
+ public ParcelableKeyRing next() {
+ try {
+ return ring;
+ } finally {
+ ring = null;
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ });
+
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "error saving secret");
+ return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
+ } finally {
+ mIndent -= 1;
+ }
+
+ // 1b. fetch all public keyrings into a cache file
+ try {
+
+ log(LogLevel.DEBUG, LogType.MSG_CON_SAVE_PUBLIC, mIndent);
+ mIndent += 1;
+
+ final Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[] {
+ KeyRings.PUBKEY_DATA, KeyRings.FINGERPRINT
+ }, null, null, null);
+
+ if (cursor == null || !cursor.moveToFirst()) {
+ return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
+ }
+
+ numPublics = cursor.getCount();
+
+ FileImportCache cache =
+ new FileImportCache(mContext, "consolidate_public.pcl");
+ cache.writeCache(new Iterator() {
+ ParcelableKeyRing ring;
+
+ @Override
+ public boolean hasNext() {
+ if (ring != null) {
+ return true;
+ }
+ if (cursor.isAfterLast()) {
+ return false;
+ }
+ ring = new ParcelableKeyRing(cursor.getBlob(0),
+ PgpKeyHelper.convertFingerprintToHex(cursor.getBlob(1)));
+ cursor.moveToNext();
+ return true;
+ }
+
+ @Override
+ public ParcelableKeyRing next() {
+ try {
+ return ring;
+ } finally {
+ ring = null;
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ });
+
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "error saving public");
+ return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
+ } finally {
+ mIndent -= 1;
+ }
+
+ // 2. wipe database (IT'S DANGEROUS)
+ log(LogLevel.DEBUG, LogType.MSG_CON_DB_CLEAR, mIndent);
+ new KeychainDatabase(mContext).clearDatabase();
+
+ // 3. Re-Import secret keyrings from cache
+ try {
+ log(LogLevel.DEBUG, LogType.MSG_CON_REIMPORT_SECRET, mIndent, numSecrets);
+ mIndent += 1;
+
+ FileImportCache cache =
+ new FileImportCache(mContext, "consolidate_secret.pcl");
+ new PgpImportExport(mContext, this, new ProgressScaler(progress, 10, 25, 100))
+ .importKeyRings(cache.readCache(), numSecrets);
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "error importing secret");
+ return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
+ } finally {
+ mIndent -= 1;
+ }
+
+ // 3. Re-Import public keyrings from cache
+ try {
+ log(LogLevel.DEBUG, LogType.MSG_CON_REIMPORT_PUBLIC, mIndent, numPublics);
+ mIndent += 1;
+
+ FileImportCache cache =
+ new FileImportCache(mContext, "consolidate_public.pcl");
+ new PgpImportExport(mContext, this, new ProgressScaler(progress, 25, 99, 100))
+ .importKeyRings(cache.readCache(), numPublics);
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "error importing public");
+ return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
+ } finally {
+ mIndent -= 1;
+ }
+
+ progress.setProgress(100, 100);
+ log(LogLevel.OK, LogType.MSG_CON_SUCCESS, mIndent);
+ mIndent -= 1;
+
+ return new ConsolidateResult(ConsolidateResult.RESULT_OK, mLog);
+
+ }
+
/**
* Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing
*/
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index 0505a6339..9f5650df6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -52,6 +52,7 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.OperationResults.ConsolidateResult;
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult;
import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult;
@@ -103,6 +104,8 @@ public class KeychainIntentService extends IntentService
public static final String ACTION_CERTIFY_KEYRING = Constants.INTENT_PREFIX + "SIGN_KEYRING";
+ public static final String ACTION_CONSOLIDATE = Constants.INTENT_PREFIX + "CONSOLIDATE";
+
/* keys for data bundle */
// encrypt, decrypt, import export
@@ -142,6 +145,7 @@ public class KeychainIntentService extends IntentService
// import key
public static final String IMPORT_KEY_LIST = "import_key_list";
+ public static final String IMPORT_KEY_FILE = "import_key_file";
// export key
public static final String EXPORT_OUTPUT_STREAM = "export_output_stream";
@@ -179,6 +183,8 @@ public class KeychainIntentService extends IntentService
public static final String RESULT_IMPORT = "result";
+ public static final String RESULT_CONSOLIDATE = "consolidate_result";
+
Messenger mMessenger;
private boolean mIsCanceled;
@@ -662,7 +668,16 @@ public class KeychainIntentService extends IntentService
} catch (Exception e) {
sendErrorToHandler(e);
}
+
+ } else if (ACTION_CONSOLIDATE.equals(action)) {
+ ConsolidateResult result = new ProviderHelper(this).consolidateDatabase(this);
+
+ Bundle resultData = new Bundle();
+ resultData.putParcelable(RESULT_CONSOLIDATE, result);
+
+ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
}
+
}
private void sendErrorToHandler(Exception e) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index 26fe63550..c601ec57e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -388,6 +388,15 @@ public class OperationResultParcel implements Parcelable {
MSG_MF_UID_ERROR_EMPTY (R.string.msg_mf_uid_error_empty),
MSG_MF_UNLOCK_ERROR (R.string.msg_mf_unlock_error),
MSG_MF_UNLOCK (R.string.msg_mf_unlock),
+
+ // consolidate
+ MSG_CON (R.string.msg_con),
+ MSG_CON_SAVE_SECRET (R.string.msg_con_save_secret),
+ MSG_CON_SAVE_PUBLIC (R.string.msg_con_save_public),
+ MSG_CON_DB_CLEAR (R.string.msg_con_db_clear),
+ MSG_CON_REIMPORT_SECRET (R.plurals.msg_con_reimport_secret),
+ MSG_CON_REIMPORT_PUBLIC (R.plurals.msg_con_reimport_public),
+ MSG_CON_SUCCESS (R.string.msg_con_success),
;
private final int mMsgId;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
index 1fc496082..878f6ca47 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
@@ -272,4 +272,12 @@ public abstract class OperationResults {
};
}
+ public static class ConsolidateResult extends OperationResultParcel {
+
+ public ConsolidateResult(int result, OperationLog log) {
+ super(result, log);
+ }
+
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
index 7a6e78a7d..9d9462648 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
@@ -17,8 +17,11 @@
package org.sufficientlysecure.keychain.ui;
+import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
+import android.os.Message;
+import android.os.Messenger;
import android.view.Menu;
import android.view.MenuItem;
@@ -28,6 +31,9 @@ import org.sufficientlysecure.keychain.helper.ExportHelper;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
+import org.sufficientlysecure.keychain.service.KeychainIntentService;
+import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
+import org.sufficientlysecure.keychain.service.OperationResults.ConsolidateResult;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Notify;
@@ -63,6 +69,7 @@ public class KeyListActivity extends DrawerActivity {
getMenuInflater().inflate(R.menu.key_list, menu);
if (Constants.DEBUG) {
+ menu.findItem(R.id.menu_key_list_debug_cons).setVisible(true);
menu.findItem(R.id.menu_key_list_debug_read).setVisible(true);
menu.findItem(R.id.menu_key_list_debug_write).setVisible(true);
menu.findItem(R.id.menu_key_list_debug_first_time).setVisible(true);
@@ -92,6 +99,10 @@ public class KeyListActivity extends DrawerActivity {
mExportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE, true);
return true;
+ case R.id.menu_key_list_debug_cons:
+ consolidate();
+ return true;
+
case R.id.menu_key_list_debug_read:
try {
KeychainDatabase.debugBackup(this, true);
@@ -136,4 +147,53 @@ public class KeyListActivity extends DrawerActivity {
startActivity(intent);
}
+ private void consolidate() {
+ // Message is received after importing is done in KeychainIntentService
+ KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
+ this,
+ getString(R.string.progress_importing),
+ ProgressDialog.STYLE_HORIZONTAL) {
+ public void handleMessage(Message message) {
+ // handle messages by standard KeychainIntentServiceHandler first
+ super.handleMessage(message);
+
+ if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
+ // get returned data bundle
+ Bundle returnData = message.getData();
+ if (returnData == null) {
+ return;
+ }
+ final ConsolidateResult result =
+ returnData.getParcelable(KeychainIntentService.RESULT_CONSOLIDATE);
+ if (result == null) {
+ return;
+ }
+
+ result.createNotify(KeyListActivity.this).show();
+ }
+ }
+ };
+
+ // Send all information needed to service to import key in other thread
+ Intent intent = new Intent(this, KeychainIntentService.class);
+
+ intent.setAction(KeychainIntentService.ACTION_CONSOLIDATE);
+
+ // fill values for this action
+ Bundle data = new Bundle();
+
+ intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(saveHandler);
+ intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
+
+ // show progress dialog
+ saveHandler.showProgressDialog(this);
+
+ // start service with intent
+ startService(intent);
+
+ }
+
}
diff --git a/OpenKeychain/src/main/res/menu/key_list.xml b/OpenKeychain/src/main/res/menu/key_list.xml
index 056dd5986..6e571243d 100644
--- a/OpenKeychain/src/main/res/menu/key_list.xml
+++ b/OpenKeychain/src/main/res/menu/key_list.xml
@@ -31,6 +31,12 @@
app:showAsAction="never"
android:title="@string/menu_import_existing_key" />
+
+
- Error unlocking keyring!
Unlocking keyring
+
+ Consolidating database
+ Saving secret keyrings
+ Saving public keyrings
+ Clearing database
+
+ - Reimporting one secret key
+ - Reimporting %d secret keys
+
+
+ - Reimporting one public key
+ - Reimporting %d public keys
+
+ Successfully consolidated database
+
Click to clear cached passphrases
OpenKeychain has cached %d passphrases
From 3cc57a092a7ba59390b2d892db028cc1990cdbd1 Mon Sep 17 00:00:00 2001
From: mar-v-in
Date: Sun, 17 Aug 2014 11:07:34 +0200
Subject: [PATCH 052/142] Remove NoSwipeWrapContentViewPager
---
.../keychain/ui/EncryptActivity.java | 41 ++++++------
.../widget/NoSwipeWrapContentViewPager.java | 62 -------------------
.../src/main/res/layout/encrypt_content.xml | 8 +--
3 files changed, 23 insertions(+), 88 deletions(-)
delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NoSwipeWrapContentViewPager.java
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
index 7e08f6b7c..59a433af3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
@@ -73,16 +73,13 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
public static final String EXTRA_ENCRYPTION_KEY_IDS = "encryption_key_ids";
// view
- ViewPager mViewPagerMode;
- //PagerTabStrip mPagerTabStripMode;
- PagerTabStripAdapter mTabsAdapterMode;
- ViewPager mViewPagerContent;
- PagerTabStrip mPagerTabStripContent;
- PagerTabStripAdapter mTabsAdapterContent;
+ private int mCurrentMode = PAGER_MODE_ASYMMETRIC;
+ private ViewPager mViewPagerContent;
+ private PagerTabStrip mPagerTabStripContent;
+ private PagerTabStripAdapter mTabsAdapterContent;
// tabs
- int mSwitchToMode = PAGER_MODE_ASYMMETRIC;
- int mSwitchToContent = PAGER_CONTENT_MESSAGE;
+ private int mSwitchToContent = PAGER_CONTENT_MESSAGE;
private static final int PAGER_MODE_ASYMMETRIC = 0;
private static final int PAGER_MODE_SYMMETRIC = 1;
@@ -102,7 +99,7 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
private String mMessage = "";
public boolean isModeSymmetric() {
- return PAGER_MODE_SYMMETRIC == mViewPagerMode.getCurrentItem();
+ return PAGER_MODE_SYMMETRIC == mCurrentMode;
}
public boolean isContentMessage() {
@@ -474,13 +471,9 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
}
private void initView() {
- mViewPagerMode = (ViewPager) findViewById(R.id.encrypt_pager_mode);
- //mPagerTabStripMode = (PagerTabStrip) findViewById(R.id.encrypt_pager_tab_strip_mode);
mViewPagerContent = (ViewPager) findViewById(R.id.encrypt_pager_content);
mPagerTabStripContent = (PagerTabStrip) findViewById(R.id.encrypt_pager_tab_strip_content);
- mTabsAdapterMode = new PagerTabStripAdapter(this);
- mViewPagerMode.setAdapter(mTabsAdapterMode);
mTabsAdapterContent = new PagerTabStripAdapter(this);
mViewPagerContent.setAdapter(mTabsAdapterContent);
}
@@ -502,10 +495,7 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
// Handle intent actions
handleActions(getIntent());
-
- mTabsAdapterMode.addTab(EncryptAsymmetricFragment.class, null, getString(R.string.label_asymmetric));
- mTabsAdapterMode.addTab(EncryptSymmetricFragment.class, null, getString(R.string.label_symmetric));
- mViewPagerMode.setCurrentItem(mSwitchToMode);
+ updateModeFragment();
mTabsAdapterContent.addTab(EncryptMessageFragment.class, null, getString(R.string.label_message));
mTabsAdapterContent.addTab(EncryptFileFragment.class, null, getString(R.string.label_files));
@@ -521,6 +511,16 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
return super.onCreateOptionsMenu(menu);
}
+ private void updateModeFragment() {
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.encrypt_pager_mode,
+ mCurrentMode == PAGER_MODE_SYMMETRIC
+ ? new EncryptSymmetricFragment()
+ : new EncryptAsymmetricFragment())
+ .commitAllowingStateLoss();
+ getSupportFragmentManager().executePendingTransactions();
+ }
+
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.isCheckable()) {
@@ -528,9 +528,8 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
}
switch (item.getItemId()) {
case R.id.check_use_symmetric:
- mSwitchToMode = item.isChecked() ? PAGER_MODE_SYMMETRIC : PAGER_MODE_ASYMMETRIC;
-
- mViewPagerMode.setCurrentItem(mSwitchToMode);
+ mCurrentMode = item.isChecked() ? PAGER_MODE_SYMMETRIC : PAGER_MODE_ASYMMETRIC;
+ updateModeFragment();
notifyUpdate();
break;
case R.id.check_use_armor:
@@ -604,7 +603,7 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
mEncryptionKeyIds = extras.getLongArray(EXTRA_ENCRYPTION_KEY_IDS);
// preselect keys given by intent
- mSwitchToMode = PAGER_MODE_ASYMMETRIC;
+ mCurrentMode = PAGER_MODE_ASYMMETRIC;
/**
* Main Actions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NoSwipeWrapContentViewPager.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NoSwipeWrapContentViewPager.java
deleted file mode 100644
index a48d2a026..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NoSwipeWrapContentViewPager.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2014 Dominik Schürmann
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.sufficientlysecure.keychain.ui.widget;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-
-public class NoSwipeWrapContentViewPager extends android.support.v4.view.ViewPager {
- public NoSwipeWrapContentViewPager(Context context) {
- super(context);
- }
-
- public NoSwipeWrapContentViewPager(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-
- int height;
- View child = getChildAt(getCurrentItem());
- if (child != null) {
- child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- height = child.getMeasuredHeight();
- } else {
- height = 0;
- }
-
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
-
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent arg0) {
- // Never allow swiping to switch between pages
- return false;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- // Never allow swiping to switch between pages
- return false;
- }
-}
diff --git a/OpenKeychain/src/main/res/layout/encrypt_content.xml b/OpenKeychain/src/main/res/layout/encrypt_content.xml
index e5edc6657..d029e7b83 100644
--- a/OpenKeychain/src/main/res/layout/encrypt_content.xml
+++ b/OpenKeychain/src/main/res/layout/encrypt_content.xml
@@ -9,13 +9,11 @@
-
-
-
+ android:layout_height="wrap_content"
+ android:orientation="vertical" />
Date: Sun, 17 Aug 2014 11:31:41 +0200
Subject: [PATCH 053/142] Work-around rendering bug when switching back to
asymmetric with multiple recipients selected
---
.../keychain/ui/EncryptAsymmetricFragment.java | 16 ++--------------
1 file changed, 2 insertions(+), 14 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
index 748cbca14..a508472d6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
@@ -18,30 +18,16 @@
package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
-import android.support.v4.app.LoaderManager;
-import android.support.v4.content.CursorLoader;
-import android.support.v4.content.Loader;
-import android.support.v4.widget.CursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.Spinner;
-import android.widget.SpinnerAdapter;
-import android.widget.TextView;
import com.tokenautocomplete.TokenCompleteTextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.KeyRing;
-import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
@@ -169,6 +155,8 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi
Log.e(Constants.TAG, "key not found!", e);
}
}
+ // This is to work-around a rendering bug in TokenCompleteTextView
+ mEncryptKeyView.requestFocus();
updateEncryptionKeys();
}
}
From 3e7ce0008fde176634980a31f61052052698ff93 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Mon, 18 Aug 2014 11:02:41 +0200
Subject: [PATCH 054/142] Fixes for expiry UI
---
.../keychain/ui/EditKeyFragment.java | 4 +-
.../keychain/ui/adapter/SubkeysAdapter.java | 8 +-
.../ui/adapter/SubkeysAddedAdapter.java | 8 +-
.../ui/dialog/AddSubkeyDialogFragment.java | 5 +-
.../EditSubkeyExpiryDialogFragment.java | 141 ++++++++++--------
.../res/layout/edit_subkey_expiry_dialog.xml | 10 ++
6 files changed, 109 insertions(+), 67 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
index 409953ad5..f2d6d4c13 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
@@ -406,10 +406,10 @@ public class EditKeyFragment extends LoaderFragment implements
@Override
public void handleMessage(Message message) {
switch (message.what) {
- case EditSubkeyExpiryDialogFragment.MESSAGE_NEW_EXPIRY_DATE:
+ case EditSubkeyExpiryDialogFragment.MESSAGE_NEW_EXPIRY:
mSaveKeyringParcel.getOrCreateSubkeyChange(keyId).mExpiry =
(Long) message.getData().getSerializable(
- EditSubkeyExpiryDialogFragment.MESSAGE_DATA_EXPIRY_DATE);
+ EditSubkeyExpiryDialogFragment.MESSAGE_DATA_EXPIRY);
break;
}
getLoaderManager().getLoader(LOADER_ID_SUBKEYS).forceLoad();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
index 6df84a056..9958b33a1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
@@ -35,7 +35,9 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import java.util.Calendar;
import java.util.Date;
+import java.util.TimeZone;
public class SubkeysAdapter extends CursorAdapter {
private LayoutInflater mInflater;
@@ -198,9 +200,13 @@ public class SubkeysAdapter extends CursorAdapter {
boolean isExpired;
if (expiryDate != null) {
isExpired = expiryDate.before(new Date());
+ Calendar expiryCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ expiryCal.setTime(expiryDate);
+ // convert from UTC to time zone of device
+ expiryCal.setTimeZone(TimeZone.getDefault());
vKeyExpiry.setText(context.getString(R.string.label_expiry) + ": "
- + DateFormat.getDateFormat(context).format(expiryDate));
+ + DateFormat.getDateFormat(context).format(expiryCal.getTime()));
} else {
isExpired = false;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java
index 7e0027ddc..a1dfeb10c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java
@@ -33,8 +33,10 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import java.util.Calendar;
import java.util.Date;
import java.util.List;
+import java.util.TimeZone;
public class SubkeysAddedAdapter extends ArrayAdapter {
private LayoutInflater mInflater;
@@ -108,9 +110,13 @@ public class SubkeysAddedAdapter extends ArrayAdapter= android.os.Build.VERSION_CODES.HONEYCOMB) {
- mExpiryDatePicker.setMinDate(new Date().getTime() + DateUtils.DAY_IN_MILLIS);
+ // date picker works based on default time zone
+ Calendar minDateCal = Calendar.getInstance(TimeZone.getDefault());
+ minDateCal.add(Calendar.DAY_OF_YEAR, 1); // at least one day after creation (today)
+ mExpiryDatePicker.setMinDate(minDateCal.getTime().getTime());
}
ArrayList choices = new ArrayList();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
index fde8a3477..f46e253c0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
@@ -25,9 +25,10 @@ import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v4.app.DialogFragment;
-import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
import android.widget.DatePicker;
import org.sufficientlysecure.keychain.Constants;
@@ -40,17 +41,15 @@ import java.util.TimeZone;
public class EditSubkeyExpiryDialogFragment extends DialogFragment {
private static final String ARG_MESSENGER = "messenger";
- private static final String ARG_CREATION_DATE = "creation_date";
- private static final String ARG_EXPIRY_DATE = "expiry_date";
+ private static final String ARG_CREATION = "creation";
+ private static final String ARG_EXPIRY = "expiry";
- public static final int MESSAGE_NEW_EXPIRY_DATE = 1;
+ public static final int MESSAGE_NEW_EXPIRY = 1;
public static final int MESSAGE_CANCEL = 2;
- public static final String MESSAGE_DATA_EXPIRY_DATE = "expiry_date";
+ public static final String MESSAGE_DATA_EXPIRY = "expiry";
private Messenger mMessenger;
- private DatePicker mDatePicker;
-
/**
* Creates new instance of this dialog fragment
*/
@@ -59,8 +58,8 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
EditSubkeyExpiryDialogFragment frag = new EditSubkeyExpiryDialogFragment();
Bundle args = new Bundle();
args.putParcelable(ARG_MESSENGER, messenger);
- args.putSerializable(ARG_CREATION_DATE, creationDate);
- args.putSerializable(ARG_EXPIRY_DATE, expiryDate);
+ args.putSerializable(ARG_CREATION, creationDate);
+ args.putSerializable(ARG_EXPIRY, expiryDate);
frag.setArguments(args);
@@ -74,13 +73,13 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Activity activity = getActivity();
mMessenger = getArguments().getParcelable(ARG_MESSENGER);
- long creationDate = getArguments().getLong(ARG_CREATION_DATE);
- long expiryDate = getArguments().getLong(ARG_EXPIRY_DATE);
+ long creation = getArguments().getLong(ARG_CREATION);
+ long expiry = getArguments().getLong(ARG_EXPIRY);
Calendar creationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- creationCal.setTime(new Date(creationDate * 1000));
+ creationCal.setTime(new Date(creation * 1000));
final Calendar expiryCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- expiryCal.setTime(new Date(expiryDate * 1000));
+ expiryCal.setTime(new Date(expiry * 1000));
// date picker works with default time zone, we need to convert from UTC to default timezone
creationCal.setTimeZone(TimeZone.getDefault());
@@ -96,44 +95,64 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
View view = inflater.inflate(R.layout.edit_subkey_expiry_dialog, null);
alert.setView(view);
- mDatePicker = (DatePicker) view.findViewById(R.id.edit_subkey_expiry_date_picker);
+ final CheckBox noExpiry = (CheckBox) view.findViewById(R.id.edit_subkey_expiry_no_expiry);
+ final DatePicker datePicker = (DatePicker) view.findViewById(R.id.edit_subkey_expiry_date_picker);
- // set default date
- if (expiryDate == 0L) {
- // if key has no expiry, set it to creation date +1 day
+ noExpiry.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (isChecked) {
+ datePicker.setVisibility(View.GONE);
+ } else {
+ datePicker.setVisibility(View.VISIBLE);
+ }
+ }
+ });
- Calendar creationCalPlusOne = (Calendar) creationCal.clone();
- creationCalPlusOne.add(Calendar.DAY_OF_MONTH, 1);
- mDatePicker.init(
- creationCalPlusOne.get(Calendar.YEAR),
- creationCalPlusOne.get(Calendar.MONTH),
- creationCalPlusOne.get(Calendar.DAY_OF_MONTH),
- null
- );
+ // init date picker with default selected date
+ if (expiry == 0L) {
+ noExpiry.setChecked(true);
+ datePicker.setVisibility(View.GONE);
+
+ Calendar todayCal = Calendar.getInstance(TimeZone.getDefault());
+ if (creationCal.after(todayCal)) {
+ // Note: This is just for the rare cases where creation is _after_ today
+
+ // set it to creation date +1 day (don't set it to creationCal, it would break crash
+ // datePicker.setMinDate() execution with IllegalArgumentException
+ Calendar creationCalPlusOne = (Calendar) creationCal.clone();
+ creationCalPlusOne.add(Calendar.DAY_OF_YEAR, 1);
+ datePicker.init(
+ creationCalPlusOne.get(Calendar.YEAR),
+ creationCalPlusOne.get(Calendar.MONTH),
+ creationCalPlusOne.get(Calendar.DAY_OF_MONTH),
+ null
+ );
+
+ } else {
+ // normally, just init with today
+ datePicker.init(
+ todayCal.get(Calendar.YEAR),
+ todayCal.get(Calendar.MONTH),
+ todayCal.get(Calendar.DAY_OF_MONTH),
+ null
+ );
+ }
} else {
- // set date picker to current expiry date +1 day
+ noExpiry.setChecked(false);
+ datePicker.setVisibility(View.VISIBLE);
- Calendar expiryCalPlusOne = (Calendar) expiryCal.clone();
- expiryCalPlusOne.add(Calendar.DAY_OF_MONTH, 1);
- mDatePicker.init(
- expiryCalPlusOne.get(Calendar.YEAR),
- expiryCalPlusOne.get(Calendar.MONTH),
- expiryCalPlusOne.get(Calendar.DAY_OF_MONTH),
+ // set date picker to current expiry
+ datePicker.init(
+ expiryCal.get(Calendar.YEAR),
+ expiryCal.get(Calendar.MONTH),
+ expiryCal.get(Calendar.DAY_OF_MONTH),
null
);
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
- // will crash with IllegalArgumentException if we set a min date
- // that is before creation date
- if (expiryDate == 0L || creationCal.before(expiryCal)) {
- mDatePicker.setMinDate(creationCal.getTime().getTime()
- + DateUtils.DAY_IN_MILLIS);
- } else {
- // set min to expiry date
- mDatePicker.setMinDate(expiryCal.getTime().getTime()
- + DateUtils.DAY_IN_MILLIS);
- }
+ datePicker.setMinDate(creationCal.getTime().getTime());
}
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@@ -141,30 +160,28 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
public void onClick(DialogInterface dialog, int id) {
dismiss();
- Calendar selectedCal = Calendar.getInstance(TimeZone.getDefault());
- //noinspection ResourceType
- selectedCal.set(mDatePicker.getYear(), mDatePicker.getMonth(), mDatePicker.getDayOfMonth());
- // date picker uses default time zone, we need to convert to UTC
- selectedCal.setTimeZone(TimeZone.getTimeZone("UTC"));
+ long expiry;
+ if (noExpiry.isChecked()) {
+ expiry = 0L;
+ } else {
+ Calendar selectedCal = Calendar.getInstance(TimeZone.getDefault());
+ //noinspection ResourceType
+ selectedCal.set(datePicker.getYear(), datePicker.getMonth(), datePicker.getDayOfMonth());
+ // date picker uses default time zone, we need to convert to UTC
+ selectedCal.setTimeZone(TimeZone.getTimeZone("UTC"));
- long numDays = (selectedCal.getTimeInMillis() / 86400000)
- - (expiryCal.getTimeInMillis() / 86400000);
- if (numDays > 0) {
- Bundle data = new Bundle();
- data.putSerializable(MESSAGE_DATA_EXPIRY_DATE, selectedCal.getTime().getTime() / 1000);
- sendMessageToHandler(MESSAGE_NEW_EXPIRY_DATE, data);
+ long numDays = (selectedCal.getTimeInMillis() / 86400000)
+ - (expiryCal.getTimeInMillis() / 86400000);
+ if (numDays <= 0) {
+ Log.e(Constants.TAG, "Should not happen! Expiry num of days <= 0!");
+ throw new RuntimeException();
+ }
+ expiry = selectedCal.getTime().getTime() / 1000;
}
- }
- });
-
- alert.setNeutralButton(R.string.btn_no_date, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dismiss();
Bundle data = new Bundle();
- data.putSerializable(MESSAGE_DATA_EXPIRY_DATE, 0L);
- sendMessageToHandler(MESSAGE_NEW_EXPIRY_DATE, data);
+ data.putSerializable(MESSAGE_DATA_EXPIRY, expiry);
+ sendMessageToHandler(MESSAGE_NEW_EXPIRY, data);
}
});
diff --git a/OpenKeychain/src/main/res/layout/edit_subkey_expiry_dialog.xml b/OpenKeychain/src/main/res/layout/edit_subkey_expiry_dialog.xml
index 062f07863..8a713115e 100644
--- a/OpenKeychain/src/main/res/layout/edit_subkey_expiry_dialog.xml
+++ b/OpenKeychain/src/main/res/layout/edit_subkey_expiry_dialog.xml
@@ -4,6 +4,16 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
+
+
Date: Mon, 18 Aug 2014 11:13:52 +0200
Subject: [PATCH 055/142] Add subkey: at least one flag should be selected!
---
.../ui/dialog/AddSubkeyDialogFragment.java | 127 ++++++++++--------
OpenKeychain/src/main/res/values/strings.xml | 1 +
2 files changed, 75 insertions(+), 53 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
index d5c80d18a..450e6a5f5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
@@ -33,6 +33,7 @@ import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
+import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.DatePicker;
@@ -40,6 +41,7 @@ import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TableRow;
import android.widget.TextView;
+import android.widget.Toast;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
import org.spongycastle.bcpg.sig.KeyFlags;
@@ -167,60 +169,11 @@ public class AddSubkeyDialogFragment extends DialogFragment {
mKeySizeSpinner.setSelection(1); // Default to 4096 for the key length
- dialog.setPositiveButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface di, int id) {
- di.dismiss();
- Choice newKeyAlgorithmChoice = (Choice) mAlgorithmSpinner.getSelectedItem();
- int newKeySize = getProperKeyLength(newKeyAlgorithmChoice.getId(), getSelectedKeyLength());
-
- int flags = 0;
- if (mFlagCertify.isChecked()) {
- flags |= KeyFlags.CERTIFY_OTHER;
- }
- if (mFlagSign.isChecked()) {
- flags |= KeyFlags.SIGN_DATA;
- }
- if (mFlagEncrypt.isChecked()) {
- flags |= KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE;
- }
- if (mFlagAuthenticate.isChecked()) {
- flags |= KeyFlags.AUTHENTICATION;
- }
-
- long expiry;
- if (mNoExpiryCheckBox.isChecked()) {
- expiry = 0L;
- } else {
- Calendar selectedCal = Calendar.getInstance(TimeZone.getDefault());
- //noinspection ResourceType
- selectedCal.set(mExpiryDatePicker.getYear(),
- mExpiryDatePicker.getMonth(), mExpiryDatePicker.getDayOfMonth());
- // date picker uses default time zone, we need to convert to UTC
- selectedCal.setTimeZone(TimeZone.getTimeZone("UTC"));
-
- expiry = selectedCal.getTime().getTime() / 1000;
- }
-
- SaveKeyringParcel.SubkeyAdd newSubkey = new SaveKeyringParcel.SubkeyAdd(
- newKeyAlgorithmChoice.getId(),
- newKeySize,
- flags,
- expiry
- );
- mAlgorithmSelectedListener.onAlgorithmSelected(newSubkey);
- }
- }
- );
-
dialog.setCancelable(true);
- dialog.setNegativeButton(android.R.string.cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface di, int id) {
- di.dismiss();
- }
- }
- );
+
+ // onClickListener are set in onStart() to override default dismiss behaviour
+ dialog.setPositiveButton(android.R.string.ok, null);
+ dialog.setNegativeButton(android.R.string.cancel, null);
final AlertDialog alertDialog = dialog.show();
@@ -268,6 +221,74 @@ public class AddSubkeyDialogFragment extends DialogFragment {
return alertDialog;
}
+ @Override
+ public void onStart() {
+ super.onStart(); //super.onStart() is where dialog.show() is actually called on the underlying dialog, so we have to do it after this point
+ AlertDialog d = (AlertDialog) getDialog();
+ if (d != null) {
+ Button positiveButton = d.getButton(Dialog.BUTTON_POSITIVE);
+ Button negativeButton = d.getButton(Dialog.BUTTON_NEGATIVE);
+ positiveButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (!mFlagCertify.isChecked() && !mFlagSign.isChecked()
+ && !mFlagEncrypt.isChecked() && !mFlagAuthenticate.isChecked()) {
+ Toast.makeText(getActivity(), R.string.edit_key_select_flag, Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ // dismiss only if at least one flag is selected
+ dismiss();
+
+ Choice newKeyAlgorithmChoice = (Choice) mAlgorithmSpinner.getSelectedItem();
+ int newKeySize = getProperKeyLength(newKeyAlgorithmChoice.getId(), getSelectedKeyLength());
+
+ int flags = 0;
+ if (mFlagCertify.isChecked()) {
+ flags |= KeyFlags.CERTIFY_OTHER;
+ }
+ if (mFlagSign.isChecked()) {
+ flags |= KeyFlags.SIGN_DATA;
+ }
+ if (mFlagEncrypt.isChecked()) {
+ flags |= KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE;
+ }
+ if (mFlagAuthenticate.isChecked()) {
+ flags |= KeyFlags.AUTHENTICATION;
+ }
+
+ long expiry;
+ if (mNoExpiryCheckBox.isChecked()) {
+ expiry = 0L;
+ } else {
+ Calendar selectedCal = Calendar.getInstance(TimeZone.getDefault());
+ //noinspection ResourceType
+ selectedCal.set(mExpiryDatePicker.getYear(),
+ mExpiryDatePicker.getMonth(), mExpiryDatePicker.getDayOfMonth());
+ // date picker uses default time zone, we need to convert to UTC
+ selectedCal.setTimeZone(TimeZone.getTimeZone("UTC"));
+
+ expiry = selectedCal.getTime().getTime() / 1000;
+ }
+
+ SaveKeyringParcel.SubkeyAdd newSubkey = new SaveKeyringParcel.SubkeyAdd(
+ newKeyAlgorithmChoice.getId(),
+ newKeySize,
+ flags,
+ expiry
+ );
+ mAlgorithmSelectedListener.onAlgorithmSelected(newSubkey);
+ }
+ });
+ negativeButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ dismiss();
+ }
+ });
+ }
+ }
+
private int getSelectedKeyLength() {
final String selectedItemString = (String) mKeySizeSpinner.getSelectedItem();
final String customLengthString = getResources().getString(R.string.key_size_custom);
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 51053754e..7a4f41969 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -457,6 +457,7 @@
- Revoke Subkey
new
+ Please select at least one flag!
Upload key to keyserver
From 638c29792d38dc48581c22ef4f89ef5780dad0dd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Tue, 19 Aug 2014 09:52:15 +0200
Subject: [PATCH 056/142] Header for certs view
---
.../src/main/res/layout/view_key_activity.xml | 10 ++--
.../res/layout/view_key_certs_fragment.xml | 51 ++++++++++++-------
OpenKeychain/src/main/res/values/strings.xml | 1 +
3 files changed, 39 insertions(+), 23 deletions(-)
diff --git a/OpenKeychain/src/main/res/layout/view_key_activity.xml b/OpenKeychain/src/main/res/layout/view_key_activity.xml
index b15a73c0e..451eb30ee 100644
--- a/OpenKeychain/src/main/res/layout/view_key_activity.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_activity.xml
@@ -4,7 +4,7 @@
android:layout_height="match_parent"
android:orientation="vertical">
-
+
+ android:layout_height="wrap_content" />
+ android:layout_marginLeft="8dp" />
diff --git a/OpenKeychain/src/main/res/layout/view_key_certs_fragment.xml b/OpenKeychain/src/main/res/layout/view_key_certs_fragment.xml
index 00b3f85c5..0b63abbb1 100644
--- a/OpenKeychain/src/main/res/layout/view_key_certs_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_certs_fragment.xml
@@ -1,24 +1,39 @@
-
-
-
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ android:text="@string/certs_text" />
+
+
+
+
+
+
+
+
+
+
-
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 7a4f41969..8d57f6f2e 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -698,6 +698,7 @@
Identity
<unknown>
No certificates for this key
+ Only certificates created with your keys and self-certificates are displayed here.
Identities to certify
Revocation Reason
Verification Status
From c1a265bfd17c6cb2fdc83403bcda6bb875c70e7c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Tue, 19 Aug 2014 10:01:31 +0200
Subject: [PATCH 057/142] certs header design
---
.../main/res/layout/view_key_certs_fragment.xml | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/OpenKeychain/src/main/res/layout/view_key_certs_fragment.xml b/OpenKeychain/src/main/res/layout/view_key_certs_fragment.xml
index 0b63abbb1..1cf826b30 100644
--- a/OpenKeychain/src/main/res/layout/view_key_certs_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_certs_fragment.xml
@@ -4,11 +4,19 @@
android:orientation="vertical">
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text="@string/certs_text"
+ android:gravity="center_horizontal" />
+
+
Date: Tue, 19 Aug 2014 10:01:39 +0200
Subject: [PATCH 058/142] Add license headers
---
.../keychain/pgp/PgpKeyOperationTest.java | 17 +++++++++++++++++
.../pgp/UncachedKeyringCanonicalizeTest.java | 17 +++++++++++++++++
.../keychain/pgp/UncachedKeyringMergeTest.java | 17 +++++++++++++++++
.../keychain/pgp/UncachedKeyringTest.java | 17 +++++++++++++++++
.../provider/ProviderHelperSaveTest.java | 17 +++++++++++++++++
.../keychain/support/KeyringTestingHelper.java | 1 +
.../keychain/util/FileImportCacheTest.java | 17 +++++++++++++++++
.../keychain/ui/widget/CertifyKeySpinner.java | 17 +++++++++++++++++
.../keychain/ui/widget/KeySpinner.java | 17 +++++++++++++++++
.../keychain/ui/widget/SignKeySpinner.java | 17 +++++++++++++++++
10 files changed, 154 insertions(+)
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index 964512617..3c54c3528 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -1,3 +1,20 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
package org.sufficientlysecure.keychain.pgp;
import junit.framework.AssertionFailedError;
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
index 6e3a9814e..1e4fb564a 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
@@ -1,3 +1,20 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
package org.sufficientlysecure.keychain.pgp;
import org.junit.BeforeClass;
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
index 428206c97..6324b65d8 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
@@ -1,3 +1,20 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
package org.sufficientlysecure.keychain.pgp;
import org.junit.Assert;
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java
index 581e315a0..e25f0b081 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java
@@ -1,3 +1,20 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
package org.sufficientlysecure.keychain.pgp;
import org.junit.Assert;
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/provider/ProviderHelperSaveTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/provider/ProviderHelperSaveTest.java
index 7a5afcc3a..065c1ffba 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/provider/ProviderHelperSaveTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/provider/ProviderHelperSaveTest.java
@@ -1,3 +1,20 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
package org.sufficientlysecure.keychain.provider;
import org.junit.Assert;
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/support/KeyringTestingHelper.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/support/KeyringTestingHelper.java
index 015e134ea..3bf046773 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/support/KeyringTestingHelper.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/support/KeyringTestingHelper.java
@@ -14,6 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
+
package org.sufficientlysecure.keychain.support;
import android.content.Context;
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java
index 11bc05c9e..23649e6f8 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java
@@ -1,3 +1,20 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
package org.sufficientlysecure.keychain.util;
import android.os.Bundle;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java
index 030a76136..e3c9804bb 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java
@@ -1,3 +1,20 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
package org.sufficientlysecure.keychain.ui.widget;
import android.content.Context;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
index b12029239..3a31fc9f4 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
@@ -1,3 +1,20 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
package org.sufficientlysecure.keychain.ui.widget;
import android.content.Context;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java
index cbec7f920..a1ed2c065 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java
@@ -1,3 +1,20 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
package org.sufficientlysecure.keychain.ui.widget;
import android.content.Context;
From a2b38245567ec314cbe1d428d8ad2082d1148134 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Tue, 19 Aug 2014 10:30:44 +0200
Subject: [PATCH 059/142] New preferred hash and symmetric algos, removed
SHA-1, 3DES, new ordering
---
.../keychain/pgp/PgpKeyOperation.java | 24 +++++++++++++------
1 file changed, 17 insertions(+), 7 deletions(-)
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 cdd2eacc0..c6c064a25 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -84,15 +84,25 @@ import java.util.Stack;
public class PgpKeyOperation {
private Stack mProgress;
+ // most preferred is first
private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{
- SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192,
- SymmetricKeyAlgorithmTags.AES_128, SymmetricKeyAlgorithmTags.CAST5,
- SymmetricKeyAlgorithmTags.TRIPLE_DES};
- private static final int[] PREFERRED_HASH_ALGORITHMS = new int[]{HashAlgorithmTags.SHA1,
- HashAlgorithmTags.SHA256, HashAlgorithmTags.RIPEMD160};
+ 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.SHA224,
+ HashAlgorithmTags.SHA256,
+ HashAlgorithmTags.RIPEMD160
+ };
private static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[]{
- CompressionAlgorithmTags.ZLIB, CompressionAlgorithmTags.BZIP2,
- CompressionAlgorithmTags.ZIP};
+ CompressionAlgorithmTags.ZLIB,
+ CompressionAlgorithmTags.BZIP2,
+ CompressionAlgorithmTags.ZIP
+ };
public PgpKeyOperation(Progressable progress) {
super();
From 2c8bcffff3d04a84e7fb51efac6b099a477a98f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Tue, 19 Aug 2014 10:37:27 +0200
Subject: [PATCH 060/142] add feature to key sig subpacket to indicate that we
want MDC
---
.../org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java | 3 +++
1 file changed, 3 insertions(+)
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 c6c064a25..7dedcb242 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -22,6 +22,7 @@ import org.spongycastle.bcpg.CompressionAlgorithmTags;
import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.spongycastle.bcpg.sig.Features;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.jce.spec.ElGamalParameterSpec;
import org.spongycastle.openpgp.PGPEncryptedData;
@@ -894,6 +895,8 @@ public class PgpKeyOperation {
hashedPacketsGen.setPreferredSymmetricAlgorithms(true, PREFERRED_SYMMETRIC_ALGORITHMS);
hashedPacketsGen.setPreferredHashAlgorithms(true, PREFERRED_HASH_ALGORITHMS);
hashedPacketsGen.setPreferredCompressionAlgorithms(true, PREFERRED_COMPRESSION_ALGORITHMS);
+ // Request senders add additional checksums to the message (useful when verifying unsigned messages.)
+ hashedPacketsGen.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION);
hashedPacketsGen.setPrimaryUserID(false, primary);
hashedPacketsGen.setKeyFlags(false, flags);
if (expiry > 0) {
From b1bde6ead93f61d471c7fcd183c50da81d7ee848 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Tue, 19 Aug 2014 10:42:35 +0200
Subject: [PATCH 061/142] Mark packets critical
---
.../keychain/pgp/PgpKeyOperation.java | 22 +++++++++----------
1 file changed, 11 insertions(+), 11 deletions(-)
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 7dedcb242..c1c261126 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -891,17 +891,17 @@ public class PgpKeyOperation {
PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator();
{
- hashedPacketsGen.setSignatureCreationTime(false, new Date());
+ hashedPacketsGen.setSignatureCreationTime(true, new Date());
hashedPacketsGen.setPreferredSymmetricAlgorithms(true, PREFERRED_SYMMETRIC_ALGORITHMS);
hashedPacketsGen.setPreferredHashAlgorithms(true, PREFERRED_HASH_ALGORITHMS);
hashedPacketsGen.setPreferredCompressionAlgorithms(true, PREFERRED_COMPRESSION_ALGORITHMS);
- // Request senders add additional checksums to the message (useful when verifying unsigned messages.)
+ // Request that senders add the MDC to the message (useful when verifying unsigned messages.)
hashedPacketsGen.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION);
- hashedPacketsGen.setPrimaryUserID(false, primary);
- hashedPacketsGen.setKeyFlags(false, flags);
+ hashedPacketsGen.setPrimaryUserID(true, primary);
+ hashedPacketsGen.setKeyFlags(true, flags);
if (expiry > 0) {
hashedPacketsGen.setKeyExpirationTime(
- false, expiry - pKey.getCreationTime().getTime() / 1000);
+ true, expiry - pKey.getCreationTime().getTime() / 1000);
}
}
@@ -918,7 +918,7 @@ public class PgpKeyOperation {
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
- subHashedPacketsGen.setSignatureCreationTime(false, new Date());
+ subHashedPacketsGen.setSignatureCreationTime(true, new Date());
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
sGen.init(PGPSignature.CERTIFICATION_REVOCATION, masterPrivateKey);
return sGen.generateCertification(userId, pKey);
@@ -932,7 +932,7 @@ public class PgpKeyOperation {
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
- subHashedPacketsGen.setSignatureCreationTime(false, new Date());
+ subHashedPacketsGen.setSignatureCreationTime(true, new Date());
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
// Generate key revocation or subkey revocation, depending on master/subkey-ness
if (masterPublicKey.getKeyID() == pKey.getKeyID()) {
@@ -978,16 +978,16 @@ public class PgpKeyOperation {
sGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
PGPSignature certification = sGen.generateCertification(masterPublicKey, pKey);
- unhashedPacketsGen.setEmbeddedSignature(false, certification);
+ unhashedPacketsGen.setEmbeddedSignature(true, certification);
}
PGPSignatureSubpacketGenerator hashedPacketsGen;
{
hashedPacketsGen = new PGPSignatureSubpacketGenerator();
- hashedPacketsGen.setSignatureCreationTime(false, creationTime);
- hashedPacketsGen.setKeyFlags(false, flags);
+ hashedPacketsGen.setSignatureCreationTime(true, creationTime);
+ hashedPacketsGen.setKeyFlags(true, flags);
if (expiry > 0) {
- hashedPacketsGen.setKeyExpirationTime(false,
+ hashedPacketsGen.setKeyExpirationTime(true,
expiry - pKey.getCreationTime().getTime() / 1000);
}
}
From d131693bb89f2bddd194993be45aeb13402196a4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Tue, 19 Aug 2014 10:58:38 +0200
Subject: [PATCH 062/142] Use SHA512 instead of SHA1 and AES256 instead of
CAST5 where possible
---
.../keychain/pgp/PgpKeyOperation.java | 44 ++++++++++---------
1 file changed, 23 insertions(+), 21 deletions(-)
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 c1c261126..b143085d5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -35,7 +35,6 @@ import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureGenerator;
import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
-import org.spongycastle.openpgp.PGPUtil;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor;
import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
@@ -250,13 +249,16 @@ public class PgpKeyOperation {
progress(R.string.progress_building_master_key, 40);
- // define hashing and signing algos
+ // Build key encrypter and decrypter based on passphrase
+ PGPDigestCalculator sha512Calc = new JcaPGPDigestCalculatorProviderBuilder()
+ .build().get(HashAlgorithmTags.SHA512);
+ PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
+ PGPEncryptedData.AES_256, sha512Calc)
+ .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 key encrypter and decrypter based on passphrase
- PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.CAST5, sha1Calc)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
PGPSecretKey masterSecretKey = new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(),
sha1Calc, true, keyEncryptor);
@@ -702,17 +704,17 @@ public class PgpKeyOperation {
pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
PGPSecretKey sKey; {
- // define hashing and signing algos
- PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
- .build().get(HashAlgorithmTags.SHA1);
-
// Build key encrypter and decrypter based on passphrase
+ PGPDigestCalculator sha512Calc = new JcaPGPDigestCalculatorProviderBuilder()
+ .build().get(HashAlgorithmTags.SHA512);
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.CAST5, sha1Calc)
+ PGPEncryptedData.AES_256, sha512Calc)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
- sKey = new PGPSecretKey(keyPair.getPrivateKey(), pKey,
- sha1Calc, false, keyEncryptor);
+ // NOTE: only SHA1 is supported for key checksum calculations.
+ PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
+ .build().get(HashAlgorithmTags.SHA1);
+ sKey = new PGPSecretKey(keyPair.getPrivateKey(), pKey, sha1Calc, false, keyEncryptor);
}
log.add(LogLevel.DEBUG, LogType.MSG_MF_SUBKEY_NEW_ID,
@@ -729,13 +731,13 @@ public class PgpKeyOperation {
log.add(LogLevel.INFO, LogType.MSG_MF_PASSPHRASE, indent);
indent += 1;
- PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build()
- .get(HashAlgorithmTags.SHA1);
+ PGPDigestCalculator sha512Calc = new JcaPGPDigestCalculatorProviderBuilder().build()
+ .get(HashAlgorithmTags.SHA512);
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
// Build key encryptor based on new passphrase
PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.CAST5, sha1Calc)
+ PGPEncryptedData.AES_256, sha512Calc)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
saveParcel.mNewPassphrase.toCharArray());
@@ -885,7 +887,7 @@ public class PgpKeyOperation {
int flags, long expiry)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPrivateKey.getPublicKeyPacket().getAlgorithm(), PGPUtil.SHA1)
+ masterPrivateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
@@ -914,7 +916,7 @@ public class PgpKeyOperation {
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPrivateKey.getPublicKeyPacket().getAlgorithm(), PGPUtil.SHA1)
+ masterPrivateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
@@ -928,7 +930,7 @@ public class PgpKeyOperation {
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, PGPPublicKey pKey)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPublicKey.getAlgorithm(), PGPUtil.SHA1)
+ masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA512)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
@@ -972,7 +974,7 @@ public class PgpKeyOperation {
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
subHashedPacketsGen.setSignatureCreationTime(false, creationTime);
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PGPUtil.SHA1)
+ pKey.getAlgorithm(), HashAlgorithmTags.SHA512)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
sGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
@@ -993,7 +995,7 @@ public class PgpKeyOperation {
}
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPublicKey.getAlgorithm(), PGPUtil.SHA1)
+ masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA512)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
sGen.init(PGPSignature.SUBKEY_BINDING, masterPrivateKey);
From 4a280f6ba36f35d21e87642d74d3e9dfdf6f09d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Tue, 19 Aug 2014 11:11:58 +0200
Subject: [PATCH 063/142] Use higher s2k count
---
.../keychain/pgp/PgpKeyOperation.java | 39 ++++++++++++++-----
1 file changed, 29 insertions(+), 10 deletions(-)
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 b143085d5..c69eeaf04 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -25,7 +25,6 @@ import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.spongycastle.bcpg.sig.Features;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.jce.spec.ElGamalParameterSpec;
-import org.spongycastle.openpgp.PGPEncryptedData;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPKeyPair;
import org.spongycastle.openpgp.PGPPrivateKey;
@@ -104,6 +103,26 @@ public class PgpKeyOperation {
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. I'll use 0xc0 as a
+ * default -- about 130,000 iterations.
+ *
+ * http://kbsriram.com/2013/01/generating-rsa-keys-with-bouncycastle.html
+ */
+ private static final int SECRET_KEY_ENCRYPTOR_HASH_ALGO = HashAlgorithmTags.SHA512;
+ private static final int SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO = SymmetricKeyAlgorithmTags.AES_256;
+ private static final int SECRET_KEY_ENCRYPTOR_S2K_COUNT = 0xc0;
+
public PgpKeyOperation(Progressable progress) {
super();
if (progress != null) {
@@ -250,10 +269,10 @@ public class PgpKeyOperation {
progress(R.string.progress_building_master_key, 40);
// Build key encrypter and decrypter based on passphrase
- PGPDigestCalculator sha512Calc = new JcaPGPDigestCalculatorProviderBuilder()
- .build().get(HashAlgorithmTags.SHA512);
+ PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder()
+ .build().get(SECRET_KEY_ENCRYPTOR_HASH_ALGO);
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.AES_256, sha512Calc)
+ SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, SECRET_KEY_ENCRYPTOR_S2K_COUNT)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
// NOTE: only SHA1 is supported for key checksum calculations.
@@ -705,10 +724,10 @@ public class PgpKeyOperation {
PGPSecretKey sKey; {
// Build key encrypter and decrypter based on passphrase
- PGPDigestCalculator sha512Calc = new JcaPGPDigestCalculatorProviderBuilder()
- .build().get(HashAlgorithmTags.SHA512);
+ PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder()
+ .build().get(SECRET_KEY_ENCRYPTOR_HASH_ALGO);
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.AES_256, sha512Calc)
+ SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, SECRET_KEY_ENCRYPTOR_S2K_COUNT)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
// NOTE: only SHA1 is supported for key checksum calculations.
@@ -731,13 +750,13 @@ public class PgpKeyOperation {
log.add(LogLevel.INFO, LogType.MSG_MF_PASSPHRASE, indent);
indent += 1;
- PGPDigestCalculator sha512Calc = new JcaPGPDigestCalculatorProviderBuilder().build()
- .get(HashAlgorithmTags.SHA512);
+ PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build()
+ .get(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(
- PGPEncryptedData.AES_256, sha512Calc)
+ SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, SECRET_KEY_ENCRYPTOR_S2K_COUNT)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
saveParcel.mNewPassphrase.toCharArray());
From c1d05d0ee92e9c9bc2a12a64aa4b73e832fbde0a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Tue, 19 Aug 2014 14:16:30 +0200
Subject: [PATCH 064/142] Change criticallity of subpackets after discussion
---
.../keychain/pgp/PgpKeyOperation.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
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 c69eeaf04..85e772d52 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -913,12 +913,12 @@ public class PgpKeyOperation {
PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator();
{
hashedPacketsGen.setSignatureCreationTime(true, new Date());
- hashedPacketsGen.setPreferredSymmetricAlgorithms(true, PREFERRED_SYMMETRIC_ALGORITHMS);
- hashedPacketsGen.setPreferredHashAlgorithms(true, PREFERRED_HASH_ALGORITHMS);
- hashedPacketsGen.setPreferredCompressionAlgorithms(true, PREFERRED_COMPRESSION_ALGORITHMS);
- // Request that senders add the MDC to the message (useful when verifying unsigned messages.)
+ hashedPacketsGen.setPreferredSymmetricAlgorithms(false, PREFERRED_SYMMETRIC_ALGORITHMS);
+ hashedPacketsGen.setPreferredHashAlgorithms(false, PREFERRED_HASH_ALGORITHMS);
+ hashedPacketsGen.setPreferredCompressionAlgorithms(false, PREFERRED_COMPRESSION_ALGORITHMS);
+ // Request that senders add the MDC to the message (authenticate unsigned messages)
hashedPacketsGen.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION);
- hashedPacketsGen.setPrimaryUserID(true, primary);
+ hashedPacketsGen.setPrimaryUserID(false, primary);
hashedPacketsGen.setKeyFlags(true, flags);
if (expiry > 0) {
hashedPacketsGen.setKeyExpirationTime(
From 6a3150d8788664a5e1d501488159ff5e080cb9b4 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Tue, 19 Aug 2014 14:42:40 +0200
Subject: [PATCH 065/142] fix primary user id in master key flag modification
---
.../org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
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 c69eeaf04..88c6437d3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -881,10 +881,12 @@ public class PgpKeyOperation {
}
// add shiny new user id certificate
+ boolean isPrimary = currentCert.getHashedSubPackets() != null &&
+ currentCert.getHashedSubPackets().isPrimaryUserID();
modifiedPublicKey = PGPPublicKey.removeCertification(
modifiedPublicKey, userId, currentCert);
PGPSignature newCert = generateUserIdSignature(
- masterPrivateKey, masterPublicKey, userId, true, flags, expiry);
+ masterPrivateKey, masterPublicKey, userId, isPrimary, flags, expiry);
modifiedPublicKey = PGPPublicKey.addCertification(
modifiedPublicKey, userId, newCert);
ok = true;
From 9474749be15b49c89b6e2de820f62b2e0029f393 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Tue, 19 Aug 2014 14:51:28 +0200
Subject: [PATCH 066/142] Decrease iteration count, delayed for 2.9
---
.../org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 913bfafed..6228b36ac 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -121,7 +121,7 @@ public class PgpKeyOperation {
*/
private static final int SECRET_KEY_ENCRYPTOR_HASH_ALGO = HashAlgorithmTags.SHA512;
private static final int SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO = SymmetricKeyAlgorithmTags.AES_256;
- private static final int SECRET_KEY_ENCRYPTOR_S2K_COUNT = 0xc0;
+ private static final int SECRET_KEY_ENCRYPTOR_S2K_COUNT = 0x60;
public PgpKeyOperation(Progressable progress) {
super();
From 68cce5c0c85aea44257f294369a0abe316dd2347 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Tue, 19 Aug 2014 14:53:25 +0200
Subject: [PATCH 067/142] Bouncy Castle link
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 4b8f23063..a9b03b2c3 100644
--- a/README.md
+++ b/README.md
@@ -107,6 +107,7 @@ see
* Tests in https://github.com/bcgit/bc-java/tree/master/pg/src/test/java/org/bouncycastle/openpgp/test
* Examples in https://github.com/bcgit/bc-java/tree/master/pg/src/main/java/org/bouncycastle/openpgp/examples
* Mailinglist Archive at http://bouncy-castle.1462172.n4.nabble.com/Bouncy-Castle-Dev-f1462173.html
+* Commit changelog of pg subpackage: https://github.com/bcgit/bc-java/commits/master/pg
## Notes
From 8d668d170c41959897aa78e2f0acc9fac7168d36 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Tue, 19 Aug 2014 15:23:37 +0200
Subject: [PATCH 068/142] Notes about criticality
---
.../keychain/pgp/PgpKeyOperation.java | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
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 6228b36ac..b4e21cc0e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -914,13 +914,26 @@ public class PgpKeyOperation {
PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator();
{
- hashedPacketsGen.setSignatureCreationTime(true, new Date());
+ /*
+ * From RFC about critical subpackets:
+ * If a subpacket is encountered that is
+ * marked critical but is unknown to the evaluating software, the
+ * evaluator SHOULD consider the signature to be in error.
+ * An evaluator may "recognize" a subpacket, but not implement it. The
+ * purpose of the critical bit is to allow the signer to tell an
+ * evaluator that it would prefer a new, unknown feature to generate an
+ * 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.setPrimaryUserID(false, primary);
+
+ /* critical subpackets: */
+ hashedPacketsGen.setSignatureCreationTime(true, new Date());
// Request that senders add the MDC to the message (authenticate unsigned messages)
hashedPacketsGen.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION);
- hashedPacketsGen.setPrimaryUserID(false, primary);
hashedPacketsGen.setKeyFlags(true, flags);
if (expiry > 0) {
hashedPacketsGen.setKeyExpirationTime(
From c725239a69544213229e2d1d0b69b4dca0bcc5d9 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Tue, 19 Aug 2014 15:45:42 +0200
Subject: [PATCH 069/142] consolidate: split into two steps, can pick up at
second step if anything fails
---
.../keychain/Constants.java | 3 +
.../keychain/helper/Preferences.java | 31 +++++++++
.../keychain/provider/ProviderHelper.java | 65 ++++++++++++++-----
.../service/KeychainIntentService.java | 13 +---
.../service/OperationResultParcel.java | 1 +
.../keychain/util/FileImportCache.java | 22 ++++++-
OpenKeychain/src/main/res/values/strings.xml | 3 +
7 files changed, 112 insertions(+), 26 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
index bce093427..78b66464b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
@@ -68,6 +68,9 @@ public final class Constants {
public static final String KEY_SERVERS_DEFAULT_VERSION = "keyServersDefaultVersion";
public static final String WRITE_VERSION_HEADER = "writeVersionHeader";
public static final String FIRST_TIME = "firstTime";
+ public static final String CACHED_CONSOLIDATE = "cachedConsolidate";
+ public static final String CACHED_CONSOLIDATE_SECRETS = "cachedConsolidateSecrets";
+ public static final String CACHED_CONSOLIDATE_PUBLICS = "cachedConsolidatePublics";
}
public static final class Defaults {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
index 14ae46840..9a10148f2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
@@ -25,6 +25,7 @@ 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;
import java.util.ArrayList;
import java.util.Arrays;
@@ -134,6 +135,36 @@ public class Preferences {
editor.commit();
}
+ public boolean getCachedConsolidate() {
+ return mSharedPreferences.getBoolean(Pref.CACHED_CONSOLIDATE, false);
+ }
+
+ public void setCachedConsolidate(boolean value) {
+ SharedPreferences.Editor editor = mSharedPreferences.edit();
+ editor.putBoolean(Pref.CACHED_CONSOLIDATE, value);
+ editor.commit();
+ }
+
+ public int getCachedConsolidateNumPublics() {
+ return mSharedPreferences.getInt(Pref.CACHED_CONSOLIDATE_PUBLICS, 100);
+ }
+
+ public void setCachedConsolidateNumPublics(int value) {
+ SharedPreferences.Editor editor = mSharedPreferences.edit();
+ editor.putInt(Pref.CACHED_CONSOLIDATE_PUBLICS, value);
+ editor.commit();
+ }
+
+ public int getCachedConsolidateNumSecrets() {
+ return mSharedPreferences.getInt(Pref.CACHED_CONSOLIDATE_SECRETS, 100);
+ }
+
+ public void setCachedConsolidateNumSecrets(int value) {
+ SharedPreferences.Editor editor = mSharedPreferences.edit();
+ editor.putInt(Pref.CACHED_CONSOLIDATE_SECRETS, value);
+ editor.commit();
+ }
+
public boolean isFirstTime() {
return mSharedPreferences.getBoolean(Constants.Pref.FIRST_TIME, true);
}
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 3594ded51..5f55eedd5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -28,6 +28,8 @@ import android.os.RemoteException;
import android.support.v4.util.LongSparseArray;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
@@ -58,6 +60,7 @@ import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResul
import org.sufficientlysecure.keychain.util.FileImportCache;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.ProgressFixedScaler;
import org.sufficientlysecure.keychain.util.ProgressScaler;
import java.io.ByteArrayOutputStream;
@@ -823,11 +826,9 @@ public class ProviderHelper {
}
- public ConsolidateResult consolidateDatabase(Progressable progress) {
+ public ConsolidateResult consolidateDatabaseStep1(Progressable progress) {
// 1a. fetch all secret keyrings into a cache file
- int numSecrets, numPublics;
-
log(LogLevel.START, LogType.MSG_CON, mIndent);
mIndent += 1;
@@ -836,7 +837,7 @@ public class ProviderHelper {
log(LogLevel.DEBUG, LogType.MSG_CON_SAVE_SECRET, mIndent);
mIndent += 1;
- final Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[] {
+ final Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[]{
KeyRings.PRIVKEY_DATA, KeyRings.FINGERPRINT, KeyRings.HAS_ANY_SECRET
}, KeyRings.HAS_ANY_SECRET + " = 1", null, null);
@@ -844,7 +845,7 @@ public class ProviderHelper {
return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
}
- numSecrets = cursor.getCount();
+ Preferences.getPreferences(mContext).setCachedConsolidateNumSecrets(cursor.getCount());
FileImportCache cache =
new FileImportCache(mContext, "consolidate_secret.pcl");
@@ -894,7 +895,7 @@ public class ProviderHelper {
log(LogLevel.DEBUG, LogType.MSG_CON_SAVE_PUBLIC, mIndent);
mIndent += 1;
- final Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[] {
+ final Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[]{
KeyRings.PUBKEY_DATA, KeyRings.FINGERPRINT
}, null, null, null);
@@ -902,7 +903,7 @@ public class ProviderHelper {
return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
}
- numPublics = cursor.getCount();
+ Preferences.getPreferences(mContext).setCachedConsolidateNumSecrets(cursor.getCount());
FileImportCache cache =
new FileImportCache(mContext, "consolidate_public.pcl");
@@ -946,19 +947,39 @@ public class ProviderHelper {
mIndent -= 1;
}
+ Preferences.getPreferences(mContext).setCachedConsolidate(true);
+
+ return consolidateDatabaseStep2(progress);
+ }
+
+ public ConsolidateResult consolidateDatabaseStep2(Progressable progress) {
+
+ Preferences prefs = Preferences.getPreferences(mContext);
+ if ( ! prefs.getCachedConsolidate()) {
+ log(LogLevel.ERROR, LogType.MSG_CON_ERROR_BAD_STATE);
+ return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
+ }
+
+ // Set flag that we have a cached consolidation here
+ int numSecrets = prefs.getCachedConsolidateNumSecrets();
+ int numPublics = prefs.getCachedConsolidateNumPublics();
+
// 2. wipe database (IT'S DANGEROUS)
log(LogLevel.DEBUG, LogType.MSG_CON_DB_CLEAR, mIndent);
new KeychainDatabase(mContext).clearDatabase();
+ FileImportCache cacheSecret =
+ new FileImportCache(mContext, "consolidate_secret.pcl");
+ FileImportCache cachePublic =
+ new FileImportCache(mContext, "consolidate_public.pcl");
+
// 3. Re-Import secret keyrings from cache
try {
log(LogLevel.DEBUG, LogType.MSG_CON_REIMPORT_SECRET, mIndent, numSecrets);
mIndent += 1;
- FileImportCache cache =
- new FileImportCache(mContext, "consolidate_secret.pcl");
- new PgpImportExport(mContext, this, new ProgressScaler(progress, 10, 25, 100))
- .importKeyRings(cache.readCache(), numSecrets);
+ new PgpImportExport(mContext, this, new ProgressFixedScaler(progress, 10, 25, 100, R.string.progress_con_reimport))
+ .importKeyRings(cacheSecret.readCache(false), numSecrets);
} catch (IOException e) {
Log.e(Constants.TAG, "error importing secret");
return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
@@ -966,15 +987,13 @@ public class ProviderHelper {
mIndent -= 1;
}
- // 3. Re-Import public keyrings from cache
+ // 4. Re-Import public keyrings from cache
try {
log(LogLevel.DEBUG, LogType.MSG_CON_REIMPORT_PUBLIC, mIndent, numPublics);
mIndent += 1;
- FileImportCache cache =
- new FileImportCache(mContext, "consolidate_public.pcl");
new PgpImportExport(mContext, this, new ProgressScaler(progress, 25, 99, 100))
- .importKeyRings(cache.readCache(), numPublics);
+ .importKeyRings(cachePublic.readCache(false), numPublics);
} catch (IOException e) {
Log.e(Constants.TAG, "error importing public");
return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
@@ -982,6 +1001,22 @@ public class ProviderHelper {
mIndent -= 1;
}
+ Preferences.getPreferences(mContext).setCachedConsolidate(false);
+
+ // 5. Delete caches
+ try {
+ cacheSecret.delete();
+ } catch (IOException e) {
+ // doesn't really matter
+ Log.e(Constants.TAG, "IOException during delete of secret cache", e);
+ }
+ try {
+ cachePublic.delete();
+ } catch (IOException e) {
+ // doesn't really matter
+ Log.e(Constants.TAG, "IOException during deletion of public cache", e);
+ }
+
progress.setProgress(100, 100);
log(LogLevel.OK, LogType.MSG_CON_SUCCESS, mIndent);
mIndent -= 1;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index 9f5650df6..2c1bc8463 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -490,10 +490,7 @@ public class KeychainIntentService extends IntentService
PgpImportExport pgpImportExport = new PgpImportExport(this, this);
ImportKeyResult result = pgpImportExport.importKeyRings(entries);
- Bundle resultData = new Bundle();
- resultData.putParcelable(RESULT_IMPORT, result);
-
- sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
+ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
} catch (Exception e) {
sendErrorToHandler(e);
}
@@ -670,12 +667,8 @@ public class KeychainIntentService extends IntentService
}
} else if (ACTION_CONSOLIDATE.equals(action)) {
- ConsolidateResult result = new ProviderHelper(this).consolidateDatabase(this);
-
- Bundle resultData = new Bundle();
- resultData.putParcelable(RESULT_CONSOLIDATE, result);
-
- sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
+ ConsolidateResult result = new ProviderHelper(this).consolidateDatabaseStep1(this);
+ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index c601ec57e..3f478cfed 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -391,6 +391,7 @@ public class OperationResultParcel implements Parcelable {
// consolidate
MSG_CON (R.string.msg_con),
+ MSG_CON_ERROR_BAD_STATE (R.string.msg_con_error_bad_state),
MSG_CON_SAVE_SECRET (R.string.msg_con_save_secret),
MSG_CON_SAVE_PUBLIC (R.string.msg_con_save_public),
MSG_CON_DB_CLEAR (R.string.msg_con_db_clear),
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java
index 35833adc6..09275fc95 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java
@@ -92,6 +92,10 @@ public class FileImportCache {
}
public Iterator readCache() throws IOException {
+ return readCache(true);
+ }
+
+ public Iterator readCache(final boolean deleteAfterRead) throws IOException {
File cacheDir = mContext.getCacheDir();
if (cacheDir == null) {
@@ -166,7 +170,10 @@ public class FileImportCache {
if (!closed) {
try {
ois.close();
- tempFile.delete();
+ if (deleteAfterRead) {
+ //noinspection ResultOfMethodCallIgnored
+ tempFile.delete();
+ }
} catch (IOException e) {
// nvm
}
@@ -177,4 +184,17 @@ public class FileImportCache {
};
}
+
+ public boolean delete() throws IOException {
+
+ File cacheDir = mContext.getCacheDir();
+ if (cacheDir == null) {
+ // https://groups.google.com/forum/#!topic/android-developers/-694j87eXVU
+ throw new IOException("cache dir is null!");
+ }
+
+ final File tempFile = new File(cacheDir, mFilename);
+ return tempFile.delete();
+ }
+
}
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 8d57f6f2e..e506bf488 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -302,6 +302,8 @@
verifying integrity…
deleting \'%s\' securely…
+ reimporting database…
+
Name/Email/Key ID…
Name/Email/Proof/Key…
@@ -671,6 +673,7 @@
Consolidating database
+ Consolidation started while no database was cached! This is probably a programming error, please file a bug report.
Saving secret keyrings
Saving public keyrings
Clearing database
From a2ae318a1adb355efd593b8fd8041d75c25866b3 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Tue, 19 Aug 2014 15:55:40 +0200
Subject: [PATCH 070/142] add OpenDialogActivity (stub)
---
.../keychain/ui/OpenDialogActivity.java | 117 ++++++++++++++++++
1 file changed, 117 insertions(+)
create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OpenDialogActivity.java
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OpenDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OpenDialogActivity.java
new file mode 100644
index 000000000..cdb09bbd0
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OpenDialogActivity.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.sufficientlysecure.keychain.ui;
+
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.support.v4.app.FragmentActivity;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+
+import org.sufficientlysecure.keychain.Constants;
+
+/**
+ * We can not directly create a dialog on the context provided inside the content provider.
+ * This activity encapsulates a DialogFragment to emulate a dialog.
+ */
+public class OpenDialogActivity extends FragmentActivity {
+
+ public static final String EXTRA_MESSENGER = "messenger";
+ public static final String EXTRA_FILENAME = "filename";
+
+ public static final int MSG_CANCEL = 1;
+ public static final int MSG_DECRYPT_OPEN = 2;
+ public static final int MSG_GET_ENCRYPTED = 3;
+
+ MyDialogFragment mDialogFragment;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // this activity itself has no content view (see manifest)
+
+ mDialogFragment = new MyDialogFragment();
+ // give all extras through to the fragment
+ mDialogFragment.setArguments(getIntent().getExtras());
+
+ mDialogFragment.show(getFragmentManager(), "dialog");
+ }
+
+ public static class MyDialogFragment extends DialogFragment {
+
+ private Messenger mMessenger;
+
+ /**
+ * Creates dialog
+ */
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ mMessenger = getArguments().getParcelable(EXTRA_MESSENGER);
+ String filename = getArguments().getString(EXTRA_FILENAME);
+
+ // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay
+ ContextThemeWrapper context = new ContextThemeWrapper(getActivity(),
+ android.R.style.Theme_DeviceDefault_Light_Dialog);
+ ProgressDialog.Builder progress = new ProgressDialog.Builder(context);
+ return progress.show();
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ super.onCancel(dialog);
+
+ dismiss();
+ sendMessageToHandler(MSG_CANCEL);
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ Log.d(Constants.TAG, "onDismiss");
+
+ getActivity().finish();
+ }
+
+ /**
+ * Send message back to handler which is initialized in a activity
+ *
+ * @param what Message integer you want to send
+ */
+ private void sendMessageToHandler(Integer what) {
+ Message msg = Message.obtain();
+ msg.what = what;
+
+ try {
+ mMessenger.send(msg);
+ } catch (RemoteException e) {
+ Log.w(Constants.TAG, "Exception sending message, Is handler present?", e);
+ } catch (NullPointerException e) {
+ Log.w(Constants.TAG, "Messenger is null!", e);
+ }
+ }
+
+ }
+
+}
From 0422d48b61011ff75ef6d85a6e45b90aebb5e58b Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Tue, 19 Aug 2014 15:55:53 +0200
Subject: [PATCH 071/142] add ProgressFixedScaler (forgot in a previous commit)
---
.../keychain/util/ProgressFixedScaler.java | 29 +++++++++++++++++++
1 file changed, 29 insertions(+)
create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressFixedScaler.java
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressFixedScaler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressFixedScaler.java
new file mode 100644
index 000000000..4bb4ca5de
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressFixedScaler.java
@@ -0,0 +1,29 @@
+package org.sufficientlysecure.keychain.util;
+
+import org.sufficientlysecure.keychain.pgp.Progressable;
+
+/** This is a simple variant of ProgressScaler which shows a fixed progress message, ignoring
+ * the provided ones.
+ */
+public class ProgressFixedScaler extends ProgressScaler {
+
+ final int mResId;
+
+ public ProgressFixedScaler(Progressable wrapped, int from, int to, int max, int resId) {
+ super(wrapped, from, to, max);
+ mResId = resId;
+ }
+
+ public void setProgress(int resourceId, int progress, int max) {
+ if (mWrapped != null) {
+ mWrapped.setProgress(mResId, mFrom + progress * (mTo - mFrom) / max, mMax);
+ }
+ }
+
+ public void setProgress(String message, int progress, int max) {
+ if (mWrapped != null) {
+ mWrapped.setProgress(mResId, mFrom + progress * (mTo - mFrom) / max, mMax);
+ }
+ }
+
+}
From 9fb1050fed5cdaa238219b29958cba1c484dff7e Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Tue, 19 Aug 2014 15:56:53 +0200
Subject: [PATCH 072/142] stub for consolidate recovery in KeychainApplication
---
.../sufficientlysecure/keychain/KeychainApplication.java | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
index 9b9880533..233226cc5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
@@ -84,11 +84,18 @@ public class KeychainApplication extends Application {
setupAccountAsNeeded(this);
// Update keyserver list as needed
- Preferences.getPreferences(this).updatePreferences();
+ Preferences prefs = Preferences.getPreferences(this);
+
+ prefs.updatePreferences();
TlsHelper.addStaticCA("pool.sks-keyservers.net", getAssets(), "sks-keyservers.netCA.cer");
TemporaryStorageProvider.cleanUp(this);
+
+ if (prefs.getCachedConsolidate()) {
+ // do something which calls ProviderHelper.consolidateDatabaseStep2 with a progressable
+ }
+
}
public static void setupAccountAsNeeded(Context context) {
From 5f8bbab5694bfe1e1c45205b075481d696f34738 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Tue, 19 Aug 2014 16:31:51 +0200
Subject: [PATCH 073/142] Scroll fixes for certify activity
---
.../keychain/pgp/PgpKeyOperation.java | 2 +-
.../keychain/ui/CertifyKeyActivity.java | 15 +++++++++++++++
.../src/main/res/layout/certify_key_activity.xml | 12 +++++-------
3 files changed, 21 insertions(+), 8 deletions(-)
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 b4e21cc0e..e357db412 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -930,7 +930,7 @@ public class PgpKeyOperation {
hashedPacketsGen.setPreferredCompressionAlgorithms(false, PREFERRED_COMPRESSION_ALGORITHMS);
hashedPacketsGen.setPrimaryUserID(false, primary);
- /* critical subpackets: */
+ /* critical subpackets: we consider those important for a modern pgp implementation */
hashedPacketsGen.setSignatureCreationTime(true, new Date());
// Request that senders add the MDC to the message (authenticate unsigned messages)
hashedPacketsGen.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
index 7c6e94d5e..e81ebb9c4 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
@@ -40,6 +40,7 @@ import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.ListView;
+import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
@@ -71,6 +72,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements LoaderManag
private ImageView mActionCertifyImage;
private CheckBox mUploadKeyCheckbox;
private Spinner mSelectKeyserverSpinner;
+ private ScrollView mScrollView;
private CertifyKeySpinner mCertifyKeySpinner;
@@ -96,6 +98,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements LoaderManag
mCertifyButton = findViewById(R.id.certify_key_certify_button);
mActionCertifyImage = (ImageView) findViewById(R.id.certify_key_action_certify_image);
mUserIds = (ListView) findViewById(R.id.view_key_user_ids);
+ mScrollView = (ScrollView) findViewById(R.id.certify_scroll_view);
// make certify image gray, like action icons
mActionCertifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light),
@@ -141,6 +144,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements LoaderManag
if (mMasterKeyId == 0) {
Notify.showNotify(CertifyKeyActivity.this, getString(R.string.select_key_to_certify),
Notify.Style.ERROR);
+ scrollUp();
} else {
initiateCertifying();
}
@@ -165,6 +169,14 @@ public class CertifyKeyActivity extends ActionBarActivity implements LoaderManag
getSupportLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this);
}
+ private void scrollUp() {
+ mScrollView.post(new Runnable() {
+ public void run() {
+ mScrollView.fullScroll(ScrollView.FOCUS_UP);
+ }
+ });
+ }
+
static final String USER_IDS_SELECTION = UserIds.IS_REVOKED + " = 0";
static final String[] KEYRING_PROJECTION =
@@ -217,6 +229,9 @@ public class CertifyKeyActivity extends ActionBarActivity implements LoaderManag
break;
case LOADER_ID_USER_IDS:
mUserIdsAdapter.swapCursor(data);
+ // when some user ids are pre-checked, the focus is requested and the scroll view goes
+ // down. This fixes it.
+ scrollUp();
break;
}
}
diff --git a/OpenKeychain/src/main/res/layout/certify_key_activity.xml b/OpenKeychain/src/main/res/layout/certify_key_activity.xml
index bce194438..9796a6ddc 100644
--- a/OpenKeychain/src/main/res/layout/certify_key_activity.xml
+++ b/OpenKeychain/src/main/res/layout/certify_key_activity.xml
@@ -1,6 +1,5 @@
@@ -8,6 +7,7 @@
@@ -27,9 +27,9 @@
android:text="@string/section_certification_key" />
+ android:id="@+id/certify_key_spinner"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ android:layout_height="wrap_content" />
-
From 4f8ddad9d37f77d5a119623ccaf042f41b65ebbc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Tue, 19 Aug 2014 16:40:57 +0200
Subject: [PATCH 074/142] ConsolidateDialogActivity
---
OpenKeychain/src/main/AndroidManifest.xml | 4 ++
...ty.java => ConsolidateDialogActivity.java} | 67 +++++++------------
2 files changed, 30 insertions(+), 41 deletions(-)
rename OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/{OpenDialogActivity.java => ConsolidateDialogActivity.java} (58%)
diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml
index c10629c6d..142690abb 100644
--- a/OpenKeychain/src/main/AndroidManifest.xml
+++ b/OpenKeychain/src/main/AndroidManifest.xml
@@ -556,6 +556,10 @@
android:name="android.support.PARENT_ACTIVITY"
android:value=".ui.KeyListActivity" />
+
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OpenDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java
similarity index 58%
rename from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OpenDialogActivity.java
rename to OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java
index cdb09bbd0..e4a80ff48 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OpenDialogActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java
@@ -18,31 +18,23 @@
package org.sufficientlysecure.keychain.ui;
import android.app.Dialog;
-import android.app.DialogFragment;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Bundle;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
+import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.ContextThemeWrapper;
+import android.view.KeyEvent;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
/**
- * We can not directly create a dialog on the context provided inside the content provider.
+ * We can not directly create a dialog on the application context.
* This activity encapsulates a DialogFragment to emulate a dialog.
*/
-public class OpenDialogActivity extends FragmentActivity {
-
- public static final String EXTRA_MESSENGER = "messenger";
- public static final String EXTRA_FILENAME = "filename";
-
- public static final int MSG_CANCEL = 1;
- public static final int MSG_DECRYPT_OPEN = 2;
- public static final int MSG_GET_ENCRYPTED = 3;
+public class ConsolidateDialogActivity extends FragmentActivity {
MyDialogFragment mDialogFragment;
@@ -56,26 +48,38 @@ public class OpenDialogActivity extends FragmentActivity {
// give all extras through to the fragment
mDialogFragment.setArguments(getIntent().getExtras());
- mDialogFragment.show(getFragmentManager(), "dialog");
+ mDialogFragment.show(getSupportFragmentManager(), "dialog");
}
public static class MyDialogFragment extends DialogFragment {
- private Messenger mMessenger;
-
/**
* Creates dialog
*/
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- mMessenger = getArguments().getParcelable(EXTRA_MESSENGER);
- String filename = getArguments().getString(EXTRA_FILENAME);
-
// hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay
ContextThemeWrapper context = new ContextThemeWrapper(getActivity(),
- android.R.style.Theme_DeviceDefault_Light_Dialog);
- ProgressDialog.Builder progress = new ProgressDialog.Builder(context);
- return progress.show();
+ R.style.Theme_AppCompat_Light);
+ ProgressDialog dialog = new ProgressDialog(context);
+ dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ dialog.setCancelable(false);
+ dialog.setCanceledOnTouchOutside(false);
+
+ // Disable the back button
+ DialogInterface.OnKeyListener keyListener = new DialogInterface.OnKeyListener() {
+ @Override
+ public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ return true;
+ }
+ return false;
+ }
+
+ };
+ dialog.setOnKeyListener(keyListener);
+
+ return dialog;
}
@Override
@@ -83,7 +87,6 @@ public class OpenDialogActivity extends FragmentActivity {
super.onCancel(dialog);
dismiss();
- sendMessageToHandler(MSG_CANCEL);
}
@Override
@@ -94,24 +97,6 @@ public class OpenDialogActivity extends FragmentActivity {
getActivity().finish();
}
- /**
- * Send message back to handler which is initialized in a activity
- *
- * @param what Message integer you want to send
- */
- private void sendMessageToHandler(Integer what) {
- Message msg = Message.obtain();
- msg.what = what;
-
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.w(Constants.TAG, "Exception sending message, Is handler present?", e);
- } catch (NullPointerException e) {
- Log.w(Constants.TAG, "Messenger is null!", e);
- }
- }
-
}
}
From c42f6a04eddf29eb655e56d574dee46374488614 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Tue, 19 Aug 2014 16:49:48 +0200
Subject: [PATCH 075/142] Start consolidate activity
---
.../sufficientlysecure/keychain/KeychainApplication.java | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
index 233226cc5..bb691a9d2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
@@ -21,6 +21,7 @@ import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Application;
import android.content.Context;
+import android.content.Intent;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Environment;
@@ -29,6 +30,7 @@ import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.helper.TlsHelper;
import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
+import org.sufficientlysecure.keychain.ui.ConsolidateDialogActivity;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.PRNGFixes;
@@ -92,12 +94,17 @@ public class KeychainApplication extends Application {
TemporaryStorageProvider.cleanUp(this);
+ // restart consolidate process if it has been interruped before
if (prefs.getCachedConsolidate()) {
// do something which calls ProviderHelper.consolidateDatabaseStep2 with a progressable
+ Intent consolidateIntent = new Intent(this, ConsolidateDialogActivity.class);
+ consolidateIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(consolidateIntent);
}
-
}
+
+
public static void setupAccountAsNeeded(Context context) {
AccountManager manager = AccountManager.get(context);
Account[] accounts = manager.getAccountsByType(Constants.PACKAGE_NAME);
From 9930ab7f6ff9400d6e3aa36ce06c663ce09be633 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser
Date: Tue, 19 Aug 2014 16:53:44 +0200
Subject: [PATCH 076/142] consolidate: a lot more log output, better recovery
---
.../keychain/helper/Preferences.java | 4 +-
.../keychain/provider/ProviderHelper.java | 86 ++++++++++++++-----
.../service/OperationResultParcel.java | 27 ++++--
OpenKeychain/src/main/res/values/strings.xml | 28 ++++--
4 files changed, 109 insertions(+), 36 deletions(-)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
index 9a10148f2..5190a550e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
@@ -146,7 +146,7 @@ public class Preferences {
}
public int getCachedConsolidateNumPublics() {
- return mSharedPreferences.getInt(Pref.CACHED_CONSOLIDATE_PUBLICS, 100);
+ return mSharedPreferences.getInt(Pref.CACHED_CONSOLIDATE_PUBLICS, -1);
}
public void setCachedConsolidateNumPublics(int value) {
@@ -156,7 +156,7 @@ public class Preferences {
}
public int getCachedConsolidateNumSecrets() {
- return mSharedPreferences.getInt(Pref.CACHED_CONSOLIDATE_SECRETS, 100);
+ return mSharedPreferences.getInt(Pref.CACHED_CONSOLIDATE_SECRETS, -1);
}
public void setCachedConsolidateNumSecrets(int value) {
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 5f55eedd5..4f8b50a94 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -829,12 +829,12 @@ public class ProviderHelper {
public ConsolidateResult consolidateDatabaseStep1(Progressable progress) {
// 1a. fetch all secret keyrings into a cache file
- log(LogLevel.START, LogType.MSG_CON, mIndent);
+ log(LogLevel.START, LogType.MSG_CON);
mIndent += 1;
try {
- log(LogLevel.DEBUG, LogType.MSG_CON_SAVE_SECRET, mIndent);
+ log(LogLevel.DEBUG, LogType.MSG_CON_SAVE_SECRET);
mIndent += 1;
final Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[]{
@@ -842,6 +842,7 @@ public class ProviderHelper {
}, KeyRings.HAS_ANY_SECRET + " = 1", null, null);
if (cursor == null || !cursor.moveToFirst()) {
+ log(LogLevel.ERROR, LogType.MSG_CON_ERROR_DB);
return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
}
@@ -883,7 +884,8 @@ public class ProviderHelper {
});
} catch (IOException e) {
- Log.e(Constants.TAG, "error saving secret");
+ Log.e(Constants.TAG, "error saving secret", e);
+ log(LogLevel.ERROR, LogType.MSG_CON_ERROR_IO_SECRET);
return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
} finally {
mIndent -= 1;
@@ -892,7 +894,7 @@ public class ProviderHelper {
// 1b. fetch all public keyrings into a cache file
try {
- log(LogLevel.DEBUG, LogType.MSG_CON_SAVE_PUBLIC, mIndent);
+ log(LogLevel.DEBUG, LogType.MSG_CON_SAVE_PUBLIC);
mIndent += 1;
final Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[]{
@@ -900,10 +902,11 @@ public class ProviderHelper {
}, null, null, null);
if (cursor == null || !cursor.moveToFirst()) {
+ log(LogLevel.ERROR, LogType.MSG_CON_ERROR_DB);
return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
}
- Preferences.getPreferences(mContext).setCachedConsolidateNumSecrets(cursor.getCount());
+ Preferences.getPreferences(mContext).setCachedConsolidateNumPublics(cursor.getCount());
FileImportCache cache =
new FileImportCache(mContext, "consolidate_public.pcl");
@@ -941,31 +944,48 @@ public class ProviderHelper {
});
} catch (IOException e) {
- Log.e(Constants.TAG, "error saving public");
+ Log.e(Constants.TAG, "error saving public", e);
+ log(LogLevel.ERROR, LogType.MSG_CON_ERROR_IO_PUBLIC);
return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
} finally {
mIndent -= 1;
}
+ log(LogLevel.INFO, LogType.MSG_CON_CRITICAL_IN);
Preferences.getPreferences(mContext).setCachedConsolidate(true);
- return consolidateDatabaseStep2(progress);
+ return consolidateDatabaseStep2(progress, false);
}
public ConsolidateResult consolidateDatabaseStep2(Progressable progress) {
+ return consolidateDatabaseStep2(progress, true);
+ }
+
+ private ConsolidateResult consolidateDatabaseStep2(Progressable progress, boolean recovery) {
+
Preferences prefs = Preferences.getPreferences(mContext);
- if ( ! prefs.getCachedConsolidate()) {
- log(LogLevel.ERROR, LogType.MSG_CON_ERROR_BAD_STATE);
- return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
- }
// Set flag that we have a cached consolidation here
int numSecrets = prefs.getCachedConsolidateNumSecrets();
int numPublics = prefs.getCachedConsolidateNumPublics();
+ if (recovery) {
+ if (numSecrets >= 0 && numPublics >= 0) {
+ log(LogLevel.START, LogType.MSG_CON_RECOVER, numSecrets, Integer.toString(numPublics));
+ } else {
+ log(LogLevel.START, LogType.MSG_CON_RECOVER_UNKNOWN);
+ }
+ mIndent += 1;
+ }
+
+ if ( ! prefs.getCachedConsolidate()) {
+ log(LogLevel.ERROR, LogType.MSG_CON_ERROR_BAD_STATE);
+ return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
+ }
+
// 2. wipe database (IT'S DANGEROUS)
- log(LogLevel.DEBUG, LogType.MSG_CON_DB_CLEAR, mIndent);
+ log(LogLevel.DEBUG, LogType.MSG_CON_DB_CLEAR);
new KeychainDatabase(mContext).clearDatabase();
FileImportCache cacheSecret =
@@ -974,51 +994,71 @@ public class ProviderHelper {
new FileImportCache(mContext, "consolidate_public.pcl");
// 3. Re-Import secret keyrings from cache
- try {
- log(LogLevel.DEBUG, LogType.MSG_CON_REIMPORT_SECRET, mIndent, numSecrets);
+ if (numSecrets > 0) try {
+ log(LogLevel.DEBUG, LogType.MSG_CON_REIMPORT_SECRET, numSecrets);
mIndent += 1;
- new PgpImportExport(mContext, this, new ProgressFixedScaler(progress, 10, 25, 100, R.string.progress_con_reimport))
+ new PgpImportExport(mContext, this,
+ new ProgressFixedScaler(progress, 10, 25, 100, R.string.progress_con_reimport))
.importKeyRings(cacheSecret.readCache(false), numSecrets);
} catch (IOException e) {
- Log.e(Constants.TAG, "error importing secret");
+ Log.e(Constants.TAG, "error importing secret", e);
+ log(LogLevel.ERROR, LogType.MSG_CON_ERROR_SECRET);
return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
} finally {
mIndent -= 1;
+ } else {
+ log(LogLevel.DEBUG, LogType.MSG_CON_REIMPORT_SECRET_SKIP);
}
// 4. Re-Import public keyrings from cache
- try {
- log(LogLevel.DEBUG, LogType.MSG_CON_REIMPORT_PUBLIC, mIndent, numPublics);
+ if (numPublics > 0) try {
+ log(LogLevel.DEBUG, LogType.MSG_CON_REIMPORT_PUBLIC, numPublics);
mIndent += 1;
- new PgpImportExport(mContext, this, new ProgressScaler(progress, 25, 99, 100))
+ new PgpImportExport(mContext, this,
+ new ProgressFixedScaler(progress, 25, 99, 100, R.string.progress_con_reimport))
.importKeyRings(cachePublic.readCache(false), numPublics);
} catch (IOException e) {
- Log.e(Constants.TAG, "error importing public");
+ Log.e(Constants.TAG, "error importing public", e);
+ log(LogLevel.ERROR, LogType.MSG_CON_ERROR_PUBLIC);
return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
} finally {
mIndent -= 1;
+ } else {
+ log(LogLevel.DEBUG, LogType.MSG_CON_REIMPORT_PUBLIC_SKIP);
}
+ log(LogLevel.INFO, LogType.MSG_CON_CRITICAL_OUT);
Preferences.getPreferences(mContext).setCachedConsolidate(false);
// 5. Delete caches
try {
+ log(LogLevel.DEBUG, LogType.MSG_CON_DELETE_SECRET);
+ mIndent += 1;
cacheSecret.delete();
} catch (IOException e) {
- // doesn't really matter
+ // doesn't /really/ matter
Log.e(Constants.TAG, "IOException during delete of secret cache", e);
+ log(LogLevel.WARN, LogType.MSG_CON_WARN_DELETE_SECRET);
+ } finally {
+ mIndent -= 1;
}
+
try {
+ log(LogLevel.DEBUG, LogType.MSG_CON_DELETE_PUBLIC);
+ mIndent += 1;
cachePublic.delete();
} catch (IOException e) {
- // doesn't really matter
+ // doesn't /really/ matter
Log.e(Constants.TAG, "IOException during deletion of public cache", e);
+ log(LogLevel.WARN, LogType.MSG_CON_WARN_DELETE_PUBLIC);
+ } finally {
+ mIndent -= 1;
}
progress.setProgress(100, 100);
- log(LogLevel.OK, LogType.MSG_CON_SUCCESS, mIndent);
+ log(LogLevel.OK, LogType.MSG_CON_SUCCESS);
mIndent -= 1;
return new ConsolidateResult(ConsolidateResult.RESULT_OK, mLog);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index 3f478cfed..cf9f69033 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -390,14 +390,29 @@ public class OperationResultParcel implements Parcelable {
MSG_MF_UNLOCK (R.string.msg_mf_unlock),
// consolidate
- MSG_CON (R.string.msg_con),
- MSG_CON_ERROR_BAD_STATE (R.string.msg_con_error_bad_state),
- MSG_CON_SAVE_SECRET (R.string.msg_con_save_secret),
- MSG_CON_SAVE_PUBLIC (R.string.msg_con_save_public),
+ MSG_CON_CRITICAL_IN (R.string.msg_con_critical_in),
+ MSG_CON_CRITICAL_OUT (R.string.msg_con_critical_out),
MSG_CON_DB_CLEAR (R.string.msg_con_db_clear),
- MSG_CON_REIMPORT_SECRET (R.plurals.msg_con_reimport_secret),
- MSG_CON_REIMPORT_PUBLIC (R.plurals.msg_con_reimport_public),
+ MSG_CON_DELETE_PUBLIC (R.string.msg_con_delete_public),
+ MSG_CON_DELETE_SECRET (R.string.msg_con_delete_secret),
+ MSG_CON_ERROR_BAD_STATE (R.string.msg_con_error_bad_state),
+ MSG_CON_ERROR_DB (R.string.msg_con_error_db),
+ MSG_CON_ERROR_IO_PUBLIC (R.string.msg_con_error_io_public),
+ MSG_CON_ERROR_IO_SECRET (R.string.msg_con_error_io_secret),
+ MSG_CON_ERROR_PUBLIC (R.string.msg_con_error_public),
+ MSG_CON_ERROR_SECRET (R.string.msg_con_error_secret),
+ MSG_CON_RECOVER (R.plurals.msg_con_recover),
+ MSG_CON_RECOVER_UNKNOWN (R.string.msg_con_recover_unknown),
+ MSG_CON_REIMPORT_PUBLIC (R.string.msg_con_reimport_public),
+ MSG_CON_REIMPORT_PUBLIC_SKIP (R.string.msg_con_reimport_public_skip),
+ MSG_CON_REIMPORT_SECRET (R.string.msg_con_reimport_secret),
+ MSG_CON_REIMPORT_SECRET_SKIP (R.string.msg_con_reimport_secret_skip),
+ MSG_CON (R.string.msg_con),
+ MSG_CON_SAVE_PUBLIC (R.string.msg_con_save_public),
+ MSG_CON_SAVE_SECRET (R.string.msg_con_save_secret),
MSG_CON_SUCCESS (R.string.msg_con_success),
+ MSG_CON_WARN_DELETE_PUBLIC (R.string.msg_con_warn_delete_public),
+ MSG_CON_WARN_DELETE_SECRET (R.string.msg_con_warn_delete_secret),
;
private final int mMsgId;
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index e506bf488..c00449f8e 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -677,15 +677,33 @@
Saving secret keyrings
Saving public keyrings
Clearing database
-
- - Reimporting one secret key
- - Reimporting %d secret keys
+ Successfully consolidated database
+ Entering critical phase
+ Leaving critical phase
+ Deleting public keyring cache file
+ Deleting secret keyring cache file
+ Error opening database!
+ IO error writing public keys to cache!
+ IO error writing secret keys to cache!
+ Error reimporting public keys!
+ Error reimporting secret keys!
+
+ - Recovering consolidation with one secret and %s public keys
+ - Recovering consolidation with %d secret and %s public keys
+ Recovering from unknown state
- Reimporting one public key
- - Reimporting %d public keys
+ - Reimporting %d public keys
- Successfully consolidated database
+ No public keys to reimport, skipping…
+
+ - Reimporting one secret key
+ - Reimporting %d secret keys
+
+ No secret keys to reimport, skipping…
+ Exception deleting public cache file
+ Exception deleting public cache file
Click to clear cached passphrases
From 16ab7610061726110f917533348f4c37a0690321 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Tue, 19 Aug 2014 18:12:19 +0200
Subject: [PATCH 077/142] Fix strings
---
.../keychain/provider/ProviderHelper.java | 2 +-
.../keychain/service/OperationResultParcel.java | 4 ++--
OpenKeychain/src/main/res/values/strings.xml | 8 ++++----
3 files changed, 7 insertions(+), 7 deletions(-)
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 4f8b50a94..2867967ff 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -972,7 +972,7 @@ public class ProviderHelper {
if (recovery) {
if (numSecrets >= 0 && numPublics >= 0) {
- log(LogLevel.START, LogType.MSG_CON_RECOVER, numSecrets, Integer.toString(numPublics));
+ log(LogLevel.START, LogType.MSG_CON_RECOVER, numSecrets, numPublics);
} else {
log(LogLevel.START, LogType.MSG_CON_RECOVER_UNKNOWN);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index cf9f69033..91939739a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -403,9 +403,9 @@ public class OperationResultParcel implements Parcelable {
MSG_CON_ERROR_SECRET (R.string.msg_con_error_secret),
MSG_CON_RECOVER (R.plurals.msg_con_recover),
MSG_CON_RECOVER_UNKNOWN (R.string.msg_con_recover_unknown),
- MSG_CON_REIMPORT_PUBLIC (R.string.msg_con_reimport_public),
+ MSG_CON_REIMPORT_PUBLIC (R.plurals.msg_con_reimport_public),
MSG_CON_REIMPORT_PUBLIC_SKIP (R.string.msg_con_reimport_public_skip),
- MSG_CON_REIMPORT_SECRET (R.string.msg_con_reimport_secret),
+ MSG_CON_REIMPORT_SECRET (R.plurals.msg_con_reimport_secret),
MSG_CON_REIMPORT_SECRET_SKIP (R.string.msg_con_reimport_secret_skip),
MSG_CON (R.string.msg_con),
MSG_CON_SAVE_PUBLIC (R.string.msg_con_save_public),
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index c00449f8e..1bd412d4d 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -688,18 +688,18 @@
Error reimporting public keys!
Error reimporting secret keys!
- - Recovering consolidation with one secret and %s public keys
- - Recovering consolidation with %d secret and %s public keys
+ - Recovering consolidation with %1$d secret and %2$d public keys
+ - Recovering consolidation with %1$d secret and %2$d public keys
Recovering from unknown state
- Reimporting one public key
- - Reimporting %d public keys
+ - Reimporting %d public keys
No public keys to reimport, skipping…
- Reimporting one secret key
- - Reimporting %d secret keys
+ - Reimporting %d secret keys
No secret keys to reimport, skipping…
Exception deleting public cache file
From 1a6734f29c0a07c58f356e3861530adfe63f684a Mon Sep 17 00:00:00 2001
From: mar-v-in
Date: Tue, 19 Aug 2014 18:54:48 +0200
Subject: [PATCH 078/142] Fix mime types, #781
---
OpenKeychain/src/main/AndroidManifest.xml | 6 ++++--
.../org/sufficientlysecure/keychain/ui/EncryptActivity.java | 2 +-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml
index 142690abb..a1ad7139d 100644
--- a/OpenKeychain/src/main/AndroidManifest.xml
+++ b/OpenKeychain/src/main/AndroidManifest.xml
@@ -176,7 +176,7 @@
android:label="@string/title_decrypt"
android:windowSoftInputMode="stateHidden">
-
+
@@ -184,7 +184,9 @@
-
+
+
+
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
index 59a433af3..d33e5116c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
@@ -382,7 +382,7 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
sendIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
sendIntent.putExtra(Intent.EXTRA_STREAM, mOutputUris);
}
- sendIntent.setType("application/pgp-encrypted");
+ sendIntent.setType("application/octet-stream");
}
if (!isModeSymmetric() && mEncryptionUserIds != null) {
Set users = new HashSet();
From d26c6b1a08448c6fa884b8b7591d625006d1ac3b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Wed, 20 Aug 2014 09:20:30 +0200
Subject: [PATCH 079/142] Update keybase lib
---
extern/KeybaseLib | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extern/KeybaseLib b/extern/KeybaseLib
index e214906a5..2e8f38f6e 160000
--- a/extern/KeybaseLib
+++ b/extern/KeybaseLib
@@ -1 +1 @@
-Subproject commit e214906a52233bb6f230bc6759ac7be803d24bf5
+Subproject commit 2e8f38f6e38fe77b828826d3c6e8cb89a8a9aee5
From d6d68622cee488d06f680334f3c4f53d4d410bca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Wed, 20 Aug 2014 11:03:56 +0200
Subject: [PATCH 080/142] Travis is now stable
---
README.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/README.md b/README.md
index a9b03b2c3..7338f1071 100644
--- a/README.md
+++ b/README.md
@@ -5,8 +5,6 @@ For a more detailed description and installation instructions go to http://www.o
### Travis CI Build Status
-Currently, some tests could fail even when everything is okay!
-
[](https://travis-ci.org/open-keychain/open-keychain)
## How to help the project?
From 70426041dfb828c7117b05fd25ae6d077fdd501e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?=
Date: Wed, 20 Aug 2014 11:09:41 +0200
Subject: [PATCH 081/142] Pull from transifex
---
.../src/main/res/raw-cs/help_nfc_beam.html | 10 +-
.../src/main/res/raw-cs/help_start.html | 22 +-
.../src/main/res/raw-cs/help_wot.html | 2 +-
.../src/main/res/raw-cs/nfc_beam_share.html | 8 +-
.../src/main/res/raw-de/help_start.html | 6 +-
.../src/main/res/raw-es/help_changelog.html | 140 +++++------
.../src/main/res/raw-fr/help_changelog.html | 6 +-
.../src/main/res/raw-it/help_changelog.html | 168 +++++++-------
.../src/main/res/raw-ja/help_changelog.html | 4 +-
.../src/main/res/raw-pt/help_about.html | 54 +++++
.../src/main/res/raw-pt/help_changelog.html | 170 ++++++++++++++
.../src/main/res/raw-pt/help_nfc_beam.html | 12 +
.../src/main/res/raw-pt/help_start.html | 22 ++
.../src/main/res/raw-pt/help_wot.html | 17 ++
.../src/main/res/raw-pt/nfc_beam_share.html | 11 +
.../src/main/res/raw-uk/help_about.html | 20 +-
.../src/main/res/raw-uk/help_changelog.html | 168 +++++++-------
.../src/main/res/values-cs/strings.xml | 124 +++++++++-
.../src/main/res/values-de/strings.xml | 42 +++-
.../src/main/res/values-es/strings.xml | 55 ++++-
.../src/main/res/values-et/strings.xml | 1 +
.../src/main/res/values-fr/strings.xml | 65 ++++--
.../src/main/res/values-it/strings.xml | 84 ++++++-
.../src/main/res/values-ja/strings.xml | 47 +++-
.../src/main/res/values-nl/strings.xml | 3 +-
.../src/main/res/values-pl/strings.xml | 1 +
.../src/main/res/values-pt/strings.xml | 44 ++++
.../src/main/res/values-ru/strings.xml | 6 +-
.../src/main/res/values-sl/strings.xml | 5 +-
.../src/main/res/values-tr/strings.xml | 1 +
.../src/main/res/values-uk/strings.xml | 218 +++++++++++++++++-
.../src/main/res/values-zh/strings.xml | 1 +
32 files changed, 1201 insertions(+), 336 deletions(-)
create mode 100644 OpenKeychain/src/main/res/raw-pt/help_about.html
create mode 100644 OpenKeychain/src/main/res/raw-pt/help_changelog.html
create mode 100644 OpenKeychain/src/main/res/raw-pt/help_nfc_beam.html
create mode 100644 OpenKeychain/src/main/res/raw-pt/help_start.html
create mode 100644 OpenKeychain/src/main/res/raw-pt/help_wot.html
create mode 100644 OpenKeychain/src/main/res/raw-pt/nfc_beam_share.html
create mode 100644 OpenKeychain/src/main/res/values-pt/strings.xml
diff --git a/OpenKeychain/src/main/res/raw-cs/help_nfc_beam.html b/OpenKeychain/src/main/res/raw-cs/help_nfc_beam.html
index 88492731c..d691df871 100644
--- a/OpenKeychain/src/main/res/raw-cs/help_nfc_beam.html
+++ b/OpenKeychain/src/main/res/raw-cs/help_nfc_beam.html
@@ -1,12 +1,12 @@
-How to receive keys
+Jak přijmout klíče
-- Go to your partners contacts and open the contact you want to share.
-- Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.
-- After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.
-- Tap the card and the content will then load on the your device.
+- Navigujte na kontakt vašeho partnera a otevřete ten který chcete sdílet.
+- Podržte dvě zařízení zády k sobě (musí se téměř dotýkat) a ucítíte vibraci.
+- Po tom co ucítíte vibraci, uvidíte že se obsah na displeji zařízení vašeho partnera změní na objekt typu karta s animací na pozadí připomínající rychlost warpu ze Star Treku.
+- Tapněte na kartu a obsach se nahraje do zařízení.
diff --git a/OpenKeychain/src/main/res/raw-cs/help_start.html b/OpenKeychain/src/main/res/raw-cs/help_start.html
index 51a76c01e..eaffc2389 100644
--- a/OpenKeychain/src/main/res/raw-cs/help_start.html
+++ b/OpenKeychain/src/main/res/raw-cs/help_start.html
@@ -1,22 +1,22 @@
-Getting started
-First you need a personal secret key. Create one via the option menus in "Keys" or import existing secret keys. Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.
+Začínáme
+Nejprve potřebujete osobní tajný klíč. Vytvořte si ho pomocí volby v menu v sekci "Klíče" nebo importujte existující tajné klíče. Následně můžete stáhnout klíče vašich známých nebo si je vyměnit pomocí QR kódu případně NFC.
-It is recommended that you install OI File Manager for enhanced file selection and Barcode Scanner to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.
+Doporučujeme instalaci OI File Manager pro zlepšení práce se soubory a Barcode Scanner pro skenování generovaných QR kódů. Kliknutí na odkazy otevře Google Play Store nebo F-Droid odkud můžete začít installovat.
-Applications
-Several applications support OpenKeychain to encrypt/sign your private communication:

K-9 Mail: OpenKeychain support available in current alpha build!

Conversations: Jabber/XMPP client

PGPAuth: App to send a PGP-signed request to a server to open or close something, e.g. a door
+Aplikace
+Několik aplikací umožňuje šifrovat/podepsat privátní komunikaci pomocí OpenKeychain:

K-9 Mail: podpora OpenKeychain v aktualní verzi alpha build!

Konverzace: Jabber/XMPP client

PGPAuth: Appka sloužící k odesílání požadavků podepsaných PGP na servery pro otevření nebo zavření něčeho, třeba dveří
-I found a bug in OpenKeychain!
-Please report the bug using the issue tracker of OpenKeychain.
+Našel jsem bug v OpenChain!
+Reportujte chyby pomocí issue trackeru OpenKeychain.
-Contribute
-If you want to help us developing OpenKeychain by contributing code follow our small guide on Github.
+Přispět
+Pokud chcete pomoci vyvýjet OpenKeychain tak, že přispějete svými kodérskými schopnostmi přečtěte si naší malou příručku na Githubu.
-Translations
-Help translating OpenKeychain! Everybody can participate at OpenKeychain on Transifex.
+Překlady
+Pomozte s překladem OpenKeychain! Každý může participovat na OpenKeychain na Transifexu
diff --git a/OpenKeychain/src/main/res/raw-cs/help_wot.html b/OpenKeychain/src/main/res/raw-cs/help_wot.html
index 29790139b..30288f2bb 100644
--- a/OpenKeychain/src/main/res/raw-cs/help_wot.html
+++ b/OpenKeychain/src/main/res/raw-cs/help_wot.html
@@ -1,7 +1,7 @@
-Web of Trust
+Síť důvěry
The Web of Trust describes the part of PGP which deals with creation and bookkeeping of certifications. It provides mechanisms to help the user keep track of who a public key belongs to, and share this information with others; To ensure the privacy of encrypted communication, it is essential to know that the public key you encrypt to belongs to the person you think it does.
Support in OpenKeychain
diff --git a/OpenKeychain/src/main/res/raw-cs/nfc_beam_share.html b/OpenKeychain/src/main/res/raw-cs/nfc_beam_share.html
index 083e055c7..09128be62 100644
--- a/OpenKeychain/src/main/res/raw-cs/nfc_beam_share.html
+++ b/OpenKeychain/src/main/res/raw-cs/nfc_beam_share.html
@@ -2,10 +2,10 @@
-- Make sure that NFC is turned on in Settings > More > NFC and make sure that Android Beam is also on in the same section.
-- Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.
-- After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.
-- Tap the card and the content will then load on the other person’s device.
+- Ujistěte se, že NFC je zapnuto v Nastavení > Další > NFC a ujistěte se, že Android Beam ve stejné sekci je také zapnutý.
+- Podržte dvě zařízení zády k sobě (musí se téměř dotýkat) a ucítíte vibraci.
+- Po tom co ucítíte vibraci, uvidíte že se obsah na displeji zařízení vašeho partnera změní na objekt typu karta s animací na pozadí připomínající rychlost warpu ze Star Treku.
+- Tapněte na kartu a obsach se nahraje do zařízení.
diff --git a/OpenKeychain/src/main/res/raw-de/help_start.html b/OpenKeychain/src/main/res/raw-de/help_start.html
index dfff2bc03..0764c9ebb 100644
--- a/OpenKeychain/src/main/res/raw-de/help_start.html
+++ b/OpenKeychain/src/main/res/raw-de/help_start.html
@@ -1,7 +1,7 @@
-Los gehts
+Los geht's
Zuerst benötigen Sie einen privaten Schlüssel. Erstellen Sie einen Schlüssel über den Eintrag "Schlüssel" im Menu oder importieren Sie bestehende private Schlüssel. Anschließend können Sie die Schlüssel ihrer Freunde runterladen oder Sie über QR-Codes oder NFC austauschen.
Es wird empfohlen, dass Sie den OI File Manager für ein verbessertes Dateihandling installieren, sowie den Barcode Scanner installieren um erstellte QR-Codes zu scannen. Die Links führen entweder zu Google Play oder zu F-Droid zur Installation.
@@ -13,10 +13,10 @@
Bitte berichten Sie Bugs mithilfe des Issue Trackers der OpenKeychain.
Unterstützen
-Wenn Sie uns bei der Entwickelung von OpenKeychain durch das Beisteuern von Code helfen wollt, schaut euch unsere kurze Anleitung auf Github an.
+Wenn Sie uns bei der Entwickelung von OpenKeychain durch das Beisteuern von Code helfen wollen, schauen Sie unsere kurze Anleitung auf Github an.
Übersetzungen
-Hilf mit OpenKeychain zu übersetzten! Jeder kann auf OpenKeychain auf Transifex mitmachen.
+Hilf mit, OpenKeychain zu übersetzten! Jeder kann auf OpenKeychain auf Transifex mitmachen.
diff --git a/OpenKeychain/src/main/res/raw-es/help_changelog.html b/OpenKeychain/src/main/res/raw-es/help_changelog.html
index a6b2d269d..0530f3999 100644
--- a/OpenKeychain/src/main/res/raw-es/help_changelog.html
+++ b/OpenKeychain/src/main/res/raw-es/help_changelog.html
@@ -7,7 +7,7 @@
Edición de clave: Tremendo nuevo diseño, revocación de clave
Importación de clave: Impresionante nuevo diseño, conexiones seguras al servidor de claves vía hkps, el servidor de claves resuelve mediante registros DNS SRV
Nueva pantalla de primer inicio
-Nueva pantalla de creación de clave: Autocompletado del nombre y correo electrónico basado en sus cuentas Android personales
+Nueva pantalla de creación: autocompletado de nombre y correo electrónico basado en sus cuentas de Android personales
Cifrado de fichero: Pasmante nuevo diseño, soporte para cifrar múltiples ficheros.
Nuevos iconos para mostrar el estado de la clave (por Brennan Novak)
Importante reparacion de fallo: Ahora es posible la importación de grandes colecciones de claves desde un fichero
@@ -33,13 +33,13 @@
Soporte para claves secretas parciales de GnuPG (gracias a Vincent Breitmoser)
Nuevo diseño para verificación de firma
Tamaño de clave personalizado (gracias a Greg Witczak)
-Fix share-functionality from other apps
+Repara la funcionalidad de compartido desde otras aplicaciones
2.5
-- Fix decryption of symmetric pgp messages/files
-- Refactored edit key screen (thanks to Ash Hughes)
-- New modern design for encrypt/decrypt screens
+- Repara el descifrado de mensajes/ficheros pgp simétricos
+- Pantalla de edición de clave refactorizada (gracias a Ash Hughes)
+- Nuevo diseño moderno para pantallas de cifrado/descifrado
- OpenPGP API versión 3 (múltiples cuentas API, reparaciones internas, comprobación de claves)
2.4
@@ -47,45 +47,45 @@
Además de varios parches pequeños, un notable número de correcciones fueron hechas por las siguientes personas (en orden alfabético):
Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.
-- New unified key list
-- Colorized key fingerprint
-- Support for keyserver ports
-- Deactivate possibility to generate weak keys
-- Much more internal work on the API
-- Certify user ids
-- Keyserver query based on machine-readable output
-- Lock navigation drawer on tablets
-- Suggestions for emails on creation of keys
-- Search in public key lists
-- And much more improvements and fixes…
+- Nueva lista unificada de claves
+- Huella de validación de clave coloreada
+- Soporte para puertos de servidores de claves
+- Desactiva la posibilidad de generar claves débiles.
+- Mucho más trabajo interno en la API
+- Certifica las identidades de usuario
+- Petición al servidor de claves basada en salida legible-por-máquina
+- Cerrar panel lateral de navegación en tabletas
+- Sugerencias para correos electrónicos al crear claves
+- Buscar en listas de claves públicas
+- Añadir muchas más mejoras y reparaciones...
2.3.1
-- Hotfix for crash when upgrading from old versions
+- Reparación para fallo al actualizar desde versiones antiguas.
2.3
-- Remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)
-- Fix setting expiry dates on keys (thanks to Ash Hughes)
-- More internal fixes when editing keys (thanks to Ash Hughes)
-- Querying keyservers directly from the import screen
-- Fix layout and dialog style on Android 2.2-3.0
-- Fix crash on keys with empty user ids
-- Fix crash and empty lists when coming back from signing screen
+- Elimina la exportación innecesaria de claves públicas al exportar claves secretas (privadas) (gracias a Ash Hughes)
+- Repara el establecimiento de fechas de expiración de claves (gracias a Ash Hughes)
+- Más reparaciones internas al editar claves (gracias a Ash Hughes)
+- Realización de peticiones a los servidores de claves desde la pantalla de importación
+- Repara la disposición y el estilo del cuadro de diálogo en Android 2.2-3.0
+- Repara fallos en claves con identidades de usuario vacías
+- Repara fallos y listas vacías al volver desde la pantalla de firmado
- Bouncy Castle (librería criptográfica) actualizada de 1.47 a 1.50 y compilada desde la fuente
-- Fix upload of key from signing screen
+- Repara la subida de clave desde la pantalla de firmado
2.2
-- New design with navigation drawer
-- New public key list design
-- New public key view
-- Bug fixes for importing of keys
-- Key cross-certification (thanks to Ash Hughes)
-- Handle UTF-8 passwords properly (thanks to Ash Hughes)
-- First version with new languages (thanks to the contributors on Transifex)
-- Sharing of keys via QR Codes fixed and improved
-- Package signature verification for API
+- Nuevo diseño con panel lateral de navegación
+- Nuevo diseño de lista de claves públicas
+- Nueva vista de clave pública
+- Reparación de fallos para la importación de claves
+- Certificación-cruzada de clave (gracias a Ash Hughes)
+- Tratamiento adecuado de contraseñas UTF-8 (gracias a Ash Hughes)
+- Primera versión nuevos idiomas (gracias a los contribuidores en Transifex)
+- Compartición de claves mediante códigos QR reparada y mejorada
+- Verificación de firma de paquetes para la API
2.1.1
@@ -93,65 +93,65 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
2.1
-- Lots of bug fixes
-- New API for developers
+- Muchas reparaciones de fallos
+- Nueva API para desarrolladores
- corrección del bug PRNG por Google
2.0
-- Complete redesign
-- Share public keys via qr codes, nfc beam
-- Sign keys
-- Upload keys to server
-- Fixes import issues
-- New AIDL API
+- Rediseño completo
+- Compartido de claves públicas mediante códigos qr, nfc beam
+- Firmar claves
+- Subir claves al servidor
+- Repara problemas de importación
+- Nueva API AIDL
1.0.8
-- Basic keyserver support
+- Soporte básico de servidor de claves
- App2sd
-- More choices for pass phrase cache: 1, 2, 4, 8, hours
-- Translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)
-- Bugfixes
-- Optimizations
+- Más opciones para caché de frase contraseña: 1, 2, 4, 8 horas
+- Traducciones: noruego (gracias, Sander Danielsen), chino (gracias, Zhang Fredrick)
+- Reparaciones de fallos
+- Optimizaciones
1.0.7
-- Fixed problem with signature verification of texts with trailing newline
-- More options for pass phrase cache time to live (20, 40, 60 mins)
+- Reparado un problema con la verificación de firma de textos con una nueva línea al principio
+- Más opciones para el periodo de vida en caché de la frase contraseña (20, 40, 60 mins)
1.0.6
-- Account adding crash on Froyo fixed
-- Secure file deletion
-- Option to delete key file after import
-- Stream encryption/decryption (gallery, etc.)
-- New options (language, force v3 signatures)
-- Interface changes
-- Bugfixes
+- Reparado el fallo de la adición de cuenta en Froyo
+- Borrado seguro de fichero
+- Opción para borrar fichero de clave después de importar
+- Cifrado/descifrado del stream (galería, etc.)
+- Nuevas opciones (idioma, forzar firmas v3)
+- Cambios en la interfaz
+- Reparaciones de fallos
1.0.5
- traducciones a alemán e italiano
-- Much smaller package, due to reduced BC sources
-- New preferences GUI
-- Layout adjustment for localization
-- Signature bugfix
+- Paquete mucho más pequeño, debido a fuentes de codec de bitrate (BC) reducido
+- Nueva interfaz gráfica (GUI) de prefencias
+- Ajuste de la disposición para localización
+- Reparación de firma
1.0.4
-- Fixed another crash caused by some SDK bug with query builder
+- Reparado otro fallo causado por algún fallo del kit de desarrollo de software (SDK) con el constructor de peticiones
1.0.3
-- Fixed crashes during encryption/signing and possibly key export
+- Reparados fallos durante el cifrado/firmado y posiblemente el exportado de clave
1.0.2
-- Filterable key lists
-- Smarter pre-selection of encryption keys
-- New Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers
-- Fixes and additional features (key preselection) for K-9 Mail, new beta build available
+- Listas de claves filtrables
+- Pre-selección de claves de cifrado más inteligente
+- Nuevo objeto Intent que maneja VIEW y SEND (ver y enviar), permite que los ficheros sean cifrados/descifrados fuera de los administradores de ficheros.
+- Reparaciones y características adicionales (preselección de clave) para K-9 Mail, nueva versión beta disponible
1.0.1
@@ -160,11 +160,11 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
1.0.0
- integración con K-9 Mail, APG compatible con la compilación beta de K-9 Mail
-- Support of more file managers (including ASTRO)
+- Soporte de más administradores de ficheros (incluyendo ASTRO)
- traducción al esloveno
-- New database, much faster, less memory usage
-- Defined Intents and content provider for other apps
-- Bugfixes
+- Nueva base de datos, mucho más rápida, menos uso de memoria
+- Definidos objetos Intent y proveedores de contenido para otras aplicaciones
+- Reparaciones de fallos