diff options
Diffstat (limited to 'OpenKeychain/src')
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> |