Fix decryption of messages/files encrypted for multiple public keys

This commit is contained in:
Dominik Schürmann 2014-04-08 23:01:38 +02:00
parent a1efb24228
commit d81de8509b

View File

@ -200,7 +200,7 @@ public class PgpDecryptVerify {
*/ */
private PgpDecryptVerifyResult decryptVerify(InputStream in) private PgpDecryptVerifyResult decryptVerify(InputStream in)
throws IOException, PgpGeneralException, PGPException, SignatureException { throws IOException, PgpGeneralException, PGPException, SignatureException {
PgpDecryptVerifyResult returnData = new PgpDecryptVerifyResult(); PgpDecryptVerifyResult result = new PgpDecryptVerifyResult();
PGPObjectFactory pgpF = new PGPObjectFactory(in); PGPObjectFactory pgpF = new PGPObjectFactory(in);
PGPEncryptedDataList enc; PGPEncryptedDataList enc;
@ -228,6 +228,7 @@ public class PgpDecryptVerify {
PGPPBEEncryptedData encryptedDataSymmetric = null; PGPPBEEncryptedData encryptedDataSymmetric = null;
PGPSecretKey secretKey = null; PGPSecretKey secretKey = null;
Iterator<?> it = enc.getEncryptedDataObjects(); Iterator<?> it = enc.getEncryptedDataObjects();
boolean asymmetricPacketFound = false;
boolean symmetricPacketFound = false; boolean symmetricPacketFound = false;
// find secret key // find secret key
while (it.hasNext()) { while (it.hasNext()) {
@ -245,18 +246,22 @@ public class PgpDecryptVerify {
); );
} catch (ProviderHelper.NotFoundException e) { } catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e); Log.e(Constants.TAG, "key not found!", e);
// continue with the next packet in the while loop
continue;
} }
// get actual keyring object based on master key id // get actual keyring object based on master key id
PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRing(mContext, masterKeyId); PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRing(mContext, masterKeyId);
if (secretKeyRing == null) { if (secretKeyRing == null) {
throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found)); // continue with the next packet in the while loop
continue;
} }
secretKey = secretKeyRing.getSecretKey(encData.getKeyID()); secretKey = secretKeyRing.getSecretKey(encData.getKeyID());
if (secretKey == null) { if (secretKey == null) {
throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found)); // continue with the next packet in the while loop
continue;
} }
// secret key exists in database
/* secret key exists in database! */
// allow only a specific key for decryption? // allow only a specific key for decryption?
if (mAllowedKeyIds != null) { if (mAllowedKeyIds != null) {
@ -265,11 +270,15 @@ public class PgpDecryptVerify {
Log.d(Constants.TAG, "masterKeyId: " + masterKeyId); Log.d(Constants.TAG, "masterKeyId: " + masterKeyId);
if (!mAllowedKeyIds.contains(masterKeyId)) { if (!mAllowedKeyIds.contains(masterKeyId)) {
throw new PgpGeneralException( // this key is in our db, but NOT allowed!
mContext.getString(R.string.error_no_secret_key_found)); // continue with the next packet in the while loop
continue;
} }
} }
/* secret key exists in database and is allowed! */
asymmetricPacketFound = true;
encryptedDataAsymmetric = encData; encryptedDataAsymmetric = encData;
// if no passphrase was explicitly set try to get it from the cache service // if no passphrase was explicitly set try to get it from the cache service
@ -281,16 +290,20 @@ public class PgpDecryptVerify {
// if passphrase was not cached, return here // if passphrase was not cached, return here
// indicating that a passphrase is missing! // indicating that a passphrase is missing!
if (mPassphrase == null) { if (mPassphrase == null) {
returnData.setKeyIdPassphraseNeeded(masterKeyId); result.setKeyIdPassphraseNeeded(masterKeyId);
returnData.setStatus(PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED); result.setStatus(PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED);
return returnData; return result;
} }
} }
// break out of while, only get first object here // break out of while, only decrypt the first packet where we have a key
// TODO???: There could be more pgp objects, which are not decrypted! // TODO???: There could be more pgp objects, which are not decrypted!
break; break;
} else if (mAllowSymmetricDecryption && obj instanceof PGPPBEEncryptedData) { } else if (mAllowSymmetricDecryption && obj instanceof PGPPBEEncryptedData) {
/*
* When mAllowSymmetricDecryption == true and we find a data packet here,
* we do not search for other available asymmetric packets!
*/
symmetricPacketFound = true; symmetricPacketFound = true;
encryptedDataSymmetric = (PGPPBEEncryptedData) obj; encryptedDataSymmetric = (PGPPBEEncryptedData) obj;
@ -298,11 +311,11 @@ public class PgpDecryptVerify {
// if no passphrase is given, return here // if no passphrase is given, return here
// indicating that a passphrase is missing! // indicating that a passphrase is missing!
if (mPassphrase == null) { if (mPassphrase == null) {
returnData.setStatus(PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED); result.setStatus(PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED);
return returnData; return result;
} }
// break out of while, only get first object here // break out of while, only decrypt the first packet
// TODO???: There could be more pgp objects, which are not decrypted! // TODO???: There could be more pgp objects, which are not decrypted!
break; break;
} }
@ -321,11 +334,7 @@ public class PgpDecryptVerify {
encryptedData = encryptedDataSymmetric; encryptedData = encryptedDataSymmetric;
currentProgress += 5; currentProgress += 5;
} else { } else if (asymmetricPacketFound) {
if (secretKey == null) {
throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found));
}
currentProgress += 5; currentProgress += 5;
updateProgress(R.string.progress_extracting_key, currentProgress, 100); updateProgress(R.string.progress_extracting_key, currentProgress, 100);
PGPPrivateKey privateKey; PGPPrivateKey privateKey;
@ -351,6 +360,9 @@ public class PgpDecryptVerify {
encryptedData = encryptedDataAsymmetric; encryptedData = encryptedDataAsymmetric;
currentProgress += 5; currentProgress += 5;
} else {
// no packet has been found where we have the corresponding secret key in our db
throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found));
} }
PGPObjectFactory plainFact = new PGPObjectFactory(clear); PGPObjectFactory plainFact = new PGPObjectFactory(clear);
@ -379,7 +391,7 @@ public class PgpDecryptVerify {
for (int i = 0; i < sigList.size(); ++i) { for (int i = 0; i < sigList.size(); ++i) {
signature = sigList.get(i); signature = sigList.get(i);
signatureKey = ProviderHelper signatureKey = ProviderHelper
.getPGPPublicKeyRing(mContext, signature.getKeyID()).getPublicKey(); .getPGPPublicKeyRingWithKeyId(mContext, signature.getKeyID()).getPublicKey();
if (signatureKeyId == 0) { if (signatureKeyId == 0) {
signatureKeyId = signature.getKeyID(); signatureKeyId = signature.getKeyID();
} }
@ -408,6 +420,7 @@ public class PgpDecryptVerify {
signature.init(contentVerifierBuilderProvider, signatureKey); signature.init(contentVerifierBuilderProvider, signatureKey);
} else { } else {
Log.d(Constants.TAG, "SIGNATURE_UNKNOWN_PUB_KEY");
signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY); signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY);
} }
@ -446,6 +459,7 @@ public class PgpDecryptVerify {
try { try {
signature.update(buffer, 0, n); signature.update(buffer, 0, n);
} catch (SignatureException e) { } catch (SignatureException e) {
Log.d(Constants.TAG, "SIGNATURE_ERROR");
signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR); signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR);
signature = null; signature = null;
} }
@ -479,7 +493,12 @@ public class PgpDecryptVerify {
// TODO: implement CERTIFIED! // TODO: implement CERTIFIED!
if (validKeyBinding & validSignature) { if (validKeyBinding & validSignature) {
Log.d(Constants.TAG, "SIGNATURE_SUCCESS_UNCERTIFIED");
signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED); signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED);
} else {
signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR);
Log.e(Constants.TAG, "Error!\nvalidKeyBinding: " + validKeyBinding
+ "\nvalidSignature: " + validSignature);
} }
} }
} }
@ -503,8 +522,8 @@ public class PgpDecryptVerify {
updateProgress(R.string.progress_done, 100, 100); updateProgress(R.string.progress_done, 100, 100);
returnData.setSignatureResult(signatureResult); result.setSignatureResult(signatureResult);
return returnData; return result;
} }
/** /**
@ -522,7 +541,7 @@ public class PgpDecryptVerify {
*/ */
private PgpDecryptVerifyResult verifyCleartextSignature(ArmoredInputStream aIn) private PgpDecryptVerifyResult verifyCleartextSignature(ArmoredInputStream aIn)
throws IOException, PgpGeneralException, PGPException, SignatureException { throws IOException, PgpGeneralException, PGPException, SignatureException {
PgpDecryptVerifyResult returnData = new PgpDecryptVerifyResult(); PgpDecryptVerifyResult result = new PgpDecryptVerifyResult();
OpenPgpSignatureResult signatureResult = new OpenPgpSignatureResult(); OpenPgpSignatureResult signatureResult = new OpenPgpSignatureResult();
// cleartext signatures are never encrypted ;) // cleartext signatures are never encrypted ;)
signatureResult.setSignatureOnly(true); signatureResult.setSignatureOnly(true);
@ -569,10 +588,10 @@ public class PgpDecryptVerify {
// find data about this subkey // find data about this subkey
HashMap<String, Object> data = ProviderHelper.getGenericData(mContext, HashMap<String, Object> data = ProviderHelper.getGenericData(mContext,
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(signature.getKeyID())), KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(signature.getKeyID())),
new String[] { KeyRings.MASTER_KEY_ID, KeyRings.USER_ID }, new String[]{KeyRings.MASTER_KEY_ID, KeyRings.USER_ID},
new int[] { ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_STRING }); new int[]{ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_STRING});
// any luck? otherwise, try next. // any luck? otherwise, try next.
if(data.get(KeyRings.MASTER_KEY_ID) == null) { if (data.get(KeyRings.MASTER_KEY_ID) == null) {
signature = null; signature = null;
// do NOT reset signatureKeyId, that one is shown when no known one is found! // do NOT reset signatureKeyId, that one is shown when no known one is found!
continue; continue;
@ -588,11 +607,12 @@ public class PgpDecryptVerify {
signatureResult.setKeyId(signatureKeyId); signatureResult.setKeyId(signatureKeyId);
if (signature == null) { if (signature == null) {
Log.d(Constants.TAG, "SIGNATURE_UNKNOWN_PUB_KEY");
signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY); signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY);
returnData.setSignatureResult(signatureResult); result.setSignatureResult(signatureResult);
updateProgress(R.string.progress_done, 100, 100); updateProgress(R.string.progress_done, 100, 100);
return returnData; return result;
} }
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
@ -622,16 +642,21 @@ public class PgpDecryptVerify {
boolean validKeyBinding = verifyKeyBinding(mContext, signature, signatureKey); boolean validKeyBinding = verifyKeyBinding(mContext, signature, signatureKey);
boolean validSignature = signature.verify(); boolean validSignature = signature.verify();
if (validSignature & validKeyBinding) { if (validKeyBinding & validSignature) {
Log.d(Constants.TAG, "SIGNATURE_SUCCESS_UNCERTIFIED");
signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED); signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED);
} else {
signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR);
Log.e(Constants.TAG, "Error!\nvalidKeyBinding: " + validKeyBinding
+ "\nvalidSignature: " + validSignature);
} }
// TODO: what about SIGNATURE_SUCCESS_CERTIFIED and SIGNATURE_ERROR???? // TODO: what about SIGNATURE_SUCCESS_CERTIFIED and SIGNATURE_ERROR????
returnData.setSignatureResult(signatureResult); result.setSignatureResult(signatureResult);
updateProgress(R.string.progress_done, 100, 100); updateProgress(R.string.progress_done, 100, 100);
return returnData; return result;
} }
private static boolean verifyKeyBinding(Context context, private static boolean verifyKeyBinding(Context context,