aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2014-08-14 13:31:01 +0200
committerDominik Schürmann <dominik@dominikschuermann.de>2014-08-14 13:31:01 +0200
commit6da17ef6bbe9569e53268b446e59dcc69aaa2da4 (patch)
tree0747b0f06b974f032573f48c08930498050ab9ce /OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service
parent881a50207af0a9f9f5aa69f451110de786779b54 (diff)
parent37edd0f390064e725d1b5c1c866a76c9922b0f64 (diff)
downloadopen-keychain-6da17ef6bbe9569e53268b446e59dcc69aaa2da4.tar.gz
open-keychain-6da17ef6bbe9569e53268b446e59dcc69aaa2da4.tar.bz2
open-keychain-6da17ef6bbe9569e53268b446e59dcc69aaa2da4.zip
Merge branch 'master' into yubikey
Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java97
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java102
2 files changed, 144 insertions, 55 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index a7115a53d..d6c470e11 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -86,6 +86,8 @@ public class KeychainIntentService extends IntentService
public static final String ACTION_DECRYPT_VERIFY = Constants.INTENT_PREFIX + "DECRYPT_VERIFY";
+ public static final String ACTION_DECRYPT_METADATA = Constants.INTENT_PREFIX + "DECRYPT_METADATA";
+
public static final String ACTION_SAVE_KEYRING = Constants.INTENT_PREFIX + "SAVE_KEYRING";
public static final String ACTION_DELETE_FILE_SECURELY = Constants.INTENT_PREFIX
@@ -241,16 +243,17 @@ public class KeychainIntentService extends IntentService
data.putInt(SELECTED_URI, i);
InputData inputData = createEncryptInputData(data);
OutputStream outStream = createCryptOutputStream(data);
+ String originalFilename = getOriginalFilename(data);
/* Operation */
PgpSignEncrypt.Builder builder =
new PgpSignEncrypt.Builder(
new ProviderHelper(this),
- PgpHelper.getFullVersion(this),
inputData, outStream);
builder.setProgressable(this);
builder.setEnableAsciiArmorOutput(useAsciiArmor)
+ .setVersionHeader(PgpHelper.getVersionForHeader(this))
.setCompressionId(compressionId)
.setSymmetricEncryptionAlgorithm(
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
@@ -261,7 +264,8 @@ public class KeychainIntentService extends IntentService
.setSignatureHashAlgorithm(
Preferences.getPreferences(this).getDefaultHashAlgorithm())
.setSignaturePassphrase(
- PassphraseCacheService.getCachedPassphrase(this, signatureKeyId));
+ PassphraseCacheService.getCachedPassphrase(this, signatureKeyId))
+ .setOriginalFilename(originalFilename);
// this assumes that the bytes are cleartext (valid for current implementation!)
if (source == IO_BYTES) {
@@ -302,15 +306,19 @@ public class KeychainIntentService extends IntentService
new ProviderHelper(this),
new PgpDecryptVerify.PassphraseCache() {
@Override
- public String getCachedPassphrase(long masterKeyId) {
- return PassphraseCacheService.getCachedPassphrase(
- KeychainIntentService.this, masterKeyId);
+ public String getCachedPassphrase(long masterKeyId) throws PgpDecryptVerify.NoSecretKeyException {
+ try {
+ return PassphraseCacheService.getCachedPassphrase(
+ KeychainIntentService.this, masterKeyId);
+ } catch (PassphraseCacheService.KeyNotFoundException e) {
+ throw new PgpDecryptVerify.NoSecretKeyException();
+ }
}
},
- inputData, outStream);
- builder.setProgressable(this);
-
- builder.setAllowSymmetricDecryption(true)
+ inputData, outStream
+ );
+ builder.setProgressable(this)
+ .setAllowSymmetricDecryption(true)
.setPassphrase(passphrase);
PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute();
@@ -329,6 +337,50 @@ public class KeychainIntentService extends IntentService
} catch (Exception e) {
sendErrorToHandler(e);
}
+ } else if (ACTION_DECRYPT_METADATA.equals(action)) {
+ try {
+ /* Input */
+ String passphrase = data.getString(DECRYPT_PASSPHRASE);
+
+ InputData inputData = createDecryptInputData(data);
+
+ /* Operation */
+
+ Bundle resultData = new Bundle();
+
+ // verifyText and decrypt returning additional resultData values for the
+ // verification of signatures
+ PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
+ new ProviderHelper(this),
+ new PgpDecryptVerify.PassphraseCache() {
+ @Override
+ public String getCachedPassphrase(long masterKeyId) throws PgpDecryptVerify.NoSecretKeyException {
+ try {
+ return PassphraseCacheService.getCachedPassphrase(
+ KeychainIntentService.this, masterKeyId);
+ } catch (PassphraseCacheService.KeyNotFoundException e) {
+ throw new PgpDecryptVerify.NoSecretKeyException();
+ }
+ }
+ },
+ inputData, null
+ );
+ builder.setProgressable(this)
+ .setAllowSymmetricDecryption(true)
+ .setPassphrase(passphrase)
+ .setDecryptMetadataOnly(true);
+
+ PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute();
+
+ resultData.putParcelable(RESULT_DECRYPT_VERIFY_RESULT, decryptVerifyResult);
+
+ /* Output */
+ OtherHelper.logDebugBundle(resultData, "resultData");
+
+ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
+ } catch (Exception e) {
+ sendErrorToHandler(e);
+ }
} else if (ACTION_SAVE_KEYRING.equals(action)) {
try {
/* Input */
@@ -355,7 +407,7 @@ public class KeychainIntentService extends IntentService
UncachedKeyRing ring = result.getRing();
- providerHelper.saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100));
+ providerHelper.saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100));
// cache new passphrase
if (saveParcel.mNewPassphrase != null) {
@@ -402,7 +454,7 @@ public class KeychainIntentService extends IntentService
} else {
// get entries from cached file
FileImportCache<ParcelableKeyRing> cache =
- new FileImportCache<ParcelableKeyRing>(this);
+ new FileImportCache<ParcelableKeyRing>(this);
entries = cache.readCacheIntoList();
}
@@ -575,7 +627,7 @@ public class KeychainIntentService extends IntentService
CanonicalizedPublicKeyRing publicRing = providerHelper.getCanonicalizedPublicKeyRing(pubKeyId);
CanonicalizedSecretKeyRing secretKeyRing = providerHelper.getCanonicalizedSecretKeyRing(masterKeyId);
CanonicalizedSecretKey certificationKey = secretKeyRing.getSecretKey();
- if(!certificationKey.unlock(signaturePassphrase)) {
+ if (!certificationKey.unlock(signaturePassphrase)) {
throw new PgpGeneralException("Error extracting key (bad passphrase?)");
}
UncachedKeyRing newRing = certificationKey.certifyUserIds(publicRing, userIds);
@@ -728,6 +780,27 @@ public class KeychainIntentService extends IntentService
}
}
+ private String getOriginalFilename(Bundle data) throws PgpGeneralException, FileNotFoundException {
+ int target = data.getInt(TARGET);
+ switch (target) {
+ case IO_BYTES:
+ return "";
+
+ case IO_URI:
+ Uri providerUri = data.getParcelable(ENCRYPT_INPUT_URI);
+
+ return FileHelper.getFilename(this, providerUri);
+
+ case IO_URIS:
+ providerUri = data.<Uri>getParcelableArrayList(ENCRYPT_INPUT_URIS).get(data.getInt(SELECTED_URI));
+
+ return FileHelper.getFilename(this, providerUri);
+
+ default:
+ throw new PgpGeneralException("No target choosen!");
+ }
+ }
+
private OutputStream createCryptOutputStream(Bundle data) throws PgpGeneralException, FileNotFoundException {
int target = data.getInt(TARGET);
switch (target) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
index e813ca26c..8cd9876eb 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
@@ -77,12 +77,24 @@ public class PassphraseCacheService extends Service {
private static final int NOTIFICATION_ID = 1;
+ private static final int MSG_PASSPHRASE_CACHE_GET_OKAY = 1;
+ private static final int MSG_PASSPHRASE_CACHE_GET_KEY_NO_FOUND = 2;
+
private BroadcastReceiver mIntentReceiver;
private LongSparseArray<CachedPassphrase> mPassphraseCache = new LongSparseArray<CachedPassphrase>();
Context mContext;
+ public static class KeyNotFoundException extends Exception {
+ public KeyNotFoundException() {
+ }
+
+ public KeyNotFoundException(String name) {
+ super(name);
+ }
+ }
+
/**
* 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
@@ -115,24 +127,23 @@ public class PassphraseCacheService extends Service {
* @param keyId
* @return passphrase or null (if no passphrase is cached for this keyId)
*/
- public static String getCachedPassphrase(Context context, long keyId) {
+ public static String getCachedPassphrase(Context context, long keyId) throws KeyNotFoundException {
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphrase() get masterKeyId for " + keyId);
Intent intent = new Intent(context, PassphraseCacheService.class);
intent.setAction(ACTION_PASSPHRASE_CACHE_GET);
final Object mutex = new Object();
- final Bundle returnBundle = new Bundle();
+ final Message returnMessage = Message.obtain();
HandlerThread handlerThread = new HandlerThread("getPassphraseThread");
handlerThread.start();
Handler returnHandler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message message) {
- if (message.obj != null) {
- String passphrase = ((Bundle) message.obj).getString(EXTRA_PASSPHRASE);
- returnBundle.putString(EXTRA_PASSPHRASE, passphrase);
- }
+ // copy over result to handle after mutex.wait
+ returnMessage.what = message.what;
+ returnMessage.copyFrom(message);
synchronized (mutex) {
mutex.notify();
}
@@ -156,10 +167,13 @@ public class PassphraseCacheService extends Service {
}
}
- if (returnBundle.containsKey(EXTRA_PASSPHRASE)) {
- return returnBundle.getString(EXTRA_PASSPHRASE);
- } else {
- return null;
+ switch (returnMessage.what) {
+ case MSG_PASSPHRASE_CACHE_GET_OKAY:
+ return returnMessage.getData().getString(EXTRA_PASSPHRASE);
+ case MSG_PASSPHRASE_CACHE_GET_KEY_NO_FOUND:
+ throw new KeyNotFoundException();
+ default:
+ throw new KeyNotFoundException("should not happen!");
}
}
@@ -169,7 +183,7 @@ public class PassphraseCacheService extends Service {
* @param keyId
* @return
*/
- private String getCachedPassphraseImpl(long keyId) {
+ private String getCachedPassphraseImpl(long keyId) throws ProviderHelper.NotFoundException {
// passphrase for symmetric encryption?
if (keyId == Constants.key.symmetric) {
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for symmetric encryption");
@@ -182,46 +196,41 @@ public class PassphraseCacheService extends Service {
}
// try to get master key id which is used as an identifier for cached passphrases
- try {
- Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for masterKeyId " + keyId);
- CanonicalizedSecretKeyRing key = new ProviderHelper(this).getCanonicalizedSecretKeyRing(
- KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(keyId));
- // no passphrase needed? just add empty string and return it, then
- if (!key.hasPassphrase()) {
- Log.d(Constants.TAG, "Key has no passphrase! Caches and returns empty passphrase!");
+ Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for masterKeyId " + keyId);
+ CanonicalizedSecretKeyRing key = new ProviderHelper(this).getCanonicalizedSecretKeyRing(
+ KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(keyId));
- try {
- addCachedPassphrase(this, keyId, "", key.getPrimaryUserIdWithFallback());
- } catch (PgpGeneralException e) {
- Log.d(Constants.TAG, "PgpGeneralException occured");
- }
- return "";
- }
+ // no passphrase needed? just add empty string and return it, then
+ if (!key.hasPassphrase()) {
+ Log.d(Constants.TAG, "Key has no passphrase! Caches and returns empty passphrase!");
- // TODO: HACK
+ // TODO: HACK for yubikeys
if (key.getSecretKey().getSecretKey().getS2K().getType() == S2K.GNU_DUMMY_S2K
&& key.getSecretKey().getSecretKey().getS2K().getProtectionMode() == 2) {
// NFC!
return "123456";
}
- // get cached passphrase
- CachedPassphrase cachedPassphrase = mPassphraseCache.get(keyId);
- 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
- return null;
+ try {
+ addCachedPassphrase(this, keyId, "", key.getPrimaryUserIdWithFallback());
+ } catch (PgpGeneralException e) {
+ Log.d(Constants.TAG, "PgpGeneralException occured");
}
+ return "";
+ }
- // set it again to reset the cache life cycle
- Log.d(Constants.TAG, "PassphraseCacheService: Cache passphrase again when getting it!");
- addCachedPassphrase(this, keyId, cachedPassphrase.getPassphrase(), cachedPassphrase.getPrimaryUserID());
- return cachedPassphrase.getPassphrase();
-
- } catch (ProviderHelper.NotFoundException e) {
- Log.e(Constants.TAG, "PassphraseCacheService: Passphrase for unknown key was requested!");
+ // get cached passphrase
+ CachedPassphrase cachedPassphrase = mPassphraseCache.get(keyId);
+ 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
return null;
}
+
+ // set it again to reset the cache life cycle
+ Log.d(Constants.TAG, "PassphraseCacheService: Cache passphrase again when getting it!");
+ addCachedPassphrase(this, keyId, cachedPassphrase.getPassphrase(), cachedPassphrase.getPrimaryUserID());
+ return cachedPassphrase.getPassphrase();
}
/**
@@ -303,12 +312,19 @@ public class PassphraseCacheService extends Service {
long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
Messenger messenger = intent.getParcelableExtra(EXTRA_MESSENGER);
- String passphrase = getCachedPassphraseImpl(keyId);
Message msg = Message.obtain();
- Bundle bundle = new Bundle();
- bundle.putString(EXTRA_PASSPHRASE, passphrase);
- msg.obj = bundle;
+ try {
+ String passphrase = getCachedPassphraseImpl(keyId);
+ msg.what = MSG_PASSPHRASE_CACHE_GET_OKAY;
+ Bundle bundle = new Bundle();
+ bundle.putString(EXTRA_PASSPHRASE, passphrase);
+ msg.setData(bundle);
+ } catch (ProviderHelper.NotFoundException e) {
+ Log.e(Constants.TAG, "PassphraseCacheService: Passphrase for unknown key was requested!");
+ msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NO_FOUND;
+ }
+
try {
messenger.send(msg);
} catch (RemoteException e) {