diff options
Diffstat (limited to 'OpenKeychain')
25 files changed, 202 insertions, 1207 deletions
diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index b92d49d28..9b52bb788 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -671,12 +671,6 @@ taskAffinity and allowTaskReparenting somehow prevents this from happening! --> <activity - android:name=".ui.NfcActivity" - android:launchMode="singleTop" - android:taskAffinity=":Nfc" - android:allowTaskReparenting="true" /> - - <activity android:name=".ui.NfcOperationActivity" android:launchMode="singleTop" android:taskAffinity=":Nfc" diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java index b5552a40d..d718d231e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java @@ -20,14 +20,21 @@ package org.sufficientlysecure.keychain.operations; import android.content.Context; import android.net.Uri; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; +import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType; import org.sufficientlysecure.keychain.util.FileHelper; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.ProgressScaler; @@ -55,7 +62,7 @@ public class SignEncryptOperation extends BaseOperation { super(context, providerHelper, progressable, cancelled); } - public SignEncryptResult execute(SignEncryptParcel input) { + public SignEncryptResult execute(SignEncryptParcel input, CryptoInputParcel cryptoInput) { OperationLog log = new OperationLog(); log.add(LogType.MSG_SE, 0); @@ -68,6 +75,20 @@ public class SignEncryptOperation extends BaseOperation { int total = inputBytes != null ? 1 : inputUris.size(), count = 0; ArrayList<PgpSignEncryptResult> results = new ArrayList<>(); + NfcSignOperationsBuilder pendingInputBuilder = null; + + if (input.getSignatureMasterKeyId() != Constants.key.none + && input.getSignatureSubKeyId() == null) { + try { + long signKeyId = mProviderHelper.getCachedPublicKeyRing( + input.getSignatureMasterKeyId()).getSecretSignId(); + input.setSignatureSubKeyId(signKeyId); + } catch (PgpKeyNotFoundException e) { + e.printStackTrace(); + return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log, results); + } + } + do { if (checkCancelled()) { @@ -123,15 +144,22 @@ public class SignEncryptOperation extends BaseOperation { PgpSignEncryptOperation op = new PgpSignEncryptOperation(mContext, mProviderHelper, new ProgressScaler(mProgressable, 100 * count / total, 100 * ++count / total, 100), mCancelled); - PgpSignEncryptResult result = op.execute(input, inputData, outStream); + PgpSignEncryptResult result = op.execute(input, cryptoInput, inputData, outStream); results.add(result); log.add(result, 2); if (result.isPending()) { - return new SignEncryptResult(SignEncryptResult.RESULT_PENDING, log, results); - } - - if (!result.success()) { + RequiredInputParcel requiredInput = result.getRequiredInputParcel(); + // Passphrase returns immediately, nfc are aggregated + if (requiredInput.mType == RequiredInputType.PASSPHRASE) { + return new SignEncryptResult(log, requiredInput, results); + } + if (pendingInputBuilder == null) { + pendingInputBuilder = new NfcSignOperationsBuilder(requiredInput.mSignatureTime, + input.getSignatureMasterKeyId(), input.getSignatureSubKeyId()); + } + pendingInputBuilder.addAll(requiredInput); + } else if (!result.success()) { return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log, results); } @@ -141,9 +169,12 @@ public class SignEncryptOperation extends BaseOperation { } while (!inputUris.isEmpty()); + if (pendingInputBuilder != null && !pendingInputBuilder.isEmpty()) { + return new SignEncryptResult(log, pendingInputBuilder.build(), results); + } + if (!outputUris.isEmpty()) { - // Any output URIs left are indicative of a programming error - log.add(LogType.MSG_SE_WARN_OUTPUT_LEFT, 1); + throw new AssertionError("Got outputs left but no inputs. This is a programming error, please report!"); } log.add(LogType.MSG_SE_SUCCESS, 1); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java index 45a6b98b8..0b7aa6d03 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java @@ -18,6 +18,8 @@ package org.sufficientlysecure.keychain.operations.results; +import java.util.ArrayList; + import android.os.Parcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index 47f9271e1..55d5d974a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -671,7 +671,6 @@ public abstract class OperationResult implements Parcelable { MSG_SE_ERROR_INPUT_URI_NOT_FOUND (LogLevel.ERROR, R.string.msg_se_error_input_uri_not_found), MSG_SE_ERROR_OUTPUT_URI_NOT_FOUND (LogLevel.ERROR, R.string.msg_se_error_output_uri_not_found), MSG_SE_ERROR_TOO_MANY_INPUTS (LogLevel.ERROR, R.string.msg_se_error_too_many_inputs), - MSG_SE_WARN_OUTPUT_LEFT (LogLevel.WARN, R.string.msg_se_warn_output_left), MSG_SE_SUCCESS (LogLevel.OK, R.string.msg_se_success), // pgpsignencrypt diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java index bda9893dd..acb265462 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java @@ -19,78 +19,31 @@ package org.sufficientlysecure.keychain.operations.results; import android.os.Parcel; -import org.sufficientlysecure.keychain.util.Passphrase; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; -import java.util.Date; -public class PgpSignEncryptResult extends OperationResult { +public class PgpSignEncryptResult extends InputPendingResult { - // the fourth bit indicates a "data pending" result! (it's also a form of non-success) - public static final int RESULT_PENDING = RESULT_ERROR + 8; - - // fifth to sixth bit in addition indicate specific type of pending - public static final int RESULT_PENDING_PASSPHRASE = RESULT_PENDING + 16; - public static final int RESULT_PENDING_NFC = RESULT_PENDING + 32; - - long mKeyIdPassphraseNeeded; - - long mNfcKeyId; - byte[] mNfcHash; - int mNfcAlgo; - Passphrase mNfcPassphrase; byte[] mDetachedSignature; - public long getKeyIdPassphraseNeeded() { - return mKeyIdPassphraseNeeded; - } - - public void setKeyIdPassphraseNeeded(long keyIdPassphraseNeeded) { - mKeyIdPassphraseNeeded = keyIdPassphraseNeeded; - } - - public void setNfcData(long nfcKeyId, byte[] nfcHash, int nfcAlgo, Passphrase passphrase) { - mNfcKeyId = nfcKeyId; - mNfcHash = nfcHash; - mNfcAlgo = nfcAlgo; - mNfcPassphrase = passphrase; - } - public void setDetachedSignature(byte[] detachedSignature) { mDetachedSignature = detachedSignature; } - public long getNfcKeyId() { - return mNfcKeyId; - } - - public byte[] getNfcHash() { - return mNfcHash; - } - - public int getNfcAlgo() { - return mNfcAlgo; - } - - public Passphrase getNfcPassphrase() { - return mNfcPassphrase; - } - public byte[] getDetachedSignature() { return mDetachedSignature; } - public boolean isPending() { - return (mResult & RESULT_PENDING) == RESULT_PENDING; - } - public PgpSignEncryptResult(int result, OperationLog log) { super(result, log); } + public PgpSignEncryptResult(OperationLog log, RequiredInputParcel requiredInput) { + super(log, requiredInput); + } + public PgpSignEncryptResult(Parcel source) { super(source); - mNfcHash = source.readInt() != 0 ? source.createByteArray() : null; - mNfcAlgo = source.readInt(); mDetachedSignature = source.readInt() != 0 ? source.createByteArray() : null; } @@ -100,13 +53,6 @@ public class PgpSignEncryptResult extends OperationResult { 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 (mDetachedSignature != null) { dest.writeInt(1); dest.writeByteArray(mDetachedSignature); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java index 87483ade9..b05921b0d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java @@ -21,22 +21,17 @@ import android.os.Parcel; import java.util.ArrayList; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; -public class SignEncryptResult extends OperationResult { + +public class SignEncryptResult extends InputPendingResult { ArrayList<PgpSignEncryptResult> mResults; byte[] mResultBytes; - public static final int RESULT_PENDING = RESULT_ERROR + 8; - - - public PgpSignEncryptResult getPending() { - for (PgpSignEncryptResult sub : mResults) { - if (sub.isPending()) { - return sub; - } - } - return null; + public SignEncryptResult(OperationLog log, RequiredInputParcel requiredInput, ArrayList<PgpSignEncryptResult> results) { + super(log, requiredInput); + mResults = results; } public SignEncryptResult(int result, OperationLog log, ArrayList<PgpSignEncryptResult> results) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java index d5f3cf964..fd3c4910c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java @@ -42,14 +42,12 @@ public class PgpSignEncryptInputParcel implements Parcelable { protected long mSignatureMasterKeyId = Constants.key.none; protected Long mSignatureSubKeyId = null; protected int mSignatureHashAlgorithm = PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED; - protected Passphrase mSignaturePassphrase = null; protected long mAdditionalEncryptId = Constants.key.none; protected boolean mFailOnMissingEncryptionKeyIds = false; protected String mCharset; protected boolean mCleartextSignature; protected boolean mDetachedSignature = false; protected boolean mHiddenRecipients = false; - protected CryptoInputParcel mCryptoInput = new CryptoInputParcel(); public PgpSignEncryptInputParcel() { @@ -69,15 +67,12 @@ public class PgpSignEncryptInputParcel implements Parcelable { mSignatureMasterKeyId = source.readLong(); mSignatureSubKeyId = source.readInt() == 1 ? source.readLong() : null; mSignatureHashAlgorithm = source.readInt(); - mSignaturePassphrase = source.readParcelable(loader); mAdditionalEncryptId = source.readLong(); mFailOnMissingEncryptionKeyIds = source.readInt() == 1; mCharset = source.readString(); mCleartextSignature = source.readInt() == 1; mDetachedSignature = source.readInt() == 1; mHiddenRecipients = source.readInt() == 1; - - mCryptoInput = source.readParcelable(loader); } @Override @@ -101,15 +96,12 @@ public class PgpSignEncryptInputParcel implements Parcelable { dest.writeInt(0); } dest.writeInt(mSignatureHashAlgorithm); - dest.writeParcelable(mSignaturePassphrase, 0); dest.writeLong(mAdditionalEncryptId); dest.writeInt(mFailOnMissingEncryptionKeyIds ? 1 : 0); dest.writeString(mCharset); dest.writeInt(mCleartextSignature ? 1 : 0); dest.writeInt(mDetachedSignature ? 1 : 0); dest.writeInt(mHiddenRecipients ? 1 : 0); - - dest.writeParcelable(mCryptoInput, 0); } public String getCharset() { @@ -133,15 +125,6 @@ public class PgpSignEncryptInputParcel implements Parcelable { return this; } - public Passphrase getSignaturePassphrase() { - return mSignaturePassphrase; - } - - public PgpSignEncryptInputParcel setSignaturePassphrase(Passphrase signaturePassphrase) { - mSignaturePassphrase = signaturePassphrase; - return this; - } - public int getSignatureHashAlgorithm() { return mSignatureHashAlgorithm; } @@ -255,19 +238,6 @@ public class PgpSignEncryptInputParcel implements Parcelable { return mHiddenRecipients; } - public PgpSignEncryptInputParcel setCryptoInput(CryptoInputParcel cryptoInput) { - mCryptoInput = cryptoInput; - return this; - } - - public Map<ByteBuffer, byte[]> getCryptoData() { - return mCryptoInput.getCryptoData(); - } - - public Date getSignatureTime() { - return mCryptoInput.getSignatureTime(); - } - public static final Creator<PgpSignEncryptInputParcel> CREATOR = new Creator<PgpSignEncryptInputParcel>() { public PgpSignEncryptInputParcel createFromParcel(final Parcel source) { return new PgpSignEncryptInputParcel(source); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java index ef19e3fa1..0b22df790 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java @@ -40,10 +40,13 @@ import org.sufficientlysecure.keychain.operations.BaseOperation; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; +import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; @@ -99,7 +102,7 @@ public class PgpSignEncryptOperation extends BaseOperation { /** * Signs and/or encrypts data based on parameters of class */ - public PgpSignEncryptResult execute(PgpSignEncryptInputParcel input, + public PgpSignEncryptResult execute(PgpSignEncryptInputParcel input, CryptoInputParcel cryptoInput, InputData inputData, OutputStream outputStream) { int indent = 0; @@ -145,62 +148,39 @@ public class PgpSignEncryptOperation extends BaseOperation { CanonicalizedSecretKey signingKey = null; if (enableSignature) { + updateProgress(R.string.progress_extracting_signature_key, 0, 100); + try { // fetch the indicated master key id (the one whose name we sign in) CanonicalizedSecretKeyRing signingKeyRing = mProviderHelper.getCanonicalizedSecretKeyRing(input.getSignatureMasterKeyId()); - long signKeyId; - // use specified signing subkey, or find the one to use - if (input.getSignatureSubKeyId() == null) { - signKeyId = signingKeyRing.getSecretSignId(); - } else { - signKeyId = input.getSignatureSubKeyId(); - } - // fetch the specific subkey to sign with, or just use the master key if none specified - signingKey = signingKeyRing.getSecretKey(signKeyId); - - } catch (ProviderHelper.NotFoundException | PgpGeneralException e) { - log.add(LogType.MSG_PSE_ERROR_SIGN_KEY, indent); - return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); - } - - // Make sure we are allowed to sign here! - if (!signingKey.canSign()) { - log.add(LogType.MSG_PSE_ERROR_KEY_SIGN, indent); - return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); - } + signingKey = signingKeyRing.getSecretKey(input.getSignatureSubKeyId()); - // if no passphrase was explicitly set try to get it from the cache service - if (input.getSignaturePassphrase() == null) { - try { - // returns "" if key has no passphrase - input.setSignaturePassphrase(getCachedPassphrase(signingKey.getKeyId())); - // TODO -// log.add(LogType.MSG_DC_PASS_CACHED, indent + 1); - } catch (PassphraseCacheInterface.NoSecretKeyException e) { - // TODO -// log.add(LogType.MSG_DC_ERROR_NO_KEY, indent + 1); + // Make sure we are allowed to sign here! + if (!signingKey.canSign()) { + log.add(LogType.MSG_PSE_ERROR_KEY_SIGN, indent); return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); } - // if passphrase was not cached, return here indicating that a passphrase is missing! - if (input.getSignaturePassphrase() == null) { - log.add(LogType.MSG_PSE_PENDING_PASSPHRASE, indent + 1); - PgpSignEncryptResult result = new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE, log); - result.setKeyIdPassphraseNeeded(signingKey.getKeyId()); - return result; + if (signingKey.getSecretKeyType() != SecretKeyType.DIVERT_TO_CARD) { + if (cryptoInput.getPassphrase() == null) { + log.add(LogType.MSG_PSE_PENDING_PASSPHRASE, indent + 1); + return new PgpSignEncryptResult(log, RequiredInputParcel.createRequiredPassphrase( + signingKeyRing.getMasterKeyId(), signingKey.getKeyId(), + cryptoInput.getSignatureTime())); + } } - } - updateProgress(R.string.progress_extracting_signature_key, 0, 100); - - try { - if (!signingKey.unlock(input.getSignaturePassphrase())) { + if (!signingKey.unlock(cryptoInput.getPassphrase())) { log.add(LogType.MSG_PSE_ERROR_BAD_PASSPHRASE, indent); return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); } + + } catch (ProviderHelper.NotFoundException e) { + log.add(LogType.MSG_PSE_ERROR_SIGN_KEY, indent); + return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); } catch (PgpGeneralException e) { log.add(LogType.MSG_PSE_ERROR_UNLOCK, indent); return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); @@ -283,7 +263,7 @@ public class PgpSignEncryptOperation extends BaseOperation { boolean cleartext = input.isCleartextSignature() && input.isEnableAsciiArmorOutput() && !enableEncryption; signatureGenerator = signingKey.getDataSignatureGenerator( input.getSignatureHashAlgorithm(), cleartext, - input.getCryptoData(), input.getSignatureTime()); + cryptoInput.getCryptoData(), cryptoInput.getSignatureTime()); } catch (PgpGeneralException e) { log.add(LogType.MSG_PSE_ERROR_NFC, indent); return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); @@ -486,20 +466,8 @@ public class PgpSignEncryptOperation extends BaseOperation { } catch (NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded e) { // this secret key diverts to a OpenPGP card, throw exception with hash that will be signed log.add(LogType.MSG_PSE_PENDING_NFC, indent); - PgpSignEncryptResult result = - new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_PENDING_NFC, log); - - // SignatureSubKeyId can be null. - if (input.getSignatureSubKeyId() == null) { - return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); - } - - // Note that the checked key here is the master key, not the signing key - // (although these are always the same on Yubikeys) - result.setNfcData(signingKey.getKeyId(), e.hashToSign, e.hashAlgo, - input.getSignaturePassphrase()); - Log.d(Constants.TAG, "e.hashToSign" + Hex.toHexString(e.hashToSign)); - return result; + return new PgpSignEncryptResult(log, RequiredInputParcel.createNfcSignOperation( + e.hashToSign, e.hashAlgo, cryptoInput.getSignatureTime())); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java index b178e9515..464de37f5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java @@ -21,12 +21,9 @@ package org.sufficientlysecure.keychain.pgp; import android.net.Uri; import android.os.Parcel; -import org.sufficientlysecure.keychain.util.Passphrase; - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Date; import java.util.List; /** This parcel stores the input of one or more PgpSignEncrypt operations. 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 204af1b67..4760412ea 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -18,6 +18,7 @@ package org.sufficientlysecure.keychain.remote; import android.app.PendingIntent; +import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; @@ -31,7 +32,6 @@ import org.openintents.openpgp.OpenPgpMetadata; import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.util.OpenPgpApi; import org.spongycastle.bcpg.CompressionAlgorithmTags; -import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel; @@ -49,19 +49,18 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.remote.ui.RemoteServiceActivity; import org.sufficientlysecure.keychain.remote.ui.SelectSignKeyIdActivity; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.ImportKeysActivity; -import org.sufficientlysecure.keychain.ui.NfcActivity; +import org.sufficientlysecure.keychain.ui.NfcOperationActivity; 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 org.sufficientlysecure.keychain.util.Passphrase; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; -import java.util.Date; import java.util.Set; public class OpenPgpService extends RemoteService { @@ -79,9 +78,6 @@ public class OpenPgpService extends RemoteService { /** * Search database for key ids based on emails. - * - * @param encryptionUserIds - * @return */ private Intent returnKeyIdsFromEmails(Intent data, String[] encryptionUserIds) { boolean noUserIdsCheck = (encryptionUserIds == null || encryptionUserIds.length == 0); @@ -164,52 +160,35 @@ public class OpenPgpService extends RemoteService { } } - private Intent returnPassphraseIntent(Intent data, long keyId) { - // build PendingIntent for passphrase input - Intent intent = new Intent(getBaseContext(), PassphraseDialogActivity.class); - intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, keyId); - // pass params through to activity that it can be returned again later to repeat pgp operation - intent.putExtra(PassphraseDialogActivity.EXTRA_DATA, data); - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, - intent, - PendingIntent.FLAG_CANCEL_CURRENT); - - // return PendingIntent to be executed by client - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - return result; - } + private static PendingIntent getRequiredInputPendingIntent(Context context, + Intent data, RequiredInputParcel requiredInput) { + + switch (requiredInput.mType) { + case NFC_DECRYPT: + case NFC_SIGN: { + // build PendingIntent for Yubikey NFC operations + Intent intent = new Intent(context, NfcOperationActivity.class); + // pass params through to activity that it can be returned again later to repeat pgp operation + intent.putExtra(NfcOperationActivity.EXTRA_SERVICE_INTENT, data); + intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput); + return PendingIntent.getActivity(context, 0, intent, + PendingIntent.FLAG_CANCEL_CURRENT); + } - private PendingIntent getNfcSignPendingIntent(Intent data, long keyId, Passphrase pin, byte[] hashToSign, int hashAlgo) { - // build PendingIntent for Yubikey NFC operations - Intent intent = new Intent(getBaseContext(), NfcActivity.class); - intent.setAction(NfcActivity.ACTION_SIGN_HASH); - // pass params through to activity that it can be returned again later to repeat pgp operation - intent.putExtra(NfcActivity.EXTRA_DATA, data); - intent.putExtra(NfcActivity.EXTRA_PIN, pin); - intent.putExtra(NfcActivity.EXTRA_KEY_ID, keyId); - - intent.putExtra(NfcActivity.EXTRA_NFC_HASH_TO_SIGN, hashToSign); - intent.putExtra(NfcActivity.EXTRA_NFC_HASH_ALGO, hashAlgo); - return PendingIntent.getActivity(getBaseContext(), 0, - intent, - PendingIntent.FLAG_CANCEL_CURRENT); - } + case PASSPHRASE: { + // build PendingIntent for Passphrase request + Intent intent = new Intent(context, PassphraseDialogActivity.class); + // pass params through to activity that it can be returned again later to repeat pgp operation + intent.putExtra(PassphraseDialogActivity.EXTRA_SERVICE_INTENT, data); + intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, requiredInput); + return PendingIntent.getActivity(context, 0, intent, + PendingIntent.FLAG_CANCEL_CURRENT); + } - private PendingIntent getNfcDecryptPendingIntent(Intent data, long subKeyId, Passphrase pin, byte[] encryptedSessionKey) { - // build PendingIntent for Yubikey NFC operations - Intent intent = new Intent(getBaseContext(), NfcActivity.class); - intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY); - // pass params through to activity that it can be returned again later to repeat pgp operation - intent.putExtra(NfcActivity.EXTRA_DATA, data); - intent.putExtra(NfcActivity.EXTRA_PIN, pin); - intent.putExtra(NfcActivity.EXTRA_KEY_ID, subKeyId); + default: + throw new AssertionError("Unhandled required input type!"); + } - intent.putExtra(NfcActivity.EXTRA_NFC_ENC_SESSION_KEY, encryptedSessionKey); - return PendingIntent.getActivity(getBaseContext(), 0, - intent, - PendingIntent.FLAG_CANCEL_CURRENT); } private PendingIntent getKeyserverPendingIntent(Intent data, long masterKeyId) { @@ -241,18 +220,6 @@ public class OpenPgpService extends RemoteService { try { boolean asciiArmor = cleartextSign || data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); - Passphrase passphrase = null; - if (data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE) != null) { - passphrase = new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE)); - } - - byte[] nfcSignedHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH); - if (nfcSignedHash != null) { - Log.d(Constants.TAG, "nfcSignedHash:" + Hex.toHexString(nfcSignedHash)); - } else { - Log.d(Constants.TAG, "nfcSignedHash: null"); - } - Intent signKeyIdIntent = getSignKeyMasterId(data); // NOTE: Fallback to return account settings (Old API) if (signKeyIdIntent.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR) @@ -264,16 +231,6 @@ public class OpenPgpService extends RemoteService { Log.e(Constants.TAG, "No signing key given!"); } - // carefully: only set if timestamp exists - Date nfcCreationDate; - long nfcCreationTimestamp = data.getLongExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, -1); - Log.d(Constants.TAG, "nfcCreationTimestamp: " + nfcCreationTimestamp); - if (nfcCreationTimestamp != -1) { - nfcCreationDate = new Date(nfcCreationTimestamp); - } else { - nfcCreationDate = new Date(); - } - // Get Input- and OutputStream from ParcelFileDescriptor is = new ParcelFileDescriptor.AutoCloseInputStream(input); if (cleartextSign) { @@ -284,45 +241,32 @@ public class OpenPgpService extends RemoteService { long inputLength = is.available(); InputData inputData = new InputData(is, inputLength); - CryptoInputParcel cryptoInput = new CryptoInputParcel(nfcCreationDate); - cryptoInput.addCryptoData(null, nfcSignedHash); // TODO fix + CryptoInputParcel cryptoInput = data.getParcelableExtra(OpenPgpApi.EXTRA_CRYPTO_INPUT); // sign-only PgpSignEncryptInputParcel pseInput = new PgpSignEncryptInputParcel() - .setSignaturePassphrase(passphrase) .setEnableAsciiArmorOutput(asciiArmor) .setCleartextSignature(cleartextSign) .setDetachedSignature(!cleartextSign) .setVersionHeader(null) .setSignatureHashAlgorithm(PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED) - .setSignatureMasterKeyId(signKeyId) - .setCryptoInput(cryptoInput); + .setSignatureMasterKeyId(signKeyId); // execute PGP operation! PgpSignEncryptOperation pse = new PgpSignEncryptOperation(this, new ProviderHelper(getContext()), null); - PgpSignEncryptResult pgpResult = pse.execute(pseInput, inputData, os); + PgpSignEncryptResult pgpResult = pse.execute(pseInput, cryptoInput, inputData, os); if (pgpResult.isPending()) { - if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) == - PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) { - return returnPassphraseIntent(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, nfcCreationDate.getTime()); - - // return PendingIntent to be executed by client - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_INTENT, - getNfcSignPendingIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo())); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - return result; - } else { - throw new PgpGeneralException( - "Encountered unhandled type of pending action not supported by API!"); - } + + RequiredInputParcel requiredInput = pgpResult.getRequiredInputParcel(); + PendingIntent pIntent = getRequiredInputPendingIntent(getBaseContext(), data, requiredInput); + + // return PendingIntent to be executed by client + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_INTENT, pIntent); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); + return result; + } else if (pgpResult.success()) { Intent result = new Intent(); if (pgpResult.getDetachedSignature() != null && !cleartextSign) { @@ -378,11 +322,6 @@ public class OpenPgpService extends RemoteService { compressionId = CompressionAlgorithmTags.UNCOMPRESSED; } - Passphrase passphrase = null; - if (data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE) != null) { - passphrase = new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE)); - } - // first try to get key ids from non-ambiguous key id extra long[] keyIds = data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS); if (keyIds == null) { @@ -408,8 +347,7 @@ public class OpenPgpService extends RemoteService { InputData inputData = new InputData(is, inputLength, originalFilename); PgpSignEncryptInputParcel pseInput = new PgpSignEncryptInputParcel(); - pseInput.setSignaturePassphrase(passphrase) - .setEnableAsciiArmorOutput(asciiArmor) + pseInput.setEnableAsciiArmorOutput(asciiArmor) .setVersionHeader(null) .setCompressionId(compressionId) .setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED) @@ -429,51 +367,28 @@ public class OpenPgpService extends RemoteService { Log.e(Constants.TAG, "No signing key given!"); } - byte[] nfcSignedHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH); - // carefully: only set if timestamp exists - Date nfcCreationDate; - long nfcCreationTimestamp = data.getLongExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, -1); - if (nfcCreationTimestamp != -1) { - nfcCreationDate = new Date(nfcCreationTimestamp); - } else { - nfcCreationDate = new Date(); - } - - CryptoInputParcel cryptoInput = new CryptoInputParcel(nfcCreationDate); - cryptoInput.addCryptoData(null, nfcSignedHash); // TODO fix! - // sign and encrypt pseInput.setSignatureHashAlgorithm(PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED) .setSignatureMasterKeyId(signKeyId) - .setCryptoInput(cryptoInput) .setAdditionalEncryptId(signKeyId); // add sign key for encryption } + CryptoInputParcel cryptoInput = data.getParcelableExtra(OpenPgpApi.EXTRA_CRYPTO_INPUT); + PgpSignEncryptOperation op = new PgpSignEncryptOperation(this, new ProviderHelper(getContext()), null); // execute PGP operation! - PgpSignEncryptResult pgpResult = op.execute(pseInput, inputData, os); + PgpSignEncryptResult pgpResult = op.execute(pseInput, cryptoInput, inputData, os); if (pgpResult.isPending()) { - if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) == - PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) { - return returnPassphraseIntent(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, 0L); // TODO fix - // return PendingIntent to be executed by client - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_INTENT, - getNfcSignPendingIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo())); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - return result; - } else { - throw new PgpGeneralException( - "Encountered unhandled type of pending action not supported by API!"); - } + RequiredInputParcel requiredInput = pgpResult.getRequiredInputParcel(); + PendingIntent pIntent = getRequiredInputPendingIntent(getBaseContext(), data, requiredInput); + + // return PendingIntent to be executed by client + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_INTENT, pIntent); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); + return result; } else if (pgpResult.success()) { Intent result = new Intent(); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); @@ -522,11 +437,6 @@ public class OpenPgpService extends RemoteService { os = new ParcelFileDescriptor.AutoCloseOutputStream(output); } - Passphrase passphrase = null; - if (data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE) != null) { - passphrase = new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE)); - } - String currentPkg = getCurrentCallingPackage(); Set<Long> allowedKeyIds; if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 7) { @@ -544,17 +454,17 @@ public class OpenPgpService extends RemoteService { this, new ProviderHelper(getContext()), null, inputData, os ); - byte[] nfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY); + CryptoInputParcel cryptoInput = data.getParcelableExtra(OpenPgpApi.EXTRA_CRYPTO_INPUT); 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) + builder.setPassphrase(cryptoInput.getPassphrase()) // TODO proper CryptoInputParcel support .setAllowSymmetricDecryption(false) .setAllowedKeyIds(allowedKeyIds) .setDecryptMetadataOnly(decryptMetadataOnly) - .setNfcState(nfcDecryptedSessionKey) + .setNfcState(null) // TODO proper CryptoInputParcel support .setDetachedSignature(detachedSignature); DecryptVerifyResult pgpResult = builder.build().execute(); @@ -562,20 +472,15 @@ public class OpenPgpService extends RemoteService { if (pgpResult.isPending()) { if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) == DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) { - return returnPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded()); + throw new AssertionError("not implemented"); // TODO + // return returnPassphraseIntent(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 PendingIntent to be executed by client - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_INTENT, - getNfcDecryptPendingIntent(data, pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey())); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - return result; + throw new AssertionError("not implemented"); // TODO } else { throw new PgpGeneralException( "Encountered unhandled type of pending action not supported by API!"); @@ -765,7 +670,6 @@ public class OpenPgpService extends RemoteService { * - has supported API version * - is allowed to call the service (access has been granted) * - * @param data * @return null if everything is okay, or a Bundle with an error/PendingIntent */ private Intent checkRequirements(Intent data) { 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 1a94d70b7..c7d9d5e38 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -46,7 +46,6 @@ import org.sufficientlysecure.keychain.operations.results.CertifyResult; import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.DeleteResult; -import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.ExportResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; @@ -284,14 +283,13 @@ public class KeychainIntentService extends IntentService implements Progressable case ACTION_DECRYPT_METADATA: { try { - /* Input */ + /* Input */ Passphrase passphrase = data.getParcelable(DECRYPT_PASSPHRASE); byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY); InputData inputData = createDecryptInputData(data); - /* Operation */ - + /* Operation */ Bundle resultData = new Bundle(); // verifyText and decrypt returning additional resultData values for the @@ -549,11 +547,12 @@ public class KeychainIntentService extends IntentService implements Progressable // Input SignEncryptParcel inputParcel = data.getParcelable(SIGN_ENCRYPT_PARCEL); + CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT); // Operation SignEncryptOperation op = new SignEncryptOperation( this, new ProviderHelper(this), this, mActionCanceled); - SignEncryptResult result = op.execute(inputParcel); + SignEncryptResult result = op.execute(inputParcel, cryptoInput); // Result sendMessageToHandler(MessageStatus.OKAY, result); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java index 471fc0ec9..5cc2607cc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java @@ -1,6 +1,7 @@ package org.sufficientlysecure.keychain.service.input; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Date; @@ -56,11 +57,11 @@ public class RequiredInputParcel implements Parcelable { } - public long getMasterKeyId() { + public Long getMasterKeyId() { return mMasterKeyId; } - public long getSubKeyId() { + public Long getSubKeyId() { return mSubKeyId; } @@ -88,7 +89,6 @@ public class RequiredInputParcel implements Parcelable { null, null, req.mSignatureTime, req.mMasterKeyId, req.mSubKeyId); } - @Override public int describeContents() { return 0; @@ -142,10 +142,10 @@ public class RequiredInputParcel implements Parcelable { Date mSignatureTime; ArrayList<Integer> mSignAlgos = new ArrayList<>(); ArrayList<byte[]> mInputHashes = new ArrayList<>(); - long mMasterKeyId; - long mSubKeyId; + Long mMasterKeyId; + Long mSubKeyId; - public NfcSignOperationsBuilder(Date signatureTime, long masterKeyId, long subKeyId) { + public NfcSignOperationsBuilder(Date signatureTime, Long masterKeyId, Long subKeyId) { mSignatureTime = signatureTime; mMasterKeyId = masterKeyId; mSubKeyId = subKeyId; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java index 5227c1477..b632509bb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java @@ -66,7 +66,7 @@ public abstract class CryptoOperationFragment extends Fragment { case REQUEST_CODE_PASSPHRASE: { if (resultCode == Activity.RESULT_OK && data != null) { CryptoInputParcel cryptoInput = - data.getParcelableExtra(PassphraseDialogActivity.RESULT_DATA); + data.getParcelableExtra(PassphraseDialogActivity.RESULT_CRYPTO_INPUT); cryptoOperation(cryptoInput); return; } @@ -110,6 +110,10 @@ public abstract class CryptoOperationFragment extends Fragment { return false; } + protected void cryptoOperation() { + cryptoOperation(new CryptoInputParcel()); + } + protected abstract void cryptoOperation(CryptoInputParcel cryptoInput); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java index ecc99b348..d1c005868 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java @@ -198,7 +198,7 @@ public class DecryptFilesFragment extends DecryptFragment { // data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); // data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); // -// intent.putExtra(KeychainIntentService.EXTRA_DATA, data); +// intent.putExtra(KeychainIntentService.EXTRA_SERVICE_INTENT, data); // // // Message is received after decrypting is done in KeychainIntentService // ServiceProgressHandler saveHandler = new ServiceProgressHandler( diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java index f00136d5b..38ad54ad3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -105,7 +105,7 @@ public abstract class DecryptFragment extends CryptoOperationFragment { // // build PendingIntent for Yubikey NFC operations // Intent intent = new Intent(getActivity(), NfcActivity.class); // intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY); -// intent.putExtra(NfcActivity.EXTRA_DATA, new Intent()); // not used, only relevant to OpenPgpService +// intent.putExtra(NfcActivity.EXTRA_SERVICE_INTENT, new Intent()); // not used, only relevant to OpenPgpService // intent.putExtra(NfcActivity.EXTRA_KEY_ID, subKeyId); // intent.putExtra(NfcActivity.EXTRA_PIN, pin); // diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java deleted file mode 100644 index a1edf808c..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * 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.ui; - -import android.app.Activity; -import android.app.ProgressDialog; -import android.content.Intent; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.view.View; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; -import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; -import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; -import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; -import org.sufficientlysecure.keychain.ui.base.BaseActivity; -import org.sufficientlysecure.keychain.service.ServiceProgressHandler; -import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; -import org.sufficientlysecure.keychain.util.Passphrase; - -public abstract class EncryptActivity extends BaseActivity { - - public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; - public static final int REQUEST_CODE_NFC = 0x00008002; - - // For NFC data - protected Passphrase mSigningKeyPassphrase = null; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setFullScreenDialogClose(new View.OnClickListener() { - @Override - public void onClick(View v) { - setResult(Activity.RESULT_CANCELED); - finish(); - } - }, false); - } - - protected void startPassphraseDialog(long subkeyId) { - Intent intent = new Intent(this, PassphraseDialogActivity.class); - intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, subkeyId); - startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); - } - - protected void startNfcSign(long keyId, RequiredInputParcel nfcOps) { - - Intent intent = new Intent(this, NfcOperationActivity.class); - intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, nfcOps); - // TODO respect keyid(?) - - startActivityForResult(intent, REQUEST_CODE_NFC); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case REQUEST_CODE_PASSPHRASE: { - if (resultCode == RESULT_OK && data != null) { - mSigningKeyPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); - startEncrypt(); - return; - } - break; - } - - case REQUEST_CODE_NFC: { - if (resultCode == RESULT_OK && data != null) { - CryptoInputParcel cryptoInput = - data.getParcelableExtra(NfcOperationActivity.RESULT_DATA); - startEncrypt(cryptoInput); - return; - } - break; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - break; - } - } - } - - public void startEncrypt() { - startEncrypt(null); - } - - public void startEncrypt(CryptoInputParcel cryptoInput) { - if (!inputIsValid()) { - // Notify was created by inputIsValid. - return; - } - - // Send all information needed to service to edit key in other thread - Intent intent = new Intent(this, KeychainIntentService.class); - intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT); - - final SignEncryptParcel input = createEncryptBundle(); - if (cryptoInput != null) { - input.setCryptoInput(cryptoInput); - } - - Bundle data = new Bundle(); - data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, input); - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Message is received after encrypting is done in KeychainIntentService - ServiceProgressHandler serviceHandler = new ServiceProgressHandler( - this, - getString(R.string.progress_encrypting), - ProgressDialog.STYLE_HORIZONTAL, - ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == MessageStatus.OKAY.ordinal()) { - SignEncryptResult result = - message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT); - - PgpSignEncryptResult pgpResult = result.getPending(); - - if (pgpResult != null && pgpResult.isPending()) { - if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) == - PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) { - startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); - } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) == - PgpSignEncryptResult.RESULT_PENDING_NFC) { - - RequiredInputParcel parcel = RequiredInputParcel.createNfcSignOperation( - pgpResult.getNfcHash(), - pgpResult.getNfcAlgo(), - input.getSignatureTime()); - startNfcSign(pgpResult.getNfcKeyId(), parcel); - - } else { - throw new RuntimeException("Unhandled pending result!"); - } - return; - } - - if (result.success()) { - onEncryptSuccess(result); - } else { - result.createNotify(EncryptActivity.this).show(); - } - - // no matter the result, reset parameters - mSigningKeyPassphrase = null; - } - } - }; - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(serviceHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - serviceHandler.showProgressDialog(this); - - // start service with intent - startService(intent); - } - - protected abstract boolean inputIsValid(); - - protected abstract void onEncryptSuccess(SignEncryptResult result); - - protected abstract SignEncryptParcel createEncryptBundle(); - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index dad8704fb..1a67bc8dd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -137,7 +137,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { try { mModeInterface = (IMode) activity; } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must be IMode"); + throw new ClassCastException(activity + " must be IMode"); } } @@ -369,11 +369,6 @@ public class EncryptFilesFragment extends CryptoOperationFragment { return true; } - public void startEncrypt(boolean share) { - mShareAfterEncrypt = share; - cryptoOperation(new CryptoInputParcel()); - } - public void onEncryptSuccess(final SignEncryptResult result) { if (mDeleteAfterEncrypt) { DeleteFileDialogFragment deleteFileDialog = @@ -479,6 +474,11 @@ public class EncryptFilesFragment extends CryptoOperationFragment { return sendIntent; } + public void startEncrypt(boolean share) { + mShareAfterEncrypt = share; + cryptoOperation(); + } + @Override protected void cryptoOperation(CryptoInputParcel cryptoInput) { @@ -494,12 +494,10 @@ public class EncryptFilesFragment extends CryptoOperationFragment { intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT); final SignEncryptParcel input = createEncryptBundle(); - if (cryptoInput != null) { - input.setCryptoInput(cryptoInput); - } Bundle data = new Bundle(); data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, input); + data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); // Message is received after encrypting is done in KeychainIntentService @@ -521,36 +519,11 @@ public class EncryptFilesFragment extends CryptoOperationFragment { if (message.arg1 == MessageStatus.OKAY.ordinal()) { SignEncryptResult result = message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT); - -// PgpSignEncryptResult pgpResult = result.getPending(); -// -// if (pgpResult != null && pgpResult.isPending()) { -// if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) == -// PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) { -// startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); -// } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) == -// PgpSignEncryptResult.RESULT_PENDING_NFC) { -// -// RequiredInputParcel parcel = RequiredInputParcel.createNfcSignOperation( -// pgpResult.getNfcHash(), -// pgpResult.getNfcAlgo(), -// input.getSignatureTime()); -// startNfcSign(pgpResult.getNfcKeyId(), parcel); -// -// } else { -// throw new RuntimeException("Unhandled pending result!"); -// } -// return; -// } - if (result.success()) { onEncryptSuccess(result); } else { result.createNotify(getActivity()).show(); } - - // no matter the result, reset parameters -// mSigningKeyPassphrase = null; } } }; 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 2ffb29b09..03ab48e23 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -160,6 +160,6 @@ public class EncryptTextActivity extends BaseActivity implements @Override public void onPassphraseChanged(Passphrase passphrase) { - mEncryptFragment.setPassphrase(passphrase); + mEncryptFragment.setSymmetricPassphrase(passphrase); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java index 3303b2c65..fecc9ef52 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -37,7 +37,6 @@ import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; -import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.PgpConstants; @@ -73,7 +72,7 @@ public class EncryptTextFragment extends CryptoOperationFragment { private String mEncryptionUserIds[] = null; // TODO Constants.key.none? What's wrong with a null value? private long mSigningKeyId = Constants.key.none; - private Passphrase mPassphrase = new Passphrase(); + private Passphrase mSymmetricPassphrase = new Passphrase(); private String mMessage = ""; private TextView mText; @@ -90,8 +89,8 @@ public class EncryptTextFragment extends CryptoOperationFragment { mSigningKeyId = signingKeyId; } - public void setPassphrase(Passphrase passphrase) { - mPassphrase = passphrase; + public void setSymmetricPassphrase(Passphrase passphrase) { + mSymmetricPassphrase = passphrase; } /** @@ -233,7 +232,7 @@ public class EncryptTextFragment extends CryptoOperationFragment { if (mSymmetricMode) { Log.d(Constants.TAG, "Symmetric encryption enabled!"); - Passphrase passphrase = mPassphrase; + Passphrase passphrase = mSymmetricPassphrase; if (passphrase.isEmpty()) { passphrase = null; } @@ -241,7 +240,6 @@ public class EncryptTextFragment extends CryptoOperationFragment { } else { data.setEncryptionMasterKeyIds(mEncryptionKeyIds); data.setSignatureMasterKeyId(mSigningKeyId); -// data.setSignaturePassphrase(mSigningKeyPassphrase); } return data; } @@ -296,12 +294,12 @@ public class EncryptTextFragment extends CryptoOperationFragment { if (mSymmetricMode) { // symmetric encryption checks - if (mPassphrase == null) { + if (mSymmetricPassphrase == null) { Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR) .show(); return false; } - if (mPassphrase.isEmpty()) { + if (mSymmetricPassphrase.isEmpty()) { Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR) .show(); return false; @@ -325,11 +323,7 @@ public class EncryptTextFragment extends CryptoOperationFragment { public void startEncrypt(boolean share) { mShareAfterEncrypt = share; - startEncrypt(); - } - - public void startEncrypt() { - cryptoOperation(null); + cryptoOperation(); } @Override @@ -344,12 +338,9 @@ public class EncryptTextFragment extends CryptoOperationFragment { intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT); final SignEncryptParcel input = createEncryptBundle(); - if (cryptoInput != null) { - input.setCryptoInput(cryptoInput); - } - final Bundle data = new Bundle(); data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, input); + data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); // Message is received after encrypting is done in KeychainIntentService @@ -362,45 +353,19 @@ public class EncryptTextFragment extends CryptoOperationFragment { // handle messages by standard KeychainIntentServiceHandler first super.handleMessage(message); - // TODO: We need a InputPendingResult! -// // handle pending messages -// if (handlePendingMessage(message)) { -// return; -// } + if (handlePendingMessage(message)) { + return; + } if (message.arg1 == MessageStatus.OKAY.ordinal()) { SignEncryptResult result = message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT); - PgpSignEncryptResult pgpResult = result.getPending(); - -// if (pgpResult != null && pgpResult.isPending()) { -// if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) == -// PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) { -// startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); -// } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) == -// PgpSignEncryptResult.RESULT_PENDING_NFC) { -// -// RequiredInputParcel parcel = RequiredInputParcel.createNfcSignOperation( -// pgpResult.getNfcHash(), -// pgpResult.getNfcAlgo(), -// input.getSignatureTime()); -// startNfcSign(pgpResult.getNfcKeyId(), parcel); -// -// } else { -// throw new RuntimeException("Unhandled pending result!"); -// } -// return; -// } - if (result.success()) { onEncryptSuccess(result); } else { result.createNotify(getActivity()).show(); } - - // no matter the result, reset parameters -// mSigningKeyPassphrase = null; } } }; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java deleted file mode 100644 index 57acf3e93..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java +++ /dev/null @@ -1,569 +0,0 @@ -/** - * Copyright (c) 2013-2014 Philipp Jakubeit, Signe Rüsch, Dominik Schürmann - * - * Licensed under the Bouncy Castle License (MIT license). See LICENSE file for details. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.annotation.TargetApi; -import android.app.PendingIntent; -import android.content.Intent; -import android.content.IntentFilter; -import android.nfc.NfcAdapter; -import android.nfc.Tag; -import android.nfc.tech.IsoDep; -import android.os.Build; -import android.os.Bundle; -import android.view.WindowManager; -import android.widget.Toast; - -import org.spongycastle.bcpg.HashAlgorithmTags; -import org.spongycastle.util.encoders.Hex; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.base.BaseActivity; -import org.sufficientlysecure.keychain.util.Iso7816TLV; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.IOException; -import java.nio.ByteBuffer; - -/** - * This class provides a communication interface to OpenPGP applications on ISO SmartCard compliant - * NFC devices. - * - * For the full specs, see http://g10code.com/docs/openpgp-card-2.0.pdf - */ -@TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1) -public class NfcActivity extends BaseActivity { - - // actions - public static final String ACTION_SIGN_HASH = "sign_hash"; - public static final String ACTION_DECRYPT_SESSION_KEY = "decrypt_session_key"; - - // always - public static final String EXTRA_KEY_ID = "key_id"; - public static final String EXTRA_PIN = "pin"; - // special extra for OpenPgpService - public static final String EXTRA_DATA = "data"; - - // sign - public static final String EXTRA_NFC_HASH_TO_SIGN = "nfc_hash"; - public static final String EXTRA_NFC_HASH_ALGO = "nfc_hash_algo"; - - // decrypt - public static final String EXTRA_NFC_ENC_SESSION_KEY = "encrypted_session_key"; - - private Intent mServiceIntent; - - private static final int TIMEOUT = 100000; - - private NfcAdapter mNfcAdapter; - private IsoDep mIsoDep; - private String mAction; - - private String mPin; - private Long mKeyId; - - // sign - private byte[] mHashToSign; - private int mHashAlgo; - - // decrypt - private byte[] mEncryptedSessionKey; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Log.d(Constants.TAG, "NfcActivity.onCreate"); - - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - - Intent intent = getIntent(); - Bundle data = intent.getExtras(); - String action = intent.getAction(); - - // if we get are passed a key id, save it for the check - if (data.containsKey(EXTRA_KEY_ID)) { - mKeyId = data.getLong(EXTRA_KEY_ID); - } - - switch (action) { - case ACTION_SIGN_HASH: - mAction = action; - mPin = data.getString(EXTRA_PIN); - mHashToSign = data.getByteArray(EXTRA_NFC_HASH_TO_SIGN); - mHashAlgo = data.getInt(EXTRA_NFC_HASH_ALGO); - mServiceIntent = data.getParcelable(EXTRA_DATA); - - Log.d(Constants.TAG, "NfcActivity mAction: " + mAction); - Log.d(Constants.TAG, "NfcActivity mPin: " + mPin); - Log.d(Constants.TAG, "NfcActivity mHashToSign as hex: " + getHex(mHashToSign)); - Log.d(Constants.TAG, "NfcActivity mServiceIntent: " + mServiceIntent.toString()); - break; - case ACTION_DECRYPT_SESSION_KEY: - mAction = action; - mPin = data.getString(EXTRA_PIN); - mEncryptedSessionKey = data.getByteArray(EXTRA_NFC_ENC_SESSION_KEY); - mServiceIntent = data.getParcelable(EXTRA_DATA); - - Log.d(Constants.TAG, "NfcActivity mAction: " + mAction); - Log.d(Constants.TAG, "NfcActivity mPin: " + mPin); - Log.d(Constants.TAG, "NfcActivity mEncryptedSessionKey as hex: " + getHex(mEncryptedSessionKey)); - Log.d(Constants.TAG, "NfcActivity mServiceIntent: " + mServiceIntent.toString()); - break; - case NfcAdapter.ACTION_TAG_DISCOVERED: - Log.e(Constants.TAG, "This should not happen! NfcActivity.onCreate() is being called instead of onNewIntent()!"); - toast("This should not happen! Please create a new bug report that the NFC screen is restarted!"); - finish(); - break; - default: - Log.d(Constants.TAG, "Action not supported: " + action); - break; - } - } - - @Override - protected void initLayout() { - setContentView(R.layout.nfc_activity); - } - - /** - * Called when the system is about to start resuming a previous activity, - * disables NFC Foreground Dispatch - */ - public void onPause() { - super.onPause(); - Log.d(Constants.TAG, "NfcActivity.onPause"); - - disableNfcForegroundDispatch(); - } - - /** - * Called when the activity will start interacting with the user, - * enables NFC Foreground Dispatch - */ - public void onResume() { - super.onResume(); - Log.d(Constants.TAG, "NfcActivity.onResume"); - - enableNfcForegroundDispatch(); - } - - /** - * This activity is started as a singleTop activity. - * All new NFC Intents which are delivered to this activity are handled here - */ - public void onNewIntent(Intent intent) { - if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) { - try { - handleNdefDiscoveredIntent(intent); - } catch (IOException e) { - Log.e(Constants.TAG, "Connection error!", e); - toast("Connection Error: " + e.getMessage()); - setResult(RESULT_CANCELED, mServiceIntent); - finish(); - } - } - } - - /** Handle NFC communication and return a result. - * - * This method is called by onNewIntent above upon discovery of an NFC tag. - * It handles initialization and login to the application, subsequently - * calls either nfcCalculateSignature() or nfcDecryptSessionKey(), then - * finishes the activity with an appropiate result. - * - * On general communication, see also - * http://www.cardwerk.com/smartcards/smartcard_standard_ISO7816-4_annex-a.aspx - * - * References to pages are generally related to the OpenPGP Application - * on ISO SmartCard Systems specification. - * - */ - private void handleNdefDiscoveredIntent(Intent intent) throws IOException { - - Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); - - // Connect to the detected tag, setting a couple of settings - mIsoDep = IsoDep.get(detectedTag); - mIsoDep.setTimeout(TIMEOUT); // timeout is set to 100 seconds to avoid cancellation during calculation - mIsoDep.connect(); - - // SW1/2 0x9000 is the generic "ok" response, which we expect most of the time. - // See specification, page 51 - String accepted = "9000"; - - // Command APDU (page 51) for SELECT FILE command (page 29) - String opening = - "00" // CLA - + "A4" // INS - + "04" // P1 - + "00" // P2 - + "06" // Lc (number of bytes) - + "D27600012401" // Data (6 bytes) - + "00"; // Le - if ( ! card(opening).equals(accepted)) { // activate connection - toast("Opening Error!"); - setResult(RESULT_CANCELED, mServiceIntent); - finish(); - return; - } - - // Command APDU for VERIFY command (page 32) - String login = - "00" // CLA - + "20" // INS - + "00" // P1 - + "82" // P2 (PW1) - + String.format("%02x", mPin.length()) // Lc - + Hex.toHexString(mPin.getBytes()); - if ( ! card(login).equals(accepted)) { // login - toast("Wrong PIN!"); - setResult(RESULT_CANCELED, mServiceIntent); - finish(); - return; - } - - if (ACTION_SIGN_HASH.equals(mAction)) { - - // If we were supplied with a key id for checking, do so - if (mKeyId != null) { - // For signing, we check the master key - long keyId = nfcGetKeyId(mIsoDep, 0); - // If it's wrong, just cancel - if (keyId != mKeyId) { - toast("NFC Tag has wrong signing key id!"); - setResult(RESULT_CANCELED, mServiceIntent); - finish(); - return; - } - } - - // returns signed hash - byte[] signedHash = nfcCalculateSignature(mHashToSign, mHashAlgo); - - if (signedHash == null) { - setResult(RESULT_CANCELED, mServiceIntent); - finish(); - return; - } - - Log.d(Constants.TAG, "NfcActivity signedHash as hex: " + getHex(signedHash)); - - // give data through for new service call - // OpenPgpApi.EXTRA_NFC_SIGNED_HASH - mServiceIntent.putExtra("nfc_signed_hash", signedHash); - setResult(RESULT_OK, mServiceIntent); - finish(); - - } else if (ACTION_DECRYPT_SESSION_KEY.equals(mAction)) { - - // If we were supplied with a key id for checking, do so - if (mKeyId != null) { - // For decryption, we check the confidentiality key - long keyId = nfcGetKeyId(mIsoDep, 1); - // If it's wrong, just cancel - if (keyId != mKeyId) { - toast("NFC Tag has wrong encryption key id!"); - setResult(RESULT_CANCELED, mServiceIntent); - finish(); - return; - } - } - - byte[] decryptedSessionKey = nfcDecryptSessionKey(mEncryptedSessionKey); - - // give data through for new service call - // OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY - mServiceIntent.putExtra("nfc_decrypted_session_key", decryptedSessionKey); - setResult(RESULT_OK, mServiceIntent); - finish(); - } - - } - - /** - * Gets the user ID - * - * @return the user id as "name <email>" - * @throws java.io.IOException - */ - public String getUserId() throws IOException { - String info = "00CA006500"; - String data = "00CA005E00"; - return getName(card(info)) + " <" + (new String(Hex.decode(getDataField(card(data))))) + ">"; - } - - /** Return the key id from application specific data stored on tag, or null - * if it doesn't exist. - * - * @param idx Index of the key to return the fingerprint from. - * @return The long key id of the requested key, or null if not found. - */ - public static Long nfcGetKeyId(IsoDep isoDep, int idx) throws IOException { - byte[] fp = nfcGetFingerprint(isoDep, idx); - if (fp == null) { - return null; - } - ByteBuffer buf = ByteBuffer.wrap(fp); - // skip first 12 bytes of the fingerprint - buf.position(12); - // the last eight bytes are the key id (big endian, which is default order in ByteBuffer) - return buf.getLong(); - } - - /** Return fingerprints of all keys from application specific data stored - * on tag, or null if data not available. - * - * @return The fingerprints of all subkeys in a contiguous byte array. - */ - public static byte[] nfcGetFingerprints(IsoDep isoDep) throws IOException { - String data = "00CA006E00"; - byte[] buf = isoDep.transceive(Hex.decode(data)); - - Iso7816TLV tlv = Iso7816TLV.readSingle(buf, true); - Log.d(Constants.TAG, "nfc tlv data:\n" + tlv.prettyPrint()); - - Iso7816TLV fptlv = Iso7816TLV.findRecursive(tlv, 0xc5); - if (fptlv == null) { - return null; - } - - return fptlv.mV; - } - - /** Return the fingerprint from application specific data stored on tag, or - * null if it doesn't exist. - * - * @param idx Index of the key to return the fingerprint from. - * @return The fingerprint of the requested key, or null if not found. - */ - public static byte[] nfcGetFingerprint(IsoDep isoDep, int idx) throws IOException { - byte[] data = nfcGetFingerprints(isoDep); - - // return the master key fingerprint - ByteBuffer fpbuf = ByteBuffer.wrap(data); - byte[] fp = new byte[20]; - fpbuf.position(idx*20); - fpbuf.get(fp, 0, 20); - - return fp; - } - - /** - * Calls to calculate the signature and returns the MPI value - * - * @param hash the hash for signing - * @return a big integer representing the MPI for the given hash - * @throws java.io.IOException - */ - public byte[] nfcCalculateSignature(byte[] hash, int hashAlgo) throws IOException { - - // dsi, including Lc - String dsi; - - Log.i(Constants.TAG, "Hash: " + hashAlgo); - switch (hashAlgo) { - case HashAlgorithmTags.SHA1: - if (hash.length != 20) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 10!"); - } - dsi = "23" // Lc - + "3021" // Tag/Length of Sequence, the 0x21 includes all following 33 bytes - + "3009" // Tag/Length of Sequence, the 0x09 are the following header bytes - + "0605" + "2B0E03021A" // OID of SHA1 - + "0500" // TLV coding of ZERO - + "0414" + getHex(hash); // 0x14 are 20 hash bytes - break; - case HashAlgorithmTags.RIPEMD160: - if (hash.length != 20) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 20!"); - } - dsi = "233021300906052B2403020105000414" + getHex(hash); - break; - case HashAlgorithmTags.SHA224: - if (hash.length != 28) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 28!"); - } - dsi = "2F302D300D06096086480165030402040500041C" + getHex(hash); - break; - case HashAlgorithmTags.SHA256: - if (hash.length != 32) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 32!"); - } - dsi = "333031300D060960864801650304020105000420" + getHex(hash); - break; - case HashAlgorithmTags.SHA384: - if (hash.length != 48) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 48!"); - } - dsi = "433041300D060960864801650304020205000430" + getHex(hash); - break; - case HashAlgorithmTags.SHA512: - if (hash.length != 64) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 64!"); - } - dsi = "533051300D060960864801650304020305000440" + getHex(hash); - break; - default: - throw new RuntimeException("Not supported hash algo!"); - } - - // Command APDU for PERFORM SECURITY OPERATION: COMPUTE DIGITAL SIGNATURE (page 37) - String apdu = - "002A9E9A" // CLA, INS, P1, P2 - + dsi // digital signature input - + "00"; // Le - - String response = card(apdu); - - // split up response into signature and status - String status = response.substring(response.length()-4); - String signature = response.substring(0, response.length() - 4); - - // while we are getting 0x61 status codes, retrieve more data - while (status.substring(0, 2).equals("61")) { - Log.d(Constants.TAG, "requesting more data, status " + status); - // Send GET RESPONSE command - response = card("00C00000" + status.substring(2)); - status = response.substring(response.length()-4); - signature += response.substring(0, response.length()-4); - } - - Log.d(Constants.TAG, "final response:" + status); - - if ( ! status.equals("9000")) { - toast("Bad NFC response code: " + status); - return null; - } - - // Make sure the signature we received is actually the expected number of bytes long! - if (signature.length() != 256 && signature.length() != 512) { - toast("Bad signature length! Expected 128 or 256 bytes, got " + signature.length() / 2); - return null; - } - - return Hex.decode(signature); - } - - /** - * Calls to calculate the signature and returns the MPI value - * - * @param encryptedSessionKey the encoded session key - * @return the decoded session key - * @throws java.io.IOException - */ - public byte[] nfcDecryptSessionKey(byte[] encryptedSessionKey) throws IOException { - String firstApdu = "102a8086fe"; - String secondApdu = "002a808603"; - String le = "00"; - - byte[] one = new byte[254]; - // leave out first byte: - System.arraycopy(encryptedSessionKey, 1, one, 0, one.length); - - byte[] two = new byte[encryptedSessionKey.length - 1 - one.length]; - for (int i = 0; i < two.length; i++) { - two[i] = encryptedSessionKey[i + one.length + 1]; - } - - String first = card(firstApdu + getHex(one)); - String second = card(secondApdu + getHex(two) + le); - - String decryptedSessionKey = getDataField(second); - - Log.d(Constants.TAG, "decryptedSessionKey: " + decryptedSessionKey); - - return Hex.decode(decryptedSessionKey); - } - - /** - * Prints a message to the screen - * - * @param text the text which should be contained within the toast - */ - private void toast(String text) { - Toast.makeText(this, text, Toast.LENGTH_LONG).show(); - } - - /** - * Receive new NFC Intents to this activity only by enabling foreground dispatch. - * This can only be done in onResume! - */ - public void enableNfcForegroundDispatch() { - mNfcAdapter = NfcAdapter.getDefaultAdapter(this); - Intent nfcI = new Intent(this, NfcActivity.class) - .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); - PendingIntent nfcPendingIntent = PendingIntent.getActivity(this, 0, nfcI, PendingIntent.FLAG_CANCEL_CURRENT); - IntentFilter[] writeTagFilters = new IntentFilter[]{ - new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED) - }; - - // https://code.google.com/p/android/issues/detail?id=62918 - // maybe mNfcAdapter.enableReaderMode(); ? - try { - mNfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, writeTagFilters, null); - } catch (IllegalStateException e) { - Log.i(Constants.TAG, "NfcForegroundDispatch Error!", e); - } - Log.d(Constants.TAG, "NfcForegroundDispatch has been enabled!"); - } - - /** - * Disable foreground dispatch in onPause! - */ - public void disableNfcForegroundDispatch() { - mNfcAdapter.disableForegroundDispatch(this); - Log.d(Constants.TAG, "NfcForegroundDispatch has been disabled!"); - } - - /** - * Gets the name of the user out of the raw card output regarding card holder related data - * - * @param name the raw card holder related data from the card - * @return the name given in this data - */ - public String getName(String name) { - String slength; - int ilength; - name = name.substring(6); - slength = name.substring(0, 2); - ilength = Integer.parseInt(slength, 16) * 2; - name = name.substring(2, ilength + 2); - name = (new String(Hex.decode(name))).replace('<', ' '); - return (name); - } - - /** - * Reduces the raw data from the card by four characters - * - * @param output the raw data from the card - * @return the data field of that data - */ - private String getDataField(String output) { - return output.substring(0, output.length() - 4); - } - - /** - * Communicates with the OpenPgpCard via the APDU - * - * @param hex the hexadecimal APDU - * @return The answer from the card - * @throws java.io.IOException throws an exception if something goes wrong - */ - public String card(String hex) throws IOException { - return getHex(mIsoDep.transceive(Hex.decode(hex))); - } - - /** - * Converts a byte array into an hex string - * - * @param raw the byte array representation - * @return the hexadecimal string representation - */ - public static String getHex(byte[] raw) { - return new String(Hex.encode(raw)); - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java index 511183b04..d70b0aad1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java @@ -10,8 +10,10 @@ import android.annotation.TargetApi; import android.content.Intent; import android.os.Build; import android.os.Bundle; +import android.os.Parcelable; import android.view.WindowManager; +import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.service.PassphraseCacheService; @@ -34,9 +36,13 @@ public class NfcOperationActivity extends BaseNfcActivity { public static final String EXTRA_REQUIRED_INPUT = "required_input"; + // passthrough for OpenPgpService + public static final String EXTRA_SERVICE_INTENT = "data"; + public static final String RESULT_DATA = "result_data"; - RequiredInputParcel mRequiredInput; + private RequiredInputParcel mRequiredInput; + private Intent mServiceIntent; @Override protected void onCreate(Bundle savedInstanceState) { @@ -49,6 +55,7 @@ public class NfcOperationActivity extends BaseNfcActivity { Bundle data = intent.getExtras(); mRequiredInput = data.getParcelable(EXTRA_REQUIRED_INPUT); + mServiceIntent = data.getParcelable(EXTRA_SERVICE_INTENT); // obtain passphrase for this subkey obtainYubikeyPin(RequiredInputParcel.createRequiredPassphrase(mRequiredInput)); @@ -84,10 +91,15 @@ public class NfcOperationActivity extends BaseNfcActivity { break; } - // give data through for new service call - Intent result = new Intent(); - result.putExtra(NfcOperationActivity.RESULT_DATA, resultData); - setResult(RESULT_OK, result); + if (mServiceIntent != null) { + mServiceIntent.putExtra(OpenPgpApi.EXTRA_CRYPTO_INPUT, resultData); + setResult(RESULT_OK, mServiceIntent); + } else { + Intent result = new Intent(); + result.putExtra(NfcOperationActivity.RESULT_DATA, resultData); + setResult(RESULT_OK, result); + } + finish(); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index 9e04426eb..c1771ce57 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -41,7 +41,7 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; -import junit.framework.Assert; +import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; @@ -67,14 +67,13 @@ import org.sufficientlysecure.keychain.util.Preferences; * This activity encapsulates a DialogFragment to emulate a dialog. */ public class PassphraseDialogActivity extends FragmentActivity { - public static final String MESSAGE_DATA_PASSPHRASE = "passphrase"; - public static final String RESULT_DATA = "result_data"; + public static final String RESULT_CRYPTO_INPUT = "result_data"; public static final String EXTRA_REQUIRED_INPUT = "required_input"; public static final String EXTRA_SUBKEY_ID = "secret_key_id"; // special extra for OpenPgpService - public static final String EXTRA_DATA = "data"; + public static final String EXTRA_SERVICE_INTENT = "data"; private static final int REQUEST_CODE_ENTER_PATTERN = 2; @@ -104,7 +103,7 @@ public class PassphraseDialogActivity extends FragmentActivity { keyId = requiredInput.getSubKeyId(); } - Intent serviceIntent = getIntent().getParcelableExtra(EXTRA_DATA); + Intent serviceIntent = getIntent().getParcelableExtra(EXTRA_SERVICE_INTENT); show(this, keyId, serviceIntent); } @@ -155,7 +154,7 @@ public class PassphraseDialogActivity extends FragmentActivity { PassphraseDialogFragment frag = new PassphraseDialogFragment(); Bundle args = new Bundle(); args.putLong(EXTRA_SUBKEY_ID, keyId); - args.putParcelable(EXTRA_DATA, serviceIntent); + args.putParcelable(EXTRA_SERVICE_INTENT, serviceIntent); frag.setArguments(args); @@ -188,7 +187,7 @@ public class PassphraseDialogActivity extends FragmentActivity { R.style.Theme_AppCompat_Light_Dialog); mSubKeyId = getArguments().getLong(EXTRA_SUBKEY_ID); - mServiceIntent = getArguments().getParcelable(EXTRA_DATA); + mServiceIntent = getArguments().getParcelable(EXTRA_SERVICE_INTENT); CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme); @@ -418,15 +417,13 @@ public class PassphraseDialogActivity extends FragmentActivity { } if (mServiceIntent != null) { - // TODO: Not routing passphrase through OpenPGP API currently - // due to security concerns... - // BUT this means you need to _cache_ passphrases! + // TODO really pass this through the PendingIntent? + mServiceIntent.putExtra(OpenPgpApi.EXTRA_CRYPTO_INPUT, new CryptoInputParcel(null, passphrase)); getActivity().setResult(RESULT_OK, mServiceIntent); } else { // also return passphrase back to activity Intent returnIntent = new Intent(); - returnIntent.putExtra(MESSAGE_DATA_PASSPHRASE, passphrase); - returnIntent.putExtra(RESULT_DATA, new CryptoInputParcel(null, passphrase)); + returnIntent.putExtra(RESULT_CRYPTO_INPUT, new CryptoInputParcel(null, passphrase)); getActivity().setResult(RESULT_OK, returnIntent); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index a8a5a1f28..0b22ecdaf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -130,7 +130,7 @@ public abstract class BaseNfcActivity extends BaseActivity { protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_CODE_PASSPHRASE: - CryptoInputParcel input = data.getParcelableExtra(PassphraseDialogActivity.RESULT_DATA); + CryptoInputParcel input = data.getParcelableExtra(PassphraseDialogActivity.RESULT_CRYPTO_INPUT); mPin = input.getPassphrase(); break; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyUpdateHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyUpdateHelper.java index 943b913d7..3bbd86d6a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyUpdateHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyUpdateHelper.java @@ -57,7 +57,7 @@ public class KeyUpdateHelper { Bundle importData = new Bundle(); importData.putParcelableArrayList(KeychainIntentService.DOWNLOAD_KEY_LIST, new ArrayList<ImportKeysListEntry>(keys)); - importIntent.putExtra(KeychainIntentService.EXTRA_DATA, importData); + importIntent.putExtra(KeychainIntentService.EXTRA_SERVICE_INTENT, importData); importIntent.putExtra(KeychainIntentService.EXTRA_MESSENGER, new Messenger(mHandler)); diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 78940aa9e..6d29ce3fd 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -1048,7 +1048,6 @@ <string name="msg_se_error_input_uri_not_found">"Error opening URI for reading!"</string> <string name="msg_se_error_output_uri_not_found">"Error opening URI for writing!"</string> <string name="msg_se_error_too_many_inputs">"More inputs than outputs specified! This is probably a programming error, please report!"</string> - <string name="msg_se_warn_output_left">"Got outputs left but no inputs. This is probably a programming error, please report!"</string> <string name="msg_se_success">"Sign/encrypt operation successful"</string> <!-- Messages for PgpSignEncrypt operation --> |