aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest.xml1
-rw-r--r--src/org/thialfihar/android/apg/Apg.java132
-rw-r--r--src/org/thialfihar/android/apg/DataSource.java10
-rw-r--r--src/org/thialfihar/android/apg/EncryptActivity.java44
4 files changed, 177 insertions, 10 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 0f57cd80c..f496d0f41 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -124,6 +124,7 @@
<action android:name="org.thialfihar.android.apg.intent.ENCRYPT" />
<action android:name="org.thialfihar.android.apg.intent.ENCRYPT_FILE" />
<action android:name="org.thialfihar.android.apg.intent.ENCRYPT_AND_RETURN" />
+ <action android:name="org.thialfihar.android.apg.intent.GENERATE_SIGNATURE" />
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="*/*"/>
</intent-filter>
diff --git a/src/org/thialfihar/android/apg/Apg.java b/src/org/thialfihar/android/apg/Apg.java
index 91532b64f..d3be3907c 100644
--- a/src/org/thialfihar/android/apg/Apg.java
+++ b/src/org/thialfihar/android/apg/Apg.java
@@ -118,6 +118,7 @@ public class Apg {
public static final String IMPORT = "org.thialfihar.android.apg.intent.IMPORT";
public static final String LOOK_UP_KEY_ID = "org.thialfihar.android.apg.intent.LOOK_UP_KEY_ID";
public static final String LOOK_UP_KEY_ID_AND_RETURN = "org.thialfihar.android.apg.intent.LOOK_UP_KEY_ID_AND_RETURN";
+ public static final String GENERATE_SIGNATURE = "org.thialfihar.android.apg.intent.GENERATE_SIGNATURE";
}
public static final String EXTRA_TEXT = "text";
@@ -133,6 +134,8 @@ public class Apg {
public static final String EXTRA_SIGNATURE_USER_ID = "signatureUserId";
public static final String EXTRA_SIGNATURE_SUCCESS = "signatureSuccess";
public static final String EXTRA_SIGNATURE_UNKNOWN = "signatureUnknown";
+ public static final String EXTRA_SIGNATURE_DATA = "signatureData";
+ public static final String EXTRA_SIGNATURE_TEXT = "signatureText";
public static final String EXTRA_USER_ID = "userId";
public static final String EXTRA_USER_IDS = "userIds";
public static final String EXTRA_KEY_ID = "keyId";
@@ -1426,6 +1429,127 @@ public class Apg {
progress.setProgress(R.string.progress_done, 100, 100);
}
+ public static void generateSignature(Context context,
+ InputData data, OutputStream outStream,
+ boolean armored, boolean binary,
+ long signatureKeyId, String signaturePassPhrase,
+ int hashAlgorithm,
+ boolean forceV3Signature,
+ ProgressDialogUpdater progress)
+ throws GeneralException, PGPException, IOException, NoSuchAlgorithmException,
+ SignatureException {
+ Security.addProvider(new BouncyCastleProvider());
+
+ ArmoredOutputStream armorOut = null;
+ OutputStream out = null;
+ if (armored) {
+ armorOut = new ArmoredOutputStream(outStream);
+ armorOut.setHeader("Version", getFullVersion(context));
+ out = armorOut;
+ } else {
+ out = outStream;
+ }
+
+ PGPSecretKey signingKey = null;
+ PGPSecretKeyRing signingKeyRing = null;
+ PGPPrivateKey signaturePrivateKey = null;
+
+ if (signatureKeyId == 0) {
+ throw new GeneralException(context.getString(R.string.error_noSignatureKey));
+ }
+
+ signingKeyRing = getSecretKeyRing(signatureKeyId);
+ signingKey = getSigningKey(signatureKeyId);
+ if (signingKey == null) {
+ throw new GeneralException(context.getString(R.string.error_signatureFailed));
+ }
+
+ if (signaturePassPhrase == null) {
+ throw new GeneralException(context.getString(R.string.error_noSignaturePassPhrase));
+ }
+ signaturePrivateKey =
+ signingKey.extractPrivateKey(signaturePassPhrase.toCharArray(),
+ new BouncyCastleProvider());
+ if (signaturePrivateKey == null) {
+ throw new GeneralException(context.getString(R.string.error_couldNotExtractPrivateKey));
+ }
+ progress.setProgress(R.string.progress_preparingStreams, 0, 100);
+
+ progress.setProgress(R.string.progress_preparingSignature, 30, 100);
+
+ PGPSignatureGenerator signatureGenerator = null;
+ PGPV3SignatureGenerator signatureV3Generator = null;
+
+ int type = PGPSignature.CANONICAL_TEXT_DOCUMENT;
+ if (binary) {
+ type = PGPSignature.BINARY_DOCUMENT;
+ }
+
+ if (forceV3Signature) {
+ signatureV3Generator =
+ new PGPV3SignatureGenerator(signingKey.getPublicKey().getAlgorithm(),
+ hashAlgorithm,
+ new BouncyCastleProvider());
+ signatureV3Generator.initSign(type, signaturePrivateKey);
+ } else {
+ signatureGenerator =
+ new PGPSignatureGenerator(signingKey.getPublicKey().getAlgorithm(),
+ hashAlgorithm,
+ new BouncyCastleProvider());
+ signatureGenerator.initSign(type, 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);
+
+ InputStream inStream = data.getInputStream();
+ if (binary) {
+ byte[] buffer = new byte[1 << 16];
+ int n = 0;
+ while ((n = inStream.read(buffer)) > 0) {
+ if (forceV3Signature) {
+ signatureV3Generator.update(buffer, 0, n);
+ } else {
+ signatureGenerator.update(buffer, 0, n);
+ }
+ }
+ } else {
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
+ final byte[] newline = "\r\n".getBytes("UTF-8");
+
+ while (true) {
+ final String line = reader.readLine();
+
+ if (line == null) {
+ break;
+ }
+
+ if (forceV3Signature) {
+ processLine(line, null, signatureV3Generator);
+ signatureV3Generator.update(newline);
+ } else {
+ processLine(line, null, signatureGenerator);
+ signatureGenerator.update(newline);
+ }
+ }
+ }
+
+ BCPGOutputStream bOut = new BCPGOutputStream(out);
+ if (forceV3Signature) {
+ signatureV3Generator.generate().encode(bOut);
+ } else {
+ signatureGenerator.generate().encode(bOut);
+ }
+ out.close();
+ outStream.close();
+
+ progress.setProgress(R.string.progress_done, 100, 100);
+ }
+
public static long getDecryptionKeyId(Context context, InputData data)
throws GeneralException, NoAsymmetricEncryptionException, IOException {
InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
@@ -1867,7 +1991,9 @@ public class Apg {
final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
- pArmoredOutput.write(data);
+ if (pArmoredOutput != null) {
+ pArmoredOutput.write(data);
+ }
pSignatureGenerator.update(data);
}
@@ -1892,7 +2018,9 @@ public class Apg {
final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
- pArmoredOutput.write(data);
+ if (pArmoredOutput != null) {
+ pArmoredOutput.write(data);
+ }
pSignatureGenerator.update(data);
}
diff --git a/src/org/thialfihar/android/apg/DataSource.java b/src/org/thialfihar/android/apg/DataSource.java
index 3ad1d0b07..4ce5c5f7b 100644
--- a/src/org/thialfihar/android/apg/DataSource.java
+++ b/src/org/thialfihar/android/apg/DataSource.java
@@ -36,10 +36,20 @@ public class DataSource {
public void setText(String text) {
mText = text;
+ mData = null;
}
public void setData(byte[] data) {
mData = data;
+ mText = null;
+ }
+
+ public boolean isText() {
+ return mText != null;
+ }
+
+ public boolean isBinary() {
+ return mData != null;
}
public InputData getInputData(Context context, boolean withSize)
diff --git a/src/org/thialfihar/android/apg/EncryptActivity.java b/src/org/thialfihar/android/apg/EncryptActivity.java
index ac9550788..066b0b483 100644
--- a/src/org/thialfihar/android/apg/EncryptActivity.java
+++ b/src/org/thialfihar/android/apg/EncryptActivity.java
@@ -101,11 +101,15 @@ public class EncryptActivity extends BaseActivity {
private DataSource mDataSource = null;
private DataDestination mDataDestination = null;
+ private boolean mGenerateSignature = false;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.encrypt);
+ mGenerateSignature = false;
+
mSource = (ViewFlipper) findViewById(R.id.source);
mSourceLabel = (TextView) findViewById(R.id.sourceLabel);
mSourcePrevious = (ImageView) findViewById(R.id.sourcePrevious);
@@ -271,17 +275,25 @@ public class EncryptActivity extends BaseActivity {
mIntent = getIntent();
if (Apg.Intent.ENCRYPT.equals(mIntent.getAction()) ||
Apg.Intent.ENCRYPT_FILE.equals(mIntent.getAction()) ||
- Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction())) {
+ Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction()) ||
+ Apg.Intent.GENERATE_SIGNATURE.equals(mIntent.getAction())) {
mContentUri = mIntent.getData();
Bundle extras = mIntent.getExtras();
if (extras == null) {
extras = new Bundle();
}
- if (Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction())) {
+ if (Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction()) ||
+ Apg.Intent.GENERATE_SIGNATURE.equals(mIntent.getAction())) {
mReturnResult = true;
}
+ if (Apg.Intent.GENERATE_SIGNATURE.equals(mIntent.getAction())) {
+ mGenerateSignature = true;
+ mOverrideAsciiArmour = true;
+ mAsciiArmourDemand = false;
+ }
+
if (extras.containsKey(Apg.EXTRA_ASCII_ARMOUR)) {
mAsciiArmourDemand = extras.getBoolean(Apg.EXTRA_ASCII_ARMOUR, true);
mOverrideAsciiArmour = true;
@@ -338,7 +350,8 @@ public class EncryptActivity extends BaseActivity {
}
if (Apg.Intent.ENCRYPT.equals(mIntent.getAction()) ||
- Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction())) {
+ Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction()) ||
+ Apg.Intent.GENERATE_SIGNATURE.equals(mIntent.getAction())) {
if (textData != null) {
mMessage.setText(textData);
}
@@ -660,7 +673,14 @@ public class EncryptActivity extends BaseActivity {
useAsciiArmour = mAsciiArmourDemand;
}
- if (signOnly) {
+ if (mGenerateSignature) {
+ Apg.generateSignature(this, in, out, useAsciiArmour, mDataSource.isBinary(),
+ getSecretKeyId(),
+ Apg.getCachedPassPhrase(getSecretKeyId()),
+ mPreferences.getDefaultHashAlgorithm(),
+ mPreferences.getForceV3Signatures(),
+ this);
+ } else if (signOnly) {
Apg.signText(this, in, out, getSecretKeyId(),
Apg.getCachedPassPhrase(getSecretKeyId()),
mPreferences.getDefaultHashAlgorithm(),
@@ -680,11 +700,19 @@ public class EncryptActivity extends BaseActivity {
out.close();
if (mEncryptTarget != Id.target.file) {
if (useAsciiArmour) {
- data.putString(Apg.EXTRA_ENCRYPTED_MESSAGE,
- new String(((ByteArrayOutputStream)out).toByteArray()));
+ String extraData = new String(((ByteArrayOutputStream)out).toByteArray());
+ if (mGenerateSignature) {
+ data.putString(Apg.EXTRA_SIGNATURE_TEXT, extraData);
+ } else {
+ data.putString(Apg.EXTRA_ENCRYPTED_MESSAGE, extraData);
+ }
} else {
- data.putByteArray(Apg.EXTRA_ENCRYPTED_DATA,
- ((ByteArrayOutputStream)out).toByteArray());
+ byte extraData[] = ((ByteArrayOutputStream)out).toByteArray();
+ if (mGenerateSignature) {
+ data.putByteArray(Apg.EXTRA_SIGNATURE_DATA, extraData);
+ } else {
+ data.putByteArray(Apg.EXTRA_ENCRYPTED_DATA, extraData);
+ }
}
}
} catch (IOException e) {