From 8cdee9ec30599359d5eb18cbf4a85df5cc788b0b Mon Sep 17 00:00:00 2001 From: Thialfihar Date: Wed, 14 Apr 2010 13:47:29 +0000 Subject: [PATCH 1/5] branch 0.8.x From b8009d6d43277a7840819885a64aeda9e5f582e7 Mon Sep 17 00:00:00 2001 From: Thialfihar Date: Wed, 14 Apr 2010 14:08:24 +0000 Subject: [PATCH 2/5] 0.8.x branch promoted to version 0.8.1, fixed list view of mail accounts not filling the main layout, made a bunch of private classes static --- AndroidManifest.xml | 2 +- res/layout/main.xml | 5 +++-- src/org/thialfihar/android/apg/Apg.java | 2 +- src/org/thialfihar/android/apg/MailListActivity.java | 4 ++-- src/org/thialfihar/android/apg/MainActivity.java | 2 +- .../thialfihar/android/apg/PublicKeyListActivity.java | 2 +- .../thialfihar/android/apg/SecretKeyListActivity.java | 2 +- .../thialfihar/android/apg/provider/DataProvider.java | 9 +-------- 8 files changed, 11 insertions(+), 17 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 5a41f262d..497da3ce1 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -16,7 +16,7 @@ + android:versionName="0.8.1" android:versionCode="4"> + android:layout_weight="1" + android:fillViewport="true"> + android:layout_height="fill_parent"> diff --git a/src/org/thialfihar/android/apg/Apg.java b/src/org/thialfihar/android/apg/Apg.java index 68c4f8877..bf32fc1eb 100644 --- a/src/org/thialfihar/android/apg/Apg.java +++ b/src/org/thialfihar/android/apg/Apg.java @@ -97,7 +97,7 @@ public class Apg { public static final String ENCRYPT = "org.thialfihar.android.apg.intent.ENCRYPT"; } - public static String VERSION = "0.8.0"; + public static String VERSION = "0.8.1"; public static String FULL_VERSION = "APG v" + VERSION; private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = diff --git a/src/org/thialfihar/android/apg/MailListActivity.java b/src/org/thialfihar/android/apg/MailListActivity.java index 8e63a7920..570e761df 100644 --- a/src/org/thialfihar/android/apg/MailListActivity.java +++ b/src/org/thialfihar/android/apg/MailListActivity.java @@ -39,7 +39,7 @@ import android.widget.AdapterView.OnItemClickListener; public class MailListActivity extends ListActivity { LayoutInflater minflater = null; - private class Conversation { + private static class Conversation { public long id; public String subject; public Vector messages; @@ -50,7 +50,7 @@ public class MailListActivity extends ListActivity { } } - private class Message { + private static class Message { public Conversation parent; public long id; public String subject; diff --git a/src/org/thialfihar/android/apg/MainActivity.java b/src/org/thialfihar/android/apg/MainActivity.java index e7107f255..af0618031 100644 --- a/src/org/thialfihar/android/apg/MainActivity.java +++ b/src/org/thialfihar/android/apg/MainActivity.java @@ -360,7 +360,7 @@ public class MainActivity extends Activity { startActivity(new Intent(this, MailListActivity.class).putExtra("account", account)); } - private class AccountListAdapter extends CursorAdapter { + private static class AccountListAdapter extends CursorAdapter { private LayoutInflater minflater; public AccountListAdapter(Context context, Cursor cursor) { diff --git a/src/org/thialfihar/android/apg/PublicKeyListActivity.java b/src/org/thialfihar/android/apg/PublicKeyListActivity.java index cebd9c7ae..d858908c9 100644 --- a/src/org/thialfihar/android/apg/PublicKeyListActivity.java +++ b/src/org/thialfihar/android/apg/PublicKeyListActivity.java @@ -481,7 +481,7 @@ public class PublicKeyListActivity extends ExpandableListActivity ((PublicKeyListAdapter) getExpandableListAdapter()).notifyDataSetChanged(); } - private class PublicKeyListAdapter extends BaseExpandableListAdapter { + private static class PublicKeyListAdapter extends BaseExpandableListAdapter { private LayoutInflater mInflater; private class KeyChild { diff --git a/src/org/thialfihar/android/apg/SecretKeyListActivity.java b/src/org/thialfihar/android/apg/SecretKeyListActivity.java index f42b4ccad..69e8c8c7a 100644 --- a/src/org/thialfihar/android/apg/SecretKeyListActivity.java +++ b/src/org/thialfihar/android/apg/SecretKeyListActivity.java @@ -580,7 +580,7 @@ public class SecretKeyListActivity extends ExpandableListActivity .notifyDataSetChanged(); } - private class SecretKeyListAdapter extends BaseExpandableListAdapter { + private static class SecretKeyListAdapter extends BaseExpandableListAdapter { private LayoutInflater mInflater; private class KeyChild { diff --git a/src/org/thialfihar/android/apg/provider/DataProvider.java b/src/org/thialfihar/android/apg/provider/DataProvider.java index 0a6a814e4..fbc1be047 100644 --- a/src/org/thialfihar/android/apg/provider/DataProvider.java +++ b/src/org/thialfihar/android/apg/provider/DataProvider.java @@ -115,14 +115,7 @@ public class DataProvider extends ContentProvider { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - int currentVersion = oldVersion; - while (currentVersion < newVersion) { - switch (currentVersion) { - default: { - break; - } - } - } + // TODO: upgrade db if necessary, and do that in a clever way } } From acd71a45c09ad6668a03ec74399d8f526ab647e2 Mon Sep 17 00:00:00 2001 From: Thialfihar Date: Thu, 15 Apr 2010 14:37:46 +0000 Subject: [PATCH 3/5] minor layout fixes, replace non breakable spaces if found in an encrypted armored message, as they break the decryption, the HTML representation of GMail introduces them for empty lines ending in a normal space, also adjusted the PGP_MESSAGE regex to allow for spaces after the -----, which seems to be added by some implementations --- res/layout/mailbox_message_item.xml | 2 +- src/org/thialfihar/android/apg/Apg.java | 16 +++++++++++----- .../android/apg/DecryptMessageActivity.java | 7 +++++-- .../android/apg/EncryptMessageActivity.java | 3 ++- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/res/layout/mailbox_message_item.xml b/res/layout/mailbox_message_item.xml index b2b5e91d4..a5858fba3 100644 --- a/res/layout/mailbox_message_item.xml +++ b/res/layout/mailbox_message_item.xml @@ -29,7 +29,7 @@ android:src="@drawable/encrypted" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_centerVertical="true"/> + android:layout_gravity="center_vertical"/> mSecretKeyRings; public static Pattern PGP_MESSAGE = - Pattern.compile(".*?(-----BEGIN PGP MESSAGE-----\n.*?-----END PGP MESSAGE-----).*", + Pattern.compile(".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*", Pattern.DOTALL); protected static boolean mInitialized = false; @@ -1135,6 +1135,7 @@ public class Apg { } public static void encrypt(InputStream inStream, OutputStream outStream, + boolean armored, long encryptionKeyIds[], long signatureKeyId, String signaturePassPhrase, ProgressDialogUpdater progress) @@ -1142,11 +1143,16 @@ public class Apg { NoSuchAlgorithmException, SignatureException { Security.addProvider(new BouncyCastleProvider()); - ArmoredOutputStream armorOut = new ArmoredOutputStream(outStream); - armorOut.setHeader("Version", FULL_VERSION); - OutputStream out = armorOut; + ArmoredOutputStream armorOut = null; + OutputStream out = null; OutputStream encryptOut = null; - + if (armored) { + armorOut = new ArmoredOutputStream(outStream); + armorOut.setHeader("Version", FULL_VERSION); + out = armorOut; + } else { + out = outStream; + } PGPSecretKey signingKey = null; PGPSecretKeyRing signingKeyRing = null; PGPPrivateKey signaturePrivateKey = null; diff --git a/src/org/thialfihar/android/apg/DecryptMessageActivity.java b/src/org/thialfihar/android/apg/DecryptMessageActivity.java index 179d5be55..055c8256c 100644 --- a/src/org/thialfihar/android/apg/DecryptMessageActivity.java +++ b/src/org/thialfihar/android/apg/DecryptMessageActivity.java @@ -190,6 +190,8 @@ public class DecryptMessageActivity extends Activity Matcher matcher = Apg.PGP_MESSAGE.matcher(data); if (matcher.matches()) { data = matcher.group(1); + // replace non breakable spaces + data = data.replaceAll("\\xa0", " "); mMessage.setText(data); } } @@ -312,8 +314,9 @@ public class DecryptMessageActivity extends Activity Bundle data = new Bundle(); Message msg = new Message(); - ByteArrayInputStream in = - new ByteArrayInputStream(mMessage.getText().toString().getBytes()); + String messageData = mMessage.getText().toString(); + + ByteArrayInputStream in = new ByteArrayInputStream(messageData.getBytes()); ByteArrayOutputStream out = new ByteArrayOutputStream(); try { diff --git a/src/org/thialfihar/android/apg/EncryptMessageActivity.java b/src/org/thialfihar/android/apg/EncryptMessageActivity.java index 27e4c29be..af2eac82d 100644 --- a/src/org/thialfihar/android/apg/EncryptMessageActivity.java +++ b/src/org/thialfihar/android/apg/EncryptMessageActivity.java @@ -312,7 +312,8 @@ public class EncryptMessageActivity extends Activity try { if (mEncryptionKeyIds != null && mEncryptionKeyIds.length > 0) { - Apg.encrypt(in, out, mEncryptionKeyIds, mSignatureKeyId, Apg.getPassPhrase(), this); + Apg.encrypt(in, out, true, mEncryptionKeyIds, mSignatureKeyId, + Apg.getPassPhrase(), this); data.putString("message", new String(out.toByteArray())); } else { Apg.sign(in, out, mSignatureKeyId, Apg.getPassPhrase(), this); From c212f28c446044acb5fc7ef7487b95b777b39c44 Mon Sep 17 00:00:00 2001 From: Thialfihar Date: Thu, 15 Apr 2010 16:37:32 +0000 Subject: [PATCH 4/5] rewrote sign-only code, also finally recognize sign-only emails in the list and allow opening them for verification --- res/layout/mailbox_message_item.xml | 2 +- res/values/strings.xml | 1 + src/org/thialfihar/android/apg/Apg.java | 266 +++++++++++++++++- .../android/apg/DecryptMessageActivity.java | 28 +- .../android/apg/EncryptMessageActivity.java | 18 +- .../android/apg/MailListActivity.java | 28 +- 6 files changed, 310 insertions(+), 33 deletions(-) diff --git a/res/layout/mailbox_message_item.xml b/res/layout/mailbox_message_item.xml index a5858fba3..6026909d3 100644 --- a/res/layout/mailbox_message_item.xml +++ b/res/layout/mailbox_message_item.xml @@ -25,7 +25,7 @@ android:layout_width="fill_parent"> Send via Email Decrypt + Verify Select Recipients Reply Encrypt Message diff --git a/src/org/thialfihar/android/apg/Apg.java b/src/org/thialfihar/android/apg/Apg.java index affc78cd7..91bfb3b44 100644 --- a/src/org/thialfihar/android/apg/Apg.java +++ b/src/org/thialfihar/android/apg/Apg.java @@ -16,7 +16,9 @@ package org.thialfihar.android.apg; +import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; @@ -42,6 +44,7 @@ import java.util.HashMap; import java.util.Vector; import java.util.regex.Pattern; +import org.bouncycastle2.bcpg.ArmoredInputStream; import org.bouncycastle2.bcpg.ArmoredOutputStream; import org.bouncycastle2.bcpg.BCPGOutputStream; import org.bouncycastle2.bcpg.CompressionAlgorithmTags; @@ -125,6 +128,10 @@ public class Apg { Pattern.compile(".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*", Pattern.DOTALL); + public static Pattern PGP_SIGNED_MESSAGE = + Pattern.compile(".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*", + Pattern.DOTALL); + protected static boolean mInitialized = false; protected static final int RETURN_NO_MASTER_KEY = -2; @@ -1247,17 +1254,16 @@ public class Apg { progress.setProgress("done.", 100, 100); } - public static void sign(InputStream inStream, OutputStream outStream, - long signatureKeyId, String signaturePassPhrase, - ProgressDialogUpdater progress) + public static void signText(InputStream inStream, OutputStream outStream, + long signatureKeyId, String signaturePassPhrase, + int hashAlgorithm, + ProgressDialogUpdater progress) throws GeneralException, PGPException, IOException, NoSuchAlgorithmException, SignatureException { Security.addProvider(new BouncyCastleProvider()); ArmoredOutputStream armorOut = new ArmoredOutputStream(outStream); armorOut.setHeader("Version", FULL_VERSION); - OutputStream out = armorOut; - OutputStream signOut = out; PGPSecretKey signingKey = null; PGPSecretKeyRing signingKeyRing = null; @@ -1286,7 +1292,7 @@ public class Apg { progress.setProgress("preparing signature...", 30, 100); signatureGenerator = new PGPSignatureGenerator(signingKey.getPublicKey().getAlgorithm(), - HashAlgorithmTags.SHA1, + hashAlgorithm, new BouncyCastleProvider()); signatureGenerator.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT, signaturePrivateKey); String userId = getMainUserId(getMasterKey(signingKeyRing)); @@ -1296,15 +1302,31 @@ public class Apg { signatureGenerator.setHashedSubpackets(spGen.generate()); progress.setProgress("signing...", 40, 100); - int n = 0; - byte[] buffer = new byte[1 << 16]; - while ((n = inStream.read(buffer)) > 0) { - signatureGenerator.update(buffer, 0, n); + + armorOut.beginClearText(hashAlgorithm); + + ByteArrayOutputStream lineOut = new ByteArrayOutputStream(); + int lookAhead = readInputLine(lineOut, inStream); + + processLine(armorOut, signatureGenerator, lineOut.toByteArray()); + + if (lookAhead != -1) { + do { + lookAhead = readInputLine(lineOut, lookAhead, inStream); + + signatureGenerator.update((byte)'\r'); + signatureGenerator.update((byte)'\n'); + + processLine(armorOut, signatureGenerator, lineOut.toByteArray()); + } + while (lookAhead != -1); } - signatureGenerator.generate().encode(signOut); - signOut.close(); - out.close(); + armorOut.endClearText(); + + BCPGOutputStream bOut = new BCPGOutputStream(armorOut); + signatureGenerator.generate().encode(bOut); + armorOut.close(); progress.setProgress("done.", 100, 100); } @@ -1492,6 +1514,108 @@ public class Apg { return returnData; } + public static Bundle verifyText(InputStream inStream, OutputStream outStream, + ProgressDialogUpdater progress) + throws IOException, GeneralException, PGPException, SignatureException { + Bundle returnData = new Bundle(); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ArmoredInputStream aIn = new ArmoredInputStream(inStream); + + progress.setProgress("reading data...", 0, 100); + + // mostly taken from CLearSignedFileProcessor + ByteArrayOutputStream lineOut = new ByteArrayOutputStream(); + int lookAhead = readInputLine(lineOut, aIn); + byte[] lineSep = getLineSeparator(); + + if (lookAhead != -1 && aIn.isClearText()) + { + byte[] line = lineOut.toByteArray(); + out.write(line, 0, getLengthWithoutSeparator(line)); + out.write(lineSep); + + while (lookAhead != -1 && aIn.isClearText()) + { + lookAhead = readInputLine(lineOut, lookAhead, aIn); + + line = lineOut.toByteArray(); + out.write(line, 0, getLengthWithoutSeparator(line)); + out.write(lineSep); + } + } + + out.close(); + + byte[] clearText = out.toByteArray(); + outStream.write(clearText); + + returnData.putBoolean("signature", true); + + progress.setProgress("processing signature...", 60, 100); + PGPObjectFactory pgpFact = new PGPObjectFactory(aIn); + + PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject(); + if (sigList == null) { + throw new GeneralException("corrupt data"); + } + PGPSignature signature = null; + long signatureKeyId = 0; + PGPPublicKey signatureKey = null; + for (int i = 0; i < sigList.size(); ++i) { + signature = sigList.get(i); + signatureKey = findPublicKey(signature.getKeyID()); + if (signatureKeyId == 0) { + signatureKeyId = signature.getKeyID(); + } + if (signatureKey == null) { + signature = null; + } else { + signatureKeyId = signature.getKeyID(); + String userId = null; + PGPPublicKeyRing sigKeyRing = findPublicKeyRing(signatureKeyId); + if (sigKeyRing != null) { + userId = getMainUserId(getMasterKey(sigKeyRing)); + } + returnData.putString("signatureUserId", userId); + break; + } + } + + returnData.putLong("signatureKeyId", signatureKeyId); + + if (signature == null) { + returnData.putBoolean("signatureUnknown", true); + progress.setProgress("done.", 100, 100); + return returnData; + } + + signature.initVerify(signatureKey, new BouncyCastleProvider()); + + InputStream sigIn = new BufferedInputStream(new ByteArrayInputStream(clearText)); + + lookAhead = readInputLine(lineOut, sigIn); + + processLine(signature, lineOut.toByteArray()); + + if (lookAhead != -1) { + do { + lookAhead = readInputLine(lineOut, lookAhead, sigIn); + + signature.update((byte)'\r'); + signature.update((byte)'\n'); + + processLine(signature, lineOut.toByteArray()); + } + while (lookAhead != -1); + } + + returnData.putBoolean("signatureSuccess", signature.verify()); + + progress.setProgress("done.", 100, 100); + return returnData; + } + public static Vector getPublicKeyRings() { return mPublicKeyRings; } @@ -1499,4 +1623,120 @@ public class Apg { public static Vector getSecretKeyRings() { return mSecretKeyRings; } + + + // taken from ClearSignedFileProcessor in BC + private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn) + throws IOException + { + bOut.reset(); + + int lookAhead = -1; + int ch; + + while ((ch = fIn.read()) >= 0) + { + bOut.write(ch); + if (ch == '\r' || ch == '\n') + { + lookAhead = readPassedEOL(bOut, ch, fIn); + break; + } + } + + return lookAhead; + } + + private static int readInputLine(ByteArrayOutputStream bOut, int lookAhead, InputStream fIn) + throws IOException { + bOut.reset(); + + int ch = lookAhead; + + do { + bOut.write(ch); + if (ch == '\r' || ch == '\n') { + lookAhead = readPassedEOL(bOut, ch, fIn); + break; + } + } + while ((ch = fIn.read()) >= 0); + + if (ch < 0) { + lookAhead = -1; + } + + return lookAhead; + } + + private static int readPassedEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn) + throws IOException { + int lookAhead = fIn.read(); + + if (lastCh == '\r' && lookAhead == '\n') { + bOut.write(lookAhead); + lookAhead = fIn.read(); + } + + return lookAhead; + } + + private static void processLine(PGPSignature sig, byte[] line) + throws SignatureException, IOException { + int length = getLengthWithoutWhiteSpace(line); + if (length > 0) + { + sig.update(line, 0, length); + } + } + + private static void processLine(OutputStream aOut, PGPSignatureGenerator sGen, byte[] line) + throws SignatureException, IOException { + int length = getLengthWithoutWhiteSpace(line); + if (length > 0) + { + sGen.update(line, 0, length); + } + + aOut.write(line, 0, line.length); + } + + private static int getLengthWithoutSeparator(byte[] line) { + int end = line.length - 1; + + while (end >= 0 && isLineEnding(line[end])) { + end--; + } + + return end + 1; + } + + private static boolean isLineEnding(byte b) { + return b == '\r' || b == '\n'; + } + + private static int getLengthWithoutWhiteSpace(byte[] line) { + int end = line.length - 1; + + while (end >= 0 && isWhiteSpace(line[end])) { + end--; + } + + return end + 1; + } + + private static boolean isWhiteSpace(byte b) { + return b == '\r' || b == '\n' || b == '\t' || b == ' '; + } + + private static byte[] getLineSeparator() { + String nl = System.getProperty("line.separator"); + byte[] nlBytes = new byte[nl.length()]; + + for (int i = 0; i != nlBytes.length; i++) { + nlBytes[i] = (byte)nl.charAt(i); + } + + return nlBytes; + } } diff --git a/src/org/thialfihar/android/apg/DecryptMessageActivity.java b/src/org/thialfihar/android/apg/DecryptMessageActivity.java index 055c8256c..8b7985c77 100644 --- a/src/org/thialfihar/android/apg/DecryptMessageActivity.java +++ b/src/org/thialfihar/android/apg/DecryptMessageActivity.java @@ -63,6 +63,7 @@ public class DecryptMessageActivity extends Activity private String mReplyTo = null; private String mSubject = null; + private boolean mSignedOnly = false; private ProgressDialog mProgressDialog = null; private Thread mRunningThread = null; @@ -193,6 +194,15 @@ public class DecryptMessageActivity extends Activity // replace non breakable spaces data = data.replaceAll("\\xa0", " "); mMessage.setText(data); + } else { + matcher = Apg.PGP_SIGNED_MESSAGE.matcher(data); + if (matcher.matches()) { + data = matcher.group(1); + // replace non breakable spaces + data = data.replaceAll("\\xa0", " "); + mMessage.setText(data); + mDecryptButton.setText(R.string.btn_verify); + } } } mReplyTo = intent.getExtras().getString("replyTo"); @@ -266,8 +276,18 @@ public class DecryptMessageActivity extends Activity private void decryptClicked() { String error = null; + String messageData = mMessage.getText().toString(); + Matcher matcher = Apg.PGP_SIGNED_MESSAGE.matcher(messageData); + if (matcher.matches()) { + mSignedOnly = true; + decryptStart(); + return; + } + + // else treat it as an encrypted message + mSignedOnly = false; ByteArrayInputStream in = - new ByteArrayInputStream(mMessage.getText().toString().getBytes()); + new ByteArrayInputStream(messageData.getBytes()); try { mDecryptionKeyId = Apg.getDecryptionKeyId(in); showDialog(AskForSecretKeyPassPhrase.DIALOG_PASS_PHRASE); @@ -320,7 +340,11 @@ public class DecryptMessageActivity extends Activity ByteArrayOutputStream out = new ByteArrayOutputStream(); try { - data = Apg.decrypt(in, out, Apg.getPassPhrase(), this); + if (mSignedOnly) { + data = Apg.verifyText(in, out, this); + } else { + data = Apg.decrypt(in, out, Apg.getPassPhrase(), this); + } } catch (PGPException e) { error = e.getMessage(); } catch (IOException e) { diff --git a/src/org/thialfihar/android/apg/EncryptMessageActivity.java b/src/org/thialfihar/android/apg/EncryptMessageActivity.java index af2eac82d..b954f31a1 100644 --- a/src/org/thialfihar/android/apg/EncryptMessageActivity.java +++ b/src/org/thialfihar/android/apg/EncryptMessageActivity.java @@ -24,6 +24,7 @@ import java.security.NoSuchProviderException; import java.security.SignatureException; import java.util.Vector; +import org.bouncycastle2.bcpg.HashAlgorithmTags; import org.bouncycastle2.openpgp.PGPException; import org.bouncycastle2.openpgp.PGPPublicKey; import org.bouncycastle2.openpgp.PGPPublicKeyRing; @@ -104,16 +105,9 @@ public class EncryptMessageActivity extends Activity return; } else { String message = data.getString("message"); - String signature = data.getString("signature"); Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND); emailIntent.setType("text/plain; charset=utf-8"); emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, message); - if (signature != null) { - String fullText = "-----BEGIN PGP SIGNED MESSAGE-----\n" + - "Hash: SHA256\n" + "\n" + - message + "\n" + signature; - emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, fullText); - } if (mSubject != null) { emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, mSubject); @@ -305,7 +299,9 @@ public class EncryptMessageActivity extends Activity message = message.replaceAll(" +\n", "\n"); message = message.replaceAll("\n\n+", "\n\n"); message = message.replaceFirst("^\n+", ""); - message = message.replaceFirst("\n+$", ""); + // make sure there'll be exactly one newline at the end + message = message.replaceFirst("\n*$", "\n"); + ByteArrayInputStream in = new ByteArrayInputStream(Strings.toUTF8ByteArray(message)); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -316,9 +312,9 @@ public class EncryptMessageActivity extends Activity Apg.getPassPhrase(), this); data.putString("message", new String(out.toByteArray())); } else { - Apg.sign(in, out, mSignatureKeyId, Apg.getPassPhrase(), this); - data.putString("message", message); - data.putString("signature", new String(out.toByteArray())); + Apg.signText(in, out, mSignatureKeyId, + Apg.getPassPhrase(), HashAlgorithmTags.SHA256, this); + data.putString("message", new String(out.toByteArray())); } } catch (IOException e) { error = e.getMessage(); diff --git a/src/org/thialfihar/android/apg/MailListActivity.java b/src/org/thialfihar/android/apg/MailListActivity.java index 570e761df..ed207d4cd 100644 --- a/src/org/thialfihar/android/apg/MailListActivity.java +++ b/src/org/thialfihar/android/apg/MailListActivity.java @@ -57,9 +57,11 @@ public class MailListActivity extends ListActivity { public String fromAddress; public String data; public String replyTo; + public boolean signedOnly; public Message(Conversation parent, long id, String subject, - String fromAddress, String replyTo, String data) { + String fromAddress, String replyTo, + String data, boolean signedOnly) { this.parent = parent; this.id = id; this.subject = subject; @@ -69,6 +71,7 @@ public class MailListActivity extends ListActivity { if (this.replyTo == null || this.replyTo.equals("")) { this.replyTo = this.fromAddress; } + this.signedOnly = signedOnly; } } @@ -115,18 +118,26 @@ public class MailListActivity extends ListActivity { int bodyIndex = messageCursor.getColumnIndex("body"); String data = messageCursor.getString(bodyIndex); data = Html.fromHtml(data).toString(); + boolean signedOnly = false; Matcher matcher = Apg.PGP_MESSAGE.matcher(data); if (matcher.matches()) { data = matcher.group(1); } else { - data = null; + matcher = Apg.PGP_SIGNED_MESSAGE.matcher(data); + if (matcher.matches()) { + data = matcher.group(1); + signedOnly = true; + } else { + data = null; + } } Message message = new Message(conversation, messageCursor.getLong(idIndex), messageCursor.getString(subjectIndex), messageCursor.getString(fromAddressIndex), - messageCursor.getString(replyToIndex), data); + messageCursor.getString(replyToIndex), + data, signedOnly); messages.add(message); mmessages.add(message); @@ -186,14 +197,19 @@ public class MailListActivity extends ListActivity { TextView subject = (TextView) view.findViewById(R.id.subject); TextView email = (TextView) view.findViewById(R.id.email_address); - ImageView encrypted = (ImageView) view.findViewById(R.id.ic_encrypted); + ImageView status = (ImageView) view.findViewById(R.id.ic_status); subject.setText(message.subject); email.setText(message.fromAddress); if (message.data != null) { - encrypted.setVisibility(View.VISIBLE); + if (message.signedOnly) { + status.setImageResource(R.drawable.signed); + } else { + status.setImageResource(R.drawable.encrypted); + } + status.setVisibility(View.VISIBLE); } else { - encrypted.setVisibility(View.INVISIBLE); + status.setVisibility(View.INVISIBLE); } return view; From 5b5e15c88663acfc282d42ff51cdceff1d9d4084 Mon Sep 17 00:00:00 2001 From: Thialfihar Date: Thu, 15 Apr 2010 16:44:45 +0000 Subject: [PATCH 5/5] changelog details for 0.8.1 --- src/org/thialfihar/android/apg/MainActivity.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/org/thialfihar/android/apg/MainActivity.java b/src/org/thialfihar/android/apg/MainActivity.java index af0618031..531441c1d 100644 --- a/src/org/thialfihar/android/apg/MainActivity.java +++ b/src/org/thialfihar/android/apg/MainActivity.java @@ -220,12 +220,9 @@ public class MainActivity extends Activity { SpannableString info = new SpannableString("Read the warnings!\n\n" + "Changes:\n" + - " * create/edit keys\n" + - " * export keys\n" + - " * GUI more Android-like\n" + - " * better error handling\n" + - " * bug fixes, optimizations\n" + - " * starting with v0.8.0 APG will be open source, see website\n" + + " * display signed-only mails\n" + + " * verify signed-only mails\n" + + " * bug fixes, layout fixes\n" + "\n" + "WARNING: be careful editing your existing keys, as they " + "WILL be stripped of certificates right now.\n" +