From f2a6064e38d46bad34282bcbc961e16c1bf8f533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 17 Jul 2014 20:29:07 +0200 Subject: Fixes --- .../keychain/pgp/PgpSignEncrypt.java | 93 +++++++++++++++++----- .../keychain/pgp/UncachedKeyRing.java | 2 + .../keychain/pgp/WrappedSecretKey.java | 5 ++ .../keychain/remote/OpenPgpService.java | 40 ++++++++-- .../keychain/remote/ui/AppSettingsActivity.java | 8 ++ .../keychain/service/PassphraseCacheService.java | 8 ++ 6 files changed, 132 insertions(+), 24 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java index 4cb92c368..0750c2a3a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.BCPGOutputStream; +import org.spongycastle.bcpg.S2K; import org.spongycastle.openpgp.PGPCompressedDataGenerator; import org.spongycastle.openpgp.PGPEncryptedDataGenerator; import org.spongycastle.openpgp.PGPException; @@ -38,11 +39,13 @@ import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SignatureException; @@ -70,6 +73,7 @@ public class PgpSignEncrypt { private String mSignaturePassphrase; private boolean mEncryptToSigner; private boolean mCleartextInput; + private String mNfcData; private static byte[] NEW_LINE; @@ -100,6 +104,7 @@ public class PgpSignEncrypt { this.mSignaturePassphrase = builder.mSignaturePassphrase; this.mEncryptToSigner = builder.mEncryptToSigner; this.mCleartextInput = builder.mCleartextInput; + this.mNfcData = builder.mNfcData; } public static class Builder { @@ -122,6 +127,7 @@ public class PgpSignEncrypt { private String mSignaturePassphrase = null; private boolean mEncryptToSigner = false; private boolean mCleartextInput = false; + private String mNfcData = null; public Builder(ProviderHelper providerHelper, String versionHeader, InputData data, OutputStream outStream) { this.mProviderHelper = providerHelper; @@ -130,7 +136,7 @@ public class PgpSignEncrypt { this.mOutStream = outStream; } - public Builder setProgressable(Progressable progressable) { + public Builder setProgressable(Progressable progressable) { mProgressable = progressable; return this; } @@ -170,6 +176,12 @@ public class PgpSignEncrypt { return this; } + /** + * Generate old V3 signatures + * + * @param signatureForceV3 + * @return + */ public Builder setSignatureForceV3(boolean signatureForceV3) { mSignatureForceV3 = signatureForceV3; return this; @@ -200,6 +212,11 @@ public class PgpSignEncrypt { return this; } + public Builder setNfcData(String nfcData) { + mNfcData = nfcData; + return this; + } + public PgpSignEncrypt build() { return new PgpSignEncrypt(this); } @@ -232,12 +249,26 @@ public class PgpSignEncrypt { } } + public static class NeedNfcDataException extends Exception { + public String mData; + + public NeedNfcDataException(String data) { + mData = data; + } + } + + // TODO: remove later + static String convertStreamToString(java.io.InputStream is) { + java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A"); + return s.hasNext() ? s.next() : ""; + } + /** * Signs and/or encrypts data based on parameters of class */ public void execute() throws IOException, PGPException, NoSuchProviderException, - NoSuchAlgorithmException, SignatureException, KeyExtractionException, NoSigningKeyException, NoPassphraseException { + NoSuchAlgorithmException, SignatureException, KeyExtractionException, NoSigningKeyException, NoPassphraseException, NeedNfcDataException { boolean enableSignature = mSignatureMasterKeyId != Constants.key.none; boolean enableEncryption = ((mEncryptionMasterKeyIds != null && mEncryptionMasterKeyIds.length > 0) @@ -255,16 +286,6 @@ public class PgpSignEncrypt { mEncryptionMasterKeyIds[mEncryptionMasterKeyIds.length - 1] = mSignatureMasterKeyId; } - ArmoredOutputStream armorOut = null; - OutputStream out; - if (mEnableAsciiArmorOutput) { - armorOut = new ArmoredOutputStream(mOutStream); - armorOut.setHeader("Version", mVersionHeader); - out = armorOut; - } else { - out = mOutStream; - } - /* Get keys for signature generation for later usage */ WrappedSecretKey signingKey = null; if (enableSignature) { @@ -276,7 +297,7 @@ public class PgpSignEncrypt { } try { signingKey = signingKeyRing.getSigningSubKey(); - } catch(PgpGeneralException e) { + } catch (PgpGeneralException e) { throw new NoSigningKeyException(); } @@ -329,17 +350,24 @@ public class PgpSignEncrypt { } } + // HACK + boolean useNfc = false; + if (signingKey.getSecretKey().getS2K().getType() == S2K.GNU_DUMMY_S2K + && signingKey.getSecretKey().getS2K().getProtectionMode() == 2) { + useNfc = true; + } + /* Initialize signature generator object for later usage */ PGPSignatureGenerator signatureGenerator = null; PGPV3SignatureGenerator signatureV3Generator = null; - if (enableSignature) { + if (enableSignature && !useNfc) { updateProgress(R.string.progress_preparing_signature, 10, 100); try { boolean cleartext = mCleartextInput && mEnableAsciiArmorOutput && !enableEncryption; if (mSignatureForceV3) { signatureV3Generator = signingKey.getV3SignatureGenerator( - mSignatureHashAlgorithm,cleartext); + mSignatureHashAlgorithm, cleartext); } else { signatureGenerator = signingKey.getSignatureGenerator( mSignatureHashAlgorithm, cleartext); @@ -349,12 +377,39 @@ public class PgpSignEncrypt { throw new KeyExtractionException(); } } +// else if (enableSignature && useNfc) { +// +// } + + + ArmoredOutputStream armorOut = null; + OutputStream out = null; + if (mEnableAsciiArmorOutput && !useNfc) { + armorOut = new ArmoredOutputStream(mOutStream); + armorOut.setHeader("Version", mVersionHeader); + out = armorOut; + } else { + out = mOutStream; + } PGPCompressedDataGenerator compressGen = null; - OutputStream pOut; + OutputStream pOut = null; OutputStream encryptionOut = null; BCPGOutputStream bcpgOut; - if (enableEncryption) { + + // Barrier function! + if (useNfc && mNfcData == null) { + Log.d(Constants.TAG, "mNfcData is null"); + String nfcData = convertStreamToString(mData.getInputStream()); + Log.d(Constants.TAG, "nfcData: " + nfcData); + throw new NeedNfcDataException(nfcData); + } + + if (useNfc) { + Log.d(Constants.TAG, "mNfcData: " + mNfcData); + out.write(mNfcData.getBytes()); + out.flush(); + } else if (enableEncryption) { /* actual encryption */ encryptionOut = cPk.open(out, new byte[1 << 16]); @@ -488,7 +543,7 @@ public class PgpSignEncrypt { Log.e(Constants.TAG, "not supported!"); } - if (enableSignature) { + if (enableSignature && !useNfc) { updateProgress(R.string.progress_generating_signature, 95, 100); if (mSignatureForceV3) { signatureV3Generator.generate().encode(pOut); @@ -507,7 +562,7 @@ public class PgpSignEncrypt { encryptionOut.close(); } - if (mEnableAsciiArmorOutput) { + if (mEnableAsciiArmorOutput && !useNfc) { armorOut.close(); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index 9ddfd3405..1a8607e3f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -179,6 +179,8 @@ public class UncachedKeyRing { // Set to 1, except if the encryption type is GNU_DUMMY_S2K if(s2k == null || s2k.getType() != S2K.GNU_DUMMY_S2K) { result.add(sub.getKeyID()); + } else { + Log.d(Constants.TAG, "S2K GNU extension!, mode: " + s2k.getProtectionMode()); } } return result; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java index 98ad2b706..b928fd8cc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java @@ -197,4 +197,9 @@ public class WrappedSecretKey extends WrappedPublicKey { return new UncachedSecretKey(mSecretKey); } + // HACK + public PGPSecretKey getSecretKey() { + return mSecretKey; + } + } 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 62d6b5ad6..f7ee0eab3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -28,6 +28,7 @@ import org.openintents.openpgp.IOpenPgpService; import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.util.OpenPgpApi; +import org.openkeychain.nfc.NfcActivity; import org.spongycastle.util.Arrays; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; @@ -135,7 +136,26 @@ public class OpenPgpService extends RemoteService { return result; } - private Intent getPassphraseBundleIntent(Intent data, long keyId) { + private Intent getNfcIntent(Intent data, String in) { + // build PendingIntent for Yubikey NFC operations + Intent intent = new Intent(getBaseContext(), NfcActivity.class); + intent.setAction(NfcActivity.ACTION_SIGN); + intent.putExtra(NfcActivity.EXTRA_NFC_DATA, in); + intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); + // pass params through to activity that it can be returned again later to repeat pgp operation + intent.putExtra(NfcActivity.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 Intent getPassphraseIntent(Intent data, long keyId) { // build PendingIntent for passphrase input Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); intent.setAction(RemoteServiceActivity.ACTION_CACHE_PASSPHRASE); @@ -167,10 +187,12 @@ public class OpenPgpService extends RemoteService { } if (passphrase == null) { // get PendingIntent for passphrase input, add it to given params and return to client - Intent passphraseBundle = getPassphraseBundleIntent(data, accSettings.getKeyId()); + Intent passphraseBundle = getPassphraseIntent(data, accSettings.getKeyId()); return passphraseBundle; } + String nfcData = data.getStringExtra(OpenPgpApi.EXTRA_NFC_DATA); + // Get Input- and OutputStream from ParcelFileDescriptor InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); @@ -187,7 +209,8 @@ public class OpenPgpService extends RemoteService { .setSignatureHashAlgorithm(accSettings.getHashAlgorithm()) .setSignatureForceV3(false) .setSignatureMasterKeyId(accSettings.getKeyId()) - .setSignaturePassphrase(passphrase); + .setSignaturePassphrase(passphrase) + .setNfcData(nfcData); // TODO: currently always assume cleartext input, no sign-only of binary currently! builder.setCleartextInput(true); @@ -202,6 +225,10 @@ public class OpenPgpService extends RemoteService { throw new Exception(getString(R.string.error_no_signature_passphrase)); } catch (PgpSignEncrypt.NoSigningKeyException e) { throw new Exception(getString(R.string.error_no_signature_key)); + } catch (PgpSignEncrypt.NeedNfcDataException e) { + // return PendingIntent to execute NFC activity + Intent nfcIntent = getNfcIntent(data, e.mData); + return nfcIntent; } } finally { is.close(); @@ -212,6 +239,7 @@ public class OpenPgpService extends RemoteService { result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); return result; } catch (Exception e) { + Log.d(Constants.TAG, "signImpl", e); Intent result = new Intent(); result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); @@ -282,7 +310,7 @@ public class OpenPgpService extends RemoteService { } if (passphrase == null) { // get PendingIntent for passphrase input, add it to given params and return to client - Intent passphraseBundle = getPassphraseBundleIntent(data, accSettings.getKeyId()); + Intent passphraseBundle = getPassphraseIntent(data, accSettings.getKeyId()); return passphraseBundle; } @@ -317,6 +345,7 @@ public class OpenPgpService extends RemoteService { result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); return result; } catch (Exception e) { + Log.d(Constants.TAG, "encryptAndSignImpl", e); Intent result = new Intent(); result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); @@ -376,7 +405,7 @@ public class OpenPgpService extends RemoteService { if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) { // get PendingIntent for passphrase input, add it to given params and return to client Intent passphraseBundle = - getPassphraseBundleIntent(data, decryptVerifyResult.getKeyIdPassphraseNeeded()); + getPassphraseIntent(data, decryptVerifyResult.getKeyIdPassphraseNeeded()); return passphraseBundle; } else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) { @@ -411,6 +440,7 @@ public class OpenPgpService extends RemoteService { result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); return result; } catch (Exception e) { + Log.d(Constants.TAG, "decryptAndVerifyImpl", e); Intent result = new Intent(); result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java index 8df341f9e..b37405304 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java @@ -17,9 +17,12 @@ package org.sufficientlysecure.keychain.remote.ui; +import android.content.ComponentName; import android.content.Intent; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Bundle; import android.support.v7.app.ActionBar; @@ -34,6 +37,8 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.remote.AppSettings; import org.sufficientlysecure.keychain.util.Log; +import java.util.List; + public class AppSettingsActivity extends ActionBarActivity { private Uri mAppUri; @@ -90,6 +95,7 @@ public class AppSettingsActivity extends ActionBarActivity { return super.onOptionsItemSelected(item); } + // disabled: breaks Yubikey NFC Foreground dispatching private void startApp() { Intent i; PackageManager manager = getPackageManager(); @@ -97,6 +103,8 @@ public class AppSettingsActivity extends ActionBarActivity { i = manager.getLaunchIntentForPackage(mAppSettings.getPackageName()); if (i == null) throw new PackageManager.NameNotFoundException(); + // start like the Android launcher would do + i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); i.addCategory(Intent.CATEGORY_LAUNCHER); startActivity(i); } catch (PackageManager.NameNotFoundException e) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java index 13d9b497f..774b9a0df 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -38,6 +38,7 @@ import android.os.RemoteException; import android.support.v4.util.LongSparseArray; import android.support.v4.app.NotificationCompat; +import org.spongycastle.bcpg.S2K; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.Preferences; @@ -198,6 +199,13 @@ public class PassphraseCacheService extends Service { return ""; } + // TODO: HACK + if (key.getSecretKey().getSecretKey().getS2K().getType() == S2K.GNU_DUMMY_S2K + && key.getSecretKey().getSecretKey().getS2K().getProtectionMode() == 2) { + // NFC! + return "123456"; + } + // get cached passphrase CachedPassphrase cachedPassphrase = mPassphraseCache.get(keyId); if (cachedPassphrase == null) { -- cgit v1.2.3