private keys without master keys and some fixes for things which broke along the way

This commit is contained in:
Ash Hughes 2013-03-14 03:23:50 +00:00
parent 99122fa8d9
commit 115d34ba0e
3 changed files with 95 additions and 35 deletions

View File

@ -24,12 +24,16 @@ import java.util.Locale;
import java.util.Vector; import java.util.Vector;
import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureSubpacketVector; import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.spongycastle.openpgp.PGPException;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.IterableIterator;
@ -76,6 +80,22 @@ public class PgpHelper {
return null; return null;
} }
@SuppressWarnings("unchecked")
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;
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Vector<PGPPublicKey> getEncryptKeys(PGPPublicKeyRing keyRing) { public static Vector<PGPPublicKey> getEncryptKeys(PGPPublicKeyRing keyRing) {
Vector<PGPPublicKey> encryptKeys = new Vector<PGPPublicKey>(); Vector<PGPPublicKey> encryptKeys = new Vector<PGPPublicKey>();
@ -144,7 +164,17 @@ public class PgpHelper {
for (int i = 0; i < signingKeys.size(); ++i) { for (int i = 0; i < signingKeys.size(); ++i) {
PGPSecretKey key = signingKeys.get(i); PGPSecretKey key = signingKeys.get(i);
if (key.isMasterKey()) { if (key.isMasterKey()) {
masterKey = key; try {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
.setProvider(PgpMain.BOUNCY_CASTLE_PROVIDER_NAME).build(new char[] {});
PGPPrivateKey testKey = key.extractPrivateKey(
keyDecryptor);
if (testKey != null) {
masterKey = key;
}
} catch (PGPException e) {
// all good if this fails, we likely didn't use the right password
}
} else { } else {
usableKeys.add(key); usableKeys.add(key);
} }

View File

@ -84,6 +84,7 @@ import org.sufficientlysecure.keychain.util.PositionAwareInputStream;
import org.sufficientlysecure.keychain.util.Primes; import org.sufficientlysecure.keychain.util.Primes;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException; import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import android.content.Context; import android.content.Context;
@ -483,25 +484,28 @@ public class PgpMain {
* @param keyring * @param keyring
* @return * @return
*/ */
@SuppressWarnings("unchecked")
public static int storeKeyRingInCache(Context context, PGPKeyRing keyring) { public static int storeKeyRingInCache(Context context, PGPKeyRing keyring) {
int status = Integer.MIN_VALUE; // out of bounds value (Id.return_value.*) int status = Integer.MIN_VALUE; // out of bounds value (Id.return_value.*)
try { try {
if (keyring instanceof PGPSecretKeyRing) { if (keyring instanceof PGPSecretKeyRing) {
PGPSecretKeyRing secretKeyRing = (PGPSecretKeyRing) keyring; PGPSecretKeyRing secretKeyRing = (PGPSecretKeyRing) keyring;
boolean save = true; boolean save = true;
try {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() for (PGPSecretKey testSecretKey : new IterableIterator<PGPSecretKey>(secretKeyRing.getSecretKeys())) {
.setProvider(BOUNCY_CASTLE_PROVIDER_NAME).build(new char[] {}); try {
PGPPrivateKey testKey = secretKeyRing.getSecretKey().extractPrivateKey( PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
keyDecryptor); .setProvider(BOUNCY_CASTLE_PROVIDER_NAME).build(new char[] {});
if (testKey == null) { PGPPrivateKey testKey = testSecretKey.extractPrivateKey(
// this is bad, something is very wrong... likely a --export-secret-subkeys keyDecryptor);
// export if (testKey == null && !testSecretKey.isMasterKey()) {
save = false; // this is bad, something is very wrong...
status = Id.return_value.bad; save = false;
status = Id.return_value.bad;
}
} catch (PGPException e) {
// all good if this fails, we likely didn't use the right password
} }
} catch (PGPException e) {
// all good if this fails, we likely didn't use the right password
} }
if (save) { if (save) {

View File

@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.ui.dialog;
import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPPrivateKey; import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; 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;
@ -63,6 +64,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
private Messenger mMessenger; private Messenger mMessenger;
private EditText mPassphraseEditText; private EditText mPassphraseEditText;
private boolean canKB;
/** /**
* Creates new instance of this dialog fragment * Creates new instance of this dialog fragment
@ -137,8 +139,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
final Activity activity = getActivity(); final Activity activity = getActivity();
final long secretKeyId = getArguments().getLong(ARG_SECRET_KEY_ID);
long secretKeyId = getArguments().getLong(ARG_SECRET_KEY_ID);
mMessenger = getArguments().getParcelable(ARG_MESSENGER); mMessenger = getArguments().getParcelable(ARG_MESSENGER);
AlertDialog.Builder alert = new AlertDialog.Builder(activity); AlertDialog.Builder alert = new AlertDialog.Builder(activity);
@ -152,8 +153,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
alert.setMessage(R.string.passPhraseForSymmetricEncryption); alert.setMessage(R.string.passPhraseForSymmetricEncryption);
} else { } else {
// TODO: by master key id??? // TODO: by master key id???
secretKey = PgpHelper.getMasterKey(ProviderHelper.getPGPSecretKeyRingByMasterKeyId( secretKey = PgpHelper.getMasterKey(ProviderHelper.getPGPSecretKeyRingByKeyId(activity, secretKeyId));
activity, secretKeyId));
// secretKey = PGPHelper.getMasterKey(PGPMain.getSecretKeyRing(secretKeyId)); // secretKey = PGPHelper.getMasterKey(PGPMain.getSecretKeyRing(secretKeyId));
if (secretKey == null) { if (secretKey == null) {
@ -165,6 +165,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
} }
}); });
alert.setCancelable(false); alert.setCancelable(false);
canKB = false;
return alert.create(); return alert.create();
} }
String userId = PgpHelper.getMainUserIdSafe(activity, secretKey); String userId = PgpHelper.getMainUserIdSafe(activity, secretKey);
@ -184,24 +185,43 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
@Override @Override
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
dismiss(); dismiss();
long curKeyIndex = 0;
boolean keyOK = true;
String passPhrase = mPassphraseEditText.getText().toString(); String passPhrase = mPassphraseEditText.getText().toString();
long keyId; long keyId;
if (secretKey != null) { PGPSecretKey clickSecretKey = secretKey;
try {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() if (clickSecretKey != null) {
.setProvider(PgpMain.BOUNCY_CASTLE_PROVIDER_NAME).build( while (keyOK == true) {
passPhrase.toCharArray()); if (clickSecretKey != null) { //check again for loop
PGPPrivateKey testKey = secretKey.extractPrivateKey(keyDecryptor); try {
if (testKey == null) { PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
.setProvider(PgpMain.BOUNCY_CASTLE_PROVIDER_NAME).build(
passPhrase.toCharArray());
PGPPrivateKey testKey = clickSecretKey.extractPrivateKey(keyDecryptor);
if (testKey == null) {
if (!clickSecretKey.isMasterKey()) {
Toast.makeText(activity, R.string.error_couldNotExtractPrivateKey,
Toast.LENGTH_SHORT).show();
return;
} else {
clickSecretKey = PgpHelper.getKeyNum(ProviderHelper.getPGPSecretKeyRingByKeyId(activity, secretKeyId), curKeyIndex);
curKeyIndex++; //does post-increment work like C?
continue;
}
} else {
keyOK = false;
}
} catch (PGPException e) {
Toast.makeText(activity, R.string.wrongPassPhrase, Toast.LENGTH_SHORT)
.show();
return;
}
} else {
Toast.makeText(activity, R.string.error_couldNotExtractPrivateKey, Toast.makeText(activity, R.string.error_couldNotExtractPrivateKey,
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
return; return; //ran out of keys to try
} }
} catch (PGPException e) {
Toast.makeText(activity, R.string.wrongPassPhrase, Toast.LENGTH_SHORT)
.show();
return;
} }
keyId = secretKey.getKeyID(); keyId = secretKey.getKeyID();
} else { } else {
@ -211,6 +231,9 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
// cache the new passphrase // cache the new passphrase
Log.d(Constants.TAG, "Everything okay! Caching entered passphrase"); Log.d(Constants.TAG, "Everything okay! Caching entered passphrase");
PassphraseCacheService.addCachedPassphrase(activity, keyId, passPhrase); PassphraseCacheService.addCachedPassphrase(activity, keyId, passPhrase);
if (keyOK == false) {
PassphraseCacheService.addCachedPassphrase(activity, clickSecretKey.getKeyID(), passPhrase);
}
sendMessageToHandler(MESSAGE_OKAY); sendMessageToHandler(MESSAGE_OKAY);
} }
@ -224,18 +247,20 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
} }
}); });
canKB = true;
return alert.create(); return alert.create();
} }
@Override @Override
public void onActivityCreated(Bundle arg0) { public void onActivityCreated(Bundle arg0) {
super.onActivityCreated(arg0); super.onActivityCreated(arg0);
if (canKB) {
// request focus and open soft keyboard // request focus and open soft keyboard
mPassphraseEditText.requestFocus(); mPassphraseEditText.requestFocus();
getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE); getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
mPassphraseEditText.setOnEditorActionListener(this); mPassphraseEditText.setOnEditorActionListener(this);
}
} }
/** /**
@ -273,3 +298,4 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
} }
} }