implemented secret keys without passphrase

This commit is contained in:
Dominik 2012-04-13 16:54:50 +02:00
parent 4793cd1c25
commit 4eebeede2b
8 changed files with 98 additions and 55 deletions

View File

@ -25,15 +25,14 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:fillViewport="true" android:fillViewport="true" >
android:paddingLeft="10dp"
android:paddingRight="10dp" >
<LinearLayout <LinearLayout
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:padding="4dp" > android:paddingLeft="10dp"
android:paddingRight="10dp" >
<LinearLayout <LinearLayout
android:layout_width="fill_parent" android:layout_width="fill_parent"

View File

@ -98,7 +98,7 @@
<string name="menu_keyServer">Key Server</string> <string name="menu_keyServer">Key Server</string>
<string name="menu_updateKey">Update</string> <string name="menu_updateKey">Update</string>
<string name="menu_exportKeyToServer">Export To Server</string> <string name="menu_exportKeyToServer">Export To Server</string>
<string name="menu_share">Share</string> <string name="menu_share">Share with QR Code</string>
<string name="menu_scanQRCode">Scan QR Code</string> <string name="menu_scanQRCode">Scan QR Code</string>
<string name="menu_signKey">Sign Key</string> <string name="menu_signKey">Sign Key</string>

View File

@ -27,6 +27,7 @@ import org.apg.ui.widget.KeyEditor;
import org.apg.ui.widget.SectionView; import org.apg.ui.widget.SectionView;
import org.apg.ui.widget.UserIdEditor; import org.apg.ui.widget.UserIdEditor;
import org.apg.util.IterableIterator; import org.apg.util.IterableIterator;
import org.apg.util.Utils;
import org.spongycastle.bcpg.ArmoredInputStream; import org.spongycastle.bcpg.ArmoredInputStream;
import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.bcpg.BCPGOutputStream; import org.spongycastle.bcpg.BCPGOutputStream;
@ -155,6 +156,7 @@ public class Apg {
public static final String EXTRA_BINARY = "binary"; public static final String EXTRA_BINARY = "binary";
public static final String EXTRA_KEY_SERVERS = "keyServers"; public static final String EXTRA_KEY_SERVERS = "keyServers";
public static final String EXTRA_EXPECTED_FINGERPRINT = "expectedFingerprint"; public static final String EXTRA_EXPECTED_FINGERPRINT = "expectedFingerprint";
public static final String EXTRA_NO_PASSPHRASE = "noPassphrase";
public static final String AUTHORITY = DataProvider.AUTHORITY; public static final String AUTHORITY = DataProvider.AUTHORITY;
@ -374,18 +376,6 @@ public class Apg {
return secretKey; return secretKey;
} }
private static long getNumDaysBetween(GregorianCalendar first, GregorianCalendar second) {
GregorianCalendar tmp = new GregorianCalendar();
tmp.setTime(first.getTime());
long numDays = (second.getTimeInMillis() - first.getTimeInMillis()) / 1000 / 86400;
tmp.add(Calendar.DAY_OF_MONTH, (int) numDays);
while (tmp.before(second)) {
tmp.add(Calendar.DAY_OF_MONTH, 1);
++numDays;
}
return numDays;
}
public static void buildSecretKey(Activity context, SectionView userIdsView, public static void buildSecretKey(Activity context, SectionView userIdsView,
SectionView keysView, String oldPassPhrase, String newPassPhrase, SectionView keysView, String oldPassPhrase, String newPassPhrase,
ProgressDialogUpdater progress) throws Apg.GeneralException, NoSuchProviderException, ProgressDialogUpdater progress) throws Apg.GeneralException, NoSuchProviderException,
@ -509,7 +499,7 @@ public class Apg {
GregorianCalendar creationDate = new GregorianCalendar(); GregorianCalendar creationDate = new GregorianCalendar();
creationDate.setTime(getCreationDate(masterKey)); creationDate.setTime(getCreationDate(masterKey));
GregorianCalendar expiryDate = keyEditor.getExpiryDate(); GregorianCalendar expiryDate = keyEditor.getExpiryDate();
long numDays = getNumDaysBetween(creationDate, expiryDate); long numDays = Utils.getNumDaysBetween(creationDate, expiryDate);
if (numDays <= 0) { if (numDays <= 0) {
throw new GeneralException( throw new GeneralException(
context.getString(R.string.error_expiryMustComeAfterCreation)); context.getString(R.string.error_expiryMustComeAfterCreation));
@ -517,8 +507,10 @@ public class Apg {
hashedPacketsGen.setKeyExpirationTime(true, numDays * 86400); hashedPacketsGen.setKeyExpirationTime(true, numDays * 86400);
} }
if (progress != null) if (progress != null) {
progress.setProgress(R.string.progress_buildingMasterKeyRing, 30, 100); progress.setProgress(R.string.progress_buildingMasterKeyRing, 30, 100);
}
PGPKeyRingGenerator keyGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, PGPKeyRingGenerator keyGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION,
masterKeyPair, mainUserId, PGPEncryptedData.CAST5, newPassPhrase.toCharArray(), masterKeyPair, mainUserId, PGPEncryptedData.CAST5, newPassPhrase.toCharArray(),
hashedPacketsGen.generate(), unhashedPacketsGen.generate(), new SecureRandom(), hashedPacketsGen.generate(), unhashedPacketsGen.generate(), new SecureRandom(),
@ -558,7 +550,7 @@ public class Apg {
GregorianCalendar creationDate = new GregorianCalendar(); GregorianCalendar creationDate = new GregorianCalendar();
creationDate.setTime(getCreationDate(masterKey)); creationDate.setTime(getCreationDate(masterKey));
GregorianCalendar expiryDate = keyEditor.getExpiryDate(); GregorianCalendar expiryDate = keyEditor.getExpiryDate();
long numDays = getNumDaysBetween(creationDate, expiryDate); long numDays = Utils.getNumDaysBetween(creationDate, expiryDate);
if (numDays <= 0) { if (numDays <= 0) {
throw new GeneralException( throw new GeneralException(
context.getString(R.string.error_expiryMustComeAfterCreation)); context.getString(R.string.error_expiryMustComeAfterCreation));
@ -2202,7 +2194,7 @@ public class Apg {
return false; return false;
} }
} catch (NameNotFoundException e) { } catch (NameNotFoundException e) {
// unpossible! // impossible!
return false; return false;
} }
} }
@ -2216,7 +2208,7 @@ public class Apg {
VERSION = pi.versionName; VERSION = pi.versionName;
return VERSION; return VERSION;
} catch (NameNotFoundException e) { } catch (NameNotFoundException e) {
// unpossible! // impossible!
return "0.0.0"; return "0.0.0";
} }
} }

