diff options
author | Damien Caliste <dcaliste@free.fr> | 2023-08-25 15:14:44 +0200 |
---|---|---|
committer | Damien Caliste <dcaliste@free.fr> | 2024-04-10 18:03:00 +0200 |
commit | a78a3cc8748757949b1c81d4d12595f75fa97aa7 (patch) | |
tree | 8c77519990e4768ec3d4125ec72cd31cc1641b1b | |
parent | 539b06d0890c872e48632dd03f48f99710f32990 (diff) |
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.cpp | 44 | ||||
-rw-r--r-- | src/libraries/qmfclient/qmailcrypto.h | 8 | ||||
-rw-r--r-- | src/libraries/qmfclient/qmailcryptofwd.h | 17 | ||||
-rw-r--r-- | src/plugins/crypto/common/qgpgme.cpp | 49 | ||||
-rw-r--r-- | src/plugins/crypto/common/qgpgme.h | 3 | ||||
-rw-r--r-- | src/plugins/crypto/gpgme/gpgmeplugin.cpp | 48 | ||||
-rw-r--r-- | src/plugins/crypto/gpgme/gpgmeplugin.h | 3 | ||||
-rw-r--r-- | src/plugins/crypto/smime/smimeplugin.cpp | 12 | ||||
-rw-r--r-- | src/plugins/crypto/smime/smimeplugin.h | 3 |
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 |