From 363dcb62b81cff2a2b5ec275ece76c00045d2ec9 Mon Sep 17 00:00:00 2001 From: Thialfihar Date: Sat, 15 May 2010 15:19:56 +0000 Subject: [PATCH] password cache introduced, not cleared yet. --- src/org/thialfihar/android/apg/Apg.java | 29 +++++++++++--- .../apg/AskForSecretKeyPassPhrase.java | 10 +++-- .../thialfihar/android/apg/BaseActivity.java | 13 ++----- .../android/apg/CachedPassPhrase.java | 39 +++++++++++++++++++ .../android/apg/DecryptActivity.java | 29 +++++++++----- .../android/apg/EditKeyActivity.java | 28 +++++++------ .../android/apg/EncryptActivity.java | 14 +++---- src/org/thialfihar/android/apg/Id.java | 5 +++ .../android/apg/SecretKeyListActivity.java | 4 +- .../android/apg/ui/widget/SectionView.java | 7 +++- 10 files changed, 129 insertions(+), 49 deletions(-) create mode 100644 src/org/thialfihar/android/apg/CachedPassPhrase.java diff --git a/src/org/thialfihar/android/apg/Apg.java b/src/org/thialfihar/android/apg/Apg.java index 12b4719b2..a453cdf4a 100644 --- a/src/org/thialfihar/android/apg/Apg.java +++ b/src/org/thialfihar/android/apg/Apg.java @@ -155,7 +155,8 @@ public class Apg { PublicKeys.KEY_DATA, PublicKeys.WHO_ID, }; - private static String mPassPhrase = null; + private static HashMap mPassPhraseCache = + new HashMap(); public static class GeneralException extends Exception { static final long serialVersionUID = 0xf812773342L; @@ -271,12 +272,28 @@ public class Apg { } } - public static void setPassPhrase(String passPhrase) { - mPassPhrase = passPhrase; + public static void setCachedPassPhrase(long keyId, String passPhrase) { + mPassPhraseCache.put(keyId, new CachedPassPhrase(new Date().getTime(), passPhrase)); } - public static String getPassPhrase() { - return mPassPhrase; + public static String getCachedPassPhrase(long keyId) { + long realId = keyId; + if (realId != Id.key.symmetric) { + PGPSecretKeyRing keyRing = findSecretKeyRing(keyId); + if (keyRing == null) { + return null; + } + PGPSecretKey masterKey = getMasterKey(keyRing); + if (masterKey == null) { + return null; + } + realId = masterKey.getKeyID(); + } + CachedPassPhrase cpp = mPassPhraseCache.get(realId); + if (cpp == null) { + return null; + } + return cpp.passPhrase; } public static PGPSecretKey createKey(Context context, @@ -1440,7 +1457,7 @@ public class Apg { } if (secretKey == null) { - return 0; + return Id.key.none; } return secretKey.getKeyID(); diff --git a/src/org/thialfihar/android/apg/AskForSecretKeyPassPhrase.java b/src/org/thialfihar/android/apg/AskForSecretKeyPassPhrase.java index afc8e4320..67aad7529 100644 --- a/src/org/thialfihar/android/apg/AskForSecretKeyPassPhrase.java +++ b/src/org/thialfihar/android/apg/AskForSecretKeyPassPhrase.java @@ -32,7 +32,7 @@ import android.widget.Toast; public class AskForSecretKeyPassPhrase { public static interface PassPhraseCallbackInterface { - void passPhraseCallback(String passPhrase); + void passPhraseCallback(long keyId, String passPhrase); } public static Dialog createDialog(Activity context, long secretKeyId, @@ -43,7 +43,7 @@ public class AskForSecretKeyPassPhrase { final PGPSecretKey secretKey; - if (secretKeyId == 0) { + if (secretKeyId == Id.key.symmetric || secretKeyId == Id.key.none) { secretKey = null; alert.setMessage(context.getString(R.string.passPhraseForSymmetricEncryption)); } else { @@ -71,6 +71,7 @@ public class AskForSecretKeyPassPhrase { public void onClick(DialogInterface dialog, int id) { activity.removeDialog(Id.dialog.pass_phrase); String passPhrase = "" + input.getText(); + long keyId; if (secretKey != null) { try { secretKey.extractPrivateKey(passPhrase.toCharArray(), @@ -81,8 +82,11 @@ public class AskForSecretKeyPassPhrase { Toast.LENGTH_SHORT).show(); return; } + keyId = secretKey.getKeyID(); + } else { + keyId = Id.key.symmetric; } - cb.passPhraseCallback(passPhrase); + cb.passPhraseCallback(keyId, passPhrase); } }); diff --git a/src/org/thialfihar/android/apg/BaseActivity.java b/src/org/thialfihar/android/apg/BaseActivity.java index c0a3b03e1..6ab2089f3 100644 --- a/src/org/thialfihar/android/apg/BaseActivity.java +++ b/src/org/thialfihar/android/apg/BaseActivity.java @@ -192,14 +192,9 @@ public class BaseActivity extends Activity case Id.request.secret_keys: { if (resultCode == RESULT_OK) { Bundle bundle = data.getExtras(); - long newId = bundle.getLong("selectedKeyId"); - if (getSecretKeyId() != newId) { - Apg.setPassPhrase(null); - } - setSecretKeyId(newId); + setSecretKeyId(bundle.getLong("selectedKeyId")); } else { - setSecretKeyId(0); - Apg.setPassPhrase(null); + setSecretKeyId(Id.key.none); } break; } @@ -271,8 +266,8 @@ public class BaseActivity extends Activity } - public void passPhraseCallback(String passPhrase) { - Apg.setPassPhrase(passPhrase); + public void passPhraseCallback(long keyId, String passPhrase) { + Apg.setCachedPassPhrase(keyId, passPhrase); } public void sendMessage(Message msg) { diff --git a/src/org/thialfihar/android/apg/CachedPassPhrase.java b/src/org/thialfihar/android/apg/CachedPassPhrase.java new file mode 100644 index 000000000..e7566220e --- /dev/null +++ b/src/org/thialfihar/android/apg/CachedPassPhrase.java @@ -0,0 +1,39 @@ +package org.thialfihar.android.apg; + +public class CachedPassPhrase { + public final long timestamp; + public final String passPhrase; + + public CachedPassPhrase(long timestamp, String passPhrase) { + super(); + this.timestamp = timestamp; + this.passPhrase = passPhrase; + } + + public boolean equals(Object other) { + if (!(other instanceof CachedPassPhrase)) { + return false; + } + + CachedPassPhrase o = (CachedPassPhrase) other; + if (timestamp != o.timestamp) { + return false; + } + + if (passPhrase != o.passPhrase) { + if (passPhrase == null || o.passPhrase == null) { + return false; + } + + if (!passPhrase.equals(o.passPhrase)) { + return false; + } + } + + return true; + } + + public String toString() { + return "(" + timestamp + ", *******)"; + } +} diff --git a/src/org/thialfihar/android/apg/DecryptActivity.java b/src/org/thialfihar/android/apg/DecryptActivity.java index 377f9e9ea..b34bbba49 100644 --- a/src/org/thialfihar/android/apg/DecryptActivity.java +++ b/src/org/thialfihar/android/apg/DecryptActivity.java @@ -351,26 +351,35 @@ public class DecryptActivity extends BaseActivity { } try { setSecretKeyId(Apg.getDecryptionKeyId(this, in)); - if (getSecretKeyId() == 0) { + if (getSecretKeyId() == Id.key.none) { throw new Apg.GeneralException(getString(R.string.error_noSecretKeyFound)); } mAssumeSymmetricEncryption = false; } catch (Apg.NoAsymmetricEncryptionException e) { - setSecretKeyId(0); - // reopen the file/message to check whether there's + setSecretKeyId(Id.key.symmetric); + // look at the file/message again to check whether there's // symmetric encryption data in there if (mDecryptTarget == Id.target.file) { - in = new FileInputStream(mInputFilename); + ((FileInputStream) in).reset(); } else { - in = new ByteArrayInputStream(mMessage.getText().toString().getBytes()); + ((ByteArrayInputStream) in).reset(); } if (!Apg.hasSymmetricEncryption(this, in)) { throw new Apg.GeneralException(getString(R.string.error_noKnownEncryptionFound)); } mAssumeSymmetricEncryption = true; - } + } - showDialog(Id.dialog.pass_phrase); + if (getSecretKeyId() == Id.key.symmetric || + Apg.getCachedPassPhrase(getSecretKeyId()) == null) { + showDialog(Id.dialog.pass_phrase); + } else { + if (mDecryptTarget == Id.target.file) { + askForOutputFilename(); + } else { + decryptStart(); + } + } } catch (FileNotFoundException e) { error = getString(R.string.error_fileNotFound); } catch (IOException e) { @@ -404,8 +413,8 @@ public class DecryptActivity extends BaseActivity { } @Override - public void passPhraseCallback(String passPhrase) { - super.passPhraseCallback(passPhrase); + public void passPhraseCallback(long keyId, String passPhrase) { + super.passPhraseCallback(keyId, passPhrase); if (mDecryptTarget == Id.target.file) { askForOutputFilename(); } else { @@ -441,7 +450,7 @@ public class DecryptActivity extends BaseActivity { if (mSignedOnly) { data = Apg.verifyText(this, in, out, this); } else { - data = Apg.decrypt(this, in, out, Apg.getPassPhrase(), + data = Apg.decrypt(this, in, out, Apg.getCachedPassPhrase(getSecretKeyId()), this, mAssumeSymmetricEncryption); } diff --git a/src/org/thialfihar/android/apg/EditKeyActivity.java b/src/org/thialfihar/android/apg/EditKeyActivity.java index 6fd21178c..eb462d24a 100644 --- a/src/org/thialfihar/android/apg/EditKeyActivity.java +++ b/src/org/thialfihar/android/apg/EditKeyActivity.java @@ -24,6 +24,7 @@ import java.util.Vector; import org.bouncycastle2.openpgp.PGPException; import org.bouncycastle2.openpgp.PGPSecretKey; import org.bouncycastle2.openpgp.PGPSecretKeyRing; +import org.thialfihar.android.apg.ui.widget.KeyEditor; import org.thialfihar.android.apg.ui.widget.SectionView; import org.thialfihar.android.apg.utils.IterableIterator; @@ -70,9 +71,7 @@ public class EditKeyActivity extends BaseActivity implements OnClickListener { keyId = intent.getExtras().getLong("keyId"); } - if (keyId == 0) { - Apg.setPassPhrase(null); - } else { + if (keyId != 0) { PGPSecretKey masterKey = null; mKeyRing = Apg.getSecretKeyRing(keyId); if (mKeyRing != null) { @@ -88,10 +87,6 @@ public class EditKeyActivity extends BaseActivity implements OnClickListener { } } - if (Apg.getPassPhrase() == null) { - Apg.setPassPhrase(""); - } - mSaveButton = (Button) findViewById(R.id.btn_save); mDiscardButton = (Button) findViewById(R.id.btn_discard); @@ -114,15 +109,26 @@ public class EditKeyActivity extends BaseActivity implements OnClickListener { Toast.makeText(this, "Warning: Key editing is still kind of beta.", Toast.LENGTH_LONG).show(); } + public long getMasterKeyId() { + if (mKeys.getEditors().getChildCount() == 0) { + return 0; + } + return ((KeyEditor) mKeys.getEditors().getChildAt(0)).getValue().getKeyID(); + } + public boolean havePassPhrase() { - return (Apg.getPassPhrase() != null && !Apg.getPassPhrase().equals("")) || + long keyId = getMasterKeyId(); + if (keyId == 0) { + return false; + } + return (Apg.getCachedPassPhrase(keyId) != null && !Apg.getCachedPassPhrase(keyId).equals("")) || (mNewPassPhrase != null && !mNewPassPhrase.equals("")); } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, Id.menu.option.new_pass_phrase, 0, - (havePassPhrase() ? R.string.menu_changePassPhrase : R.string.menu_setPassPhrase)) + (havePassPhrase() ? R.string.menu_changePassPhrase : R.string.menu_setCachedPassPhrase)) .setIcon(android.R.drawable.ic_menu_add); return true; } @@ -151,7 +157,7 @@ public class EditKeyActivity extends BaseActivity implements OnClickListener { if (havePassPhrase()) { alert.setTitle(R.string.title_changePassPhrase); } else { - alert.setTitle(R.string.title_setPassPhrase); + alert.setTitle(R.string.title_setCachedPassPhrase); } alert.setMessage(R.string.enterPassPhraseTwice); @@ -227,7 +233,7 @@ public class EditKeyActivity extends BaseActivity implements OnClickListener { Message msg = new Message(); try { - String oldPassPhrase = Apg.getPassPhrase(); + String oldPassPhrase = Apg.getCachedPassPhrase(getMasterKeyId()); String newPassPhrase = mNewPassPhrase; if (newPassPhrase == null) { newPassPhrase = oldPassPhrase; diff --git a/src/org/thialfihar/android/apg/EncryptActivity.java b/src/org/thialfihar/android/apg/EncryptActivity.java index 2b89803b4..18273d5d7 100644 --- a/src/org/thialfihar/android/apg/EncryptActivity.java +++ b/src/org/thialfihar/android/apg/EncryptActivity.java @@ -235,8 +235,7 @@ public class EncryptActivity extends BaseActivity { if (checkBox.isChecked()) { selectSecretKey(); } else { - setSecretKeyId(0); - Apg.setPassPhrase(null); + setSecretKeyId(Id.key.none); updateView(); } } @@ -447,7 +446,7 @@ public class EncryptActivity extends BaseActivity { return; } - if (getSecretKeyId() != 0 && Apg.getPassPhrase() == null) { + if (getSecretKeyId() != 0 && Apg.getCachedPassPhrase(getSecretKeyId()) == null) { showDialog(Id.dialog.pass_phrase); return; } @@ -465,8 +464,8 @@ public class EncryptActivity extends BaseActivity { } @Override - public void passPhraseCallback(String passPhrase) { - super.passPhraseCallback(passPhrase); + public void passPhraseCallback(long keyId, String passPhrase) { + super.passPhraseCallback(keyId, passPhrase); if (mEncryptTarget == Id.target.file) { askForOutputFilename(); } else { @@ -544,11 +543,12 @@ public class EncryptActivity extends BaseActivity { if (signOnly) { Apg.signText(this, in, out, getSecretKeyId(), - Apg.getPassPhrase(), getDefaultHashAlgorithm(), this); + Apg.getCachedPassPhrase(getSecretKeyId()), + getDefaultHashAlgorithm(), this); } else { Apg.encrypt(this, in, out, size, useAsciiArmour, encryptionKeyIds, signatureKeyId, - Apg.getPassPhrase(), this, + Apg.getCachedPassPhrase(signatureKeyId), this, getDefaultEncryptionAlgorithm(), getDefaultHashAlgorithm(), passPhrase); } diff --git a/src/org/thialfihar/android/apg/Id.java b/src/org/thialfihar/android/apg/Id.java index e208cdfcc..d869c810a 100644 --- a/src/org/thialfihar/android/apg/Id.java +++ b/src/org/thialfihar/android/apg/Id.java @@ -112,4 +112,9 @@ public final class Id { public static final int file = 0x21070003; public static final int message = 0x21070004; } + + public static final class key { + public static final int none = 0; + public static final int symmetric = -1; + } } diff --git a/src/org/thialfihar/android/apg/SecretKeyListActivity.java b/src/org/thialfihar/android/apg/SecretKeyListActivity.java index a3661c7cb..7b1ef4334 100644 --- a/src/org/thialfihar/android/apg/SecretKeyListActivity.java +++ b/src/org/thialfihar/android/apg/SecretKeyListActivity.java @@ -264,8 +264,8 @@ public class SecretKeyListActivity extends BaseActivity implements OnChildClickL } @Override - public void passPhraseCallback(String passPhrase) { - super.passPhraseCallback(passPhrase); + public void passPhraseCallback(long keyId, String passPhrase) { + super.passPhraseCallback(keyId, passPhrase); editKey(); } diff --git a/src/org/thialfihar/android/apg/ui/widget/SectionView.java b/src/org/thialfihar/android/apg/ui/widget/SectionView.java index b2db2c88b..cc1410c26 100644 --- a/src/org/thialfihar/android/apg/ui/widget/SectionView.java +++ b/src/org/thialfihar/android/apg/ui/widget/SectionView.java @@ -298,12 +298,17 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor String error = null; try { PGPSecretKey masterKey = null; + String passPhrase; if (mEditors.getChildCount() > 0) { masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue(); + passPhrase = Apg.getCachedPassPhrase(masterKey.getKeyID()); + } else { + passPhrase = ""; } mNewKey = Apg.createKey(getContext(), mNewKeyAlgorithmChoice.getId(), - mNewKeySize, Apg.getPassPhrase(), masterKey); + mNewKeySize, passPhrase, + masterKey); } catch (NoSuchProviderException e) { error = e.getMessage(); } catch (NoSuchAlgorithmException e) {