aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
diff options
context:
space:
mode:
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java609
1 files changed, 308 insertions, 301 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
index a5813567a..1a65b1bee 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -26,35 +26,34 @@ import android.os.ParcelFileDescriptor;
import android.text.TextUtils;
import org.openintents.openpgp.IOpenPgpService;
-import org.openintents.openpgp.OpenPgpMetadata;
import org.openintents.openpgp.OpenPgpError;
+import org.openintents.openpgp.OpenPgpMetadata;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.openintents.openpgp.util.OpenPgpApi;
import org.spongycastle.util.encoders.Hex;
-import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
-import org.sufficientlysecure.keychain.ui.NfcActivity;
import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
-import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
-import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel;
+import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult;
+import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
-import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
+import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInput;
+import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.remote.ui.RemoteServiceActivity;
-import org.sufficientlysecure.keychain.service.PassphraseCacheService;
-import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel;
-import org.sufficientlysecure.keychain.operations.results.SignEncryptResult;
import org.sufficientlysecure.keychain.ui.ImportKeysActivity;
+import org.sufficientlysecure.keychain.ui.NfcActivity;
import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;
import org.sufficientlysecure.keychain.ui.ViewKeyActivity;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
@@ -85,9 +84,9 @@ public class OpenPgpService extends RemoteService {
boolean missingUserIdsCheck = false;
boolean duplicateUserIdsCheck = false;
- ArrayList<Long> keyIds = new ArrayList<Long>();
- ArrayList<String> missingUserIds = new ArrayList<String>();
- ArrayList<String> duplicateUserIds = new ArrayList<String>();
+ ArrayList<Long> keyIds = new ArrayList<>();
+ ArrayList<String> missingUserIds = new ArrayList<>();
+ ArrayList<String> duplicateUserIds = new ArrayList<>();
if (!noUserIdsCheck) {
for (String email : encryptionUserIds) {
// try to find the key for this specific email
@@ -222,9 +221,12 @@ public class OpenPgpService extends RemoteService {
}
private Intent signImpl(Intent data, ParcelFileDescriptor input,
- ParcelFileDescriptor output, AccountSettings accSettings) {
+ ParcelFileDescriptor output, AccountSettings accSettings,
+ boolean cleartextSign) {
+ InputStream is = null;
+ OutputStream os = null;
try {
- boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
+ boolean asciiArmor = cleartextSign || data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
byte[] nfcSignedHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH);
if (nfcSignedHash != null) {
@@ -242,91 +244,55 @@ public class OpenPgpService extends RemoteService {
}
// Get Input- and OutputStream from ParcelFileDescriptor
- InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
- OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
- try {
- long inputLength = is.available();
- InputData inputData = new InputData(is, inputLength);
-
- // Find the appropriate subkey to sign with
- long sigSubKeyId;
- try {
- CachedPublicKeyRing signingRing =
- new ProviderHelper(this).getCachedPublicKeyRing(accSettings.getKeyId());
- sigSubKeyId = signingRing.getSecretSignId();
- } catch (PgpKeyNotFoundException e) {
- // secret key that is set for this account is deleted?
- // show account config again!
- return getCreateAccountIntent(data, getAccountName(data));
- }
-
- // get passphrase from cache, if key has "no" passphrase, this returns an empty String
- String passphrase;
- if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
- passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
+ is = new ParcelFileDescriptor.AutoCloseInputStream(input);
+ if (cleartextSign) {
+ // output stream only needed for cleartext signatures,
+ // detached signatures are returned as extra
+ os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
+ }
+ long inputLength = is.available();
+ InputData inputData = new InputData(is, inputLength);
+
+ // sign-only
+ PgpSignEncryptInput pseInput = new PgpSignEncryptInput()
+ .setEnableAsciiArmorOutput(asciiArmor)
+ .setCleartextSignature(cleartextSign)
+ .setDetachedSignature(!cleartextSign)
+ .setVersionHeader(PgpHelper.getVersionForHeader(this))
+ .setSignatureHashAlgorithm(accSettings.getHashAlgorithm())
+ .setSignatureMasterKeyId(accSettings.getKeyId())
+ .setNfcState(nfcSignedHash, nfcCreationDate);
+
+ // execute PGP operation!
+ PgpSignEncryptOperation pse = new PgpSignEncryptOperation(this, new ProviderHelper(getContext()), null);
+ PgpSignEncryptResult pgpResult = pse.execute(pseInput, inputData, os);
+
+ if (pgpResult.isPending()) {
+ if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) ==
+ PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) {
+ return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded());
+ } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) ==
+ PgpSignEncryptResult.RESULT_PENDING_NFC) {
+ // return PendingIntent to execute NFC activity
+ // pass through the signature creation timestamp to be used again on second execution
+ // of PgpSignEncrypt when we have the signed hash!
+ data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime());
+ return getNfcSignIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo());
} else {
- try {
- passphrase = PassphraseCacheService.getCachedPassphrase(getContext(),
- accSettings.getKeyId(), sigSubKeyId);
- } catch (PassphraseCacheService.KeyNotFoundException e) {
- // should happen earlier, but return again here if it happens
- return getCreateAccountIntent(data, getAccountName(data));
- }
+ throw new PgpGeneralException(
+ "Encountered unhandled type of pending action not supported by API!");
}
- if (passphrase == null) {
- // get PendingIntent for passphrase input, add it to given params and return to client
- return getPassphraseIntent(data, sigSubKeyId);
- }
-
- // sign-only
- PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
- this, new ProviderHelper(getContext()), null,
- inputData, os
- );
- builder.setEnableAsciiArmorOutput(asciiArmor)
- .setVersionHeader(PgpHelper.getVersionForHeader(this))
- .setSignatureHashAlgorithm(accSettings.getHashAlgorithm())
- .setSignatureMasterKeyId(accSettings.getKeyId())
- .setSignatureSubKeyId(sigSubKeyId)
- .setSignaturePassphrase(passphrase)
- .setNfcState(nfcSignedHash, nfcCreationDate);
-
- // TODO: currently always assume cleartext input, no sign-only of binary currently!
- builder.setCleartextInput(true);
-
- // execute PGP operation!
- SignEncryptResult pgpResult = builder.build().execute();
-
- if (pgpResult.isPending()) {
- if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) ==
- SignEncryptResult.RESULT_PENDING_PASSPHRASE) {
- return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded());
- } else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) ==
- SignEncryptResult.RESULT_PENDING_NFC) {
- // return PendingIntent to execute NFC activity
- // pass through the signature creation timestamp to be used again on second execution
- // of PgpSignEncrypt when we have the signed hash!
- data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime());
- return getNfcSignIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo());
- } else {
- throw new PgpGeneralException(
- "Encountered unhandled type of pending action not supported by API!");
- }
- } else if (pgpResult.success()) {
- // see end of method
- } else {
- LogEntryParcel errorMsg = pgpResult.getLog().getLast();
- throw new Exception(getString(errorMsg.mType.getMsgId()));
+ } else if (pgpResult.success()) {
+ Intent result = new Intent();
+ if (!cleartextSign) {
+ result.putExtra(OpenPgpApi.RESULT_DETACHED_SIGNATURE, pgpResult.getDetachedSignature());
}
-
- } finally {
- is.close();
- os.close();
+ result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
+ return result;
+ } else {
+ LogEntryParcel errorMsg = pgpResult.getLog().getLast();
+ throw new Exception(getString(errorMsg.mType.getMsgId()));
}
-
- Intent result = new Intent();
- result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
- return result;
} catch (Exception e) {
Log.d(Constants.TAG, "signImpl", e);
Intent result = new Intent();
@@ -334,12 +300,29 @@ public class OpenPgpService extends RemoteService {
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
return result;
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "IOException when closing InputStream", e);
+ }
+ }
+ if (os != null) {
+ try {
+ os.close();
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "IOException when closing OutputStream", e);
+ }
+ }
}
}
private Intent encryptAndSignImpl(Intent data, ParcelFileDescriptor input,
ParcelFileDescriptor output, AccountSettings accSettings,
boolean sign) {
+ InputStream is = null;
+ OutputStream os = null;
try {
boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
String originalFilename = data.getStringExtra(OpenPgpApi.EXTRA_ORIGINAL_FILENAME);
@@ -365,99 +348,65 @@ public class OpenPgpService extends RemoteService {
// build InputData and write into OutputStream
// Get Input- and OutputStream from ParcelFileDescriptor
- InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
- OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
- try {
- long inputLength = is.available();
- InputData inputData = new InputData(is, inputLength);
-
- PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
- this, new ProviderHelper(getContext()), null, inputData, os
- );
- builder.setEnableAsciiArmorOutput(asciiArmor)
- .setVersionHeader(PgpHelper.getVersionForHeader(this))
- .setCompressionId(accSettings.getCompression())
- .setSymmetricEncryptionAlgorithm(accSettings.getEncryptionAlgorithm())
- .setEncryptionMasterKeyIds(keyIds)
- .setFailOnMissingEncryptionKeyIds(true)
- .setOriginalFilename(originalFilename)
- .setAdditionalEncryptId(accSettings.getKeyId()); // add acc key for encryption
-
- if (sign) {
-
- // Find the appropriate subkey to sign with
- long sigSubKeyId;
- try {
- CachedPublicKeyRing signingRing =
- new ProviderHelper(this).getCachedPublicKeyRing(accSettings.getKeyId());
- sigSubKeyId = signingRing.getSecretSignId();
- } catch (PgpKeyNotFoundException e) {
- // secret key that is set for this account is deleted?
- // show account config again!
- return getCreateAccountIntent(data, getAccountName(data));
- }
-
- String passphrase;
- if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
- passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
- } else {
- passphrase = PassphraseCacheService.getCachedPassphrase(getContext(),
- accSettings.getKeyId(), sigSubKeyId);
- }
- if (passphrase == null) {
- // get PendingIntent for passphrase input, add it to given params and return to client
- return getPassphraseIntent(data, sigSubKeyId);
- }
-
- byte[] nfcSignedHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH);
- // carefully: only set if timestamp exists
- Date nfcCreationDate = null;
- long nfcCreationTimestamp = data.getLongExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, -1);
- if (nfcCreationTimestamp != -1) {
- nfcCreationDate = new Date(nfcCreationTimestamp);
- }
-
- // sign and encrypt
- builder.setSignatureHashAlgorithm(accSettings.getHashAlgorithm())
- .setSignatureMasterKeyId(accSettings.getKeyId())
- .setSignatureSubKeyId(sigSubKeyId)
- .setSignaturePassphrase(passphrase)
- .setNfcState(nfcSignedHash, nfcCreationDate);
+ is = new ParcelFileDescriptor.AutoCloseInputStream(input);
+ os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
+
+ long inputLength = is.available();
+ InputData inputData = new InputData(is, inputLength, originalFilename);
+
+ PgpSignEncryptInput pseInput = new PgpSignEncryptInput();
+ pseInput.setEnableAsciiArmorOutput(asciiArmor)
+ .setVersionHeader(PgpHelper.getVersionForHeader(this))
+ .setCompressionId(accSettings.getCompression())
+ .setSymmetricEncryptionAlgorithm(accSettings.getEncryptionAlgorithm())
+ .setEncryptionMasterKeyIds(keyIds)
+ .setFailOnMissingEncryptionKeyIds(true)
+ .setAdditionalEncryptId(accSettings.getKeyId()); // add acc key for encryption
+
+ if (sign) {
+
+ byte[] nfcSignedHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH);
+ // carefully: only set if timestamp exists
+ Date nfcCreationDate = null;
+ long nfcCreationTimestamp = data.getLongExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, -1);
+ if (nfcCreationTimestamp != -1) {
+ nfcCreationDate = new Date(nfcCreationTimestamp);
}
- // execute PGP operation!
- SignEncryptResult pgpResult = builder.build().execute();
-
- if (pgpResult.isPending()) {
- if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) ==
- SignEncryptResult.RESULT_PENDING_PASSPHRASE) {
- return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded());
- } else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) ==
- SignEncryptResult.RESULT_PENDING_NFC) {
- // return PendingIntent to execute NFC activity
- // pass through the signature creation timestamp to be used again on second execution
- // of PgpSignEncrypt when we have the signed hash!
- data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime());
- return getNfcSignIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo());
- } else {
- throw new PgpGeneralException(
- "Encountered unhandled type of pending action not supported by API!");
- }
- } else if (pgpResult.success()) {
- // see end of method
+ // sign and encrypt
+ pseInput.setSignatureHashAlgorithm(accSettings.getHashAlgorithm())
+ .setSignatureMasterKeyId(accSettings.getKeyId())
+ .setNfcState(nfcSignedHash, nfcCreationDate);
+ }
+
+ PgpSignEncryptOperation op = new PgpSignEncryptOperation(this, new ProviderHelper(getContext()), null);
+
+ // execute PGP operation!
+ PgpSignEncryptResult pgpResult = op.execute(pseInput, inputData, os);
+
+ if (pgpResult.isPending()) {
+ if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) ==
+ PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) {
+ return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded());
+ } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) ==
+ PgpSignEncryptResult.RESULT_PENDING_NFC) {
+ // return PendingIntent to execute NFC activity
+ // pass through the signature creation timestamp to be used again on second execution
+ // of PgpSignEncrypt when we have the signed hash!
+ data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime());
+ return getNfcSignIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo());
} else {
- LogEntryParcel errorMsg = pgpResult.getLog().getLast();
- throw new Exception(getString(errorMsg.mType.getMsgId()));
+ throw new PgpGeneralException(
+ "Encountered unhandled type of pending action not supported by API!");
}
-
- } finally {
- is.close();
- os.close();
+ } else if (pgpResult.success()) {
+ Intent result = new Intent();
+ result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
+ return result;
+ } else {
+ LogEntryParcel errorMsg = pgpResult.getLog().getLast();
+ throw new Exception(getString(errorMsg.mType.getMsgId()));
}
-
- Intent result = new Intent();
- result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
- return result;
} catch (Exception e) {
Log.d(Constants.TAG, "encryptAndSignImpl", e);
Intent result = new Intent();
@@ -465,111 +414,129 @@ public class OpenPgpService extends RemoteService {
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
return result;
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "IOException when closing InputStream", e);
+ }
+ }
+ if (os != null) {
+ try {
+ os.close();
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "IOException when closing OutputStream", e);
+ }
+ }
}
}
private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor input,
ParcelFileDescriptor output, Set<Long> allowedKeyIds,
boolean decryptMetadataOnly) {
+ InputStream is = null;
+ OutputStream os = null;
try {
// Get Input- and OutputStream from ParcelFileDescriptor
- InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
+ is = new ParcelFileDescriptor.AutoCloseInputStream(input);
- OutputStream os;
- if (decryptMetadataOnly) {
+ // output is optional, e.g., for verifying detached signatures
+ if (decryptMetadataOnly || output == null) {
os = null;
} else {
os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
}
- Intent result = new Intent();
- try {
- String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
- long inputLength = is.available();
- InputData inputData = new InputData(is, inputLength);
-
- PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
- this, new ProviderHelper(getContext()), null, inputData, os
- );
-
- byte[] nfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY);
-
- // allow only private keys associated with accounts of this app
- // no support for symmetric encryption
- builder.setPassphrase(passphrase)
- .setAllowSymmetricDecryption(false)
- .setAllowedKeyIds(allowedKeyIds)
- .setDecryptMetadataOnly(decryptMetadataOnly)
- .setNfcState(nfcDecryptedSessionKey);
-
- // TODO: currently does not support binary signed-only content
- DecryptVerifyResult pgpResult = builder.build().execute();
-
- if (pgpResult.isPending()) {
- if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) ==
- DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) {
- return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded());
- } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) ==
- DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) {
- throw new PgpGeneralException(
- "Decryption of symmetric content not supported by API!");
- } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) ==
- DecryptVerifyResult.RESULT_PENDING_NFC) {
- return getNfcDecryptIntent(
- data, pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey());
- } else {
- throw new PgpGeneralException(
- "Encountered unhandled type of pending action not supported by API!");
- }
- } else if (pgpResult.success()) {
-
- OpenPgpSignatureResult signatureResult = pgpResult.getSignatureResult();
- if (signatureResult != null) {
- result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult);
-
- if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 5) {
- // SIGNATURE_KEY_REVOKED and SIGNATURE_KEY_EXPIRED have been added in version 5
- if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED
- || signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED) {
- signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR);
- }
+ String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
+ long inputLength = is.available();
+ InputData inputData = new InputData(is, inputLength);
+
+ PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
+ this, new ProviderHelper(getContext()), null, inputData, os
+ );
+
+ byte[] nfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY);
+
+ byte[] detachedSignature = data.getByteArrayExtra(OpenPgpApi.EXTRA_DETACHED_SIGNATURE);
+
+ // allow only private keys associated with accounts of this app
+ // no support for symmetric encryption
+ builder.setPassphrase(passphrase)
+ .setAllowSymmetricDecryption(false)
+ .setAllowedKeyIds(allowedKeyIds)
+ .setDecryptMetadataOnly(decryptMetadataOnly)
+ .setNfcState(nfcDecryptedSessionKey)
+ .setDetachedSignature(detachedSignature);
+
+ DecryptVerifyResult pgpResult = builder.build().execute();
+
+ if (pgpResult.isPending()) {
+ if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) ==
+ DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) {
+ return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded());
+ } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) ==
+ DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) {
+ throw new PgpGeneralException(
+ "Decryption of symmetric content not supported by API!");
+ } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) ==
+ DecryptVerifyResult.RESULT_PENDING_NFC) {
+ return getNfcDecryptIntent(
+ data, pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey());
+ } else {
+ throw new PgpGeneralException(
+ "Encountered unhandled type of pending action not supported by API!");
+ }
+ } else if (pgpResult.success()) {
+ Intent result = new Intent();
+
+ OpenPgpSignatureResult signatureResult = pgpResult.getSignatureResult();
+ if (signatureResult != null) {
+ result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult);
+
+ if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 5) {
+ // SIGNATURE_KEY_REVOKED and SIGNATURE_KEY_EXPIRED have been added in version 5
+ if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED
+ || signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED) {
+ signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR);
}
+ }
- if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_MISSING) {
- // If signature is unknown we return an _additional_ PendingIntent
- // to retrieve the missing key
- Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class);
- intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE);
- intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, signatureResult.getKeyId());
- intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data);
+ if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_MISSING) {
+ // If signature is unknown we return an _additional_ PendingIntent
+ // to retrieve the missing key
+ Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class);
+ intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE);
+ intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, signatureResult.getKeyId());
+ intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data);
- PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
- intent,
- PendingIntent.FLAG_CANCEL_CURRENT);
+ PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
+ intent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
- result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
- }
+ result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
}
+ }
- if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) >= 4) {
- OpenPgpMetadata metadata = pgpResult.getDecryptMetadata();
- if (metadata != null) {
- result.putExtra(OpenPgpApi.RESULT_METADATA, metadata);
- }
+ if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) >= 4) {
+ OpenPgpMetadata metadata = pgpResult.getDecryptMetadata();
+ if (metadata != null) {
+ result.putExtra(OpenPgpApi.RESULT_METADATA, metadata);
}
- } else {
- LogEntryParcel errorMsg = pgpResult.getLog().getLast();
- throw new Exception(getString(errorMsg.mType.getMsgId()));
}
- } finally {
- is.close();
- if (os != null) {
- os.close();
+
+ String charset = pgpResult.getCharset();
+ if (charset != null) {
+ result.putExtra(OpenPgpApi.RESULT_CHARSET, charset);
}
+
+ result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
+ return result;
+ } else {
+ LogEntryParcel errorMsg = pgpResult.getLog().getLast();
+ throw new Exception(getString(errorMsg.mType.getMsgId()));
}
- result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
- return result;
} catch (Exception e) {
Log.d(Constants.TAG, "decryptAndVerifyImpl", e);
Intent result = new Intent();
@@ -577,6 +544,21 @@ public class OpenPgpService extends RemoteService {
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
return result;
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "IOException when closing InputStream", e);
+ }
+ }
+ if (os != null) {
+ try {
+ os.close();
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "IOException when closing OutputStream", e);
+ }
+ }
}
}
@@ -668,15 +650,16 @@ public class OpenPgpService extends RemoteService {
// version code is required and needs to correspond to version code of service!
// History of versions in org.openintents.openpgp.util.OpenPgpApi
- // we support 3, 4, 5
+ // we support 3, 4, 5, 6
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 3
&& data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 4
- && data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 5) {
+ && data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 5
+ && data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 6) {
Intent result = new Intent();
OpenPgpError error = new OpenPgpError
(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!\n"
+ "used API version: " + data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) + "\n"
- + "supported API versions: 3, 4");
+ + "supported API versions: 3, 4, 5, 6");
result.putExtra(OpenPgpApi.RESULT_ERROR, error);
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
return result;
@@ -706,42 +689,66 @@ public class OpenPgpService extends RemoteService {
@Override
public Intent execute(Intent data, ParcelFileDescriptor input, ParcelFileDescriptor output) {
- Intent errorResult = checkRequirements(data);
- if (errorResult != null) {
- return errorResult;
- }
+ try {
+ Intent errorResult = checkRequirements(data);
+ if (errorResult != null) {
+ return errorResult;
+ }
- String accName = getAccountName(data);
- final AccountSettings accSettings = getAccSettings(accName);
- if (accSettings == null) {
- return getCreateAccountIntent(data, accName);
- }
+ String accName = getAccountName(data);
+ final AccountSettings accSettings = getAccSettings(accName);
+ if (accSettings == null) {
+ return getCreateAccountIntent(data, accName);
+ }
- String action = data.getAction();
- if (OpenPgpApi.ACTION_SIGN.equals(action)) {
- return signImpl(data, input, output, accSettings);
- } else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) {
- return encryptAndSignImpl(data, input, output, accSettings, false);
- } else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) {
- return encryptAndSignImpl(data, input, output, accSettings, true);
- } else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) {
- String currentPkg = getCurrentCallingPackage();
- Set<Long> allowedKeyIds =
- mProviderHelper.getAllKeyIdsForApp(
- ApiAccounts.buildBaseUri(currentPkg));
- return decryptAndVerifyImpl(data, input, output, allowedKeyIds, false);
- } else if (OpenPgpApi.ACTION_DECRYPT_METADATA.equals(action)) {
- String currentPkg = getCurrentCallingPackage();
- Set<Long> allowedKeyIds =
- mProviderHelper.getAllKeyIdsForApp(
- ApiAccounts.buildBaseUri(currentPkg));
- return decryptAndVerifyImpl(data, input, output, allowedKeyIds, true);
- } else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) {
- return getKeyImpl(data);
- } else if (OpenPgpApi.ACTION_GET_KEY_IDS.equals(action)) {
- return getKeyIdsImpl(data);
- } else {
- return null;
+ String action = data.getAction();
+ if (OpenPgpApi.ACTION_CLEARTEXT_SIGN.equals(action)) {
+ return signImpl(data, input, output, accSettings, true);
+ } else if (OpenPgpApi.ACTION_SIGN.equals(action)) {
+ // DEPRECATED: same as ACTION_CLEARTEXT_SIGN
+ Log.w(Constants.TAG, "You are using a deprecated API call, please use ACTION_CLEARTEXT_SIGN instead of ACTION_SIGN!");
+ return signImpl(data, input, output, accSettings, true);
+ } else if (OpenPgpApi.ACTION_DETACHED_SIGN.equals(action)) {
+ return signImpl(data, input, output, accSettings, false);
+ } else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) {
+ return encryptAndSignImpl(data, input, output, accSettings, false);
+ } else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) {
+ return encryptAndSignImpl(data, input, output, accSettings, true);
+ } else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) {
+ String currentPkg = getCurrentCallingPackage();
+ Set<Long> allowedKeyIds =
+ mProviderHelper.getAllKeyIdsForApp(
+ ApiAccounts.buildBaseUri(currentPkg));
+ return decryptAndVerifyImpl(data, input, output, allowedKeyIds, false);
+ } else if (OpenPgpApi.ACTION_DECRYPT_METADATA.equals(action)) {
+ String currentPkg = getCurrentCallingPackage();
+ Set<Long> allowedKeyIds =
+ mProviderHelper.getAllKeyIdsForApp(
+ ApiAccounts.buildBaseUri(currentPkg));
+ return decryptAndVerifyImpl(data, input, output, allowedKeyIds, true);
+ } else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) {
+ return getKeyImpl(data);
+ } else if (OpenPgpApi.ACTION_GET_KEY_IDS.equals(action)) {
+ return getKeyIdsImpl(data);
+ } else {
+ return null;
+ }
+ } finally {
+ // always close input and output file descriptors even in error cases
+ if (input != null) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "IOException when closing input ParcelFileDescriptor", e);
+ }
+ }
+ if (output != null) {
+ try {
+ output.close();
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "IOException when closing output ParcelFileDescriptor", e);
+ }
+ }
}
}