View File

@ -28,6 +28,7 @@ import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener; import android.content.DialogInterface.OnClickListener;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.EditText; import android.widget.EditText;
@ -86,7 +87,7 @@ public class AskForSecretKeyPassPhrase {
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
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().toString();
long keyId; long keyId;
if (secretKey != null) { if (secretKey != null) {
try { try {
@ -116,6 +117,23 @@ public class AskForSecretKeyPassPhrase {
} }
}); });
// check if the key has no passphrase
if (secretKey != null) {
try {
Log.d("APG", "check if key has no passphrase...");
PGPPrivateKey testKey = secretKey.extractPrivateKey("".toCharArray(),
new BouncyCastleProvider());
if (testKey != null) {
Log.d("APG", "Key has no passphrase!");
cb.passPhraseCallback(secretKey.getKeyID(), null);
return null;
}
} catch (PGPException e) {
}
}
return alert.create(); return alert.create();
} }
} }

View File

@ -118,16 +118,12 @@ public class DecryptActivity extends BaseActivity {
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
if (mDecryptEnabled) { if (mDecryptEnabled) {
menu.add(1, Id.menu.option.decrypt, 0, mDecryptString) menu.add(1, Id.menu.option.decrypt, 0, mDecryptString).setShowAsAction(
// .setIcon(R.drawable.ic_menu_encrypt) MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
.setShowAsAction(
MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
} }
if (mReplyEnabled) { if (mReplyEnabled) {
menu.add(1, Id.menu.option.reply, 1, mReplyString) menu.add(1, Id.menu.option.reply, 1, mReplyString).setShowAsAction(
// .setIcon(R.drawable.ic_menu_decrypt) MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
.setShowAsAction(
MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
} }
return true; return true;
@ -275,9 +271,8 @@ public class DecryptActivity extends BaseActivity {
// replace non breakable spaces // replace non breakable spaces
textData = textData.replaceAll("\\xa0", " "); textData = textData.replaceAll("\\xa0", " ");
mMessage.setText(textData); mMessage.setText(textData);
mDecryptString = getString(R.string.btn_verify); mDecryptString = getString(R.string.btn_verify);
// mDecryptButton.setText(R.string.btn_verify);
// build new action bar // build new action bar
invalidateOptionsMenu(); invalidateOptionsMenu();
} else { } else {
@ -399,8 +394,6 @@ public class DecryptActivity extends BaseActivity {
if (mSource.getCurrentView().getId() == R.id.sourceMessage if (mSource.getCurrentView().getId() == R.id.sourceMessage
&& (mMessage.getText().length() > 0 || mData != null || mContentUri != null)) { && (mMessage.getText().length() > 0 || mData != null || mContentUri != null)) {
// mDecryptButton.performClick();
// TODO: why was it performClick()???
decryptClicked(); decryptClicked();
} }
} }

View File

@ -38,7 +38,6 @@ import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Message; import android.os.Message;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -49,7 +48,6 @@ import android.widget.CheckBox;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.EditText; import android.widget.EditText;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TableRow;
import android.widget.Toast; import android.widget.Toast;
import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.CompoundButton.OnCheckedChangeListener;
@ -72,6 +70,8 @@ public class EditKeyActivity extends BaseActivity {
private Button mChangePassPhrase; private Button mChangePassPhrase;
private CheckBox mNoPassphrase;
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
menu.add(1, Id.menu.option.cancel, 0, R.string.btn_doNotSave).setShowAsAction( menu.add(1, Id.menu.option.cancel, 0, R.string.btn_doNotSave).setShowAsAction(
@ -152,6 +152,14 @@ public class EditKeyActivity extends BaseActivity {
if (extras.containsKey(Apg.EXTRA_USER_IDS)) { if (extras.containsKey(Apg.EXTRA_USER_IDS)) {
userIds.add(extras.getString(Apg.EXTRA_USER_IDS)); userIds.add(extras.getString(Apg.EXTRA_USER_IDS));
} }
// if userId is given, prefill the fields
if (extras.containsKey(Apg.EXTRA_NO_PASSPHRASE)) {
boolean noPassphrase = extras.getBoolean(Apg.EXTRA_NO_PASSPHRASE);
if (noPassphrase) {
mCurrentPassPhrase = "";
}
}
} }
mChangePassPhrase = (Button) findViewById(R.id.edit_key_btn_change_pass_phrase); mChangePassPhrase = (Button) findViewById(R.id.edit_key_btn_change_pass_phrase);
@ -162,12 +170,15 @@ public class EditKeyActivity extends BaseActivity {
}); });
// disable passphrase when no passphrase checkobox is checked! // disable passphrase when no passphrase checkobox is checked!
final CheckBox noPassphrase = (CheckBox) findViewById(R.id.edit_key_no_passphrase); mNoPassphrase = (CheckBox) findViewById(R.id.edit_key_no_passphrase);
noPassphrase.setOnCheckedChangeListener(new OnCheckedChangeListener() { mNoPassphrase.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) { if (isChecked) {
// remove passphrase
mNewPassPhrase = null;
mChangePassPhrase.setVisibility(View.GONE); mChangePassPhrase.setVisibility(View.GONE);
} else { } else {
mChangePassPhrase.setVisibility(View.VISIBLE); mChangePassPhrase.setVisibility(View.VISIBLE);
@ -194,6 +205,12 @@ public class EditKeyActivity extends BaseActivity {
mCurrentPassPhrase = ""; mCurrentPassPhrase = "";
} }
if (mCurrentPassPhrase.equals("")) {
// check "no passphrase" checkbox and remove button
mNoPassphrase.setChecked(true);
mChangePassPhrase.setVisibility(View.GONE);
}
updatePassPhraseButtonText(); updatePassPhraseButtonText();
} }
@ -204,9 +221,15 @@ public class EditKeyActivity extends BaseActivity {
return ((KeyEditor) mKeys.getEditors().getChildAt(0)).getValue().getKeyID(); return ((KeyEditor) mKeys.getEditors().getChildAt(0)).getValue().getKeyID();
} }
public boolean havePassPhrase() { public boolean isPassphraseSet() {
return (!mCurrentPassPhrase.equals("")) if (mNoPassphrase.isChecked()) {
|| (mNewPassPhrase != null && !mNewPassPhrase.equals("")); return true;
} else if ((!mCurrentPassPhrase.equals(""))
|| (mNewPassPhrase != null && !mNewPassPhrase.equals(""))) {
return true;
} else {
return false;
}
} }
@Override @Override
@ -215,7 +238,7 @@ public class EditKeyActivity extends BaseActivity {
case Id.dialog.new_pass_phrase: { case Id.dialog.new_pass_phrase: {
AlertDialog.Builder alert = new AlertDialog.Builder(this); AlertDialog.Builder alert = new AlertDialog.Builder(this);
if (havePassPhrase()) { if (isPassphraseSet()) {
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_setPassPhrase);
@ -266,7 +289,7 @@ public class EditKeyActivity extends BaseActivity {
} }
private void saveClicked() { private void saveClicked() {
if (!havePassPhrase()) { if (!isPassphraseSet()) {
Toast.makeText(this, R.string.setAPassPhrase, Toast.LENGTH_SHORT).show(); Toast.makeText(this, R.string.setAPassPhrase, Toast.LENGTH_SHORT).show();
return; return;
} }
@ -333,7 +356,7 @@ public class EditKeyActivity extends BaseActivity {
} }
private void updatePassPhraseButtonText() { private void updatePassPhraseButtonText() {
mChangePassPhrase.setText(havePassPhrase() ? R.string.btn_changePassPhrase mChangePassPhrase.setText(isPassphraseSet() ? R.string.btn_changePassPhrase
: R.string.btn_setPassPhrase); : R.string.btn_setPassPhrase);
} }
} }

View File

@ -49,15 +49,13 @@ public class SecretKeyListActivity extends KeyListActivity implements OnChildCli
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
menu.add(3, Id.menu.option.search, 0, R.string.menu_search) menu.add(3, Id.menu.option.search, 0, R.string.menu_search)
.setIcon(R.drawable.ic_menu_search) .setIcon(R.drawable.ic_menu_search).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); menu.add(1, Id.menu.option.create, 1, R.string.menu_createKey).setShowAsAction(
menu.add(1, Id.menu.option.create, 1, R.string.menu_createKey) MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
.setShowAsAction( menu.add(0, Id.menu.option.import_keys, 2, R.string.menu_importKeys).setShowAsAction(
MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); MenuItem.SHOW_AS_ACTION_NEVER | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
menu.add(0, Id.menu.option.import_keys, 2, R.string.menu_importKeys) menu.add(0, Id.menu.option.export_keys, 3, R.string.menu_exportKeys).setShowAsAction(
.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER | MenuItem.SHOW_AS_ACTION_WITH_TEXT); MenuItem.SHOW_AS_ACTION_NEVER | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
menu.add(0, Id.menu.option.export_keys, 3, R.string.menu_exportKeys)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
return true; return true;
} }
@ -114,7 +112,6 @@ public class SecretKeyListActivity extends KeyListActivity implements OnChildCli
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()) long keyId = ((KeyListAdapter) mList.getExpandableListAdapter())
.getGroupId(mSelectedItem); .getGroupId(mSelectedItem);
String msg = keyId + "," + Apg.getFingerPrint(keyId); String msg = keyId + "," + Apg.getFingerPrint(keyId);
;
new IntentIntegrator(this).shareText(msg); new IntentIntegrator(this).shareText(msg);
} }

View File

@ -19,6 +19,8 @@ package org.apg.util;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Calendar;
import java.util.GregorianCalendar;
import android.content.Context; import android.content.Context;
@ -51,4 +53,23 @@ public class Utils {
return stream.toString(); return stream.toString();
} }
/**
* Return the number if days between two dates
*
* @param first
* @param second
* @return number of days
*/
public static long getNumDaysBetween(GregorianCalendar first, GregorianCalendar second) {
GregorianCalendar tmp = new GregorianCalendar();
tmp.setTime(first.getTime());
long numDays = (second.getTimeInMillis() - first.getTimeInMillis()) / 1000 / 86400;
tmp.add(Calendar.DAY_OF_MONTH, (int) numDays);
while (tmp.before(second)) {
tmp.add(Calendar.DAY_OF_MONTH, 1);
++numDays;
}
return numDays;
}
} }