diff options
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui')
11 files changed, 53 insertions, 862 deletions
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; |