aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitmodules5
-rw-r--r--OpenKeychain/build.gradle2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java93
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java40
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java8
m---------extern/openpgp-card-nfc-lib0
-rw-r--r--settings.gradle1
10 files changed, 138 insertions, 26 deletions
diff --git a/.gitmodules b/.gitmodules
index 687126e37..93ca9d49b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -30,4 +30,7 @@
url = https://github.com/open-keychain/KeybaseLib.git
[submodule "extern/minidns"]
path = extern/minidns
- url = https://github.com/open-keychain/minidns.git \ No newline at end of file
+ url = https://github.com/open-keychain/minidns.git
+[submodule "extern/openpgp-card-nfc-lib"]
+ path = extern/openpgp-card-nfc-lib
+ url = https://github.com/open-keychain/openpgp-card-nfc-lib.git \ No newline at end of file
diff --git a/OpenKeychain/build.gradle b/OpenKeychain/build.gradle
index a6c01543c..c4c8156cd 100644
--- a/OpenKeychain/build.gradle
+++ b/OpenKeychain/build.gradle
@@ -20,7 +20,7 @@ dependencies {
compile project(':extern:SuperToasts:supertoasts')
compile project(':extern:minidns')
compile project(':extern:KeybaseLib:Lib')
-
+ compile project(':extern:openpgp-card-nfc-lib:library')
}
android {
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) {
diff --git a/extern/openpgp-card-nfc-lib b/extern/openpgp-card-nfc-lib
new file mode 160000
+Subproject d05ad01970f4f08cc747bc1c44a99255d2796c7
diff --git a/settings.gradle b/settings.gradle
index 86088e04a..d0b2b9954 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -14,3 +14,4 @@ include ':extern:AppMsg:library'
include ':extern:SuperToasts:supertoasts'
include ':extern:minidns'
include ':extern:KeybaseLib:Lib'
+include ':extern:openpgp-card-nfc-lib:library' \ No newline at end of file