mirror of
https://github.com/moparisthebest/open-keychain
synced 2025-02-01 07:30:18 -05:00
Modify KeychainIntentService to support I/O with URIs, allow input and output to/from different types (eg. encrypt file and return byte array)
This commit is contained in:
parent
90f9646f25
commit
08d63340c9
@ -107,9 +107,11 @@ public class KeychainIntentService extends IntentService
|
|||||||
|
|
||||||
// encrypt, decrypt, import export
|
// encrypt, decrypt, import export
|
||||||
public static final String TARGET = "target";
|
public static final String TARGET = "target";
|
||||||
|
public static final String SOURCE = "source";
|
||||||
// possible targets:
|
// possible targets:
|
||||||
public static final int TARGET_BYTES = 1;
|
public static final int IO_BYTES = 1;
|
||||||
public static final int TARGET_URI = 2;
|
public static final int IO_FILE = 2; // This was misleadingly TARGET_URI before!
|
||||||
|
public static final int IO_URI = 3;
|
||||||
|
|
||||||
// encrypt
|
// encrypt
|
||||||
public static final String ENCRYPT_SIGNATURE_KEY_ID = "secret_key_id";
|
public static final String ENCRYPT_SIGNATURE_KEY_ID = "secret_key_id";
|
||||||
@ -118,7 +120,9 @@ public class KeychainIntentService extends IntentService
|
|||||||
public static final String ENCRYPT_COMPRESSION_ID = "compression_id";
|
public static final String ENCRYPT_COMPRESSION_ID = "compression_id";
|
||||||
public static final String ENCRYPT_MESSAGE_BYTES = "message_bytes";
|
public static final String ENCRYPT_MESSAGE_BYTES = "message_bytes";
|
||||||
public static final String ENCRYPT_INPUT_FILE = "input_file";
|
public static final String ENCRYPT_INPUT_FILE = "input_file";
|
||||||
|
public static final String ENCRYPT_INPUT_URI = "input_uri";
|
||||||
public static final String ENCRYPT_OUTPUT_FILE = "output_file";
|
public static final String ENCRYPT_OUTPUT_FILE = "output_file";
|
||||||
|
public static final String ENCRYPT_OUTPUT_URI = "output_uri";
|
||||||
public static final String ENCRYPT_SYMMETRIC_PASSPHRASE = "passphrase";
|
public static final String ENCRYPT_SYMMETRIC_PASSPHRASE = "passphrase";
|
||||||
|
|
||||||
// decrypt/verify
|
// decrypt/verify
|
||||||
@ -230,7 +234,7 @@ public class KeychainIntentService extends IntentService
|
|||||||
if (ACTION_ENCRYPT_SIGN.equals(action)) {
|
if (ACTION_ENCRYPT_SIGN.equals(action)) {
|
||||||
try {
|
try {
|
||||||
/* Input */
|
/* Input */
|
||||||
int target = data.getInt(TARGET);
|
int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET);
|
||||||
|
|
||||||
long signatureKeyId = data.getLong(ENCRYPT_SIGNATURE_KEY_ID);
|
long signatureKeyId = data.getLong(ENCRYPT_SIGNATURE_KEY_ID);
|
||||||
String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE);
|
String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE);
|
||||||
@ -238,71 +242,8 @@ public class KeychainIntentService extends IntentService
|
|||||||
boolean useAsciiArmor = data.getBoolean(ENCRYPT_USE_ASCII_ARMOR);
|
boolean useAsciiArmor = data.getBoolean(ENCRYPT_USE_ASCII_ARMOR);
|
||||||
long encryptionKeyIds[] = data.getLongArray(ENCRYPT_ENCRYPTION_KEYS_IDS);
|
long encryptionKeyIds[] = data.getLongArray(ENCRYPT_ENCRYPTION_KEYS_IDS);
|
||||||
int compressionId = data.getInt(ENCRYPT_COMPRESSION_ID);
|
int compressionId = data.getInt(ENCRYPT_COMPRESSION_ID);
|
||||||
InputStream inStream;
|
InputData inputData = createEncryptInputData(data);
|
||||||
long inLength;
|
OutputStream outStream = createCryptOutputStream(data);
|
||||||
InputData inputData;
|
|
||||||
OutputStream outStream;
|
|
||||||
// String streamFilename = null;
|
|
||||||
switch (target) {
|
|
||||||
case TARGET_BYTES: /* encrypting bytes directly */
|
|
||||||
byte[] bytes = data.getByteArray(ENCRYPT_MESSAGE_BYTES);
|
|
||||||
|
|
||||||
inStream = new ByteArrayInputStream(bytes);
|
|
||||||
inLength = bytes.length;
|
|
||||||
|
|
||||||
inputData = new InputData(inStream, inLength);
|
|
||||||
outStream = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
break;
|
|
||||||
case TARGET_URI: /* encrypting file */
|
|
||||||
String inputFile = data.getString(ENCRYPT_INPUT_FILE);
|
|
||||||
String outputFile = data.getString(ENCRYPT_OUTPUT_FILE);
|
|
||||||
|
|
||||||
// check if storage is ready
|
|
||||||
if (!FileHelper.isStorageMounted(inputFile)
|
|
||||||
|| !FileHelper.isStorageMounted(outputFile)) {
|
|
||||||
throw new PgpGeneralException(
|
|
||||||
getString(R.string.error_external_storage_not_ready));
|
|
||||||
}
|
|
||||||
|
|
||||||
inStream = new FileInputStream(inputFile);
|
|
||||||
File file = new File(inputFile);
|
|
||||||
inLength = file.length();
|
|
||||||
inputData = new InputData(inStream, inLength);
|
|
||||||
|
|
||||||
outStream = new FileOutputStream(outputFile);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
// TODO: not used currently
|
|
||||||
// case TARGET_STREAM: /* Encrypting stream from content uri */
|
|
||||||
// Uri providerUri = (Uri) data.getParcelable(ENCRYPT_PROVIDER_URI);
|
|
||||||
//
|
|
||||||
// // InputStream
|
|
||||||
// InputStream in = getContentResolver().openInputStream(providerUri);
|
|
||||||
// inLength = PgpHelper.getLengthOfStream(in);
|
|
||||||
// inputData = new InputData(in, inLength);
|
|
||||||
//
|
|
||||||
// // OutputStream
|
|
||||||
// try {
|
|
||||||
// while (true) {
|
|
||||||
// streamFilename = PgpHelper.generateRandomFilename(32);
|
|
||||||
// if (streamFilename == null) {
|
|
||||||
// throw new PgpGeneralException("couldn't generate random file name");
|
|
||||||
// }
|
|
||||||
// openFileInput(streamFilename).close();
|
|
||||||
// }
|
|
||||||
// } catch (FileNotFoundException e) {
|
|
||||||
// // found a name that isn't used yet
|
|
||||||
// }
|
|
||||||
// outStream = openFileOutput(streamFilename, Context.MODE_PRIVATE);
|
|
||||||
//
|
|
||||||
// break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new PgpGeneralException("No target choosen!");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Operation */
|
/* Operation */
|
||||||
PgpSignEncrypt.Builder builder =
|
PgpSignEncrypt.Builder builder =
|
||||||
@ -327,7 +268,7 @@ public class KeychainIntentService extends IntentService
|
|||||||
PassphraseCacheService.getCachedPassphrase(this, signatureKeyId));
|
PassphraseCacheService.getCachedPassphrase(this, signatureKeyId));
|
||||||
|
|
||||||
// this assumes that the bytes are cleartext (valid for current implementation!)
|
// this assumes that the bytes are cleartext (valid for current implementation!)
|
||||||
if (target == TARGET_BYTES) {
|
if (source == IO_BYTES) {
|
||||||
builder.setCleartextInput(true);
|
builder.setCleartextInput(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,24 +279,7 @@ public class KeychainIntentService extends IntentService
|
|||||||
/* Output */
|
/* Output */
|
||||||
|
|
||||||
Bundle resultData = new Bundle();
|
Bundle resultData = new Bundle();
|
||||||
|
finalizeEncryptOutputStream(data, resultData, outStream);
|
||||||
switch (target) {
|
|
||||||
case TARGET_BYTES:
|
|
||||||
byte output[] = ((ByteArrayOutputStream) outStream).toByteArray();
|
|
||||||
|
|
||||||
resultData.putByteArray(RESULT_BYTES, output);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case TARGET_URI:
|
|
||||||
// nothing, file was written, just send okay
|
|
||||||
|
|
||||||
break;
|
|
||||||
// case TARGET_STREAM:
|
|
||||||
// String uri = DataStream.buildDataStreamUri(streamFilename).toString();
|
|
||||||
// resultData.putString(RESULT_URI, uri);
|
|
||||||
//
|
|
||||||
// break;
|
|
||||||
}
|
|
||||||
|
|
||||||
OtherHelper.logDebugBundle(resultData, "resultData");
|
OtherHelper.logDebugBundle(resultData, "resultData");
|
||||||
|
|
||||||
@ -366,78 +290,10 @@ public class KeychainIntentService extends IntentService
|
|||||||
} else if (ACTION_DECRYPT_VERIFY.equals(action)) {
|
} else if (ACTION_DECRYPT_VERIFY.equals(action)) {
|
||||||
try {
|
try {
|
||||||
/* Input */
|
/* Input */
|
||||||
int target = data.getInt(TARGET);
|
|
||||||
|
|
||||||
byte[] bytes = data.getByteArray(DECRYPT_CIPHERTEXT_BYTES);
|
|
||||||
String passphrase = data.getString(DECRYPT_PASSPHRASE);
|
String passphrase = data.getString(DECRYPT_PASSPHRASE);
|
||||||
|
|
||||||
InputStream inStream;
|
InputData inputData = createDecryptInputData(data);
|
||||||
long inLength;
|
OutputStream outStream = createCryptOutputStream(data);
|
||||||
InputData inputData;
|
|
||||||
OutputStream outStream;
|
|
||||||
String streamFilename = null;
|
|
||||||
switch (target) {
|
|
||||||
case TARGET_BYTES: /* decrypting bytes directly */
|
|
||||||
inStream = new ByteArrayInputStream(bytes);
|
|
||||||
inLength = bytes.length;
|
|
||||||
|
|
||||||
inputData = new InputData(inStream, inLength);
|
|
||||||
outStream = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TARGET_URI: /* decrypting file */
|
|
||||||
String inputFile = data.getString(ENCRYPT_INPUT_FILE);
|
|
||||||
String outputFile = data.getString(ENCRYPT_OUTPUT_FILE);
|
|
||||||
|
|
||||||
// check if storage is ready
|
|
||||||
if (!FileHelper.isStorageMounted(inputFile)
|
|
||||||
|| !FileHelper.isStorageMounted(outputFile)) {
|
|
||||||
throw new PgpGeneralException(
|
|
||||||
getString(R.string.error_external_storage_not_ready));
|
|
||||||
}
|
|
||||||
|
|
||||||
// InputStream
|
|
||||||
inLength = -1;
|
|
||||||
inStream = new FileInputStream(inputFile);
|
|
||||||
File file = new File(inputFile);
|
|
||||||
inLength = file.length();
|
|
||||||
inputData = new InputData(inStream, inLength);
|
|
||||||
|
|
||||||
// OutputStream
|
|
||||||
outStream = new FileOutputStream(outputFile);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
// TODO: not used, maybe contains code useful for new decrypt method for files?
|
|
||||||
// case TARGET_STREAM: /* decrypting stream from content uri */
|
|
||||||
// Uri providerUri = (Uri) data.getParcelable(ENCRYPT_PROVIDER_URI);
|
|
||||||
//
|
|
||||||
// // InputStream
|
|
||||||
// InputStream in = getContentResolver().openInputStream(providerUri);
|
|
||||||
// inLength = PgpHelper.getLengthOfStream(in);
|
|
||||||
// inputData = new InputData(in, inLength);
|
|
||||||
//
|
|
||||||
// // OutputStream
|
|
||||||
// try {
|
|
||||||
// while (true) {
|
|
||||||
// streamFilename = PgpHelper.generateRandomFilename(32);
|
|
||||||
// if (streamFilename == null) {
|
|
||||||
// throw new PgpGeneralException("couldn't generate random file name");
|
|
||||||
// }
|
|
||||||
// openFileInput(streamFilename).close();
|
|
||||||
// }
|
|
||||||
// } catch (FileNotFoundException e) {
|
|
||||||
// // found a name that isn't used yet
|
|
||||||
// }
|
|
||||||
// outStream = openFileOutput(streamFilename, Context.MODE_PRIVATE);
|
|
||||||
//
|
|
||||||
// break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new PgpGeneralException("No target choosen!");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Operation */
|
/* Operation */
|
||||||
|
|
||||||
@ -468,21 +324,7 @@ public class KeychainIntentService extends IntentService
|
|||||||
|
|
||||||
/* Output */
|
/* Output */
|
||||||
|
|
||||||
switch (target) {
|
finalizeDecryptOutputStream(data, resultData, outStream);
|
||||||
case TARGET_BYTES:
|
|
||||||
byte output[] = ((ByteArrayOutputStream) outStream).toByteArray();
|
|
||||||
resultData.putByteArray(RESULT_DECRYPTED_BYTES, output);
|
|
||||||
break;
|
|
||||||
case TARGET_URI:
|
|
||||||
// nothing, file was written, just send okay and verification bundle
|
|
||||||
|
|
||||||
break;
|
|
||||||
// case TARGET_STREAM:
|
|
||||||
// String uri = DataStream.buildDataStreamUri(streamFilename).toString();
|
|
||||||
// resultData.putString(RESULT_URI, uri);
|
|
||||||
//
|
|
||||||
// break;
|
|
||||||
}
|
|
||||||
|
|
||||||
OtherHelper.logDebugBundle(resultData, "resultData");
|
OtherHelper.logDebugBundle(resultData, "resultData");
|
||||||
|
|
||||||
@ -915,4 +757,95 @@ public class KeychainIntentService extends IntentService
|
|||||||
public boolean hasServiceStopped() {
|
public boolean hasServiceStopped() {
|
||||||
return mIsCanceled;
|
return mIsCanceled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InputData createDecryptInputData(Bundle data) throws IOException, PgpGeneralException {
|
||||||
|
return createCryptInputData(data, DECRYPT_CIPHERTEXT_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
private InputData createEncryptInputData(Bundle data) throws IOException, PgpGeneralException {
|
||||||
|
return createCryptInputData(data, ENCRYPT_MESSAGE_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
private InputData createCryptInputData(Bundle data, String bytesName) throws PgpGeneralException, IOException {
|
||||||
|
int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET);
|
||||||
|
switch (source) {
|
||||||
|
case IO_BYTES: /* encrypting bytes directly */
|
||||||
|
byte[] bytes = data.getByteArray(bytesName);
|
||||||
|
return new InputData(new ByteArrayInputStream(bytes), bytes.length);
|
||||||
|
|
||||||
|
case IO_FILE: /* encrypting file */
|
||||||
|
String inputFile = data.getString(ENCRYPT_INPUT_FILE);
|
||||||
|
|
||||||
|
// check if storage is ready
|
||||||
|
if (!FileHelper.isStorageMounted(inputFile)) {
|
||||||
|
throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new InputData(new FileInputStream(inputFile), new File(inputFile).length());
|
||||||
|
|
||||||
|
case IO_URI: /* encrypting content uri */
|
||||||
|
Uri providerUri = data.getParcelable(ENCRYPT_INPUT_URI);
|
||||||
|
|
||||||
|
// InputStream
|
||||||
|
InputStream in = getContentResolver().openInputStream(providerUri);
|
||||||
|
return new InputData(in, PgpHelper.getLengthOfStream(in));
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new PgpGeneralException("No target choosen!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private OutputStream createCryptOutputStream(Bundle data) throws PgpGeneralException, FileNotFoundException {
|
||||||
|
int target = data.getInt(TARGET);
|
||||||
|
switch (target) {
|
||||||
|
case IO_BYTES:
|
||||||
|
return new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
case IO_FILE:
|
||||||
|
String outputFile = data.getString(ENCRYPT_OUTPUT_FILE);
|
||||||
|
|
||||||
|
// check if storage is ready
|
||||||
|
if (!FileHelper.isStorageMounted(outputFile)) {
|
||||||
|
throw new PgpGeneralException(
|
||||||
|
getString(R.string.error_external_storage_not_ready));
|
||||||
|
}
|
||||||
|
|
||||||
|
// OutputStream
|
||||||
|
return new FileOutputStream(outputFile);
|
||||||
|
|
||||||
|
case IO_URI:
|
||||||
|
Uri providerUri = data.getParcelable(ENCRYPT_OUTPUT_URI);
|
||||||
|
|
||||||
|
return getContentResolver().openOutputStream(providerUri);
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new PgpGeneralException("No target choosen!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void finalizeEncryptOutputStream(Bundle data, Bundle resultData, OutputStream outStream) {
|
||||||
|
finalizeCryptOutputStream(data, resultData, outStream, RESULT_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void finalizeDecryptOutputStream(Bundle data, Bundle resultData, OutputStream outStream) {
|
||||||
|
finalizeCryptOutputStream(data, resultData, outStream, RESULT_DECRYPTED_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void finalizeCryptOutputStream(Bundle data, Bundle resultData, OutputStream outStream, String bytesName) {
|
||||||
|
int target = data.getInt(TARGET);
|
||||||
|
switch (target) {
|
||||||
|
case IO_BYTES:
|
||||||
|
byte output[] = ((ByteArrayOutputStream) outStream).toByteArray();
|
||||||
|
resultData.putByteArray(bytesName, output);
|
||||||
|
break;
|
||||||
|
case IO_FILE:
|
||||||
|
// nothing, file was written, just send okay and verification bundle
|
||||||
|
|
||||||
|
break;
|
||||||
|
case IO_URI:
|
||||||
|
// nothing, output was written, just send okay and verification bundle
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ public class DecryptFileFragment extends DecryptFragment {
|
|||||||
intent.setAction(KeychainIntentService.ACTION_DECRYPT_VERIFY);
|
intent.setAction(KeychainIntentService.ACTION_DECRYPT_VERIFY);
|
||||||
|
|
||||||
// data
|
// data
|
||||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_URI);
|
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_FILE);
|
||||||
|
|
||||||
Log.d(Constants.TAG, "mInputFilename=" + mInputFilename + ", mOutputFilename="
|
Log.d(Constants.TAG, "mInputFilename=" + mInputFilename + ", mOutputFilename="
|
||||||
+ mOutputFilename);
|
+ mOutputFilename);
|
||||||
|
@ -129,7 +129,7 @@ public class DecryptMessageFragment extends DecryptFragment {
|
|||||||
intent.setAction(KeychainIntentService.ACTION_DECRYPT_VERIFY);
|
intent.setAction(KeychainIntentService.ACTION_DECRYPT_VERIFY);
|
||||||
|
|
||||||
// data
|
// data
|
||||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_BYTES);
|
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_BYTES);
|
||||||
data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, mCiphertext.getBytes());
|
data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, mCiphertext.getBytes());
|
||||||
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, passphrase);
|
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, passphrase);
|
||||||
|
|
||||||
|
@ -280,7 +280,7 @@ public class EncryptFileFragment extends Fragment {
|
|||||||
// fill values for this action
|
// fill values for this action
|
||||||
Bundle data = new Bundle();
|
Bundle data = new Bundle();
|
||||||
|
|
||||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_URI);
|
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_FILE);
|
||||||
|
|
||||||
if (mEncryptInterface.isModeSymmetric()) {
|
if (mEncryptInterface.isModeSymmetric()) {
|
||||||
Log.d(Constants.TAG, "Symmetric encryption enabled!");
|
Log.d(Constants.TAG, "Symmetric encryption enabled!");
|
||||||
|
@ -177,7 +177,7 @@ public class EncryptMessageFragment extends Fragment {
|
|||||||
// fill values for this action
|
// fill values for this action
|
||||||
Bundle data = new Bundle();
|
Bundle data = new Bundle();
|
||||||
|
|
||||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_BYTES);
|
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_BYTES);
|
||||||
|
|
||||||
String message = mMessage.getText().toString();
|
String message = mMessage.getText().toString();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user