aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2015-04-24 14:18:01 +0200
committerVincent Breitmoser <valodim@mugenguild.com>2015-04-24 14:18:01 +0200
commitb4aec3114d9911cf9aef0d14ee697e5131b2853f (patch)
tree7237de5955ec34d8849737b2f9229bfbb37d0c45 /OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp
parentc2163460971cc01e65d7dfd18eec491f01ebc744 (diff)
parentbaac30508d24dcda6135bf8ae338c99d8c3b8ad8 (diff)
downloadopen-keychain-b4aec3114d9911cf9aef0d14ee697e5131b2853f.tar.gz
open-keychain-b4aec3114d9911cf9aef0d14ee697e5131b2853f.tar.bz2
open-keychain-b4aec3114d9911cf9aef0d14ee697e5131b2853f.zip
Merge branch 'development' into linked-identities
Conflicts: Graphics/update-drawables.sh OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java OpenKeychain/build.gradle OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java182
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpCertifyOperation.java149
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java80
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java327
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInput.java)129
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java121
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java56
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java2
9 files changed, 600 insertions, 455 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java
index c2506685d..8432b8f9f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java
@@ -98,11 +98,14 @@ public class CanonicalizedPublicKeyRing extends CanonicalizedKeyRing {
/** Create a dummy secret ring from this key */
public UncachedKeyRing createDummySecretRing () {
-
- PGPSecretKeyRing secRing = PGPSecretKeyRing.constructDummyFromPublic(getRing(),
- S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY);
+ PGPSecretKeyRing secRing = PGPSecretKeyRing.constructDummyFromPublic(getRing(), null);
return new UncachedKeyRing(secRing);
+ }
+ /** Create a dummy secret ring from this key */
+ public UncachedKeyRing createDivertSecretRing (byte[] cardAid) {
+ PGPSecretKeyRing secRing = PGPSecretKeyRing.constructDummyFromPublic(getRing(), cardAid);
+ return new UncachedKeyRing(secRing);
}
} \ No newline at end of file
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 6ce77394c..39d0a2f1d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
@@ -40,13 +40,17 @@ import org.spongycastle.openpgp.operator.jcajce.NfcSyncPublicKeyDataDecryptorFac
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+
/**
* Wrapper for a PGPSecretKey.
@@ -184,13 +188,13 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
return PgpConstants.sPreferredHashAlgorithms;
}
- private PGPContentSignerBuilder getContentSignerBuilder(int hashAlgo, byte[] nfcSignedHash,
- Date nfcCreationTimestamp) {
+ private PGPContentSignerBuilder getContentSignerBuilder(int hashAlgo,
+ Map<ByteBuffer,byte[]> signedHashes) {
if (mPrivateKeyState == PRIVATE_KEY_STATE_DIVERT_TO_CARD) {
// use synchronous "NFC based" SignerBuilder
return new NfcSyncPGPContentSignerBuilder(
mSecretKey.getPublicKey().getAlgorithm(), hashAlgo,
- mSecretKey.getKeyID(), nfcSignedHash, nfcCreationTimestamp)
+ mSecretKey.getKeyID(), signedHashes)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
} else {
// content signer based on signing key algorithm and chosen hash algorithm
@@ -200,29 +204,43 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
}
}
- public PGPSignatureGenerator getSignatureGenerator(int hashAlgo, boolean cleartext,
- byte[] nfcSignedHash, Date nfcCreationTimestamp)
- throws PgpGeneralException {
+ public PGPSignatureGenerator getCertSignatureGenerator(Map<ByteBuffer, byte[]> signedHashes) {
+ PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(
+ PgpConstants.CERTIFY_HASH_ALGO, signedHashes);
+
if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {
throw new PrivateKeyNotUnlockedException();
}
- if (nfcSignedHash != null && nfcCreationTimestamp == null) {
- throw new PgpGeneralException("Got nfc hash without timestamp!!");
+
+ PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
+ try {
+ signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, mPrivateKey);
+ return signatureGenerator;
+ } catch (PGPException e) {
+ Log.e(Constants.TAG, "signing error", e);
+ return null;
+ }
+ }
+
+ public PGPSignatureGenerator getDataSignatureGenerator(int hashAlgo, boolean cleartext,
+ Map<ByteBuffer, byte[]> signedHashes, Date creationTimestamp)
+ throws PgpGeneralException {
+ if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {
+ throw new PrivateKeyNotUnlockedException();
}
// We explicitly create a signature creation timestamp in this place.
// That way, we can inject an artificial one from outside, ie the one
// used in previous runs of this function.
- if (nfcCreationTimestamp == null) {
+ if (creationTimestamp == null) {
// 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
// the second time the signed hash is used.
// to get the same hash we cache the timestamp for the second round!
- nfcCreationTimestamp = new Date();
+ creationTimestamp = new Date();
}
- PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(hashAlgo,
- nfcSignedHash, nfcCreationTimestamp);
+ PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(hashAlgo, signedHashes);
int signatureType;
if (cleartext) {
@@ -238,7 +256,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
spGen.setSignerUserID(false, mRing.getPrimaryUserIdWithFallback());
- spGen.setSignatureCreationTime(false, nfcCreationTimestamp);
+ spGen.setSignatureCreationTime(false, creationTimestamp);
signatureGenerator.setHashedSubpackets(spGen.generate());
return signatureGenerator;
} catch (PgpKeyNotFoundException | PGPException e) {
@@ -247,145 +265,24 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
}
}
- public PublicKeyDataDecryptorFactory getDecryptorFactory(byte[] nfcDecryptedSessionKey) {
+ public PublicKeyDataDecryptorFactory getDecryptorFactory(CryptoInputParcel cryptoInput) {
if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {
throw new PrivateKeyNotUnlockedException();
}
if (mPrivateKeyState == PRIVATE_KEY_STATE_DIVERT_TO_CARD) {
return new NfcSyncPublicKeyDataDecryptorFactoryBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(nfcDecryptedSessionKey);
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
+ cryptoInput.getCryptoData()
+ );
} else {
return new JcePublicKeyDataDecryptorFactoryBuilder()
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mPrivateKey);
}
}
- /**
- * Certify the given pubkeyid with the given masterkeyid.
- *
- * @param publicKeyRing Keyring to add certification to.
- * @param userIds User IDs to certify
- * @return A keyring with added certifications
- */
- public UncachedKeyRing certifyUserIds(CanonicalizedPublicKeyRing publicKeyRing, List<String> userIds,
- byte[] nfcSignedHash, Date nfcCreationTimestamp) {
- if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {
- throw new PrivateKeyNotUnlockedException();
- }
- if (!isMasterKey()) {
- throw new AssertionError("tried to certify with non-master key, this is a programming error!");
- }
- if (publicKeyRing.getMasterKeyId() == getKeyId()) {
- throw new AssertionError("key tried to self-certify, this is a programming error!");
- }
-
- // create a signatureGenerator from the supplied masterKeyId and passphrase
- PGPSignatureGenerator signatureGenerator;
- {
- PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(
- PgpConstants.CERTIFY_HASH_ALGO, nfcSignedHash, nfcCreationTimestamp);
-
- signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
- try {
- signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, mPrivateKey);
- } catch (PGPException e) {
- Log.e(Constants.TAG, "signing error", e);
- return null;
- }
- }
-
- { // 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);
- }
-
- // get the master subkey (which we certify for)
- PGPPublicKey publicKey = publicKeyRing.getPublicKey().getPublicKey();
-
- // fetch public key ring, add the certification and return it
- try {
- for (String userId : userIds) {
- PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey);
- publicKey = PGPPublicKey.addCertification(publicKey, userId, sig);
- }
- } catch (PGPException e) {
- Log.e(Constants.TAG, "signing error", e);
- return null;
- }
-
- PGPPublicKeyRing ring = PGPPublicKeyRing.insertPublicKey(publicKeyRing.getRing(), publicKey);
-
- return new UncachedKeyRing(ring);
- }
-
- /**
- * Certify the given user attributes with the given masterkeyid.
- *
- * @param publicKeyRing Keyring to add certification to.
- * @param userAttributes User IDs to certify, or all if null
- * @return A keyring with added certifications
- */
- public UncachedKeyRing certifyUserAttributes(CanonicalizedPublicKeyRing publicKeyRing,
- List<WrappedUserAttribute> userAttributes, byte[] nfcSignedHash, Date nfcCreationTimestamp) {
- if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {
- throw new PrivateKeyNotUnlockedException();
- }
- if (!isMasterKey()) {
- throw new AssertionError("tried to certify with non-master key, this is a programming error!");
- }
- if (publicKeyRing.getMasterKeyId() == getKeyId()) {
- throw new AssertionError("key tried to self-certify, this is a programming error!");
- }
-
- // create a signatureGenerator from the supplied masterKeyId and passphrase
- PGPSignatureGenerator signatureGenerator;
- {
- PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(
- PgpConstants.CERTIFY_HASH_ALGO, nfcSignedHash, nfcCreationTimestamp);
-
- signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
- try {
- signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, mPrivateKey);
- } catch (PGPException e) {
- Log.e(Constants.TAG, "signing error", e);
- return null;
- }
- }
-
- { // 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);
- }
-
- // get the master subkey (which we certify for)
- PGPPublicKey publicKey = publicKeyRing.getPublicKey().getPublicKey();
-
- // fetch public key ring, add the certification and return it
- try {
- for (WrappedUserAttribute userAttribute : userAttributes) {
- PGPUserAttributeSubpacketVector vector = userAttribute.getVector();
- PGPSignature sig = signatureGenerator.generateCertification(vector, publicKey);
- publicKey = PGPPublicKey.addCertification(publicKey, vector, sig);
- }
- } catch (PGPException e) {
- Log.e(Constants.TAG, "signing error", e);
- return null;
- }
-
- PGPPublicKeyRing ring = PGPPublicKeyRing.insertPublicKey(publicKeyRing.getRing(), publicKey);
-
- return new UncachedKeyRing(ring);
+ public byte[] getIv() {
+ return mSecretKey.getIV();
}
static class PrivateKeyNotUnlockedException extends RuntimeException {
@@ -402,4 +299,9 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
return mPrivateKey;
}
+ // HACK, for TESTING ONLY!!
+ PGPSecretKey getSecretKey() {
+ return mSecretKey;
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpCertifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpCertifyOperation.java
new file mode 100644
index 000000000..90ec3053f
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpCertifyOperation.java
@@ -0,0 +1,149 @@
+package org.sufficientlysecure.keychain.pgp;
+
+
+import java.nio.ByteBuffer;
+import java.util.Date;
+import java.util.Map;
+
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPPublicKey;
+import org.spongycastle.openpgp.PGPPublicKeyRing;
+import org.spongycastle.openpgp.PGPSignature;
+import org.spongycastle.openpgp.PGPSignatureGenerator;
+import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
+import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
+import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector;
+import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
+import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder;
+import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
+import org.sufficientlysecure.keychain.util.Log;
+
+
+public class PgpCertifyOperation {
+
+ public PgpCertifyResult certify(
+ CanonicalizedSecretKey secretKey,
+ CanonicalizedPublicKeyRing publicRing,
+ OperationLog log,
+ int indent,
+ CertifyAction action,
+ Map<ByteBuffer,byte[]> signedHashes,
+ Date creationTimestamp) {
+
+ if (!secretKey.isMasterKey()) {
+ throw new AssertionError("tried to certify with non-master key, this is a programming error!");
+ }
+ if (publicRing.getMasterKeyId() == secretKey.getKeyId()) {
+ throw new AssertionError("key tried to self-certify, this is a programming error!");
+ }
+
+ // create a signatureGenerator from the supplied masterKeyId and passphrase
+ PGPSignatureGenerator signatureGenerator = secretKey.getCertSignatureGenerator(signedHashes);
+
+ { // supply signatureGenerator with a SubpacketVector
+ PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+ if (creationTimestamp != null) {
+ spGen.setSignatureCreationTime(false, creationTimestamp);
+ Log.d(Constants.TAG, "For NFC: set sig creation time to " + creationTimestamp);
+ }
+ PGPSignatureSubpacketVector packetVector = spGen.generate();
+ signatureGenerator.setHashedSubpackets(packetVector);
+ }
+
+ // get the master subkey (which we certify for)
+ PGPPublicKey publicKey = publicRing.getPublicKey().getPublicKey();
+
+ NfcSignOperationsBuilder requiredInput = new NfcSignOperationsBuilder(creationTimestamp,
+ publicKey.getKeyID(), publicKey.getKeyID());
+
+ try {
+ if (action.mUserIds != null) {
+ log.add(LogType.MSG_CRT_CERTIFY_UIDS, 2, action.mUserIds.size(),
+ KeyFormattingUtils.convertKeyIdToHex(action.mMasterKeyId));
+
+ // fetch public key ring, add the certification and return it
+ for (String userId : action.mUserIds) {
+ try {
+ PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey);
+ publicKey = PGPPublicKey.addCertification(publicKey, userId, sig);
+ } catch (NfcInteractionNeeded e) {
+ requiredInput.addHash(e.hashToSign, e.hashAlgo);
+ }
+ }
+
+ }
+
+ if (action.mUserAttributes != null) {
+ log.add(LogType.MSG_CRT_CERTIFY_UATS, 2, action.mUserAttributes.size(),
+ KeyFormattingUtils.convertKeyIdToHex(action.mMasterKeyId));
+
+ // fetch public key ring, add the certification and return it
+ for (WrappedUserAttribute userAttribute : action.mUserAttributes) {
+ PGPUserAttributeSubpacketVector vector = userAttribute.getVector();
+ try {
+ PGPSignature sig = signatureGenerator.generateCertification(vector, publicKey);
+ publicKey = PGPPublicKey.addCertification(publicKey, vector, sig);
+ } catch (NfcInteractionNeeded e) {
+ requiredInput.addHash(e.hashToSign, e.hashAlgo);
+ }
+ }
+
+ }
+ } catch (PGPException e) {
+ Log.e(Constants.TAG, "signing error", e);
+ return new PgpCertifyResult();
+ }
+
+ if (!requiredInput.isEmpty()) {
+ return new PgpCertifyResult(requiredInput.build());
+ }
+
+ PGPPublicKeyRing ring = PGPPublicKeyRing.insertPublicKey(publicRing.getRing(), publicKey);
+ return new PgpCertifyResult(new UncachedKeyRing(ring));
+
+ }
+
+ public static class PgpCertifyResult {
+
+ final RequiredInputParcel mRequiredInput;
+ final UncachedKeyRing mCertifiedRing;
+
+ PgpCertifyResult() {
+ mRequiredInput = null;
+ mCertifiedRing = null;
+ }
+
+ PgpCertifyResult(RequiredInputParcel requiredInput) {
+ mRequiredInput = requiredInput;
+ mCertifiedRing = null;
+ }
+
+ PgpCertifyResult(UncachedKeyRing certifiedRing) {
+ mRequiredInput = null;
+ mCertifiedRing = certifiedRing;
+ }
+
+ public boolean success() {
+ return mCertifiedRing != null || mRequiredInput != null;
+ }
+
+ public boolean nfcInputRequired() {
+ return mRequiredInput != null;
+ }
+
+ public UncachedKeyRing getCertifiedRing() {
+ return mCertifiedRing;
+ }
+
+ public RequiredInputParcel getRequiredInput() {
+ return mRequiredInput;
+ }
+
+ }
+
+}
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 364a1067d..f6580b85a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -47,16 +47,15 @@ import org.spongycastle.openpgp.operator.jcajce.NfcSyncPublicKeyDataDecryptorFac
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.BaseOperation;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
-import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
-import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
@@ -84,10 +83,8 @@ public class PgpDecryptVerify extends BaseOperation {
private OutputStream mOutStream;
private boolean mAllowSymmetricDecryption;
- private Passphrase mPassphrase;
private Set<Long> mAllowedKeyIds;
private boolean mDecryptMetadataOnly;
- private byte[] mDecryptedSessionKey;
private byte[] mDetachedSignature;
private String mRequiredSignerFingerprint;
private boolean mSignedLiteralData;
@@ -100,10 +97,8 @@ public class PgpDecryptVerify extends BaseOperation {
this.mOutStream = builder.mOutStream;
this.mAllowSymmetricDecryption = builder.mAllowSymmetricDecryption;
- this.mPassphrase = builder.mPassphrase;
this.mAllowedKeyIds = builder.mAllowedKeyIds;
this.mDecryptMetadataOnly = builder.mDecryptMetadataOnly;
- this.mDecryptedSessionKey = builder.mDecryptedSessionKey;
this.mDetachedSignature = builder.mDetachedSignature;
this.mSignedLiteralData = builder.mSignedLiteralData;
this.mRequiredSignerFingerprint = builder.mRequiredSignerFingerprint;
@@ -119,10 +114,8 @@ public class PgpDecryptVerify extends BaseOperation {
private OutputStream mOutStream = null;
private Progressable mProgressable = null;
private boolean mAllowSymmetricDecryption = true;
- private Passphrase mPassphrase = null;
private Set<Long> mAllowedKeyIds = null;
private boolean mDecryptMetadataOnly = false;
- private byte[] mDecryptedSessionKey = null;
private byte[] mDetachedSignature = null;
private String mRequiredSignerFingerprint = null;
private boolean mSignedLiteralData = false;
@@ -160,11 +153,6 @@ public class PgpDecryptVerify extends BaseOperation {
return this;
}
- public Builder setPassphrase(Passphrase passphrase) {
- mPassphrase = passphrase;
- return this;
- }
-
/**
* Allow these key ids alone for decryption.
* This means only ciphertexts encrypted for one of these private key can be decrypted.
@@ -183,11 +171,6 @@ public class PgpDecryptVerify extends BaseOperation {
return this;
}
- public Builder setNfcState(byte[] decryptedSessionKey) {
- mDecryptedSessionKey = decryptedSessionKey;
- return this;
- }
-
/**
* If detachedSignature != null, it will be used exclusively to verify the signature
*/
@@ -204,7 +187,7 @@ public class PgpDecryptVerify extends BaseOperation {
/**
* Decrypts and/or verifies data based on parameters of class
*/
- public DecryptVerifyResult execute() {
+ public DecryptVerifyResult execute(CryptoInputParcel cryptoInput) {
try {
if (mDetachedSignature != null) {
Log.d(Constants.TAG, "Detached signature present, verifying with this signature only");
@@ -226,10 +209,10 @@ public class PgpDecryptVerify extends BaseOperation {
return verifyCleartextSignature(aIn, 0);
} else {
// else: ascii armored encryption! go on...
- return decryptVerify(in, 0);
+ return decryptVerify(cryptoInput, in, 0);
}
} else {
- return decryptVerify(in, 0);
+ return decryptVerify(cryptoInput, in, 0);
}
}
} catch (PGPException e) {
@@ -248,7 +231,8 @@ public class PgpDecryptVerify extends BaseOperation {
/**
* Verify Keybase.io style signed literal data
*/
- private DecryptVerifyResult verifySignedLiteralData(InputStream in, int indent) throws IOException, PGPException {
+ private DecryptVerifyResult verifySignedLiteralData(InputStream in, int indent)
+ throws IOException, PGPException {
OperationLog log = new OperationLog();
log.add(LogType.MSG_VL, indent);
@@ -378,7 +362,8 @@ public class PgpDecryptVerify extends BaseOperation {
/**
* Decrypt and/or verifies binary or ascii armored pgp
*/
- private DecryptVerifyResult decryptVerify(InputStream in, int indent) throws IOException, PGPException {
+ private DecryptVerifyResult decryptVerify(CryptoInputParcel cryptoInput,
+ InputStream in, int indent) throws IOException, PGPException {
OperationLog log = new OperationLog();
@@ -433,6 +418,8 @@ public class PgpDecryptVerify extends BaseOperation {
}
}
+ Passphrase passphrase = null;
+
// go through all objects and find one we can decrypt
while (it.hasNext()) {
Object obj = it.next();
@@ -492,11 +479,15 @@ public class PgpDecryptVerify extends BaseOperation {
encryptedDataAsymmetric = encData;
- // if no passphrase was explicitly set try to get it from the cache service
- if (mPassphrase == null) {
+ if (secretEncryptionKey.getSecretKeyType() == SecretKeyType.DIVERT_TO_CARD) {
+ passphrase = null;
+ } else if (cryptoInput.hasPassphrase()) {
+ passphrase = cryptoInput.getPassphrase();
+ } else {
+ // if no passphrase was explicitly set try to get it from the cache service
try {
// returns "" if key has no passphrase
- mPassphrase = getCachedPassphrase(subKeyId);
+ passphrase = getCachedPassphrase(subKeyId);
log.add(LogType.MSG_DC_PASS_CACHED, indent + 1);
} catch (PassphraseCacheInterface.NoSecretKeyException e) {
log.add(LogType.MSG_DC_ERROR_NO_KEY, indent + 1);
@@ -504,12 +495,11 @@ public class PgpDecryptVerify extends BaseOperation {
}
// if passphrase was not cached, return here indicating that a passphrase is missing!
- if (mPassphrase == null) {
+ if (passphrase == null) {
log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1);
- DecryptVerifyResult result =
- new DecryptVerifyResult(DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE, log);
- result.setKeyIdPassphraseNeeded(subKeyId);
- return result;
+ return new DecryptVerifyResult(log,
+ RequiredInputParcel.createRequiredDecryptPassphrase(
+ secretKeyRing.getMasterKeyId(), secretEncryptionKey.getKeyId()));
}
}
@@ -536,11 +526,14 @@ public class PgpDecryptVerify extends BaseOperation {
// if no passphrase is given, return here
// indicating that a passphrase is missing!
- if (mPassphrase == null) {
+ if (!cryptoInput.hasPassphrase()) {
log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1);
- return new DecryptVerifyResult(DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE, log);
+ return new DecryptVerifyResult(log,
+ RequiredInputParcel.createRequiredSymmetricPassphrase());
}
+ passphrase = cryptoInput.getPassphrase();
+
// break out of while, only decrypt the first packet
break;
}
@@ -573,7 +566,7 @@ public class PgpDecryptVerify extends BaseOperation {
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build();
PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder(
digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- mPassphrase.getCharArray());
+ passphrase.getCharArray());
clear = encryptedDataSymmetric.getDataStream(decryptorFactory);
encryptedData = encryptedDataSymmetric;
@@ -585,7 +578,7 @@ public class PgpDecryptVerify extends BaseOperation {
try {
log.add(LogType.MSG_DC_UNLOCKING, indent + 1);
- if (!secretEncryptionKey.unlock(mPassphrase)) {
+ if (!secretEncryptionKey.unlock(passphrase)) {
log.add(LogType.MSG_DC_ERROR_BAD_PASSPHRASE, indent + 1);
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
}
@@ -599,16 +592,15 @@ public class PgpDecryptVerify extends BaseOperation {
try {
PublicKeyDataDecryptorFactory decryptorFactory
- = secretEncryptionKey.getDecryptorFactory(mDecryptedSessionKey);
+ = secretEncryptionKey.getDecryptorFactory(cryptoInput);
clear = encryptedDataAsymmetric.getDataStream(decryptorFactory);
symmetricEncryptionAlgo = encryptedDataAsymmetric.getSymmetricAlgorithm(decryptorFactory);
} catch (NfcSyncPublicKeyDataDecryptorFactoryBuilder.NfcInteractionNeeded e) {
log.add(LogType.MSG_DC_PENDING_NFC, indent + 1);
- DecryptVerifyResult result =
- new DecryptVerifyResult(DecryptVerifyResult.RESULT_PENDING_NFC, log);
- result.setNfcState(secretEncryptionKey.getKeyId(), e.encryptedSessionKey, mPassphrase);
- return result;
+ return new DecryptVerifyResult(log, RequiredInputParcel.createNfcDecryptOperation(
+ e.encryptedSessionKey, secretEncryptionKey.getKeyId()
+ ));
}
encryptedData = encryptedDataAsymmetric;
} else {
@@ -878,8 +870,8 @@ public class PgpDecryptVerify extends BaseOperation {
* The method is heavily based on
* pg/src/main/java/org/spongycastle/openpgp/examples/ClearSignedFileProcessor.java
*/
- private DecryptVerifyResult verifyCleartextSignature(ArmoredInputStream aIn, int indent)
- throws IOException, PGPException {
+ private DecryptVerifyResult verifyCleartextSignature(
+ ArmoredInputStream aIn, int indent) throws IOException, PGPException {
OperationLog log = new OperationLog();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
index b3bf92364..89db378a9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -18,7 +18,7 @@
package org.sufficientlysecure.keychain.pgp;
-import org.spongycastle.bcpg.HashAlgorithmTags;
+import org.spongycastle.bcpg.S2K;
import org.spongycastle.bcpg.sig.Features;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.jce.spec.ElGamalParameterSpec;
@@ -43,6 +43,8 @@ import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBu
import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
+import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder;
+import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
@@ -54,6 +56,9 @@ import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
@@ -86,6 +91,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* This indicator may be null.
*/
public class PgpKeyOperation {
+
private Stack<Progressable> mProgress;
private AtomicBoolean mCancelled;
@@ -317,7 +323,8 @@ public class PgpKeyOperation {
masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator());
subProgressPush(50, 100);
- return internal(sKR, masterSecretKey, add.mFlags, add.mExpiry, saveParcel, new Passphrase(), log);
+ CryptoInputParcel cryptoInput = new CryptoInputParcel(new Date(), new Passphrase(""));
+ return internal(sKR, masterSecretKey, add.mFlags, add.mExpiry, cryptoInput, saveParcel, log);
} catch (PGPException e) {
log.add(LogType.MSG_CR_ERROR_INTERNAL_PGP, indent);
@@ -348,8 +355,9 @@ public class PgpKeyOperation {
* namely stripping of subkeys and changing the protection mode of dummy keys.
*
*/
- public PgpEditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR, SaveKeyringParcel saveParcel,
- Passphrase passphrase) {
+ public PgpEditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR,
+ CryptoInputParcel cryptoInput,
+ SaveKeyringParcel saveParcel) {
OperationLog log = new OperationLog();
int indent = 0;
@@ -387,11 +395,24 @@ public class PgpKeyOperation {
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
}
- // If we have no passphrase, only allow restricted operation
- if (passphrase == null) {
+ if (saveParcel.isEmpty()) {
+ log.add(LogType.MSG_MF_ERROR_NOOP, indent);
+ return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
+ }
+
+ if (isDummy(masterSecretKey) || saveParcel.isRestrictedOnly()) {
+ log.add(LogType.MSG_MF_RESTRICTED_MODE, indent);
return internalRestricted(sKR, saveParcel, log);
}
+ // Do we require a passphrase? If so, pass it along
+ if (!isDivertToCard(masterSecretKey) && !cryptoInput.hasPassphrase()) {
+ log.add(LogType.MSG_MF_REQUIRE_PASSPHRASE, indent);
+ return new PgpEditKeyResult(log, RequiredInputParcel.createRequiredSignPassphrase(
+ masterSecretKey.getKeyID(), masterSecretKey.getKeyID(),
+ cryptoInput.getSignatureTime()));
+ }
+
// read masterKeyFlags, and use the same as before.
// since this is the master key, this contains at least CERTIFY_OTHER
PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
@@ -399,33 +420,45 @@ public class PgpKeyOperation {
Date expiryTime = wsKR.getPublicKey().getExpiryTime();
long masterKeyExpiry = expiryTime != null ? expiryTime.getTime() / 1000 : 0L;
- return internal(sKR, masterSecretKey, masterKeyFlags, masterKeyExpiry, saveParcel, passphrase, log);
+ return internal(sKR, masterSecretKey, masterKeyFlags, masterKeyExpiry, cryptoInput, saveParcel, log);
}
private PgpEditKeyResult internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey,
int masterKeyFlags, long masterKeyExpiry,
- SaveKeyringParcel saveParcel, Passphrase passphrase,
+ CryptoInputParcel cryptoInput,
+ SaveKeyringParcel saveParcel,
OperationLog log) {
int indent = 1;
+ NfcSignOperationsBuilder nfcSignOps = new NfcSignOperationsBuilder(
+ cryptoInput.getSignatureTime(), masterSecretKey.getKeyID(),
+ masterSecretKey.getKeyID());
+
progress(R.string.progress_modify, 0);
PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
- // 1. Unlock private key
- progress(R.string.progress_modify_unlock, 10);
- log.add(LogType.MSG_MF_UNLOCK, indent);
PGPPrivateKey masterPrivateKey;
- {
- try {
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
- Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray());
- masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
- } catch (PGPException e) {
- log.add(LogType.MSG_MF_UNLOCK_ERROR, indent + 1);
- return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
+
+ if (isDivertToCard(masterSecretKey)) {
+ masterPrivateKey = null;
+ log.add(LogType.MSG_MF_DIVERT, indent);
+ } else {
+
+ // 1. Unlock private key
+ progress(R.string.progress_modify_unlock, 10);
+ log.add(LogType.MSG_MF_UNLOCK, indent);
+ {
+ try {
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(cryptoInput.getPassphrase().getCharArray());
+ masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
+ } catch (PGPException e) {
+ log.add(LogType.MSG_MF_UNLOCK_ERROR, indent + 1);
+ return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
+ }
}
}
@@ -449,7 +482,7 @@ public class PgpKeyOperation {
String userId = saveParcel.mAddUserIds.get(i);
log.add(LogType.MSG_MF_UID_ADD, indent, userId);
- if (userId.equals("")) {
+ if ("".equals(userId)) {
log.add(LogType.MSG_MF_UID_ERROR_EMPTY, indent + 1);
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
}
@@ -480,9 +513,16 @@ public class PgpKeyOperation {
boolean isPrimary = saveParcel.mChangePrimaryUserId != null
&& userId.equals(saveParcel.mChangePrimaryUserId);
// generate and add new certificate
- PGPSignature cert = generateUserIdSignature(masterPrivateKey,
- masterPublicKey, userId, isPrimary, masterKeyFlags, masterKeyExpiry);
- modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
+ try {
+ PGPSignature cert = generateUserIdSignature(
+ getSignatureGenerator(masterSecretKey, cryptoInput),
+ cryptoInput.getSignatureTime(),
+ masterPrivateKey, masterPublicKey, userId,
+ isPrimary, masterKeyFlags, masterKeyExpiry);
+ modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
+ } catch (NfcInteractionNeeded e) {
+ nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
+ }
}
subProgressPop();
@@ -509,9 +549,15 @@ public class PgpKeyOperation {
PGPUserAttributeSubpacketVector vector = attribute.getVector();
// generate and add new certificate
- PGPSignature cert = generateUserAttributeSignature(masterPrivateKey,
- masterPublicKey, vector);
- modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, vector, cert);
+ try {
+ PGPSignature cert = generateUserAttributeSignature(
+ getSignatureGenerator(masterSecretKey, cryptoInput),
+ cryptoInput.getSignatureTime(),
+ masterPrivateKey, masterPublicKey, vector);
+ modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, vector, cert);
+ } catch (NfcInteractionNeeded e) {
+ nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
+ }
}
subProgressPop();
@@ -539,9 +585,15 @@ public class PgpKeyOperation {
// a duplicate revocation will be removed during canonicalization, so no need to
// take care of that here.
- PGPSignature cert = generateRevocationSignature(masterPrivateKey,
- masterPublicKey, userId);
- modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
+ try {
+ PGPSignature cert = generateRevocationSignature(
+ getSignatureGenerator(masterSecretKey, cryptoInput),
+ cryptoInput.getSignatureTime(),
+ masterPrivateKey, masterPublicKey, userId);
+ modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
+ } catch (NfcInteractionNeeded e) {
+ nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
+ }
}
subProgressPop();
@@ -611,11 +663,18 @@ public class PgpKeyOperation {
log.add(LogType.MSG_MF_PRIMARY_REPLACE_OLD, indent);
modifiedPublicKey = PGPPublicKey.removeCertification(
modifiedPublicKey, userId, currentCert);
- PGPSignature newCert = generateUserIdSignature(
- masterPrivateKey, masterPublicKey, userId, false,
- masterKeyFlags, masterKeyExpiry);
- modifiedPublicKey = PGPPublicKey.addCertification(
- modifiedPublicKey, userId, newCert);
+ try {
+ PGPSignature newCert = generateUserIdSignature(
+ getSignatureGenerator(masterSecretKey, cryptoInput),
+ cryptoInput.getSignatureTime(),
+ masterPrivateKey, masterPublicKey, userId, false,
+ masterKeyFlags, masterKeyExpiry);
+ modifiedPublicKey = PGPPublicKey.addCertification(
+ modifiedPublicKey, userId, newCert);
+ } catch (NfcInteractionNeeded e) {
+ nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
+ }
+
continue;
}
@@ -627,11 +686,17 @@ public class PgpKeyOperation {
log.add(LogType.MSG_MF_PRIMARY_NEW, indent);
modifiedPublicKey = PGPPublicKey.removeCertification(
modifiedPublicKey, userId, currentCert);
- PGPSignature newCert = generateUserIdSignature(
- masterPrivateKey, masterPublicKey, userId, true,
- masterKeyFlags, masterKeyExpiry);
- modifiedPublicKey = PGPPublicKey.addCertification(
- modifiedPublicKey, userId, newCert);
+ try {
+ PGPSignature newCert = generateUserIdSignature(
+ getSignatureGenerator(masterSecretKey, cryptoInput),
+ cryptoInput.getSignatureTime(),
+ masterPrivateKey, masterPublicKey, userId, true,
+ masterKeyFlags, masterKeyExpiry);
+ modifiedPublicKey = PGPPublicKey.addCertification(
+ modifiedPublicKey, userId, newCert);
+ } catch (NfcInteractionNeeded e) {
+ nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
+ }
ok = true;
}
@@ -718,8 +783,9 @@ public class PgpKeyOperation {
}
PGPPublicKey pKey =
- updateMasterCertificates(masterPrivateKey, masterPublicKey,
- flags, expiry, indent, log);
+ updateMasterCertificates(
+ masterSecretKey, masterPrivateKey, masterPublicKey,
+ flags, expiry, cryptoInput, nfcSignOps, indent, log);
if (pKey == null) {
// error log entry has already been added by updateMasterCertificates itself
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
@@ -756,9 +822,16 @@ public class PgpKeyOperation {
pKey = PGPPublicKey.removeCertification(pKey, sig);
}
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
+ cryptoInput.getPassphrase().getCharArray());
+ PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
+ PGPSignature sig = generateSubkeyBindingSignature(
+ getSignatureGenerator(masterSecretKey, cryptoInput),
+ cryptoInput.getSignatureTime(),
+ masterPublicKey, masterPrivateKey, subPrivateKey, pKey, flags, expiry);
+
// generate and add new signature
- PGPSignature sig = generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey,
- sKey, pKey, flags, expiry, passphrase);
pKey = PGPPublicKey.addCertification(pKey, sig);
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
}
@@ -782,10 +855,17 @@ public class PgpKeyOperation {
PGPPublicKey pKey = sKey.getPublicKey();
// generate and add new signature
- PGPSignature sig = generateRevocationSignature(masterPublicKey, masterPrivateKey, pKey);
-
- pKey = PGPPublicKey.addCertification(pKey, sig);
- sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
+ try {
+ PGPSignature sig = generateRevocationSignature(
+ getSignatureGenerator(masterSecretKey, cryptoInput),
+ cryptoInput.getSignatureTime(),
+ masterPublicKey, masterPrivateKey, pKey);
+
+ pKey = PGPPublicKey.addCertification(pKey, sig);
+ sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
+ } catch (NfcInteractionNeeded e) {
+ nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
+ }
}
subProgressPop();
@@ -828,10 +908,16 @@ public class PgpKeyOperation {
// add subkey binding signature (making this a sub rather than master key)
PGPPublicKey pKey = keyPair.getPublicKey();
- PGPSignature cert = generateSubkeyBindingSignature(
- masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey,
- add.mFlags, add.mExpiry);
- pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
+ try {
+ PGPSignature cert = generateSubkeyBindingSignature(
+ getSignatureGenerator(masterSecretKey, cryptoInput),
+ cryptoInput.getSignatureTime(),
+ masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey,
+ add.mFlags, add.mExpiry);
+ pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
+ } catch (NfcInteractionNeeded e) {
+ nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
+ }
PGPSecretKey sKey; {
// Build key encrypter and decrypter based on passphrase
@@ -840,7 +926,8 @@ public class PgpKeyOperation {
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray());
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
+ cryptoInput.getPassphrase().getCharArray());
PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
.build().get(PgpConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO);
@@ -868,7 +955,7 @@ public class PgpKeyOperation {
indent += 1;
sKR = applyNewUnlock(sKR, masterPublicKey, masterPrivateKey,
- passphrase, saveParcel.mNewUnlock, log, indent);
+ cryptoInput.getPassphrase(), saveParcel.mNewUnlock, log, indent);
if (sKR == null) {
// The error has been logged above, just return a bad state
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
@@ -892,6 +979,12 @@ public class PgpKeyOperation {
}
progress(R.string.progress_done, 100);
+
+ if (!nfcSignOps.isEmpty()) {
+ log.add(LogType.MSG_MF_REQUIRE_DIVERT, indent);
+ return new PgpEditKeyResult(log, nfcSignOps.build());
+ }
+
log.add(LogType.MSG_MF_SUCCESS, indent);
return new PgpEditKeyResult(OperationResult.RESULT_OK, log, new UncachedKeyRing(sKR));
@@ -1064,8 +1157,7 @@ public class PgpKeyOperation {
PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder(
PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- newPassphrase.getCharArray());
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(newPassphrase.getCharArray());
// noinspection unchecked
for (PGPSecretKey sKey : new IterableIterator<PGPSecretKey>(sKR.getSecretKeys())) {
@@ -1116,9 +1208,13 @@ public class PgpKeyOperation {
}
/** Update all (non-revoked) uid signatures with new flags and expiry time. */
- private static PGPPublicKey updateMasterCertificates(
- PGPPrivateKey masterPrivateKey, PGPPublicKey masterPublicKey,
- int flags, long expiry, int indent, OperationLog log)
+ private PGPPublicKey updateMasterCertificates(
+ PGPSecretKey masterSecretKey, PGPPrivateKey masterPrivateKey,
+ PGPPublicKey masterPublicKey,
+ int flags, long expiry,
+ CryptoInputParcel cryptoInput,
+ NfcSignOperationsBuilder nfcSignOps,
+ int indent, OperationLog log)
throws PGPException, IOException, SignatureException {
// keep track if we actually changed one
@@ -1173,10 +1269,16 @@ public class PgpKeyOperation {
currentCert.getHashedSubPackets().isPrimaryUserID();
modifiedPublicKey = PGPPublicKey.removeCertification(
modifiedPublicKey, userId, currentCert);
- PGPSignature newCert = generateUserIdSignature(
- masterPrivateKey, masterPublicKey, userId, isPrimary, flags, expiry);
- modifiedPublicKey = PGPPublicKey.addCertification(
- modifiedPublicKey, userId, newCert);
+ try {
+ PGPSignature newCert = generateUserIdSignature(
+ getSignatureGenerator(masterSecretKey, cryptoInput),
+ cryptoInput.getSignatureTime(),
+ masterPrivateKey, masterPublicKey, userId, isPrimary, flags, expiry);
+ modifiedPublicKey = PGPPublicKey.addCertification(
+ modifiedPublicKey, userId, newCert);
+ } catch (NfcInteractionNeeded e) {
+ nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
+ }
ok = true;
}
@@ -1191,15 +1293,37 @@ public class PgpKeyOperation {
}
- private static PGPSignature generateUserIdSignature(
+ static PGPSignatureGenerator getSignatureGenerator(
+ PGPSecretKey secretKey, CryptoInputParcel cryptoInput) {
+
+ PGPContentSignerBuilder builder;
+
+ S2K s2k = secretKey.getS2K();
+ if (s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K
+ && s2k.getProtectionMode() == S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD) {
+ // use synchronous "NFC based" SignerBuilder
+ builder = new NfcSyncPGPContentSignerBuilder(
+ secretKey.getPublicKey().getAlgorithm(),
+ PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO,
+ secretKey.getKeyID(), cryptoInput.getCryptoData())
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ } else {
+ // content signer based on signing key algorithm and chosen hash algorithm
+ builder = new JcaPGPContentSignerBuilder(
+ secretKey.getPublicKey().getAlgorithm(),
+ PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ }
+
+ return new PGPSignatureGenerator(builder);
+
+ }
+
+ private PGPSignature generateUserIdSignature(
+ PGPSignatureGenerator sGen, Date creationTime,
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId, boolean primary,
int flags, long expiry)
throws IOException, PGPException, SignatureException {
- PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPrivateKey.getPublicKeyPacket().getAlgorithm(),
- PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator();
{
@@ -1223,7 +1347,7 @@ public class PgpKeyOperation {
hashedPacketsGen.setPrimaryUserID(false, primary);
/* critical subpackets: we consider those important for a modern pgp implementation */
- hashedPacketsGen.setSignatureCreationTime(true, new Date());
+ hashedPacketsGen.setSignatureCreationTime(true, creationTime);
// Request that senders add the MDC to the message (authenticate unsigned messages)
hashedPacketsGen.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION);
hashedPacketsGen.setKeyFlags(true, flags);
@@ -1239,19 +1363,15 @@ public class PgpKeyOperation {
}
private static PGPSignature generateUserAttributeSignature(
+ PGPSignatureGenerator sGen, Date creationTime,
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey,
PGPUserAttributeSubpacketVector vector)
throws IOException, PGPException, SignatureException {
- PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPrivateKey.getPublicKeyPacket().getAlgorithm(),
- PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator();
{
/* critical subpackets: we consider those important for a modern pgp implementation */
- hashedPacketsGen.setSignatureCreationTime(true, new Date());
+ hashedPacketsGen.setSignatureCreationTime(true, creationTime);
}
sGen.setHashedSubpackets(hashedPacketsGen.generate());
@@ -1260,29 +1380,24 @@ public class PgpKeyOperation {
}
private static PGPSignature generateRevocationSignature(
+ PGPSignatureGenerator sGen, Date creationTime,
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId)
+
throws IOException, PGPException, SignatureException {
- PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPrivateKey.getPublicKeyPacket().getAlgorithm(),
- PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
- subHashedPacketsGen.setSignatureCreationTime(true, new Date());
+ subHashedPacketsGen.setSignatureCreationTime(true, creationTime);
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
sGen.init(PGPSignature.CERTIFICATION_REVOCATION, masterPrivateKey);
return sGen.generateCertification(userId, pKey);
}
private static PGPSignature generateRevocationSignature(
+ PGPSignatureGenerator sGen, Date creationTime,
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, PGPPublicKey pKey)
throws IOException, PGPException, SignatureException {
- PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPublicKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
+
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
- subHashedPacketsGen.setSignatureCreationTime(true, new Date());
+ subHashedPacketsGen.setSignatureCreationTime(true, creationTime);
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
// Generate key revocation or subkey revocation, depending on master/subkey-ness
if (masterPublicKey.getKeyID() == pKey.getKeyID()) {
@@ -1294,26 +1409,12 @@ public class PgpKeyOperation {
}
}
- private static PGPSignature generateSubkeyBindingSignature(
- PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey,
- PGPSecretKey sKey, PGPPublicKey pKey, int flags, long expiry, Passphrase passphrase)
- throws IOException, PGPException, SignatureException {
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- passphrase.getCharArray());
- PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
- return generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey, subPrivateKey,
- pKey, flags, expiry);
- }
-
static PGPSignature generateSubkeyBindingSignature(
+ PGPSignatureGenerator sGen, Date creationTime,
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey,
PGPPrivateKey subPrivateKey, PGPPublicKey pKey, int flags, long expiry)
throws IOException, PGPException, SignatureException {
- // date for signing
- Date creationTime = new Date();
-
PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator();
// If this key can sign, we need a primary key binding signature
@@ -1324,10 +1425,10 @@ public class PgpKeyOperation {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
- sGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
- sGen.setHashedSubpackets(subHashedPacketsGen.generate());
- PGPSignature certification = sGen.generateCertification(masterPublicKey, pKey);
+ PGPSignatureGenerator subSigGen = new PGPSignatureGenerator(signerBuilder);
+ subSigGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
+ subSigGen.setHashedSubpackets(subHashedPacketsGen.generate());
+ PGPSignature certification = subSigGen.generateCertification(masterPublicKey, pKey);
unhashedPacketsGen.setEmbeddedSignature(true, certification);
}
@@ -1342,10 +1443,6 @@ public class PgpKeyOperation {
}
}
- PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPublicKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
sGen.init(PGPSignature.SUBKEY_BINDING, masterPrivateKey);
sGen.setHashedSubpackets(hashedPacketsGen.generate());
sGen.setUnhashedSubpackets(unhashedPacketsGen.generate());
@@ -1372,4 +1469,16 @@ public class PgpKeyOperation {
return flags;
}
+ private static boolean isDummy(PGPSecretKey secretKey) {
+ S2K s2k = secretKey.getS2K();
+ return s2k.getType() == S2K.GNU_DUMMY_S2K
+ && s2k.getProtectionMode() == S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY;
+ }
+
+ private static boolean isDivertToCard(PGPSecretKey secretKey) {
+ S2K s2k = secretKey.getS2K();
+ return s2k.getType() == S2K.GNU_DUMMY_S2K
+ && s2k.getProtectionMode() == S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD;
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInput.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java
index 4a920685a..fd3c4910c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInput.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java
@@ -20,11 +20,18 @@ package org.sufficientlysecure.keychain.pgp;
import org.spongycastle.bcpg.CompressionAlgorithmTags;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.util.Passphrase;
+import java.nio.ByteBuffer;
import java.util.Date;
+import java.util.Map;
-public class PgpSignEncryptInput {
+import android.os.Parcel;
+import android.os.Parcelable;
+
+
+public class PgpSignEncryptInputParcel implements Parcelable {
protected String mVersionHeader = null;
protected boolean mEnableAsciiArmorOutput = false;
@@ -35,16 +42,68 @@ public class PgpSignEncryptInput {
protected long mSignatureMasterKeyId = Constants.key.none;
protected Long mSignatureSubKeyId = null;
protected int mSignatureHashAlgorithm = PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED;
- protected Passphrase mSignaturePassphrase = null;
protected long mAdditionalEncryptId = Constants.key.none;
- protected byte[] mNfcSignedHash = null;
- protected Date mNfcCreationTimestamp = null;
protected boolean mFailOnMissingEncryptionKeyIds = false;
protected String mCharset;
protected boolean mCleartextSignature;
protected boolean mDetachedSignature = false;
protected boolean mHiddenRecipients = false;
+ public PgpSignEncryptInputParcel() {
+
+ }
+
+ PgpSignEncryptInputParcel(Parcel source) {
+
+ ClassLoader loader = getClass().getClassLoader();
+
+ // we do all of those here, so the PgpSignEncryptInput class doesn't have to be parcelable
+ mVersionHeader = source.readString();
+ mEnableAsciiArmorOutput = source.readInt() == 1;
+ mCompressionId = source.readInt();
+ mEncryptionMasterKeyIds = source.createLongArray();
+ mSymmetricPassphrase = source.readParcelable(loader);
+ mSymmetricEncryptionAlgorithm = source.readInt();
+ mSignatureMasterKeyId = source.readLong();
+ mSignatureSubKeyId = source.readInt() == 1 ? source.readLong() : null;
+ mSignatureHashAlgorithm = source.readInt();
+ mAdditionalEncryptId = source.readLong();
+ mFailOnMissingEncryptionKeyIds = source.readInt() == 1;
+ mCharset = source.readString();
+ mCleartextSignature = source.readInt() == 1;
+ mDetachedSignature = source.readInt() == 1;
+ mHiddenRecipients = source.readInt() == 1;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mVersionHeader);
+ dest.writeInt(mEnableAsciiArmorOutput ? 1 : 0);
+ dest.writeInt(mCompressionId);
+ dest.writeLongArray(mEncryptionMasterKeyIds);
+ dest.writeParcelable(mSymmetricPassphrase, 0);
+ dest.writeInt(mSymmetricEncryptionAlgorithm);
+ dest.writeLong(mSignatureMasterKeyId);
+ if (mSignatureSubKeyId != null) {
+ dest.writeInt(1);
+ dest.writeLong(mSignatureSubKeyId);
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeInt(mSignatureHashAlgorithm);
+ dest.writeLong(mAdditionalEncryptId);
+ dest.writeInt(mFailOnMissingEncryptionKeyIds ? 1 : 0);
+ dest.writeString(mCharset);
+ dest.writeInt(mCleartextSignature ? 1 : 0);
+ dest.writeInt(mDetachedSignature ? 1 : 0);
+ dest.writeInt(mHiddenRecipients ? 1 : 0);
+ }
+
public String getCharset() {
return mCharset;
}
@@ -57,37 +116,20 @@ public class PgpSignEncryptInput {
return mFailOnMissingEncryptionKeyIds;
}
- public Date getNfcCreationTimestamp() {
- return mNfcCreationTimestamp;
- }
-
- public byte[] getNfcSignedHash() {
- return mNfcSignedHash;
- }
-
public long getAdditionalEncryptId() {
return mAdditionalEncryptId;
}
- public PgpSignEncryptInput setAdditionalEncryptId(long additionalEncryptId) {
+ public PgpSignEncryptInputParcel setAdditionalEncryptId(long additionalEncryptId) {
mAdditionalEncryptId = additionalEncryptId;
return this;
}
- public Passphrase getSignaturePassphrase() {
- return mSignaturePassphrase;
- }
-
- public PgpSignEncryptInput setSignaturePassphrase(Passphrase signaturePassphrase) {
- mSignaturePassphrase = signaturePassphrase;
- return this;
- }
-
public int getSignatureHashAlgorithm() {
return mSignatureHashAlgorithm;
}
- public PgpSignEncryptInput setSignatureHashAlgorithm(int signatureHashAlgorithm) {
+ public PgpSignEncryptInputParcel setSignatureHashAlgorithm(int signatureHashAlgorithm) {
mSignatureHashAlgorithm = signatureHashAlgorithm;
return this;
}
@@ -96,7 +138,7 @@ public class PgpSignEncryptInput {
return mSignatureSubKeyId;
}
- public PgpSignEncryptInput setSignatureSubKeyId(long signatureSubKeyId) {
+ public PgpSignEncryptInputParcel setSignatureSubKeyId(long signatureSubKeyId) {
mSignatureSubKeyId = signatureSubKeyId;
return this;
}
@@ -105,7 +147,7 @@ public class PgpSignEncryptInput {
return mSignatureMasterKeyId;
}
- public PgpSignEncryptInput setSignatureMasterKeyId(long signatureMasterKeyId) {
+ public PgpSignEncryptInputParcel setSignatureMasterKeyId(long signatureMasterKeyId) {
mSignatureMasterKeyId = signatureMasterKeyId;
return this;
}
@@ -114,7 +156,7 @@ public class PgpSignEncryptInput {
return mSymmetricEncryptionAlgorithm;
}
- public PgpSignEncryptInput setSymmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm) {
+ public PgpSignEncryptInputParcel setSymmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm) {
mSymmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm;
return this;
}
@@ -123,7 +165,7 @@ public class PgpSignEncryptInput {
return mSymmetricPassphrase;
}
- public PgpSignEncryptInput setSymmetricPassphrase(Passphrase symmetricPassphrase) {
+ public PgpSignEncryptInputParcel setSymmetricPassphrase(Passphrase symmetricPassphrase) {
mSymmetricPassphrase = symmetricPassphrase;
return this;
}
@@ -132,7 +174,7 @@ public class PgpSignEncryptInput {
return mEncryptionMasterKeyIds;
}
- public PgpSignEncryptInput setEncryptionMasterKeyIds(long[] encryptionMasterKeyIds) {
+ public PgpSignEncryptInputParcel setEncryptionMasterKeyIds(long[] encryptionMasterKeyIds) {
mEncryptionMasterKeyIds = encryptionMasterKeyIds;
return this;
}
@@ -141,7 +183,7 @@ public class PgpSignEncryptInput {
return mCompressionId;
}
- public PgpSignEncryptInput setCompressionId(int compressionId) {
+ public PgpSignEncryptInputParcel setCompressionId(int compressionId) {
mCompressionId = compressionId;
return this;
}
@@ -154,28 +196,22 @@ public class PgpSignEncryptInput {
return mVersionHeader;
}
- public PgpSignEncryptInput setVersionHeader(String versionHeader) {
+ public PgpSignEncryptInputParcel setVersionHeader(String versionHeader) {
mVersionHeader = versionHeader;
return this;
}
- public PgpSignEncryptInput setEnableAsciiArmorOutput(boolean enableAsciiArmorOutput) {
+ public PgpSignEncryptInputParcel setEnableAsciiArmorOutput(boolean enableAsciiArmorOutput) {
mEnableAsciiArmorOutput = enableAsciiArmorOutput;
return this;
}
- public PgpSignEncryptInput setFailOnMissingEncryptionKeyIds(boolean failOnMissingEncryptionKeyIds) {
+ public PgpSignEncryptInputParcel setFailOnMissingEncryptionKeyIds(boolean failOnMissingEncryptionKeyIds) {
mFailOnMissingEncryptionKeyIds = failOnMissingEncryptionKeyIds;
return this;
}
- public PgpSignEncryptInput setNfcState(byte[] signedHash, Date creationTimestamp) {
- mNfcSignedHash = signedHash;
- mNfcCreationTimestamp = creationTimestamp;
- return this;
- }
-
- public PgpSignEncryptInput setCleartextSignature(boolean cleartextSignature) {
+ public PgpSignEncryptInputParcel setCleartextSignature(boolean cleartextSignature) {
this.mCleartextSignature = cleartextSignature;
return this;
}
@@ -184,7 +220,7 @@ public class PgpSignEncryptInput {
return mCleartextSignature;
}
- public PgpSignEncryptInput setDetachedSignature(boolean detachedSignature) {
+ public PgpSignEncryptInputParcel setDetachedSignature(boolean detachedSignature) {
this.mDetachedSignature = detachedSignature;
return this;
}
@@ -193,7 +229,7 @@ public class PgpSignEncryptInput {
return mDetachedSignature;
}
- public PgpSignEncryptInput setHiddenRecipients(boolean hiddenRecipients) {
+ public PgpSignEncryptInputParcel setHiddenRecipients(boolean hiddenRecipients) {
this.mHiddenRecipients = hiddenRecipients;
return this;
}
@@ -201,5 +237,16 @@ public class PgpSignEncryptInput {
public boolean isHiddenRecipients() {
return mHiddenRecipients;
}
+
+ public static final Creator<PgpSignEncryptInputParcel> CREATOR = new Creator<PgpSignEncryptInputParcel>() {
+ public PgpSignEncryptInputParcel createFromParcel(final Parcel source) {
+ return new PgpSignEncryptInputParcel(source);
+ }
+
+ public PgpSignEncryptInputParcel[] newArray(final int size) {
+ return new PgpSignEncryptInputParcel[size];
+ }
+ };
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java
index 16a09e77b..8ecb30cdd 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java
@@ -33,7 +33,6 @@ import org.spongycastle.openpgp.PGPSignatureGenerator;
import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator;
import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder;
-import org.spongycastle.util.encoders.Hex;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.BaseOperation;
@@ -44,11 +43,15 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.ProgressScaler;
+import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -72,7 +75,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* <p/>
* For a high-level operation based on URIs, see SignEncryptOperation.
*
- * @see org.sufficientlysecure.keychain.pgp.PgpSignEncryptInput
+ * @see PgpSignEncryptInputParcel
* @see org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult
* @see org.sufficientlysecure.keychain.operations.SignEncryptOperation
*/
@@ -99,8 +102,8 @@ public class PgpSignEncryptOperation extends BaseOperation {
/**
* Signs and/or encrypts data based on parameters of class
*/
- public PgpSignEncryptResult execute(PgpSignEncryptInput input,
- InputData inputData, OutputStream outputStream) {
+ public PgpSignEncryptResult execute(PgpSignEncryptInputParcel input, CryptoInputParcel cryptoInput,
+ InputData inputData, OutputStream outputStream) {
int indent = 0;
OperationLog log = new OperationLog();
@@ -128,7 +131,7 @@ public class PgpSignEncryptOperation extends BaseOperation {
ArmoredOutputStream armorOut = null;
OutputStream out;
if (input.isEnableAsciiArmorOutput()) {
- armorOut = new ArmoredOutputStream(outputStream);
+ armorOut = new ArmoredOutputStream(new BufferedOutputStream(outputStream, 1 << 16));
if (input.getVersionHeader() != null) {
armorOut.setHeader("Version", input.getVersionHeader());
}
@@ -145,62 +148,62 @@ public class PgpSignEncryptOperation extends BaseOperation {
CanonicalizedSecretKey signingKey = null;
if (enableSignature) {
+ updateProgress(R.string.progress_extracting_signature_key, 0, 100);
+
try {
// fetch the indicated master key id (the one whose name we sign in)
CanonicalizedSecretKeyRing signingKeyRing =
mProviderHelper.getCanonicalizedSecretKeyRing(input.getSignatureMasterKeyId());
- long signKeyId;
- // use specified signing subkey, or find the one to use
- if (input.getSignatureSubKeyId() == null) {
- signKeyId = signingKeyRing.getSecretSignId();
- } else {
- signKeyId = input.getSignatureSubKeyId();
- }
-
// fetch the specific subkey to sign with, or just use the master key if none specified
- signingKey = signingKeyRing.getSecretKey(signKeyId);
+ signingKey = signingKeyRing.getSecretKey(input.getSignatureSubKeyId());
- } catch (ProviderHelper.NotFoundException | PgpGeneralException e) {
- log.add(LogType.MSG_PSE_ERROR_SIGN_KEY, indent);
- return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
- }
-
- // Make sure we are allowed to sign here!
- if (!signingKey.canSign()) {
- log.add(LogType.MSG_PSE_ERROR_KEY_SIGN, indent);
- return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
- }
-
- // if no passphrase was explicitly set try to get it from the cache service
- if (input.getSignaturePassphrase() == null) {
- try {
- // returns "" if key has no passphrase
- input.setSignaturePassphrase(getCachedPassphrase(signingKey.getKeyId()));
- // TODO
-// log.add(LogType.MSG_DC_PASS_CACHED, indent + 1);
- } catch (PassphraseCacheInterface.NoSecretKeyException e) {
- // TODO
-// log.add(LogType.MSG_DC_ERROR_NO_KEY, indent + 1);
+ // Make sure we are allowed to sign here!
+ if (!signingKey.canSign()) {
+ log.add(LogType.MSG_PSE_ERROR_KEY_SIGN, indent);
return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
}
- // if passphrase was not cached, return here indicating that a passphrase is missing!
- if (input.getSignaturePassphrase() == null) {
- log.add(LogType.MSG_PSE_PENDING_PASSPHRASE, indent + 1);
- PgpSignEncryptResult result = new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE, log);
- result.setKeyIdPassphraseNeeded(signingKey.getKeyId());
- return result;
- }
- }
+ switch (signingKey.getSecretKeyType()) {
+ case DIVERT_TO_CARD:
+ case PASSPHRASE_EMPTY: {
+ if (!signingKey.unlock(new Passphrase())) {
+ throw new AssertionError(
+ "PASSPHRASE_EMPTY/DIVERT_TO_CARD keyphrase not unlocked with empty passphrase."
+ + " This is a programming error!");
+ }
+ break;
+ }
- updateProgress(R.string.progress_extracting_signature_key, 0, 100);
+ case PIN:
+ case PATTERN:
+ case PASSPHRASE: {
+ if (cryptoInput.getPassphrase() == null) {
+ log.add(LogType.MSG_PSE_PENDING_PASSPHRASE, indent + 1);
+ return new PgpSignEncryptResult(log, RequiredInputParcel.createRequiredSignPassphrase(
+ signingKeyRing.getMasterKeyId(), signingKey.getKeyId(),
+ cryptoInput.getSignatureTime()));
+ }
+ if (!signingKey.unlock(cryptoInput.getPassphrase())) {
+ log.add(LogType.MSG_PSE_ERROR_BAD_PASSPHRASE, indent);
+ return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
+ }
+ break;
+ }
+
+ case GNU_DUMMY: {
+ log.add(LogType.MSG_PSE_ERROR_UNLOCK, indent);
+ return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
+ }
+ default: {
+ throw new AssertionError("Unhandled SecretKeyType! (should not happen)");
+ }
- try {
- if (!signingKey.unlock(input.getSignaturePassphrase())) {
- log.add(LogType.MSG_PSE_ERROR_BAD_PASSPHRASE, indent);
- return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
}
+
+ } catch (ProviderHelper.NotFoundException e) {
+ log.add(LogType.MSG_PSE_ERROR_SIGN_KEY, indent);
+ return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
} catch (PgpGeneralException e) {
log.add(LogType.MSG_PSE_ERROR_UNLOCK, indent);
return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
@@ -281,8 +284,9 @@ public class PgpSignEncryptOperation extends BaseOperation {
try {
boolean cleartext = input.isCleartextSignature() && input.isEnableAsciiArmorOutput() && !enableEncryption;
- signatureGenerator = signingKey.getSignatureGenerator(
- input.getSignatureHashAlgorithm(), cleartext, input.getNfcSignedHash(), input.getNfcCreationTimestamp());
+ signatureGenerator = signingKey.getDataSignatureGenerator(
+ input.getSignatureHashAlgorithm(), cleartext,
+ cryptoInput.getCryptoData(), cryptoInput.getSignatureTime());
} catch (PgpGeneralException e) {
log.add(LogType.MSG_PSE_ERROR_NFC, indent);
return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
@@ -405,7 +409,7 @@ public class PgpSignEncryptOperation extends BaseOperation {
detachedByteOut = new ByteArrayOutputStream();
OutputStream detachedOut = detachedByteOut;
if (input.isEnableAsciiArmorOutput()) {
- detachedArmorOut = new ArmoredOutputStream(detachedOut);
+ detachedArmorOut = new ArmoredOutputStream(new BufferedOutputStream(detachedOut, 1 << 16));
if (input.getVersionHeader() != null) {
detachedArmorOut.setHeader("Version", input.getVersionHeader());
}
@@ -485,19 +489,8 @@ public class PgpSignEncryptOperation extends BaseOperation {
} catch (NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded e) {
// this secret key diverts to a OpenPGP card, throw exception with hash that will be signed
log.add(LogType.MSG_PSE_PENDING_NFC, indent);
- PgpSignEncryptResult result =
- new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_PENDING_NFC, log);
-
- // SignatureSubKeyId can be null.
- if (input.getSignatureSubKeyId() == null) {
- return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
- }
-
- // Note that the checked key here is the master key, not the signing key
- // (although these are always the same on Yubikeys)
- result.setNfcData(input.getSignatureSubKeyId(), e.hashToSign, e.hashAlgo, e.creationTimestamp, input.getSignaturePassphrase());
- Log.d(Constants.TAG, "e.hashToSign" + Hex.toHexString(e.hashToSign));
- return result;
+ return new PgpSignEncryptResult(log, RequiredInputParcel.createNfcSignOperation(
+ e.hashToSign, e.hashAlgo, cryptoInput.getSignatureTime()));
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java
index 975548c95..464de37f5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java
@@ -20,14 +20,10 @@ package org.sufficientlysecure.keychain.pgp;
import android.net.Uri;
import android.os.Parcel;
-import android.os.Parcelable;
-
-import org.sufficientlysecure.keychain.util.Passphrase;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.Date;
import java.util.List;
/** This parcel stores the input of one or more PgpSignEncrypt operations.
@@ -42,7 +38,7 @@ import java.util.List;
* left, which will be returned in a byte array as part of the result parcel.
*
*/
-public class SignEncryptParcel extends PgpSignEncryptInput implements Parcelable {
+public class SignEncryptParcel extends PgpSignEncryptInputParcel {
public ArrayList<Uri> mInputUris = new ArrayList<>();
public ArrayList<Uri> mOutputUris = new ArrayList<>();
@@ -53,26 +49,7 @@ public class SignEncryptParcel extends PgpSignEncryptInput implements Parcelable
}
public SignEncryptParcel(Parcel src) {
-
- // we do all of those here, so the PgpSignEncryptInput class doesn't have to be parcelable
- mVersionHeader = src.readString();
- mEnableAsciiArmorOutput = src.readInt() == 1;
- mCompressionId = src.readInt();
- mEncryptionMasterKeyIds = src.createLongArray();
- mSymmetricPassphrase = src.readParcelable(Passphrase.class.getClassLoader());
- mSymmetricEncryptionAlgorithm = src.readInt();
- mSignatureMasterKeyId = src.readLong();
- mSignatureSubKeyId = src.readInt() == 1 ? src.readLong() : null;
- mSignatureHashAlgorithm = src.readInt();
- mSignaturePassphrase = src.readParcelable(Passphrase.class.getClassLoader());
- mAdditionalEncryptId = src.readLong();
- mNfcSignedHash = src.createByteArray();
- mNfcCreationTimestamp = src.readInt() == 1 ? new Date(src.readLong()) : null;
- mFailOnMissingEncryptionKeyIds = src.readInt() == 1;
- mCharset = src.readString();
- mCleartextSignature = src.readInt() == 1;
- mDetachedSignature = src.readInt() == 1;
- mHiddenRecipients = src.readInt() == 1;
+ super(src);
mInputUris = src.createTypedArrayList(Uri.CREATOR);
mOutputUris = src.createTypedArrayList(Uri.CREATOR);
@@ -110,34 +87,7 @@ public class SignEncryptParcel extends PgpSignEncryptInput implements Parcelable
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mVersionHeader);
- dest.writeInt(mEnableAsciiArmorOutput ? 1 : 0);
- dest.writeInt(mCompressionId);
- dest.writeLongArray(mEncryptionMasterKeyIds);
- dest.writeParcelable(mSymmetricPassphrase, flags);
- dest.writeInt(mSymmetricEncryptionAlgorithm);
- dest.writeLong(mSignatureMasterKeyId);
- if (mSignatureSubKeyId != null) {
- dest.writeInt(1);
- dest.writeLong(mSignatureSubKeyId);
- } else {
- dest.writeInt(0);
- }
- dest.writeInt(mSignatureHashAlgorithm);
- dest.writeParcelable(mSignaturePassphrase, flags);
- dest.writeLong(mAdditionalEncryptId);
- dest.writeByteArray(mNfcSignedHash);
- if (mNfcCreationTimestamp != null) {
- dest.writeInt(1);
- dest.writeLong(mNfcCreationTimestamp.getTime());
- } else {
- dest.writeInt(0);
- }
- dest.writeInt(mFailOnMissingEncryptionKeyIds ? 1 : 0);
- dest.writeString(mCharset);
- dest.writeInt(mCleartextSignature ? 1 : 0);
- dest.writeInt(mDetachedSignature ? 1 : 0);
- dest.writeInt(mHiddenRecipients ? 1 : 0);
+ super.writeToParcel(dest, flags);
dest.writeTypedList(mInputUris);
dest.writeTypedList(mOutputUris);
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 681aff56d..b86618a9a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -1165,7 +1165,7 @@ public class UncachedKeyRing {
}
}
- // If anything changed, save the updated (sub)key
+ // If anything change, save the updated (sub)key
if (modified != resultKey) {
result = replacePublicKey(result, modified);
}