wrapped-key-ring: more work on passphrase caching and certification

This commit is contained in:
Vincent Breitmoser
2014-05-04 16:59:20 +02:00
parent 8cf0638f54
commit cd8af25ba7
4 changed files with 58 additions and 100 deletions

View File

@@ -81,23 +81,6 @@ public class PgpKeyHelper {
return getExpiryDate(key.getPublicKey()); return getExpiryDate(key.getPublicKey());
} }
@SuppressWarnings("unchecked")
@Deprecated
public static PGPSecretKey getKeyNum(PGPSecretKeyRing keyRing, long num) {
long cnt = 0;
if (keyRing == null) {
return null;
}
for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
if (cnt == num) {
return key;
}
cnt++;
}
return null;
}
public static int getKeyUsage(PGPSecretKey key) { public static int getKeyUsage(PGPSecretKey key) {
return getKeyUsage(key.getPublicKey()); return getKeyUsage(key.getPublicKey());
} }

View File

@@ -42,6 +42,7 @@ import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.pgp.CachedSecretKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
@@ -163,38 +164,46 @@ public class PassphraseCacheService extends Service {
* @return * @return
*/ */
private String getCachedPassphraseImpl(long keyId) { private String getCachedPassphraseImpl(long keyId) {
Log.d(TAG, "getCachedPassphraseImpl() get masterKeyId for " + keyId); // passphrase for symmetric encryption?
if (keyId == Constants.key.symmetric) {
Log.d(TAG, "getCachedPassphraseImpl() for symmetric encryption");
String cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric);
if (cachedPassphrase == null) {
return null;
}
addCachedPassphrase(this, Constants.key.symmetric, cachedPassphrase);
return cachedPassphrase;
}
// 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
long masterKeyId = keyId; try {
if (masterKeyId != Constants.key.symmetric) { Log.d(TAG, "getCachedPassphraseImpl() for masterKeyId " + keyId);
try { CachedSecretKeyRing key = new ProviderHelper(this).getCachedSecretKeyRing(
masterKeyId = new ProviderHelper(this).getMasterKeyId( KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId)));
KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId))); // no passphrase needed? just add empty string and return it, then
} catch (ProviderHelper.NotFoundException e) { if (!key.hasPassphrase()) {
return null;
}
}
Log.d(TAG, "getCachedPassphraseImpl() for masterKeyId " + masterKeyId);
// get cached passphrase
String cachedPassphrase = mPassphraseCache.get(masterKeyId);
if (cachedPassphrase == null) {
// if key has no passphrase -> cache and return empty passphrase
if (!hasPassphrase(this, masterKeyId)) {
Log.d(Constants.TAG, "Key has no passphrase! Caches and returns empty passphrase!"); Log.d(Constants.TAG, "Key has no passphrase! Caches and returns empty passphrase!");
addCachedPassphrase(this, masterKeyId, ""); addCachedPassphrase(this, keyId, "");
return ""; return "";
} else { }
// get cached passphrase
String cachedPassphrase = mPassphraseCache.get(keyId);
if (cachedPassphrase == null) {
// this is an error
return null; return null;
} }
}
// set it again to reset the cache life cycle
Log.d(TAG, "Cache passphrase again when getting it!");
addCachedPassphrase(this, masterKeyId, cachedPassphrase);
return cachedPassphrase; // set it again to reset the cache life cycle
Log.d(TAG, "Cache passphrase again when getting it!");
addCachedPassphrase(this, keyId, cachedPassphrase);
return cachedPassphrase;
} catch (ProviderHelper.NotFoundException e) {
Log.e(TAG, "Passphrase for unknown key was requested!");
return null;
}
} }
@Deprecated @Deprecated
@@ -230,16 +239,9 @@ public class PassphraseCacheService extends Service {
* @return true if it has a passphrase * @return true if it has a passphrase
*/ */
@Deprecated @Deprecated
public static boolean hasPassphrase(Context context, long secretKeyId) { public static boolean hasPassphrase(Context context, long secretKeyId)
// check if the key has no passphrase throws ProviderHelper.NotFoundException {
try { return new ProviderHelper(context).getCachedSecretKeyRing(secretKeyId).hasPassphrase();
PGPSecretKeyRing secRing = new ProviderHelper(context).getPGPSecretKeyRing(secretKeyId);
return hasPassphrase(secRing);
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e);
}
return true;
} }
/** /**

View File

@@ -226,53 +226,22 @@ public class CertifyKeyActivity extends ActionBarActivity implements
* handles the UI bits of the signing process on the UI thread * handles the UI bits of the signing process on the UI thread
*/ */
private void initiateSigning() { private void initiateSigning() {
try { // get the user's passphrase for this key (if required)
PGPPublicKeyRing pubring = new ProviderHelper(this).getPGPPublicKeyRing(mPubKeyId); String passphrase = PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId);
if (passphrase == null) {
// if we have already signed this key, dont bother doing it again PassphraseDialogFragment.show(this, mMasterKeyId,
boolean alreadySigned = false; new Handler() {
@Override
/* todo: reconsider this at a later point when certs are in the db public void handleMessage(Message message) {
@SuppressWarnings("unchecked") if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
Iterator<PGPSignature> itr = pubring.getPublicKey(mPubKeyId).getSignatures(); startSigning();
while (itr.hasNext()) { }
PGPSignature sig = itr.next(); }
if (sig.getKeyID() == mMasterKeyId) { });
alreadySigned = true; // bail out; need to wait until the user has entered the passphrase before trying again
break; return;
} } else {
} startSigning();
*/
if (!alreadySigned) {
/*
* get the user's passphrase for this key (if required)
*/
String passphrase = PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId);
if (passphrase == null) {
PassphraseDialogFragment.show(this, mMasterKeyId,
new Handler() {
@Override
public void handleMessage(Message message) {
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
startSigning();
}
}
});
// bail out; need to wait until the user has entered the passphrase before trying again
return;
} else {
startSigning();
}
} else {
AppMsg.makeText(this, R.string.key_has_already_been_certified, AppMsg.STYLE_ALERT)
.show();
setResult(RESULT_CANCELED);
finish();
}
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e);
} }
} }

View File

@@ -101,8 +101,12 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
long secretKeyId) throws PgpGeneralException { long secretKeyId) throws PgpGeneralException {
// check if secret key has a passphrase // check if secret key has a passphrase
if (!(secretKeyId == Constants.key.symmetric || secretKeyId == Constants.key.none)) { if (!(secretKeyId == Constants.key.symmetric || secretKeyId == Constants.key.none)) {
if (!PassphraseCacheService.hasPassphrase(context, secretKeyId)) { try {
throw new PgpGeneralException("No passphrase! No passphrase dialog needed!"); if (new ProviderHelper(context).getCachedSecretKeyRing(secretKeyId).hasPassphrase()) {
throw new PgpGeneralException("No passphrase! No passphrase dialog needed!");
}
} catch(ProviderHelper.NotFoundException e) {
throw new PgpGeneralException("Error: Key not found!", e);
} }
} }