mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-12-25 00:18:51 -05:00
passphrasecache: cache by master key, introduce preference for cache by subkey
This commit is contained in:
parent
675e8e2015
commit
070017b12f
@ -72,6 +72,7 @@ public final class Constants {
|
|||||||
public static final String DEFAULT_MESSAGE_COMPRESSION = "defaultMessageCompression";
|
public static final String DEFAULT_MESSAGE_COMPRESSION = "defaultMessageCompression";
|
||||||
public static final String DEFAULT_FILE_COMPRESSION = "defaultFileCompression";
|
public static final String DEFAULT_FILE_COMPRESSION = "defaultFileCompression";
|
||||||
public static final String PASSPHRASE_CACHE_TTL = "passphraseCacheTtl";
|
public static final String PASSPHRASE_CACHE_TTL = "passphraseCacheTtl";
|
||||||
|
public static final String PASSPHRASE_CACHE_SUBS = "passphraseCacheSubs";
|
||||||
public static final String LANGUAGE = "language";
|
public static final String LANGUAGE = "language";
|
||||||
public static final String KEY_SERVERS = "keyServers";
|
public static final String KEY_SERVERS = "keyServers";
|
||||||
public static final String PREF_DEFAULT_VERSION = "keyServersDefaultVersion";
|
public static final String PREF_DEFAULT_VERSION = "keyServersDefaultVersion";
|
||||||
|
@ -6,6 +6,8 @@ public interface PassphraseCacheInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCachedPassphrase(long masterKeyId) throws NoSecretKeyException;
|
public String getCachedPassphrase(long subKeyId) throws NoSecretKeyException;
|
||||||
|
|
||||||
|
public String getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,11 @@ import org.spongycastle.util.encoders.Hex;
|
|||||||
import org.sufficientlysecure.keychain.nfc.NfcActivity;
|
import org.sufficientlysecure.keychain.nfc.NfcActivity;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface;
|
import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface.NoSecretKeyException;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
||||||
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
||||||
|
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
|
||||||
import org.sufficientlysecure.keychain.service.results.DecryptVerifyResult;
|
import org.sufficientlysecure.keychain.service.results.DecryptVerifyResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
|
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
|
||||||
@ -74,6 +76,28 @@ public class OpenPgpService extends RemoteService {
|
|||||||
static final String EMAIL_SEARCH_WHERE = Tables.KEYS + "." + KeychainContract.KeyRings.IS_REVOKED
|
static final String EMAIL_SEARCH_WHERE = Tables.KEYS + "." + KeychainContract.KeyRings.IS_REVOKED
|
||||||
+ " = 0 AND " + KeychainContract.KeyRings.IS_EXPIRED + " = 0";
|
+ " = 0 AND " + KeychainContract.KeyRings.IS_EXPIRED + " = 0";
|
||||||
|
|
||||||
|
private PassphraseCacheInterface passphraseCacheInterface = new PassphraseCacheInterface() {
|
||||||
|
@Override
|
||||||
|
public String getCachedPassphrase(long subKeyId) throws NoSecretKeyException {
|
||||||
|
try {
|
||||||
|
long masterKeyId = new ProviderHelper(getContext()).getMasterKeyId(subKeyId);
|
||||||
|
return getCachedPassphrase(masterKeyId, subKeyId);
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
throw new PassphraseCacheInterface.NoSecretKeyException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException {
|
||||||
|
try {
|
||||||
|
return PassphraseCacheService.getCachedPassphrase(
|
||||||
|
getContext(), masterKeyId, subKeyId);
|
||||||
|
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
||||||
|
throw new PassphraseCacheInterface.NoSecretKeyException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search database for key ids based on emails.
|
* Search database for key ids based on emails.
|
||||||
*
|
*
|
||||||
@ -232,7 +256,8 @@ public class OpenPgpService extends RemoteService {
|
|||||||
passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
|
passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), accSettings.getKeyId());
|
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(),
|
||||||
|
accSettings.getKeyId(), accSettings.getKeyId());
|
||||||
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
||||||
// secret key that is set for this account is deleted?
|
// secret key that is set for this account is deleted?
|
||||||
// show account config again!
|
// show account config again!
|
||||||
@ -269,22 +294,11 @@ public class OpenPgpService extends RemoteService {
|
|||||||
// Find the appropriate subkey to sign with
|
// Find the appropriate subkey to sign with
|
||||||
CachedPublicKeyRing signingRing =
|
CachedPublicKeyRing signingRing =
|
||||||
new ProviderHelper(this).getCachedPublicKeyRing(accSettings.getKeyId());
|
new ProviderHelper(this).getCachedPublicKeyRing(accSettings.getKeyId());
|
||||||
long sigSubKeyId = signingRing.getSignId();
|
final long sigSubKeyId = signingRing.getSignId();
|
||||||
|
|
||||||
// sign-only
|
// sign-only
|
||||||
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
|
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
|
||||||
new ProviderHelper(getContext()),
|
new ProviderHelper(getContext()), passphraseCacheInterface,
|
||||||
new PassphraseCacheInterface() {
|
|
||||||
@Override
|
|
||||||
public String getCachedPassphrase(long masterKeyId) throws PassphraseCacheInterface.NoSecretKeyException {
|
|
||||||
try {
|
|
||||||
return PassphraseCacheService.getCachedPassphrase(
|
|
||||||
OpenPgpService.this, masterKeyId);
|
|
||||||
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
|
||||||
throw new PassphraseCacheInterface.NoSecretKeyException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
inputData, os
|
inputData, os
|
||||||
);
|
);
|
||||||
builder.setEnableAsciiArmorOutput(asciiArmor)
|
builder.setEnableAsciiArmorOutput(asciiArmor)
|
||||||
@ -376,18 +390,7 @@ public class OpenPgpService extends RemoteService {
|
|||||||
InputData inputData = new InputData(is, inputLength);
|
InputData inputData = new InputData(is, inputLength);
|
||||||
|
|
||||||
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
|
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
|
||||||
new ProviderHelper(getContext()),
|
new ProviderHelper(getContext()), passphraseCacheInterface,
|
||||||
new PassphraseCacheInterface() {
|
|
||||||
@Override
|
|
||||||
public String getCachedPassphrase(long masterKeyId) throws PassphraseCacheInterface.NoSecretKeyException {
|
|
||||||
try {
|
|
||||||
return PassphraseCacheService.getCachedPassphrase(
|
|
||||||
OpenPgpService.this, masterKeyId);
|
|
||||||
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
|
||||||
throw new PassphraseCacheInterface.NoSecretKeyException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
inputData, os
|
inputData, os
|
||||||
);
|
);
|
||||||
builder.setEnableAsciiArmorOutput(asciiArmor)
|
builder.setEnableAsciiArmorOutput(asciiArmor)
|
||||||
@ -404,7 +407,7 @@ public class OpenPgpService extends RemoteService {
|
|||||||
passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
|
passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
|
||||||
} else {
|
} else {
|
||||||
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(),
|
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(),
|
||||||
accSettings.getKeyId());
|
accSettings.getKeyId(), accSettings.getKeyId());
|
||||||
}
|
}
|
||||||
if (passphrase == null) {
|
if (passphrase == null) {
|
||||||
// get PendingIntent for passphrase input, add it to given params and return to client
|
// get PendingIntent for passphrase input, add it to given params and return to client
|
||||||
@ -496,18 +499,7 @@ public class OpenPgpService extends RemoteService {
|
|||||||
InputData inputData = new InputData(is, inputLength);
|
InputData inputData = new InputData(is, inputLength);
|
||||||
|
|
||||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
||||||
new ProviderHelper(this),
|
new ProviderHelper(getContext()), passphraseCacheInterface,
|
||||||
new PassphraseCacheInterface() {
|
|
||||||
@Override
|
|
||||||
public String getCachedPassphrase(long masterKeyId) throws PassphraseCacheInterface.NoSecretKeyException {
|
|
||||||
try {
|
|
||||||
return PassphraseCacheService.getCachedPassphrase(
|
|
||||||
OpenPgpService.this, masterKeyId);
|
|
||||||
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
|
||||||
throw new PassphraseCacheInterface.NoSecretKeyException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
inputData, os
|
inputData, os
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import android.os.RemoteException;
|
|||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
|
||||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
|
import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
|
||||||
@ -84,7 +85,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
* data from the activities or other apps, queues these intents, executes them, and stops itself
|
* data from the activities or other apps, queues these intents, executes them, and stops itself
|
||||||
* after doing them.
|
* after doing them.
|
||||||
*/
|
*/
|
||||||
public class KeychainIntentService extends IntentService implements Progressable {
|
public class KeychainIntentService extends IntentService implements Progressable, PassphraseCacheInterface {
|
||||||
|
|
||||||
/* extras that can be given by intent */
|
/* extras that can be given by intent */
|
||||||
public static final String EXTRA_MESSENGER = "messenger";
|
public static final String EXTRA_MESSENGER = "messenger";
|
||||||
@ -268,19 +269,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
|
|
||||||
/* Operation */
|
/* Operation */
|
||||||
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
|
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
|
||||||
new ProviderHelper(this),
|
new ProviderHelper(this), this, inputData, outStream
|
||||||
new PassphraseCacheInterface() {
|
|
||||||
@Override
|
|
||||||
public String getCachedPassphrase(long masterKeyId) throws PassphraseCacheInterface.NoSecretKeyException {
|
|
||||||
try {
|
|
||||||
return PassphraseCacheService.getCachedPassphrase(
|
|
||||||
KeychainIntentService.this, masterKeyId);
|
|
||||||
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
|
||||||
throw new PassphraseCacheInterface.NoSecretKeyException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
inputData, outStream
|
|
||||||
);
|
);
|
||||||
builder.setProgressable(this)
|
builder.setProgressable(this)
|
||||||
.setEnableAsciiArmorOutput(useAsciiArmor)
|
.setEnableAsciiArmorOutput(useAsciiArmor)
|
||||||
@ -348,18 +337,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
// verifyText and decrypt returning additional resultData values for the
|
// verifyText and decrypt returning additional resultData values for the
|
||||||
// verification of signatures
|
// verification of signatures
|
||||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
||||||
new ProviderHelper(this),
|
new ProviderHelper(this), this,
|
||||||
new PassphraseCacheInterface() {
|
|
||||||
@Override
|
|
||||||
public String getCachedPassphrase(long masterKeyId) throws PassphraseCacheInterface.NoSecretKeyException {
|
|
||||||
try {
|
|
||||||
return PassphraseCacheService.getCachedPassphrase(
|
|
||||||
KeychainIntentService.this, masterKeyId);
|
|
||||||
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
|
||||||
throw new PassphraseCacheInterface.NoSecretKeyException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
inputData, outStream
|
inputData, outStream
|
||||||
);
|
);
|
||||||
builder.setProgressable(this)
|
builder.setProgressable(this)
|
||||||
@ -397,18 +375,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
// verification of signatures
|
// verification of signatures
|
||||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
||||||
new ProviderHelper(this),
|
new ProviderHelper(this),
|
||||||
new PassphraseCacheInterface() {
|
this, inputData, null
|
||||||
@Override
|
|
||||||
public String getCachedPassphrase(long masterKeyId) throws PassphraseCacheInterface.NoSecretKeyException {
|
|
||||||
try {
|
|
||||||
return PassphraseCacheService.getCachedPassphrase(
|
|
||||||
KeychainIntentService.this, masterKeyId);
|
|
||||||
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
|
||||||
throw new PassphraseCacheInterface.NoSecretKeyException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
inputData, null
|
|
||||||
);
|
);
|
||||||
builder.setProgressable(this)
|
builder.setProgressable(this)
|
||||||
.setAllowSymmetricDecryption(true)
|
.setAllowSymmetricDecryption(true)
|
||||||
@ -489,7 +456,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
|
|
||||||
// cache new passphrase
|
// cache new passphrase
|
||||||
if (saveParcel.mNewPassphrase != null) {
|
if (saveParcel.mNewPassphrase != null) {
|
||||||
PassphraseCacheService.addCachedPassphrase(this, ring.getMasterKeyId(),
|
PassphraseCacheService.addCachedPassphrase(this, ring.getMasterKeyId(), ring.getMasterKeyId(),
|
||||||
saveParcel.mNewPassphrase, ring.getPublicKey().getPrimaryUserIdWithFallback());
|
saveParcel.mNewPassphrase, ring.getPublicKey().getPrimaryUserIdWithFallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -715,7 +682,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
|
|
||||||
/* Operation */
|
/* Operation */
|
||||||
String signaturePassphrase = PassphraseCacheService.getCachedPassphrase(this,
|
String signaturePassphrase = PassphraseCacheService.getCachedPassphrase(this,
|
||||||
masterKeyId);
|
masterKeyId, masterKeyId);
|
||||||
if (signaturePassphrase == null) {
|
if (signaturePassphrase == null) {
|
||||||
throw new PgpGeneralException("Unable to obtain passphrase");
|
throw new PgpGeneralException("Unable to obtain passphrase");
|
||||||
}
|
}
|
||||||
@ -898,6 +865,26 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCachedPassphrase(long subKeyId) throws NoSecretKeyException {
|
||||||
|
try {
|
||||||
|
long masterKeyId = new ProviderHelper(this).getMasterKeyId(subKeyId);
|
||||||
|
return getCachedPassphrase(masterKeyId, subKeyId);
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
throw new PassphraseCacheInterface.NoSecretKeyException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException {
|
||||||
|
try {
|
||||||
|
return PassphraseCacheService.getCachedPassphrase(
|
||||||
|
KeychainIntentService.this, masterKeyId, subKeyId);
|
||||||
|
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
||||||
|
throw new PassphraseCacheInterface.NoSecretKeyException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
if (ACTION_CANCEL.equals(intent.getAction())) {
|
if (ACTION_CANCEL.equals(intent.getAction())) {
|
||||||
|
@ -53,14 +53,26 @@ import java.util.Date;
|
|||||||
* passphrase cache. Use the static methods addCachedPassphrase and getCachedPassphrase for
|
* passphrase cache. Use the static methods addCachedPassphrase and getCachedPassphrase for
|
||||||
* convenience.
|
* convenience.
|
||||||
*
|
*
|
||||||
* Design decisions:
|
* The passphrase cache service always works with both a master key id and a subkey id. The master
|
||||||
* - Cache passphrases based on master key ids, but try to unlock before using the subkey id
|
* key id is always used to retrieve relevant info from the database, while the subkey id is used
|
||||||
* (to be compatible with stripped keys)
|
* to determine the type behavior (regular passphrase, empty passphrase, stripped key,
|
||||||
* - Cache based on master key id so that there is not need to enter a passphrase twice for sign and
|
* divert-to-card) for the specific key requested.
|
||||||
* decrypt (if these are two different subkeys)
|
*
|
||||||
* - Assume that all passphrases cached here are valid passphrases
|
* Caching behavior for subkeys depends on the cacheSubs preference:
|
||||||
* - Do not handle if a keyring contains subkeys with different passphrases. This is not considered
|
*
|
||||||
* supported and has not been seen in other OpenPGP implementations
|
* - If cacheSubs is NOT set, passphrases will be cached and retrieved by master key id. The
|
||||||
|
* checks for special subkeys will still be done, but otherwise it is assumed that all subkeys
|
||||||
|
* from the same master key will use the same passphrase. This can lead to bad passphrase
|
||||||
|
* errors if two subkeys are encrypted differently. This is the default behavior.
|
||||||
|
*
|
||||||
|
* - If cacheSubs IS set, passphrases will be cached per subkey id. This means that if a keyring
|
||||||
|
* has two subkeys for different purposes, passphrases will be cached independently and the
|
||||||
|
* user will be asked for a passphrase once per subkey even if it is the same one. This mode
|
||||||
|
* of operation is more precise, since we can assume that all passphrases returned from cache
|
||||||
|
* will be correct without fail. Since keyrings with differently encrypted subkeys are a very
|
||||||
|
* rare occurrence, and caching by keyring is what the user expects in the vast majority of
|
||||||
|
* cases, this is not the default behavior.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public class PassphraseCacheService extends Service {
|
public class PassphraseCacheService extends Service {
|
||||||
|
|
||||||
@ -76,6 +88,7 @@ public class PassphraseCacheService extends Service {
|
|||||||
|
|
||||||
public static final String EXTRA_TTL = "ttl";
|
public static final String EXTRA_TTL = "ttl";
|
||||||
public static final String EXTRA_KEY_ID = "key_id";
|
public static final String EXTRA_KEY_ID = "key_id";
|
||||||
|
public static final String EXTRA_SUBKEY_ID = "subkey_id";
|
||||||
public static final String EXTRA_PASSPHRASE = "passphrase";
|
public static final String EXTRA_PASSPHRASE = "passphrase";
|
||||||
public static final String EXTRA_MESSENGER = "messenger";
|
public static final String EXTRA_MESSENGER = "messenger";
|
||||||
public static final String EXTRA_USER_ID = "user_id";
|
public static final String EXTRA_USER_ID = "user_id";
|
||||||
@ -107,21 +120,19 @@ public class PassphraseCacheService extends Service {
|
|||||||
* This caches a new passphrase in memory by sending a new command to the service. An android
|
* This caches a new passphrase in memory by sending a new command to the service. An android
|
||||||
* service is only run once. Thus, when the service is already started, new commands just add
|
* service is only run once. Thus, when the service is already started, new commands just add
|
||||||
* new events to the alarm manager for new passphrases to let them timeout in the future.
|
* new events to the alarm manager for new passphrases to let them timeout in the future.
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* @param keyId
|
|
||||||
* @param passphrase
|
|
||||||
*/
|
*/
|
||||||
public static void addCachedPassphrase(Context context, long keyId, String passphrase,
|
public static void addCachedPassphrase(Context context, long masterKeyId, long subKeyId,
|
||||||
|
String passphrase,
|
||||||
String primaryUserId) {
|
String primaryUserId) {
|
||||||
Log.d(Constants.TAG, "PassphraseCacheService.cacheNewPassphrase() for " + keyId);
|
Log.d(Constants.TAG, "PassphraseCacheService.cacheNewPassphrase() for " + masterKeyId);
|
||||||
|
|
||||||
Intent intent = new Intent(context, PassphraseCacheService.class);
|
Intent intent = new Intent(context, PassphraseCacheService.class);
|
||||||
intent.setAction(ACTION_PASSPHRASE_CACHE_ADD);
|
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_PASSPHRASE, passphrase);
|
||||||
intent.putExtra(EXTRA_KEY_ID, keyId);
|
intent.putExtra(EXTRA_KEY_ID, masterKeyId);
|
||||||
|
intent.putExtra(EXTRA_SUBKEY_ID, subKeyId);
|
||||||
intent.putExtra(EXTRA_USER_ID, primaryUserId);
|
intent.putExtra(EXTRA_USER_ID, primaryUserId);
|
||||||
|
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
@ -130,13 +141,11 @@ public class PassphraseCacheService extends Service {
|
|||||||
/**
|
/**
|
||||||
* Gets a cached passphrase from memory by sending an intent to the service. This method is
|
* Gets a cached passphrase from memory by sending an intent to the service. This method is
|
||||||
* designed to wait until the service returns the passphrase.
|
* designed to wait until the service returns the passphrase.
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* @param keyId
|
|
||||||
* @return passphrase or null (if no passphrase is cached for this keyId)
|
* @return passphrase or null (if no passphrase is cached for this keyId)
|
||||||
*/
|
*/
|
||||||
public static String getCachedPassphrase(Context context, long keyId) throws KeyNotFoundException {
|
public static String getCachedPassphrase(Context context, long masterKeyId, long subKeyId) throws KeyNotFoundException {
|
||||||
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphrase() get masterKeyId for " + keyId);
|
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphrase() get masterKeyId for " + masterKeyId);
|
||||||
|
|
||||||
Intent intent = new Intent(context, PassphraseCacheService.class);
|
Intent intent = new Intent(context, PassphraseCacheService.class);
|
||||||
intent.setAction(ACTION_PASSPHRASE_CACHE_GET);
|
intent.setAction(ACTION_PASSPHRASE_CACHE_GET);
|
||||||
@ -162,16 +171,20 @@ public class PassphraseCacheService extends Service {
|
|||||||
|
|
||||||
// Create a new Messenger for the communication back
|
// Create a new Messenger for the communication back
|
||||||
Messenger messenger = new Messenger(returnHandler);
|
Messenger messenger = new Messenger(returnHandler);
|
||||||
intent.putExtra(EXTRA_KEY_ID, keyId);
|
intent.putExtra(EXTRA_KEY_ID, masterKeyId);
|
||||||
|
intent.putExtra(EXTRA_SUBKEY_ID, subKeyId);
|
||||||
intent.putExtra(EXTRA_MESSENGER, messenger);
|
intent.putExtra(EXTRA_MESSENGER, messenger);
|
||||||
// send intent to this service
|
// send intent to this service
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
|
|
||||||
// Wait on mutex until passphrase is returned to handlerThread
|
// Wait on mutex until passphrase is returned to handlerThread. Note that this local
|
||||||
|
// variable is used in the handler closure above, so it does make sense here!
|
||||||
|
// noinspection SynchronizationOnLocalVariableOrMethodParameter
|
||||||
synchronized (mutex) {
|
synchronized (mutex) {
|
||||||
try {
|
try {
|
||||||
mutex.wait(3000);
|
mutex.wait(3000);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
// don't care
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,34 +200,31 @@ public class PassphraseCacheService extends Service {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal implementation to get cached passphrase.
|
* Internal implementation to get cached passphrase.
|
||||||
*
|
|
||||||
* @param subKeyId
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
private String getCachedPassphraseImpl(long subKeyId) throws ProviderHelper.NotFoundException {
|
private String getCachedPassphraseImpl(long masterKeyId, long subKeyId) throws ProviderHelper.NotFoundException {
|
||||||
// passphrase for symmetric encryption?
|
// passphrase for symmetric encryption?
|
||||||
if (subKeyId == Constants.key.symmetric) {
|
if (masterKeyId == Constants.key.symmetric) {
|
||||||
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for symmetric encryption");
|
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for symmetric encryption");
|
||||||
String cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric).getPassphrase();
|
String cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric).getPassphrase();
|
||||||
if (cachedPassphrase == null) {
|
if (cachedPassphrase == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
addCachedPassphrase(this, Constants.key.symmetric, cachedPassphrase, getString(R.string.passp_cache_notif_pwd));
|
addCachedPassphrase(this, Constants.key.symmetric, Constants.key.symmetric,
|
||||||
|
cachedPassphrase, getString(R.string.passp_cache_notif_pwd));
|
||||||
return cachedPassphrase;
|
return cachedPassphrase;
|
||||||
}
|
}
|
||||||
|
|
||||||
// on "none" key, just do nothing
|
// on "none" key, just do nothing
|
||||||
if(subKeyId == Constants.key.none) {
|
if(masterKeyId == Constants.key.none) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to get master key id which is used as an identifier for cached passphrases
|
// try to get master key id which is used as an identifier for cached passphrases
|
||||||
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for masterKeyId " + subKeyId);
|
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for masterKeyId "
|
||||||
// find a master key id for our key
|
+ masterKeyId + ", subKeyId " + subKeyId);
|
||||||
long masterKeyId = new ProviderHelper(this).getMasterKeyId(subKeyId);
|
|
||||||
CachedPublicKeyRing keyRing = new ProviderHelper(this).getCachedPublicKeyRing(masterKeyId);
|
|
||||||
|
|
||||||
// get the type of key (from the database)
|
// get the type of key (from the database)
|
||||||
|
CachedPublicKeyRing keyRing = new ProviderHelper(this).getCachedPublicKeyRing(masterKeyId);
|
||||||
SecretKeyType keyType = keyRing.getSecretKeyType(subKeyId);
|
SecretKeyType keyType = keyRing.getSecretKeyType(subKeyId);
|
||||||
|
|
||||||
switch (keyType) {
|
switch (keyType) {
|
||||||
@ -237,14 +247,33 @@ public class PassphraseCacheService extends Service {
|
|||||||
// get cached passphrase
|
// get cached passphrase
|
||||||
CachedPassphrase cachedPassphrase = mPassphraseCache.get(subKeyId);
|
CachedPassphrase cachedPassphrase = mPassphraseCache.get(subKeyId);
|
||||||
if (cachedPassphrase == null) {
|
if (cachedPassphrase == null) {
|
||||||
Log.d(Constants.TAG, "PassphraseCacheService: Passphrase not (yet) cached, returning null");
|
|
||||||
// not really an error, just means the passphrase is not cached but not empty either
|
// If we cache strictly by subkey, exit early
|
||||||
return null;
|
if (Preferences.getPreferences(mContext).getPassphraseCacheSubs()) {
|
||||||
|
Log.d(Constants.TAG, "PassphraseCacheService: specific subkey passphrase not (yet) cached, returning null");
|
||||||
|
// not really an error, just means the passphrase is not cached but not empty either
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subKeyId == masterKeyId) {
|
||||||
|
Log.d(Constants.TAG, "PassphraseCacheService: masterkey passphrase not (yet) cached, returning null");
|
||||||
|
// not really an error, just means the passphrase is not cached but not empty either
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedPassphrase = mPassphraseCache.get(masterKeyId);
|
||||||
|
// If we cache strictly by subkey, exit early
|
||||||
|
if (cachedPassphrase == null) {
|
||||||
|
Log.d(Constants.TAG, "PassphraseCacheService: keyring passphrase not (yet) cached, returning null");
|
||||||
|
// not really an error, just means the passphrase is not cached but not empty either
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set it again to reset the cache life cycle
|
// set it again to reset the cache life cycle
|
||||||
Log.d(Constants.TAG, "PassphraseCacheService: Cache passphrase again when getting it!");
|
Log.d(Constants.TAG, "PassphraseCacheService: Cache passphrase again when getting it!");
|
||||||
addCachedPassphrase(this, subKeyId, cachedPassphrase.getPassphrase(), cachedPassphrase.getPrimaryUserID());
|
addCachedPassphrase(this, masterKeyId, subKeyId, cachedPassphrase.getPassphrase(), cachedPassphrase.getPrimaryUserID());
|
||||||
return cachedPassphrase.getPassphrase();
|
return cachedPassphrase.getPassphrase();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,10 +306,6 @@ public class PassphraseCacheService extends Service {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Build pending intent that is executed by alarm manager to time out a specific passphrase
|
* Build pending intent that is executed by alarm manager to time out a specific passphrase
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* @param keyId
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
private static PendingIntent buildIntent(Context context, long keyId) {
|
private static PendingIntent buildIntent(Context context, long keyId) {
|
||||||
Intent intent = new Intent(BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE);
|
Intent intent = new Intent(BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE);
|
||||||
@ -302,38 +327,57 @@ public class PassphraseCacheService extends Service {
|
|||||||
if (intent != null && intent.getAction() != null) {
|
if (intent != null && intent.getAction() != null) {
|
||||||
if (ACTION_PASSPHRASE_CACHE_ADD.equals(intent.getAction())) {
|
if (ACTION_PASSPHRASE_CACHE_ADD.equals(intent.getAction())) {
|
||||||
long ttl = intent.getLongExtra(EXTRA_TTL, DEFAULT_TTL);
|
long ttl = intent.getLongExtra(EXTRA_TTL, DEFAULT_TTL);
|
||||||
long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
|
long masterKeyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
|
||||||
|
long subKeyId = intent.getLongExtra(EXTRA_SUBKEY_ID, -1);
|
||||||
|
|
||||||
String passphrase = intent.getStringExtra(EXTRA_PASSPHRASE);
|
String passphrase = intent.getStringExtra(EXTRA_PASSPHRASE);
|
||||||
String primaryUserID = intent.getStringExtra(EXTRA_USER_ID);
|
String primaryUserID = intent.getStringExtra(EXTRA_USER_ID);
|
||||||
|
|
||||||
Log.d(Constants.TAG,
|
Log.d(Constants.TAG,
|
||||||
"PassphraseCacheService: Received ACTION_PASSPHRASE_CACHE_ADD intent in onStartCommand() with keyId: "
|
"PassphraseCacheService: Received ACTION_PASSPHRASE_CACHE_ADD intent in onStartCommand() with masterkeyId: "
|
||||||
+ keyId + ", ttl: " + ttl + ", usrId: " + primaryUserID
|
+ masterKeyId + ", subKeyId: " + subKeyId + ", ttl: " + ttl + ", usrId: " + primaryUserID
|
||||||
);
|
);
|
||||||
|
|
||||||
// add keyId, passphrase and primary user id to memory
|
// if we don't cache by specific subkey id, or the requested subkey is the master key,
|
||||||
mPassphraseCache.put(keyId, new CachedPassphrase(passphrase, primaryUserID));
|
// just add master key id to the cache
|
||||||
|
if (subKeyId == masterKeyId || !Preferences.getPreferences(mContext).getPassphraseCacheSubs()) {
|
||||||
if (ttl > 0) {
|
mPassphraseCache.put(masterKeyId, new CachedPassphrase(passphrase, primaryUserID));
|
||||||
// register new alarm with keyId for this passphrase
|
if (ttl > 0) {
|
||||||
long triggerTime = new Date().getTime() + (ttl * 1000);
|
// register new alarm with keyId for this passphrase
|
||||||
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
|
long triggerTime = new Date().getTime() + (ttl * 1000);
|
||||||
am.set(AlarmManager.RTC_WAKEUP, triggerTime, buildIntent(this, keyId));
|
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
|
||||||
|
am.set(AlarmManager.RTC_WAKEUP, triggerTime, buildIntent(this, masterKeyId));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// otherwise, add this specific subkey to the cache
|
||||||
|
mPassphraseCache.put(subKeyId, new CachedPassphrase(passphrase, primaryUserID));
|
||||||
|
if (ttl > 0) {
|
||||||
|
// register new alarm with keyId for this passphrase
|
||||||
|
long triggerTime = new Date().getTime() + (ttl * 1000);
|
||||||
|
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
|
||||||
|
am.set(AlarmManager.RTC_WAKEUP, triggerTime, buildIntent(this, subKeyId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateService();
|
updateService();
|
||||||
} else if (ACTION_PASSPHRASE_CACHE_GET.equals(intent.getAction())) {
|
} else if (ACTION_PASSPHRASE_CACHE_GET.equals(intent.getAction())) {
|
||||||
long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
|
long masterKeyId = intent.getLongExtra(EXTRA_KEY_ID, Constants.key.symmetric);
|
||||||
|
long subKeyId = intent.getLongExtra(EXTRA_SUBKEY_ID, Constants.key.symmetric);
|
||||||
Messenger messenger = intent.getParcelableExtra(EXTRA_MESSENGER);
|
Messenger messenger = intent.getParcelableExtra(EXTRA_MESSENGER);
|
||||||
|
|
||||||
Message msg = Message.obtain();
|
Message msg = Message.obtain();
|
||||||
try {
|
try {
|
||||||
String passphrase = getCachedPassphraseImpl(keyId);
|
// If only one of these is symmetric, error out!
|
||||||
msg.what = MSG_PASSPHRASE_CACHE_GET_OKAY;
|
if (masterKeyId == Constants.key.symmetric ^ subKeyId == Constants.key.symmetric) {
|
||||||
Bundle bundle = new Bundle();
|
Log.e(Constants.TAG, "PassphraseCacheService: Bad request, missing masterKeyId or subKeyId!");
|
||||||
bundle.putString(EXTRA_PASSPHRASE, passphrase);
|
msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND;
|
||||||
msg.setData(bundle);
|
} else {
|
||||||
|
String passphrase = getCachedPassphraseImpl(masterKeyId, subKeyId);
|
||||||
|
msg.what = MSG_PASSPHRASE_CACHE_GET_OKAY;
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putString(EXTRA_PASSPHRASE, passphrase);
|
||||||
|
msg.setData(bundle);
|
||||||
|
}
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
} catch (ProviderHelper.NotFoundException e) {
|
||||||
Log.e(Constants.TAG, "PassphraseCacheService: Passphrase for unknown key was requested!");
|
Log.e(Constants.TAG, "PassphraseCacheService: Passphrase for unknown key was requested!");
|
||||||
msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND;
|
msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND;
|
||||||
@ -365,9 +409,6 @@ public class PassphraseCacheService extends Service {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when one specific passphrase for keyId timed out
|
* Called when one specific passphrase for keyId timed out
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* @param keyId
|
|
||||||
*/
|
*/
|
||||||
private void timeout(Context context, long keyId) {
|
private void timeout(Context context, long keyId) {
|
||||||
// remove passphrase corresponding to keyId from memory
|
// remove passphrase corresponding to keyId from memory
|
||||||
|
@ -271,7 +271,7 @@ public class CertifyKeyFragment extends LoaderFragment
|
|||||||
// get the user's passphrase for this key (if required)
|
// get the user's passphrase for this key (if required)
|
||||||
String passphrase;
|
String passphrase;
|
||||||
try {
|
try {
|
||||||
passphrase = PassphraseCacheService.getCachedPassphrase(mActivity, mMasterKeyId);
|
passphrase = PassphraseCacheService.getCachedPassphrase(mActivity, mMasterKeyId, mMasterKeyId);
|
||||||
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
||||||
Log.e(Constants.TAG, "Key not found!", e);
|
Log.e(Constants.TAG, "Key not found!", e);
|
||||||
mActivity.finish();
|
mActivity.finish();
|
||||||
|
@ -236,7 +236,7 @@ public class EditKeyFragment extends LoaderFragment implements
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
mCurrentPassphrase = PassphraseCacheService.getCachedPassphrase(getActivity(),
|
mCurrentPassphrase = PassphraseCacheService.getCachedPassphrase(getActivity(),
|
||||||
mSaveKeyringParcel.mMasterKeyId);
|
mSaveKeyringParcel.mMasterKeyId, mSaveKeyringParcel.mMasterKeyId);
|
||||||
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
||||||
finishWithError(LogType.MSG_EK_ERROR_NOT_FOUND);
|
finishWithError(LogType.MSG_EK_ERROR_NOT_FOUND);
|
||||||
return;
|
return;
|
||||||
|
@ -64,7 +64,6 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
|||||||
// special extra for OpenPgpService
|
// special extra for OpenPgpService
|
||||||
public static final String EXTRA_DATA = "data";
|
public static final String EXTRA_DATA = "data";
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@ -251,8 +250,9 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
|||||||
|
|
||||||
// Early breakout if we are dealing with a symmetric key
|
// Early breakout if we are dealing with a symmetric key
|
||||||
if (mSecretRing == null) {
|
if (mSecretRing == null) {
|
||||||
PassphraseCacheService.addCachedPassphrase(getActivity(), Constants.key.symmetric,
|
PassphraseCacheService.addCachedPassphrase(getActivity(),
|
||||||
passphrase, getString(R.string.passp_cache_notif_pwd));
|
Constants.key.symmetric, Constants.key.symmetric, passphrase,
|
||||||
|
getString(R.string.passp_cache_notif_pwd));
|
||||||
|
|
||||||
finishCaching(passphrase);
|
finishCaching(passphrase);
|
||||||
return;
|
return;
|
||||||
@ -309,8 +309,9 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
|||||||
Log.d(Constants.TAG, "Everything okay! Caching entered passphrase");
|
Log.d(Constants.TAG, "Everything okay! Caching entered passphrase");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PassphraseCacheService.addCachedPassphrase(getActivity(), mSubKeyId,
|
PassphraseCacheService.addCachedPassphrase(getActivity(),
|
||||||
passphrase, mSecretRing.getPrimaryUserIdWithFallback());
|
mSecretRing.getMasterKeyId(), mSubKeyId, passphrase,
|
||||||
|
mSecretRing.getPrimaryUserIdWithFallback());
|
||||||
} catch (PgpGeneralException e) {
|
} catch (PgpGeneralException e) {
|
||||||
Log.e(Constants.TAG, "adding of a passphrase failed", e);
|
Log.e(Constants.TAG, "adding of a passphrase failed", e);
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ public class PreferencesActivity extends PreferenceActivity {
|
|||||||
} else if (action != null && action.equals(ACTION_PREFS_ADV)) {
|
} else if (action != null && action.equals(ACTION_PREFS_ADV)) {
|
||||||
addPreferencesFromResource(R.xml.adv_preferences);
|
addPreferencesFromResource(R.xml.adv_preferences);
|
||||||
|
|
||||||
initializePassPassphraceCacheTtl(
|
initializePassphraseCacheTtl(
|
||||||
(IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL));
|
(IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL));
|
||||||
|
|
||||||
initializeEncryptionAlgorithm(
|
initializeEncryptionAlgorithm(
|
||||||
@ -228,7 +228,10 @@ public class PreferencesActivity extends PreferenceActivity {
|
|||||||
// Load the preferences from an XML resource
|
// Load the preferences from an XML resource
|
||||||
addPreferencesFromResource(R.xml.adv_preferences);
|
addPreferencesFromResource(R.xml.adv_preferences);
|
||||||
|
|
||||||
initializePassPassphraceCacheTtl(
|
initializePassphraseCacheSubs(
|
||||||
|
(CheckBoxPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_SUBS));
|
||||||
|
|
||||||
|
initializePassphraseCacheTtl(
|
||||||
(IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL));
|
(IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL));
|
||||||
|
|
||||||
initializeEncryptionAlgorithm(
|
initializeEncryptionAlgorithm(
|
||||||
@ -281,7 +284,18 @@ public class PreferencesActivity extends PreferenceActivity {
|
|||||||
|| super.isValidFragment(fragmentName);
|
|| super.isValidFragment(fragmentName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void initializePassPassphraceCacheTtl(final IntegerListPreference mPassphraseCacheTtl) {
|
private static void initializePassphraseCacheSubs(final CheckBoxPreference mPassphraseCacheSubs) {
|
||||||
|
mPassphraseCacheSubs.setChecked(sPreferences.getPassphraseCacheSubs());
|
||||||
|
mPassphraseCacheSubs.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
mPassphraseCacheSubs.setChecked((Boolean) newValue);
|
||||||
|
sPreferences.setPassphraseCacheSubs((Boolean) newValue);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initializePassphraseCacheTtl(final IntegerListPreference mPassphraseCacheTtl) {
|
||||||
mPassphraseCacheTtl.setValue("" + sPreferences.getPassphraseCacheTtl());
|
mPassphraseCacheTtl.setValue("" + sPreferences.getPassphraseCacheTtl());
|
||||||
mPassphraseCacheTtl.setSummary(mPassphraseCacheTtl.getEntry());
|
mPassphraseCacheTtl.setSummary(mPassphraseCacheTtl.getEntry());
|
||||||
mPassphraseCacheTtl
|
mPassphraseCacheTtl
|
||||||
|
@ -242,7 +242,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
|
|||||||
// Early breakout if we are dealing with a symmetric key
|
// Early breakout if we are dealing with a symmetric key
|
||||||
if (mSecretRing == null) {
|
if (mSecretRing == null) {
|
||||||
PassphraseCacheService.addCachedPassphrase(getActivity(), Constants.key.symmetric,
|
PassphraseCacheService.addCachedPassphrase(getActivity(), Constants.key.symmetric,
|
||||||
passphrase, getString(R.string.passp_cache_notif_pwd));
|
Constants.key.symmetric, passphrase, getString(R.string.passp_cache_notif_pwd));
|
||||||
// also return passphrase back to activity
|
// also return passphrase back to activity
|
||||||
Bundle data = new Bundle();
|
Bundle data = new Bundle();
|
||||||
data.putString(MESSAGE_DATA_PASSPHRASE, passphrase);
|
data.putString(MESSAGE_DATA_PASSPHRASE, passphrase);
|
||||||
@ -301,8 +301,9 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
|
|||||||
Log.d(Constants.TAG, "Everything okay! Caching entered passphrase");
|
Log.d(Constants.TAG, "Everything okay! Caching entered passphrase");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PassphraseCacheService.addCachedPassphrase(getActivity(), mSubKeyId,
|
PassphraseCacheService.addCachedPassphrase(getActivity(),
|
||||||
passphrase, mSecretRing.getPrimaryUserIdWithFallback());
|
mSecretRing.getMasterKeyId(), mSubKeyId, passphrase,
|
||||||
|
mSecretRing.getPrimaryUserIdWithFallback());
|
||||||
} catch (PgpGeneralException e) {
|
} catch (PgpGeneralException e) {
|
||||||
Log.e(Constants.TAG, "adding of a passphrase failed", e);
|
Log.e(Constants.TAG, "adding of a passphrase failed", e);
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,16 @@ public class Preferences {
|
|||||||
editor.commit();
|
editor.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getPassphraseCacheSubs() {
|
||||||
|
return mSharedPreferences.getBoolean(Pref.PASSPHRASE_CACHE_SUBS, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassphraseCacheSubs(boolean value) {
|
||||||
|
SharedPreferences.Editor editor = mSharedPreferences.edit();
|
||||||
|
editor.putBoolean(Pref.PASSPHRASE_CACHE_SUBS, value);
|
||||||
|
editor.commit();
|
||||||
|
}
|
||||||
|
|
||||||
public int getDefaultEncryptionAlgorithm() {
|
public int getDefaultEncryptionAlgorithm() {
|
||||||
return mSharedPreferences.getInt(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM,
|
return mSharedPreferences.getInt(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM,
|
||||||
PGPEncryptedData.AES_256);
|
PGPEncryptedData.AES_256);
|
||||||
|
@ -111,6 +111,7 @@
|
|||||||
<string name="label_hash_algorithm">"Hash algorithm"</string>
|
<string name="label_hash_algorithm">"Hash algorithm"</string>
|
||||||
<string name="label_symmetric">"Encrypt with passphrase"</string>
|
<string name="label_symmetric">"Encrypt with passphrase"</string>
|
||||||
<string name="label_passphrase_cache_ttl">"Passphrase cache"</string>
|
<string name="label_passphrase_cache_ttl">"Passphrase cache"</string>
|
||||||
|
<string name="label_passphrase_cache_subs">"Cache passphrases by subkey"</string>
|
||||||
<string name="label_message_compression">"Message compression"</string>
|
<string name="label_message_compression">"Message compression"</string>
|
||||||
<string name="label_file_compression">"File compression"</string>
|
<string name="label_file_compression">"File compression"</string>
|
||||||
<string name="label_keyservers">"Keyservers"</string>
|
<string name="label_keyservers">"Keyservers"</string>
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
android:key="passphraseCacheTtl"
|
android:key="passphraseCacheTtl"
|
||||||
android:persistent="false"
|
android:persistent="false"
|
||||||
android:title="@string/label_passphrase_cache_ttl" />
|
android:title="@string/label_passphrase_cache_ttl" />
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:key="passphraseCacheSubs"
|
||||||
|
android:persistent="false"
|
||||||
|
android:title="@string/label_passphrase_cache_subs" />
|
||||||
<org.sufficientlysecure.keychain.ui.widget.IntegerListPreference
|
<org.sufficientlysecure.keychain.ui.widget.IntegerListPreference
|
||||||
android:key="defaultEncryptionAlgorithm"
|
android:key="defaultEncryptionAlgorithm"
|
||||||
android:persistent="false"
|
android:persistent="false"
|
||||||
|
Loading…
Reference in New Issue
Block a user