aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThialfihar <thialfihar@gmail.com>2010-07-27 22:41:50 +0000
committerThialfihar <thialfihar@gmail.com>2010-07-27 22:41:50 +0000
commitb13eb7dbf3d342e3d63d7718c1f66b082f055540 (patch)
treef08b1b04cb7366b8b357777464d120db20e39980
parent20f7755b2c2395431f059ec14ddc6c1d2359e20d (diff)
downloadopen-keychain-b13eb7dbf3d342e3d63d7718c1f66b082f055540.tar.gz
open-keychain-b13eb7dbf3d342e3d63d7718c1f66b082f055540.tar.bz2
open-keychain-b13eb7dbf3d342e3d63d7718c1f66b082f055540.zip
added a "force V3 signature" setting similar to the GPG version, hopefully making APG useful for some special cases where that is needed
Update issue 39 Two new strings: <string name="section_advanced">Advanced</string> <string name="label_forceV3Signature">Force V3 Signatures</string> "V3" is just "version 3" and should remain untranslated, both strings can be seen at the bottom of the preferences activity.
-rw-r--r--res/values/strings.xml2
-rw-r--r--res/xml/apg_preferences.xml10
-rw-r--r--src/org/thialfihar/android/apg/Apg.java120
-rw-r--r--src/org/thialfihar/android/apg/Constants.java1
-rw-r--r--src/org/thialfihar/android/apg/EncryptActivity.java32
-rw-r--r--src/org/thialfihar/android/apg/Preferences.java10
-rw-r--r--src/org/thialfihar/android/apg/PreferencesActivity.java13
7 files changed, 152 insertions, 36 deletions
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c9f35824c..a64873b0f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -46,6 +46,7 @@
<string name="section_keys">Keys</string>
<string name="section_general">General</string>
<string name="section_defaults">Defaults</string>
+ <string name="section_advanced">Advanced</string>
<!-- btn_lowerCase: capitalized words, no punctuation -->
<string name="btn_signToClipboard">Sign To Clipboard</string>
@@ -106,6 +107,7 @@
<string name="label_messageCompression">Message Compression</string>
<string name="label_fileCompression">File Compression</string>
<string name="label_language">Language</string>
+ <string name="label_forceV3Signature">Force V3 Signatures</string>
<string name="noKeysSelected">Select</string>
<string name="oneKeySelected">1 Selected</string>
diff --git a/res/xml/apg_preferences.xml b/res/xml/apg_preferences.xml
index 07471a4b9..aa2defc87 100644
--- a/res/xml/apg_preferences.xml
+++ b/res/xml/apg_preferences.xml
@@ -66,4 +66,14 @@
</PreferenceCategory>
+ <PreferenceCategory
+ android:title="@string/section_advanced">
+
+ <CheckBoxPreference
+ android:persistent="false"
+ android:key="forceV3Signatures"
+ android:title="@string/label_forceV3Signature" />
+
+ </PreferenceCategory>
+
</PreferenceScreen>
diff --git a/src/org/thialfihar/android/apg/Apg.java b/src/org/thialfihar/android/apg/Apg.java
index 725136ef2..fb6d50afd 100644
--- a/src/org/thialfihar/android/apg/Apg.java
+++ b/src/org/thialfihar/android/apg/Apg.java
@@ -78,6 +78,7 @@ import org.bouncycastle2.openpgp.PGPSignatureList;
import org.bouncycastle2.openpgp.PGPSignatureSubpacketGenerator;
import org.bouncycastle2.openpgp.PGPSignatureSubpacketVector;
import org.bouncycastle2.openpgp.PGPUtil;
+import org.bouncycastle2.openpgp.PGPV3SignatureGenerator;
import org.thialfihar.android.apg.provider.DataProvider;
import org.thialfihar.android.apg.provider.Database;
import org.thialfihar.android.apg.provider.KeyRings;
@@ -1123,6 +1124,7 @@ public class Apg {
String signaturePassPhrase,
ProgressDialogUpdater progress,
int symmetricAlgorithm, int hashAlgorithm, int compression,
+ boolean forceV3Signature,
String passPhrase)
throws IOException, GeneralException, PGPException, NoSuchProviderException,
NoSuchAlgorithmException, SignatureException {
@@ -1165,7 +1167,6 @@ public class Apg {
new BouncyCastleProvider());
}
- PGPSignatureGenerator signatureGenerator = null;
progress.setProgress(R.string.progress_preparingStreams, 5, 100);
// encrypt and compress input file content
PGPEncryptedDataGenerator cPk =
@@ -1184,18 +1185,29 @@ public class Apg {
}
encryptOut = cPk.open(out, new byte[1 << 16]);
+ PGPSignatureGenerator signatureGenerator = null;
+ PGPV3SignatureGenerator signatureV3Generator = null;
+
if (signatureKeyId != 0) {
progress.setProgress(R.string.progress_preparingSignature, 10, 100);
- signatureGenerator =
- new PGPSignatureGenerator(signingKey.getPublicKey().getAlgorithm(),
- hashAlgorithm,
- new BouncyCastleProvider());
- signatureGenerator.initSign(PGPSignature.BINARY_DOCUMENT, signaturePrivateKey);
- String userId = getMainUserId(getMasterKey(signingKeyRing));
-
- PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
- spGen.setSignerUserID(false, userId);
- signatureGenerator.setHashedSubpackets(spGen.generate());
+ if (forceV3Signature) {
+ signatureV3Generator =
+ new PGPV3SignatureGenerator(signingKey.getPublicKey().getAlgorithm(),
+ hashAlgorithm,
+ new BouncyCastleProvider());
+ signatureV3Generator.initSign(PGPSignature.BINARY_DOCUMENT, signaturePrivateKey);
+ } else {
+ signatureGenerator =
+ new PGPSignatureGenerator(signingKey.getPublicKey().getAlgorithm(),
+ hashAlgorithm,
+ new BouncyCastleProvider());
+ signatureGenerator.initSign(PGPSignature.BINARY_DOCUMENT, signaturePrivateKey);
+
+ String userId = getMainUserId(getMasterKey(signingKeyRing));
+ PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+ spGen.setSignerUserID(false, userId);
+ signatureGenerator.setHashedSubpackets(spGen.generate());
+ }
}
PGPCompressedDataGenerator compressGen = null;
@@ -1207,7 +1219,11 @@ public class Apg {
bcpgOut = new BCPGOutputStream(compressGen.open(encryptOut));
}
if (signatureKeyId != 0) {
- signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
+ if (forceV3Signature) {
+ signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut);
+ } else {
+ signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
+ }
}
PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
@@ -1223,7 +1239,11 @@ public class Apg {
while ((n = in.read(buffer)) > 0) {
pOut.write(buffer, 0, n);
if (signatureKeyId != 0) {
- signatureGenerator.update(buffer, 0, n);
+ if (forceV3Signature) {
+ signatureV3Generator.update(buffer, 0, n);
+ } else {
+ signatureGenerator.update(buffer, 0, n);
+ }
}
done += n;
if (data.getSize() != 0) {
@@ -1235,7 +1255,11 @@ public class Apg {
if (signatureKeyId != 0) {
progress.setProgress(R.string.progress_generatingSignature, 95, 100);
- signatureGenerator.generate().encode(pOut);
+ if (forceV3Signature) {
+ signatureV3Generator.generate().encode(pOut);
+ } else {
+ signatureGenerator.generate().encode(pOut);
+ }
}
if (compressGen != null) {
compressGen.close();
@@ -1252,6 +1276,7 @@ public class Apg {
InputData data, OutputStream outStream,
long signatureKeyId, String signaturePassPhrase,
int hashAlgorithm,
+ boolean forceV3Signature,
ProgressDialogUpdater progress)
throws GeneralException, PGPException, IOException, NoSuchAlgorithmException,
SignatureException {
@@ -1281,20 +1306,30 @@ public class Apg {
signingKey.extractPrivateKey(signaturePassPhrase.toCharArray(),
new BouncyCastleProvider());
- PGPSignatureGenerator signatureGenerator = null;
progress.setProgress(R.string.progress_preparingStreams, 0, 100);
progress.setProgress(R.string.progress_preparingSignature, 30, 100);
- signatureGenerator =
- new PGPSignatureGenerator(signingKey.getPublicKey().getAlgorithm(),
- hashAlgorithm,
- new BouncyCastleProvider());
- signatureGenerator.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT, signaturePrivateKey);
- String userId = getMainUserId(getMasterKey(signingKeyRing));
- PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
- spGen.setSignerUserID(false, userId);
- signatureGenerator.setHashedSubpackets(spGen.generate());
+ PGPSignatureGenerator signatureGenerator = null;
+ PGPV3SignatureGenerator signatureV3Generator = null;
+ if (forceV3Signature) {
+ signatureV3Generator =
+ new PGPV3SignatureGenerator(signingKey.getPublicKey().getAlgorithm(),
+ hashAlgorithm,
+ new BouncyCastleProvider());
+ signatureV3Generator.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT, signaturePrivateKey);
+ } else {
+ signatureGenerator =
+ new PGPSignatureGenerator(signingKey.getPublicKey().getAlgorithm(),
+ hashAlgorithm,
+ new BouncyCastleProvider());
+ signatureGenerator.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT, signaturePrivateKey);
+
+ PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+ String userId = getMainUserId(getMasterKey(signingKeyRing));
+ spGen.setSignerUserID(false, userId);
+ signatureGenerator.setHashedSubpackets(spGen.generate());
+ }
progress.setProgress(R.string.progress_signing, 40, 100);
@@ -1304,16 +1339,29 @@ public class Apg {
InputStream inStream = data.getInputStream();
int lookAhead = readInputLine(lineOut, inStream);
- processLine(armorOut, signatureGenerator, lineOut.toByteArray());
+ if (forceV3Signature) {
+ processLine(armorOut, signatureV3Generator, lineOut.toByteArray());
+ } else {
+ processLine(armorOut, signatureGenerator, lineOut.toByteArray());
+ }
if (lookAhead != -1) {
do {
lookAhead = readInputLine(lineOut, lookAhead, inStream);
- signatureGenerator.update((byte)'\r');
- signatureGenerator.update((byte)'\n');
+ if (forceV3Signature) {
+ signatureV3Generator.update((byte)'\r');
+ signatureV3Generator.update((byte)'\n');
+ } else {
+ signatureGenerator.update((byte)'\r');
+ signatureGenerator.update((byte)'\n');
+ }
- processLine(armorOut, signatureGenerator, lineOut.toByteArray());
+ if (forceV3Signature) {
+ processLine(armorOut, signatureV3Generator, lineOut.toByteArray());
+ } else {
+ processLine(armorOut, signatureGenerator, lineOut.toByteArray());
+ }
}
while (lookAhead != -1);
}
@@ -1321,7 +1369,11 @@ public class Apg {
armorOut.endClearText();
BCPGOutputStream bOut = new BCPGOutputStream(armorOut);
- signatureGenerator.generate().encode(bOut);
+ if (forceV3Signature) {
+ signatureV3Generator.generate().encode(bOut);
+ } else {
+ signatureGenerator.generate().encode(bOut);
+ }
armorOut.close();
progress.setProgress(R.string.progress_done, 100, 100);
@@ -1802,6 +1854,16 @@ public class Apg {
aOut.write(line, 0, line.length);
}
+ private static void processLine(OutputStream aOut, PGPV3SignatureGenerator 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;
diff --git a/src/org/thialfihar/android/apg/Constants.java b/src/org/thialfihar/android/apg/Constants.java
index b61395269..b8704117c 100644
--- a/src/org/thialfihar/android/apg/Constants.java
+++ b/src/org/thialfihar/android/apg/Constants.java
@@ -33,5 +33,6 @@ public final class Constants {
public static final String default_file_compression = "defaultFileCompression";
public static final String pass_phrase_cache_ttl = "passPhraseCacheTtl";
public static final String language = "language";
+ public static final String force_v3_signatures = "forceV3Signatures";
}
}
diff --git a/src/org/thialfihar/android/apg/EncryptActivity.java b/src/org/thialfihar/android/apg/EncryptActivity.java
index b3b002346..e1e773216 100644
--- a/src/org/thialfihar/android/apg/EncryptActivity.java
+++ b/src/org/thialfihar/android/apg/EncryptActivity.java
@@ -619,16 +619,15 @@ public class EncryptActivity extends BaseActivity {
String error = null;
Bundle data = new Bundle();
Message msg = new Message();
- fillDataSource();
- fillDataDestination();
+
try {
InputData in;
OutputStream out;
boolean useAsciiArmour = true;
long encryptionKeyIds[] = null;
long signatureKeyId = 0;
- boolean signOnly = false;
int compressionId = 0;
+ boolean signOnly = false;
String passPhrase = null;
if (mMode.getCurrentView().getId() == R.id.modeSymmetric) {
@@ -642,6 +641,9 @@ public class EncryptActivity extends BaseActivity {
signOnly = (mEncryptionKeyIds == null || mEncryptionKeyIds.length == 0);
}
+ fillDataSource(signOnly && !mReturnResult);
+ fillDataDestination();
+
// streams
in = mDataSource.getInputData(this, true);
out = mDataDestination.getOutputStream(this);
@@ -661,14 +663,18 @@ public class EncryptActivity extends BaseActivity {
if (signOnly) {
Apg.signText(this, in, out, getSecretKeyId(),
Apg.getCachedPassPhrase(getSecretKeyId()),
- mPreferences.getDefaultHashAlgorithm(), this);
+ mPreferences.getDefaultHashAlgorithm(),
+ mPreferences.getForceV3Signatures(),
+ this);
} else {
Apg.encrypt(this, in, out, useAsciiArmour,
encryptionKeyIds, signatureKeyId,
Apg.getCachedPassPhrase(signatureKeyId), this,
mPreferences.getDefaultEncryptionAlgorithm(),
mPreferences.getDefaultHashAlgorithm(),
- compressionId, passPhrase);
+ compressionId,
+ mPreferences.getForceV3Signatures(),
+ passPhrase);
}
out.close();
@@ -930,7 +936,7 @@ public class EncryptActivity extends BaseActivity {
return super.onCreateDialog(id);
}
- protected void fillDataSource() {
+ protected void fillDataSource(boolean fixContent) {
mDataSource = new DataSource();
if (mContentUri != null) {
mDataSource.setUri(mContentUri);
@@ -940,7 +946,19 @@ public class EncryptActivity extends BaseActivity {
if (mData != null) {
mDataSource.setData(mData);
} else {
- mDataSource.setText(mMessage.getText().toString());
+ String message = mMessage.getText().toString();
+ if (fixContent) {
+ // fix the message a bit, trailing spaces and newlines break stuff,
+ // because GMail sends as HTML and such things fuck up the
+ // signature,
+ // TODO: things like "<" and ">" also fuck up the signature
+ message = message.replaceAll(" +\n", "\n");
+ message = message.replaceAll("\n\n+", "\n\n");
+ message = message.replaceFirst("^\n+", "");
+ // make sure there'll be exactly one newline at the end
+ message = message.replaceFirst("\n*$", "\n");
+ }
+ mDataSource.setText(message);
}
}
}
diff --git a/src/org/thialfihar/android/apg/Preferences.java b/src/org/thialfihar/android/apg/Preferences.java
index 0df29718c..705da21cc 100644
--- a/src/org/thialfihar/android/apg/Preferences.java
+++ b/src/org/thialfihar/android/apg/Preferences.java
@@ -103,6 +103,16 @@ public class Preferences {
editor.commit();
}
+ public boolean getForceV3Signatures() {
+ return mSharedPreferences.getBoolean(Constants.pref.force_v3_signatures, false);
+ }
+
+ public void setForceV3Signatures(boolean value) {
+ SharedPreferences.Editor editor = mSharedPreferences.edit();
+ editor.putBoolean(Constants.pref.force_v3_signatures, value);
+ editor.commit();
+ }
+
public boolean hasSeenChangeLog(String version) {
return mSharedPreferences.getBoolean(Constants.pref.has_seen_change_log + version,
false);
diff --git a/src/org/thialfihar/android/apg/PreferencesActivity.java b/src/org/thialfihar/android/apg/PreferencesActivity.java
index 6e7e6f657..c226a8b2a 100644
--- a/src/org/thialfihar/android/apg/PreferencesActivity.java
+++ b/src/org/thialfihar/android/apg/PreferencesActivity.java
@@ -37,6 +37,7 @@ public class PreferencesActivity extends PreferenceActivity {
private IntegerListPreference mMessageCompression = null;
private IntegerListPreference mFileCompression = null;
private CheckBoxPreference mAsciiArmour = null;
+ private CheckBoxPreference mForceV3Signatures = null;
private Preferences mPreferences;
@Override
@@ -210,6 +211,18 @@ public class PreferencesActivity extends PreferenceActivity {
return false;
}
});
+
+ mForceV3Signatures = (CheckBoxPreference) findPreference(Constants.pref.force_v3_signatures);
+ mForceV3Signatures.setChecked(mPreferences.getForceV3Signatures());
+ mForceV3Signatures.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
+ {
+ public boolean onPreferenceChange(Preference preference, Object newValue)
+ {
+ mForceV3Signatures.setChecked((Boolean)newValue);
+ mPreferences.setForceV3Signatures((Boolean)newValue);
+ return false;
+ }
+ });
}
}