mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-12-25 00:18:51 -05:00
trying to add support for various source and destination modes for encryption and decryption (String, byte[], filename, content stream), also more Intent options added
This commit is contained in:
parent
3ac472125a
commit
2c47734f0f
@ -117,7 +117,9 @@ public class Apg {
|
||||
public static final String EXTRA_STATUS = "status";
|
||||
public static final String EXTRA_ERROR = "error";
|
||||
public static final String EXTRA_DECRYPTED_MESSAGE = "decryptedMessage";
|
||||
public static final String EXTRA_DECRYPTED_DATA = "decryptedData";
|
||||
public static final String EXTRA_ENCRYPTED_MESSAGE = "encryptedMessage";
|
||||
public static final String EXTRA_ENCRYPTED_DATA = "encryptedData";
|
||||
public static final String EXTRA_RESULT_URI = "resultUri";
|
||||
public static final String EXTRA_SIGNATURE = "signature";
|
||||
public static final String EXTRA_SIGNATURE_KEY_ID = "signatureKeyId";
|
||||
@ -135,6 +137,8 @@ public class Apg {
|
||||
public static final String EXTRA_PROGRESS = "progress";
|
||||
public static final String EXTRA_MAX = "max";
|
||||
public static final String EXTRA_ACCOUNT = "account";
|
||||
public static final String EXTRA_ASCII_ARMOUR = "asciiArmour";
|
||||
public static final String EXTRA_BINARY = "binary";
|
||||
|
||||
public static final String AUTHORITY = DataProvider.AUTHORITY;
|
||||
|
||||
@ -576,7 +580,7 @@ public class Apg {
|
||||
}
|
||||
|
||||
public static Bundle importKeyRings(Activity context, int type,
|
||||
InputStream inStream, long dataLength,
|
||||
InputData data,
|
||||
ProgressDialogUpdater progress)
|
||||
throws GeneralException, FileNotFoundException, PGPException, IOException {
|
||||
Bundle returnData = new Bundle();
|
||||
@ -591,7 +595,7 @@ public class Apg {
|
||||
throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
|
||||
}
|
||||
|
||||
PositionAwareInputStream progressIn = new PositionAwareInputStream(inStream);
|
||||
PositionAwareInputStream progressIn = new PositionAwareInputStream(data.getInputStream());
|
||||
// need to have access to the bufferedInput, so we can reuse it for the possible
|
||||
// PGPObject chunks after the first one, e.g. files with several consecutive ASCII
|
||||
// armour blocks
|
||||
@ -637,7 +641,7 @@ public class Apg {
|
||||
} else if (retValue == Id.return_value.ok) {
|
||||
++newKeys;
|
||||
}
|
||||
progress.setProgress((int)(100 * progressIn.position() / dataLength), 100);
|
||||
progress.setProgress((int)(100 * progressIn.position() / data.getSize()), 100);
|
||||
obj = objectFactory.nextObject();
|
||||
}
|
||||
}
|
||||
@ -1110,8 +1114,7 @@ public class Apg {
|
||||
}
|
||||
|
||||
public static void encrypt(Context context,
|
||||
InputStream inStream, OutputStream outStream,
|
||||
long dataLength,
|
||||
InputData data, OutputStream outStream,
|
||||
boolean armored,
|
||||
long encryptionKeyIds[], long signatureKeyId,
|
||||
String signaturePassPhrase,
|
||||
@ -1213,14 +1216,15 @@ public class Apg {
|
||||
long done = 0;
|
||||
int n = 0;
|
||||
byte[] buffer = new byte[1 << 16];
|
||||
while ((n = inStream.read(buffer)) > 0) {
|
||||
InputStream in = data.getInputStream();
|
||||
while ((n = in.read(buffer)) > 0) {
|
||||
pOut.write(buffer, 0, n);
|
||||
if (signatureKeyId != 0) {
|
||||
signatureGenerator.update(buffer, 0, n);
|
||||
}
|
||||
done += n;
|
||||
if (dataLength != 0) {
|
||||
progress.setProgress((int) (20 + (95 - 20) * done / dataLength), 100);
|
||||
if (data.getSize() != 0) {
|
||||
progress.setProgress((int) (20 + (95 - 20) * done / data.getSize()), 100);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1242,7 +1246,7 @@ public class Apg {
|
||||
}
|
||||
|
||||
public static void signText(Context context,
|
||||
InputStream inStream, OutputStream outStream,
|
||||
InputData data, OutputStream outStream,
|
||||
long signatureKeyId, String signaturePassPhrase,
|
||||
int hashAlgorithm,
|
||||
ProgressDialogUpdater progress)
|
||||
@ -1294,6 +1298,7 @@ public class Apg {
|
||||
armorOut.beginClearText(hashAlgorithm);
|
||||
|
||||
ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
|
||||
InputStream inStream = data.getInputStream();
|
||||
int lookAhead = readInputLine(lineOut, inStream);
|
||||
|
||||
processLine(armorOut, signatureGenerator, lineOut.toByteArray());
|
||||
@ -1319,9 +1324,9 @@ public class Apg {
|
||||
progress.setProgress(R.string.progress_done, 100, 100);
|
||||
}
|
||||
|
||||
public static long getDecryptionKeyId(Context context, InputStream inStream)
|
||||
public static long getDecryptionKeyId(Context context, InputData data)
|
||||
throws GeneralException, NoAsymmetricEncryptionException, IOException {
|
||||
InputStream in = PGPUtil.getDecoderStream(inStream);
|
||||
InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
|
||||
PGPObjectFactory pgpF = new PGPObjectFactory(in);
|
||||
PGPEncryptedDataList enc;
|
||||
Object o = pgpF.nextObject();
|
||||
@ -1365,9 +1370,9 @@ public class Apg {
|
||||
return secretKey.getKeyID();
|
||||
}
|
||||
|
||||
public static boolean hasSymmetricEncryption(Context context, InputStream inStream)
|
||||
public static boolean hasSymmetricEncryption(Context context, InputData data)
|
||||
throws GeneralException, IOException {
|
||||
InputStream in = PGPUtil.getDecoderStream(inStream);
|
||||
InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
|
||||
PGPObjectFactory pgpF = new PGPObjectFactory(in);
|
||||
PGPEncryptedDataList enc;
|
||||
Object o = pgpF.nextObject();
|
||||
@ -1395,8 +1400,7 @@ public class Apg {
|
||||
}
|
||||
|
||||
public static Bundle decrypt(Context context,
|
||||
PositionAwareInputStream inStream, OutputStream outStream,
|
||||
long dataLength,
|
||||
InputData data, OutputStream outStream,
|
||||
String passPhrase, ProgressDialogUpdater progress,
|
||||
boolean assumeSymmetric)
|
||||
throws IOException, GeneralException, PGPException, SignatureException {
|
||||
@ -1404,7 +1408,7 @@ public class Apg {
|
||||
passPhrase = "";
|
||||
}
|
||||
Bundle returnData = new Bundle();
|
||||
InputStream in = PGPUtil.getDecoderStream(inStream);
|
||||
InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
|
||||
PGPObjectFactory pgpF = new PGPObjectFactory(in);
|
||||
PGPEncryptedDataList enc;
|
||||
Object o = pgpF.nextObject();
|
||||
@ -1557,7 +1561,7 @@ public class Apg {
|
||||
}
|
||||
int n = 0;
|
||||
int done = 0;
|
||||
long startPos = inStream.position();
|
||||
long startPos = data.getStreamPosition();
|
||||
while ((n = dataIn.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, n);
|
||||
done += n;
|
||||
@ -1571,11 +1575,11 @@ public class Apg {
|
||||
}
|
||||
// unknown size, but try to at least have a moving, slowing down progress bar
|
||||
currentProgress = startProgress + (endProgress - startProgress) * done / (done + 100000);
|
||||
if (dataLength - startPos == 0) {
|
||||
if (data.getSize() - startPos == 0) {
|
||||
currentProgress = endProgress;
|
||||
} else {
|
||||
currentProgress = (int)(startProgress + (endProgress - startProgress) *
|
||||
(inStream.position() - startPos) / (dataLength - startPos));
|
||||
(data.getStreamPosition() - startPos) / (data.getSize() - startPos));
|
||||
}
|
||||
progress.setProgress(currentProgress, 100);
|
||||
}
|
||||
@ -1609,13 +1613,13 @@ public class Apg {
|
||||
}
|
||||
|
||||
public static Bundle verifyText(Context context,
|
||||
InputStream inStream, OutputStream outStream,
|
||||
InputData data, OutputStream outStream,
|
||||
ProgressDialogUpdater progress)
|
||||
throws IOException, GeneralException, PGPException, SignatureException {
|
||||
Bundle returnData = new Bundle();
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ArmoredInputStream aIn = new ArmoredInputStream(inStream);
|
||||
ArmoredInputStream aIn = new ArmoredInputStream(data.getInputStream());
|
||||
|
||||
progress.setProgress(R.string.progress_done, 0, 100);
|
||||
|
||||
|
79
src/org/thialfihar/android/apg/DataDestination.java
Normal file
79
src/org/thialfihar/android/apg/DataDestination.java
Normal file
@ -0,0 +1,79 @@
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.thialfihar.android.apg.Apg.GeneralException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
|
||||
public class DataDestination {
|
||||
private String mStreamFilename;
|
||||
private String mFilename;
|
||||
private int mMode = Id.mode.undefined;
|
||||
|
||||
public DataDestination() {
|
||||
|
||||
}
|
||||
|
||||
public void setMode(int mode) {
|
||||
mMode = mode;
|
||||
}
|
||||
|
||||
public void setFilename(String filename) {
|
||||
mFilename = filename;
|
||||
}
|
||||
|
||||
public String getStreamFilename() {
|
||||
return mStreamFilename;
|
||||
}
|
||||
|
||||
protected OutputStream getOutputStream(Context context)
|
||||
throws Apg.GeneralException, FileNotFoundException, IOException {
|
||||
OutputStream out = null;
|
||||
mStreamFilename = null;
|
||||
|
||||
switch (mMode) {
|
||||
case Id.mode.stream: {
|
||||
try {
|
||||
while (true) {
|
||||
mStreamFilename = Apg.generateRandomString(32);
|
||||
if (mStreamFilename == null) {
|
||||
throw new Apg.GeneralException("couldn't generate random file name");
|
||||
}
|
||||
context.openFileInput(mStreamFilename).close();
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
// found a name that isn't used yet
|
||||
}
|
||||
out = context.openFileOutput(mStreamFilename, Context.MODE_PRIVATE);
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.mode.byte_array: {
|
||||
out = new ByteArrayOutputStream();
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.mode.file: {
|
||||
if (mFilename.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
|
||||
}
|
||||
}
|
||||
out = new FileOutputStream(mFilename);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
88
src/org/thialfihar/android/apg/DataSource.java
Normal file
88
src/org/thialfihar/android/apg/DataSource.java
Normal file
@ -0,0 +1,88 @@
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.thialfihar.android.apg.Apg.GeneralException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
|
||||
public class DataSource {
|
||||
private Uri mContentUri = null;
|
||||
private String mText = null;
|
||||
private byte[] mData = null;
|
||||
|
||||
public DataSource() {
|
||||
|
||||
}
|
||||
|
||||
public void setUri(Uri uri) {
|
||||
mContentUri = uri;
|
||||
}
|
||||
|
||||
public void setUri(String uri) {
|
||||
if (uri.startsWith("/")) {
|
||||
setUri(Uri.parse("file://" + uri));
|
||||
} else {
|
||||
setUri(Uri.parse(uri));
|
||||
}
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
mText = text;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
mData = data;
|
||||
}
|
||||
|
||||
public InputData getInputData(Context context, boolean withSize)
|
||||
throws GeneralException, FileNotFoundException, IOException {
|
||||
InputStream in = null;
|
||||
long size = 0;
|
||||
|
||||
if (mContentUri != null) {
|
||||
if (mContentUri.getScheme().equals("file")) {
|
||||
// get the rest after "file://"
|
||||
String path = mContentUri.toString().substring(6);
|
||||
if (path.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
|
||||
}
|
||||
}
|
||||
in = new FileInputStream(path);
|
||||
File file = new File(path);
|
||||
if (withSize) {
|
||||
size = file.length();
|
||||
}
|
||||
} else {
|
||||
in = context.getContentResolver().openInputStream(mContentUri);
|
||||
if (withSize) {
|
||||
InputStream tmp = context.getContentResolver().openInputStream(mContentUri);
|
||||
size = Apg.getLengthOfStream(tmp);
|
||||
tmp.close();
|
||||
}
|
||||
}
|
||||
} else if (mText != null || mData != null) {
|
||||
byte[] bytes = null;
|
||||
if (mData != null) {
|
||||
bytes = mData;
|
||||
} else {
|
||||
bytes = mText.getBytes();
|
||||
}
|
||||
in = new ByteArrayInputStream(bytes);
|
||||
if (withSize) {
|
||||
size = bytes.length;
|
||||
}
|
||||
}
|
||||
|
||||
return new InputData(in, size);
|
||||
}
|
||||
|
||||
}
|
@ -16,12 +16,9 @@
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@ -88,6 +85,11 @@ public class DecryptActivity extends BaseActivity {
|
||||
private String mOutputFilename = null;
|
||||
|
||||
private Uri mContentUri = null;
|
||||
private byte[] mData = null;
|
||||
private boolean mReturnBinary = false;
|
||||
|
||||
private DataSource mDataSource = null;
|
||||
private DataDestination mDataDestination = null;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@ -186,21 +188,26 @@ public class DecryptActivity extends BaseActivity {
|
||||
if (extras == null) {
|
||||
extras = new Bundle();
|
||||
}
|
||||
String data = extras.getString(Apg.EXTRA_TEXT);
|
||||
if (data != null) {
|
||||
Matcher matcher = Apg.PGP_MESSAGE.matcher(data);
|
||||
|
||||
mData = extras.getByteArray(Apg.EXTRA_DATA);
|
||||
String textData = null;
|
||||
if (mData == null) {
|
||||
textData = extras.getString(Apg.EXTRA_TEXT);
|
||||
}
|
||||
if (textData != null) {
|
||||
Matcher matcher = Apg.PGP_MESSAGE.matcher(textData);
|
||||
if (matcher.matches()) {
|
||||
data = matcher.group(1);
|
||||
textData = matcher.group(1);
|
||||
// replace non breakable spaces
|
||||
data = data.replaceAll("\\xa0", " ");
|
||||
mMessage.setText(data);
|
||||
textData = textData.replaceAll("\\xa0", " ");
|
||||
mMessage.setText(textData);
|
||||
} else {
|
||||
matcher = Apg.PGP_SIGNED_MESSAGE.matcher(data);
|
||||
matcher = Apg.PGP_SIGNED_MESSAGE.matcher(textData);
|
||||
if (matcher.matches()) {
|
||||
data = matcher.group(1);
|
||||
textData = matcher.group(1);
|
||||
// replace non breakable spaces
|
||||
data = data.replaceAll("\\xa0", " ");
|
||||
mMessage.setText(data);
|
||||
textData = textData.replaceAll("\\xa0", " ");
|
||||
mMessage.setText(textData);
|
||||
mDecryptButton.setText(R.string.btn_verify);
|
||||
}
|
||||
}
|
||||
@ -208,15 +215,12 @@ public class DecryptActivity extends BaseActivity {
|
||||
mReplyTo = extras.getString(Apg.EXTRA_REPLY_TO);
|
||||
mSubject = extras.getString(Apg.EXTRA_SUBJECT);
|
||||
} else if (Apg.Intent.DECRYPT_FILE.equals(mIntent.getAction())) {
|
||||
mInputFilename = mIntent.getDataString();
|
||||
if ("file".equals(mIntent.getScheme())) {
|
||||
mInputFilename = mIntent.getDataString().replace("file://", "");
|
||||
mFilename.setText(mInputFilename);
|
||||
guessOutputFilename();
|
||||
} else if ("content".equals(mIntent.getScheme())) {
|
||||
mInputFilename = mIntent.getDataString();
|
||||
mFilename.setText(mInputFilename);
|
||||
guessOutputFilename();
|
||||
mInputFilename = mInputFilename.substring(6);
|
||||
}
|
||||
mFilename.setText(mInputFilename);
|
||||
guessOutputFilename();
|
||||
mSource.setInAnimation(null);
|
||||
mSource.setOutAnimation(null);
|
||||
while (mSource.getCurrentView().getId() != R.id.sourceFile) {
|
||||
@ -224,11 +228,15 @@ public class DecryptActivity extends BaseActivity {
|
||||
}
|
||||
} else if (Apg.Intent.DECRYPT_AND_RETURN.equals(mIntent.getAction())) {
|
||||
mContentUri = mIntent.getData();
|
||||
Bundle extras = mIntent.getExtras();
|
||||
if (extras == null) {
|
||||
extras = new Bundle();
|
||||
}
|
||||
|
||||
mReturnBinary = extras.getBoolean(Apg.EXTRA_BINARY, false);
|
||||
|
||||
if (mContentUri == null) {
|
||||
Bundle extras = mIntent.getExtras();
|
||||
if (extras == null) {
|
||||
extras = new Bundle();
|
||||
}
|
||||
mData = extras.getByteArray(Apg.EXTRA_DATA);
|
||||
String data = extras.getString(Apg.EXTRA_TEXT);
|
||||
if (data != null) {
|
||||
Matcher matcher = Apg.PGP_MESSAGE.matcher(data);
|
||||
@ -397,19 +405,9 @@ public class DecryptActivity extends BaseActivity {
|
||||
// else treat it as an decrypted message/file
|
||||
mSignedOnly = false;
|
||||
String error = null;
|
||||
fillDataSource();
|
||||
try {
|
||||
InputStream in;
|
||||
if (mContentUri != null) {
|
||||
in = getContentResolver().openInputStream(mContentUri);
|
||||
} else if (mDecryptTarget == Id.target.file) {
|
||||
if (mInputFilename.startsWith("file")) {
|
||||
in = new FileInputStream(mInputFilename);
|
||||
} else {
|
||||
in = getContentResolver().openInputStream(Uri.parse(mInputFilename));
|
||||
}
|
||||
} else {
|
||||
in = new ByteArrayInputStream(mMessage.getText().toString().getBytes());
|
||||
}
|
||||
InputData in = mDataSource.getInputData(this, false);
|
||||
try {
|
||||
setSecretKeyId(Apg.getDecryptionKeyId(this, in));
|
||||
if (getSecretKeyId() == Id.key.none) {
|
||||
@ -418,19 +416,7 @@ public class DecryptActivity extends BaseActivity {
|
||||
mAssumeSymmetricEncryption = false;
|
||||
} catch (Apg.NoAsymmetricEncryptionException e) {
|
||||
setSecretKeyId(Id.key.symmetric);
|
||||
// look at the file/message again to check whether there's
|
||||
// symmetric encryption data in there
|
||||
if (mContentUri != null) {
|
||||
in = getContentResolver().openInputStream(mContentUri);
|
||||
} else if (mDecryptTarget == Id.target.file) {
|
||||
if (mInputFilename.startsWith("file")) {
|
||||
in = new FileInputStream(mInputFilename);
|
||||
} else {
|
||||
in = getContentResolver().openInputStream(Uri.parse(mInputFilename));
|
||||
}
|
||||
} else {
|
||||
in = new ByteArrayInputStream(mMessage.getText().toString().getBytes());
|
||||
}
|
||||
in = mDataSource.getInputData(this, false);
|
||||
if (!Apg.hasSymmetricEncryption(this, in)) {
|
||||
throw new Apg.GeneralException(getString(R.string.error_noKnownEncryptionFound));
|
||||
}
|
||||
@ -500,60 +486,32 @@ public class DecryptActivity extends BaseActivity {
|
||||
|
||||
Bundle data = new Bundle();
|
||||
Message msg = new Message();
|
||||
|
||||
fillDataSource();
|
||||
fillDataDestination();
|
||||
try {
|
||||
PositionAwareInputStream in = null;
|
||||
OutputStream out = null;
|
||||
String randomString = null;
|
||||
long size = 0;
|
||||
|
||||
if (mContentUri != null) {
|
||||
in = new PositionAwareInputStream(getContentResolver().openInputStream(mContentUri));
|
||||
size = Apg.getLengthOfStream(getContentResolver().openInputStream(mContentUri));
|
||||
try {
|
||||
while (true) {
|
||||
randomString = Apg.generateRandomString(32);
|
||||
if (randomString == null) {
|
||||
throw new Apg.GeneralException("couldn't generate random file name");
|
||||
}
|
||||
this.openFileInput(randomString).close();
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
// found a name that isn't used yet
|
||||
}
|
||||
out = openFileOutput(randomString, MODE_PRIVATE);
|
||||
} else if (mDecryptTarget == Id.target.message) {
|
||||
String messageData = mMessage.getText().toString();
|
||||
in = new PositionAwareInputStream(new ByteArrayInputStream(messageData.getBytes()));
|
||||
out = new ByteArrayOutputStream();
|
||||
size = messageData.getBytes().length;
|
||||
} else {
|
||||
if (mInputFilename.startsWith("content")) {
|
||||
size = Apg.getLengthOfStream(getContentResolver().openInputStream(Uri.parse(mInputFilename)));
|
||||
in = new PositionAwareInputStream(
|
||||
getContentResolver().openInputStream(Uri.parse(mInputFilename)));
|
||||
} else {
|
||||
in = new PositionAwareInputStream(new FileInputStream(mInputFilename));
|
||||
File file = new File(mInputFilename);
|
||||
size = file.length();
|
||||
}
|
||||
out = new FileOutputStream(mOutputFilename);
|
||||
}
|
||||
InputData in = mDataSource.getInputData(this, true);
|
||||
OutputStream out = mDataDestination.getOutputStream(this);
|
||||
|
||||
if (mSignedOnly) {
|
||||
data = Apg.verifyText(this, in, out, this);
|
||||
} else {
|
||||
data = Apg.decrypt(this, in, out, size, Apg.getCachedPassPhrase(getSecretKeyId()),
|
||||
data = Apg.decrypt(this, in, out, Apg.getCachedPassPhrase(getSecretKeyId()),
|
||||
this, mAssumeSymmetricEncryption);
|
||||
}
|
||||
|
||||
out.close();
|
||||
|
||||
if (randomString != null) {
|
||||
data.putString(Apg.EXTRA_RESULT_URI, "content://" + DataProvider.AUTHORITY + "/data/" + randomString);
|
||||
if (mDataDestination.getStreamFilename() != null) {
|
||||
data.putString(Apg.EXTRA_RESULT_URI, "content://" + DataProvider.AUTHORITY +
|
||||
"/data/" + mDataDestination.getStreamFilename());
|
||||
} else if (mDecryptTarget == Id.target.message) {
|
||||
data.putString(Apg.EXTRA_DECRYPTED_MESSAGE,
|
||||
new String(((ByteArrayOutputStream) out).toByteArray()));
|
||||
if (mReturnBinary) {
|
||||
data.putByteArray(Apg.EXTRA_DECRYPTED_DATA,
|
||||
((ByteArrayOutputStream) out).toByteArray());
|
||||
} else {
|
||||
data.putString(Apg.EXTRA_DECRYPTED_MESSAGE,
|
||||
new String(((ByteArrayOutputStream) out).toByteArray()));
|
||||
}
|
||||
}
|
||||
} catch (PGPException e) {
|
||||
error = "" + e;
|
||||
@ -727,4 +685,31 @@ public class DecryptActivity extends BaseActivity {
|
||||
|
||||
return super.onCreateDialog(id);
|
||||
}
|
||||
|
||||
protected void fillDataSource() {
|
||||
mDataSource = new DataSource();
|
||||
if (mContentUri != null) {
|
||||
mDataSource.setUri(mContentUri);
|
||||
} else if (mDecryptTarget == Id.target.file) {
|
||||
mDataSource.setUri(mInputFilename);
|
||||
} else {
|
||||
if (mData != null) {
|
||||
mDataSource.setData(mData);
|
||||
} else {
|
||||
mDataSource.setText(mMessage.getText().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void fillDataDestination() {
|
||||
mDataDestination = new DataDestination();
|
||||
if (mContentUri != null) {
|
||||
mDataDestination.setMode(Id.mode.stream);
|
||||
} else if (mDecryptTarget == Id.target.file) {
|
||||
mDataDestination.setFilename(mOutputFilename);
|
||||
mDataDestination.setMode(Id.mode.file);
|
||||
} else {
|
||||
mDataDestination.setMode(Id.mode.byte_array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,13 +16,9 @@
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
@ -34,8 +30,6 @@ import org.bouncycastle2.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle2.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle2.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle2.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle2.util.Strings;
|
||||
import org.thialfihar.android.apg.Apg.GeneralException;
|
||||
import org.thialfihar.android.apg.utils.Choice;
|
||||
|
||||
import android.app.Dialog;
|
||||
@ -43,7 +37,6 @@ import android.content.ActivityNotFoundException;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Message;
|
||||
import android.text.ClipboardManager;
|
||||
import android.view.View;
|
||||
@ -100,6 +93,14 @@ public class EncryptActivity extends BaseActivity {
|
||||
private String mInputFilename = null;
|
||||
private String mOutputFilename = null;
|
||||
|
||||
private boolean mAsciiArmourDemand = false;
|
||||
private boolean mOverrideAsciiArmour = false;
|
||||
private Uri mContentUri = null;
|
||||
private byte[] mData = null;
|
||||
|
||||
private DataSource mDataSource = null;
|
||||
private DataDestination mDataDestination = null;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@ -271,6 +272,7 @@ public class EncryptActivity extends BaseActivity {
|
||||
if (Apg.Intent.ENCRYPT.equals(mIntent.getAction()) ||
|
||||
Apg.Intent.ENCRYPT_FILE.equals(mIntent.getAction()) ||
|
||||
Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction())) {
|
||||
mContentUri = mIntent.getData();
|
||||
Bundle extras = mIntent.getExtras();
|
||||
if (extras == null) {
|
||||
extras = new Bundle();
|
||||
@ -280,7 +282,17 @@ public class EncryptActivity extends BaseActivity {
|
||||
mReturnResult = true;
|
||||
}
|
||||
|
||||
String data = extras.getString(Apg.EXTRA_TEXT);
|
||||
if (extras.containsKey(Apg.EXTRA_ASCII_ARMOUR)) {
|
||||
mAsciiArmourDemand = extras.getBoolean(Apg.EXTRA_ASCII_ARMOUR, true);
|
||||
mOverrideAsciiArmour = true;
|
||||
mAsciiArmour.setChecked(mAsciiArmourDemand);
|
||||
}
|
||||
|
||||
mData = extras.getByteArray(Apg.EXTRA_DATA);
|
||||
String textData = null;
|
||||
if (mData == null) {
|
||||
textData = extras.getString(Apg.EXTRA_TEXT);
|
||||
}
|
||||
mSendTo = extras.getString(Apg.EXTRA_SEND_TO);
|
||||
mSubject = extras.getString(Apg.EXTRA_SUBJECT);
|
||||
long signatureKeyId = extras.getLong(Apg.EXTRA_SIGNATURE_KEY_ID);
|
||||
@ -327,8 +339,8 @@ public class EncryptActivity extends BaseActivity {
|
||||
|
||||
if (Apg.Intent.ENCRYPT.equals(mIntent.getAction()) ||
|
||||
Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction())) {
|
||||
if (data != null) {
|
||||
mMessage.setText(data);
|
||||
if (textData != null) {
|
||||
mMessage.setText(textData);
|
||||
}
|
||||
mSource.setInAnimation(null);
|
||||
mSource.setOutAnimation(null);
|
||||
@ -548,11 +560,11 @@ public class EncryptActivity extends BaseActivity {
|
||||
String error = null;
|
||||
Bundle data = new Bundle();
|
||||
Message msg = new Message();
|
||||
|
||||
fillDataSource();
|
||||
fillDataDestination();
|
||||
try {
|
||||
InputStream in;
|
||||
InputData in;
|
||||
OutputStream out;
|
||||
long size;
|
||||
boolean useAsciiArmour = true;
|
||||
long encryptionKeyIds[] = null;
|
||||
long signatureKeyId = 0;
|
||||
@ -571,65 +583,28 @@ public class EncryptActivity extends BaseActivity {
|
||||
signOnly = (mEncryptionKeyIds == null || mEncryptionKeyIds.length == 0);
|
||||
}
|
||||
|
||||
// streams
|
||||
in = mDataSource.getInputData(this, true);
|
||||
out = mDataDestination.getOutputStream(this);
|
||||
|
||||
if (mEncryptTarget == Id.target.file) {
|
||||
if (mInputFilename.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath()) ||
|
||||
mOutputFilename.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
throw new GeneralException(getString(R.string.error_externalStorageNotReady));
|
||||
}
|
||||
}
|
||||
|
||||
if (mInputFilename.startsWith("content")) {
|
||||
in = getContentResolver().openInputStream(Uri.parse(mInputFilename));
|
||||
size = 0;
|
||||
long n = 0;
|
||||
byte dummy[] = new byte[0x10000];
|
||||
while ((n = in.read(dummy)) > 0) {
|
||||
size += n;
|
||||
}
|
||||
in = getContentResolver().openInputStream(Uri.parse(mInputFilename));
|
||||
} else {
|
||||
in = new FileInputStream(mInputFilename);
|
||||
File file = new File(mInputFilename);
|
||||
size = file.length();
|
||||
}
|
||||
out = new FileOutputStream(mOutputFilename);
|
||||
|
||||
useAsciiArmour = mAsciiArmour.isChecked();
|
||||
compressionId = ((Choice) mFileCompression.getSelectedItem()).getId();
|
||||
} else {
|
||||
String message = mMessage.getText().toString();
|
||||
|
||||
if (signOnly && !mReturnResult) {
|
||||
// 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");
|
||||
}
|
||||
|
||||
if (signOnly && !message.endsWith("\n")) {
|
||||
message += '\n';
|
||||
}
|
||||
|
||||
byte[] byteData = Strings.toUTF8ByteArray(message);
|
||||
in = new ByteArrayInputStream(byteData);
|
||||
out = new ByteArrayOutputStream();
|
||||
|
||||
size = byteData.length;
|
||||
useAsciiArmour = true;
|
||||
compressionId = mPreferences.getDefaultMessageCompression();
|
||||
}
|
||||
|
||||
if (mOverrideAsciiArmour) {
|
||||
useAsciiArmour = mAsciiArmourDemand;
|
||||
}
|
||||
|
||||
if (signOnly) {
|
||||
Apg.signText(this, in, out, getSecretKeyId(),
|
||||
Apg.getCachedPassPhrase(getSecretKeyId()),
|
||||
mPreferences.getDefaultHashAlgorithm(), this);
|
||||
} else {
|
||||
Apg.encrypt(this, in, out, size, useAsciiArmour,
|
||||
Apg.encrypt(this, in, out, useAsciiArmour,
|
||||
encryptionKeyIds, signatureKeyId,
|
||||
Apg.getCachedPassPhrase(signatureKeyId), this,
|
||||
mPreferences.getDefaultEncryptionAlgorithm(),
|
||||
@ -639,8 +614,13 @@ public class EncryptActivity extends BaseActivity {
|
||||
|
||||
out.close();
|
||||
if (mEncryptTarget != Id.target.file) {
|
||||
data.putString(Apg.EXTRA_ENCRYPTED_MESSAGE,
|
||||
new String(((ByteArrayOutputStream)out).toByteArray()));
|
||||
if (useAsciiArmour) {
|
||||
data.putString(Apg.EXTRA_ENCRYPTED_MESSAGE,
|
||||
new String(((ByteArrayOutputStream)out).toByteArray()));
|
||||
} else {
|
||||
data.putByteArray(Apg.EXTRA_ENCRYPTED_DATA,
|
||||
((ByteArrayOutputStream)out).toByteArray());
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
error = "" + e;
|
||||
@ -889,4 +869,31 @@ public class EncryptActivity extends BaseActivity {
|
||||
|
||||
return super.onCreateDialog(id);
|
||||
}
|
||||
|
||||
protected void fillDataSource() {
|
||||
mDataSource = new DataSource();
|
||||
if (mContentUri != null) {
|
||||
mDataSource.setUri(mContentUri);
|
||||
} else if (mEncryptTarget == Id.target.file) {
|
||||
mDataSource.setUri(mInputFilename);
|
||||
} else {
|
||||
if (mData != null) {
|
||||
mDataSource.setData(mData);
|
||||
} else {
|
||||
mDataSource.setText(mMessage.getText().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void fillDataDestination() {
|
||||
mDataDestination = new DataDestination();
|
||||
if (mContentUri != null) {
|
||||
mDataDestination.setMode(Id.mode.stream);
|
||||
} else if (mEncryptTarget == Id.target.file) {
|
||||
mDataDestination.setFilename(mOutputFilename);
|
||||
mDataDestination.setMode(Id.mode.file);
|
||||
} else {
|
||||
mDataDestination.setMode(Id.mode.byte_array);
|
||||
}
|
||||
}
|
||||
}
|
@ -14,11 +14,11 @@ import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
|
||||
public class GeneralActivity extends BaseActivity {
|
||||
private Intent mIntent;
|
||||
|
@ -135,6 +135,13 @@ public final class Id {
|
||||
public static final int message = 0x21070004;
|
||||
}
|
||||
|
||||
public static final class mode {
|
||||
public static final int undefined = 0x21070001;
|
||||
public static final int byte_array = 0x21070002;
|
||||
public static final int file = 0x21070003;
|
||||
public static final int stream = 0x21070004;
|
||||
}
|
||||
|
||||
public static final class key {
|
||||
public static final int none = 0;
|
||||
public static final int symmetric = -1;
|
||||
|
25
src/org/thialfihar/android/apg/InputData.java
Normal file
25
src/org/thialfihar/android/apg/InputData.java
Normal file
@ -0,0 +1,25 @@
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public class InputData {
|
||||
private PositionAwareInputStream mInputStream;
|
||||
private long mSize;
|
||||
|
||||
InputData(InputStream inputStream, long size) {
|
||||
mInputStream = new PositionAwareInputStream(inputStream);
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return mInputStream;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
public long getStreamPosition() {
|
||||
return mInputStream.position();
|
||||
}
|
||||
}
|
@ -48,15 +48,15 @@ import android.os.Message;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseExpandableListAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ExpandableListView;
|
||||
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
|
||||
|
||||
public class KeyListActivity extends BaseActivity {
|
||||
protected ExpandableListView mList;
|
||||
@ -328,7 +328,7 @@ public class KeyListActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
if (mTask == Id.task.import_keys) {
|
||||
data = Apg.importKeyRings(this, mKeyType, importInputStream, size, this);
|
||||
data = Apg.importKeyRings(this, mKeyType, new InputData(importInputStream, size), this);
|
||||
} else {
|
||||
Vector<Integer> keyRingIds = new Vector<Integer>();
|
||||
if (mSelectedItem == -1) {
|
||||
|
@ -30,11 +30,11 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.TextView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
|
||||
public class MailListActivity extends ListActivity {
|
||||
LayoutInflater mInflater = null;
|
||||
|
@ -29,21 +29,21 @@ import android.database.SQLException;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.CursorAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
|
||||
public class MainActivity extends BaseActivity {
|
||||
private ListView mAccounts = null;
|
||||
|
@ -18,7 +18,6 @@ package org.thialfihar.android.apg;
|
||||
|
||||
import org.bouncycastle2.bcpg.HashAlgorithmTags;
|
||||
import org.bouncycastle2.openpgp.PGPEncryptedData;
|
||||
import org.thialfihar.android.apg.utils.Choice;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
|
@ -18,9 +18,9 @@ package org.thialfihar.android.apg;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.widget.ExpandableListView;
|
||||
|
||||
public class PublicKeyListActivity extends KeyListActivity {
|
||||
|
@ -20,10 +20,10 @@ import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.widget.ExpandableListView;
|
||||
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
|
||||
import android.widget.ExpandableListView.OnChildClickListener;
|
||||
|
@ -23,10 +23,10 @@ import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
|
||||
public class SelectSecretKeyListActivity extends BaseActivity {
|
||||
protected ListView mList;
|
||||
|
Loading…
Reference in New Issue
Block a user