aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2015-10-08 18:02:17 +0200
committerVincent Breitmoser <valodim@mugenguild.com>2015-10-08 18:02:17 +0200
commitd6076a998c729737fe6b96b74123e9e1af0a5a50 (patch)
tree9880f624aa1b68ce49f6b21eec8f7af56214b916 /OpenKeychain/src/main/java/org/sufficientlysecure/keychain
parente9fa8916067f4cb07cb39df20ac83a09a97afb83 (diff)
downloadopen-keychain-d6076a998c729737fe6b96b74123e9e1af0a5a50.tar.gz
open-keychain-d6076a998c729737fe6b96b74123e9e1af0a5a50.tar.bz2
open-keychain-d6076a998c729737fe6b96b74123e9e1af0a5a50.zip
pgpdecryptverify: externalize PgpSignatureChecker
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java330
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignatureChecker.java336
2 files changed, 369 insertions, 297 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
index 888869994..f31b6af59 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
@@ -18,6 +18,17 @@
package org.sufficientlysecure.keychain.pgp;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.SignatureException;
+import java.util.Date;
+import java.util.Iterator;
+
import android.content.Context;
import android.support.annotation.NonNull;
import android.webkit.MimeTypeMap;
@@ -33,18 +44,14 @@ import org.spongycastle.openpgp.PGPEncryptedDataList;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPKeyValidationException;
import org.spongycastle.openpgp.PGPLiteralData;
-import org.spongycastle.openpgp.PGPOnePassSignature;
-import org.spongycastle.openpgp.PGPOnePassSignatureList;
import org.spongycastle.openpgp.PGPPBEEncryptedData;
import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
-import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureList;
import org.spongycastle.openpgp.PGPUtil;
import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory;
import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory;
import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider;
import org.spongycastle.openpgp.operator.jcajce.CachingDataDecryptorFactory;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
import org.spongycastle.util.encoders.DecoderException;
@@ -68,17 +75,6 @@ import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.ProgressScaler;
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.security.SignatureException;
-import java.util.Date;
-import java.util.Iterator;
-
public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInputParcel> {
public PgpDecryptVerifyOperation(Context context, ProviderHelper providerHelper, Progressable progressable) {
@@ -207,7 +203,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
updateProgress(R.string.progress_decompressing_data, 80, 100);
}
- SignatureChecker signatureChecker = new SignatureChecker();
+ PgpSignatureChecker signatureChecker = new PgpSignatureChecker(mProviderHelper);
if ( ! signatureChecker.initializeOnePassSignature(o, log, indent)) {
log.add(LogType.MSG_VL_ERROR_MISSING_SIGLIST, indent);
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
@@ -392,7 +388,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
plainFact = fact;
}
- SignatureChecker signatureChecker = new SignatureChecker();
+ PgpSignatureChecker signatureChecker = new PgpSignatureChecker(mProviderHelper);
if (signatureChecker.initializeOnePassSignature(dataChunk, log, indent +1)) {
dataChunk = plainFact.nextObject();
}
@@ -558,13 +554,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
private EncryptStreamResult handleEncryptedPacket(PgpDecryptVerifyInputParcel input, CryptoInputParcel cryptoInput,
PGPEncryptedDataList enc, OperationLog log, int indent, int currentProgress) throws PGPException {
- // TODO is this necessary?
- /*
- else if (obj instanceof PGPEncryptedDataList) {
- enc = (PGPEncryptedDataList) pgpF.nextObject();
- }
- */
-
EncryptStreamResult result = new EncryptStreamResult();
boolean asymmetricPacketFound = false;
@@ -835,28 +824,31 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
OperationLog log = new OperationLog();
- ByteArrayOutputStream out = new ByteArrayOutputStream();
+ byte[] clearText;
+ { // read cleartext
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
- updateProgress(R.string.progress_reading_data, 0, 100);
+ updateProgress(R.string.progress_reading_data, 0, 100);
- ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
- int lookAhead = readInputLine(lineOut, aIn);
- byte[] lineSep = getLineSeparator();
+ ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
+ int lookAhead = readInputLine(lineOut, aIn);
+ byte[] lineSep = getLineSeparator();
- byte[] line = lineOut.toByteArray();
- out.write(line, 0, getLengthWithoutSeparator(line));
- out.write(lineSep);
-
- while (lookAhead != -1 && aIn.isClearText()) {
- lookAhead = readInputLine(lineOut, lookAhead, aIn);
- line = lineOut.toByteArray();
+ byte[] line = lineOut.toByteArray();
out.write(line, 0, getLengthWithoutSeparator(line));
out.write(lineSep);
- }
- out.close();
+ while (lookAhead != -1 && aIn.isClearText()) {
+ lookAhead = readInputLine(lineOut, lookAhead, aIn);
+ line = lineOut.toByteArray();
+ out.write(line, 0, getLengthWithoutSeparator(line));
+ out.write(lineSep);
+ }
+
+ out.close();
+ clearText = out.toByteArray();
+ }
- byte[] clearText = out.toByteArray();
if (outputStream != null) {
outputStream.write(clearText);
outputStream.close();
@@ -865,7 +857,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
updateProgress(R.string.progress_processing_signature, 60, 100);
JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(aIn);
- SignatureChecker signatureChecker = new SignatureChecker();
+ PgpSignatureChecker signatureChecker = new PgpSignatureChecker(mProviderHelper);
Object o = pgpFact.nextObject();
if (!signatureChecker.initializeSignature(o, log, indent+1)) {
@@ -924,7 +916,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
o = pgpFact.nextObject();
}
- SignatureChecker signatureChecker = new SignatureChecker();
+ PgpSignatureChecker signatureChecker = new PgpSignatureChecker(mProviderHelper);
if ( ! signatureChecker.initializeSignature(o, log, indent+1)) {
log.add(LogType.MSG_DC_ERROR_INVALID_DATA, 0);
@@ -958,7 +950,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
}
progressScaler.setProgress((int) progress, 100);
}
- // TODO: slow annealing to fake a progress?
}
updateProgress(R.string.progress_verifying_signature, 90, 100);
@@ -979,17 +970,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
return result;
}
- /**
- * Mostly taken from ClearSignedFileProcessor in Bouncy Castle
- */
- private static void processLine(PGPSignature sig, byte[] line)
- throws SignatureException {
- int length = getLengthWithoutWhiteSpace(line);
- if (length > 0) {
- sig.update(line, 0, length);
- }
- }
-
private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn)
throws IOException {
bOut.reset();
@@ -1055,253 +1035,9 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
return b == '\r' || b == '\n';
}
- private static int getLengthWithoutWhiteSpace(byte[] line) {
- int end = line.length - 1;
-
- while (end >= 0 && isWhiteSpace(line[end])) {
- end--;
- }
-
- return end + 1;
- }
-
- private static boolean isWhiteSpace(byte b) {
- return b == '\r' || b == '\n' || b == '\t' || b == ' ';
- }
-
private static byte[] getLineSeparator() {
String nl = System.getProperty("line.separator");
return nl.getBytes();
}
- private class SignatureChecker {
-
- OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
-
- private CanonicalizedPublicKey signingKey;
- // we use the signatureIndex instead of the signature itself here for two reasons:
- // 1) the signature may be either of type PGPSignature or PGPOnePassSignature (which have no common ancestor)
- // 2) in case of the latter, we need the signatureIndex to know which PGPSignature to use later on
- private int signatureIndex;
-
- PGPOnePassSignature onePassSignature;
- PGPSignature signature;
-
- ProviderHelper mProviderHelper;
-
- boolean initializeSignature(Object dataChunk, OperationLog log, int indent) throws PGPException {
-
- if ( ! (dataChunk instanceof PGPSignatureList) ) {
- return false;
- }
-
- PGPSignatureList sigList = (PGPSignatureList) dataChunk;
- findAvailableSignature(sigList);
-
- if (signingKey != null) {
-
- // key found in our database!
- signatureResultBuilder.initValid(signingKey);
-
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
- new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey());
- checkKeySecurity(log, indent);
-
-
- } else if (!sigList.isEmpty()) {
-
- signatureResultBuilder.setSignatureAvailable(true);
- signatureResultBuilder.setKnownKey(false);
- signatureResultBuilder.setKeyId(sigList.get(0).getKeyID());
-
- }
-
- return true;
-
- }
-
- boolean initializeOnePassSignature(Object dataChunk, OperationLog log, int indent) throws PGPException {
-
- if ( ! (dataChunk instanceof PGPOnePassSignatureList) ) {
- return false;
- }
-
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE, indent + 1);
-
- PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
- findAvailableSignature(sigList);
-
- if (signingKey != null) {
-
- // key found in our database!
- signatureResultBuilder.initValid(signingKey);
-
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
- new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- onePassSignature.init(contentVerifierBuilderProvider, signingKey.getPublicKey());
-
- checkKeySecurity(log, indent);
-
- } else if (!sigList.isEmpty()) {
-
- signatureResultBuilder.setSignatureAvailable(true);
- signatureResultBuilder.setKnownKey(false);
- signatureResultBuilder.setKeyId(sigList.get(0).getKeyID());
-
- }
-
- return true;
-
- }
-
- private void checkKeySecurity(OperationLog log, int indent) {
- // TODO: checks on signingRing ?
- if ( ! PgpSecurityConstants.isSecureKey(signingKey)) {
- log.add(LogType.MSG_DC_INSECURE_KEY, indent + 1);
- signatureResultBuilder.setInsecure(true);
- }
- }
-
- public boolean isInitialized() {
- return signingKey != null;
- }
-
- private void findAvailableSignature(PGPOnePassSignatureList sigList) {
- // go through all signatures (should be just one), make sure we have
- // the key and it matches the one we’re looking for
- for (int i = 0; i < sigList.size(); ++i) {
- try {
- long sigKeyId = sigList.get(i).getKeyID();
- CanonicalizedPublicKeyRing signingRing = mProviderHelper.getCanonicalizedPublicKeyRing(
- KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
- );
- signatureIndex = i;
- signingKey = signingRing.getPublicKey(sigKeyId);
- onePassSignature = sigList.get(i);
- return;
- } catch (ProviderHelper.NotFoundException e) {
- Log.d(Constants.TAG, "key not found, trying next signature...");
- }
- }
- }
-
- public void findAvailableSignature(PGPSignatureList sigList) {
- // go through all signatures (should be just one), make sure we have
- // the key and it matches the one we’re looking for
- for (int i = 0; i < sigList.size(); ++i) {
- try {
- long sigKeyId = sigList.get(i).getKeyID();
- CanonicalizedPublicKeyRing signingRing = mProviderHelper.getCanonicalizedPublicKeyRing(
- KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
- );
- signatureIndex = i;
- signingKey = signingRing.getPublicKey(sigKeyId);
- signature = sigList.get(i);
- return;
- } catch (ProviderHelper.NotFoundException e) {
- Log.d(Constants.TAG, "key not found, trying next signature...");
- }
- }
- }
-
- public void updateSignatureWithCleartext(byte[] clearText) throws IOException, SignatureException {
-
- InputStream sigIn = new BufferedInputStream(new ByteArrayInputStream(clearText));
-
- ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream();
-
- int lookAhead = readInputLine(outputBuffer, sigIn);
-
- processLine(signature, outputBuffer.toByteArray());
-
- if (lookAhead != -1) {
- do {
- lookAhead = readInputLine(outputBuffer, lookAhead, sigIn);
-
- signature.update((byte) '\r');
- signature.update((byte) '\n');
-
- processLine(signature, outputBuffer.toByteArray());
- } while (lookAhead != -1);
- }
-
- }
-
- public void updateSignatureData(byte[] buf, int off, int len) {
- if (onePassSignature != null) {
- onePassSignature.update(buf, off, len);
- }
- }
-
- void verifySignature(OperationLog log, int indent) throws PGPException {
-
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_CHECK, indent);
-
- // Verify signature
- boolean validSignature = signature.verify();
- if (validSignature) {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1);
- } else {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1);
- }
-
- // check for insecure hash algorithms
- if (!PgpSecurityConstants.isSecureHashAlgorithm(onePassSignature.getHashAlgorithm())) {
- log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1);
- signatureResultBuilder.setInsecure(true);
- }
-
- signatureResultBuilder.setValidSignature(validSignature);
-
- }
-
- boolean verifySignatureOnePass(Object o, OperationLog log, int indent) throws PGPException {
-
- if ( ! (o instanceof PGPSignatureList) ) {
- log.add(LogType.MSG_DC_ERROR_NO_SIGNATURE, indent);
- return false;
- }
- PGPSignatureList signatureList = (PGPSignatureList) o;
- if (signatureList.size() <= signatureIndex) {
- log.add(LogType.MSG_DC_ERROR_NO_SIGNATURE, indent);
- return false;
- }
-
- // PGPOnePassSignature and PGPSignature packets are "bracketed",
- // so we need to take the last-minus-index'th element here
- PGPSignature messageSignature = signatureList.get(signatureList.size() -1 - signatureIndex);
-
- // Verify signature
- boolean validSignature = onePassSignature.verify(messageSignature);
- if (validSignature) {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1);
- } else {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1);
- }
-
- // check for insecure hash algorithms
- if (!PgpSecurityConstants.isSecureHashAlgorithm(onePassSignature.getHashAlgorithm())) {
- log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1);
- signatureResultBuilder.setInsecure(true);
- }
-
- signatureResultBuilder.setValidSignature(validSignature);
-
- return true;
-
- }
-
- public byte[] getSigningFingerprint() {
- return signingKey.getFingerprint();
- }
-
- public OpenPgpSignatureResult getSignatureResult() {
- return signatureResultBuilder.build();
- }
-
- }
-
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignatureChecker.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignatureChecker.java
new file mode 100644
index 000000000..2fccf2197
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignatureChecker.java
@@ -0,0 +1,336 @@
+package org.sufficientlysecure.keychain.pgp;
+
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.SignatureException;
+
+import org.openintents.openpgp.OpenPgpSignatureResult;
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPOnePassSignature;
+import org.spongycastle.openpgp.PGPOnePassSignatureList;
+import org.spongycastle.openpgp.PGPSignature;
+import org.spongycastle.openpgp.PGPSignatureList;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
+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.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.util.Log;
+
+
+/** This class is used to track the state of a single signature verification.
+ *
+ *
+ */
+class PgpSignatureChecker {
+
+ OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
+
+ private CanonicalizedPublicKey signingKey;
+
+ private int signatureIndex;
+ PGPOnePassSignature onePassSignature;
+ PGPSignature signature;
+
+ ProviderHelper mProviderHelper;
+
+ PgpSignatureChecker(ProviderHelper providerHelper) {
+ mProviderHelper = providerHelper;
+ }
+
+ boolean initializeSignature(Object dataChunk, OperationLog log, int indent) throws PGPException {
+
+ if (!(dataChunk instanceof PGPSignatureList)) {
+ return false;
+ }
+
+ PGPSignatureList sigList = (PGPSignatureList) dataChunk;
+ findAvailableSignature(sigList);
+
+ if (signingKey != null) {
+
+ // key found in our database!
+ signatureResultBuilder.initValid(signingKey);
+
+ JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
+ new JcaPGPContentVerifierBuilderProvider()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey());
+ checkKeySecurity(log, indent);
+
+
+ } else if (!sigList.isEmpty()) {
+
+ signatureResultBuilder.setSignatureAvailable(true);
+ signatureResultBuilder.setKnownKey(false);
+ signatureResultBuilder.setKeyId(sigList.get(0).getKeyID());
+
+ }
+
+ return true;
+
+ }
+
+ boolean initializeOnePassSignature(Object dataChunk, OperationLog log, int indent) throws PGPException {
+
+ if (!(dataChunk instanceof PGPOnePassSignatureList)) {
+ return false;
+ }
+
+ log.add(LogType.MSG_DC_CLEAR_SIGNATURE, indent + 1);
+
+ PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
+ findAvailableSignature(sigList);
+
+ if (signingKey != null) {
+
+ // key found in our database!
+ signatureResultBuilder.initValid(signingKey);
+
+ JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
+ new JcaPGPContentVerifierBuilderProvider()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ onePassSignature.init(contentVerifierBuilderProvider, signingKey.getPublicKey());
+
+ checkKeySecurity(log, indent);
+
+ } else if (!sigList.isEmpty()) {
+
+ signatureResultBuilder.setSignatureAvailable(true);
+ signatureResultBuilder.setKnownKey(false);
+ signatureResultBuilder.setKeyId(sigList.get(0).getKeyID());
+
+ }
+
+ return true;
+
+ }
+
+ private void checkKeySecurity(OperationLog log, int indent) {
+ // TODO: checks on signingRing ?
+ if (!PgpSecurityConstants.isSecureKey(signingKey)) {
+ log.add(LogType.MSG_DC_INSECURE_KEY, indent + 1);
+ signatureResultBuilder.setInsecure(true);
+ }
+ }
+
+ public boolean isInitialized() {
+ return signingKey != null;
+ }
+
+ private void findAvailableSignature(PGPOnePassSignatureList sigList) {
+ // go through all signatures (should be just one), make sure we have
+ // the key and it matches the one we’re looking for
+ for (int i = 0; i < sigList.size(); ++i) {
+ try {
+ long sigKeyId = sigList.get(i).getKeyID();
+ CanonicalizedPublicKeyRing signingRing = mProviderHelper.getCanonicalizedPublicKeyRing(
+ KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
+ );
+ signatureIndex = i;
+ signingKey = signingRing.getPublicKey(sigKeyId);
+ onePassSignature = sigList.get(i);
+ return;
+ } catch (ProviderHelper.NotFoundException e) {
+ Log.d(Constants.TAG, "key not found, trying next signature...");
+ }
+ }
+ }
+
+ public void findAvailableSignature(PGPSignatureList sigList) {
+ // go through all signatures (should be just one), make sure we have
+ // the key and it matches the one we’re looking for
+ for (int i = 0; i < sigList.size(); ++i) {
+ try {
+ long sigKeyId = sigList.get(i).getKeyID();
+ CanonicalizedPublicKeyRing signingRing = mProviderHelper.getCanonicalizedPublicKeyRing(
+ KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
+ );
+ signatureIndex = i;
+ signingKey = signingRing.getPublicKey(sigKeyId);
+ signature = sigList.get(i);
+ return;
+ } catch (ProviderHelper.NotFoundException e) {
+ Log.d(Constants.TAG, "key not found, trying next signature...");
+ }
+ }
+ }
+
+ public void updateSignatureWithCleartext(byte[] clearText) throws IOException, SignatureException {
+
+ InputStream sigIn = new BufferedInputStream(new ByteArrayInputStream(clearText));
+
+ ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream();
+
+ int lookAhead = readInputLine(outputBuffer, sigIn);
+
+ processLine(signature, outputBuffer.toByteArray());
+
+ while (lookAhead != -1) {
+ lookAhead = readInputLine(outputBuffer, lookAhead, sigIn);
+
+ signature.update((byte) '\r');
+ signature.update((byte) '\n');
+
+ processLine(signature, outputBuffer.toByteArray());
+ }
+
+ }
+
+ public void updateSignatureData(byte[] buf, int off, int len) {
+ if (signature != null) {
+ signature.update(buf, off, len);
+ } else if (onePassSignature != null) {
+ onePassSignature.update(buf, off, len);
+ }
+ }
+
+ void verifySignature(OperationLog log, int indent) throws PGPException {
+
+ log.add(LogType.MSG_DC_CLEAR_SIGNATURE_CHECK, indent);
+
+ // Verify signature
+ boolean validSignature = signature.verify();
+ if (validSignature) {
+ log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1);
+ } else {
+ log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1);
+ }
+
+ // check for insecure hash algorithms
+ if (!PgpSecurityConstants.isSecureHashAlgorithm(onePassSignature.getHashAlgorithm())) {
+ log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1);
+ signatureResultBuilder.setInsecure(true);
+ }
+
+ signatureResultBuilder.setValidSignature(validSignature);
+
+ }
+
+ boolean verifySignatureOnePass(Object o, OperationLog log, int indent) throws PGPException {
+
+ if (!(o instanceof PGPSignatureList)) {
+ log.add(LogType.MSG_DC_ERROR_NO_SIGNATURE, indent);
+ return false;
+ }
+ PGPSignatureList signatureList = (PGPSignatureList) o;
+ if (signatureList.size() <= signatureIndex) {
+ log.add(LogType.MSG_DC_ERROR_NO_SIGNATURE, indent);
+ return false;
+ }
+
+ // PGPOnePassSignature and PGPSignature packets are "bracketed",
+ // so we need to take the last-minus-index'th element here
+ PGPSignature messageSignature = signatureList.get(signatureList.size() - 1 - signatureIndex);
+
+ // Verify signature
+ boolean validSignature = onePassSignature.verify(messageSignature);
+ if (validSignature) {
+ log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1);
+ } else {
+ log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1);
+ }
+
+ // check for insecure hash algorithms
+ if (!PgpSecurityConstants.isSecureHashAlgorithm(onePassSignature.getHashAlgorithm())) {
+ log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1);
+ signatureResultBuilder.setInsecure(true);
+ }
+
+ signatureResultBuilder.setValidSignature(validSignature);
+
+ return true;
+
+ }
+
+ public byte[] getSigningFingerprint() {
+ return signingKey.getFingerprint();
+ }
+
+ public OpenPgpSignatureResult getSignatureResult() {
+ return signatureResultBuilder.build();
+ }
+
+ /**
+ * Mostly taken from ClearSignedFileProcessor in Bouncy Castle
+ */
+
+ private static void processLine(PGPSignature sig, byte[] line)
+ throws SignatureException {
+ int length = getLengthWithoutWhiteSpace(line);
+ if (length > 0) {
+ sig.update(line, 0, length);
+ }
+ }
+
+ private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn)
+ throws IOException {
+ bOut.reset();
+
+ int lookAhead = -1;
+ int ch;
+
+ while ((ch = fIn.read()) >= 0) {
+ bOut.write(ch);
+ if (ch == '\r' || ch == '\n') {
+ lookAhead = readPastEOL(bOut, ch, fIn);
+ break;
+ }
+ }
+
+ return lookAhead;
+ }
+
+ private static int readInputLine(ByteArrayOutputStream bOut, int lookAhead, InputStream fIn)
+ throws IOException {
+ bOut.reset();
+
+ int ch = lookAhead;
+
+ do {
+ bOut.write(ch);
+ if (ch == '\r' || ch == '\n') {
+ lookAhead = readPastEOL(bOut, ch, fIn);
+ break;
+ }
+ } while ((ch = fIn.read()) >= 0);
+
+ if (ch < 0) {
+ lookAhead = -1;
+ }
+
+ return lookAhead;
+ }
+
+ private static int readPastEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn)
+ throws IOException {
+ int lookAhead = fIn.read();
+
+ if (lastCh == '\r' && lookAhead == '\n') {
+ bOut.write(lookAhead);
+ lookAhead = fIn.read();
+ }
+
+ return lookAhead;
+ }
+
+ private static int getLengthWithoutWhiteSpace(byte[] line) {
+ int end = line.length - 1;
+
+ while (end >= 0 && isWhiteSpace(line[end])) {
+ end--;
+ }
+
+ return end + 1;
+ }
+
+ private static boolean isWhiteSpace(byte b) {
+ return b == '\r' || b == '\n' || b == '\t' || b == ' ';
+ }
+
+}