Merge remote-tracking branch 'origin/master' into db-overhaul
Conflicts: OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
This commit is contained in:
@@ -47,7 +47,7 @@ public final class Constants {
|
||||
|
||||
public static final class Path {
|
||||
public static final String APP_DIR = Environment.getExternalStorageDirectory()
|
||||
+ "/OpenPGP-Keychain";
|
||||
+ "/OpenKeychain";
|
||||
public static final String APP_DIR_FILE_SEC = APP_DIR + "/secexport.asc";
|
||||
public static final String APP_DIR_FILE_PUB = APP_DIR + "/pubexport.asc";
|
||||
}
|
||||
@@ -55,10 +55,10 @@ public final class Constants {
|
||||
public static final class Pref {
|
||||
public static final String DEFAULT_ENCRYPTION_ALGORITHM = "defaultEncryptionAlgorithm";
|
||||
public static final String DEFAULT_HASH_ALGORITHM = "defaultHashAlgorithm";
|
||||
public static final String DEFAULT_ASCII_ARMOUR = "defaultAsciiArmour";
|
||||
public static final String DEFAULT_ASCII_ARMOR = "defaultAsciiArmor";
|
||||
public static final String DEFAULT_MESSAGE_COMPRESSION = "defaultMessageCompression";
|
||||
public static final String DEFAULT_FILE_COMPRESSION = "defaultFileCompression";
|
||||
public static final String PASS_PHRASE_CACHE_TTL = "passphraseCacheTtl";
|
||||
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";
|
||||
@@ -74,7 +74,12 @@ public final class Constants {
|
||||
public static final Class DECRYPT = DecryptActivity.class;
|
||||
public static final Class IMPORT_KEYS = ImportKeysActivity.class;
|
||||
public static final Class REGISTERED_APPS_LIST = AppsListActivity.class;
|
||||
public static final Class[] ARRAY = new Class[]{KEY_LIST, ENCRYPT, DECRYPT,
|
||||
IMPORT_KEYS, REGISTERED_APPS_LIST};
|
||||
public static final Class[] ARRAY = new Class[]{
|
||||
KEY_LIST,
|
||||
ENCRYPT,
|
||||
DECRYPT,
|
||||
IMPORT_KEYS,
|
||||
REGISTERED_APPS_LIST
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,16 +17,17 @@
|
||||
|
||||
package org.sufficientlysecure.keychain;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import android.app.Application;
|
||||
import android.os.Environment;
|
||||
|
||||
import org.spongycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
import org.sufficientlysecure.keychain.util.PRNGFixes;
|
||||
|
||||
import android.app.Application;
|
||||
import android.os.Environment;
|
||||
import java.io.File;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
|
||||
public class KeychainApplication extends Application {
|
||||
|
||||
@@ -40,14 +41,14 @@ public class KeychainApplication extends Application {
|
||||
|
||||
/*
|
||||
* Sets Bouncy (Spongy) Castle as preferred security provider
|
||||
*
|
||||
*
|
||||
* insertProviderAt() position starts from 1
|
||||
*/
|
||||
Security.insertProviderAt(new BouncyCastleProvider(), 1);
|
||||
|
||||
/*
|
||||
* apply RNG fixes
|
||||
*
|
||||
*
|
||||
* among other things, executes Security.insertProviderAt(new
|
||||
* LinuxPRNGSecureRandomProvider(), 1) for Android <= SDK 17
|
||||
*/
|
||||
|
||||
@@ -17,20 +17,20 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.compatibility;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ClipboardReflection {
|
||||
|
||||
private static final String clipboardLabel = "Keychain";
|
||||
|
||||
/**
|
||||
* Wrapper around ClipboardManager based on Android version using Reflection API
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
* @param text
|
||||
*/
|
||||
@@ -57,7 +57,7 @@ public class ClipboardReflection {
|
||||
|
||||
/**
|
||||
* Wrapper around ClipboardManager based on Android version using Reflection API
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
public static CharSequence getClipboardText(Context context) {
|
||||
|
||||
@@ -30,18 +30,12 @@ import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
||||
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.ui.dialog.DeleteKeyDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.security.Provider;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ExportHelper {
|
||||
protected FileDialogFragment mFileDialog;
|
||||
protected String mExportFilename;
|
||||
@@ -81,7 +75,7 @@ public class ExportHelper {
|
||||
int type = keyType;
|
||||
mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
|
||||
|
||||
if( data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED) ) {
|
||||
if (data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED)) {
|
||||
type = Id.type.public_secret_key;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
@@ -30,7 +30,7 @@ import java.util.Vector;
|
||||
* Singleton Implementation of a Preference Helper
|
||||
*/
|
||||
public class Preferences {
|
||||
private static Preferences mPreferences;
|
||||
private static Preferences sPreferences;
|
||||
private SharedPreferences mSharedPreferences;
|
||||
|
||||
public static synchronized Preferences getPreferences(Context context) {
|
||||
@@ -38,10 +38,10 @@ public class Preferences {
|
||||
}
|
||||
|
||||
public static synchronized Preferences getPreferences(Context context, boolean forceNew) {
|
||||
if (mPreferences == null || forceNew) {
|
||||
mPreferences = new Preferences(context);
|
||||
if (sPreferences == null || forceNew) {
|
||||
sPreferences = new Preferences(context);
|
||||
}
|
||||
return mPreferences;
|
||||
return sPreferences;
|
||||
}
|
||||
|
||||
private Preferences(Context context) {
|
||||
@@ -58,8 +58,8 @@ public class Preferences {
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
public long getPassPhraseCacheTtl() {
|
||||
int ttl = mSharedPreferences.getInt(Constants.Pref.PASS_PHRASE_CACHE_TTL, 180);
|
||||
public long getPassphraseCacheTtl() {
|
||||
int ttl = mSharedPreferences.getInt(Constants.Pref.PASSPHRASE_CACHE_TTL, 180);
|
||||
// fix the value if it was set to "never" in previous versions, which currently is not
|
||||
// supported
|
||||
if (ttl == 0) {
|
||||
@@ -68,9 +68,9 @@ public class Preferences {
|
||||
return (long) ttl;
|
||||
}
|
||||
|
||||
public void setPassPhraseCacheTtl(int value) {
|
||||
public void setPassphraseCacheTtl(int value) {
|
||||
SharedPreferences.Editor editor = mSharedPreferences.edit();
|
||||
editor.putInt(Constants.Pref.PASS_PHRASE_CACHE_TTL, value);
|
||||
editor.putInt(Constants.Pref.PASSPHRASE_CACHE_TTL, value);
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
@@ -118,13 +118,13 @@ public class Preferences {
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
public boolean getDefaultAsciiArmour() {
|
||||
return mSharedPreferences.getBoolean(Constants.Pref.DEFAULT_ASCII_ARMOUR, false);
|
||||
public boolean getDefaultAsciiArmor() {
|
||||
return mSharedPreferences.getBoolean(Constants.Pref.DEFAULT_ASCII_ARMOR, false);
|
||||
}
|
||||
|
||||
public void setDefaultAsciiArmour(boolean value) {
|
||||
public void setDefaultAsciiArmor(boolean value) {
|
||||
SharedPreferences.Editor editor = mSharedPreferences.edit();
|
||||
editor.putBoolean(Constants.Pref.DEFAULT_ASCII_ARMOUR, value);
|
||||
editor.putBoolean(Constants.Pref.DEFAULT_ASCII_ARMOR, value);
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
|
||||
@@ -65,14 +65,16 @@ public class PgpConversionHelper {
|
||||
try {
|
||||
while ((obj = factory.nextObject()) != null) {
|
||||
PGPSecretKey secKey = null;
|
||||
if(obj instanceof PGPSecretKey) {
|
||||
if ((secKey = (PGPSecretKey)obj ) == null) {
|
||||
if (obj instanceof PGPSecretKey) {
|
||||
secKey = (PGPSecretKey) obj;
|
||||
if (secKey == null) {
|
||||
Log.e(Constants.TAG, "No keys given!");
|
||||
}
|
||||
keys.add(secKey);
|
||||
} else if(obj instanceof PGPSecretKeyRing) { //master keys are sent as keyrings
|
||||
} else if (obj instanceof PGPSecretKeyRing) { //master keys are sent as keyrings
|
||||
PGPSecretKeyRing keyRing = null;
|
||||
if ((keyRing = (PGPSecretKeyRing)obj) == null) {
|
||||
keyRing = (PGPSecretKeyRing) obj;
|
||||
if (keyRing == null) {
|
||||
Log.e(Constants.TAG, "No keys given!");
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -67,6 +67,7 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.SignatureException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This class uses a Builder pattern!
|
||||
@@ -79,7 +80,7 @@ public class PgpDecryptVerify {
|
||||
private ProgressDialogUpdater mProgressDialogUpdater;
|
||||
private boolean mAllowSymmetricDecryption;
|
||||
private String mPassphrase;
|
||||
private long mEnforcedKeyId;
|
||||
private Set<Long> mAllowedKeyIds;
|
||||
|
||||
private PgpDecryptVerify(Builder builder) {
|
||||
// private Constructor can only be called from Builder
|
||||
@@ -90,7 +91,7 @@ public class PgpDecryptVerify {
|
||||
this.mProgressDialogUpdater = builder.mProgressDialogUpdater;
|
||||
this.mAllowSymmetricDecryption = builder.mAllowSymmetricDecryption;
|
||||
this.mPassphrase = builder.mPassphrase;
|
||||
this.mEnforcedKeyId = builder.mEnforcedKeyId;
|
||||
this.mAllowedKeyIds = builder.mAllowedKeyIds;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
@@ -103,7 +104,7 @@ public class PgpDecryptVerify {
|
||||
private ProgressDialogUpdater mProgressDialogUpdater = null;
|
||||
private boolean mAllowSymmetricDecryption = true;
|
||||
private String mPassphrase = null;
|
||||
private long mEnforcedKeyId = 0;
|
||||
private Set<Long> mAllowedKeyIds = null;
|
||||
|
||||
public Builder(Context context, InputData data, OutputStream outStream) {
|
||||
this.mContext = context;
|
||||
@@ -127,14 +128,14 @@ public class PgpDecryptVerify {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow this key id alone for decryption.
|
||||
* This means only ciphertexts encrypted for this private key can be decrypted.
|
||||
* Allow these key ids alone for decryption.
|
||||
* This means only ciphertexts encrypted for one of these private key can be decrypted.
|
||||
*
|
||||
* @param enforcedKeyId
|
||||
* @param allowedKeyIds
|
||||
* @return
|
||||
*/
|
||||
public Builder enforcedKeyId(long enforcedKeyId) {
|
||||
this.mEnforcedKeyId = enforcedKeyId;
|
||||
public Builder allowedKeyIds(Set<Long> allowedKeyIds) {
|
||||
this.mAllowedKeyIds = allowedKeyIds;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -236,16 +237,16 @@ public class PgpDecryptVerify {
|
||||
// secret key exists in database
|
||||
|
||||
// allow only a specific key for decryption?
|
||||
if (mEnforcedKeyId != 0) {
|
||||
if (mAllowedKeyIds != null) {
|
||||
// TODO: improve this code! get master key directly!
|
||||
PGPSecretKeyRing secretKeyRing =
|
||||
ProviderHelper.getPGPSecretKeyRingWithKeyId(mContext, encData.getKeyID());
|
||||
long masterKeyId = PgpKeyHelper.getMasterKey(secretKeyRing).getKeyID();
|
||||
Log.d(Constants.TAG, "encData.getKeyID():" + encData.getKeyID());
|
||||
Log.d(Constants.TAG, "enforcedKeyId: " + mEnforcedKeyId);
|
||||
Log.d(Constants.TAG, "allowedKeyIds: " + mAllowedKeyIds);
|
||||
Log.d(Constants.TAG, "masterKeyId: " + masterKeyId);
|
||||
|
||||
if (mEnforcedKeyId != masterKeyId) {
|
||||
if (!mAllowedKeyIds.contains(masterKeyId)) {
|
||||
throw new PgpGeneralException(
|
||||
mContext.getString(R.string.error_no_secret_key_found));
|
||||
}
|
||||
@@ -683,7 +684,8 @@ public class PgpDecryptVerify {
|
||||
}
|
||||
|
||||
private static boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector pkts,
|
||||
PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) {
|
||||
PGPPublicKey masterPublicKey,
|
||||
PGPPublicKey signingPublicKey) {
|
||||
boolean validPrimaryKeyBinding = false;
|
||||
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
||||
new JcaPGPContentVerifierBuilderProvider()
|
||||
|
||||
@@ -21,7 +21,13 @@ import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
|
||||
import org.spongycastle.openpgp.*;
|
||||
import org.spongycastle.openpgp.PGPEncryptedDataList;
|
||||
import org.spongycastle.openpgp.PGPObjectFactory;
|
||||
import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
|
||||
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.spongycastle.openpgp.PGPSecretKey;
|
||||
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.spongycastle.openpgp.PGPUtil;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
@@ -45,9 +51,9 @@ public class PgpHelper {
|
||||
".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*", Pattern.DOTALL);
|
||||
|
||||
public static final Pattern PGP_CLEARTEXT_SIGNATURE = Pattern
|
||||
.compile(
|
||||
".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*",
|
||||
Pattern.DOTALL);
|
||||
.compile(".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----" +
|
||||
"BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*",
|
||||
Pattern.DOTALL);
|
||||
|
||||
public static final Pattern PGP_PUBLIC_KEY = Pattern.compile(
|
||||
".*?(-----BEGIN PGP PUBLIC KEY BLOCK-----.*?-----END PGP PUBLIC KEY BLOCK-----).*",
|
||||
|
||||
@@ -20,8 +20,14 @@ package org.sufficientlysecure.keychain.pgp;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
|
||||
import org.spongycastle.bcpg.ArmoredOutputStream;
|
||||
import org.spongycastle.openpgp.*;
|
||||
import org.spongycastle.openpgp.PGPException;
|
||||
import org.spongycastle.openpgp.PGPKeyRing;
|
||||
import org.spongycastle.openpgp.PGPPublicKey;
|
||||
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.spongycastle.openpgp.PGPSecretKey;
|
||||
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
@@ -30,13 +36,16 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
||||
import org.sufficientlysecure.keychain.util.*;
|
||||
import org.sufficientlysecure.keychain.util.HkpKeyServer;
|
||||
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||
import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException;
|
||||
import org.sufficientlysecure.keychain.util.KeychainServiceListener;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.security.Provider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -159,7 +168,8 @@ public class PgpImportExport {
|
||||
return returnData;
|
||||
}
|
||||
|
||||
public Bundle exportKeyRings(ArrayList<Long> publicKeyRingMasterIds, ArrayList<Long> secretKeyRingMasterIds,
|
||||
public Bundle exportKeyRings(ArrayList<Long> publicKeyRingMasterIds,
|
||||
ArrayList<Long> secretKeyRingMasterIds,
|
||||
OutputStream outStream) throws PgpGeneralException,
|
||||
PGPException, IOException {
|
||||
Bundle returnData = new Bundle();
|
||||
|
||||
@@ -24,7 +24,12 @@ import android.text.SpannableStringBuilder;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
|
||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||
import org.spongycastle.openpgp.*;
|
||||
import org.spongycastle.openpgp.PGPPublicKey;
|
||||
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.spongycastle.openpgp.PGPSecretKey;
|
||||
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.spongycastle.openpgp.PGPSignature;
|
||||
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
@@ -35,7 +40,11 @@ import org.sufficientlysecure.keychain.util.Log;
|
||||
import java.security.DigestException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.*;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.Vector;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -288,8 +297,7 @@ public class PgpKeyHelper {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public static int getKeyUsage(PGPSecretKey key)
|
||||
{
|
||||
public static int getKeyUsage(PGPSecretKey key) {
|
||||
return getKeyUsage(key.getPublicKey());
|
||||
}
|
||||
|
||||
@@ -298,13 +306,19 @@ public class PgpKeyHelper {
|
||||
int usage = 0;
|
||||
if (key.getVersion() >= 4) {
|
||||
for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) {
|
||||
if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) continue;
|
||||
if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
|
||||
if (hashed != null) usage |= hashed.getKeyFlags();
|
||||
if (hashed != null) {
|
||||
usage |= hashed.getKeyFlags();
|
||||
}
|
||||
|
||||
PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
|
||||
if (unhashed != null) usage |= unhashed.getKeyFlags();
|
||||
if (unhashed != null) {
|
||||
usage |= unhashed.getKeyFlags();
|
||||
}
|
||||
}
|
||||
}
|
||||
return usage;
|
||||
|
||||
@@ -17,30 +17,54 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.pgp;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import org.spongycastle.bcpg.CompressionAlgorithmTags;
|
||||
import org.spongycastle.bcpg.HashAlgorithmTags;
|
||||
import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
|
||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||
import org.spongycastle.jce.spec.ElGamalParameterSpec;
|
||||
import org.spongycastle.openpgp.*;
|
||||
import org.spongycastle.openpgp.PGPEncryptedData;
|
||||
import org.spongycastle.openpgp.PGPException;
|
||||
import org.spongycastle.openpgp.PGPKeyPair;
|
||||
import org.spongycastle.openpgp.PGPKeyRingGenerator;
|
||||
import org.spongycastle.openpgp.PGPPrivateKey;
|
||||
import org.spongycastle.openpgp.PGPPublicKey;
|
||||
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.spongycastle.openpgp.PGPSecretKey;
|
||||
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.spongycastle.openpgp.PGPSignature;
|
||||
import org.spongycastle.openpgp.PGPSignatureGenerator;
|
||||
import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
|
||||
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
|
||||
import org.spongycastle.openpgp.PGPUtil;
|
||||
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||
import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor;
|
||||
import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
|
||||
import org.spongycastle.openpgp.operator.PGPDigestCalculator;
|
||||
import org.spongycastle.openpgp.operator.jcajce.*;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||
import org.sufficientlysecure.keychain.util.Primes;
|
||||
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
|
||||
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.*;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.SignatureException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
@@ -171,35 +195,35 @@ public class PgpKeyOperation {
|
||||
sha1Calc, isMasterKey, keyEncryptor);
|
||||
}
|
||||
|
||||
public PGPSecretKeyRing changeSecretKeyPassphrase(PGPSecretKeyRing keyRing, String oldPassPhrase,
|
||||
String newPassPhrase) throws IOException, PGPException,
|
||||
NoSuchProviderException {
|
||||
public PGPSecretKeyRing changeSecretKeyPassphrase(PGPSecretKeyRing keyRing, String oldPassphrase,
|
||||
String newPassphrase)
|
||||
throws IOException, PGPException, NoSuchProviderException {
|
||||
|
||||
updateProgress(R.string.progress_building_key, 0, 100);
|
||||
if (oldPassPhrase == null) {
|
||||
oldPassPhrase = "";
|
||||
if (oldPassphrase == null) {
|
||||
oldPassphrase = "";
|
||||
}
|
||||
if (newPassPhrase == null) {
|
||||
newPassPhrase = "";
|
||||
if (newPassphrase == null) {
|
||||
newPassphrase = "";
|
||||
}
|
||||
|
||||
PGPSecretKeyRing newKeyRing = PGPSecretKeyRing.copyWithNewPassword(
|
||||
keyRing,
|
||||
new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder()
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build()).setProvider(
|
||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassPhrase.toCharArray()),
|
||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassphrase.toCharArray()),
|
||||
new JcePBESecretKeyEncryptorBuilder(keyRing.getSecretKey()
|
||||
.getKeyEncryptionAlgorithm()).build(newPassPhrase.toCharArray()));
|
||||
.getKeyEncryptionAlgorithm()).build(newPassphrase.toCharArray()));
|
||||
|
||||
return newKeyRing;
|
||||
|
||||
}
|
||||
|
||||
private Pair<PGPSecretKeyRing,PGPPublicKeyRing> buildNewSecretKey(
|
||||
private Pair<PGPSecretKeyRing, PGPPublicKeyRing> buildNewSecretKey(
|
||||
ArrayList<String> userIds, ArrayList<PGPSecretKey> keys,
|
||||
ArrayList<GregorianCalendar> keysExpiryDates,
|
||||
ArrayList<Integer> keysUsages,
|
||||
String newPassPhrase, String oldPassPhrase)
|
||||
String newPassphrase, String oldPassphrase)
|
||||
throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException {
|
||||
|
||||
int usageId = keysUsages.get(0);
|
||||
@@ -212,7 +236,7 @@ public class PgpKeyOperation {
|
||||
PGPPublicKey masterPublicKey = masterKey.getPublicKey();
|
||||
|
||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassPhrase.toCharArray());
|
||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassphrase.toCharArray());
|
||||
PGPPrivateKey masterPrivateKey = masterKey.extractPrivateKey(keyDecryptor);
|
||||
|
||||
updateProgress(R.string.progress_certifying_master_key, 20, 100);
|
||||
@@ -246,13 +270,16 @@ public class PgpKeyOperation {
|
||||
GregorianCalendar expiryDate = keysExpiryDates.get(0);
|
||||
//note that the below, (a/c) - (b/c) is *not* the same as (a - b) /c
|
||||
//here we purposefully ignore partial days in each date - long type has no fractional part!
|
||||
long numDays = (expiryDate.getTimeInMillis() / 86400000) - (creationDate.getTimeInMillis() / 86400000);
|
||||
if (numDays <= 0)
|
||||
long numDays = (expiryDate.getTimeInMillis() / 86400000) -
|
||||
(creationDate.getTimeInMillis() / 86400000);
|
||||
if (numDays <= 0) {
|
||||
throw new PgpGeneralMsgIdException(R.string.error_expiry_must_come_after_creation);
|
||||
}
|
||||
hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400);
|
||||
} else {
|
||||
hashedPacketsGen.setKeyExpirationTime(false, 0); //do this explicitly, although since we're rebuilding,
|
||||
//this happens anyway
|
||||
hashedPacketsGen.setKeyExpirationTime(false, 0);
|
||||
// do this explicitly, although since we're rebuilding,
|
||||
// this happens anyway
|
||||
}
|
||||
|
||||
updateProgress(R.string.progress_building_master_key, 30, 100);
|
||||
@@ -267,7 +294,7 @@ public class PgpKeyOperation {
|
||||
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
|
||||
PGPEncryptedData.CAST5, sha1Calc)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||
newPassPhrase.toCharArray());
|
||||
newPassphrase.toCharArray());
|
||||
|
||||
PGPKeyRingGenerator keyGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION,
|
||||
masterKeyPair, mainUserId, sha1Calc, hashedPacketsGen.generate(),
|
||||
@@ -283,7 +310,7 @@ public class PgpKeyOperation {
|
||||
|
||||
PBESecretKeyDecryptor keyDecryptor2 = new JcePBESecretKeyDecryptorBuilder()
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||
oldPassPhrase.toCharArray());
|
||||
oldPassphrase.toCharArray());
|
||||
PGPPrivateKey subPrivateKey = subKey.extractPrivateKey(keyDecryptor2);
|
||||
|
||||
// TODO: now used without algorithm and creation time?! (APG 1)
|
||||
@@ -318,15 +345,16 @@ public class PgpKeyOperation {
|
||||
GregorianCalendar expiryDate = keysExpiryDates.get(i);
|
||||
//note that the below, (a/c) - (b/c) is *not* the same as (a - b) /c
|
||||
//here we purposefully ignore partial days in each date - long type has no fractional part!
|
||||
long numDays =
|
||||
(expiryDate.getTimeInMillis() / 86400000) - (creationDate.getTimeInMillis() / 86400000);
|
||||
long numDays = (expiryDate.getTimeInMillis() / 86400000) -
|
||||
(creationDate.getTimeInMillis() / 86400000);
|
||||
if (numDays <= 0) {
|
||||
throw new PgpGeneralMsgIdException(R.string.error_expiry_must_come_after_creation);
|
||||
}
|
||||
hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400);
|
||||
} else {
|
||||
hashedPacketsGen.setKeyExpirationTime(false, 0); //do this explicitly, although since we're rebuilding,
|
||||
//this happens anyway
|
||||
hashedPacketsGen.setKeyExpirationTime(false, 0);
|
||||
// do this explicitly, although since we're rebuilding,
|
||||
// this happens anyway
|
||||
}
|
||||
|
||||
keyGen.addSubKey(subKeyPair, hashedPacketsGen.generate(), unhashedPacketsGen.generate());
|
||||
@@ -335,11 +363,11 @@ public class PgpKeyOperation {
|
||||
PGPSecretKeyRing secretKeyRing = keyGen.generateSecretKeyRing();
|
||||
PGPPublicKeyRing publicKeyRing = keyGen.generatePublicKeyRing();
|
||||
|
||||
return new Pair<PGPSecretKeyRing,PGPPublicKeyRing>(secretKeyRing, publicKeyRing);
|
||||
return new Pair<PGPSecretKeyRing, PGPPublicKeyRing>(secretKeyRing, publicKeyRing);
|
||||
|
||||
}
|
||||
|
||||
public Pair<PGPSecretKeyRing,PGPPublicKeyRing> buildSecretKey (PGPSecretKeyRing mKR,
|
||||
public Pair<PGPSecretKeyRing, PGPPublicKeyRing> buildSecretKey(PGPSecretKeyRing mKR,
|
||||
PGPPublicKeyRing pKR,
|
||||
SaveKeyringParcel saveParcel)
|
||||
throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException {
|
||||
@@ -347,16 +375,16 @@ public class PgpKeyOperation {
|
||||
updateProgress(R.string.progress_building_key, 0, 100);
|
||||
PGPSecretKey masterKey = saveParcel.keys.get(0);
|
||||
|
||||
if (saveParcel.oldPassPhrase == null) {
|
||||
saveParcel.oldPassPhrase = "";
|
||||
if (saveParcel.oldPassphrase == null) {
|
||||
saveParcel.oldPassphrase = "";
|
||||
}
|
||||
if (saveParcel.newPassPhrase == null) {
|
||||
saveParcel.newPassPhrase = "";
|
||||
if (saveParcel.newPassphrase == null) {
|
||||
saveParcel.newPassphrase = "";
|
||||
}
|
||||
|
||||
if (mKR == null) {
|
||||
return buildNewSecretKey(saveParcel.userIDs, saveParcel.keys, saveParcel.keysExpiryDates,
|
||||
saveParcel.keysUsages, saveParcel.newPassPhrase, saveParcel.oldPassPhrase); //new Keyring
|
||||
saveParcel.keysUsages, saveParcel.newPassphrase, saveParcel.oldPassphrase); //new Keyring
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -395,7 +423,7 @@ public class PgpKeyOperation {
|
||||
String mainUserId = saveParcel.userIDs.get(0);
|
||||
|
||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(saveParcel.oldPassPhrase.toCharArray());
|
||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(saveParcel.oldPassphrase.toCharArray());
|
||||
PGPPrivateKey masterPrivateKey = masterKey.extractPrivateKey(keyDecryptor);
|
||||
|
||||
updateProgress(R.string.progress_certifying_master_key, 20, 100);
|
||||
@@ -423,22 +451,28 @@ public class PgpKeyOperation {
|
||||
GregorianCalendar expiryDate = saveParcel.keysExpiryDates.get(0);
|
||||
//note that the below, (a/c) - (b/c) is *not* the same as (a - b) /c
|
||||
//here we purposefully ignore partial days in each date - long type has no fractional part!
|
||||
long numDays = (expiryDate.getTimeInMillis() / 86400000) - (creationDate.getTimeInMillis() / 86400000);
|
||||
if (numDays <= 0)
|
||||
long numDays = (expiryDate.getTimeInMillis() / 86400000) -
|
||||
(creationDate.getTimeInMillis() / 86400000);
|
||||
if (numDays <= 0) {
|
||||
throw new PgpGeneralMsgIdException(R.string.error_expiry_must_come_after_creation);
|
||||
}
|
||||
hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400);
|
||||
} else {
|
||||
hashedPacketsGen.setKeyExpirationTime(false, 0); //do this explicitly, although since we're rebuilding,
|
||||
//this happens anyway
|
||||
hashedPacketsGen.setKeyExpirationTime(false, 0);
|
||||
// do this explicitly, although since we're rebuilding,
|
||||
// this happens anyway
|
||||
}
|
||||
|
||||
if (saveParcel.primaryIDChanged || !saveParcel.originalIDs.get(0).equals(saveParcel.userIDs.get(0))) {
|
||||
if (saveParcel.primaryIDChanged ||
|
||||
!saveParcel.originalIDs.get(0).equals(saveParcel.userIDs.get(0))) {
|
||||
anyIDChanged = true;
|
||||
ArrayList<Pair<String, PGPSignature>> sigList = new ArrayList<Pair<String, PGPSignature>>();
|
||||
for (String userId : saveParcel.userIDs) {
|
||||
String origID = saveParcel.originalIDs.get(userIDIndex);
|
||||
if (origID.equals(userId) && !userId.equals(saveParcel.originalPrimaryID) && userIDIndex != 0) {
|
||||
Iterator<PGPSignature> origSigs = masterPublicKey.getSignaturesForID(origID); //TODO: make sure this iterator only has signatures we are interested in
|
||||
if (origID.equals(userId) && !saveParcel.newIDs[userIDIndex] &&
|
||||
!userId.equals(saveParcel.originalPrimaryID) && userIDIndex != 0) {
|
||||
Iterator<PGPSignature> origSigs = masterPublicKey.getSignaturesForID(origID);
|
||||
// TODO: make sure this iterator only has signatures we are interested in
|
||||
while (origSigs.hasNext()) {
|
||||
PGPSignature origSig = origSigs.next();
|
||||
sigList.add(new Pair<String, PGPSignature>(origID, origSig));
|
||||
@@ -457,18 +491,19 @@ public class PgpKeyOperation {
|
||||
PGPSignature certification = sGen.generateCertification(userId, masterPublicKey);
|
||||
sigList.add(new Pair<String, PGPSignature>(userId, certification));
|
||||
}
|
||||
if (!origID.equals("")) {
|
||||
if (!saveParcel.newIDs[userIDIndex]) {
|
||||
masterPublicKey = PGPPublicKey.removeCertification(masterPublicKey, origID);
|
||||
}
|
||||
userIDIndex++;
|
||||
}
|
||||
for (Pair<String, PGPSignature> toAdd : sigList) {
|
||||
masterPublicKey = PGPPublicKey.addCertification(masterPublicKey, toAdd.first, toAdd.second);
|
||||
masterPublicKey =
|
||||
PGPPublicKey.addCertification(masterPublicKey, toAdd.first, toAdd.second);
|
||||
}
|
||||
} else {
|
||||
for (String userId : saveParcel.userIDs) {
|
||||
String origID = saveParcel.originalIDs.get(userIDIndex);
|
||||
if (!origID.equals(userId)) {
|
||||
if (!origID.equals(userId) || saveParcel.newIDs[userIDIndex]) {
|
||||
anyIDChanged = true;
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA1)
|
||||
@@ -481,10 +516,11 @@ public class PgpKeyOperation {
|
||||
sGen.setUnhashedSubpackets(unhashedPacketsGen.generate());
|
||||
}
|
||||
PGPSignature certification = sGen.generateCertification(userId, masterPublicKey);
|
||||
if (!origID.equals("")) {
|
||||
if (!saveParcel.newIDs[userIDIndex]) {
|
||||
masterPublicKey = PGPPublicKey.removeCertification(masterPublicKey, origID);
|
||||
}
|
||||
masterPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, certification);
|
||||
masterPublicKey =
|
||||
PGPPublicKey.addCertification(masterPublicKey, userId, certification);
|
||||
}
|
||||
userIDIndex++;
|
||||
}
|
||||
@@ -496,15 +532,14 @@ public class PgpKeyOperation {
|
||||
for (String userId : saveParcel.userIDs) {
|
||||
String origID = saveParcel.originalIDs.get(userIDIndex);
|
||||
if (!(origID.equals(saveParcel.originalPrimaryID) && !saveParcel.primaryIDChanged)) {
|
||||
Iterator<PGPSignature> sigs = masterPublicKey.getSignaturesForID(userId); //TODO: make sure this iterator only has signatures we are interested in
|
||||
Iterator<PGPSignature> sigs = masterPublicKey.getSignaturesForID(userId);
|
||||
// TODO: make sure this iterator only has signatures we are interested in
|
||||
while (sigs.hasNext()) {
|
||||
PGPSignature sig = sigs.next();
|
||||
sigList.add(new Pair<String, PGPSignature>(userId, sig));
|
||||
}
|
||||
}
|
||||
if (!userId.equals("")) {
|
||||
masterPublicKey = PGPPublicKey.removeCertification(masterPublicKey, userId);
|
||||
}
|
||||
masterPublicKey = PGPPublicKey.removeCertification(masterPublicKey, userId);
|
||||
userIDIndex++;
|
||||
}
|
||||
anyIDChanged = true;
|
||||
@@ -530,7 +565,7 @@ public class PgpKeyOperation {
|
||||
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
|
||||
PGPEncryptedData.CAST5, sha1Calc)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||
saveParcel.oldPassPhrase.toCharArray());
|
||||
saveParcel.oldPassphrase.toCharArray());
|
||||
|
||||
//this generates one more signature than necessary...
|
||||
PGPKeyRingGenerator keyGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION,
|
||||
@@ -551,7 +586,7 @@ public class PgpKeyOperation {
|
||||
} else {
|
||||
keyDecryptor2 = new JcePBESecretKeyDecryptorBuilder()
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||
saveParcel.oldPassPhrase.toCharArray());
|
||||
saveParcel.oldPassphrase.toCharArray());
|
||||
}
|
||||
PGPPrivateKey subPrivateKey = subKey.extractPrivateKey(keyDecryptor2);
|
||||
PGPKeyPair subKeyPair = new PGPKeyPair(subPublicKey, subPrivateKey);
|
||||
@@ -583,23 +618,27 @@ public class PgpKeyOperation {
|
||||
GregorianCalendar creationDate = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
|
||||
creationDate.setTime(subPublicKey.getCreationTime());
|
||||
GregorianCalendar expiryDate = saveParcel.keysExpiryDates.get(i);
|
||||
//note that the below, (a/c) - (b/c) is *not* the same as (a - b) /c
|
||||
//here we purposefully ignore partial days in each date - long type has no fractional part!
|
||||
long numDays = (expiryDate.getTimeInMillis() / 86400000) - (creationDate.getTimeInMillis() / 86400000);
|
||||
if (numDays <= 0)
|
||||
// note that the below, (a/c) - (b/c) is *not* the same as (a - b) /c
|
||||
// here we purposefully ignore partial days in each date - long type has
|
||||
// no fractional part!
|
||||
long numDays = (expiryDate.getTimeInMillis() / 86400000) -
|
||||
(creationDate.getTimeInMillis() / 86400000);
|
||||
if (numDays <= 0) {
|
||||
throw new PgpGeneralMsgIdException(R.string.error_expiry_must_come_after_creation);
|
||||
}
|
||||
hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400);
|
||||
} else {
|
||||
hashedPacketsGen.setKeyExpirationTime(false, 0); //do this explicitly, although since we're rebuilding,
|
||||
//this happens anyway
|
||||
hashedPacketsGen.setKeyExpirationTime(false, 0);
|
||||
// do this explicitly, although since we're rebuilding,
|
||||
// this happens anyway
|
||||
}
|
||||
|
||||
keyGen.addSubKey(subKeyPair, hashedPacketsGen.generate(), unhashedPacketsGen.generate());
|
||||
//certifications will be discarded if the key is changed, because I think, for a start,
|
||||
//they will be invalid. Binding certs are regenerated anyway, and other certs which
|
||||
//need to be kept are on IDs and attributes
|
||||
//TODO: don't let revoked keys be edited, other than removed - changing one would result in the
|
||||
//revocation being wrong?
|
||||
// certifications will be discarded if the key is changed, because I think, for a start,
|
||||
// they will be invalid. Binding certs are regenerated anyway, and other certs which
|
||||
// need to be kept are on IDs and attributes
|
||||
// TODO: don't let revoked keys be edited, other than removed - changing one would
|
||||
// result in the revocation being wrong?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -628,7 +667,7 @@ public class PgpKeyOperation {
|
||||
PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder(
|
||||
PGPEncryptedData.CAST5, sha1Calc)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||
saveParcel.newPassPhrase.toCharArray());
|
||||
saveParcel.newPassphrase.toCharArray());
|
||||
|
||||
//update the passphrase
|
||||
mKR = PGPSecretKeyRing.copyWithNewPassword(mKR, keyDecryptor, keyEncryptorNew);
|
||||
@@ -638,8 +677,10 @@ public class PgpKeyOperation {
|
||||
Log.d(Constants.TAG, " ------- in private key -------");
|
||||
|
||||
for(String uid : new IterableIterator<String>(secretKeyRing.getPublicKey().getUserIDs())) {
|
||||
for(PGPSignature sig : new IterableIterator<PGPSignature>(secretKeyRing.getPublicKey().getSignaturesForID(uid))) {
|
||||
Log.d(Constants.TAG, "sig: " + PgpKeyHelper.convertKeyIdToHex(sig.getKeyID()) + " for " + uid);
|
||||
for(PGPSignature sig : new IterableIterator<PGPSignature>(
|
||||
secretKeyRing.getPublicKey().getSignaturesForID(uid))) {
|
||||
Log.d(Constants.TAG, "sig: " +
|
||||
PgpKeyHelper.convertKeyIdToHex(sig.getKeyID()) + " for " + uid);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -647,14 +688,16 @@ public class PgpKeyOperation {
|
||||
Log.d(Constants.TAG, " ------- in public key -------");
|
||||
|
||||
for(String uid : new IterableIterator<String>(publicKeyRing.getPublicKey().getUserIDs())) {
|
||||
for(PGPSignature sig : new IterableIterator<PGPSignature>(publicKeyRing.getPublicKey().getSignaturesForID(uid))) {
|
||||
Log.d(Constants.TAG, "sig: " + PgpKeyHelper.convertKeyIdToHex(sig.getKeyID()) + " for " + uid);
|
||||
for(PGPSignature sig : new IterableIterator<PGPSignature>(
|
||||
publicKeyRing.getPublicKey().getSignaturesForID(uid))) {
|
||||
Log.d(Constants.TAG, "sig: " +
|
||||
PgpKeyHelper.convertKeyIdToHex(sig.getKeyID()) + " for " + uid);
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
return new Pair<PGPSecretKeyRing,PGPPublicKeyRing>(mKR, pKR);
|
||||
return new Pair<PGPSecretKeyRing, PGPPublicKeyRing>(mKR, pKR);
|
||||
|
||||
}
|
||||
|
||||
@@ -667,9 +710,10 @@ public class PgpKeyOperation {
|
||||
* @param passphrase Passphrase of the secret key
|
||||
* @return A keyring with added certifications
|
||||
*/
|
||||
public PGPPublicKey certifyKey(PGPSecretKey certificationKey, PGPPublicKey publicKey, List<String> userIds, String passphrase)
|
||||
public PGPPublicKey certifyKey(PGPSecretKey certificationKey, PGPPublicKey publicKey,
|
||||
List<String> userIds, String passphrase)
|
||||
throws PgpGeneralMsgIdException, NoSuchAlgorithmException, NoSuchProviderException,
|
||||
PGPException, SignatureException {
|
||||
PGPException, SignatureException {
|
||||
|
||||
// create a signatureGenerator from the supplied masterKeyId and passphrase
|
||||
PGPSignatureGenerator signatureGenerator; {
|
||||
@@ -701,7 +745,7 @@ public class PgpKeyOperation {
|
||||
}
|
||||
|
||||
// fetch public key ring, add the certification and return it
|
||||
for(String userId : new IterableIterator<String>(userIds.iterator())) {
|
||||
for (String userId : new IterableIterator<String>(userIds.iterator())) {
|
||||
PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey);
|
||||
publicKey = PGPPublicKey.addCertification(publicKey, userId, sig);
|
||||
}
|
||||
|
||||
@@ -21,9 +21,25 @@ import android.content.Context;
|
||||
|
||||
import org.spongycastle.bcpg.ArmoredOutputStream;
|
||||
import org.spongycastle.bcpg.BCPGOutputStream;
|
||||
import org.spongycastle.openpgp.*;
|
||||
import org.spongycastle.openpgp.PGPCompressedDataGenerator;
|
||||
import org.spongycastle.openpgp.PGPEncryptedDataGenerator;
|
||||
import org.spongycastle.openpgp.PGPException;
|
||||
import org.spongycastle.openpgp.PGPLiteralData;
|
||||
import org.spongycastle.openpgp.PGPLiteralDataGenerator;
|
||||
import org.spongycastle.openpgp.PGPPrivateKey;
|
||||
import org.spongycastle.openpgp.PGPPublicKey;
|
||||
import org.spongycastle.openpgp.PGPSecretKey;
|
||||
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.spongycastle.openpgp.PGPSignature;
|
||||
import org.spongycastle.openpgp.PGPSignatureGenerator;
|
||||
import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
|
||||
import org.spongycastle.openpgp.PGPV3SignatureGenerator;
|
||||
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||
import org.spongycastle.openpgp.operator.jcajce.*;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
@@ -33,7 +49,11 @@ import org.sufficientlysecure.keychain.util.InputData;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SignatureException;
|
||||
|
||||
@@ -18,7 +18,13 @@
|
||||
package org.sufficientlysecure.keychain.pgp;
|
||||
|
||||
import org.spongycastle.asn1.DERObjectIdentifier;
|
||||
import org.spongycastle.asn1.x509.*;
|
||||
import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
|
||||
import org.spongycastle.asn1.x509.BasicConstraints;
|
||||
import org.spongycastle.asn1.x509.GeneralName;
|
||||
import org.spongycastle.asn1.x509.GeneralNames;
|
||||
import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
|
||||
import org.spongycastle.asn1.x509.X509Extensions;
|
||||
import org.spongycastle.asn1.x509.X509Name;
|
||||
import org.spongycastle.openpgp.PGPException;
|
||||
import org.spongycastle.openpgp.PGPPrivateKey;
|
||||
import org.spongycastle.openpgp.PGPPublicKey;
|
||||
@@ -29,13 +35,14 @@ import org.spongycastle.x509.extension.SubjectKeyIdentifierStructure;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.*;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SignatureException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.text.DateFormat;
|
||||
@@ -43,6 +50,11 @@ import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
public class PgpToX509 {
|
||||
public static final String DN_COMMON_PART_O = "OpenPGP to X.509 Bridge";
|
||||
public static final String DN_COMMON_PART_OU = "OpenPGP Keychain cert";
|
||||
@@ -71,9 +83,10 @@ public class PgpToX509 {
|
||||
* @throws Exception
|
||||
* @author Bruno Harbulot
|
||||
*/
|
||||
public static X509Certificate createSelfSignedCert(PublicKey pubKey, PrivateKey privKey,
|
||||
X509Name subject, Date startDate, Date endDate, String subjAltNameURI)
|
||||
throws InvalidKeyException, IllegalStateException, NoSuchAlgorithmException,
|
||||
public static X509Certificate createSelfSignedCert(
|
||||
PublicKey pubKey, PrivateKey privKey, X509Name subject, Date startDate, Date endDate,
|
||||
String subjAltNameURI)
|
||||
throws InvalidKeyException, IllegalStateException, NoSuchAlgorithmException,
|
||||
SignatureException, CertificateException, NoSuchProviderException {
|
||||
|
||||
X509V3CertificateGenerator certGenerator = new X509V3CertificateGenerator();
|
||||
@@ -170,10 +183,10 @@ public class PgpToX509 {
|
||||
/**
|
||||
* Creates a self-signed certificate from a PGP Secret Key.
|
||||
*
|
||||
* @param pgpSecKey PGP Secret Key (from which one can extract the public and private keys and other
|
||||
* attributes).
|
||||
* @param pgpPrivKey PGP Private Key corresponding to the Secret Key (password callbacks should be done
|
||||
* before calling this method)
|
||||
* @param pgpSecKey PGP Secret Key (from which one can extract the public and private
|
||||
* keys and other attributes).
|
||||
* @param pgpPrivKey PGP Private Key corresponding to the Secret Key (password callbacks
|
||||
* should be done before calling this method)
|
||||
* @param subjAltNameURI optional URI to embed in the subject alternative-name
|
||||
* @return self-signed certificate
|
||||
* @throws PGPException
|
||||
@@ -184,9 +197,9 @@ public class PgpToX509 {
|
||||
* @throws CertificateException
|
||||
* @author Bruno Harbulot
|
||||
*/
|
||||
public static X509Certificate createSelfSignedCert(PGPSecretKey pgpSecKey,
|
||||
PGPPrivateKey pgpPrivKey, String subjAltNameURI) throws PGPException,
|
||||
NoSuchProviderException, InvalidKeyException, NoSuchAlgorithmException,
|
||||
public static X509Certificate createSelfSignedCert(
|
||||
PGPSecretKey pgpSecKey, PGPPrivateKey pgpPrivKey, String subjAltNameURI)
|
||||
throws PGPException, NoSuchProviderException, InvalidKeyException, NoSuchAlgorithmException,
|
||||
SignatureException, CertificateException {
|
||||
// get public key from secret key
|
||||
PGPPublicKey pgpPubKey = pgpSecKey.getPublicKey();
|
||||
|
||||
@@ -22,14 +22,14 @@ import android.content.Context;
|
||||
public class PgpGeneralMsgIdException extends Exception {
|
||||
static final long serialVersionUID = 0xf812773343L;
|
||||
|
||||
private final int msgId;
|
||||
private final int mMessageId;
|
||||
|
||||
public PgpGeneralMsgIdException(int msgId) {
|
||||
super("msg[" + msgId + "]");
|
||||
this.msgId = msgId;
|
||||
public PgpGeneralMsgIdException(int messageId) {
|
||||
super("msg[" + messageId + "]");
|
||||
mMessageId = messageId;
|
||||
}
|
||||
|
||||
public PgpGeneralException getContextualized(Context context) {
|
||||
return new PgpGeneralException(context.getString(msgId), this);
|
||||
return new PgpGeneralException(context.getString(mMessageId), this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsColumns;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsAccountsColumns;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsColumns;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeysColumns;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIdsColumns;
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.provider;
|
||||
|
||||
import android.content.*;
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.OperationApplicationException;
|
||||
import android.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
import android.net.Uri;
|
||||
@@ -48,6 +52,8 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ProviderHelper {
|
||||
|
||||
@@ -628,10 +634,10 @@ public class ProviderHelper {
|
||||
return settings;
|
||||
}
|
||||
|
||||
public static AccountSettings getApiAccountSettings(Context context, Uri uri) {
|
||||
public static AccountSettings getApiAccountSettings(Context context, Uri accountUri) {
|
||||
AccountSettings settings = null;
|
||||
|
||||
Cursor cur = context.getContentResolver().query(uri, null, null, null, null);
|
||||
Cursor cur = context.getContentResolver().query(accountUri, null, null, null, null);
|
||||
if (cur != null && cur.moveToFirst()) {
|
||||
settings = new AccountSettings();
|
||||
|
||||
@@ -650,6 +656,20 @@ public class ProviderHelper {
|
||||
return settings;
|
||||
}
|
||||
|
||||
public static Set<Long> getAllKeyIdsForApp(Context context, Uri uri) {
|
||||
Set<Long> keyIds = new HashSet<Long>();
|
||||
|
||||
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
|
||||
if (cursor != null) {
|
||||
int keyIdColumn = cursor.getColumnIndex(KeychainContract.ApiAccounts.KEY_ID);
|
||||
while (cursor.moveToNext()) {
|
||||
keyIds.add(cursor.getLong(keyIdColumn));
|
||||
}
|
||||
}
|
||||
|
||||
return keyIds;
|
||||
}
|
||||
|
||||
public static byte[] getApiAppSignature(Context context, String packageName) {
|
||||
Uri queryUri = ApiApps.buildByPackageNameUri(packageName);
|
||||
|
||||
|
||||
@@ -17,10 +17,6 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.remote;
|
||||
|
||||
import org.spongycastle.bcpg.HashAlgorithmTags;
|
||||
import org.spongycastle.openpgp.PGPEncryptedData;
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
|
||||
public class AppSettings {
|
||||
private String mPackageName;
|
||||
private byte[] mPackageSignature;
|
||||
|
||||
@@ -45,6 +45,7 @@ import org.sufficientlysecure.keychain.util.Log;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
public class OpenPgpService extends RemoteService {
|
||||
|
||||
@@ -187,7 +188,8 @@ public class OpenPgpService extends RemoteService {
|
||||
}
|
||||
|
||||
private Intent encryptAndSignImpl(Intent data, ParcelFileDescriptor input,
|
||||
ParcelFileDescriptor output, AccountSettings accSettings, boolean sign) {
|
||||
ParcelFileDescriptor output, AccountSettings accSettings,
|
||||
boolean sign) {
|
||||
try {
|
||||
boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
||||
|
||||
@@ -276,7 +278,7 @@ public class OpenPgpService extends RemoteService {
|
||||
}
|
||||
|
||||
private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor input,
|
||||
ParcelFileDescriptor output, AccountSettings accSettings) {
|
||||
ParcelFileDescriptor output, Set<Long> allowedKeyIds) {
|
||||
try {
|
||||
// Get Input- and OutputStream from ParcelFileDescriptor
|
||||
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
|
||||
@@ -291,7 +293,8 @@ public class OpenPgpService extends RemoteService {
|
||||
|
||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os);
|
||||
builder.allowSymmetricDecryption(false) // no support for symmetric encryption
|
||||
.enforcedKeyId(accSettings.getKeyId()) // allow only the private key for this app for decryption
|
||||
.allowedKeyIds(allowedKeyIds) // allow only private keys associated with
|
||||
// accounts of this app
|
||||
.passphrase(passphrase);
|
||||
|
||||
// TODO: currently does not support binary signed-only content
|
||||
@@ -299,9 +302,11 @@ public class OpenPgpService extends RemoteService {
|
||||
|
||||
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
||||
// get PendingIntent for passphrase input, add it to given params and return to client
|
||||
Intent passphraseBundle = getPassphraseBundleIntent(data, accSettings.getKeyId());
|
||||
Intent passphraseBundle =
|
||||
getPassphraseBundleIntent(data, decryptVerifyResult.getKeyIdPassphraseNeeded());
|
||||
return passphraseBundle;
|
||||
} else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
||||
} else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED ==
|
||||
decryptVerifyResult.getStatus()) {
|
||||
throw new PgpGeneralException("Decryption of symmetric content not supported by API!");
|
||||
}
|
||||
|
||||
@@ -452,7 +457,11 @@ public class OpenPgpService extends RemoteService {
|
||||
} else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) {
|
||||
return encryptAndSignImpl(data, input, output, accSettings, true);
|
||||
} else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) {
|
||||
return decryptAndVerifyImpl(data, input, output, accSettings);
|
||||
String currentPkg = getCurrentCallingPackage();
|
||||
Set<Long> allowedKeyIds =
|
||||
ProviderHelper.getAllKeyIdsForApp(mContext,
|
||||
KeychainContract.ApiAccounts.buildBaseUri(currentPkg));
|
||||
return decryptAndVerifyImpl(data, input, output, allowedKeyIds);
|
||||
} else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) {
|
||||
return getKeyImpl(data);
|
||||
} else if (OpenPgpApi.ACTION_GET_KEY_IDS.equals(action)) {
|
||||
|
||||
@@ -127,7 +127,7 @@ public abstract class RemoteService extends Service {
|
||||
*
|
||||
* @return package name
|
||||
*/
|
||||
private String getCurrentCallingPackage() {
|
||||
protected String getCurrentCallingPackage() {
|
||||
// TODO:
|
||||
// callingPackages contains more than one entry when sharedUserId has been used...
|
||||
String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid());
|
||||
@@ -243,7 +243,8 @@ public abstract class RemoteService extends Service {
|
||||
return true;
|
||||
} else {
|
||||
throw new WrongPackageSignatureException(
|
||||
"PACKAGE NOT ALLOWED! Signature wrong! (Signature not equals signature from database)");
|
||||
"PACKAGE NOT ALLOWED! Signature wrong! (Signature not " +
|
||||
"equals signature from database)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.remote.ui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -31,6 +33,7 @@ import android.widget.TextView;
|
||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.remote.AccountSettings;
|
||||
import org.sufficientlysecure.keychain.ui.EditKeyActivity;
|
||||
import org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment;
|
||||
@@ -40,6 +43,8 @@ import org.sufficientlysecure.keychain.util.AlgorithmNames;
|
||||
public class AccountSettingsFragment extends Fragment implements
|
||||
SelectSecretKeyLayoutFragment.SelectSecretKeyCallback {
|
||||
|
||||
private static final int REQUEST_CODE_CREATE_KEY = 0x00008884;
|
||||
|
||||
// model
|
||||
private AccountSettings mAccSettings;
|
||||
|
||||
@@ -162,7 +167,27 @@ public class AccountSettingsFragment extends Fragment implements
|
||||
intent.putExtra(EditKeyActivity.EXTRA_GENERATE_DEFAULT_KEYS, true);
|
||||
// set default user id to account name TODO: not working currently in EditKey
|
||||
intent.putExtra(EditKeyActivity.EXTRA_USER_IDS, mAccSettings.getAccountName());
|
||||
startActivityForResult(intent, 0);
|
||||
startActivityForResult(intent, REQUEST_CODE_CREATE_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_CODE_CREATE_KEY: {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
// select newly created key
|
||||
Uri newKeyUri = data.getData();
|
||||
// TODO helper method for this?
|
||||
mSelectKeyFragment.selectKey(Long.parseLong(newKeyUri.getPathSegments().get(1)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,12 +32,10 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.ui.widget.FixedListView;
|
||||
|
||||
@@ -37,11 +37,9 @@ import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
public class AppsListFragment extends ListFragment implements
|
||||
LoaderManager.LoaderCallbacks<Cursor> {
|
||||
|
||||
@@ -95,7 +95,7 @@ public class RemoteServiceActivity extends ActionBarActivity {
|
||||
if (ACTION_REGISTER.equals(action)) {
|
||||
final String packageName = extras.getString(EXTRA_PACKAGE_NAME);
|
||||
final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE);
|
||||
Log.d(Constants.TAG, "ACTION_REGISTER packageName: "+packageName);
|
||||
Log.d(Constants.TAG, "ACTION_REGISTER packageName: " + packageName);
|
||||
|
||||
// Inflate a "Done"/"Cancel" custom action bar view
|
||||
ActionBarHelper.setTwoButtonView(getSupportActionBar(),
|
||||
|
||||
@@ -26,22 +26,49 @@ import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||
import org.spongycastle.openpgp.*;
|
||||
import org.spongycastle.openpgp.PGPKeyRing;
|
||||
import org.spongycastle.openpgp.PGPObjectFactory;
|
||||
import org.spongycastle.openpgp.PGPPublicKey;
|
||||
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.spongycastle.openpgp.PGPSecretKey;
|
||||
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.spongycastle.openpgp.PGPUtil;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.helper.FileHelper;
|
||||
import org.sufficientlysecure.keychain.helper.OtherHelper;
|
||||
import org.sufficientlysecure.keychain.helper.Preferences;
|
||||
import org.sufficientlysecure.keychain.pgp.*;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpImportExport;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.DataStream;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
||||
import org.sufficientlysecure.keychain.util.*;
|
||||
import org.sufficientlysecure.keychain.util.HkpKeyServer;
|
||||
import org.sufficientlysecure.keychain.util.InputData;
|
||||
import org.sufficientlysecure.keychain.util.KeychainServiceListener;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
|
||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -461,16 +488,16 @@ public class KeychainIntentService extends IntentService
|
||||
try {
|
||||
/* Input */
|
||||
SaveKeyringParcel saveParams = data.getParcelable(SAVE_KEYRING_PARCEL);
|
||||
String oldPassPhrase = saveParams.oldPassPhrase;
|
||||
String newPassPhrase = saveParams.newPassPhrase;
|
||||
String oldPassphrase = saveParams.oldPassphrase;
|
||||
String newPassphrase = saveParams.newPassphrase;
|
||||
boolean canSign = true;
|
||||
|
||||
if (data.containsKey(SAVE_KEYRING_CAN_SIGN)) {
|
||||
canSign = data.getBoolean(SAVE_KEYRING_CAN_SIGN);
|
||||
}
|
||||
|
||||
if (newPassPhrase == null) {
|
||||
newPassPhrase = oldPassPhrase;
|
||||
if (newPassphrase == null) {
|
||||
newPassphrase = oldPassphrase;
|
||||
}
|
||||
|
||||
long masterKeyId = saveParams.keys.get(0).getKeyID();
|
||||
@@ -480,7 +507,7 @@ public class KeychainIntentService extends IntentService
|
||||
PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 50, 100));
|
||||
PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRing(this, masterKeyId);
|
||||
keyRing = keyOperations.changeSecretKeyPassphrase(keyRing,
|
||||
oldPassPhrase, newPassPhrase);
|
||||
oldPassphrase, newPassphrase);
|
||||
setProgress(R.string.progress_saving_key_ring, 50, 100);
|
||||
ProviderHelper.saveKeyRing(this, keyRing);
|
||||
setProgress(R.string.progress_done, 100, 100);
|
||||
@@ -495,7 +522,7 @@ public class KeychainIntentService extends IntentService
|
||||
ProviderHelper.saveKeyRing(this, pair.second);
|
||||
setProgress(R.string.progress_done, 100, 100);
|
||||
}
|
||||
PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassPhrase);
|
||||
PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassphrase);
|
||||
|
||||
/* Output */
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY);
|
||||
@@ -746,11 +773,14 @@ public class KeychainIntentService extends IntentService
|
||||
|
||||
// verify downloaded key by comparing fingerprints
|
||||
if (entry.getFingerPrintHex() != null) {
|
||||
String downloadedKeyFp = PgpKeyHelper.convertFingerprintToHex(downloadedKey.getPublicKey().getFingerprint());
|
||||
String downloadedKeyFp = PgpKeyHelper.convertFingerprintToHex(
|
||||
downloadedKey.getPublicKey().getFingerprint());
|
||||
if (downloadedKeyFp.equals(entry.getFingerPrintHex())) {
|
||||
Log.d(Constants.TAG, "fingerprint of downloaded key is the same as the requested fingerprint!");
|
||||
Log.d(Constants.TAG, "fingerprint of downloaded key is the same as " +
|
||||
"the requested fingerprint!");
|
||||
} else {
|
||||
throw new PgpGeneralException("fingerprint of downloaded key is NOT the same as the requested fingerprint!");
|
||||
throw new PgpGeneralException("fingerprint of downloaded key is " +
|
||||
"NOT the same as the requested fingerprint!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -783,9 +813,9 @@ public class KeychainIntentService extends IntentService
|
||||
ArrayList<String> userIds = data.getStringArrayList(CERTIFY_KEY_UIDS);
|
||||
|
||||
/* Operation */
|
||||
String signaturePassPhrase = PassphraseCacheService.getCachedPassphrase(this,
|
||||
String signaturePassphrase = PassphraseCacheService.getCachedPassphrase(this,
|
||||
masterKeyId);
|
||||
if (signaturePassPhrase == null) {
|
||||
if (signaturePassphrase == null) {
|
||||
throw new PgpGeneralException("Unable to obtain passphrase");
|
||||
}
|
||||
|
||||
@@ -795,7 +825,7 @@ public class KeychainIntentService extends IntentService
|
||||
PGPSecretKey certificationKey = PgpKeyHelper.getCertificationKey(this,
|
||||
masterKeyId);
|
||||
publicKey = keyOperation.certifyKey(certificationKey, publicKey,
|
||||
userIds, signaturePassPhrase);
|
||||
userIds, signaturePassphrase);
|
||||
publicRing = PGPPublicKeyRing.insertPublicKey(publicRing, publicKey);
|
||||
|
||||
// store the signed key in our local cache
|
||||
@@ -818,7 +848,7 @@ public class KeychainIntentService extends IntentService
|
||||
return;
|
||||
}
|
||||
// contextualize the exception, if necessary
|
||||
if(e instanceof PgpGeneralMsgIdException) {
|
||||
if (e instanceof PgpGeneralMsgIdException) {
|
||||
e = ((PgpGeneralMsgIdException) e).getContextualized(this);
|
||||
}
|
||||
Log.e(Constants.TAG, "ApgService Exception: ", e);
|
||||
|
||||
@@ -24,15 +24,24 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.*;
|
||||
import android.util.Log;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.support.v4.util.LongSparseArray;
|
||||
import android.util.Log;
|
||||
|
||||
import org.spongycastle.openpgp.PGPException;
|
||||
import org.spongycastle.openpgp.PGPPrivateKey;
|
||||
import org.spongycastle.openpgp.PGPSecretKey;
|
||||
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
import org.sufficientlysecure.keychain.helper.Preferences;
|
||||
@@ -86,7 +95,7 @@ public class PassphraseCacheService extends Service {
|
||||
|
||||
Intent intent = new Intent(context, PassphraseCacheService.class);
|
||||
intent.setAction(ACTION_PASSPHRASE_CACHE_ADD);
|
||||
intent.putExtra(EXTRA_TTL, Preferences.getPreferences(context).getPassPhraseCacheTtl());
|
||||
intent.putExtra(EXTRA_TTL, Preferences.getPreferences(context).getPassphraseCacheTtl());
|
||||
intent.putExtra(EXTRA_PASSPHRASE, passphrase);
|
||||
intent.putExtra(EXTRA_KEY_ID, keyId);
|
||||
|
||||
|
||||
@@ -32,56 +32,59 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
public ArrayList<String> userIDs;
|
||||
public ArrayList<String> originalIDs;
|
||||
public ArrayList<String> deletedIDs;
|
||||
public boolean[] newIDs;
|
||||
public boolean primaryIDChanged;
|
||||
public boolean[] moddedKeys;
|
||||
public ArrayList<PGPSecretKey> deletedKeys;
|
||||
public ArrayList<GregorianCalendar> keysExpiryDates;
|
||||
public ArrayList<Integer> keysUsages;
|
||||
public String newPassPhrase;
|
||||
public String oldPassPhrase;
|
||||
public String newPassphrase;
|
||||
public String oldPassphrase;
|
||||
public boolean[] newKeys;
|
||||
public ArrayList<PGPSecretKey> keys;
|
||||
public String originalPrimaryID;
|
||||
|
||||
public SaveKeyringParcel() {}
|
||||
|
||||
private SaveKeyringParcel(Parcel source)
|
||||
{
|
||||
userIDs = (ArrayList<String>)source.readSerializable();
|
||||
originalIDs = (ArrayList<String>)source.readSerializable();
|
||||
deletedIDs = (ArrayList<String>)source.readSerializable();
|
||||
private SaveKeyringParcel(Parcel source) {
|
||||
userIDs = (ArrayList<String>) source.readSerializable();
|
||||
originalIDs = (ArrayList<String>) source.readSerializable();
|
||||
deletedIDs = (ArrayList<String>) source.readSerializable();
|
||||
newIDs = source.createBooleanArray();
|
||||
primaryIDChanged = source.readByte() != 0;
|
||||
moddedKeys = source.createBooleanArray();
|
||||
byte[] tmp = source.createByteArray();
|
||||
if (tmp == null)
|
||||
if (tmp == null) {
|
||||
deletedKeys = null;
|
||||
else
|
||||
} else {
|
||||
deletedKeys = PgpConversionHelper.BytesToPGPSecretKeyList(tmp);
|
||||
keysExpiryDates = (ArrayList<GregorianCalendar>)source.readSerializable();
|
||||
}
|
||||
keysExpiryDates = (ArrayList<GregorianCalendar>) source.readSerializable();
|
||||
keysUsages = source.readArrayList(Integer.class.getClassLoader());
|
||||
newPassPhrase = source.readString();
|
||||
oldPassPhrase = source.readString();
|
||||
newPassphrase = source.readString();
|
||||
oldPassphrase = source.readString();
|
||||
newKeys = source.createBooleanArray();
|
||||
keys = PgpConversionHelper.BytesToPGPSecretKeyList(source.createByteArray());
|
||||
originalPrimaryID = source.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel destination, int flags)
|
||||
{
|
||||
public void writeToParcel(Parcel destination, int flags) {
|
||||
destination.writeSerializable(userIDs); //might not be the best method to store.
|
||||
destination.writeSerializable(originalIDs);
|
||||
destination.writeSerializable(deletedIDs);
|
||||
destination.writeBooleanArray(newIDs);
|
||||
destination.writeByte((byte) (primaryIDChanged ? 1 : 0));
|
||||
destination.writeBooleanArray(moddedKeys);
|
||||
byte[] tmp = null;
|
||||
if (deletedKeys.size() != 0)
|
||||
if (deletedKeys.size() != 0) {
|
||||
tmp = PgpConversionHelper.PGPSecretKeyArrayListToBytes(deletedKeys);
|
||||
}
|
||||
destination.writeByteArray(tmp);
|
||||
destination.writeSerializable(keysExpiryDates);
|
||||
destination.writeList(keysUsages);
|
||||
destination.writeString(newPassPhrase);
|
||||
destination.writeString(oldPassPhrase);
|
||||
destination.writeString(newPassphrase);
|
||||
destination.writeString(oldPassphrase);
|
||||
destination.writeBooleanArray(newKeys);
|
||||
destination.writeByteArray(PgpConversionHelper.PGPSecretKeyArrayListToBytes(keys));
|
||||
destination.writeString(originalPrimaryID);
|
||||
@@ -98,8 +101,7 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents()
|
||||
{
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2011 Senecaso
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
@@ -32,13 +32,18 @@ import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.*;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.helper.OtherHelper;
|
||||
import org.sufficientlysecure.keychain.helper.Preferences;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||
@@ -200,7 +205,8 @@ public class CertifyKeyActivity extends ActionBarActivity implements
|
||||
|
||||
byte[] fingerprintBlob = data.getBlob(INDEX_FINGERPRINT);
|
||||
String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
|
||||
((TextView) findViewById(R.id.fingerprint)).setText(PgpKeyHelper.colorizeFingerprint(fingerprint));
|
||||
((TextView) findViewById(R.id.fingerprint))
|
||||
.setText(PgpKeyHelper.colorizeFingerprint(fingerprint));
|
||||
}
|
||||
break;
|
||||
case LOADER_ID_USER_IDS:
|
||||
@@ -294,7 +300,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements
|
||||
|
||||
// Bail out if there is not at least one user id selected
|
||||
ArrayList<String> userIds = mUserIdsAdapter.getSelectedUserIds();
|
||||
if(userIds.isEmpty()) {
|
||||
if (userIds.isEmpty()) {
|
||||
Toast.makeText(CertifyKeyActivity.this, "No User IDs to sign selected!",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
|
||||
@@ -77,8 +77,10 @@ public class DecryptActivity extends DrawerActivity {
|
||||
// Handle intent actions, maybe changes the bundles
|
||||
handleActions(getIntent());
|
||||
|
||||
mTabsAdapter.addTab(DecryptMessageFragment.class, mMessageFragmentBundle, getString(R.string.label_message));
|
||||
mTabsAdapter.addTab(DecryptFileFragment.class, mFileFragmentBundle, getString(R.string.label_file));
|
||||
mTabsAdapter.addTab(DecryptMessageFragment.class,
|
||||
mMessageFragmentBundle, getString(R.string.label_message));
|
||||
mTabsAdapter.addTab(DecryptFileFragment.class,
|
||||
mFileFragmentBundle, getString(R.string.label_file));
|
||||
mViewPager.setCurrentItem(mSwitchToTab);
|
||||
}
|
||||
|
||||
@@ -164,7 +166,8 @@ public class DecryptActivity extends DrawerActivity {
|
||||
mSwitchToTab = PAGER_TAB_FILE;
|
||||
} else {
|
||||
Log.e(Constants.TAG,
|
||||
"Direct binary data without actual file in filesystem is not supported. Please use the Remote Service API!");
|
||||
"Direct binary data without actual file in filesystem is not supported. " +
|
||||
"Please use the Remote Service API!");
|
||||
Toast.makeText(this, R.string.error_only_files_are_supported, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
// end activity
|
||||
|
||||
@@ -200,9 +200,13 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
|
||||
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
||||
showPassphraseDialog(decryptVerifyResult.getKeyIdPassphraseNeeded());
|
||||
} else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
||||
} else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED ==
|
||||
decryptVerifyResult.getStatus()) {
|
||||
showPassphraseDialog(Id.key.symmetric);
|
||||
} else {
|
||||
AppMsg.makeText(getActivity(), R.string.decryption_successful,
|
||||
AppMsg.STYLE_INFO).show();
|
||||
|
||||
if (mDeleteAfter.isChecked()) {
|
||||
// Create and show dialog to delete original file
|
||||
DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment
|
||||
|
||||
@@ -47,10 +47,14 @@ import java.util.regex.Matcher;
|
||||
public class DecryptMessageFragment extends DecryptFragment {
|
||||
public static final String ARG_CIPHERTEXT = "ciphertext";
|
||||
|
||||
// view
|
||||
private EditText mMessage;
|
||||
private BootstrapButton mDecryptButton;
|
||||
private BootstrapButton mDecryptFromCLipboardButton;
|
||||
|
||||
// model
|
||||
private String mCiphertext;
|
||||
|
||||
/**
|
||||
* Inflate the layout for this fragment
|
||||
*/
|
||||
@@ -64,13 +68,13 @@ public class DecryptMessageFragment extends DecryptFragment {
|
||||
mDecryptButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
decryptStart(null);
|
||||
decryptClicked();
|
||||
}
|
||||
});
|
||||
mDecryptFromCLipboardButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
decryptFromClipboard();
|
||||
decryptFromClipboardClicked();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -88,7 +92,12 @@ public class DecryptMessageFragment extends DecryptFragment {
|
||||
}
|
||||
}
|
||||
|
||||
private void decryptFromClipboard() {
|
||||
private void decryptClicked() {
|
||||
mCiphertext = mMessage.getText().toString();
|
||||
decryptStart(null);
|
||||
}
|
||||
|
||||
private void decryptFromClipboardClicked() {
|
||||
CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity());
|
||||
|
||||
// only decrypt if clipboard content is available and a pgp message or cleartext signature
|
||||
@@ -98,8 +107,7 @@ public class DecryptMessageFragment extends DecryptFragment {
|
||||
matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(clipboardText);
|
||||
}
|
||||
if (matcher.matches()) {
|
||||
String data = matcher.group(1);
|
||||
mMessage.setText(data);
|
||||
mCiphertext = matcher.group(1);
|
||||
decryptStart(null);
|
||||
} else {
|
||||
AppMsg.makeText(getActivity(), R.string.error_invalid_data, AppMsg.STYLE_INFO)
|
||||
@@ -125,8 +133,7 @@ public class DecryptMessageFragment extends DecryptFragment {
|
||||
|
||||
// data
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_BYTES);
|
||||
String message = mMessage.getText().toString();
|
||||
data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, message.getBytes());
|
||||
data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, mCiphertext.getBytes());
|
||||
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, passphrase);
|
||||
|
||||
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
||||
@@ -147,7 +154,8 @@ public class DecryptMessageFragment extends DecryptFragment {
|
||||
|
||||
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
||||
showPassphraseDialog(decryptVerifyResult.getKeyIdPassphraseNeeded());
|
||||
} else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
||||
} else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED ==
|
||||
decryptVerifyResult.getStatus()) {
|
||||
showPassphraseDialog(Id.key.symmetric);
|
||||
} else {
|
||||
AppMsg.makeText(getActivity(), R.string.decryption_successful,
|
||||
|
||||
@@ -27,9 +27,18 @@ import android.support.v4.app.ActionBarDrawerToggle;
|
||||
import android.support.v4.view.GravityCompat;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.beardedhen.androidbootstrap.FontAwesomeText;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
|
||||
@@ -58,7 +67,7 @@ public class DrawerActivity extends ActionBarActivity {
|
||||
|
||||
// if the left margin of the loaded layout is close to the
|
||||
// one used in tablets then set drawer as open and locked
|
||||
if( Math.abs(leftMarginLoaded - leftMarginInTablets) < errorInMarginAllowed) {
|
||||
if (Math.abs(leftMarginLoaded - leftMarginInTablets) < errorInMarginAllowed) {
|
||||
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN, mDrawerList);
|
||||
mDrawerLayout.setScrimColor(Color.TRANSPARENT);
|
||||
mIsDrawerLocked = true;
|
||||
@@ -82,7 +91,7 @@ public class DrawerActivity extends ActionBarActivity {
|
||||
|
||||
// enable ActionBar app icon to behave as action to toggle nav drawer
|
||||
// if the drawer is not locked
|
||||
if ( !mIsDrawerLocked ) {
|
||||
if (!mIsDrawerLocked) {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setHomeButtonEnabled(true);
|
||||
}
|
||||
@@ -109,20 +118,18 @@ public class DrawerActivity extends ActionBarActivity {
|
||||
}
|
||||
};
|
||||
|
||||
if ( !mIsDrawerLocked ) {
|
||||
if (!mIsDrawerLocked) {
|
||||
mDrawerLayout.setDrawerListener(mDrawerToggle);
|
||||
} else {
|
||||
// If the drawer is locked open make it un-focusable
|
||||
// so that it doesn't consume all the Back button presses
|
||||
mDrawerLayout.setFocusableInTouchMode(false);
|
||||
}
|
||||
// if (savedInstanceState == null) {
|
||||
// selectItem(0);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses startActivity to call the Intent of the given class
|
||||
*
|
||||
* @param drawerItem the class of the drawer item you want to load. Based on Constants.DrawerItems.*
|
||||
*/
|
||||
public void callIntentForDrawerItem(Class drawerItem) {
|
||||
@@ -150,16 +157,6 @@ public class DrawerActivity extends ActionBarActivity {
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
/* Called whenever we call invalidateOptionsMenu() */
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
// If the nav drawer is open, hide action items related to the content
|
||||
// view
|
||||
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
|
||||
// menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
// The action bar home/up action should open or close the drawer.
|
||||
@@ -182,26 +179,11 @@ public class DrawerActivity extends ActionBarActivity {
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
// Handle action buttons
|
||||
// switch (item.getItemId()) {
|
||||
// case R.id.action_websearch:
|
||||
// // create intent to perform web search for this planet
|
||||
// Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
|
||||
// intent.putExtra(SearchManager.QUERY, getSupportActionBar().getTitle());
|
||||
// // catch event that there's no activity to handle intent
|
||||
// if (intent.resolveActivity(getPackageManager()) != null) {
|
||||
// startActivity(intent);
|
||||
// } else {
|
||||
// Toast.makeText(this, R.string.app_not_available, Toast.LENGTH_LONG).show();
|
||||
// }
|
||||
// return true;
|
||||
// default:
|
||||
// return super.onOptionsItemSelected(item);
|
||||
// }
|
||||
}
|
||||
|
||||
/* The click listener for ListView in the navigation drawer */
|
||||
/**
|
||||
* The click listener for ListView in the navigation drawer
|
||||
*/
|
||||
private class DrawerItemClickListener implements ListView.OnItemClickListener {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
@@ -218,9 +200,9 @@ public class DrawerActivity extends ActionBarActivity {
|
||||
// setTitle(mDrawerTitles[position]);
|
||||
// If drawer isn't locked just close the drawer and
|
||||
// it will move to the selected item by itself (via drawer toggle listener)
|
||||
if ( !mIsDrawerLocked ) {
|
||||
if (!mIsDrawerLocked) {
|
||||
mDrawerLayout.closeDrawer(mDrawerList);
|
||||
// else move to the selected item yourself
|
||||
// else move to the selected item yourself
|
||||
} else {
|
||||
callIntentForDrawerItem(mSelectedItem);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,13 +17,8 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
@@ -33,19 +28,26 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.view.*;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||
import com.devspark.appmsg.AppMsg;
|
||||
|
||||
import org.spongycastle.openpgp.PGPSecretKey;
|
||||
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
@@ -63,20 +65,17 @@ import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.widget.Editor;
|
||||
import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener;
|
||||
import org.sufficientlysecure.keychain.ui.widget.KeyEditor;
|
||||
import org.sufficientlysecure.keychain.ui.widget.SectionView;
|
||||
import org.sufficientlysecure.keychain.ui.widget.UserIdEditor;
|
||||
import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener;
|
||||
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import java.util.ArrayList;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
public class EditKeyActivity extends ActionBarActivity implements EditorListener {
|
||||
|
||||
@@ -89,10 +88,6 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
public static final String EXTRA_NO_PASSPHRASE = "no_passphrase";
|
||||
public static final String EXTRA_GENERATE_DEFAULT_KEYS = "generate_default_keys";
|
||||
|
||||
// results when saving key
|
||||
public static final String RESULT_EXTRA_MASTER_KEY_ID = "master_key_id";
|
||||
public static final String RESULT_EXTRA_USER_ID = "user_id";
|
||||
|
||||
// EDIT
|
||||
private Uri mDataUri;
|
||||
|
||||
@@ -102,9 +97,9 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
private SectionView mKeysView;
|
||||
|
||||
private String mCurrentPassphrase = null;
|
||||
private String mNewPassPhrase = null;
|
||||
private String mSavedNewPassPhrase = null;
|
||||
private boolean mIsPassPhraseSet;
|
||||
private String mNewPassphrase = null;
|
||||
private String mSavedNewPassphrase = null;
|
||||
private boolean mIsPassphraseSet;
|
||||
private boolean mNeedsSaving;
|
||||
private boolean mIsBrandNewKeyring = false;
|
||||
|
||||
@@ -119,8 +114,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
|
||||
ExportHelper mExportHelper;
|
||||
|
||||
public boolean needsSaving()
|
||||
{
|
||||
public boolean needsSaving() {
|
||||
mNeedsSaving = (mUserIdsView == null) ? false : mUserIdsView.needsSaving();
|
||||
mNeedsSaving |= (mKeysView == null) ? false : mKeysView.needsSaving();
|
||||
mNeedsSaving |= hasPassphraseChanged();
|
||||
@@ -129,19 +123,15 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
}
|
||||
|
||||
|
||||
public void somethingChanged()
|
||||
{
|
||||
public void somethingChanged() {
|
||||
ActivityCompat.invalidateOptionsMenu(this);
|
||||
//Toast.makeText(this, "Needs saving: " + Boolean.toString(mNeedsSaving) + "(" + Boolean.toString(mUserIdsView.needsSaving()) + ", " + Boolean.toString(mKeysView.needsSaving()) + ")", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
public void onDeleted(Editor e, boolean wasNewItem)
|
||||
{
|
||||
public void onDeleted(Editor e, boolean wasNewItem) {
|
||||
somethingChanged();
|
||||
}
|
||||
|
||||
public void onEdited()
|
||||
{
|
||||
public void onEdited() {
|
||||
somethingChanged();
|
||||
}
|
||||
|
||||
@@ -300,7 +290,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
|
||||
mCurrentPassphrase = PassphraseCacheService.getCachedPassphrase(
|
||||
EditKeyActivity.this, masterKeyId);
|
||||
finallySaveClicked();
|
||||
checkEmptyIDsWanted();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -337,41 +327,43 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
cancelClicked(); //TODO: why isn't this triggered on my tablet - one of many ui problems I've had with this device. A code compatibility issue or a Samsung fail?
|
||||
return true;
|
||||
case R.id.menu_key_edit_cancel:
|
||||
cancelClicked();
|
||||
return true;
|
||||
case R.id.menu_key_edit_export_file:
|
||||
if (needsSaving()) {
|
||||
Toast.makeText(this, R.string.error_save_first, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
|
||||
case android.R.id.home:
|
||||
cancelClicked();
|
||||
// TODO: why isn't this triggered on my tablet - one of many ui problems
|
||||
// I've had with this device. A code compatibility issue or a Samsung fail?
|
||||
return true;
|
||||
case R.id.menu_key_edit_cancel:
|
||||
cancelClicked();
|
||||
return true;
|
||||
case R.id.menu_key_edit_export_file:
|
||||
if (needsSaving()) {
|
||||
Toast.makeText(this, R.string.error_save_first, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
|
||||
long[] ids = new long[]{masterKeyId};
|
||||
mExportHelper.showExportKeysDialog(ids, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC,
|
||||
null);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
case R.id.menu_key_edit_delete:
|
||||
long rowId= ProviderHelper.getRowId(this,mDataUri);
|
||||
Uri convertUri = KeychainContract.KeyRings.buildSecretKeyRingUri(Long.toString(rowId));
|
||||
// Message is received after key is deleted
|
||||
Handler returnHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) {
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
}};
|
||||
mExportHelper.deleteKey(convertUri, returnHandler);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
case R.id.menu_key_edit_delete:
|
||||
long rowId= ProviderHelper.getRowId(this,mDataUri);
|
||||
Uri convertUri = KeychainContract.KeyRings.buildSecretKeyRingUri(Long.toString(rowId));
|
||||
// Message is received after key is deleted
|
||||
Handler returnHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) {
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
}};
|
||||
mExportHelper.deleteKey(convertUri, returnHandler);
|
||||
return true;
|
||||
|
||||
case R.id.menu_key_edit_save:
|
||||
saveClicked();
|
||||
return true;
|
||||
case R.id.menu_key_edit_save:
|
||||
saveClicked();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
@@ -398,8 +390,9 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
if (!isSet) {
|
||||
isSet = true;
|
||||
String[] parts = PgpKeyHelper.splitUserId(userId);
|
||||
if (parts[0] != null)
|
||||
if (parts[0] != null) {
|
||||
setTitle(parts[0]);
|
||||
}
|
||||
}
|
||||
mUserIds.add(userId);
|
||||
}
|
||||
@@ -409,8 +402,8 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
mCurrentPassphrase = "";
|
||||
buildLayout(false);
|
||||
|
||||
mIsPassPhraseSet = PassphraseCacheService.hasPassphrase(this, masterKeyId);
|
||||
if (!mIsPassPhraseSet) {
|
||||
mIsPassphraseSet = PassphraseCacheService.hasPassphrase(this, masterKeyId);
|
||||
if (!mIsPassphraseSet) {
|
||||
// check "no passphrase" checkbox and remove button
|
||||
mNoPassphrase.setChecked(true);
|
||||
mChangePassphrase.setVisibility(View.GONE);
|
||||
@@ -429,10 +422,10 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
Bundle data = message.getData();
|
||||
|
||||
// set new returned passphrase!
|
||||
mNewPassPhrase = data
|
||||
mNewPassphrase = data
|
||||
.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE);
|
||||
|
||||
updatePassPhraseButtonText();
|
||||
updatePassphraseButtonText();
|
||||
somethingChanged();
|
||||
}
|
||||
}
|
||||
@@ -458,6 +451,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
/**
|
||||
* Build layout based on mUserId, mKeys and mKeysUsages Vectors. It creates Views for every user
|
||||
* id and key.
|
||||
*
|
||||
* @param newKeys
|
||||
*/
|
||||
private void buildLayout(boolean newKeys) {
|
||||
@@ -471,23 +465,23 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
LinearLayout container = (LinearLayout) findViewById(R.id.edit_key_container);
|
||||
if(mIsPassPhraseSet){
|
||||
if (mIsPassphraseSet) {
|
||||
mChangePassphrase.setText(getString(R.string.btn_change_passphrase));
|
||||
}
|
||||
mUserIdsView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false);
|
||||
mUserIdsView.setType(Id.type.user_id);
|
||||
mUserIdsView.setCanEdit(mMasterCanSign);
|
||||
mUserIdsView.setCanBeEdited(mMasterCanSign);
|
||||
mUserIdsView.setUserIds(mUserIds);
|
||||
mUserIdsView.setEditorListener(this);
|
||||
container.addView(mUserIdsView);
|
||||
mKeysView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false);
|
||||
mKeysView.setType(Id.type.key);
|
||||
mKeysView.setCanEdit(mMasterCanSign);
|
||||
mKeysView.setCanBeEdited(mMasterCanSign);
|
||||
mKeysView.setKeys(mKeys, mKeysUsages, newKeys);
|
||||
mKeysView.setEditorListener(this);
|
||||
container.addView(mKeysView);
|
||||
|
||||
updatePassPhraseButtonText();
|
||||
updatePassphraseButtonText();
|
||||
|
||||
mChangePassphrase.setOnClickListener(new OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
@@ -502,11 +496,11 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (isChecked) {
|
||||
// remove passphrase
|
||||
mSavedNewPassPhrase = mNewPassPhrase;
|
||||
mNewPassPhrase = "";
|
||||
mSavedNewPassphrase = mNewPassphrase;
|
||||
mNewPassphrase = "";
|
||||
mChangePassphrase.setVisibility(View.GONE);
|
||||
} else {
|
||||
mNewPassPhrase = mSavedNewPassPhrase;
|
||||
mNewPassphrase = mSavedNewPassphrase;
|
||||
mChangePassphrase.setVisibility(View.VISIBLE);
|
||||
}
|
||||
somethingChanged();
|
||||
@@ -524,23 +518,22 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
public boolean isPassphraseSet() {
|
||||
if (mNoPassphrase.isChecked()) {
|
||||
return true;
|
||||
} else if ((mIsPassPhraseSet)
|
||||
|| (mNewPassPhrase != null && !mNewPassPhrase.equals(""))) {
|
||||
} else if ((mIsPassphraseSet)
|
||||
|| (mNewPassphrase != null && !mNewPassphrase.equals(""))) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasPassphraseChanged()
|
||||
{
|
||||
public boolean hasPassphraseChanged() {
|
||||
if (mNoPassphrase != null) {
|
||||
if (mNoPassphrase.isChecked()) {
|
||||
return mIsPassPhraseSet;
|
||||
return mIsPassphraseSet;
|
||||
} else {
|
||||
return (mNewPassPhrase != null && !mNewPassPhrase.equals(""));
|
||||
return (mNewPassphrase != null && !mNewPassphrase.equals(""));
|
||||
}
|
||||
}else {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -554,15 +547,16 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
}
|
||||
|
||||
String passphrase;
|
||||
if (mIsPassPhraseSet)
|
||||
if (mIsPassphraseSet) {
|
||||
passphrase = PassphraseCacheService.getCachedPassphrase(this, masterKeyId);
|
||||
else
|
||||
} else {
|
||||
passphrase = "";
|
||||
}
|
||||
if (passphrase == null) {
|
||||
showPassphraseDialog(masterKeyId);
|
||||
} else {
|
||||
mCurrentPassphrase = passphrase;
|
||||
finallySaveClicked();
|
||||
checkEmptyIDsWanted();
|
||||
}
|
||||
} catch (PgpGeneralException e) {
|
||||
Toast.makeText(this, getString(R.string.error_message, e.getMessage()),
|
||||
@@ -573,6 +567,50 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
}
|
||||
}
|
||||
|
||||
private void checkEmptyIDsWanted() {
|
||||
try {
|
||||
ArrayList<String> userIDs = getUserIds(mUserIdsView);
|
||||
List<Boolean> newIDs = mUserIdsView.getNewIDFlags();
|
||||
ArrayList<String> originalIDs = mUserIdsView.getOriginalIDs();
|
||||
int curID = 0;
|
||||
for (String userID : userIDs) {
|
||||
if (userID.equals("") && (!userID.equals(originalIDs.get(curID)) || newIDs.get(curID))) {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(
|
||||
EditKeyActivity.this);
|
||||
|
||||
alert.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
alert.setTitle(R.string.warning);
|
||||
alert.setMessage(EditKeyActivity.this.getString(R.string.ask_empty_id_ok));
|
||||
|
||||
alert.setPositiveButton(EditKeyActivity.this.getString(android.R.string.yes),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dialog.dismiss();
|
||||
finallySaveClicked();
|
||||
}
|
||||
}
|
||||
);
|
||||
alert.setNegativeButton(this.getString(android.R.string.no),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
);
|
||||
alert.setCancelable(false);
|
||||
alert.create().show();
|
||||
return;
|
||||
}
|
||||
curID++;
|
||||
}
|
||||
} catch (PgpGeneralException e) {
|
||||
Log.e(Constants.TAG, getString(R.string.error_message, e.getMessage()));
|
||||
Toast.makeText(this, getString(R.string.error_message, e.getMessage()),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
finallySaveClicked();
|
||||
}
|
||||
|
||||
private boolean[] toPrimitiveArray(final List<Boolean> booleanList) {
|
||||
final boolean[] primitives = new boolean[booleanList.size()];
|
||||
int index = 0;
|
||||
@@ -593,13 +631,14 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
saveParams.userIDs = getUserIds(mUserIdsView);
|
||||
saveParams.originalIDs = mUserIdsView.getOriginalIDs();
|
||||
saveParams.deletedIDs = mUserIdsView.getDeletedIDs();
|
||||
saveParams.newIDs = toPrimitiveArray(mUserIdsView.getNewIDFlags());
|
||||
saveParams.primaryIDChanged = mUserIdsView.primaryChanged();
|
||||
saveParams.moddedKeys = toPrimitiveArray(mKeysView.getNeedsSavingArray());
|
||||
saveParams.deletedKeys = mKeysView.getDeletedKeys();
|
||||
saveParams.keysExpiryDates = getKeysExpiryDates(mKeysView);
|
||||
saveParams.keysUsages = getKeysUsages(mKeysView);
|
||||
saveParams.newPassPhrase = mNewPassPhrase;
|
||||
saveParams.oldPassPhrase = mCurrentPassphrase;
|
||||
saveParams.newPassphrase = mNewPassphrase;
|
||||
saveParams.oldPassphrase = mCurrentPassphrase;
|
||||
saveParams.newKeys = toPrimitiveArray(mKeysView.getNewKeysArray());
|
||||
saveParams.keys = getKeys(mKeysView);
|
||||
saveParams.originalPrimaryID = mUserIdsView.getOriginalPrimaryID();
|
||||
@@ -621,14 +660,12 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
Intent data = new Intent();
|
||||
data.putExtra(RESULT_EXTRA_MASTER_KEY_ID, getMasterKeyId());
|
||||
ArrayList<String> userIds = null;
|
||||
try {
|
||||
userIds = getUserIds(mUserIdsView);
|
||||
} catch (PgpGeneralException e) {
|
||||
Log.e(Constants.TAG, "exception while getting user ids", e);
|
||||
}
|
||||
data.putExtra(RESULT_EXTRA_USER_ID, userIds.get(0));
|
||||
|
||||
// return uri pointing to new created key
|
||||
Uri uri = KeychainContract.KeyRings.buildGenericKeyRingUri(
|
||||
String.valueOf(getMasterKeyId()));
|
||||
data.setData(uri);
|
||||
|
||||
setResult(RESULT_OK, data);
|
||||
finish();
|
||||
}
|
||||
@@ -781,7 +818,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
||||
return keysExpiryDates;
|
||||
}
|
||||
|
||||
private void updatePassPhraseButtonText() {
|
||||
private void updatePassphraseButtonText() {
|
||||
mChangePassphrase.setText(isPassphraseSet() ? getString(R.string.btn_change_passphrase)
|
||||
: getString(R.string.btn_set_passphrase));
|
||||
}
|
||||
|
||||
@@ -155,12 +155,16 @@ public class EncryptActivity extends DrawerActivity implements
|
||||
// Handle intent actions
|
||||
handleActions(getIntent());
|
||||
|
||||
mTabsAdapterMode.addTab(EncryptAsymmetricFragment.class, mAsymmetricFragmentBundle, getString(R.string.label_asymmetric));
|
||||
mTabsAdapterMode.addTab(EncryptSymmetricFragment.class, mSymmetricFragmentBundle, getString(R.string.label_symmetric));
|
||||
mTabsAdapterMode.addTab(EncryptAsymmetricFragment.class,
|
||||
mAsymmetricFragmentBundle, getString(R.string.label_asymmetric));
|
||||
mTabsAdapterMode.addTab(EncryptSymmetricFragment.class,
|
||||
mSymmetricFragmentBundle, getString(R.string.label_symmetric));
|
||||
mViewPagerMode.setCurrentItem(mSwitchToMode);
|
||||
|
||||
mTabsAdapterContent.addTab(EncryptMessageFragment.class, mMessageFragmentBundle, getString(R.string.label_message));
|
||||
mTabsAdapterContent.addTab(EncryptFileFragment.class, mFileFragmentBundle, getString(R.string.label_file));
|
||||
mTabsAdapterContent.addTab(EncryptMessageFragment.class,
|
||||
mMessageFragmentBundle, getString(R.string.label_message));
|
||||
mTabsAdapterContent.addTab(EncryptFileFragment.class,
|
||||
mFileFragmentBundle, getString(R.string.label_file));
|
||||
mViewPagerContent.setCurrentItem(mSwitchToContent);
|
||||
}
|
||||
|
||||
@@ -212,8 +216,10 @@ public class EncryptActivity extends DrawerActivity implements
|
||||
long[] encryptionKeyIds = extras.getLongArray(EXTRA_ENCRYPTION_KEY_IDS);
|
||||
|
||||
// preselect keys given by intent
|
||||
mAsymmetricFragmentBundle.putLongArray(EncryptAsymmetricFragment.ARG_ENCRYPTION_KEY_IDS, encryptionKeyIds);
|
||||
mAsymmetricFragmentBundle.putLong(EncryptAsymmetricFragment.ARG_SIGNATURE_KEY_ID, signatureKeyId);
|
||||
mAsymmetricFragmentBundle.putLongArray(EncryptAsymmetricFragment.ARG_ENCRYPTION_KEY_IDS,
|
||||
encryptionKeyIds);
|
||||
mAsymmetricFragmentBundle.putLong(EncryptAsymmetricFragment.ARG_SIGNATURE_KEY_ID,
|
||||
signatureKeyId);
|
||||
mSwitchToMode = PAGER_MODE_ASYMMETRIC;
|
||||
|
||||
/**
|
||||
@@ -234,7 +240,8 @@ public class EncryptActivity extends DrawerActivity implements
|
||||
mSwitchToContent = PAGER_CONTENT_FILE;
|
||||
} else {
|
||||
Log.e(Constants.TAG,
|
||||
"Direct binary data without actual file in filesystem is not supported by Intents. Please use the Remote Service API!");
|
||||
"Direct binary data without actual file in filesystem is not supported " +
|
||||
"by Intents. Please use the Remote Service API!");
|
||||
Toast.makeText(this, R.string.error_only_files_are_supported, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
// end activity
|
||||
|
||||
@@ -264,8 +264,8 @@ public class EncryptAsymmetricFragment extends Fragment {
|
||||
|
||||
case RESULT_CODE_SECRET_KEYS: {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
Uri uri_master_key = data.getData();
|
||||
setSignatureKeyId(Long.valueOf(uri_master_key.getLastPathSegment()));
|
||||
Uri uriMasterKey = data.getData();
|
||||
setSignatureKeyId(Long.valueOf(uriMasterKey.getLastPathSegment()));
|
||||
} else {
|
||||
setSignatureKeyId(Id.key.none);
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ public class EncryptFileFragment extends Fragment {
|
||||
});
|
||||
|
||||
mFileCompression = (Spinner) view.findViewById(R.id.fileCompression);
|
||||
Choice[] choices = new Choice[]{
|
||||
Choice[] choices = new Choice[] {
|
||||
new Choice(Id.choice.compression.none, getString(R.string.choice_none) + " ("
|
||||
+ getString(R.string.compression_fast) + ")"),
|
||||
new Choice(Id.choice.compression.zip, "ZIP ("
|
||||
@@ -120,7 +120,8 @@ public class EncryptFileFragment extends Fragment {
|
||||
new Choice(Id.choice.compression.zlib, "ZLIB ("
|
||||
+ getString(R.string.compression_fast) + ")"),
|
||||
new Choice(Id.choice.compression.bzip2, "BZIP2 ("
|
||||
+ getString(R.string.compression_very_slow) + ")"),};
|
||||
+ getString(R.string.compression_very_slow) + ")"),
|
||||
};
|
||||
ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(getActivity(),
|
||||
android.R.layout.simple_spinner_item, choices);
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
@@ -137,8 +138,8 @@ public class EncryptFileFragment extends Fragment {
|
||||
mDeleteAfter = (CheckBox) view.findViewById(R.id.deleteAfterEncryption);
|
||||
mShareAfter = (CheckBox) view.findViewById(R.id.shareAfterEncryption);
|
||||
|
||||
mAsciiArmor = (CheckBox) view.findViewById(R.id.asciiArmour);
|
||||
mAsciiArmor.setChecked(Preferences.getPreferences(getActivity()).getDefaultAsciiArmour());
|
||||
mAsciiArmor = (CheckBox) view.findViewById(R.id.asciiArmor);
|
||||
mAsciiArmor.setChecked(Preferences.getPreferences(getActivity()).getDefaultAsciiArmor());
|
||||
|
||||
return view;
|
||||
}
|
||||
@@ -223,9 +224,9 @@ public class EncryptFileFragment extends Fragment {
|
||||
if (mEncryptInterface.isModeSymmetric()) {
|
||||
// symmetric encryption
|
||||
|
||||
boolean gotPassPhrase = (mEncryptInterface.getPassphrase() != null
|
||||
boolean gotPassphrase = (mEncryptInterface.getPassphrase() != null
|
||||
&& mEncryptInterface.getPassphrase().length() != 0);
|
||||
if (!gotPassPhrase) {
|
||||
if (!gotPassphrase) {
|
||||
AppMsg.makeText(getActivity(), R.string.passphrase_must_not_be_empty, AppMsg.STYLE_ALERT)
|
||||
.show();
|
||||
return;
|
||||
@@ -252,8 +253,9 @@ public class EncryptFileFragment extends Fragment {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mEncryptInterface.getSignatureKey() != 0
|
||||
&& PassphraseCacheService.getCachedPassphrase(getActivity(), mEncryptInterface.getSignatureKey()) == null) {
|
||||
if (mEncryptInterface.getSignatureKey() != 0 &&
|
||||
PassphraseCacheService.getCachedPassphrase(getActivity(),
|
||||
mEncryptInterface.getSignatureKey()) == null) {
|
||||
showPassphraseDialog();
|
||||
|
||||
return;
|
||||
@@ -282,8 +284,10 @@ public class EncryptFileFragment extends Fragment {
|
||||
}
|
||||
data.putString(KeychainIntentService.ENCRYPT_SYMMETRIC_PASSPHRASE, passphrase);
|
||||
} else {
|
||||
data.putLong(KeychainIntentService.ENCRYPT_SIGNATURE_KEY_ID, mEncryptInterface.getSignatureKey());
|
||||
data.putLongArray(KeychainIntentService.ENCRYPT_ENCRYPTION_KEYS_IDS, mEncryptInterface.getEncryptionKeys());
|
||||
data.putLong(KeychainIntentService.ENCRYPT_SIGNATURE_KEY_ID,
|
||||
mEncryptInterface.getSignatureKey());
|
||||
data.putLongArray(KeychainIntentService.ENCRYPT_ENCRYPTION_KEYS_IDS,
|
||||
mEncryptInterface.getEncryptionKeys());
|
||||
}
|
||||
|
||||
Log.d(Constants.TAG, "mInputFilename=" + mInputFilename + ", mOutputFilename="
|
||||
|
||||
@@ -125,9 +125,9 @@ public class EncryptMessageFragment extends Fragment {
|
||||
if (mEncryptInterface.isModeSymmetric()) {
|
||||
// symmetric encryption
|
||||
|
||||
boolean gotPassPhrase = (mEncryptInterface.getPassphrase() != null
|
||||
boolean gotPassphrase = (mEncryptInterface.getPassphrase() != null
|
||||
&& mEncryptInterface.getPassphrase().length() != 0);
|
||||
if (!gotPassPhrase) {
|
||||
if (!gotPassphrase) {
|
||||
AppMsg.makeText(getActivity(), R.string.passphrase_must_not_be_empty, AppMsg.STYLE_ALERT)
|
||||
.show();
|
||||
return;
|
||||
@@ -150,8 +150,9 @@ public class EncryptMessageFragment extends Fragment {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mEncryptInterface.getSignatureKey() != 0
|
||||
&& PassphraseCacheService.getCachedPassphrase(getActivity(), mEncryptInterface.getSignatureKey()) == null) {
|
||||
if (mEncryptInterface.getSignatureKey() != 0 &&
|
||||
PassphraseCacheService.getCachedPassphrase(getActivity(),
|
||||
mEncryptInterface.getSignatureKey()) == null) {
|
||||
showPassphraseDialog(toClipboard);
|
||||
|
||||
return;
|
||||
@@ -182,8 +183,10 @@ public class EncryptMessageFragment extends Fragment {
|
||||
}
|
||||
data.putString(KeychainIntentService.ENCRYPT_SYMMETRIC_PASSPHRASE, passphrase);
|
||||
} else {
|
||||
data.putLong(KeychainIntentService.ENCRYPT_SIGNATURE_KEY_ID, mEncryptInterface.getSignatureKey());
|
||||
data.putLongArray(KeychainIntentService.ENCRYPT_ENCRYPTION_KEYS_IDS, mEncryptInterface.getEncryptionKeys());
|
||||
data.putLong(KeychainIntentService.ENCRYPT_SIGNATURE_KEY_ID,
|
||||
mEncryptInterface.getSignatureKey());
|
||||
data.putLongArray(KeychainIntentService.ENCRYPT_ENCRYPTION_KEYS_IDS,
|
||||
mEncryptInterface.getEncryptionKeys());
|
||||
|
||||
boolean signOnly = (mEncryptInterface.getEncryptionKeys() == null
|
||||
|| mEncryptInterface.getEncryptionKeys().length == 0);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2011 Senecaso
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
@@ -168,7 +168,8 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
|
||||
}
|
||||
} else {
|
||||
Log.e(Constants.TAG,
|
||||
"IMPORT_KEY_FROM_KEYSERVER action needs to contain the 'query', 'key_id', or 'fingerprint' extra!");
|
||||
"IMPORT_KEY_FROM_KEYSERVER action needs to contain the 'query', 'key_id', or " +
|
||||
"'fingerprint' extra!");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -233,7 +234,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
|
||||
* onNavigationItemSelected() should check whether the Fragment is already in existence
|
||||
* inside your Activity."
|
||||
* <p/>
|
||||
* from http://stackoverflow.com/questions/10983396/fragment-oncreateview-and-onactivitycreated-called-twice/14295474#14295474
|
||||
* from http://bit.ly/1dBYThO
|
||||
* <p/>
|
||||
* In our case, if we start ImportKeysActivity with parameters to directly search using a fingerprint,
|
||||
* the fragment would be loaded twice resulting in the query being empty after the second load.
|
||||
@@ -337,7 +338,8 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
|
||||
// } else {
|
||||
// status.putString(
|
||||
// EXTRA_ERROR,
|
||||
// "Scanned fingerprint does NOT match the fingerprint of the received key. You shouldnt trust this key.");
|
||||
// "Scanned fingerprint does NOT match the fingerprint of the received key. " +
|
||||
// "You shouldnt trust this key.");
|
||||
// }
|
||||
// }
|
||||
// } catch (QueryException e) {
|
||||
|
||||
@@ -65,7 +65,7 @@ public class ImportKeysClipboardFragment extends Fragment {
|
||||
String sendText = "";
|
||||
if (clipboardText != null) {
|
||||
sendText = clipboardText.toString();
|
||||
if(sendText.toLowerCase(Locale.ENGLISH).startsWith(Constants.FINGERPRINT_SCHEME)) {
|
||||
if (sendText.toLowerCase(Locale.ENGLISH).startsWith(Constants.FINGERPRINT_SCHEME)) {
|
||||
mImportActivity.loadFromFingerprintUri(null, Uri.parse(sendText));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,11 @@ import com.devspark.appmsg.AppMsg;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.helper.Preferences;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.*;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.AsyncTaskResultWrapper;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListServerLoader;
|
||||
import org.sufficientlysecure.keychain.util.InputData;
|
||||
import org.sufficientlysecure.keychain.util.KeyServer;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
import com.google.zxing.integration.android.IntentResult;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
@@ -28,8 +30,9 @@ import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||
import com.google.zxing.integration.android.IntentResult;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.util.IntentIntegratorSupportV4;
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
@@ -55,10 +56,6 @@ public class KeyListActivity extends DrawerActivity {
|
||||
case R.id.menu_key_list_import:
|
||||
callIntentForDrawerItem(Constants.DrawerItems.IMPORT_KEYS);
|
||||
|
||||
return true;
|
||||
case R.id.menu_key_list_export:
|
||||
mExportHelper.showExportKeysDialog(null, Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB, null);
|
||||
|
||||
return true;
|
||||
case R.id.menu_key_list_create:
|
||||
createKey();
|
||||
@@ -67,9 +64,15 @@ public class KeyListActivity extends DrawerActivity {
|
||||
case R.id.menu_key_list_create_expert:
|
||||
createKeyExpert();
|
||||
|
||||
return true;
|
||||
case R.id.menu_key_list_export_public:
|
||||
mExportHelper.showExportKeysDialog(null,
|
||||
Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB, null);
|
||||
|
||||
return true;
|
||||
case R.id.menu_key_list_secret_export:
|
||||
mExportHelper.showExportKeysDialog(null, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC, null);
|
||||
mExportHelper.showExportKeysDialog(null, Id.type.secret_key,
|
||||
Constants.Path.APP_DIR_FILE_SEC, null);
|
||||
|
||||
return true;
|
||||
default:
|
||||
|
||||
@@ -24,7 +24,11 @@ import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.*;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
@@ -33,11 +37,21 @@ import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.support.v7.widget.SearchView;
|
||||
import android.text.TextUtils;
|
||||
import android.view.*;
|
||||
import android.view.ActionMode;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.*;
|
||||
import android.widget.AbsListView.MultiChoiceModeListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Button;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
@@ -191,9 +205,11 @@ public class KeyListFragment extends Fragment
|
||||
ProviderHelper.getPublicKeyRingsRowIds(getActivity());
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
if (allPubRowIds.contains(ids[i])) {
|
||||
masterKeyIds[i] = ProviderHelper.getPublicMasterKeyId(getActivity(), ids[i]);
|
||||
masterKeyIds[i] =
|
||||
ProviderHelper.getPublicMasterKeyId(getActivity(), ids[i]);
|
||||
} else {
|
||||
masterKeyIds[i] = ProviderHelper.getSecretMasterKeyId(getActivity(), ids[i]);
|
||||
masterKeyIds[i] =
|
||||
ProviderHelper.getSecretMasterKeyId(getActivity(), ids[i]);
|
||||
}
|
||||
}*/
|
||||
ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity());
|
||||
|
||||
@@ -20,9 +20,15 @@ import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.*;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.PreferenceScreen;
|
||||
|
||||
import org.spongycastle.bcpg.HashAlgorithmTags;
|
||||
import org.spongycastle.openpgp.PGPEncryptedData;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
@@ -38,11 +44,11 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
public static final String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV";
|
||||
|
||||
private PreferenceScreen mKeyServerPreference = null;
|
||||
private static Preferences mPreferences;
|
||||
private static Preferences sPreferences;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
mPreferences = Preferences.getPreferences(this);
|
||||
sPreferences = Preferences.getPreferences(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// final ActionBar actionBar = getSupportActionBar();
|
||||
@@ -55,11 +61,11 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
if (action != null && action.equals(ACTION_PREFS_GEN)) {
|
||||
addPreferencesFromResource(R.xml.gen_preferences);
|
||||
|
||||
initializePassPassPhraceCacheTtl(
|
||||
(IntegerListPreference) findPreference(Constants.Pref.PASS_PHRASE_CACHE_TTL));
|
||||
initializePassPassphraceCacheTtl(
|
||||
(IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL));
|
||||
|
||||
mKeyServerPreference = (PreferenceScreen) findPreference(Constants.Pref.KEY_SERVERS);
|
||||
String servers[] = mPreferences.getKeyServers();
|
||||
String servers[] = sPreferences.getKeyServers();
|
||||
mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers,
|
||||
servers.length, servers.length));
|
||||
mKeyServerPreference
|
||||
@@ -68,7 +74,7 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
Intent intent = new Intent(PreferencesActivity.this,
|
||||
PreferencesKeyServerActivity.class);
|
||||
intent.putExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS,
|
||||
mPreferences.getKeyServers());
|
||||
sPreferences.getKeyServers());
|
||||
startActivityForResult(intent, Id.request.key_server_preference);
|
||||
return false;
|
||||
}
|
||||
@@ -104,8 +110,8 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
(IntegerListPreference) findPreference(Constants.Pref.DEFAULT_FILE_COMPRESSION),
|
||||
entries, values);
|
||||
|
||||
initializeAsciiArmour(
|
||||
(CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOUR));
|
||||
initializeAsciiArmor(
|
||||
(CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOR));
|
||||
|
||||
initializeForceV3Signatures(
|
||||
(CheckBoxPreference) findPreference(Constants.Pref.FORCE_V3_SIGNATURES));
|
||||
@@ -125,7 +131,7 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
}
|
||||
String servers[] = data
|
||||
.getStringArrayExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS);
|
||||
mPreferences.setKeyServers(servers);
|
||||
sPreferences.setKeyServers(servers);
|
||||
mKeyServerPreference.setSummary(getResources().getQuantityString(
|
||||
R.plurals.n_key_servers, servers.length, servers.length));
|
||||
break;
|
||||
@@ -159,11 +165,11 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
// Load the preferences from an XML resource
|
||||
addPreferencesFromResource(R.xml.gen_preferences);
|
||||
|
||||
initializePassPassPhraceCacheTtl(
|
||||
(IntegerListPreference) findPreference(Constants.Pref.PASS_PHRASE_CACHE_TTL));
|
||||
initializePassPassphraceCacheTtl(
|
||||
(IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL));
|
||||
|
||||
mKeyServerPreference = (PreferenceScreen) findPreference(Constants.Pref.KEY_SERVERS);
|
||||
String servers[] = mPreferences.getKeyServers();
|
||||
String servers[] = sPreferences.getKeyServers();
|
||||
mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers,
|
||||
servers.length, servers.length));
|
||||
mKeyServerPreference
|
||||
@@ -172,7 +178,7 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
Intent intent = new Intent(getActivity(),
|
||||
PreferencesKeyServerActivity.class);
|
||||
intent.putExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS,
|
||||
mPreferences.getKeyServers());
|
||||
sPreferences.getKeyServers());
|
||||
startActivityForResult(intent, Id.request.key_server_preference);
|
||||
return false;
|
||||
}
|
||||
@@ -188,7 +194,7 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
}
|
||||
String servers[] = data
|
||||
.getStringArrayExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS);
|
||||
mPreferences.setKeyServers(servers);
|
||||
sPreferences.setKeyServers(servers);
|
||||
mKeyServerPreference.setSummary(getResources().getQuantityString(
|
||||
R.plurals.n_key_servers, servers.length, servers.length));
|
||||
break;
|
||||
@@ -241,8 +247,8 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
(IntegerListPreference) findPreference(Constants.Pref.DEFAULT_FILE_COMPRESSION),
|
||||
entries, values);
|
||||
|
||||
initializeAsciiArmour(
|
||||
(CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOUR));
|
||||
initializeAsciiArmor(
|
||||
(CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOR));
|
||||
|
||||
initializeForceV3Signatures(
|
||||
(CheckBoxPreference) findPreference(Constants.Pref.FORCE_V3_SIGNATURES));
|
||||
@@ -255,15 +261,15 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
|| super.isValidFragment(fragmentName);
|
||||
}
|
||||
|
||||
private static void initializePassPassPhraceCacheTtl(final IntegerListPreference mPassphraseCacheTtl) {
|
||||
mPassphraseCacheTtl.setValue("" + mPreferences.getPassPhraseCacheTtl());
|
||||
private static void initializePassPassphraceCacheTtl(final IntegerListPreference mPassphraseCacheTtl) {
|
||||
mPassphraseCacheTtl.setValue("" + sPreferences.getPassphraseCacheTtl());
|
||||
mPassphraseCacheTtl.setSummary(mPassphraseCacheTtl.getEntry());
|
||||
mPassphraseCacheTtl
|
||||
.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
mPassphraseCacheTtl.setValue(newValue.toString());
|
||||
mPassphraseCacheTtl.setSummary(mPassphraseCacheTtl.getEntry());
|
||||
mPreferences.setPassPhraseCacheTtl(Integer.parseInt(newValue.toString()));
|
||||
sPreferences.setPassphraseCacheTtl(Integer.parseInt(newValue.toString()));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
@@ -282,14 +288,14 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
}
|
||||
mEncryptionAlgorithm.setEntries(entries);
|
||||
mEncryptionAlgorithm.setEntryValues(values);
|
||||
mEncryptionAlgorithm.setValue("" + mPreferences.getDefaultEncryptionAlgorithm());
|
||||
mEncryptionAlgorithm.setValue("" + sPreferences.getDefaultEncryptionAlgorithm());
|
||||
mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry());
|
||||
mEncryptionAlgorithm
|
||||
.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
mEncryptionAlgorithm.setValue(newValue.toString());
|
||||
mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry());
|
||||
mPreferences.setDefaultEncryptionAlgorithm(Integer.parseInt(newValue
|
||||
sPreferences.setDefaultEncryptionAlgorithm(Integer.parseInt(newValue
|
||||
.toString()));
|
||||
return false;
|
||||
}
|
||||
@@ -309,13 +315,13 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
}
|
||||
mHashAlgorithm.setEntries(entries);
|
||||
mHashAlgorithm.setEntryValues(values);
|
||||
mHashAlgorithm.setValue("" + mPreferences.getDefaultHashAlgorithm());
|
||||
mHashAlgorithm.setValue("" + sPreferences.getDefaultHashAlgorithm());
|
||||
mHashAlgorithm.setSummary(mHashAlgorithm.getEntry());
|
||||
mHashAlgorithm.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
mHashAlgorithm.setValue(newValue.toString());
|
||||
mHashAlgorithm.setSummary(mHashAlgorithm.getEntry());
|
||||
mPreferences.setDefaultHashAlgorithm(Integer.parseInt(newValue.toString()));
|
||||
sPreferences.setDefaultHashAlgorithm(Integer.parseInt(newValue.toString()));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
@@ -326,14 +332,14 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
int[] valueIds, String[] entries, String[] values) {
|
||||
mMessageCompression.setEntries(entries);
|
||||
mMessageCompression.setEntryValues(values);
|
||||
mMessageCompression.setValue("" + mPreferences.getDefaultMessageCompression());
|
||||
mMessageCompression.setValue("" + sPreferences.getDefaultMessageCompression());
|
||||
mMessageCompression.setSummary(mMessageCompression.getEntry());
|
||||
mMessageCompression
|
||||
.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
mMessageCompression.setValue(newValue.toString());
|
||||
mMessageCompression.setSummary(mMessageCompression.getEntry());
|
||||
mPreferences.setDefaultMessageCompression(Integer.parseInt(newValue
|
||||
sPreferences.setDefaultMessageCompression(Integer.parseInt(newValue
|
||||
.toString()));
|
||||
return false;
|
||||
}
|
||||
@@ -344,36 +350,36 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
(final IntegerListPreference mFileCompression, String[] entries, String[] values) {
|
||||
mFileCompression.setEntries(entries);
|
||||
mFileCompression.setEntryValues(values);
|
||||
mFileCompression.setValue("" + mPreferences.getDefaultFileCompression());
|
||||
mFileCompression.setValue("" + sPreferences.getDefaultFileCompression());
|
||||
mFileCompression.setSummary(mFileCompression.getEntry());
|
||||
mFileCompression.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
mFileCompression.setValue(newValue.toString());
|
||||
mFileCompression.setSummary(mFileCompression.getEntry());
|
||||
mPreferences.setDefaultFileCompression(Integer.parseInt(newValue.toString()));
|
||||
sPreferences.setDefaultFileCompression(Integer.parseInt(newValue.toString()));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void initializeAsciiArmour(final CheckBoxPreference mAsciiArmour) {
|
||||
mAsciiArmour.setChecked(mPreferences.getDefaultAsciiArmour());
|
||||
mAsciiArmour.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
private static void initializeAsciiArmor(final CheckBoxPreference mAsciiArmor) {
|
||||
mAsciiArmor.setChecked(sPreferences.getDefaultAsciiArmor());
|
||||
mAsciiArmor.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
mAsciiArmour.setChecked((Boolean) newValue);
|
||||
mPreferences.setDefaultAsciiArmour((Boolean) newValue);
|
||||
mAsciiArmor.setChecked((Boolean) newValue);
|
||||
sPreferences.setDefaultAsciiArmor((Boolean) newValue);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void initializeForceV3Signatures(final CheckBoxPreference mForceV3Signatures) {
|
||||
mForceV3Signatures.setChecked(mPreferences.getForceV3Signatures());
|
||||
mForceV3Signatures.setChecked(sPreferences.getForceV3Signatures());
|
||||
mForceV3Signatures
|
||||
.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
mForceV3Signatures.setChecked((Boolean) newValue);
|
||||
mPreferences.setForceV3Signatures((Boolean) newValue);
|
||||
sPreferences.setForceV3Signatures((Boolean) newValue);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -32,7 +32,13 @@ import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.*;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.compatibility.ListFragmentWorkaround;
|
||||
|
||||
@@ -187,20 +187,17 @@ public class SelectSecretKeyLayoutFragment extends Fragment implements LoaderMan
|
||||
return;
|
||||
}
|
||||
|
||||
// Select Secret Key Activity delivers the intent which was sent by it using interface to Select
|
||||
// Secret Key Fragment.Intent contains the passed Uri
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode & 0xFFFF) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_CODE_SELECT_KEY: {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
mReceivedUri = data.getData();
|
||||
|
||||
//Must be restartLoader() or the data will not be updated on selecting a new key
|
||||
getActivity().getSupportLoaderManager().restartLoader(LOADER_ID, null, this);
|
||||
getActivity().getSupportLoaderManager().restartLoader(0, null, this);
|
||||
|
||||
mKeyUserId.setError(null);
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
@@ -37,7 +37,6 @@ import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.helper.OtherHelper;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
|
||||
@@ -32,7 +32,6 @@ import android.widget.LinearLayout.LayoutParams;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.helper.OtherHelper;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -45,12 +44,12 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
|
||||
protected List<ImportKeysListEntry> mData;
|
||||
|
||||
static class ViewHolder {
|
||||
private TextView mainUserId;
|
||||
private TextView mainUserIdRest;
|
||||
private TextView keyId;
|
||||
private TextView fingerprint;
|
||||
private TextView algorithm;
|
||||
private TextView status;
|
||||
public TextView mainUserId;
|
||||
public TextView mainUserIdRest;
|
||||
public TextView keyId;
|
||||
public TextView fingerprint;
|
||||
public TextView algorithm;
|
||||
public TextView status;
|
||||
}
|
||||
|
||||
public ImportKeysAdapter(Activity activity) {
|
||||
|
||||
@@ -249,7 +249,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
|
||||
/**
|
||||
* Based on <a href="http://tools.ietf.org/html/rfc2440#section-9.1">OpenPGP Message Format</a>
|
||||
*/
|
||||
private final static SparseArray<String> ALGORITHM_IDS = new SparseArray<String>() {{
|
||||
private static final SparseArray<String> ALGORITHM_IDS = new SparseArray<String>() {{
|
||||
put(-1, "unknown"); // TODO: with resources
|
||||
put(0, "unencrypted");
|
||||
put(PGPPublicKey.RSA_GENERAL, "RSA");
|
||||
@@ -267,6 +267,8 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
|
||||
* Based on <a href="http://tools.ietf.org/html/rfc2440#section-9.1">OpenPGP Message Format</a>
|
||||
*/
|
||||
public static String getAlgorithmFromId(int algorithmId) {
|
||||
return (ALGORITHM_IDS.get(algorithmId) != null ? ALGORITHM_IDS.get(algorithmId) : ALGORITHM_IDS.get(-1));
|
||||
return (ALGORITHM_IDS.get(algorithmId) != null ?
|
||||
ALGORITHM_IDS.get(algorithmId) :
|
||||
ALGORITHM_IDS.get(-1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,11 @@ package org.sufficientlysecure.keychain.ui.adapter;
|
||||
import android.content.Context;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
public class KeyValueSpinnerAdapter extends ArrayAdapter<String> {
|
||||
private final HashMap<Integer, String> mData;
|
||||
|
||||
@@ -21,10 +21,6 @@ import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentPagerAdapter;
|
||||
import android.support.v4.app.FragmentStatePagerAdapter;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -34,9 +30,9 @@ public class PagerTabStripAdapter extends FragmentPagerAdapter {
|
||||
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
|
||||
|
||||
static final class TabInfo {
|
||||
private final Class<?> clss;
|
||||
private final Bundle args;
|
||||
private final String title;
|
||||
public final Class<?> clss;
|
||||
public final Bundle args;
|
||||
public final String title;
|
||||
|
||||
TabInfo(Class<?> clss, Bundle args, String title) {
|
||||
this.clss = clss;
|
||||
|
||||
@@ -36,8 +36,8 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.
|
||||
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
|
||||
|
||||
static final class TabInfo {
|
||||
private final Class<?> clss;
|
||||
private final Bundle args;
|
||||
public final Class<?> clss;
|
||||
public final Bundle args;
|
||||
|
||||
TabInfo(Class<?> clss, Bundle args) {
|
||||
this.clss = clss;
|
||||
|
||||
@@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.ui.adapter;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Color;
|
||||
import android.support.v4.widget.CursorAdapter;
|
||||
import android.text.format.DateFormat;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -149,8 +148,7 @@ public class ViewKeyKeysAdapter extends CursorAdapter {
|
||||
DateFormat.getDateFormat(context).format(expiryDate) + ")");
|
||||
|
||||
keyExpiry.setVisibility(View.VISIBLE);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
keyExpiry.setVisibility(View.GONE);
|
||||
}
|
||||
// if key is expired or revoked, strike through text
|
||||
|
||||
@@ -37,7 +37,7 @@ public class ViewKeyUserIdsAdapter extends CursorAdapter {
|
||||
|
||||
private int mIndexUserId, mIndexRank;
|
||||
|
||||
final private ArrayList<Boolean> mCheckStates;
|
||||
private final ArrayList<Boolean> mCheckStates;
|
||||
|
||||
public ViewKeyUserIdsAdapter(Context context, Cursor c, int flags, boolean showCheckBoxes) {
|
||||
super(context, c, flags);
|
||||
@@ -55,14 +55,15 @@ public class ViewKeyUserIdsAdapter extends CursorAdapter {
|
||||
@Override
|
||||
public Cursor swapCursor(Cursor newCursor) {
|
||||
initIndex(newCursor);
|
||||
if(mCheckStates != null) {
|
||||
if (mCheckStates != null) {
|
||||
mCheckStates.clear();
|
||||
if(newCursor != null) {
|
||||
if (newCursor != null) {
|
||||
int count = newCursor.getCount();
|
||||
mCheckStates.ensureCapacity(count);
|
||||
// initialize to true (use case knowledge: we usually want to sign all uids)
|
||||
for(int i = 0; i < count; i++)
|
||||
for (int i = 0; i < count; i++) {
|
||||
mCheckStates.add(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,8 +101,9 @@ public class ViewKeyUserIdsAdapter extends CursorAdapter {
|
||||
vAddress.setText(userId[1]);
|
||||
|
||||
// don't care further if checkboxes aren't shown
|
||||
if(mCheckStates == null)
|
||||
if (mCheckStates == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final CheckBox vCheckBox = (CheckBox) view.findViewById(R.id.checkBox);
|
||||
final int position = cursor.getPosition();
|
||||
@@ -124,8 +126,8 @@ public class ViewKeyUserIdsAdapter extends CursorAdapter {
|
||||
|
||||
public ArrayList<String> getSelectedUserIds() {
|
||||
ArrayList<String> result = new ArrayList<String>();
|
||||
for(int i = 0; i < mCheckStates.size(); i++) {
|
||||
if(mCheckStates.get(i)) {
|
||||
for (int i = 0; i < mCheckStates.size(); i++) {
|
||||
if (mCheckStates.get(i)) {
|
||||
mCursor.moveToPosition(i);
|
||||
result.add(mCursor.getString(mIndexUserId));
|
||||
}
|
||||
|
||||
@@ -138,9 +138,10 @@ public class CreateKeyDialogFragment extends DialogFragment {
|
||||
final AdapterView.OnItemSelectedListener weakRsaListener = new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
final Choice selectedAlgorithm = (Choice)algorithm.getSelectedItem();
|
||||
final int selectedKeySize = Integer.parseInt((String)keySize.getSelectedItem());
|
||||
final boolean isWeakRsa = (selectedAlgorithm.getId() == Id.choice.algorithm.rsa && selectedKeySize <= 1024);
|
||||
final Choice selectedAlgorithm = (Choice) algorithm.getSelectedItem();
|
||||
final int selectedKeySize = Integer.parseInt((String) keySize.getSelectedItem());
|
||||
final boolean isWeakRsa = (selectedAlgorithm.getId() == Id.choice.algorithm.rsa &&
|
||||
selectedKeySize <= 1024);
|
||||
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(!isWeakRsa);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,12 +51,12 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
||||
public static final int MESSAGE_OKAY = 1;
|
||||
public static final int MESSAGE_ERROR = 0;
|
||||
|
||||
private boolean isSingleSelection = false;
|
||||
private boolean mIsSingleSelection = false;
|
||||
|
||||
private TextView mainMessage;
|
||||
private CheckBox checkDeleteSecret;
|
||||
private LinearLayout deleteSecretKeyView;
|
||||
private View inflateView;
|
||||
private TextView mMainMessage;
|
||||
private CheckBox mCheckDeleteSecret;
|
||||
private LinearLayout mDeleteSecretKeyView;
|
||||
private View mInflateView;
|
||||
|
||||
private Messenger mMessenger;
|
||||
|
||||
@@ -90,12 +90,12 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
||||
|
||||
//Setup custom View to display in AlertDialog
|
||||
LayoutInflater inflater = activity.getLayoutInflater();
|
||||
inflateView = inflater.inflate(R.layout.view_key_delete_fragment, null);
|
||||
builder.setView(inflateView);
|
||||
mInflateView = inflater.inflate(R.layout.view_key_delete_fragment, null);
|
||||
builder.setView(mInflateView);
|
||||
|
||||
deleteSecretKeyView = (LinearLayout) inflateView.findViewById(R.id.deleteSecretKeyView);
|
||||
mainMessage = (TextView) inflateView.findViewById(R.id.mainMessage);
|
||||
checkDeleteSecret = (CheckBox) inflateView.findViewById(R.id.checkDeleteSecret);
|
||||
mDeleteSecretKeyView = (LinearLayout) mInflateView.findViewById(R.id.deleteSecretKeyView);
|
||||
mMainMessage = (TextView) mInflateView.findViewById(R.id.mainMessage);
|
||||
mCheckDeleteSecret = (CheckBox) mInflateView.findViewById(R.id.checkDeleteSecret);
|
||||
|
||||
builder.setTitle(R.string.warning);
|
||||
/* TODO! redo
|
||||
@@ -104,7 +104,7 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
||||
if (keyRingRowIds.length == 1) {
|
||||
Uri dataUri;
|
||||
ArrayList<Long> publicKeyRings; //Any one will do
|
||||
isSingleSelection = true;
|
||||
mIsSingleSelection = true;
|
||||
|
||||
long selectedRow = keyRingRowIds[0];
|
||||
long keyType;
|
||||
@@ -120,16 +120,16 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
||||
}
|
||||
|
||||
String userId = ProviderHelper.getUserId(activity, dataUri);
|
||||
//Hide the Checkbox and TextView since this is a single selection,user will be notified thru message
|
||||
deleteSecretKeyView.setVisibility(View.GONE);
|
||||
//Set message depending on which key it is.
|
||||
mainMessage.setText(getString(keyType == Id.type.secret_key ? R.string.secret_key_deletion_confirmation
|
||||
: R.string.public_key_deletetion_confirmation, userId));
|
||||
|
||||
|
||||
// Hide the Checkbox and TextView since this is a single selection,
|
||||
// user will be notified thru message
|
||||
mDeleteSecretKeyView.setVisibility(View.GONE);
|
||||
// Set message depending on which key it is.
|
||||
mMainMessage.setText(getString(keyType == Id.type.secret_key ?
|
||||
R.string.secret_key_deletion_confirmation :
|
||||
R.string.public_key_deletetion_confirmation, userId));
|
||||
} else {
|
||||
deleteSecretKeyView.setVisibility(View.VISIBLE);
|
||||
mainMessage.setText(R.string.key_deletion_confirmation_multi);
|
||||
mDeleteSecretKeyView.setVisibility(View.VISIBLE);
|
||||
mMainMessage.setText(R.string.key_deletion_confirmation_multi);
|
||||
}
|
||||
|
||||
|
||||
@@ -149,8 +149,9 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
||||
String selectionIDs = "";
|
||||
for (int i = 0; i < keyRingRowIds.length; i++) {
|
||||
selectionIDs += "'" + String.valueOf(keyRingRowIds[i]) + "'";
|
||||
if (i + 1 < keyRingRowIds.length)
|
||||
if (i + 1 < keyRingRowIds.length) {
|
||||
selectionIDs += ",";
|
||||
}
|
||||
}
|
||||
selection += selectionIDs + ")";
|
||||
|
||||
@@ -167,30 +168,33 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
||||
masterKeyId = cursor.getLong(0);
|
||||
keyType = cursor.getLong(1);
|
||||
|
||||
Log.d(Constants.TAG, "masterKeyId: " + masterKeyId
|
||||
+ ", keyType:" + (keyType == KeychainContract.KeyTypes.PUBLIC ? "Public" : "Private"));
|
||||
|
||||
Log.d(Constants.TAG, "masterKeyId: " + masterKeyId +
|
||||
", keyType:" +
|
||||
(keyType == KeychainContract.KeyTypes.PUBLIC ?
|
||||
"Public" : "Private"));
|
||||
|
||||
if (keyType == KeychainContract.KeyTypes.SECRET) {
|
||||
if (checkDeleteSecret.isChecked() || isSingleSelection) {
|
||||
ProviderHelper.deleteUnifiedKeyRing(activity, String.valueOf(masterKeyId), true);
|
||||
if (mCheckDeleteSecret.isChecked() || mIsSingleSelection) {
|
||||
ProviderHelper.deleteUnifiedKeyRing(activity,
|
||||
String.valueOf(masterKeyId), true);
|
||||
}
|
||||
} else {
|
||||
ProviderHelper.deleteUnifiedKeyRing(activity, String.valueOf(masterKeyId), false);
|
||||
ProviderHelper.deleteUnifiedKeyRing(activity,
|
||||
String.valueOf(masterKeyId), false);
|
||||
}
|
||||
}
|
||||
|
||||
//Check if the selected rows have actually been deleted
|
||||
cursor = activity.getContentResolver().query(queryUri, projection, selection, null, null);
|
||||
if (cursor == null || cursor.getCount() == 0 || !checkDeleteSecret.isChecked()) {
|
||||
cursor = activity.getContentResolver().query(
|
||||
queryUri, projection, selection, null, null);
|
||||
if (cursor == null || cursor.getCount() == 0 ||
|
||||
!mCheckDeleteSecret.isChecked()) {
|
||||
isSuccessfullyDeleted = true;
|
||||
}
|
||||
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dismiss();
|
||||
@@ -201,9 +205,7 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
||||
sendMessageToHandler(MESSAGE_ERROR, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
});
|
||||
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
|
||||
@Override
|
||||
@@ -234,5 +236,4 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
||||
Log.w(Constants.TAG, "Messenger is null!", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ public class ShareQrCodeDialogFragment extends DialogFragment {
|
||||
content = keyringArmored.get(0);
|
||||
|
||||
// OnClickListener are set in onResume to prevent automatic dismissing of Dialogs
|
||||
// http://stackoverflow.com/questions/2620444/how-to-prevent-a-dialog-from-closing-when-a-button-is-clicked
|
||||
// http://bit.ly/O5vfaR
|
||||
alert.setPositiveButton(R.string.btn_next, null);
|
||||
alert.setNegativeButton(android.R.string.cancel, null);
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ public class FoldableLinearLayout extends LinearLayout {
|
||||
* @param attrs
|
||||
*/
|
||||
private void processAttributes(Context context, AttributeSet attrs) {
|
||||
if(attrs != null) {
|
||||
if (attrs != null) {
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
R.styleable.FoldableLinearLayout, 0, 0);
|
||||
mFoldedIconName = a.getString(R.styleable.FoldableLinearLayout_foldedIcon);
|
||||
@@ -102,7 +102,7 @@ public class FoldableLinearLayout extends LinearLayout {
|
||||
protected void onFinishInflate() {
|
||||
// if the migration has already happened
|
||||
// there is no need to move any children
|
||||
if(!mHasMigrated) {
|
||||
if (!mHasMigrated) {
|
||||
migrateChildrenToContainer();
|
||||
mHasMigrated = true;
|
||||
}
|
||||
@@ -120,10 +120,10 @@ public class FoldableLinearLayout extends LinearLayout {
|
||||
int childNum = getChildCount();
|
||||
View[] children = new View[childNum];
|
||||
|
||||
for(int i = 0; i < childNum; i++) {
|
||||
for (int i = 0; i < childNum; i++) {
|
||||
children[i] = getChildAt(i);
|
||||
}
|
||||
if(children[0].getId() == R.id.foldableControl) {
|
||||
if (children[0].getId() == R.id.foldableControl) {
|
||||
|
||||
}
|
||||
|
||||
@@ -131,14 +131,14 @@ public class FoldableLinearLayout extends LinearLayout {
|
||||
detachAllViewsFromParent();
|
||||
|
||||
// Inflate the inner foldable_linearlayout.xml
|
||||
LayoutInflater inflator = (LayoutInflater)getContext().getSystemService(
|
||||
LayoutInflater inflator = (LayoutInflater) getContext().getSystemService(
|
||||
Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
mFoldableLayout = inflator.inflate(R.layout.foldable_linearlayout, this, true);
|
||||
mFoldableContainer = (LinearLayout) mFoldableLayout.findViewById(R.id.foldableContainer);
|
||||
|
||||
// Push previously collected children into foldableContainer.
|
||||
for(int i = 0; i < childNum; i++) {
|
||||
for (int i = 0; i < childNum; i++) {
|
||||
addView(children[i]);
|
||||
}
|
||||
}
|
||||
@@ -196,7 +196,7 @@ public class FoldableLinearLayout extends LinearLayout {
|
||||
*/
|
||||
@Override
|
||||
public void addView(View child) {
|
||||
if(mFoldableContainer != null) {
|
||||
if (mFoldableContainer != null) {
|
||||
mFoldableContainer.addView(child);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,20 +16,6 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.ui.widget;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||
import org.spongycastle.openpgp.PGPKeyFlags;
|
||||
import org.spongycastle.openpgp.PGPPublicKey;
|
||||
import org.spongycastle.openpgp.PGPSecretKey;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||
import org.sufficientlysecure.keychain.util.Choice;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.DatePickerDialog;
|
||||
import android.app.Dialog;
|
||||
@@ -47,16 +33,23 @@ import android.widget.LinearLayout;
|
||||
import android.widget.TableLayout;
|
||||
import android.widget.TableRow;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||
|
||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||
import org.spongycastle.openpgp.PGPPublicKey;
|
||||
import org.spongycastle.openpgp.PGPSecretKey;
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||
import org.sufficientlysecure.keychain.util.Choice;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.*;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Vector;
|
||||
|
||||
public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
|
||||
private PGPSecretKey mKey;
|
||||
@@ -101,11 +94,13 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
|
||||
GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
|
||||
date.set(year, monthOfYear, dayOfMonth);
|
||||
if (mOriginalExpiryDate != null) {
|
||||
long numDays = (date.getTimeInMillis() / 86400000) - (mOriginalExpiryDate.getTimeInMillis() / 86400000);
|
||||
if (numDays == 0)
|
||||
long numDays = (date.getTimeInMillis() / 86400000) -
|
||||
(mOriginalExpiryDate.getTimeInMillis() / 86400000);
|
||||
if (numDays == 0) {
|
||||
setExpiryDate(mOriginalExpiryDate);
|
||||
else
|
||||
} else {
|
||||
setExpiryDate(date);
|
||||
}
|
||||
} else {
|
||||
setExpiryDate(date);
|
||||
}
|
||||
@@ -155,7 +150,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
|
||||
date = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
|
||||
}
|
||||
/*
|
||||
* Using custom DatePickerDialog which overrides the setTitle because
|
||||
* Using custom DatePickerDialog which overrides the setTitle because
|
||||
* the DatePickerDialog title is buggy (unix warparound bug).
|
||||
* See: https://code.google.com/p/android/issues/detail?id=49066
|
||||
*/
|
||||
@@ -201,8 +196,8 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
|
||||
super.onFinishInflate();
|
||||
}
|
||||
|
||||
public void setCanEdit(boolean bCanEdit) {
|
||||
if (!bCanEdit) {
|
||||
public void setCanBeEdited(boolean canBeEdited) {
|
||||
if (!canBeEdited) {
|
||||
mDeleteButton.setVisibility(View.INVISIBLE);
|
||||
mExpiryDateButton.setEnabled(false);
|
||||
mChkSign.setEnabled(false); //certify is always disabled
|
||||
@@ -228,23 +223,23 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
|
||||
boolean isDSAKey = (key.getPublicKey().getAlgorithm() == PGPPublicKey.DSA);
|
||||
if (isElGamalKey) {
|
||||
mChkSign.setVisibility(View.INVISIBLE);
|
||||
TableLayout table = (TableLayout)findViewById(R.id.table_keylayout);
|
||||
TableRow row = (TableRow)findViewById(R.id.row_sign);
|
||||
TableLayout table = (TableLayout) findViewById(R.id.table_keylayout);
|
||||
TableRow row = (TableRow) findViewById(R.id.row_sign);
|
||||
table.removeView(row);
|
||||
}
|
||||
if (isDSAKey) {
|
||||
mChkEncrypt.setVisibility(View.INVISIBLE);
|
||||
TableLayout table = (TableLayout)findViewById(R.id.table_keylayout);
|
||||
TableRow row = (TableRow)findViewById(R.id.row_encrypt);
|
||||
TableLayout table = (TableLayout) findViewById(R.id.table_keylayout);
|
||||
TableRow row = (TableRow) findViewById(R.id.row_encrypt);
|
||||
table.removeView(row);
|
||||
}
|
||||
if (!mIsMasterKey) {
|
||||
mChkCertify.setVisibility(View.INVISIBLE);
|
||||
TableLayout table = (TableLayout)findViewById(R.id.table_keylayout);
|
||||
TableRow row = (TableRow)findViewById(R.id.row_certify);
|
||||
TableLayout table = (TableLayout) findViewById(R.id.table_keylayout);
|
||||
TableRow row = (TableRow) findViewById(R.id.row_certify);
|
||||
table.removeView(row);
|
||||
} else {
|
||||
TextView mLabelUsage2= (TextView) findViewById(R.id.label_usage2);
|
||||
TextView mLabelUsage2 = (TextView) findViewById(R.id.label_usage2);
|
||||
mLabelUsage2.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
@@ -260,8 +255,9 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
|
||||
} else {
|
||||
mUsage = PgpKeyHelper.getKeyUsage(key);
|
||||
mOriginalUsage = mUsage;
|
||||
if (key.isMasterKey())
|
||||
if (key.isMasterKey()) {
|
||||
mChkCertify.setChecked(PgpKeyHelper.isCertificationKey(key));
|
||||
}
|
||||
mChkSign.setChecked(PgpKeyHelper.isSigningKey(key));
|
||||
mChkEncrypt.setChecked(PgpKeyHelper.isEncryptionKey(key));
|
||||
mChkAuthenticate.setChecked(PgpKeyHelper.isAuthenticationKey(key));
|
||||
@@ -323,19 +319,24 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
|
||||
}
|
||||
|
||||
public int getUsage() {
|
||||
mUsage = (mUsage & ~KeyFlags.CERTIFY_OTHER) | (mChkCertify.isChecked() ? KeyFlags.CERTIFY_OTHER : 0);
|
||||
mUsage = (mUsage & ~KeyFlags.SIGN_DATA) | (mChkSign.isChecked() ? KeyFlags.SIGN_DATA : 0);
|
||||
mUsage = (mUsage & ~KeyFlags.ENCRYPT_COMMS) | (mChkEncrypt.isChecked() ? KeyFlags.ENCRYPT_COMMS : 0);
|
||||
mUsage = (mUsage & ~KeyFlags.ENCRYPT_STORAGE) | (mChkEncrypt.isChecked() ? KeyFlags.ENCRYPT_STORAGE : 0);
|
||||
mUsage = (mUsage & ~KeyFlags.AUTHENTICATION) | (mChkAuthenticate.isChecked() ? KeyFlags.AUTHENTICATION : 0);
|
||||
mUsage = (mUsage & ~KeyFlags.CERTIFY_OTHER) |
|
||||
(mChkCertify.isChecked() ? KeyFlags.CERTIFY_OTHER : 0);
|
||||
mUsage = (mUsage & ~KeyFlags.SIGN_DATA) |
|
||||
(mChkSign.isChecked() ? KeyFlags.SIGN_DATA : 0);
|
||||
mUsage = (mUsage & ~KeyFlags.ENCRYPT_COMMS) |
|
||||
(mChkEncrypt.isChecked() ? KeyFlags.ENCRYPT_COMMS : 0);
|
||||
mUsage = (mUsage & ~KeyFlags.ENCRYPT_STORAGE) |
|
||||
(mChkEncrypt.isChecked() ? KeyFlags.ENCRYPT_STORAGE : 0);
|
||||
mUsage = (mUsage & ~KeyFlags.AUTHENTICATION) |
|
||||
(mChkAuthenticate.isChecked() ? KeyFlags.AUTHENTICATION : 0);
|
||||
|
||||
return mUsage;
|
||||
}
|
||||
|
||||
public boolean needsSaving()
|
||||
{
|
||||
if (mIsNewKey)
|
||||
public boolean needsSaving() {
|
||||
if (mIsNewKey) {
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean retval = (getUsage() != mOriginalUsage);
|
||||
|
||||
@@ -345,21 +346,21 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
|
||||
if (mOEDNull != mEDNull) {
|
||||
dateChanged = true;
|
||||
} else {
|
||||
if(mOEDNull) //both null, no change
|
||||
if (mOEDNull) {
|
||||
//both null, no change
|
||||
dateChanged = false;
|
||||
else
|
||||
} else {
|
||||
dateChanged = ((mExpiryDate.compareTo(mOriginalExpiryDate)) != 0);
|
||||
}
|
||||
}
|
||||
retval |= dateChanged;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
public boolean getIsNewKey()
|
||||
{
|
||||
public boolean getIsNewKey() {
|
||||
return mIsNewKey;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ExpiryDatePickerDialog extends DatePickerDialog {
|
||||
|
||||
@@ -16,23 +16,6 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.ui.widget;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.spongycastle.openpgp.PGPKeyFlags;
|
||||
import org.spongycastle.openpgp.PGPSecretKey;
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener;
|
||||
import org.sufficientlysecure.keychain.util.Choice;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
@@ -49,7 +32,10 @@ import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||
|
||||
import org.spongycastle.openpgp.PGPKeyFlags;
|
||||
import org.spongycastle.openpgp.PGPSecretKey;
|
||||
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
|
||||
@@ -61,7 +47,9 @@ import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener;
|
||||
import org.sufficientlysecure.keychain.util.Choice;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
public class SectionView extends LinearLayout implements OnClickListener, EditorListener, Editor {
|
||||
private LayoutInflater mInflater;
|
||||
@@ -73,10 +61,10 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
|
||||
|
||||
private Choice mNewKeyAlgorithmChoice;
|
||||
private int mNewKeySize;
|
||||
private boolean oldItemDeleted = false;
|
||||
private boolean mOldItemDeleted = false;
|
||||
private ArrayList<String> mDeletedIDs = new ArrayList<String>();
|
||||
private ArrayList<PGPSecretKey> mDeletedKeys = new ArrayList<PGPSecretKey>();
|
||||
private boolean mCanEdit = true;
|
||||
private boolean mCanBeEdited = true;
|
||||
|
||||
private ActionBarActivity mActivity;
|
||||
|
||||
@@ -119,9 +107,9 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
|
||||
}
|
||||
}
|
||||
|
||||
public void setCanEdit(boolean bCanEdit) {
|
||||
mCanEdit = bCanEdit;
|
||||
if (!mCanEdit) {
|
||||
public void setCanBeEdited(boolean canBeEdited) {
|
||||
mCanBeEdited = canBeEdited;
|
||||
if (!mCanBeEdited) {
|
||||
mPlusButton.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
@@ -150,13 +138,13 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void onDeleted(Editor editor, boolean wasNewItem) {
|
||||
oldItemDeleted |= !wasNewItem;
|
||||
if (oldItemDeleted) {
|
||||
if (mType == Id.type.user_id)
|
||||
mDeletedIDs.add(((UserIdEditor)editor).getOriginalID());
|
||||
else if (mType == Id.type.key)
|
||||
mDeletedKeys.add(((KeyEditor)editor).getValue());
|
||||
|
||||
mOldItemDeleted |= !wasNewItem;
|
||||
if (mOldItemDeleted) {
|
||||
if (mType == Id.type.user_id) {
|
||||
mDeletedIDs.add(((UserIdEditor) editor).getOriginalID());
|
||||
} else if (mType == Id.type.key) {
|
||||
mDeletedKeys.add(((KeyEditor) editor).getValue());
|
||||
}
|
||||
}
|
||||
this.updateEditorsVisible();
|
||||
if (mEditorListener != null) {
|
||||
@@ -176,55 +164,55 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
|
||||
mEditors.setVisibility(hasChildren ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
public boolean needsSaving()
|
||||
{
|
||||
public boolean needsSaving() {
|
||||
//check each view for needs saving, take account of deleted items
|
||||
boolean ret = oldItemDeleted;
|
||||
boolean ret = mOldItemDeleted;
|
||||
for (int i = 0; i < mEditors.getChildCount(); ++i) {
|
||||
Editor editor = (Editor) mEditors.getChildAt(i);
|
||||
ret |= editor.needsSaving();
|
||||
if (mType == Id.type.user_id)
|
||||
ret |= ((UserIdEditor)editor).primarySwapped();
|
||||
if (mType == Id.type.user_id) {
|
||||
ret |= ((UserIdEditor) editor).primarySwapped();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public boolean primaryChanged()
|
||||
{
|
||||
public boolean primaryChanged() {
|
||||
boolean ret = false;
|
||||
for (int i = 0; i < mEditors.getChildCount(); ++i) {
|
||||
Editor editor = (Editor) mEditors.getChildAt(i);
|
||||
if (mType == Id.type.user_id)
|
||||
ret |= ((UserIdEditor)editor).primarySwapped();
|
||||
if (mType == Id.type.user_id) {
|
||||
ret |= ((UserIdEditor) editor).primarySwapped();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String getOriginalPrimaryID()
|
||||
{ //NB: this will have to change when we change how Primary IDs are chosen, and so we need to be
|
||||
// careful about where Master key capabilities are stored... multiple primaries and
|
||||
// revoked ones make this harder than the simple case we are continuing to assume here
|
||||
public String getOriginalPrimaryID() {
|
||||
//NB: this will have to change when we change how Primary IDs are chosen, and so we need to be
|
||||
// careful about where Master key capabilities are stored... multiple primaries and
|
||||
// revoked ones make this harder than the simple case we are continuing to assume here
|
||||
for (int i = 0; i < mEditors.getChildCount(); ++i) {
|
||||
Editor editor = (Editor) mEditors.getChildAt(i);
|
||||
if (mType == Id.type.user_id) {
|
||||
if(((UserIdEditor)editor).getIsOriginallyMainUserID()) {
|
||||
return ((UserIdEditor)editor).getOriginalID();
|
||||
if (((UserIdEditor) editor).getIsOriginallyMainUserID()) {
|
||||
return ((UserIdEditor) editor).getOriginalID();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ArrayList<String> getOriginalIDs()
|
||||
{
|
||||
public ArrayList<String> getOriginalIDs() {
|
||||
ArrayList<String> orig = new ArrayList<String>();
|
||||
if (mType == Id.type.user_id) {
|
||||
for (int i = 0; i < mEditors.getChildCount(); ++i) {
|
||||
UserIdEditor editor = (UserIdEditor) mEditors.getChildAt(i);
|
||||
if (editor.isMainUserId())
|
||||
if (editor.isMainUserId()) {
|
||||
orig.add(0, editor.getOriginalID());
|
||||
else
|
||||
} else {
|
||||
orig.add(editor.getOriginalID());
|
||||
}
|
||||
}
|
||||
return orig;
|
||||
} else {
|
||||
@@ -232,18 +220,15 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<String> getDeletedIDs()
|
||||
{
|
||||
public ArrayList<String> getDeletedIDs() {
|
||||
return mDeletedIDs;
|
||||
}
|
||||
|
||||
public ArrayList<PGPSecretKey> getDeletedKeys()
|
||||
{
|
||||
public ArrayList<PGPSecretKey> getDeletedKeys() {
|
||||
return mDeletedKeys;
|
||||
}
|
||||
|
||||
public List<Boolean> getNeedsSavingArray()
|
||||
{
|
||||
public List<Boolean> getNeedsSavingArray() {
|
||||
ArrayList<Boolean> mList = new ArrayList<Boolean>();
|
||||
for (int i = 0; i < mEditors.getChildCount(); ++i) {
|
||||
Editor editor = (Editor) mEditors.getChildAt(i);
|
||||
@@ -252,8 +237,20 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
|
||||
return mList;
|
||||
}
|
||||
|
||||
public List<Boolean> getNewKeysArray()
|
||||
{
|
||||
public List<Boolean> getNewIDFlags() {
|
||||
ArrayList<Boolean> mList = new ArrayList<Boolean>();
|
||||
for (int i = 0; i < mEditors.getChildCount(); ++i) {
|
||||
UserIdEditor editor = (UserIdEditor) mEditors.getChildAt(i);
|
||||
if (editor.isMainUserId()) {
|
||||
mList.add(0, editor.getIsNewID());
|
||||
} else {
|
||||
mList.add(editor.getIsNewID());
|
||||
}
|
||||
}
|
||||
return mList;
|
||||
}
|
||||
|
||||
public List<Boolean> getNewKeysArray() {
|
||||
ArrayList<Boolean> mList = new ArrayList<Boolean>();
|
||||
if (mType == Id.type.key) {
|
||||
for (int i = 0; i < mEditors.getChildCount(); ++i) {
|
||||
@@ -268,7 +265,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void onClick(View v) {
|
||||
if (mCanEdit) {
|
||||
if (mCanBeEdited) {
|
||||
switch (mType) {
|
||||
case Id.type.user_id: {
|
||||
UserIdEditor view = (UserIdEditor) mInflater.inflate(
|
||||
@@ -318,7 +315,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
|
||||
mEditors, false);
|
||||
view.setEditorListener(this);
|
||||
view.setValue(userId, mEditors.getChildCount() == 0, false);
|
||||
view.setCanEdit(mCanEdit);
|
||||
view.setCanBeEdited(mCanBeEdited);
|
||||
mEditors.addView(view);
|
||||
}
|
||||
|
||||
@@ -339,7 +336,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
|
||||
view.setEditorListener(this);
|
||||
boolean isMasterKey = (mEditors.getChildCount() == 0);
|
||||
view.setValue(list.get(i), isMasterKey, usages.get(i), newKeys);
|
||||
view.setCanEdit(mCanEdit);
|
||||
view.setCanBeEdited(mCanBeEdited);
|
||||
mEditors.addView(view);
|
||||
}
|
||||
|
||||
@@ -419,8 +416,9 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
|
||||
mEditors, false);
|
||||
view.setEditorListener(SectionView.this);
|
||||
int usage = 0;
|
||||
if (mEditors.getChildCount() == 0)
|
||||
if (mEditors.getChildCount() == 0) {
|
||||
usage = PGPKeyFlags.CAN_CERTIFY;
|
||||
}
|
||||
view.setValue(newKey, newKey.isMasterKey(), usage, true);
|
||||
mEditors.addView(view);
|
||||
SectionView.this.updateEditorsVisible();
|
||||
|
||||
@@ -16,11 +16,6 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.ui.widget;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||
import android.content.Context;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
@@ -29,10 +24,18 @@ import android.util.Patterns;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.*;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.AutoCompleteTextView;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RadioButton;
|
||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||
import org.sufficientlysecure.keychain.helper.ContactHelper;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.helper.ContactHelper;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
public class UserIdEditor extends LinearLayout implements Editor, OnClickListener {
|
||||
private EditorListener mEditorListener = null;
|
||||
@@ -49,8 +52,8 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene
|
||||
private boolean mOriginallyMainUserID;
|
||||
private boolean mIsNewId;
|
||||
|
||||
public void setCanEdit(boolean bCanEdit) {
|
||||
if (!bCanEdit) {
|
||||
public void setCanBeEdited(boolean canBeEdited) {
|
||||
if (!canBeEdited) {
|
||||
mDeleteButton.setVisibility(View.INVISIBLE);
|
||||
mName.setEnabled(false);
|
||||
mIsMainUserId.setEnabled(false);
|
||||
@@ -85,8 +88,7 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s)
|
||||
{
|
||||
public void afterTextChanged(Editable s) {
|
||||
if (mEditorListener != null) {
|
||||
mEditorListener.onEdited();
|
||||
}
|
||||
@@ -240,25 +242,24 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene
|
||||
@Override
|
||||
public boolean needsSaving() {
|
||||
boolean retval = false; //(mOriginallyMainUserID != isMainUserId());
|
||||
retval |= !(mOriginalName.equals( ("" + mName.getText()).trim() ) );
|
||||
retval |= !(mOriginalEmail.equals( ("" + mEmail.getText()).trim() ) );
|
||||
retval |= !(mOriginalComment.equals( ("" + mComment.getText()).trim() ) );
|
||||
retval |= !(mOriginalName.equals(("" + mName.getText()).trim()));
|
||||
retval |= !(mOriginalEmail.equals(("" + mEmail.getText()).trim()));
|
||||
retval |= !(mOriginalComment.equals(("" + mComment.getText()).trim()));
|
||||
retval |= mIsNewId;
|
||||
return retval;
|
||||
}
|
||||
|
||||
public boolean getIsOriginallyMainUserID()
|
||||
{
|
||||
public boolean getIsOriginallyMainUserID() {
|
||||
return mOriginallyMainUserID;
|
||||
}
|
||||
|
||||
public boolean primarySwapped()
|
||||
{
|
||||
public boolean primarySwapped() {
|
||||
return (mOriginallyMainUserID != isMainUserId());
|
||||
}
|
||||
|
||||
public String getOriginalID()
|
||||
{
|
||||
public String getOriginalID() {
|
||||
return mOriginalID;
|
||||
}
|
||||
|
||||
public boolean getIsNewID() { return mIsNewId; }
|
||||
}
|
||||
|
||||
@@ -29,22 +29,30 @@ import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.InetAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry.getAlgorithmFromId;
|
||||
|
||||
public class HkpKeyServer extends KeyServer {
|
||||
private static class HttpError extends Exception {
|
||||
private static final long serialVersionUID = 1718783705229428893L;
|
||||
@@ -72,20 +80,22 @@ public class HkpKeyServer extends KeyServer {
|
||||
/**
|
||||
* pub:%keyid%:%algo%:%keylen%:%creationdate%:%expirationdate%:%flags%
|
||||
* <ul>
|
||||
* <li>%<b>keyid</b>% = this is either the fingerprint or the key ID of the key. Either the 16-digit or 8-digit
|
||||
* key IDs are acceptable, but obviously the fingerprint is best.</li>
|
||||
* <li>%<b>keyid</b>% = this is either the fingerprint or the key ID of the key.
|
||||
* Either the 16-digit or 8-digit key IDs are acceptable, but obviously the fingerprint is best.
|
||||
* </li>
|
||||
* <li>%<b>algo</b>% = the algorithm number, (i.e. 1==RSA, 17==DSA, etc).
|
||||
* See <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a></li>
|
||||
* <li>%<b>keylen</b>% = the key length (i.e. 1024, 2048, 4096, etc.)</li>
|
||||
* <li>%<b>creationdate</b>% = creation date of the key in standard
|
||||
* <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of seconds since
|
||||
* 1/1/1970 UTC time)</li>
|
||||
* <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of
|
||||
* seconds since 1/1/1970 UTC time)</li>
|
||||
* <li>%<b>expirationdate</b>% = expiration date of the key in standard
|
||||
* <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of seconds since
|
||||
* 1/1/1970 UTC time)</li>
|
||||
* <li>%<b>flags</b>% = letter codes to indicate details of the key, if any. Flags may be in any order. The
|
||||
* meaning of "disabled" is implementation-specific. Note that individual flags may be unimplemented, so
|
||||
* the absence of a given flag does not necessarily mean the absence of the detail.
|
||||
* <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of
|
||||
* seconds since 1/1/1970 UTC time)</li>
|
||||
* <li>%<b>flags</b>% = letter codes to indicate details of the key, if any. Flags may be in any
|
||||
* order. The meaning of "disabled" is implementation-specific. Note that individual flags may
|
||||
* be unimplemented, so the absence of a given flag does not necessarily mean the absence of the
|
||||
* detail.
|
||||
* <ul>
|
||||
* <li>r == revoked</li>
|
||||
* <li>d == disabled</li>
|
||||
@@ -94,7 +104,8 @@ public class HkpKeyServer extends KeyServer {
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/draft-shaw-openpgp-hkp-00#section-5.2">5.2. Machine Readable Indexes</a>
|
||||
* @see <a href="http://tools.ietf.org/html/draft-shaw-openpgp-hkp-00#section-5.2">
|
||||
* 5.2. Machine Readable Indexes</a>
|
||||
* in Internet-Draft OpenPGP HTTP Keyserver Protocol Document
|
||||
*/
|
||||
public static final Pattern PUB_KEY_LINE = Pattern
|
||||
@@ -105,17 +116,19 @@ public class HkpKeyServer extends KeyServer {
|
||||
/**
|
||||
* uid:%escaped uid string%:%creationdate%:%expirationdate%:%flags%
|
||||
* <ul>
|
||||
* <li>%<b>escaped uid string</b>% = the user ID string, with HTTP %-escaping for anything that isn't 7-bit
|
||||
* safe as well as for the ":" character. Any other characters may be escaped, as desired.</li>
|
||||
* <li>%<b>escaped uid string</b>% = the user ID string, with HTTP %-escaping for anything that
|
||||
* isn't 7-bit safe as well as for the ":" character. Any other characters may be escaped, as
|
||||
* desired.</li>
|
||||
* <li>%<b>creationdate</b>% = creation date of the key in standard
|
||||
* <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of seconds since
|
||||
* 1/1/1970 UTC time)</li>
|
||||
* <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of
|
||||
* seconds since 1/1/1970 UTC time)</li>
|
||||
* <li>%<b>expirationdate</b>% = expiration date of the key in standard
|
||||
* <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of seconds since
|
||||
* 1/1/1970 UTC time)</li>
|
||||
* <li>%<b>flags</b>% = letter codes to indicate details of the key, if any. Flags may be in any order. The
|
||||
* meaning of "disabled" is implementation-specific. Note that individual flags may be unimplemented, so
|
||||
* the absence of a given flag does not necessarily mean the absence of the detail.
|
||||
* <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of
|
||||
* seconds since 1/1/1970 UTC time)</li>
|
||||
* <li>%<b>flags</b>% = letter codes to indicate details of the key, if any. Flags may be in any
|
||||
* order. The meaning of "disabled" is implementation-specific. Note that individual flags may
|
||||
* be unimplemented, so the absence of a given flag does not necessarily mean the absence of
|
||||
* the detail.
|
||||
* <ul>
|
||||
* <li>r == revoked</li>
|
||||
* <li>d == disabled</li>
|
||||
@@ -244,11 +257,10 @@ public class HkpKeyServer extends KeyServer {
|
||||
entry.setBitStrength(Integer.parseInt(matcher.group(3)));
|
||||
|
||||
final int algorithmId = Integer.decode(matcher.group(2));
|
||||
entry.setAlgorithm(getAlgorithmFromId(algorithmId));
|
||||
entry.setAlgorithm(ImportKeysListEntry.getAlgorithmFromId(algorithmId));
|
||||
|
||||
// group 1 contains the full fingerprint (v4) or the long key id if available
|
||||
// see https://bitbucket.org/skskeyserver/sks-keyserver/pull-request/12/fixes-for-machine-readable-indexes/diff
|
||||
// and https://github.com/openpgp-keychain/openpgp-keychain/issues/259#issuecomment-38168176
|
||||
// see http://bit.ly/1d4bxbk and http://bit.ly/1gD1wwr
|
||||
String fingerprintOrKeyId = matcher.group(1);
|
||||
if (fingerprintOrKeyId.length() > 16) {
|
||||
entry.setFingerPrintHex(fingerprintOrKeyId.toLowerCase(Locale.US));
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
||||
@@ -16,9 +16,10 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.util;
|
||||
|
||||
import com.google.zxing.integration.android.IntentIntegrator;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.support.v4.app.Fragment;
|
||||
import com.google.zxing.integration.android.IntentIntegrator;
|
||||
|
||||
/**
|
||||
* IntentIntegrator for the V4 Android compatibility package.
|
||||
|
||||
@@ -24,7 +24,7 @@ public class IterableIterator<T> implements Iterable<T> {
|
||||
|
||||
public IterableIterator(Iterator<T> iter, boolean failsafe) {
|
||||
mIter = iter;
|
||||
if(failsafe && mIter == null) {
|
||||
if (failsafe && mIter == null) {
|
||||
// is there a better way?
|
||||
mIter = new ArrayList<T>().iterator();
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.util;
|
||||
|
||||
public interface KeychainServiceListener {
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.util;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
||||
@@ -36,7 +36,7 @@ public class ProgressScaler implements ProgressDialogUpdater {
|
||||
* Set progressDialogUpdater of ProgressDialog by sending message to handler on UI thread
|
||||
*/
|
||||
public void setProgress(String message, int progress, int max) {
|
||||
mWrapped.setProgress(message, mFrom+ progress*(mTo-mFrom)/max, mMax);
|
||||
mWrapped.setProgress(message, mFrom + progress * (mTo - mFrom) / max, mMax);
|
||||
}
|
||||
|
||||
public void setProgress(int resourceId, int progress, int max) {
|
||||
|
||||
@@ -18,14 +18,16 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.util;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.EncodeHintType;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.qrcode.QRCodeWriter;
|
||||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
Reference in New Issue
Block a user