spelling: fix misspellings
[gpgme.git] / lang / qt / tests / t-encrypt.cpp
1 /* t-encrypt.cpp
2
3     This file is part of qgpgme, the Qt API binding for gpgme
4     Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik
5     Software engineering by Intevation GmbH
6
7     QGpgME is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License as
9     published by the Free Software Foundation; either version 2 of the
10     License, or (at your option) any later version.
11
12     QGpgME is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20
21     In addition, as a special exception, the copyright holders give
22     permission to link the code of this program with any edition of
23     the Qt library by Trolltech AS, Norway (or with modified versions
24     of Qt that use the same license as Qt), and distribute linked
25     combinations including the two.  You must obey the GNU General
26     Public License in all respects for all of the code used other than
27     Qt.  If you modify this file, you may extend this exception to
28     your version of the file, but you are not obligated to do so.  If
29     you do not wish to do so, delete this exception statement from
30     your version.
31 */
32 #ifdef HAVE_CONFIG_H
33  #include "config.h"
34 #endif
35
36 #include <QDebug>
37 #include <QTest>
38 #include <QTemporaryDir>
39 #include <QSignalSpy>
40 #include <QBuffer>
41 #include "keylistjob.h"
42 #include "encryptjob.h"
43 #include "signencryptjob.h"
44 #include "signingresult.h"
45 #include "encryptjob.h"
46 #include "encryptionresult.h"
47 #include "decryptionresult.h"
48 #include "decryptjob.h"
49 #include "qgpgmebackend.h"
50 #include "keylistresult.h"
51 #include "engineinfo.h"
52 #include "verifyopaquejob.h"
53 #include "t-support.h"
54
55 #define PROGRESS_TEST_SIZE 1 * 1024 * 1024
56
57 using namespace QGpgME;
58 using namespace GpgME;
59
60 static bool decryptSupported()
61 {
62     /* With GnuPG 2.0.x (at least 2.0.26 by default on jessie)
63      * the passphrase_cb does not work. So the test popped up
64      * a pinentry. So tests requiring decryption don't work. */
65     static auto version = GpgME::engineInfo(GpgME::GpgEngine).engineVersion();
66     if (version < "2.0.0") {
67         /* With 1.4 it just works */
68         return true;
69     }
70     if (version < "2.1.0") {
71         /* With 2.1 it works with loopback mode */
72         return false;
73     }
74     return true;
75 }
76
77 class EncryptionTest : public QGpgMETest
78 {
79     Q_OBJECT
80
81 Q_SIGNALS:
82     void asyncDone();
83
84 private Q_SLOTS:
85
86     void testSimpleEncryptDecrypt()
87     {
88         auto listjob = openpgp()->keyListJob(false, false, false);
89         std::vector<Key> keys;
90         auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
91                                           false, keys);
92         QVERIFY(!keylistresult.error());
93         QVERIFY(keys.size() == 1);
94         delete listjob;
95
96         auto job = openpgp()->encryptJob(/*ASCII Armor */true, /* Textmode */ true);
97         QVERIFY(job);
98         QByteArray cipherText;
99         auto result = job->exec(keys, QStringLiteral("Hello World").toUtf8(), Context::AlwaysTrust, cipherText);
100         delete job;
101         QVERIFY(!result.error());
102         const auto cipherString = QString::fromUtf8(cipherText);
103         QVERIFY(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
104
105         /* Now decrypt */
106         if (!decryptSupported()) {
107             return;
108         }
109         auto decJob = openpgp()->decryptJob();
110         auto ctx = Job::context(decJob);
111         TestPassphraseProvider provider;
112         ctx->setPassphraseProvider(&provider);
113         ctx->setPinentryMode(Context::PinentryLoopback);
114         QByteArray plainText;
115         auto decResult = decJob->exec(cipherText, plainText);
116         QVERIFY(!decResult.error());
117         QVERIFY(QString::fromUtf8(plainText) == QStringLiteral("Hello World"));
118         delete decJob;
119     }
120
121     void testProgress()
122     {
123         if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.15") {
124             // We can only test the progress with 2.1.15 as this started to
125             // have total progress for memory callbacks
126             return;
127         }
128         auto listjob = openpgp()->keyListJob(false, false, false);
129         std::vector<Key> keys;
130         auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
131                                           false, keys);
132         QVERIFY(!keylistresult.error());
133         QVERIFY(keys.size() == 1);
134         delete listjob;
135
136         auto job = openpgp()->encryptJob(/*ASCII Armor */false, /* Textmode */ false);
137         QVERIFY(job);
138         QByteArray plainBa;
139         plainBa.fill('X', PROGRESS_TEST_SIZE);
140         QByteArray cipherText;
141
142         bool initSeen = false;
143         bool finishSeen = false;
144         connect(job, &Job::progress, this, [this, &initSeen, &finishSeen] (const QString&, int current, int total) {
145                 // We only check for progress 0 and max progress as the other progress
146                 // lines depend on the system speed and are as such unreliable to test.
147                 QVERIFY(total == PROGRESS_TEST_SIZE);
148                 if (current == 0) {
149                     initSeen = true;
150                 }
151                 if (current == total) {
152                     finishSeen = true;
153                 }
154                 QVERIFY(current >= 0 && current <= total);
155             });
156         connect(job, &EncryptJob::result, this, [this, &initSeen, &finishSeen] (const GpgME::EncryptionResult &,
157                                                                                 const QByteArray &,
158                                                                                 const QString,
159                                                                                 const GpgME::Error) {
160                 QVERIFY(initSeen);
161                 QVERIFY(finishSeen);
162                 Q_EMIT asyncDone();
163             });
164
165         auto inptr  = std::shared_ptr<QIODevice>(new QBuffer(&plainBa));
166         inptr->open(QIODevice::ReadOnly);
167         auto outptr = std::shared_ptr<QIODevice>(new QBuffer(&cipherText));
168         outptr->open(QIODevice::WriteOnly);
169
170         job->start(keys, inptr, outptr, Context::AlwaysTrust);
171         QSignalSpy spy (this, SIGNAL(asyncDone()));
172         QVERIFY(spy.wait(QSIGNALSPY_TIMEOUT));
173     }
174
175     void testSymmetricEncryptDecrypt()
176     {
177         if (!decryptSupported()) {
178             return;
179         }
180         auto job = openpgp()->encryptJob();
181         auto ctx = Job::context(job);
182         TestPassphraseProvider provider;
183         ctx->setPassphraseProvider(&provider);
184         ctx->setPinentryMode(Context::PinentryLoopback);
185         ctx->setArmor(true);
186         ctx->setTextMode(true);
187         QByteArray cipherText;
188         auto result = job->exec(std::vector<Key>(), QStringLiteral("Hello symmetric World").toUtf8(), Context::AlwaysTrust, cipherText);
189         delete job;
190         QVERIFY(!result.error());
191         const auto cipherString = QString::fromUtf8(cipherText);
192         QVERIFY(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
193
194         killAgent(mDir.path());
195
196         auto decJob = openpgp()->decryptJob();
197         auto ctx2 = Job::context(decJob);
198         ctx2->setPassphraseProvider(&provider);
199         ctx2->setPinentryMode(Context::PinentryLoopback);
200         QByteArray plainText;
201         auto decResult = decJob->exec(cipherText, plainText);
202         QVERIFY(!result.error());
203         QVERIFY(QString::fromUtf8(plainText) == QStringLiteral("Hello symmetric World"));
204         delete decJob;
205     }
206
207     void testEncryptDecryptNowrap()
208     {
209         /* Now decrypt */
210         if (!decryptSupported()) {
211             return;
212         }
213         auto listjob = openpgp()->keyListJob(false, false, false);
214         std::vector<Key> keys;
215         auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
216                                           false, keys);
217         QVERIFY(!keylistresult.error());
218         QVERIFY(keys.size() == 1);
219         delete listjob;
220
221         auto job = openpgp()->signEncryptJob(/*ASCII Armor */true, /* Textmode */ true);
222
223         auto encSignCtx = Job::context(job);
224         TestPassphraseProvider provider1;
225         encSignCtx->setPassphraseProvider(&provider1);
226         encSignCtx->setPinentryMode(Context::PinentryLoopback);
227
228         QVERIFY(job);
229         QByteArray cipherText;
230         auto result = job->exec(keys, keys, QStringLiteral("Hello World").toUtf8(), Context::AlwaysTrust, cipherText);
231         delete job;
232         QVERIFY(!result.first.error());
233         QVERIFY(!result.second.error());
234         const auto cipherString = QString::fromUtf8(cipherText);
235         QVERIFY(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
236
237         /* Now decrypt */
238         if (!decryptSupported()) {
239             return;
240         }
241
242         auto decJob = openpgp()->decryptJob();
243         auto ctx = Job::context(decJob);
244         TestPassphraseProvider provider;
245         ctx->setPassphraseProvider(&provider);
246         ctx->setPinentryMode(Context::PinentryLoopback);
247         ctx->setDecryptionFlags(Context::DecryptUnwrap);
248
249         QByteArray plainText;
250         auto decResult = decJob->exec(cipherText, plainText);
251
252         QVERIFY(!decResult.error());
253
254         delete decJob;
255
256         // Now verify the unwrapeped data.
257         auto verifyJob = openpgp()->verifyOpaqueJob(true);
258         QByteArray verified;
259
260         auto verResult = verifyJob->exec(plainText, verified);
261         QVERIFY(!verResult.error());
262         delete verifyJob;
263
264         QVERIFY(verResult.numSignatures() == 1);
265         auto sig = verResult.signatures()[0];
266
267         QVERIFY(verified == QStringLiteral("Hello World"));
268     }
269
270 private:
271     /* Loopback and passphrase provider don't work for mixed encryption.
272      * So this test is disabled until gnupg(?) is fixed for this. */
273     void testMixedEncryptDecrypt()
274     {
275         if (!decryptSupported()) {
276             return;
277         }
278         auto listjob = openpgp()->keyListJob(false, false, false);
279         std::vector<Key> keys;
280         auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
281                                           false, keys);
282         QVERIFY(!keylistresult.error());
283         QVERIFY(keys.size() == 1);
284         delete listjob;
285
286         auto job = openpgp()->encryptJob();
287         auto ctx = Job::context(job);
288         ctx->setPassphraseProvider(new TestPassphraseProvider);
289         ctx->setPinentryMode(Context::PinentryLoopback);
290         ctx->setArmor(true);
291         ctx->setTextMode(true);
292         QByteArray cipherText;
293         printf("Before exec, flags: %x\n", Context::Symmetric | Context::AlwaysTrust);
294         auto result = job->exec(keys, QStringLiteral("Hello symmetric World").toUtf8(),
295                                 static_cast<Context::EncryptionFlags>(Context::Symmetric | Context::AlwaysTrust),
296                                 cipherText);
297         printf("After exec\n");
298         delete job;
299         QVERIFY(!result.error());
300         printf("Cipher:\n%s\n", cipherText.constData());
301         const auto cipherString = QString::fromUtf8(cipherText);
302         QVERIFY(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
303
304         killAgent(mDir.path());
305
306         /* Now create a new homedir which with we test symmetric decrypt. */
307         QTemporaryDir tmp;
308         qputenv("GNUPGHOME", tmp.path().toUtf8());
309         QFile agentConf(tmp.path() + QStringLiteral("/gpg-agent.conf"));
310         QVERIFY(agentConf.open(QIODevice::WriteOnly));
311         agentConf.write("allow-loopback-pinentry");
312         agentConf.close();
313
314         auto decJob = openpgp()->decryptJob();
315         auto ctx2 = Job::context(decJob);
316         ctx2->setPassphraseProvider(new TestPassphraseProvider);
317         ctx2->setPinentryMode(Context::PinentryLoopback);
318         ctx2->setTextMode(true);
319         QByteArray plainText;
320         auto decResult = decJob->exec(cipherText, plainText);
321         QVERIFY(!decResult.error());
322         qDebug() << "Plain: " << plainText;
323         QVERIFY(QString::fromUtf8(plainText) == QStringLiteral("Hello symmetric World"));
324         delete decJob;
325
326         killAgent(tmp.path());
327         qputenv("GNUPGHOME", mDir.path().toUtf8());
328     }
329
330 public Q_SLOT:
331
332     void initTestCase()
333     {
334         QGpgMETest::initTestCase();
335         const QString gpgHome = qgetenv("GNUPGHOME");
336         qputenv("GNUPGHOME", mDir.path().toUtf8());
337         QVERIFY(mDir.isValid());
338         QFile agentConf(mDir.path() + QStringLiteral("/gpg-agent.conf"));
339         QVERIFY(agentConf.open(QIODevice::WriteOnly));
340         agentConf.write("allow-loopback-pinentry");
341         agentConf.close();
342         QVERIFY(copyKeyrings(gpgHome, mDir.path()));
343     }
344
345 private:
346     QTemporaryDir mDir;
347 };
348
349 QTEST_MAIN(EncryptionTest)
350
351 #include "t-encrypt.moc"