summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDamien Caliste <dcaliste@free.fr>2023-08-25 15:14:44 +0200
committerDamien Caliste <dcaliste@free.fr>2024-04-10 18:03:00 +0200
commita78a3cc8748757949b1c81d4d12595f75fa97aa7 (patch)
tree8c77519990e4768ec3d4125ec72cd31cc1641b1b
parent539b06d0890c872e48632dd03f48f99710f32990 (diff)
Implement decryptionHEADmaster
Add decryption interface to the crypto service and implement it for PGP keys via gpgme. Change-Id: Ib74fe36a4af69fe788bf1841ba5621ec0f3d593e Reviewed-by: Pekka Vuorela <pvuorela@iki.fi>
-rw-r--r--src/libraries/qmfclient/qmailcrypto.cpp44
-rw-r--r--src/libraries/qmfclient/qmailcrypto.h8
-rw-r--r--src/libraries/qmfclient/qmailcryptofwd.h17
-rw-r--r--src/plugins/crypto/common/qgpgme.cpp49
-rw-r--r--src/plugins/crypto/common/qgpgme.h3
-rw-r--r--src/plugins/crypto/gpgme/gpgmeplugin.cpp48
-rw-r--r--src/plugins/crypto/gpgme/gpgmeplugin.h3
-rw-r--r--src/plugins/crypto/smime/smimeplugin.cpp12
-rw-r--r--src/plugins/crypto/smime/smimeplugin.h3
9 files changed, 187 insertions, 0 deletions
diff --git a/src/libraries/qmfclient/qmailcrypto.cpp b/src/libraries/qmfclient/qmailcrypto.cpp
index ec468e91..fd15f215 100644
--- a/src/libraries/qmfclient/qmailcrypto.cpp
+++ b/src/libraries/qmfclient/qmailcrypto.cpp
@@ -113,6 +113,19 @@ QMailCryptographicServiceInterface* QMailCryptographicService::instance(const QS
return qobject_cast<QMailCryptographicServiceInterface*>(QMailPluginManager::instance(engine));
}
+QMailCryptographicServiceInterface* QMailCryptographicService::decryptionEngine(const QMailMessagePartContainer &part)
+{
+ if (part.isEncrypted()) {
+ QStringList engines = list();
+ for (QStringList::iterator it = engines.begin(); it != engines.end(); it++) {
+ QMailCryptographicServiceInterface *engine = instance(*it);
+ if (engine && engine->canDecrypt(part))
+ return engine;
+ }
+ }
+ return Q_NULLPTR;
+}
+
QMailMessagePartContainer* QMailCryptographicService::findSignedContainer(QMailMessagePartContainer *part, QMailCryptographicServiceInterface **engine)
{
QMailCryptographicService *plugins =
@@ -190,3 +203,34 @@ QMailCryptoFwd::SignatureResult QMailCryptographicService::sign(QMailMessagePart
return QMailCryptoFwd::BadSignature;
}
+
+bool QMailCryptographicService::canDecrypt(const QMailMessagePartContainer &part)
+{
+ return instance()->decryptionEngine(part) != Q_NULLPTR;
+}
+
+QMailCryptoFwd::DecryptionResult QMailCryptographicService::decrypt(QMailMessagePartContainer *part,
+ QMailCryptoFwd::PassphraseCallback cb)
+{
+ if (!part || !part->isEncrypted()) {
+ return QMailCryptoFwd::DecryptionResult(QMailCryptoFwd::NoDigitalEncryption);
+ }
+
+ QMailCryptographicServiceInterface *engine = instance()->decryptionEngine(*part);
+ if (engine) {
+ engine->setPassphraseCallback(cb);
+ QMailCryptoFwd::DecryptionResult result = engine->decrypt(part);
+ if (result.status == QMailCryptoFwd::Decrypted) {
+ QMailMessage* message = dynamic_cast<QMailMessage*>(part);
+ if (message && message->hasAttachments()) {
+ message->setStatus(QMailMessage::HasAttachments, true);
+ }
+ if (message && findSignedContainer(part)) {
+ message->setStatus(QMailMessage::HasSignature, true);
+ }
+ }
+ return result;
+ } else {
+ return QMailCryptoFwd::DecryptionResult(QMailCryptoFwd::UnsupportedProtocol);
+ }
+}
diff --git a/src/libraries/qmfclient/qmailcrypto.h b/src/libraries/qmfclient/qmailcrypto.h
index ca44632c..e0d6a439 100644
--- a/src/libraries/qmfclient/qmailcrypto.h
+++ b/src/libraries/qmfclient/qmailcrypto.h
@@ -51,6 +51,9 @@ public:
virtual QMailCryptoFwd::SignatureResult sign(QMailMessagePartContainer *part,
const QStringList &keys) const = 0;
+ virtual bool canDecrypt(const QMailMessagePartContainer &part) const = 0;
+ virtual QMailCryptoFwd::DecryptionResult decrypt(QMailMessagePartContainer *part) const = 0;
+
virtual void setPassphraseCallback(QMailCryptoFwd::PassphraseCallback cb) = 0;
virtual QString passphraseCallback(const QString &info) const = 0;
@@ -71,6 +74,7 @@ public:
static const QMailMessagePartContainer* findSignedContainer(const QMailMessagePartContainer *part, QMailCryptographicServiceInterface **engine = Q_NULLPTR);
QMailCryptographicServiceInterface* instance(const QString &engine);
+ QMailCryptographicServiceInterface* decryptionEngine(const QMailMessagePartContainer &part);
static QMailCryptoFwd::VerificationResult verifySignature(const QMailMessagePartContainer &part);
static QMailCryptoFwd::SignatureResult sign(QMailMessagePartContainer *part,
@@ -78,6 +82,10 @@ public:
const QStringList &keys,
QMailCryptoFwd::PassphraseCallback cb = Q_NULLPTR);
+ static bool canDecrypt(const QMailMessagePartContainer &part);
+ static QMailCryptoFwd::DecryptionResult decrypt(QMailMessagePartContainer *part,
+ QMailCryptoFwd::PassphraseCallback cb = Q_NULLPTR);
+
private:
QMailCryptographicService(QObject *parent = Q_NULLPTR);
~QMailCryptographicService();
diff --git a/src/libraries/qmfclient/qmailcryptofwd.h b/src/libraries/qmfclient/qmailcryptofwd.h
index f9369cf6..cacc1d31 100644
--- a/src/libraries/qmfclient/qmailcryptofwd.h
+++ b/src/libraries/qmfclient/qmailcryptofwd.h
@@ -56,6 +56,13 @@ public:
UnusableKey,
UnknownError
};
+ enum CryptResult {
+ NoDigitalEncryption,
+ Decrypted,
+ WrongPassphrase,
+ UnsupportedProtocol,
+ UnknownCryptError
+ };
typedef QString (*PassphraseCallback)(const QString &info);
struct QMF_EXPORT KeyResult {
@@ -81,6 +88,16 @@ public:
{
}
};
+
+ struct QMF_EXPORT DecryptionResult {
+ QString engine;
+ CryptResult status;
+
+ DecryptionResult(CryptResult result = UnknownCryptError)
+ : status(result)
+ {
+ }
+ };
};
#endif
diff --git a/src/plugins/crypto/common/qgpgme.cpp b/src/plugins/crypto/common/qgpgme.cpp
index 1d9ff598..e4a603a2 100644
--- a/src/plugins/crypto/common/qgpgme.cpp
+++ b/src/plugins/crypto/common/qgpgme.cpp
@@ -426,3 +426,52 @@ QMailCryptoFwd::SignatureResult QMailCryptoGPGME::verify(const QByteArray &sigDa
return toSignatureResult(err);
}
+
+static QMailCryptoFwd::CryptResult toCryptResult(gpgme_error_t err)
+{
+ switch (gpgme_err_code(err)) {
+ case GPG_ERR_NO_ERROR:
+ return QMailCryptoFwd::Decrypted;
+ case GPG_ERR_BAD_PASSPHRASE:
+ return QMailCryptoFwd::WrongPassphrase;
+ case GPG_ERR_DECRYPT_FAILED:
+ case GPG_ERR_NO_DATA:
+ case GPG_ERR_INV_VALUE:
+ case GPG_ERR_NO_PUBKEY:
+ return QMailCryptoFwd::NoDigitalEncryption;
+ default:
+ return QMailCryptoFwd::UnknownCryptError;
+ }
+}
+
+QMailCryptoFwd::CryptResult QMailCryptoGPGME::decrypt(const QByteArray &encData,
+ QByteArray &decData) const
+{
+ GPGmeContext ctx(m_protocol);
+ if (!ctx) {
+ qWarning() << "cannot create context:" << ctx.errorMessage();
+ return toCryptResult(ctx.err);
+ }
+
+ GPGmeData enc(encData);
+ if (!enc.isValid()) {
+ qWarning() << "cannot create encoded data:" << enc.errorMessage();
+ return toCryptResult(enc.err);
+ }
+
+ GPGmeData dec;
+ if (!dec.isValid()) {
+ qWarning() << "cannot create decoded data:" << dec.errorMessage();
+ return toCryptResult(dec.err);
+ }
+
+ gpgme_error_t err;
+ err = gpgme_op_decrypt(ctx, enc, dec);
+ if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
+ qWarning() << "decryption fails:" << gpgme_strerror(err);
+ return toCryptResult(err);
+ }
+ decData = dec.releaseData();
+
+ return QMailCryptoFwd::Decrypted;
+}
diff --git a/src/plugins/crypto/common/qgpgme.h b/src/plugins/crypto/common/qgpgme.h
index d7ae77f5..da781777 100644
--- a/src/plugins/crypto/common/qgpgme.h
+++ b/src/plugins/crypto/common/qgpgme.h
@@ -68,6 +68,9 @@ class QMailCryptoGPGME: public QObject,
const QByteArray &messageData,
QList<QMailCryptoFwd::KeyResult> &keyResults) const;
+ QMailCryptoFwd::CryptResult decrypt(const QByteArray &encData,
+ QByteArray &decData) const;
+
private:
QMailCryptoFwd::SignatureResult getSignature(const QByteArray &message,
const QStringList &keys,
diff --git a/src/plugins/crypto/gpgme/gpgmeplugin.cpp b/src/plugins/crypto/gpgme/gpgmeplugin.cpp
index 1cfd4436..5fcce0ea 100644
--- a/src/plugins/crypto/gpgme/gpgmeplugin.cpp
+++ b/src/plugins/crypto/gpgme/gpgmeplugin.cpp
@@ -103,3 +103,51 @@ QMailCryptoFwd::SignatureResult QMailCryptoGPG::sign(QMailMessagePartContainer *
return QMailCryptoFwd::SignatureValid;
}
+
+bool QMailCryptoGPG::canDecrypt(const QMailMessagePartContainer &part) const
+{
+ if (part.isEncrypted()) {
+ const QMailMessagePart &control = part.partAt(0);
+ if (control.contentType().matches("application", "pgp-encrypted")
+ && control.hasBody()) {
+ return control.body().data().startsWith(QString::fromLatin1("Version: 1"));
+ }
+ }
+ return false;
+}
+
+QMailCryptoFwd::DecryptionResult QMailCryptoGPG::decrypt(QMailMessagePartContainer *part) const
+{
+ if (!part) {
+ qWarning() << "unable to decrypt a NULL part.";
+ return QMailCryptoFwd::DecryptionResult();
+ }
+
+ if (!canDecrypt(*part))
+ return QMailCryptoFwd::DecryptionResult(QMailCryptoFwd::UnsupportedProtocol);
+
+ const QMailMessagePart &body = part->partAt(1);
+
+ if (!body.contentAvailable())
+ return QMailCryptoFwd::DecryptionResult();
+
+ QByteArray decData;
+ QMailCryptoFwd::DecryptionResult result;
+ result.engine = QStringLiteral("libgpgme.so");
+ result.status = QMailCryptoGPGME::decrypt(body.body().data(QMailMessageBodyFwd::Decoded), decData);
+ if (result.status == QMailCryptoFwd::Decrypted) {
+ const QMailMessage mail = QMailMessage::fromRfc2822(decData);
+
+ part->clearParts();
+ if (mail.partCount() > 0) {
+ part->setMultipartType(mail.multipartType(),
+ mail.contentType().parameters());
+ for (uint i = 0; i < mail.partCount(); i++) {
+ part->appendPart(mail.partAt(i));
+ }
+ } else {
+ part->setBody(mail.body());
+ }
+ }
+ return result;
+}
diff --git a/src/plugins/crypto/gpgme/gpgmeplugin.h b/src/plugins/crypto/gpgme/gpgmeplugin.h
index bd491335..68d4d250 100644
--- a/src/plugins/crypto/gpgme/gpgmeplugin.h
+++ b/src/plugins/crypto/gpgme/gpgmeplugin.h
@@ -52,6 +52,9 @@ public:
bool partHasSignature(const QMailMessagePartContainer &part) const Q_DECL_OVERRIDE;
QMailCryptoFwd::VerificationResult verifySignature(const QMailMessagePartContainer &part) const Q_DECL_OVERRIDE;
QMailCryptoFwd::SignatureResult sign(QMailMessagePartContainer *part, const QStringList &keys) const Q_DECL_OVERRIDE;
+
+ bool canDecrypt(const QMailMessagePartContainer &part) const Q_DECL_OVERRIDE;
+ QMailCryptoFwd::DecryptionResult decrypt(QMailMessagePartContainer *part) const Q_DECL_OVERRIDE;
};
#endif
diff --git a/src/plugins/crypto/smime/smimeplugin.cpp b/src/plugins/crypto/smime/smimeplugin.cpp
index 80257145..b68cd282 100644
--- a/src/plugins/crypto/smime/smimeplugin.cpp
+++ b/src/plugins/crypto/smime/smimeplugin.cpp
@@ -106,3 +106,15 @@ QMailCryptoFwd::SignatureResult QMailCryptoSMIME::sign(QMailMessagePartContainer
return QMailCryptoFwd::SignatureValid;
}
+
+bool QMailCryptoSMIME::canDecrypt(const QMailMessagePartContainer &part) const
+{
+ Q_UNUSED(part);
+ return false;
+}
+
+QMailCryptoFwd::DecryptionResult QMailCryptoSMIME::decrypt(QMailMessagePartContainer *part) const
+{
+ Q_UNUSED(part);
+ return QMailCryptoFwd::DecryptionResult(QMailCryptoFwd::UnsupportedProtocol);
+}
diff --git a/src/plugins/crypto/smime/smimeplugin.h b/src/plugins/crypto/smime/smimeplugin.h
index 341d37f7..540008c4 100644
--- a/src/plugins/crypto/smime/smimeplugin.h
+++ b/src/plugins/crypto/smime/smimeplugin.h
@@ -53,6 +53,9 @@ public:
QMailCryptoFwd::VerificationResult verifySignature(const QMailMessagePartContainer &part) const Q_DECL_OVERRIDE;
QMailCryptoFwd::SignatureResult sign(QMailMessagePartContainer *part,
const QStringList &keys) const Q_DECL_OVERRIDE;
+
+ bool canDecrypt(const QMailMessagePartContainer &part) const Q_DECL_OVERRIDE;
+ QMailCryptoFwd::DecryptionResult decrypt(QMailMessagePartContainer *part) const Q_DECL_OVERRIDE;
};
#endif