password cache introduced, not cleared yet.

This commit is contained in:
Thialfihar 2010-05-15 15:19:56 +00:00
parent cab78bf4c1
commit 363dcb62b8
10 changed files with 129 additions and 49 deletions

View File

@ -155,7 +155,8 @@ public class Apg {
PublicKeys.KEY_DATA, PublicKeys.KEY_DATA,
PublicKeys.WHO_ID, }; PublicKeys.WHO_ID, };
private static String mPassPhrase = null; private static HashMap<Long, CachedPassPhrase> mPassPhraseCache =
new HashMap<Long, CachedPassPhrase>();
public static class GeneralException extends Exception { public static class GeneralException extends Exception {
static final long serialVersionUID = 0xf812773342L; static final long serialVersionUID = 0xf812773342L;
@ -271,12 +272,28 @@ public class Apg {
} }
} }
public static void setPassPhrase(String passPhrase) { public static void setCachedPassPhrase(long keyId, String passPhrase) {
mPassPhrase = passPhrase; mPassPhraseCache.put(keyId, new CachedPassPhrase(new Date().getTime(), passPhrase));
} }
public static String getPassPhrase() { public static String getCachedPassPhrase(long keyId) {
return mPassPhrase; 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, public static PGPSecretKey createKey(Context context,
@ -1440,7 +1457,7 @@ public class Apg {
} }
if (secretKey == null) { if (secretKey == null) {
return 0; return Id.key.none;
} }
return secretKey.getKeyID(); return secretKey.getKeyID();

View File

@ -32,7 +32,7 @@ import android.widget.Toast;
public class AskForSecretKeyPassPhrase { public class AskForSecretKeyPassPhrase {
public static interface PassPhraseCallbackInterface { public static interface PassPhraseCallbackInterface {
void passPhraseCallback(String passPhrase); void passPhraseCallback(long keyId, String passPhrase);
} }
public static Dialog createDialog(Activity context, long secretKeyId, public static Dialog createDialog(Activity context, long secretKeyId,
@ -43,7 +43,7 @@ public class AskForSecretKeyPassPhrase {
final PGPSecretKey secretKey; final PGPSecretKey secretKey;
if (secretKeyId == 0) { if (secretKeyId == Id.key.symmetric || secretKeyId == Id.key.none) {
secretKey = null; secretKey = null;
alert.setMessage(context.getString(R.string.passPhraseForSymmetricEncryption)); alert.setMessage(context.getString(R.string.passPhraseForSymmetricEncryption));
} else { } else {
@ -71,6 +71,7 @@ public class AskForSecretKeyPassPhrase {
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
activity.removeDialog(Id.dialog.pass_phrase); activity.removeDialog(Id.dialog.pass_phrase);
String passPhrase = "" + input.getText(); String passPhrase = "" + input.getText();
long keyId;
if (secretKey != null) { if (secretKey != null) {
try { try {
secretKey.extractPrivateKey(passPhrase.toCharArray(), secretKey.extractPrivateKey(passPhrase.toCharArray(),
@ -81,8 +82,11 @@ public class AskForSecretKeyPassPhrase {
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
return; return;
} }
keyId = secretKey.getKeyID();
} else {
keyId = Id.key.symmetric;
} }
cb.passPhraseCallback(passPhrase); cb.passPhraseCallback(keyId, passPhrase);
} }
}); });

View File

@ -192,14 +192,9 @@ public class BaseActivity extends Activity
case Id.request.secret_keys: { case Id.request.secret_keys: {
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
Bundle bundle = data.getExtras(); Bundle bundle = data.getExtras();
long newId = bundle.getLong("selectedKeyId"); setSecretKeyId(bundle.getLong("selectedKeyId"));
if (getSecretKeyId() != newId) {
Apg.setPassPhrase(null);
}
setSecretKeyId(newId);
} else { } else {
setSecretKeyId(0); setSecretKeyId(Id.key.none);
Apg.setPassPhrase(null);
} }
break; break;
} }
@ -271,8 +266,8 @@ public class BaseActivity extends Activity
} }
public void passPhraseCallback(String passPhrase) { public void passPhraseCallback(long keyId, String passPhrase) {
Apg.setPassPhrase(passPhrase); Apg.setCachedPassPhrase(keyId, passPhrase);
} }
public void sendMessage(Message msg) { public void sendMessage(Message msg) {

View File

@ -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 + ", *******)";
}
}

View File

@ -351,18 +351,18 @@ public class DecryptActivity extends BaseActivity {
} }
try { try {
setSecretKeyId(Apg.getDecryptionKeyId(this, in)); setSecretKeyId(Apg.getDecryptionKeyId(this, in));
if (getSecretKeyId() == 0) { if (getSecretKeyId() == Id.key.none) {
throw new Apg.GeneralException(getString(R.string.error_noSecretKeyFound)); throw new Apg.GeneralException(getString(R.string.error_noSecretKeyFound));
} }
mAssumeSymmetricEncryption = false; mAssumeSymmetricEncryption = false;
} catch (Apg.NoAsymmetricEncryptionException e) { } catch (Apg.NoAsymmetricEncryptionException e) {
setSecretKeyId(0); setSecretKeyId(Id.key.symmetric);
// reopen the file/message to check whether there's // look at the file/message again to check whether there's
// symmetric encryption data in there // symmetric encryption data in there
if (mDecryptTarget == Id.target.file) { if (mDecryptTarget == Id.target.file) {
in = new FileInputStream(mInputFilename); ((FileInputStream) in).reset();
} else { } else {
in = new ByteArrayInputStream(mMessage.getText().toString().getBytes()); ((ByteArrayInputStream) in).reset();
} }
if (!Apg.hasSymmetricEncryption(this, in)) { if (!Apg.hasSymmetricEncryption(this, in)) {
throw new Apg.GeneralException(getString(R.string.error_noKnownEncryptionFound)); throw new Apg.GeneralException(getString(R.string.error_noKnownEncryptionFound));
@ -370,7 +370,16 @@ public class DecryptActivity extends BaseActivity {
mAssumeSymmetricEncryption = true; mAssumeSymmetricEncryption = true;
} }
if (getSecretKeyId() == Id.key.symmetric ||
Apg.getCachedPassPhrase(getSecretKeyId()) == null) {
showDialog(Id.dialog.pass_phrase); showDialog(Id.dialog.pass_phrase);
} else {
if (mDecryptTarget == Id.target.file) {
askForOutputFilename();
} else {
decryptStart();
}
}
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
error = getString(R.string.error_fileNotFound); error = getString(R.string.error_fileNotFound);
} catch (IOException e) { } catch (IOException e) {
@ -404,8 +413,8 @@ public class DecryptActivity extends BaseActivity {
} }
@Override @Override
public void passPhraseCallback(String passPhrase) { public void passPhraseCallback(long keyId, String passPhrase) {
super.passPhraseCallback(passPhrase); super.passPhraseCallback(keyId, passPhrase);
if (mDecryptTarget == Id.target.file) { if (mDecryptTarget == Id.target.file) {
askForOutputFilename(); askForOutputFilename();
} else { } else {
@ -441,7 +450,7 @@ public class DecryptActivity extends BaseActivity {
if (mSignedOnly) { if (mSignedOnly) {
data = Apg.verifyText(this, in, out, this); data = Apg.verifyText(this, in, out, this);
} else { } else {
data = Apg.decrypt(this, in, out, Apg.getPassPhrase(), data = Apg.decrypt(this, in, out, Apg.getCachedPassPhrase(getSecretKeyId()),
this, mAssumeSymmetricEncryption); this, mAssumeSymmetricEncryption);
} }

View File

@ -24,6 +24,7 @@ import java.util.Vector;
import org.bouncycastle2.openpgp.PGPException; import org.bouncycastle2.openpgp.PGPException;
import org.bouncycastle2.openpgp.PGPSecretKey; import org.bouncycastle2.openpgp.PGPSecretKey;
import org.bouncycastle2.openpgp.PGPSecretKeyRing; 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.ui.widget.SectionView;
import org.thialfihar.android.apg.utils.IterableIterator; import org.thialfihar.android.apg.utils.IterableIterator;
@ -70,9 +71,7 @@ public class EditKeyActivity extends BaseActivity implements OnClickListener {
keyId = intent.getExtras().getLong("keyId"); keyId = intent.getExtras().getLong("keyId");
} }
if (keyId == 0) { if (keyId != 0) {
Apg.setPassPhrase(null);
} else {
PGPSecretKey masterKey = null; PGPSecretKey masterKey = null;
mKeyRing = Apg.getSecretKeyRing(keyId); mKeyRing = Apg.getSecretKeyRing(keyId);
if (mKeyRing != null) { 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); mSaveButton = (Button) findViewById(R.id.btn_save);
mDiscardButton = (Button) findViewById(R.id.btn_discard); 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(); 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() { 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("")); (mNewPassPhrase != null && !mNewPassPhrase.equals(""));
} }
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, Id.menu.option.new_pass_phrase, 0, 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); .setIcon(android.R.drawable.ic_menu_add);
return true; return true;
} }
@ -151,7 +157,7 @@ public class EditKeyActivity extends BaseActivity implements OnClickListener {
if (havePassPhrase()) { if (havePassPhrase()) {
alert.setTitle(R.string.title_changePassPhrase); alert.setTitle(R.string.title_changePassPhrase);
} else { } else {
alert.setTitle(R.string.title_setPassPhrase); alert.setTitle(R.string.title_setCachedPassPhrase);
} }
alert.setMessage(R.string.enterPassPhraseTwice); alert.setMessage(R.string.enterPassPhraseTwice);
@ -227,7 +233,7 @@ public class EditKeyActivity extends BaseActivity implements OnClickListener {
Message msg = new Message(); Message msg = new Message();
try { try {
String oldPassPhrase = Apg.getPassPhrase(); String oldPassPhrase = Apg.getCachedPassPhrase(getMasterKeyId());
String newPassPhrase = mNewPassPhrase; String newPassPhrase = mNewPassPhrase;
if (newPassPhrase == null) { if (newPassPhrase == null) {
newPassPhrase = oldPassPhrase; newPassPhrase = oldPassPhrase;

View File

@ -235,8 +235,7 @@ public class EncryptActivity extends BaseActivity {
if (checkBox.isChecked()) { if (checkBox.isChecked()) {
selectSecretKey(); selectSecretKey();
} else { } else {
setSecretKeyId(0); setSecretKeyId(Id.key.none);
Apg.setPassPhrase(null);
updateView(); updateView();
} }
} }
@ -447,7 +446,7 @@ public class EncryptActivity extends BaseActivity {
return; return;
} }
if (getSecretKeyId() != 0 && Apg.getPassPhrase() == null) { if (getSecretKeyId() != 0 && Apg.getCachedPassPhrase(getSecretKeyId()) == null) {
showDialog(Id.dialog.pass_phrase); showDialog(Id.dialog.pass_phrase);
return; return;
} }
@ -465,8 +464,8 @@ public class EncryptActivity extends BaseActivity {
} }
@Override @Override
public void passPhraseCallback(String passPhrase) { public void passPhraseCallback(long keyId, String passPhrase) {
super.passPhraseCallback(passPhrase); super.passPhraseCallback(keyId, passPhrase);
if (mEncryptTarget == Id.target.file) { if (mEncryptTarget == Id.target.file) {
askForOutputFilename(); askForOutputFilename();
} else { } else {
@ -544,11 +543,12 @@ public class EncryptActivity extends BaseActivity {
if (signOnly) { if (signOnly) {
Apg.signText(this, in, out, getSecretKeyId(), Apg.signText(this, in, out, getSecretKeyId(),
Apg.getPassPhrase(), getDefaultHashAlgorithm(), this); Apg.getCachedPassPhrase(getSecretKeyId()),
getDefaultHashAlgorithm(), this);
} else { } else {
Apg.encrypt(this, in, out, size, useAsciiArmour, Apg.encrypt(this, in, out, size, useAsciiArmour,
encryptionKeyIds, signatureKeyId, encryptionKeyIds, signatureKeyId,
Apg.getPassPhrase(), this, Apg.getCachedPassPhrase(signatureKeyId), this,
getDefaultEncryptionAlgorithm(), getDefaultHashAlgorithm(), getDefaultEncryptionAlgorithm(), getDefaultHashAlgorithm(),
passPhrase); passPhrase);
} }

View File

@ -112,4 +112,9 @@ public final class Id {
public static final int file = 0x21070003; public static final int file = 0x21070003;
public static final int message = 0x21070004; public static final int message = 0x21070004;
} }
public static final class key {
public static final int none = 0;
public static final int symmetric = -1;
}
} }

View File

@ -264,8 +264,8 @@ public class SecretKeyListActivity extends BaseActivity implements OnChildClickL
} }
@Override @Override
public void passPhraseCallback(String passPhrase) { public void passPhraseCallback(long keyId, String passPhrase) {
super.passPhraseCallback(passPhrase); super.passPhraseCallback(keyId, passPhrase);
editKey(); editKey();
} }

View File

@ -298,12 +298,17 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
String error = null; String error = null;
try { try {
PGPSecretKey masterKey = null; PGPSecretKey masterKey = null;
String passPhrase;
if (mEditors.getChildCount() > 0) { if (mEditors.getChildCount() > 0) {
masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue(); masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue();
passPhrase = Apg.getCachedPassPhrase(masterKey.getKeyID());
} else {
passPhrase = "";
} }
mNewKey = Apg.createKey(getContext(), mNewKey = Apg.createKey(getContext(),
mNewKeyAlgorithmChoice.getId(), mNewKeyAlgorithmChoice.getId(),
mNewKeySize, Apg.getPassPhrase(), masterKey); mNewKeySize, passPhrase,
masterKey);
} catch (NoSuchProviderException e) { } catch (NoSuchProviderException e) {
error = e.getMessage(); error = e.getMessage();
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {