Line data Source code
1 : /* t-encrypt.cpp
2 :
3 : This file is part of qgpgme, the Qt API binding for gpgme
4 : Copyright (c) 2016 Intevation GmbH
5 :
6 : QGpgME is free software; you can redistribute it and/or
7 : modify it under the terms of the GNU General Public License as
8 : published by the Free Software Foundation; either version 2 of the
9 : License, or (at your option) any later version.
10 :
11 : QGpgME is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program; if not, write to the Free Software
18 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 :
20 : In addition, as a special exception, the copyright holders give
21 : permission to link the code of this program with any edition of
22 : the Qt library by Trolltech AS, Norway (or with modified versions
23 : of Qt that use the same license as Qt), and distribute linked
24 : combinations including the two. You must obey the GNU General
25 : Public License in all respects for all of the code used other than
26 : Qt. If you modify this file, you may extend this exception to
27 : your version of the file, but you are not obligated to do so. If
28 : you do not wish to do so, delete this exception statement from
29 : your version.
30 : */
31 : #include <QDebug>
32 : #include <QTest>
33 : #include <QTemporaryDir>
34 : #include <QSignalSpy>
35 : #include <QBuffer>
36 : #include "keylistjob.h"
37 : #include "encryptjob.h"
38 : #include "qgpgmeencryptjob.h"
39 : #include "encryptionresult.h"
40 : #include "decryptionresult.h"
41 : #include "qgpgmedecryptjob.h"
42 : #include "qgpgmebackend.h"
43 : #include "keylistresult.h"
44 : #include "engineinfo.h"
45 : #include "t-support.h"
46 :
47 : #define PROGRESS_TEST_SIZE 1 * 1024 * 1024
48 :
49 : using namespace QGpgME;
50 : using namespace GpgME;
51 :
52 2 : class EncryptionTest : public QGpgMETest
53 : {
54 : Q_OBJECT
55 :
56 : Q_SIGNALS:
57 : void asyncDone();
58 :
59 : private Q_SLOTS:
60 :
61 1 : void testSimpleEncryptDecrypt()
62 : {
63 1 : auto listjob = openpgp()->keyListJob(false, false, false);
64 1 : std::vector<Key> keys;
65 3 : auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
66 3 : false, keys);
67 1 : Q_ASSERT(!keylistresult.error());
68 1 : Q_ASSERT(keys.size() == 1);
69 1 : delete listjob;
70 :
71 1 : auto job = openpgp()->encryptJob(/*ASCII Armor */true, /* Textmode */ true);
72 1 : Q_ASSERT(job);
73 2 : QByteArray cipherText;
74 3 : auto result = job->exec(keys, QStringLiteral("Hello World").toUtf8(), Context::AlwaysTrust, cipherText);
75 1 : delete job;
76 1 : Q_ASSERT(!result.error());
77 2 : const auto cipherString = QString::fromUtf8(cipherText);
78 1 : Q_ASSERT(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
79 :
80 : /* Now decrypt */
81 1 : auto ctx = Context::createForProtocol(OpenPGP);
82 2 : TestPassphraseProvider provider;
83 1 : ctx->setPassphraseProvider(&provider);
84 1 : ctx->setPinentryMode(Context::PinentryLoopback);
85 1 : auto decJob = new QGpgMEDecryptJob(ctx);
86 2 : QByteArray plainText;
87 2 : auto decResult = decJob->exec(cipherText, plainText);
88 1 : Q_ASSERT(!result.error());
89 2 : Q_ASSERT(QString::fromUtf8(plainText) == QStringLiteral("Hello World"));
90 2 : delete decJob;
91 1 : }
92 :
93 1 : void testProgress()
94 : {
95 1 : if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.15") {
96 : // We can only test the progress with 2.1.15 as this started to
97 : // have total progress for memory callbacks
98 1 : return;
99 : }
100 1 : auto listjob = openpgp()->keyListJob(false, false, false);
101 1 : std::vector<Key> keys;
102 3 : auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
103 3 : false, keys);
104 1 : Q_ASSERT(!keylistresult.error());
105 1 : Q_ASSERT(keys.size() == 1);
106 1 : delete listjob;
107 :
108 1 : auto job = openpgp()->encryptJob(/*ASCII Armor */false, /* Textmode */ false);
109 1 : Q_ASSERT(job);
110 2 : QByteArray plainBa;
111 1 : plainBa.fill('X', PROGRESS_TEST_SIZE);
112 2 : QByteArray cipherText;
113 :
114 1 : bool initSeen = false;
115 1 : bool finishSeen = false;
116 2 : connect(job, &Job::progress, this, [this, &initSeen, &finishSeen] (const QString& what, int current, int total) {
117 : // We only check for progress 0 and max progress as the other progress
118 : // lines depend on the system speed and are as such unreliable to test.
119 2 : Q_ASSERT(total == PROGRESS_TEST_SIZE);
120 2 : if (current == 0) {
121 1 : initSeen = true;
122 : }
123 2 : if (current == total) {
124 1 : finishSeen = true;
125 : }
126 2 : Q_ASSERT(current >= 0 && current <= total);
127 3 : });
128 : connect(job, &EncryptJob::result, this, [this, &initSeen, &finishSeen] (const GpgME::EncryptionResult &result,
129 : const QByteArray &cipherText,
130 : const QString,
131 1 : const GpgME::Error) {
132 1 : Q_ASSERT(initSeen);
133 1 : Q_ASSERT(finishSeen);
134 1 : Q_EMIT asyncDone();
135 2 : });
136 :
137 2 : auto inptr = std::shared_ptr<QIODevice>(new QBuffer(&plainBa));
138 1 : inptr->open(QIODevice::ReadOnly);
139 2 : auto outptr = std::shared_ptr<QIODevice>(new QBuffer(&cipherText));
140 1 : outptr->open(QIODevice::WriteOnly);
141 :
142 1 : job->start(keys, inptr, outptr, Context::AlwaysTrust);
143 2 : QSignalSpy spy (this, SIGNAL(asyncDone()));
144 2 : Q_ASSERT(spy.wait());
145 : }
146 :
147 1 : void testSymmetricEncryptDecrypt()
148 : {
149 1 : auto ctx = Context::createForProtocol(OpenPGP);
150 1 : TestPassphraseProvider provider;
151 1 : ctx->setPassphraseProvider(&provider);
152 1 : ctx->setPinentryMode(Context::PinentryLoopback);
153 1 : ctx->setArmor(true);
154 1 : ctx->setTextMode(true);
155 1 : auto job = new QGpgMEEncryptJob(ctx);
156 2 : QByteArray cipherText;
157 3 : auto result = job->exec(std::vector<Key>(), QStringLiteral("Hello symmetric World").toUtf8(), Context::AlwaysTrust, cipherText);
158 1 : delete job;
159 1 : Q_ASSERT(!result.error());
160 2 : const auto cipherString = QString::fromUtf8(cipherText);
161 1 : Q_ASSERT(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
162 :
163 1 : killAgent(mDir.path());
164 :
165 1 : auto ctx2 = Context::createForProtocol(OpenPGP);
166 1 : ctx2->setPassphraseProvider(&provider);
167 1 : ctx2->setPinentryMode(Context::PinentryLoopback);
168 1 : auto decJob = new QGpgMEDecryptJob(ctx2);
169 2 : QByteArray plainText;
170 2 : auto decResult = decJob->exec(cipherText, plainText);
171 1 : Q_ASSERT(!result.error());
172 2 : Q_ASSERT(QString::fromUtf8(plainText) == QStringLiteral("Hello symmetric World"));
173 2 : delete decJob;
174 1 : }
175 :
176 : private:
177 : /* Loopback and passphrase provider don't work for mixed encryption.
178 : * So this test is disabled until gnupg(?) is fixed for this. */
179 : void testMixedEncryptDecrypt()
180 : {
181 : auto listjob = openpgp()->keyListJob(false, false, false);
182 : std::vector<Key> keys;
183 : auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
184 : false, keys);
185 : Q_ASSERT(!keylistresult.error());
186 : Q_ASSERT(keys.size() == 1);
187 : delete listjob;
188 :
189 : auto ctx = Context::createForProtocol(OpenPGP);
190 : ctx->setPassphraseProvider(new TestPassphraseProvider);
191 : ctx->setPinentryMode(Context::PinentryLoopback);
192 : ctx->setArmor(true);
193 : ctx->setTextMode(true);
194 : auto job = new QGpgMEEncryptJob(ctx);
195 : QByteArray cipherText;
196 : printf("Before exec, flags: %x\n", Context::Symmetric | Context::AlwaysTrust);
197 : auto result = job->exec(keys, QStringLiteral("Hello symmetric World").toUtf8(),
198 : static_cast<Context::EncryptionFlags>(Context::Symmetric | Context::AlwaysTrust),
199 : cipherText);
200 : printf("After exec\n");
201 : delete job;
202 : Q_ASSERT(!result.error());
203 : printf("Cipher:\n%s\n", cipherText.constData());
204 : const auto cipherString = QString::fromUtf8(cipherText);
205 : Q_ASSERT(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
206 :
207 : killAgent(mDir.path());
208 :
209 : /* Now create a new homedir which with we test symetric decrypt. */
210 : QTemporaryDir tmp;
211 : qputenv("GNUPGHOME", tmp.path().toUtf8());
212 : QFile agentConf(tmp.path() + QStringLiteral("/gpg-agent.conf"));
213 : Q_ASSERT(agentConf.open(QIODevice::WriteOnly));
214 : agentConf.write("allow-loopback-pinentry");
215 : agentConf.close();
216 :
217 : auto ctx2 = Context::createForProtocol(OpenPGP);
218 : ctx2->setPassphraseProvider(new TestPassphraseProvider);
219 : ctx2->setPinentryMode(Context::PinentryLoopback);
220 : ctx2->setTextMode(true);
221 : auto decJob = new QGpgMEDecryptJob(ctx2);
222 : QByteArray plainText;
223 : auto decResult = decJob->exec(cipherText, plainText);
224 : Q_ASSERT(!decResult.error());
225 : qDebug() << "Plain: " << plainText;
226 : Q_ASSERT(QString::fromUtf8(plainText) == QStringLiteral("Hello symmetric World"));
227 : delete decJob;
228 :
229 : killAgent(tmp.path());
230 : qputenv("GNUPGHOME", mDir.path().toUtf8());
231 : }
232 :
233 : public Q_SLOT:
234 :
235 : void initTestCase()
236 : {
237 : QGpgMETest::initTestCase();
238 : const QString gpgHome = qgetenv("GNUPGHOME");
239 : qputenv("GNUPGHOME", mDir.path().toUtf8());
240 : Q_ASSERT(mDir.isValid());
241 : QFile agentConf(mDir.path() + QStringLiteral("/gpg-agent.conf"));
242 : Q_ASSERT(agentConf.open(QIODevice::WriteOnly));
243 : agentConf.write("allow-loopback-pinentry");
244 : agentConf.close();
245 : Q_ASSERT(copyKeyrings(gpgHome, mDir.path()));
246 : }
247 :
248 : private:
249 : QTemporaryDir mDir;
250 : };
251 :
252 1 : QTEST_MAIN(EncryptionTest)
253 :
254 : #include "t-encrypt.moc"
|