Get original filename for decryption

This commit is contained in:
Dominik Schürmann 2014-08-11 17:10:47 +02:00
parent 549feb69ed
commit b673565035
4 changed files with 188 additions and 20 deletions

View File

@ -71,6 +71,7 @@ public class PgpDecryptVerify {
private boolean mAllowSymmetricDecryption; private boolean mAllowSymmetricDecryption;
private String mPassphrase; private String mPassphrase;
private Set<Long> mAllowedKeyIds; private Set<Long> mAllowedKeyIds;
private boolean mReturnMetadataOnly;
private PgpDecryptVerify(Builder builder) { private PgpDecryptVerify(Builder builder) {
// private Constructor can only be called from Builder // private Constructor can only be called from Builder
@ -83,6 +84,7 @@ public class PgpDecryptVerify {
this.mAllowSymmetricDecryption = builder.mAllowSymmetricDecryption; this.mAllowSymmetricDecryption = builder.mAllowSymmetricDecryption;
this.mPassphrase = builder.mPassphrase; this.mPassphrase = builder.mPassphrase;
this.mAllowedKeyIds = builder.mAllowedKeyIds; this.mAllowedKeyIds = builder.mAllowedKeyIds;
this.mReturnMetadataOnly = builder.mReturnMetadataOnly;
} }
public static class Builder { public static class Builder {
@ -97,6 +99,7 @@ public class PgpDecryptVerify {
private boolean mAllowSymmetricDecryption = true; private boolean mAllowSymmetricDecryption = true;
private String mPassphrase = null; private String mPassphrase = null;
private Set<Long> mAllowedKeyIds = null; private Set<Long> mAllowedKeyIds = null;
private boolean mReturnMetadataOnly = false;
public Builder(ProviderHelper providerHelper, PassphraseCache passphraseCache, public Builder(ProviderHelper providerHelper, PassphraseCache passphraseCache,
InputData data, OutputStream outStream) { InputData data, OutputStream outStream) {
@ -126,7 +129,16 @@ public class PgpDecryptVerify {
* This means only ciphertexts encrypted for one of these private key can be decrypted. * This means only ciphertexts encrypted for one of these private key can be decrypted.
*/ */
public Builder setAllowedKeyIds(Set<Long> allowedKeyIds) { public Builder setAllowedKeyIds(Set<Long> allowedKeyIds) {
this.mAllowedKeyIds = allowedKeyIds; mAllowedKeyIds = allowedKeyIds;
return this;
}
/**
* If enabled, the actual decryption/verification of the content will not be executed.
* The metadata only will be decrypted and returned.
*/
public Builder setReturnMetadataOnly(boolean returnMetadataOnly) {
mReturnMetadataOnly = returnMetadataOnly;
return this; return this;
} }
@ -442,7 +454,7 @@ public class PgpDecryptVerify {
PGPLiteralData literalData = (PGPLiteralData) dataChunk; PGPLiteralData literalData = (PGPLiteralData) dataChunk;
// TODO: how to get the real original size? // TODO: how to get the real original size?
// this is the encrypted size // this is the encrypted size so if we enable compression this value is wrong!
long originalSize = mData.getSize() - mData.getStreamPosition(); long originalSize = mData.getSize() - mData.getStreamPosition();
if (originalSize < 0) { if (originalSize < 0) {
originalSize = 0; originalSize = 0;
@ -455,6 +467,13 @@ public class PgpDecryptVerify {
originalSize); originalSize);
result.setDecryptMetadata(metadata); result.setDecryptMetadata(metadata);
Log.d(Constants.TAG, "metadata: " + metadata);
// return here if we want to decrypt the metadata only
if (mReturnMetadataOnly) {
return result;
}
int endProgress; int endProgress;
if (signature != null) { if (signature != null) {
endProgress = 90; endProgress = 90;

View File

@ -86,6 +86,8 @@ public class KeychainIntentService extends IntentService
public static final String ACTION_DECRYPT_VERIFY = Constants.INTENT_PREFIX + "DECRYPT_VERIFY"; public static final String ACTION_DECRYPT_VERIFY = Constants.INTENT_PREFIX + "DECRYPT_VERIFY";
public static final String ACTION_DECRYPT_METADATA = Constants.INTENT_PREFIX + "DECRYPT_METADATA";
public static final String ACTION_SAVE_KEYRING = Constants.INTENT_PREFIX + "SAVE_KEYRING"; public static final String ACTION_SAVE_KEYRING = Constants.INTENT_PREFIX + "SAVE_KEYRING";
public static final String ACTION_DELETE_FILE_SECURELY = Constants.INTENT_PREFIX public static final String ACTION_DELETE_FILE_SECURELY = Constants.INTENT_PREFIX
@ -241,6 +243,7 @@ public class KeychainIntentService extends IntentService
data.putInt(SELECTED_URI, i); data.putInt(SELECTED_URI, i);
InputData inputData = createEncryptInputData(data); InputData inputData = createEncryptInputData(data);
OutputStream outStream = createCryptOutputStream(data); OutputStream outStream = createCryptOutputStream(data);
String originalFilename = getOriginalFilename(data);
/* Operation */ /* Operation */
PgpSignEncrypt.Builder builder = PgpSignEncrypt.Builder builder =
@ -262,7 +265,8 @@ public class KeychainIntentService extends IntentService
.setSignatureHashAlgorithm( .setSignatureHashAlgorithm(
Preferences.getPreferences(this).getDefaultHashAlgorithm()) Preferences.getPreferences(this).getDefaultHashAlgorithm())
.setSignaturePassphrase( .setSignaturePassphrase(
PassphraseCacheService.getCachedPassphrase(this, signatureKeyId)); PassphraseCacheService.getCachedPassphrase(this, signatureKeyId))
.setOriginalFilename(originalFilename);
// this assumes that the bytes are cleartext (valid for current implementation!) // this assumes that the bytes are cleartext (valid for current implementation!)
if (source == IO_BYTES) { if (source == IO_BYTES) {
@ -308,10 +312,10 @@ public class KeychainIntentService extends IntentService
KeychainIntentService.this, masterKeyId); KeychainIntentService.this, masterKeyId);
} }
}, },
inputData, outStream); inputData, outStream
builder.setProgressable(this); );
builder.setProgressable(this)
builder.setAllowSymmetricDecryption(true) .setAllowSymmetricDecryption(true)
.setPassphrase(passphrase); .setPassphrase(passphrase);
PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute(); PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute();
@ -326,6 +330,46 @@ public class KeychainIntentService extends IntentService
OtherHelper.logDebugBundle(resultData, "resultData"); OtherHelper.logDebugBundle(resultData, "resultData");
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
} catch (Exception e) {
sendErrorToHandler(e);
}
} else if (ACTION_DECRYPT_METADATA.equals(action)) {
try {
/* Input */
String passphrase = data.getString(DECRYPT_PASSPHRASE);
InputData inputData = createDecryptInputData(data);
/* Operation */
Bundle resultData = new Bundle();
// verifyText and decrypt returning additional resultData values for the
// verification of signatures
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
new ProviderHelper(this),
new PgpDecryptVerify.PassphraseCache() {
@Override
public String getCachedPassphrase(long masterKeyId) {
return PassphraseCacheService.getCachedPassphrase(
KeychainIntentService.this, masterKeyId);
}
},
inputData, null
);
builder.setProgressable(this)
.setAllowSymmetricDecryption(true)
.setPassphrase(passphrase)
.setReturnMetadataOnly(true);
PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute();
resultData.putParcelable(RESULT_DECRYPT_VERIFY_RESULT, decryptVerifyResult);
/* Output */
OtherHelper.logDebugBundle(resultData, "resultData");
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
} catch (Exception e) { } catch (Exception e) {
sendErrorToHandler(e); sendErrorToHandler(e);
@ -356,7 +400,7 @@ public class KeychainIntentService extends IntentService
UncachedKeyRing ring = result.getRing(); UncachedKeyRing ring = result.getRing();
providerHelper.saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100)); providerHelper.saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100));
// cache new passphrase // cache new passphrase
if (saveParcel.mNewPassphrase != null) { if (saveParcel.mNewPassphrase != null) {
@ -403,7 +447,7 @@ public class KeychainIntentService extends IntentService
} else { } else {
// get entries from cached file // get entries from cached file
FileImportCache<ParcelableKeyRing> cache = FileImportCache<ParcelableKeyRing> cache =
new FileImportCache<ParcelableKeyRing>(this); new FileImportCache<ParcelableKeyRing>(this);
entries = cache.readCacheIntoList(); entries = cache.readCacheIntoList();
} }
@ -576,7 +620,7 @@ public class KeychainIntentService extends IntentService
CanonicalizedPublicKeyRing publicRing = providerHelper.getCanonicalizedPublicKeyRing(pubKeyId); CanonicalizedPublicKeyRing publicRing = providerHelper.getCanonicalizedPublicKeyRing(pubKeyId);
CanonicalizedSecretKeyRing secretKeyRing = providerHelper.getCanonicalizedSecretKeyRing(masterKeyId); CanonicalizedSecretKeyRing secretKeyRing = providerHelper.getCanonicalizedSecretKeyRing(masterKeyId);
CanonicalizedSecretKey certificationKey = secretKeyRing.getSecretKey(); CanonicalizedSecretKey certificationKey = secretKeyRing.getSecretKey();
if(!certificationKey.unlock(signaturePassphrase)) { if (!certificationKey.unlock(signaturePassphrase)) {
throw new PgpGeneralException("Error extracting key (bad passphrase?)"); throw new PgpGeneralException("Error extracting key (bad passphrase?)");
} }
UncachedKeyRing newRing = certificationKey.certifyUserIds(publicRing, userIds); UncachedKeyRing newRing = certificationKey.certifyUserIds(publicRing, userIds);
@ -729,6 +773,27 @@ public class KeychainIntentService extends IntentService
} }
} }
private String getOriginalFilename(Bundle data) throws PgpGeneralException, FileNotFoundException {
int target = data.getInt(TARGET);
switch (target) {
case IO_BYTES:
return "";
case IO_URI:
Uri providerUri = data.getParcelable(ENCRYPT_INPUT_URI);
return FileHelper.getFilename(this, providerUri);
case IO_URIS:
providerUri = data.<Uri>getParcelableArrayList(ENCRYPT_INPUT_URIS).get(data.getInt(SELECTED_URI));
return FileHelper.getFilename(this, providerUri);
default:
throw new PgpGeneralException("No target choosen!");
}
}
private OutputStream createCryptOutputStream(Bundle data) throws PgpGeneralException, FileNotFoundException { private OutputStream createCryptOutputStream(Bundle data) throws PgpGeneralException, FileNotFoundException {
int target = data.getInt(TARGET); int target = data.getInt(TARGET);
switch (target) { switch (target) {

View File

@ -23,8 +23,10 @@ import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.os.Messenger; import android.os.Messenger;
import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -38,6 +40,7 @@ import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Notify; import org.sufficientlysecure.keychain.util.Notify;
@ -113,7 +116,8 @@ public class DecryptFileFragment extends DecryptFragment {
return; return;
} }
askForOutputFilename(); // askForOutputFilename();
decryptOriginalFilename(null);
} }
private String removeEncryptedAppend(String name) { private String removeEncryptedAppend(String name) {
@ -123,8 +127,13 @@ public class DecryptFileFragment extends DecryptFragment {
return name; return name;
} }
private void askForOutputFilename() { private void askForOutputFilename(String originalFilename) {
String targetName = removeEncryptedAppend(FileHelper.getFilename(getActivity(), mInputUri)); String targetName;
if (!TextUtils.isEmpty(originalFilename)) {
targetName = originalFilename;
} else {
targetName = removeEncryptedAppend(FileHelper.getFilename(getActivity(), mInputUri));
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
File file = new File(mInputUri.getPath()); File file = new File(mInputUri.getPath());
File parentDir = file.exists() ? file.getParentFile() : Constants.Path.APP_DIR; File parentDir = file.exists() ? file.getParentFile() : Constants.Path.APP_DIR;
@ -136,6 +145,82 @@ public class DecryptFileFragment extends DecryptFragment {
} }
} }
private void decryptOriginalFilename(String passphrase) {
Log.d(Constants.TAG, "decryptOriginalFilename");
Intent intent = new Intent(getActivity(), KeychainIntentService.class);
// fill values for this action
Bundle data = new Bundle();
intent.setAction(KeychainIntentService.ACTION_DECRYPT_METADATA);
// data
Log.d(Constants.TAG, "mInputUri=" + mInputUri + ", mOutputUri=" + mOutputUri);
data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URI);
data.putParcelable(KeychainIntentService.ENCRYPT_INPUT_URI, mInputUri);
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URI);
data.putParcelable(KeychainIntentService.ENCRYPT_OUTPUT_URI, mOutputUri);
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, passphrase);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
// Message is received after decrypting is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(),
getString(R.string.progress_decrypting), ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
// get returned data bundle
Bundle returnData = message.getData();
PgpDecryptVerifyResult decryptVerifyResult =
returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
showPassphraseDialogForFilename(decryptVerifyResult.getKeyIdPassphraseNeeded());
} else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED ==
decryptVerifyResult.getStatus()) {
showPassphraseDialogForFilename(Constants.key.symmetric);
} else {
// go on...
askForOutputFilename(decryptVerifyResult.getDecryptMetadata().getFilename());
}
}
}
};
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(saveHandler);
intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
// show progress dialog
saveHandler.showProgressDialog(getActivity());
// start service with intent
getActivity().startService(intent);
}
protected void showPassphraseDialogForFilename(long keyId) {
PassphraseDialogFragment.show(getActivity(), keyId,
new Handler() {
@Override
public void handleMessage(Message message) {
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
String passphrase =
message.getData().getString(PassphraseDialogFragment.MESSAGE_DATA_PASSPHRASE);
decryptOriginalFilename(passphrase);
}
}
}
);
}
@Override @Override
protected void decryptStart(String passphrase) { protected void decryptStart(String passphrase) {
Log.d(Constants.TAG, "decryptStart"); Log.d(Constants.TAG, "decryptStart");
@ -161,7 +246,7 @@ public class DecryptFileFragment extends DecryptFragment {
intent.putExtra(KeychainIntentService.EXTRA_DATA, data); intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
// Message is received after encrypting is done in KeychainIntentService // Message is received after decrypting is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(), KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(),
getString(R.string.progress_decrypting), ProgressDialog.STYLE_HORIZONTAL) { getString(R.string.progress_decrypting), ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) { public void handleMessage(Message message) {
@ -178,7 +263,7 @@ public class DecryptFileFragment extends DecryptFragment {
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) { if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
showPassphraseDialog(decryptVerifyResult.getKeyIdPassphraseNeeded()); showPassphraseDialog(decryptVerifyResult.getKeyIdPassphraseNeeded());
} else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED == } else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED ==
decryptVerifyResult.getStatus()) { decryptVerifyResult.getStatus()) {
showPassphraseDialog(Constants.key.symmetric); showPassphraseDialog(Constants.key.symmetric);
} else { } else {
// display signature result in activity // display signature result in activity

View File

@ -264,12 +264,12 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
// fill values for this action // fill values for this action
Bundle data = new Bundle(); Bundle data = new Bundle();
int compressionId;
if (isContentMessage()) { if (isContentMessage()) {
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_BYTES); data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_BYTES);
data.putByteArray(KeychainIntentService.ENCRYPT_MESSAGE_BYTES, mMessage.getBytes()); data.putByteArray(KeychainIntentService.ENCRYPT_MESSAGE_BYTES, mMessage.getBytes());
compressionId = Preferences.getPreferences(this).getDefaultMessageCompression(); data.putInt(KeychainIntentService.ENCRYPT_COMPRESSION_ID,
Preferences.getPreferences(this).getDefaultMessageCompression());
} else { } else {
data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URIS); data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URIS);
data.putParcelableArrayList(KeychainIntentService.ENCRYPT_INPUT_URIS, mInputUris); data.putParcelableArrayList(KeychainIntentService.ENCRYPT_INPUT_URIS, mInputUris);
@ -277,10 +277,10 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URIS); data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URIS);
data.putParcelableArrayList(KeychainIntentService.ENCRYPT_OUTPUT_URIS, mOutputUris); data.putParcelableArrayList(KeychainIntentService.ENCRYPT_OUTPUT_URIS, mOutputUris);
compressionId = Preferences.getPreferences(this).getDefaultFileCompression(); data.putInt(KeychainIntentService.ENCRYPT_COMPRESSION_ID,
Preferences.getPreferences(this).getDefaultFileCompression());
} }
data.putInt(KeychainIntentService.ENCRYPT_COMPRESSION_ID, compressionId);
// Always use armor for messages // Always use armor for messages
data.putBoolean(KeychainIntentService.ENCRYPT_USE_ASCII_ARMOR, mUseArmor || isContentMessage()); data.putBoolean(KeychainIntentService.ENCRYPT_USE_ASCII_ARMOR, mUseArmor || isContentMessage());
@ -429,7 +429,6 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
if (isModeSymmetric()) { if (isModeSymmetric()) {
// symmetric encryption checks // symmetric encryption checks
if (mPassphrase == null) { if (mPassphrase == null) {
Notify.showNotify(this, R.string.passphrases_do_not_match, Notify.Style.ERROR); Notify.showNotify(this, R.string.passphrases_do_not_match, Notify.Style.ERROR);
return false; return false;