aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2014-09-14 00:56:03 +0200
committerDominik Schürmann <dominik@dominikschuermann.de>2014-09-14 00:56:03 +0200
commit88bbce831c30c1220e03439ffca4c8f390506ba6 (patch)
tree74982b9f53abd4de3907a88a4dbbe67bfaea77b4 /OpenKeychain/src
parentdb5d12800c01f41b04fd90426bc6ba2b4f99d72b (diff)
parent760b05273c99dec72a4d0af525d101955f8f2234 (diff)
downloadopen-keychain-88bbce831c30c1220e03439ffca4c8f390506ba6.tar.gz
open-keychain-88bbce831c30c1220e03439ffca4c8f390506ba6.tar.bz2
open-keychain-88bbce831c30c1220e03439ffca4c8f390506ba6.zip
Merge branch 'master' of github.com:open-keychain/open-keychain
Diffstat (limited to 'OpenKeychain/src')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java342
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java81
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java14
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/OperationResultParcel.java31
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/SignEncryptResult.java103
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileActivity.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java19
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml26
8 files changed, 404 insertions, 214 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
index 070239a80..9f97ac4c9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
@@ -35,6 +35,10 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.results.OperationResultParcel.LogLevel;
+import org.sufficientlysecure.keychain.service.results.OperationResultParcel.LogType;
+import org.sufficientlysecure.keychain.service.results.OperationResultParcel.OperationLog;
+import org.sufficientlysecure.keychain.service.results.SignEncryptResult;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressScaler;
@@ -45,8 +49,6 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
import java.security.SignatureException;
import java.util.Arrays;
import java.util.Date;
@@ -247,44 +249,16 @@ public class PgpSignEncrypt {
}
}
- public static class KeyExtractionException extends Exception {
- public KeyExtractionException() {
- }
- }
-
- public static class NoPassphraseException extends Exception {
- public NoPassphraseException() {
- }
- }
-
- public static class WrongPassphraseException extends Exception {
- public WrongPassphraseException() {
- }
- }
-
- public static class NoSigningKeyException extends Exception {
- public NoSigningKeyException() {
- }
- }
-
- public static class NeedNfcDataException extends Exception {
- public byte[] mHashToSign;
- public int mHashAlgo;
- public Date mCreationTimestamp;
-
- public NeedNfcDataException(byte[] hashToSign, int hashAlgo, Date creationTimestamp) {
- mHashToSign = hashToSign;
- mHashAlgo = hashAlgo;
- mCreationTimestamp = creationTimestamp;
- }
- }
-
/**
* Signs and/or encrypts data based on parameters of class
*/
- public void execute()
- throws IOException, PGPException, NoSuchProviderException,
- NoSuchAlgorithmException, SignatureException, KeyExtractionException, NoSigningKeyException, NoPassphraseException, NeedNfcDataException, WrongPassphraseException {
+ public SignEncryptResult execute() {
+
+ int indent = 0;
+ OperationLog log = new OperationLog();
+
+ log.add(LogLevel.START, LogType.MSG_SE, indent);
+ indent += 1;
boolean enableSignature = mSignatureMasterKeyId != Constants.key.none;
boolean enableEncryption = ((mEncryptionMasterKeyIds != null && mEncryptionMasterKeyIds.length > 0)
@@ -320,7 +294,8 @@ public class PgpSignEncrypt {
// If we weren't handed a passphrase, throw early
if (mSignaturePassphrase == null) {
- throw new NoPassphraseException();
+ log.add(LogLevel.ERROR, LogType.MSG_SE_ERROR_NO_PASSPHRASE, indent);
+ return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log);
}
try {
@@ -332,22 +307,26 @@ public class PgpSignEncrypt {
signingKey = signingKeyRing.getSecretKey(signKeyId);
// make sure it's a signing key alright!
} catch (ProviderHelper.NotFoundException e) {
- throw new NoSigningKeyException();
+ log.add(LogLevel.ERROR, LogType.MSG_SE_ERROR_SIGN_KEY, indent);
+ return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log);
}
// Make sure we are allowed to sign here!
- if ( ! signingKey.canSign()) {
- throw new NoSigningKeyException();
+ if (!signingKey.canSign()) {
+ log.add(LogLevel.ERROR, LogType.MSG_SE_ERROR_KEY_SIGN, indent);
+ return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log);
}
updateProgress(R.string.progress_extracting_signature_key, 0, 100);
try {
- if ( ! signingKey.unlock(mSignaturePassphrase)) {
- throw new WrongPassphraseException();
+ if (!signingKey.unlock(mSignaturePassphrase)) {
+ log.add(LogLevel.ERROR, LogType.MSG_SE_ERROR_BAD_PASSPHRASE, indent);
+ return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log);
}
} catch (PgpGeneralException e) {
- throw new KeyExtractionException();
+ log.add(LogLevel.ERROR, LogType.MSG_SE_ERROR_UNLOCK, indent);
+ return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log);
}
// check if hash algo is supported
@@ -372,12 +351,14 @@ public class PgpSignEncrypt {
if (mSymmetricPassphrase != null) {
// Symmetric encryption
- Log.d(Constants.TAG, "encryptionMasterKeyIds length is 0 -> symmetric encryption");
+ log.add(LogLevel.DEBUG, LogType.MSG_SE_SYMMETRIC, indent);
JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator =
new JcePBEKeyEncryptionMethodGenerator(mSymmetricPassphrase.toCharArray());
cPk.addMethod(symmetricEncryptionGenerator);
} else {
+ log.add(LogLevel.INFO, LogType.MSG_SE_ASYMMETRIC, indent);
+
// Asymmetric encryption
for (long id : mEncryptionMasterKeyIds) {
try {
@@ -385,10 +366,14 @@ public class PgpSignEncrypt {
KeyRings.buildUnifiedKeyRingUri(id));
CanonicalizedPublicKey key = keyRing.getEncryptionSubKey();
cPk.addMethod(key.getPubKeyEncryptionGenerator());
+ log.add(LogLevel.DEBUG, LogType.MSG_SE_KEY_OK, indent +1,
+ PgpKeyHelper.convertKeyIdToHex(id));
} catch (PgpGeneralException e) {
- Log.e(Constants.TAG, "key not found!", e);
+ log.add(LogLevel.WARN, LogType.MSG_SE_KEY_WARN, indent +1,
+ PgpKeyHelper.convertKeyIdToHex(id));
} catch (ProviderHelper.NotFoundException e) {
- Log.e(Constants.TAG, "key not found!", e);
+ log.add(LogLevel.WARN, LogType.MSG_SE_KEY_UNKNOWN, indent +1,
+ PgpKeyHelper.convertKeyIdToHex(id));
}
}
}
@@ -404,168 +389,199 @@ public class PgpSignEncrypt {
signatureGenerator = signingKey.getSignatureGenerator(
mSignatureHashAlgorithm, cleartext, mNfcSignedHash, mNfcCreationTimestamp);
} catch (PgpGeneralException e) {
- // TODO throw correct type of exception (which shouldn't be PGPException)
- throw new KeyExtractionException();
+ log.add(LogLevel.ERROR, LogType.MSG_SE_ERROR_NFC, indent);
+ return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log);
}
}
ProgressScaler progressScaler =
new ProgressScaler(mProgressable, 8, 95, 100);
PGPCompressedDataGenerator compressGen = null;
- OutputStream pOut = null;
+ OutputStream pOut;
OutputStream encryptionOut = null;
BCPGOutputStream bcpgOut;
- if (enableEncryption) {
- /* actual encryption */
- updateProgress(R.string.progress_encrypting, 8, 100);
-
- encryptionOut = cPk.open(out, new byte[1 << 16]);
-
- if (enableCompression) {
- compressGen = new PGPCompressedDataGenerator(mCompressionId);
- bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut));
- } else {
- bcpgOut = new BCPGOutputStream(encryptionOut);
- }
-
- if (enableSignature) {
- signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
- }
-
- PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
- char literalDataFormatTag;
- if (mCleartextInput) {
- literalDataFormatTag = PGPLiteralData.UTF8;
- } else {
- literalDataFormatTag = PGPLiteralData.BINARY;
- }
- pOut = literalGen.open(bcpgOut, literalDataFormatTag, mOriginalFilename, new Date(),
- new byte[1 << 16]);
+ try {
- long alreadyWritten = 0;
- int length;
- byte[] buffer = new byte[1 << 16];
- InputStream in = mData.getInputStream();
- while ((length = in.read(buffer)) > 0) {
- pOut.write(buffer, 0, length);
+ if (enableEncryption) {
+ /* actual encryption */
+ updateProgress(R.string.progress_encrypting, 8, 100);
+ log.add(LogLevel.DEBUG, enableSignature
+ ? LogType.MSG_SE_SIGCRYPTING
+ : LogType.MSG_SE_ENCRYPTING,
+ indent);
+ indent += 1;
+
+ encryptionOut = cPk.open(out, new byte[1 << 16]);
+
+ if (enableCompression) {
+ log.add(LogLevel.DEBUG, LogType.MSG_SE_COMPRESSING, indent);
+ compressGen = new PGPCompressedDataGenerator(mCompressionId);
+ bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut));
+ } else {
+ bcpgOut = new BCPGOutputStream(encryptionOut);
+ }
- // update signature buffer if signature is requested
if (enableSignature) {
- signatureGenerator.update(buffer, 0, length);
+ signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
}
- alreadyWritten += length;
- if (mData.getSize() > 0) {
- long progress = 100 * alreadyWritten / mData.getSize();
- progressScaler.setProgress((int) progress, 100);
+ PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
+ char literalDataFormatTag;
+ if (mCleartextInput) {
+ literalDataFormatTag = PGPLiteralData.UTF8;
+ } else {
+ literalDataFormatTag = PGPLiteralData.BINARY;
+ }
+ pOut = literalGen.open(bcpgOut, literalDataFormatTag, mOriginalFilename, new Date(),
+ new byte[1 << 16]);
+
+ long alreadyWritten = 0;
+ int length;
+ byte[] buffer = new byte[1 << 16];
+ InputStream in = mData.getInputStream();
+ while ((length = in.read(buffer)) > 0) {
+ pOut.write(buffer, 0, length);
+
+ // update signature buffer if signature is requested
+ if (enableSignature) {
+ signatureGenerator.update(buffer, 0, length);
+ }
+
+ alreadyWritten += length;
+ if (mData.getSize() > 0) {
+ long progress = 100 * alreadyWritten / mData.getSize();
+ progressScaler.setProgress((int) progress, 100);
+ }
}
- }
- literalGen.close();
- } else if (enableSignature && mCleartextInput && mEnableAsciiArmorOutput) {
- /* cleartext signature: sign-only of ascii text */
+ literalGen.close();
+ indent -= 1;
- updateProgress(R.string.progress_signing, 8, 100);
+ } else if (enableSignature && mCleartextInput && mEnableAsciiArmorOutput) {
+ /* cleartext signature: sign-only of ascii text */
- // write -----BEGIN PGP SIGNED MESSAGE-----
- armorOut.beginClearText(mSignatureHashAlgorithm);
+ updateProgress(R.string.progress_signing, 8, 100);
+ log.add(LogLevel.DEBUG, LogType.MSG_SE_SIGNING, indent);
- InputStream in = mData.getInputStream();
- final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+ // write -----BEGIN PGP SIGNED MESSAGE-----
+ armorOut.beginClearText(mSignatureHashAlgorithm);
- // update signature buffer with first line
- processLine(reader.readLine(), armorOut, signatureGenerator);
+ InputStream in = mData.getInputStream();
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
- // TODO: progress: fake annealing?
- while (true) {
- String line = reader.readLine();
+ // update signature buffer with first line
+ processLine(reader.readLine(), armorOut, signatureGenerator);
+
+ // TODO: progress: fake annealing?
+ while (true) {
+ String line = reader.readLine();
+
+ // end cleartext signature with newline, see http://tools.ietf.org/html/rfc4880#section-7
+ if (line == null) {
+ armorOut.write(NEW_LINE);
+ break;
+ }
- // end cleartext signature with newline, see http://tools.ietf.org/html/rfc4880#section-7
- if (line == null) {
armorOut.write(NEW_LINE);
- break;
+
+ // update signature buffer with input line
+ signatureGenerator.update(NEW_LINE);
+ processLine(line, armorOut, signatureGenerator);
}
- armorOut.write(NEW_LINE);
+ armorOut.endClearText();
- // update signature buffer with input line
- signatureGenerator.update(NEW_LINE);
- processLine(line, armorOut, signatureGenerator);
- }
+ pOut = new BCPGOutputStream(armorOut);
+ } else if (enableSignature && !mCleartextInput) {
+ /* sign-only binary (files/data stream) */
- armorOut.endClearText();
+ updateProgress(R.string.progress_signing, 8, 100);
+ log.add(LogLevel.DEBUG, LogType.MSG_SE_ENCRYPTING, indent);
- pOut = new BCPGOutputStream(armorOut);
- } else if (enableSignature && !mCleartextInput) {
- /* sign-only binary (files/data stream) */
+ InputStream in = mData.getInputStream();
- updateProgress(R.string.progress_signing, 8, 100);
+ if (enableCompression) {
+ compressGen = new PGPCompressedDataGenerator(mCompressionId);
+ bcpgOut = new BCPGOutputStream(compressGen.open(out));
+ } else {
+ bcpgOut = new BCPGOutputStream(out);
+ }
- InputStream in = mData.getInputStream();
+ signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
- if (enableCompression) {
- compressGen = new PGPCompressedDataGenerator(mCompressionId);
- bcpgOut = new BCPGOutputStream(compressGen.open(out));
- } else {
- bcpgOut = new BCPGOutputStream(out);
- }
+ PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
+ pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, mOriginalFilename, new Date(),
+ new byte[1 << 16]);
- signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
+ long alreadyWritten = 0;
+ int length;
+ byte[] buffer = new byte[1 << 16];
+ while ((length = in.read(buffer)) > 0) {
+ pOut.write(buffer, 0, length);
- PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
- pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, mOriginalFilename, new Date(),
- new byte[1 << 16]);
+ signatureGenerator.update(buffer, 0, length);
- long alreadyWritten = 0;
- int length;
- byte[] buffer = new byte[1 << 16];
- while ((length = in.read(buffer)) > 0) {
- pOut.write(buffer, 0, length);
+ alreadyWritten += length;
+ if (mData.getSize() > 0) {
+ long progress = 100 * alreadyWritten / mData.getSize();
+ progressScaler.setProgress((int) progress, 100);
+ }
+ }
- signatureGenerator.update(buffer, 0, length);
+ literalGen.close();
+ } else {
+ pOut = null;
+ log.add(LogLevel.WARN, LogType.MSG_SE_CLEARSIGN_ONLY, indent);
+ }
- alreadyWritten += length;
- if (mData.getSize() > 0) {
- long progress = 100 * alreadyWritten / mData.getSize();
- progressScaler.setProgress((int) progress, 100);
+ if (enableSignature) {
+ updateProgress(R.string.progress_generating_signature, 95, 100);
+ try {
+ signatureGenerator.generate().encode(pOut);
+ } catch (NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded e) {
+ // this secret key diverts to a OpenPGP card, throw exception with hash that will be signed
+ log.add(LogLevel.OK, LogType.MSG_SE_PENDING_NFC, indent);
+ SignEncryptResult result =
+ new SignEncryptResult(SignEncryptResult.RESULT_PENDING_NFC, log);
+ result.setNfcData(e.hashToSign, e.hashAlgo, e.creationTimestamp);
+ return new SignEncryptResult(SignEncryptResult.RESULT_PENDING_NFC, log);
}
}
- literalGen.close();
- } else {
- pOut = null;
- Log.e(Constants.TAG, "not supported!");
- }
+ // closing outputs
+ // NOTE: closing needs to be done in the correct order!
+ // TODO: closing bcpgOut and pOut???
+ if (enableEncryption) {
+ if (enableCompression) {
+ compressGen.close();
+ }
- if (enableSignature) {
- updateProgress(R.string.progress_generating_signature, 95, 100);
- try {
- signatureGenerator.generate().encode(pOut);
- } catch (NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded e) {
- // this secret key diverts to a OpenPGP card, throw exception with hash that will be signed
- throw new NeedNfcDataException(e.hashToSign, e.hashAlgo, e.creationTimestamp);
+ encryptionOut.close();
}
- }
-
- // closing outputs
- // NOTE: closing needs to be done in the correct order!
- // TODO: closing bcpgOut and pOut???
- if (enableEncryption) {
- if (enableCompression) {
- compressGen.close();
+ if (mEnableAsciiArmorOutput) {
+ armorOut.close();
}
- encryptionOut.close();
- }
- if (mEnableAsciiArmorOutput) {
- armorOut.close();
- }
+ out.close();
+ mOutStream.close();
- out.close();
- mOutStream.close();
+ } catch (SignatureException e) {
+ log.add(LogLevel.ERROR, LogType.MSG_SE_ERROR_SIG, indent);
+ return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log);
+ } catch (PGPException e) {
+ log.add(LogLevel.ERROR, LogType.MSG_SE_ERROR_PGP, indent);
+ return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log);
+ } catch (IOException e) {
+ log.add(LogLevel.ERROR, LogType.MSG_SE_ERROR_IO, indent);
+ return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log);
+ }
updateProgress(R.string.progress_done, 100, 100);
+
+ log.add(LogLevel.OK, LogType.MSG_SE_OK, indent);
+ return new SignEncryptResult(SignEncryptResult.RESULT_OK, log);
+
}
private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
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 205395dbf..29f888a82 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -45,6 +45,8 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.remote.ui.RemoteServiceActivity;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
+import org.sufficientlysecure.keychain.service.results.OperationResultParcel.LogEntryParcel;
+import org.sufficientlysecure.keychain.service.results.SignEncryptResult;
import org.sufficientlysecure.keychain.ui.ImportKeysActivity;
import org.sufficientlysecure.keychain.ui.ViewKeyActivity;
import org.sufficientlysecure.keychain.util.InputData;
@@ -269,25 +271,28 @@ public class OpenPgpService extends RemoteService {
// TODO: currently always assume cleartext input, no sign-only of binary currently!
builder.setCleartextInput(true);
- try {
- builder.build().execute();
-
- // throw exceptions upwards to client with meaningful messages
- } catch (PgpSignEncrypt.KeyExtractionException e) {
- throw new Exception(getString(R.string.error_could_not_extract_private_key));
- } catch (PgpSignEncrypt.NoPassphraseException e) {
- throw new Exception(getString(R.string.error_no_signature_passphrase));
- } catch (PgpSignEncrypt.WrongPassphraseException e) {
- throw new Exception(getString(R.string.error_wrong_passphrase));
- } catch (PgpSignEncrypt.NoSigningKeyException e) {
- throw new Exception(getString(R.string.error_no_signature_key));
- } catch (PgpSignEncrypt.NeedNfcDataException e) {
- // 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, e.mCreationTimestamp.getTime());
- return getNfcSignIntent(data, passphrase, e.mHashToSign, e.mHashAlgo);
+ // execute PGP operation!
+ SignEncryptResult result = builder.build().execute();
+
+ if (result.isPending()) {
+ switch (result.getResult()) {
+ case 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, result.getNfcTimestamp().getTime());
+ return getNfcSignIntent(data, passphrase, result.getNfcHash(), result.getNfcAlgo());
+
+ default:
+ throw new Exception("Encountered unhandled pending state - please file a bug report!");
+ }
}
+
+ if (!result.success()) {
+ LogEntryParcel errorMsg = result.getLog().getLast();
+ throw new Exception(getString(errorMsg.mType.getMsgId()));
+ }
+
} finally {
is.close();
os.close();
@@ -379,26 +384,28 @@ public class OpenPgpService extends RemoteService {
.setNfcState(nfcSignedHash, nfcCreationDate);
}
- try {
- // execute PGP operation!
- builder.build().execute();
-
- // throw exceptions upwards to client with meaningful messages
- } catch (PgpSignEncrypt.KeyExtractionException e) {
- throw new Exception(getString(R.string.error_could_not_extract_private_key));
- } catch (PgpSignEncrypt.NoPassphraseException e) {
- throw new Exception(getString(R.string.error_no_signature_passphrase));
- } catch (PgpSignEncrypt.WrongPassphraseException e) {
- throw new Exception(getString(R.string.error_wrong_passphrase));
- } catch (PgpSignEncrypt.NoSigningKeyException e) {
- throw new Exception(getString(R.string.error_no_signature_key));
- } catch (PgpSignEncrypt.NeedNfcDataException e) {
- // 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, e.mCreationTimestamp.getTime());
- return getNfcSignIntent(data, passphrase, e.mHashToSign, e.mHashAlgo);
+ // execute PGP operation!
+ SignEncryptResult result = builder.build().execute();
+
+ if (result.isPending()) {
+ switch (result.getResult()) {
+ case 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, result.getNfcTimestamp().getTime());
+ return getNfcSignIntent(data, passphrase, result.getNfcHash(), result.getNfcAlgo());
+
+ default:
+ throw new Exception("Encountered unhandled pending state - please file a bug report!");
+ }
}
+
+ if (!result.success()) {
+ LogEntryParcel errorMsg = result.getLog().getLast();
+ throw new Exception(getString(errorMsg.mType.getMsgId()));
+ }
+
} finally {
is.close();
os.close();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index f8ef9b0f6..e09c71787 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -63,6 +63,7 @@ import org.sufficientlysecure.keychain.service.results.ConsolidateResult;
import org.sufficientlysecure.keychain.service.results.EditKeyResult;
import org.sufficientlysecure.keychain.service.results.ImportKeyResult;
import org.sufficientlysecure.keychain.service.results.SaveKeyringResult;
+import org.sufficientlysecure.keychain.service.results.SignEncryptResult;
import org.sufficientlysecure.keychain.util.ParcelableFileCache;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
@@ -91,7 +92,7 @@ public class KeychainIntentService extends IntentService implements Progressable
public static final String EXTRA_DATA = "data";
/* possible actions */
- public static final String ACTION_ENCRYPT_SIGN = Constants.INTENT_PREFIX + "ENCRYPT_SIGN";
+ public static final String ACTION_SIGN_ENCRYPT = Constants.INTENT_PREFIX + "SIGN_ENCRYPT";
public static final String ACTION_DECRYPT_VERIFY = Constants.INTENT_PREFIX + "DECRYPT_VERIFY";
@@ -247,7 +248,7 @@ public class KeychainIntentService extends IntentService implements Progressable
String action = intent.getAction();
// executeServiceMethod action from extra bundle
- if (ACTION_ENCRYPT_SIGN.equals(action)) {
+ if (ACTION_SIGN_ENCRYPT.equals(action)) {
try {
/* Input */
int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET);
@@ -309,7 +310,8 @@ public class KeychainIntentService extends IntentService implements Progressable
builder.setCleartextInput(true);
}
- builder.build().execute();
+ SignEncryptResult result = builder.build().execute();
+ resultData.putParcelable(SignEncryptResult.EXTRA_RESULT, result);
outStream.close();
@@ -779,12 +781,6 @@ public class KeychainIntentService extends IntentService implements Progressable
if (e instanceof PgpGeneralMsgIdException) {
e = ((PgpGeneralMsgIdException) e).getContextualized(this);
message = e.getMessage();
- } else if (e instanceof PgpSignEncrypt.KeyExtractionException) {
- message = getString(R.string.error_could_not_extract_private_key);
- } else if (e instanceof PgpSignEncrypt.NoPassphraseException) {
- message = getString(R.string.error_no_signature_passphrase);
- } else if (e instanceof PgpSignEncrypt.NoSigningKeyException) {
- message = getString(R.string.error_no_signature_key);
} else {
message = e.getMessage();
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/OperationResultParcel.java
index 46823a24d..56f5248cb 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/OperationResultParcel.java
@@ -474,6 +474,30 @@ public class OperationResultParcel implements Parcelable {
MSG_DC_TRAIL_UNKNOWN (R.string.msg_dc_trail_unknown),
MSG_DC_UNLOCKING (R.string.msg_dc_unlocking),
+ // signencrypt
+ MSG_SE_ASYMMETRIC (R.string.msg_se_asymmetric),
+ MSG_SE_CLEARSIGN_ONLY (R.string.msg_se_clearsign_only),
+ MSG_SE_COMPRESSING (R.string.msg_se_compressing),
+ MSG_SE_ENCRYPTING (R.string.msg_se_encrypting),
+ MSG_SE_ERROR_BAD_PASSPHRASE (R.string.msg_se_error_bad_passphrase),
+ MSG_SE_ERROR_IO (R.string.msg_se_error_io),
+ MSG_SE_ERROR_SIGN_KEY(R.string.msg_se_error_sign_key),
+ MSG_SE_ERROR_KEY_SIGN (R.string.msg_se_error_key_sign),
+ MSG_SE_ERROR_NFC (R.string.msg_se_error_nfc),
+ MSG_SE_ERROR_NO_PASSPHRASE (R.string.msg_se_error_no_passphrase),
+ MSG_SE_ERROR_PGP (R.string.msg_se_error_pgp),
+ MSG_SE_ERROR_SIG (R.string.msg_se_error_sig),
+ MSG_SE_ERROR_UNLOCK (R.string.msg_se_error_unlock),
+ MSG_SE_KEY_OK (R.string.msg_se_key_ok),
+ MSG_SE_KEY_UNKNOWN (R.string.msg_se_key_unknown),
+ MSG_SE_KEY_WARN (R.string.msg_se_key_warn),
+ MSG_SE_OK (R.string.msg_se_ok),
+ MSG_SE_PENDING_NFC (R.string.msg_se_pending_nfc),
+ MSG_SE (R.string.msg_se),
+ MSG_SE_SIGNING (R.string.msg_se_signing),
+ MSG_SE_SIGCRYPTING (R.string.msg_se_sigcrypting),
+ MSG_SE_SYMMETRIC (R.string.msg_se_symmetric),
+
;
private final int mMsgId;
@@ -562,6 +586,13 @@ public class OperationResultParcel implements Parcelable {
return mParcels.isEmpty();
}
+ public LogEntryParcel getLast() {
+ if (mParcels.isEmpty()) {
+ return null;
+ }
+ return mParcels.get(mParcels.size() -1);
+ }
+
@Override
public Iterator<LogEntryParcel> iterator() {
return mParcels.iterator();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/SignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/SignEncryptResult.java
new file mode 100644
index 000000000..073eab354
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/SignEncryptResult.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.service.results;
+
+import android.os.Parcel;
+
+import org.openintents.openpgp.OpenPgpMetadata;
+import org.openintents.openpgp.OpenPgpSignatureResult;
+
+import java.util.Date;
+
+public class SignEncryptResult extends OperationResultParcel {
+
+ // the fourth bit indicates a "data pending" result!
+ public static final int RESULT_PENDING = 8;
+
+ // fifth to sixth bit in addition indicate specific type of pending
+ public static final int RESULT_PENDING_NFC = RESULT_PENDING +16;
+
+ byte[] mNfcHash;
+ int mNfcAlgo;
+ Date mNfcTimestamp;
+
+ public void setNfcData(byte[] sessionKey, int nfcAlgo, Date nfcTimestamp) {
+ mNfcHash = sessionKey;
+ mNfcAlgo = nfcAlgo;
+ mNfcTimestamp = nfcTimestamp;
+ }
+
+ public byte[] getNfcHash() {
+ return mNfcHash;
+ }
+
+ public int getNfcAlgo() {
+ return mNfcAlgo;
+ }
+
+ public Date getNfcTimestamp() {
+ return mNfcTimestamp;
+ }
+
+ public boolean isPending() {
+ return (mResult & RESULT_PENDING) != 0;
+ }
+
+ public SignEncryptResult(int result, OperationLog log) {
+ super(result, log);
+ }
+
+ public SignEncryptResult(Parcel source) {
+ super(source);
+ mNfcHash = source.readInt() != 0 ? source.createByteArray() : null;
+ mNfcAlgo = source.readInt();
+ mNfcTimestamp = source.readInt() != 0 ? new Date(source.readLong()) : null;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ if (mNfcHash != null) {
+ dest.writeInt(1);
+ dest.writeByteArray(mNfcHash);
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeInt(mNfcAlgo);
+ if (mNfcHash != null) {
+ dest.writeInt(1);
+ dest.writeLong(mNfcTimestamp.getTime());
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
+ public static final Creator<SignEncryptResult> CREATOR = new Creator<SignEncryptResult>() {
+ public SignEncryptResult createFromParcel(final Parcel source) {
+ return new SignEncryptResult(source);
+ }
+
+ public SignEncryptResult[] newArray(final int size) {
+ return new SignEncryptResult[size];
+ }
+ };
+
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileActivity.java
index 96f8bd983..a5de20986 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileActivity.java
@@ -183,7 +183,7 @@ public class EncryptFileActivity extends DrawerActivity implements EncryptActivi
// Send all information needed to service to edit key in other thread
Intent intent = new Intent(this, KeychainIntentService.class);
- intent.setAction(KeychainIntentService.ACTION_ENCRYPT_SIGN);
+ intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT);
intent.putExtra(KeychainIntentService.EXTRA_DATA, createEncryptBundle());
// Message is received after encrypting is done in KeychainIntentService
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
index 6e6e52562..4bf1cad3c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
@@ -42,6 +42,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
+import org.sufficientlysecure.keychain.service.results.SignEncryptResult;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Notify;
@@ -184,7 +185,7 @@ public class EncryptTextActivity extends DrawerActivity implements EncryptActivi
// Send all information needed to service to edit key in other thread
Intent intent = new Intent(this, KeychainIntentService.class);
- intent.setAction(KeychainIntentService.ACTION_ENCRYPT_SIGN);
+ intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT);
intent.putExtra(KeychainIntentService.EXTRA_DATA, createEncryptBundle());
// Message is received after encrypting is done in KeychainIntentService
@@ -195,14 +196,26 @@ public class EncryptTextActivity extends DrawerActivity implements EncryptActivi
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
+
+ SignEncryptResult result =
+ message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT);
+
+ // TODO if (result.isPending())
+
+ if (!result.success()) {
+ result.createNotify(EncryptTextActivity.this).show();
+ return;
+ }
+
if (mShareAfterEncrypt) {
// Share encrypted message/file
startActivity(sendWithChooserExcludingEncrypt(message));
} else {
// Copy to clipboard
copyToClipboard(message);
- Notify.showNotify(EncryptTextActivity.this,
- R.string.encrypt_sign_clipboard_successful, Notify.Style.INFO);
+ result.createNotify(EncryptTextActivity.this).show();
+ // Notify.showNotify(EncryptTextActivity.this,
+ // R.string.encrypt_sign_clipboard_successful, Notify.Style.INFO);
}
}
}
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 62299ed34..e1fcf4a0b 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -701,7 +701,7 @@
<string name="msg_mf_error_revoked_primary">"Revoked user ids cannot be primary!"</string>
<string name="msg_mf_error_null_expiry">"Expiry time cannot be "same as before" on subkey creation. This is a programming error, please file a bug report!"</string>
<string name="msg_mf_error_passphrase_master">"Fatal error decrypting master key! This is likely a programming error, please file a bug report!"</string>
- <string name="msg_mf_error_pgp">"PGP internal exception!"</string>
+ <string name="msg_mf_error_pgp">"Internal PGP error!"</string>
<string name="msg_mf_error_sig">"Signature exception!"</string>
<string name="msg_mf_master">"Modifying master certifications"</string>
<string name="msg_mf_passphrase">"Changing passphrase for keyring…"</string>
@@ -803,6 +803,30 @@
<string name="msg_dc_trail_unknown">"Encountered trailing data of unknown type"</string>
<string name="msg_dc_unlocking">"Unlocking secret key"</string>
+ <!-- Messages for SignEncrypt operation -->
+ <string name="msg_se_asymmetric">"Preparing public keys for encryption"</string>
+ <string name="msg_se_clearsign_only">"Signing of cleartext input not supported!"</string>
+ <string name="msg_se_compressing">"Preparing compression"</string>
+ <string name="msg_se_encrypting">"Encrypting data"</string>
+ <string name="msg_se_error_bad_passphrase">"Bad passphrase!"</string>
+ <string name="msg_se_error_io">"Encountered IO Exception during operation!"</string>
+ <string name="msg_se_error_key_sign">"Selected signing key cannot sign data!"</string>
+ <string name="msg_se_error_sign_key">"Error fetching signing key!"</string>
+ <string name="msg_se_error_nfc">"NFC data error!"</string>
+ <string name="msg_se_error_no_passphrase">"No passphrase provided!"</string>
+ <string name="msg_se_error_pgp">"Internal PGP error!"</string>
+ <string name="msg_se_error_sig">"Encountered PGP signature exception!"</string>
+ <string name="msg_se_error_unlock">"Unknown error unlocking key!"</string>
+ <string name="msg_se_key_ok">"Encrypting for key: %s"</string>
+ <string name="msg_se_key_unknown">"Missing key for encryption: %s"</string>
+ <string name="msg_se_key_warn">"Bad key for encryption: %s"</string>
+ <string name="msg_se_ok">"Sign/Encrypt operation successful!"</string>
+ <string name="msg_se_pending_nfc">"NFC token required, requesting user input…"</string>
+ <string name="msg_se_signing">"Signing data (without encryption)"</string>
+ <string name="msg_se_sigcrypting">"Encrypting data with signature"</string>
+ <string name="msg_se">"Starting sign and/or encrypt operation"</string>
+ <string name="msg_se_symmetric">"Preparing symmetric encryption"</string>
+
<!-- PassphraseCache -->
<string name="passp_cache_notif_click_to_clear">"Click to clear cached passphrases"</string>
<string name="passp_cache_notif_n_keys">"OpenKeychain has cached %d passphrases"</string>