aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2014-09-08 00:01:29 +0200
committerDominik Schürmann <dominik@dominikschuermann.de>2014-09-08 00:01:29 +0200
commit83af19de20cbfa8fe99216f4dcb8af8819570147 (patch)
tree7f4b29d6aecc8b9627058a1d24e2125f18afa824 /OpenKeychain/src/main/java/org/sufficientlysecure
parentfd7f1873641031b9dece88db0cf0dd18a94830a5 (diff)
downloadopen-keychain-83af19de20cbfa8fe99216f4dcb8af8819570147.tar.gz
open-keychain-83af19de20cbfa8fe99216f4dcb8af8819570147.tar.bz2
open-keychain-83af19de20cbfa8fe99216f4dcb8af8819570147.zip
Prepare Yubikey decryption
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java57
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java20
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java34
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java3
4 files changed, 83 insertions, 31 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
index 833e1ad3d..f0ce2ea78 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
@@ -36,6 +36,7 @@ import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
+import org.spongycastle.openpgp.operator.jcajce.NfcPublicKeyDataDecryptorFactoryBuilder;
import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
@@ -189,14 +190,8 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
return supported;
}
- public PGPSignatureGenerator getSignatureGenerator(int hashAlgo, boolean cleartext,
- byte[] nfcSignedHash, Date nfcCreationTimestamp)
- throws PgpGeneralException {
- if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {
- throw new PrivateKeyNotUnlockedException();
- }
-
- PGPContentSignerBuilder contentSignerBuilder;
+ private PGPContentSignerBuilder getContentSignerBuilder(int hashAlgo, byte[] nfcSignedHash,
+ Date nfcCreationTimestamp) {
if (mPrivateKeyState == PRIVATE_KEY_STATE_DIVERT_TO_CARD) {
// to sign using nfc PgpSignEncrypt is executed two times.
// the first time it stops to return the PendingIntent for nfc connection and signing the hash
@@ -207,18 +202,27 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
}
// use synchronous "NFC based" SignerBuilder
- contentSignerBuilder = new NfcSyncPGPContentSignerBuilder(
+ return new NfcSyncPGPContentSignerBuilder(
mSecretKey.getPublicKey().getAlgorithm(), hashAlgo,
mSecretKey.getKeyID(), nfcSignedHash, nfcCreationTimestamp)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
-
- Log.d(Constants.TAG, "mSecretKey.getKeyID() " + PgpKeyHelper.convertKeyIdToHex(mSecretKey.getKeyID()));
} else {
// content signer based on signing key algorithm and chosen hash algorithm
- contentSignerBuilder = new JcaPGPContentSignerBuilder(
+ return new JcaPGPContentSignerBuilder(
mSecretKey.getPublicKey().getAlgorithm(), hashAlgo)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
}
+ }
+
+ public PGPSignatureGenerator getSignatureGenerator(int hashAlgo, boolean cleartext,
+ byte[] nfcSignedHash, Date nfcCreationTimestamp)
+ throws PgpGeneralException {
+ if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {
+ throw new PrivateKeyNotUnlockedException();
+ }
+
+ PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(hashAlgo,
+ nfcSignedHash, nfcCreationTimestamp);
int signatureType;
if (cleartext) {
@@ -247,12 +251,17 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
}
public PublicKeyDataDecryptorFactory getDecryptorFactory() {
- // TODO: divert to card missing
- if (mPrivateKeyState != PRIVATE_KEY_STATE_UNLOCKED) {
+ if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {
throw new PrivateKeyNotUnlockedException();
}
- return new JcePublicKeyDataDecryptorFactoryBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mPrivateKey);
+
+ if (mPrivateKeyState == PRIVATE_KEY_STATE_DIVERT_TO_CARD) {
+ return new NfcPublicKeyDataDecryptorFactoryBuilder()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mPrivateKey);
+ } else {
+ return new JcePublicKeyDataDecryptorFactoryBuilder()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mPrivateKey);
+ }
}
/**
@@ -262,12 +271,11 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
* @param userIds User IDs to certify, must not be null or empty
* @return A keyring with added certifications
*/
- public UncachedKeyRing certifyUserIds(CanonicalizedPublicKeyRing publicKeyRing, List<String> userIds)
+ public UncachedKeyRing certifyUserIds(CanonicalizedPublicKeyRing publicKeyRing, List<String> userIds,
+ byte[] nfcSignedHash, Date nfcCreationTimestamp)
throws PgpGeneralMsgIdException, NoSuchAlgorithmException, NoSuchProviderException,
PGPException, SignatureException {
-
- // TODO: divert to card missing
- if (mPrivateKeyState != PRIVATE_KEY_STATE_UNLOCKED) {
+ if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {
throw new PrivateKeyNotUnlockedException();
}
@@ -275,9 +283,8 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
PGPSignatureGenerator signatureGenerator;
{
// TODO: SHA256 fixed?
- JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
- mSecretKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(PGPUtil.SHA256,
+ nfcSignedHash, nfcCreationTimestamp);
signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, mPrivateKey);
@@ -285,6 +292,10 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
{ // supply signatureGenerator with a SubpacketVector
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+ if (nfcCreationTimestamp != null) {
+ spGen.setSignatureCreationTime(false, nfcCreationTimestamp);
+ Log.d(Constants.TAG, "For NFC: set sig creation time to " + nfcCreationTimestamp);
+ }
PGPSignatureSubpacketVector packetVector = spGen.generate();
signatureGenerator.setHashedSubpackets(packetVector);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
index cb077c55c..6abef1ad2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -42,6 +42,7 @@ import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
+import org.spongycastle.openpgp.operator.jcajce.NfcPublicKeyDataDecryptorFactoryBuilder;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
@@ -59,6 +60,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLConnection;
import java.security.SignatureException;
+import java.util.Date;
import java.util.Iterator;
import java.util.Set;
@@ -193,13 +195,21 @@ public class PgpDecryptVerify {
}
}
+ public static class NeedNfcDataException extends Exception {
+ public byte[] mDec;
+
+ public NeedNfcDataException(byte[] dec) {
+ mDec = dec;
+ }
+ }
+
/**
* Decrypts and/or verifies data based on parameters of class
*/
public PgpDecryptVerifyResult execute()
throws IOException, PGPException, SignatureException,
WrongPassphraseException, NoSecretKeyException, KeyExtractionException,
- InvalidDataException, IntegrityCheckFailedException {
+ InvalidDataException, IntegrityCheckFailedException, NeedNfcDataException {
// automatically works with ascii armor input and binary
InputStream in = PGPUtil.getDecoderStream(mData.getInputStream());
if (in instanceof ArmoredInputStream) {
@@ -223,7 +233,7 @@ public class PgpDecryptVerify {
private PgpDecryptVerifyResult decryptVerify(InputStream in)
throws IOException, PGPException, SignatureException,
WrongPassphraseException, KeyExtractionException, NoSecretKeyException,
- InvalidDataException, IntegrityCheckFailedException {
+ InvalidDataException, IntegrityCheckFailedException, NeedNfcDataException {
PgpDecryptVerifyResult result = new PgpDecryptVerifyResult();
PGPObjectFactory pgpF = new PGPObjectFactory(in, new JcaKeyFingerprintCalculator());
@@ -370,7 +380,11 @@ public class PgpDecryptVerify {
updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
PublicKeyDataDecryptorFactory decryptorFactory = secretEncryptionKey.getDecryptorFactory();
- clear = encryptedDataAsymmetric.getDataStream(decryptorFactory);
+ try {
+ clear = encryptedDataAsymmetric.getDataStream(decryptorFactory);
+ } catch (NfcPublicKeyDataDecryptorFactoryBuilder.NfcInteractionNeeded e) {
+ throw new NeedNfcDataException(e.dec);
+ }
encryptedData = encryptedDataAsymmetric;
} else {
// no packet has been found where we have the corresponding secret key in our db
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 00a9dc8f1..3b4559cf2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -155,15 +155,38 @@ public class OpenPgpService extends RemoteService {
}
}
- private Intent getNfcIntent(Intent data, byte[] hashToSign, int hashAlgo) {
+ private Intent getNfcSignIntent(Intent data, String 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_NFC_HASH_TO_SIGN, hashToSign);
intent.putExtra(NfcActivity.EXTRA_NFC_HASH_ALGO, hashAlgo);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ 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 getNfcDecryptIntent(Intent data, String pin, byte[] dec) {
+ // 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_NFC_DEC, dec);
+ intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
intent,
PendingIntent.FLAG_CANCEL_CURRENT);
@@ -257,7 +280,7 @@ public class OpenPgpService extends RemoteService {
// pass through the signature creation timestamp to be used again on second execution
// of PgpSignEncrypt when we have the signed hash!
data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, e.mCreationTimestamp.getTime());
- return getNfcIntent(data, e.mHashToSign, e.mHashAlgo);
+ return getNfcSignIntent(data, passphrase, e.mHashToSign, e.mHashAlgo);
}
} finally {
is.close();
@@ -322,8 +345,8 @@ public class OpenPgpService extends RemoteService {
.setOriginalFilename(originalFilename)
.setAdditionalEncryptId(accSettings.getKeyId()); // add acc key for encryption
+ String passphrase = null;
if (sign) {
- String passphrase;
if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
} else {
@@ -359,7 +382,7 @@ public class OpenPgpService extends RemoteService {
// pass through the signature creation timestamp to be used again on second execution
// of PgpSignEncrypt when we have the signed hash!
data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, e.mCreationTimestamp.getTime());
- return getNfcIntent(data, e.mHashToSign, e.mHashAlgo);
+ return getNfcSignIntent(data, passphrase, e.mHashToSign, e.mHashAlgo);
}
} finally {
is.close();
@@ -439,6 +462,9 @@ public class OpenPgpService extends RemoteService {
throw new Exception(getString(R.string.error_no_secret_key_found));
} catch (PgpDecryptVerify.IntegrityCheckFailedException e) {
throw new Exception(getString(R.string.error_integrity_check_failed));
+ } catch (PgpDecryptVerify.NeedNfcDataException e) {
+ // return PendingIntent to execute NFC activity
+ return getNfcDecryptIntent(data, passphrase, e.mDec);
}
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
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 a5b672e7e..b9746aee5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -697,7 +697,8 @@ public class KeychainIntentService extends IntentService implements Progressable
if (!certificationKey.unlock(signaturePassphrase)) {
throw new PgpGeneralException("Error extracting key (bad passphrase?)");
}
- UncachedKeyRing newRing = certificationKey.certifyUserIds(publicRing, userIds);
+ // TODO: supply nfc stuff
+ UncachedKeyRing newRing = certificationKey.certifyUserIds(publicRing, userIds, null, null);
// store the signed key in our local cache
providerHelper.savePublicKeyRing(newRing);