mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-12-25 00:18:51 -05:00
cache key s2k type in database, for later use
This commit is contained in:
parent
a97ebc1ec9
commit
e0905a3afb
@ -80,6 +80,59 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
|
||||
return (CanonicalizedSecretKeyRing) mRing;
|
||||
}
|
||||
|
||||
public enum SecretKeyType {
|
||||
UNAVAILABLE(0), GNU_DUMMY (1), PASSPHRASE (2), PASSPHRASE_EMPTY (3), DIVERT_TO_CARD (4);
|
||||
|
||||
final int mNum;
|
||||
SecretKeyType(int num) {
|
||||
mNum = num;
|
||||
}
|
||||
|
||||
public static SecretKeyType fromNum(int num) {
|
||||
switch (num) {
|
||||
case 1: return GNU_DUMMY;
|
||||
case 2: return PASSPHRASE;
|
||||
case 3: return PASSPHRASE_EMPTY;
|
||||
case 4: return DIVERT_TO_CARD;
|
||||
// if this case happens, it's probably a check from a database value
|
||||
default: return UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
public int getNum() {
|
||||
return mNum;
|
||||
}
|
||||
|
||||
public boolean isUsable() {
|
||||
return this != UNAVAILABLE && this != GNU_DUMMY;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public SecretKeyType getSecretKeyType() {
|
||||
if (mSecretKey.getS2K().getType() == S2K.GNU_DUMMY_S2K) {
|
||||
// divert to card is special
|
||||
if (mSecretKey.getS2K().getProtectionMode() == S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD) {
|
||||
return SecretKeyType.DIVERT_TO_CARD;
|
||||
}
|
||||
// no matter the exact protection mode, it's some kind of dummy key
|
||||
return SecretKeyType.GNU_DUMMY;
|
||||
}
|
||||
|
||||
try {
|
||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
|
||||
// If this doesn't throw
|
||||
mSecretKey.extractPrivateKey(keyDecryptor);
|
||||
// It means the passphrase is empty
|
||||
return SecretKeyType.PASSPHRASE_EMPTY;
|
||||
} catch (PGPException e) {
|
||||
// Otherwise, it's just a regular ol' passphrase
|
||||
return SecretKeyType.PASSPHRASE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true on right passphrase
|
||||
*/
|
||||
|
@ -74,19 +74,6 @@ public class CanonicalizedSecretKeyRing extends CanonicalizedKeyRing {
|
||||
return new CanonicalizedSecretKey(this, mRing.getSecretKey(id));
|
||||
}
|
||||
|
||||
public HashSet<Long> getAvailableSubkeys() {
|
||||
HashSet<Long> result = new HashSet<Long>();
|
||||
// then, mark exactly the keys we have available
|
||||
for (PGPSecretKey sub : new IterableIterator<PGPSecretKey>(getRing().getSecretKeys())) {
|
||||
S2K s2k = sub.getS2K();
|
||||
// add key, except if the private key has been stripped (GNU extension)
|
||||
if(s2k == null || (s2k.getProtectionMode() != S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY)) {
|
||||
result.add(sub.getKeyID());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Getter that returns the subkey that should be used for signing. */
|
||||
CanonicalizedSecretKey getSigningSubKey() throws PgpGeneralException {
|
||||
PGPSecretKey key = mRing.getSecretKey(getSignId());
|
||||
|
@ -34,6 +34,8 @@ import org.sufficientlysecure.keychain.helper.Preferences;
|
||||
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||
@ -592,27 +594,40 @@ public class ProviderHelper {
|
||||
values.put(Keys.HAS_SECRET, 0);
|
||||
mContentResolver.update(uri, values, null, null);
|
||||
|
||||
values.put(Keys.HAS_SECRET, 1);
|
||||
// then, mark exactly the keys we have available
|
||||
log(LogLevel.INFO, LogType.MSG_IS_IMPORTING_SUBKEYS);
|
||||
mIndent += 1;
|
||||
Set<Long> available = keyRing.getAvailableSubkeys();
|
||||
for (UncachedPublicKey sub : keyRing.publicKeyIterator()) {
|
||||
for (CanonicalizedSecretKey sub : keyRing.secretKeyIterator()) {
|
||||
long id = sub.getKeyId();
|
||||
if (available.contains(id)) {
|
||||
SecretKeyType mode = sub.getSecretKeyType();
|
||||
values.put(Keys.HAS_SECRET, mode.getNum());
|
||||
int upd = mContentResolver.update(uri, values, Keys.KEY_ID + " = ?",
|
||||
new String[]{ Long.toString(id) });
|
||||
if (upd == 1) {
|
||||
switch (mode) {
|
||||
case PASSPHRASE:
|
||||
log(LogLevel.DEBUG, LogType.MSG_IS_SUBKEY_OK,
|
||||
PgpKeyHelper.convertKeyIdToHex(id)
|
||||
);
|
||||
} else {
|
||||
log(LogLevel.WARN, LogType.MSG_IS_SUBKEY_NONEXISTENT,
|
||||
break;
|
||||
case PASSPHRASE_EMPTY:
|
||||
log(LogLevel.DEBUG, LogType.MSG_IS_SUBKEY_EMPTY,
|
||||
PgpKeyHelper.convertKeyIdToHex(id)
|
||||
);
|
||||
break;
|
||||
case GNU_DUMMY:
|
||||
log(LogLevel.DEBUG, LogType.MSG_IS_SUBKEY_STRIPPED,
|
||||
PgpKeyHelper.convertKeyIdToHex(id)
|
||||
);
|
||||
break;
|
||||
case DIVERT_TO_CARD:
|
||||
log(LogLevel.DEBUG, LogType.MSG_IS_SUBKEY_DIVERT,
|
||||
PgpKeyHelper.convertKeyIdToHex(id)
|
||||
);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
log(LogLevel.INFO, LogType.MSG_IS_SUBKEY_STRIPPED,
|
||||
log(LogLevel.WARN, LogType.MSG_IS_SUBKEY_NONEXISTENT,
|
||||
PgpKeyHelper.convertKeyIdToHex(id)
|
||||
);
|
||||
}
|
||||
|
@ -287,6 +287,8 @@ public class OperationResultParcel implements Parcelable {
|
||||
MSG_IS_SUBKEY_NONEXISTENT (R.string.msg_is_subkey_nonexistent),
|
||||
MSG_IS_SUBKEY_OK (R.string.msg_is_subkey_ok),
|
||||
MSG_IS_SUBKEY_STRIPPED (R.string.msg_is_subkey_stripped),
|
||||
MSG_IS_SUBKEY_DIVERT (R.string.msg_is_subkey_divert),
|
||||
MSG_IS_SUBKEY_EMPTY (R.string.msg_is_subkey_empty),
|
||||
MSG_IS_SUCCESS_IDENTICAL (R.string.msg_is_success_identical),
|
||||
MSG_IS_SUCCESS (R.string.msg_is_success),
|
||||
|
||||
|
@ -32,6 +32,7 @@ import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ListView;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter;
|
||||
|
||||
@ -190,7 +191,7 @@ public class SelectSecretKeyFragment extends ListFragment implements
|
||||
if(mFilterCertify) {
|
||||
// Only enable if can certify
|
||||
if (cursor.getInt(mIndexCanCertify) == 0
|
||||
|| cursor.getInt(mIndexHasSecret) == 0) {
|
||||
|| !SecretKeyType.fromNum(cursor.getInt(mIndexHasSecret)).isUsable()) {
|
||||
h.status.setText(R.string.can_certify_not);
|
||||
} else {
|
||||
h.status.setText(R.string.can_certify);
|
||||
|
@ -300,7 +300,7 @@ public class ViewKeyActivity extends ActionBarActivity implements
|
||||
|
||||
exportHelper.showExportKeysDialog(
|
||||
new long[]{(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)},
|
||||
Constants.Path.APP_DIR_FILE, ((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) == 1)
|
||||
Constants.Path.APP_DIR_FILE, ((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) != 0)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.helper.OtherHelper;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||
@ -113,7 +114,8 @@ public class SubkeysAdapter extends CursorAdapter {
|
||||
hasAnySecret = false;
|
||||
if (newCursor != null && newCursor.moveToFirst()) {
|
||||
do {
|
||||
if (newCursor.getInt(INDEX_HAS_SECRET) != 0) {
|
||||
SecretKeyType hasSecret = SecretKeyType.fromNum(newCursor.getInt(INDEX_HAS_SECRET));
|
||||
if (hasSecret.isUsable()) {
|
||||
hasAnySecret = true;
|
||||
break;
|
||||
}
|
||||
@ -149,12 +151,21 @@ public class SubkeysAdapter extends CursorAdapter {
|
||||
|
||||
vKeyId.setText(keyIdStr);
|
||||
// may be set with additional "stripped" later on
|
||||
if (hasAnySecret && cursor.getInt(INDEX_HAS_SECRET) == 0) {
|
||||
vKeyDetails.setText(algorithmStr + ", " +
|
||||
context.getString(R.string.key_stripped));
|
||||
} else {
|
||||
vKeyDetails.setText(algorithmStr);
|
||||
switch (SecretKeyType.fromNum(cursor.getInt(INDEX_HAS_SECRET))) {
|
||||
case GNU_DUMMY:
|
||||
algorithmStr += ", " + context.getString(R.string.key_stripped);
|
||||
break;
|
||||
case DIVERT_TO_CARD:
|
||||
algorithmStr += ", " + context.getString(R.string.key_divert);
|
||||
break;
|
||||
case PASSPHRASE_EMPTY:
|
||||
algorithmStr += ", " + context.getString(R.string.key_no_passphrase);
|
||||
break;
|
||||
case UNAVAILABLE:
|
||||
algorithmStr += ", " + context.getString(R.string.key_unavailable);
|
||||
break;
|
||||
}
|
||||
vKeyDetails.setText(algorithmStr);
|
||||
|
||||
boolean isMasterKey = cursor.getInt(INDEX_RANK) == 0;
|
||||
if (isMasterKey) {
|
||||
|
@ -589,9 +589,11 @@
|
||||
<string name="msg_is_importing_subkeys">Processing secret subkeys</string>
|
||||
<string name="msg_is_io_exc">Error encoding keyring</string>
|
||||
<string name="msg_is_pubring_generate">Generating public keyring from secret keyring</string>
|
||||
<string name="msg_is_subkey_nonexistent">Subkey %s unavailable in public key</string>
|
||||
<string name="msg_is_subkey_ok">Marked %s as available</string>
|
||||
<string name="msg_is_subkey_stripped">Marked %s as stripped</string>
|
||||
<string name="msg_is_subkey_nonexistent">Subkey %s unavailable in secret key</string>
|
||||
<string name="msg_is_subkey_ok">Marked secret subkey %s as available</string>
|
||||
<string name="msg_is_subkey_empty">Marked secret subkey %s as available, with empty passphrase</string>
|
||||
<string name="msg_is_subkey_stripped">Marked secret subkey %s as stripped</string>
|
||||
<string name="msg_is_subkey_divert">Marked secret subkey %s as "divert to smartcard/nfc"</string>
|
||||
<string name="msg_is_success_identical">Keyring contains no new data, nothing to do</string>
|
||||
<string name="msg_is_success">Successfully imported secret keyring</string>
|
||||
|
||||
@ -765,6 +767,9 @@
|
||||
<string name="error_key_not_found">Key not found!</string>
|
||||
<string name="error_key_processing">Error processing key!</string>
|
||||
<string name="key_stripped">stripped</string>
|
||||
<string name="key_divert">divert to card</string>
|
||||
<string name="key_no_passphrase">no passphrase</string>
|
||||
<string name="key_unavailable">unavailable</string>
|
||||
<string name="secret_cannot_multiple">Your own keys can only be deleted individually!</string>
|
||||
<string name="title_view_cert">View Certificate Details</string>
|
||||
<string name="unknown_algorithm">unknown</string>
|
||||
|
Loading…
Reference in New Issue
Block a user