diff --git a/OpenPGP-Keychain/res/layout/edit_key_section.xml b/OpenPGP-Keychain/res/layout/edit_key_section.xml index 870e1b063..dd0a5d4bd 100644 --- a/OpenPGP-Keychain/res/layout/edit_key_section.xml +++ b/OpenPGP-Keychain/res/layout/edit_key_section.xml @@ -41,6 +41,7 @@ android:text="Section Name" /> - \ No newline at end of file + diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpMain.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpMain.java index f4b7c7bbd..27047cd0f 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpMain.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpMain.java @@ -309,6 +309,31 @@ public class PgpMain { return secKeyRing; } + public static void changeSecretKeyPassphrase(Context context, + PGPSecretKeyRing keyRing, String oldPassPhrase, String newPassPhrase, + ProgressDialogUpdater progress) throws IOException, PGPException, PGPException, + NoSuchProviderException { + + updateProgress(progress, R.string.progress_buildingKey, 0, 100); + if (oldPassPhrase == null) { + oldPassPhrase = ""; + } + if (newPassPhrase == null) { + newPassPhrase = ""; + } + + PGPSecretKeyRing newKeyRing = PGPSecretKeyRing.copyWithNewPassword(keyRing, + oldPassPhrase.toCharArray(), newPassPhrase.toCharArray(), keyRing.getSecretKey().getKeyEncryptionAlgorithm(), + new SecureRandom(), BOUNCY_CASTLE_PROVIDER_NAME); + + updateProgress(progress, R.string.progress_savingKeyRing, 50, 100); + + ProviderHelper.saveKeyRing(context, newKeyRing); + + updateProgress(progress, R.string.progress_done, 100, 100); + + } + public static void buildSecretKey(Context context, ArrayList userIds, ArrayList keys, ArrayList keysUsages, long masterKeyId, String oldPassPhrase, String newPassPhrase, ProgressDialogUpdater progress) diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 7190d72c4..2665456ea 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -34,6 +34,7 @@ import org.sufficientlysecure.keychain.helper.PgpMain; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; +import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; @@ -494,6 +495,49 @@ public class ProviderHelper { return getMasterKeyId(context, queryUri, keyRingRowId); } + /** + * Get empty status of master key of keyring by its row id + * + * @param context + * @param keyRingRowId + * @return + */ + public static boolean getSecretMasterKeyCanSign(Context context, long keyRingRowId) { + Uri queryUri = KeyRings.buildSecretKeyRingsUri(String.valueOf(keyRingRowId)); + return getMasterKeyCanSign(context, queryUri, keyRingRowId); + } + + /** + * Private helper method to get master key private empty status of keyring by its row id + * + * @param context + * @param queryUri + * @param keyRingRowId + * @return + */ + private static boolean getMasterKeyCanSign(Context context, Uri queryUri, long keyRingRowId) { + String[] projection = new String[] { KeyRings.MASTER_KEY_ID, "(SELECT COUNT(sign_keys." + + Keys._ID + ") FROM " + Tables.KEYS + " AS sign_keys WHERE sign_keys." + Keys.KEY_RING_ROW_ID + " = " + + KeychainDatabase.Tables.KEY_RINGS + "." + KeyRings._ID + " AND sign_keys." + + Keys.CAN_SIGN + " = '1' AND " + Keys.IS_MASTER_KEY + " = 1) AS sign", }; + + ContentResolver cr = context.getContentResolver(); + Cursor cursor = cr.query(queryUri, projection, null, null, null); + + long masterKeyId = -1; + if (cursor != null && cursor.moveToFirst()) { + int masterKeyIdCol = cursor.getColumnIndex("sign"); + + masterKeyId = cursor.getLong(masterKeyIdCol); + } + + if (cursor != null) { + cursor.close(); + } + + return (masterKeyId > 0); + } + /** * Get master key id of keyring by its row id * diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/KeychainIntentService.java index e525fe96e..48afdff5c 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -123,6 +123,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial public static final String SAVE_KEYRING_KEYS = "keys"; public static final String SAVE_KEYRING_KEYS_USAGES = "keysUsages"; public static final String SAVE_KEYRING_MASTER_KEY_ID = "masterKeyId"; + public static final String SAVE_KEYRING_CAN_SIGN = "can_sign"; // generate key public static final String GENERATE_KEY_ALGORITHM = "algorithm"; @@ -523,6 +524,12 @@ public class KeychainIntentService extends IntentService implements ProgressDial /* Input */ String oldPassPhrase = data.getString(SAVE_KEYRING_CURRENT_PASSPHRASE); String newPassPhrase = data.getString(SAVE_KEYRING_NEW_PASSPHRASE); + boolean canSign = true; + + if (data.containsKey(SAVE_KEYRING_CAN_SIGN)) { + canSign = data.getBoolean(SAVE_KEYRING_CAN_SIGN); + } + if (newPassPhrase == null) { newPassPhrase = oldPassPhrase; } @@ -533,8 +540,13 @@ public class KeychainIntentService extends IntentService implements ProgressDial long masterKeyId = data.getLong(SAVE_KEYRING_MASTER_KEY_ID); /* Operation */ - PgpMain.buildSecretKey(this, userIds, keys, keysUsages, masterKeyId, oldPassPhrase, + if (!canSign) { //library fails, fix later + //PgpMain.changeSecretKeyPassphrase(this, ProviderHelper.getPGPSecretKeyRingByKeyId(this, masterKeyId), + //oldPassPhrase, newPassPhrase, this); + } else { + PgpMain.buildSecretKey(this, userIds, keys, keysUsages, masterKeyId, oldPassPhrase, newPassPhrase, this); + } PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassPhrase); /* Output */ diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 90ee9838e..3d819a824 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -75,6 +75,7 @@ public class EditKeyActivity extends SherlockFragmentActivity { public static final String EXTRA_NO_PASSPHRASE = "noPassphrase"; public static final String EXTRA_GENERATE_DEFAULT_KEYS = "generateDefaultKeys"; public static final String EXTRA_MASTER_KEY_ID = "masterKeyId"; + public static final String EXTRA_MASTER_CAN_SIGN = "masterCanSign"; // results when saving key public static final String RESULT_EXTRA_MASTER_KEY_ID = "masterKeyId"; @@ -97,6 +98,7 @@ public class EditKeyActivity extends SherlockFragmentActivity { Vector mUserIds; Vector mKeys; Vector mKeysUsages; + boolean masterCanSign = true; // will be set to false to build layout later in handler private boolean mBuildLayout = true; @@ -192,6 +194,13 @@ public class EditKeyActivity extends SherlockFragmentActivity { } }); + //disable key passhphrase changing with empty private keys for no + //library fails, fix later + if (!masterCanSign) { + mChangePassPhrase.setEnabled(false); + mNoPassphrase.setEnabled(false); + } + if (mBuildLayout) { buildLayout(); } @@ -317,6 +326,9 @@ public class EditKeyActivity extends SherlockFragmentActivity { } if (extras != null) { + if (extras.containsKey(EXTRA_MASTER_CAN_SIGN)) { + masterCanSign = extras.getBoolean(EXTRA_MASTER_CAN_SIGN); + } if (extras.containsKey(EXTRA_MASTER_KEY_ID)) { long masterKeyId = extras.getLong(EXTRA_MASTER_KEY_ID); @@ -394,10 +406,12 @@ public class EditKeyActivity extends SherlockFragmentActivity { LinearLayout container = (LinearLayout) findViewById(R.id.edit_key_container); mUserIdsView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false); mUserIdsView.setType(Id.type.user_id); + mUserIdsView.setCanEdit(masterCanSign); mUserIdsView.setUserIds(mUserIds); container.addView(mUserIdsView); mKeysView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false); mKeysView.setType(Id.type.key); + mKeysView.setCanEdit(masterCanSign); mKeysView.setKeys(mKeys, mKeysUsages); container.addView(mKeysView); @@ -447,6 +461,7 @@ public class EditKeyActivity extends SherlockFragmentActivity { data.putIntegerArrayList(KeychainIntentService.SAVE_KEYRING_KEYS_USAGES, getKeysUsages(mKeysView)); data.putLong(KeychainIntentService.SAVE_KEYRING_MASTER_KEY_ID, getMasterKeyId()); + data.putBoolean(KeychainIntentService.SAVE_KEYRING_CAN_SIGN, masterCanSign); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java index 0e6cdd6a1..52ce19f97 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java @@ -70,18 +70,19 @@ public class KeyListSecretActivity extends KeyListActivity { } } - public void checkPassPhraseAndEdit(long masterKeyId) { + public void checkPassPhraseAndEdit(long masterKeyId, boolean masterCanSign) { String passPhrase = PassphraseCacheService.getCachedPassphrase(this, masterKeyId); if (passPhrase == null) { - showPassphraseDialog(masterKeyId); + showPassphraseDialog(masterKeyId, masterCanSign); } else { PgpMain.setEditPassPhrase(passPhrase); - editKey(masterKeyId); + editKey(masterKeyId, masterCanSign); } } - private void showPassphraseDialog(final long masterKeyId) { + private void showPassphraseDialog(final long masterKeyId, boolean masterCanSign) { // Message is received after passphrase is cached + final boolean mCanSign = masterCanSign; Handler returnHandler = new Handler() { @Override public void handleMessage(Message message) { @@ -89,7 +90,7 @@ public class KeyListSecretActivity extends KeyListActivity { String passPhrase = PassphraseCacheService.getCachedPassphrase( KeyListSecretActivity.this, masterKeyId); PgpMain.setEditPassPhrase(passPhrase); - editKey(masterKeyId); + editKey(masterKeyId, mCanSign); } } }; @@ -115,9 +116,10 @@ public class KeyListSecretActivity extends KeyListActivity { startActivityForResult(intent, 0); } - private void editKey(long masterKeyId) { + private void editKey(long masterKeyId, boolean masterCanSign) { Intent intent = new Intent(EditKeyActivity.ACTION_EDIT_KEY); intent.putExtra(EditKeyActivity.EXTRA_MASTER_KEY_ID, masterKeyId); + intent.putExtra(EditKeyActivity.EXTRA_MASTER_CAN_SIGN, masterCanSign); startActivityForResult(intent, 0); } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java index f4ba2b4d9..e41755840 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java @@ -91,9 +91,11 @@ public class KeyListSecretFragment extends KeyListFragment implements long masterKeyId = ProviderHelper .getSecretMasterKeyId(mKeyListSecretActivity, keyRingRowId); + boolean masterCanSign = ProviderHelper.getSecretMasterKeyCanSign(mKeyListSecretActivity, keyRingRowId); + switch (item.getItemId()) { case Id.menu.edit: - mKeyListSecretActivity.checkPassPhraseAndEdit(masterKeyId); + mKeyListSecretActivity.checkPassPhraseAndEdit(masterKeyId, masterCanSign); return true; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java index 1122fc522..e9a5674cd 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java @@ -125,6 +125,14 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { super.onFinishInflate(); } + public void setCanEdit(boolean bCanEdit) { + if (!bCanEdit) { + mDeleteButton.setVisibility(View.INVISIBLE); + mUsage.setEnabled(false); + mExpiryDateButton.setEnabled(false); + } + } + public void setValue(PGPSecretKey key, boolean isMasterKey, int usage) { mKey = key; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java index 7142e4426..898b05372 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java @@ -45,6 +45,7 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.EditText; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; @@ -55,12 +56,14 @@ import java.util.Vector; public class SectionView extends LinearLayout implements OnClickListener, EditorListener { private LayoutInflater mInflater; private View mAdd; + private ImageView mPlusButton; private ViewGroup mEditors; private TextView mTitle; private int mType = 0; private Choice mNewKeyAlgorithmChoice; private int mNewKeySize; + private boolean canEdit = true; private SherlockFragmentActivity mActivity; @@ -99,6 +102,14 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor } } + public void setCanEdit(boolean bCanEdit) { + canEdit = bCanEdit; + mPlusButton = (ImageView)findViewById(R.id.plusbutton); + if (!canEdit) { + mPlusButton.setVisibility(View.INVISIBLE); + } + } + /** {@inheritDoc} */ @Override protected void onFinishInflate() { @@ -129,6 +140,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor /** {@inheritDoc} */ public void onClick(View v) { + if (canEdit) { switch (mType) { case Id.type.user_id: { UserIdEditor view = (UserIdEditor) mInflater.inflate(R.layout.edit_key_user_id_item, @@ -205,6 +217,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor } } this.updateEditorsVisible(); + } } public void setUserIds(Vector list) { @@ -221,6 +234,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor if (mEditors.getChildCount() == 0) { view.setIsMainUserId(true); } + view.setCanEdit(canEdit); mEditors.addView(view); } @@ -241,6 +255,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor view.setEditorListener(this); boolean isMasterKey = (mEditors.getChildCount() == 0); view.setValue(list.get(i), isMasterKey, usages.get(i)); + view.setCanEdit(canEdit); mEditors.addView(view); } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java index 2215d29e7..5b43ebbd9 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java @@ -56,6 +56,16 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene } } + public void setCanEdit(boolean bCanEdit) { + if (!bCanEdit) { + mDeleteButton.setVisibility(View.INVISIBLE); + mName.setEnabled(false); + mIsMainUserId.setEnabled(false); + mEmail.setEnabled(false); + mComment.setEnabled(false); + } + } + public static class NoEmailException extends Exception { static final long serialVersionUID = 0xf812773344L;