1 #include <openssl/rsa.h>
2 #include <openssl/evp.h>
3 #include <openssl/pem.h>
4 #include <openssl/err.h>
5 #include <openssl/engine.h>
6 #include <openssl/rand.h>
7 
8 
9 #include "clientsideencryption.h"
10 #include "account.h"
11 #include "capabilities.h"
12 #include "networkjobs.h"
13 #include "clientsideencryptionjobs.h"
14 #include "theme.h"
15 #include "creds/abstractcredentials.h"
16 
17 #include <map>
18 #include <string>
19 #include <algorithm>
20 
21 #include <cstdio>
22 
23 #include <QDebug>
24 #include <QLoggingCategory>
25 #include <QFileInfo>
26 #include <QDir>
27 #include <QJsonObject>
28 #include <QXmlStreamReader>
29 #include <QXmlStreamNamespaceDeclaration>
30 #include <QStack>
31 #include <QInputDialog>
32 #include <QLineEdit>
33 #include <QIODevice>
34 #include <QUuid>
35 #include <QScopeGuard>
36 #include <QRandomGenerator>
37 
38 #include <qt5keychain/keychain.h>
39 #include <common/utility.h>
40 #include <common/constants.h>
41 
42 #include "wordlist.h"
43 
44 #ifdef LIBRESSL_VERSION_NUMBER
45 #ifndef EVP_PKEY_CTX_set_rsa_oaep_md
46 # define EVP_PKEY_CTRL_RSA_OAEP_MD	(EVP_PKEY_ALG_CTRL + 9)
47 # define EVP_PKEY_CTRL_GET_RSA_OAEP_MD	(EVP_PKEY_ALG_CTRL + 11)
48 
49 # define EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) \
50 	EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,  \
51 			  EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void *)(md))
52 #endif
53 #endif
54 
operator <<(QDebug out,const std::string & str)55 QDebug operator<<(QDebug out, const std::string& str)
56 {
57     out << QString::fromStdString(str);
58     return out;
59 }
60 
61 using namespace QKeychain;
62 
63 namespace OCC
64 {
65 
66 Q_LOGGING_CATEGORY(lcCse, "nextcloud.sync.clientsideencryption", QtInfoMsg)
67 Q_LOGGING_CATEGORY(lcCseDecryption, "nextcloud.e2e", QtInfoMsg)
68 Q_LOGGING_CATEGORY(lcCseMetadata, "nextcloud.metadata", QtInfoMsg)
69 
e2eeBaseUrl()70 QString e2eeBaseUrl()
71 {
72     return QStringLiteral("ocs/v2.php/apps/end_to_end_encryption/api/v1/");
73 }
74 
75 namespace {
76     constexpr char accountProperty[] = "account";
77 
78     const char e2e_cert[] = "_e2e-certificate";
79     const char e2e_private[] = "_e2e-private";
80     const char e2e_mnemonic[] = "_e2e-mnemonic";
81 
82     constexpr qint64 blockSize = 1024;
83 
oldCipherFormatSplit(const QByteArray & cipher)84     QList<QByteArray> oldCipherFormatSplit(const QByteArray &cipher)
85     {
86         const auto separator = QByteArrayLiteral("fA=="); // BASE64 encoded '|'
87         auto result = QList<QByteArray>();
88 
89         auto data = cipher;
90         auto index = data.indexOf(separator);
91         while (index >=0) {
92             result.append(data.left(index));
93             data = data.mid(index + separator.size());
94             index = data.indexOf(separator);
95         }
96 
97         result.append(data);
98         return result;
99     }
100 
splitCipherParts(const QByteArray & data)101     QList<QByteArray> splitCipherParts(const QByteArray &data)
102     {
103         const auto isOldFormat = !data.contains('|');
104         const auto parts = isOldFormat ? oldCipherFormatSplit(data) : data.split('|');
105         qCInfo(lcCse()) << "found parts:" << parts << "old format?" << isOldFormat;
106         return parts;
107     }
108 } // ns
109 
110 namespace {
unsignedData(QByteArray & array)111     unsigned char* unsignedData(QByteArray& array)
112     {
113         return (unsigned char*)array.data();
114     }
115 
116     //
117     // Simple classes for safe (RAII) handling of OpenSSL
118     // data structures
119     //
120 
121     class CipherCtx {
122     public:
CipherCtx()123         CipherCtx()
124             : _ctx(EVP_CIPHER_CTX_new())
125         {
126         }
127 
~CipherCtx()128         ~CipherCtx()
129         {
130             EVP_CIPHER_CTX_free(_ctx);
131         }
132 
operator EVP_CIPHER_CTX*()133         operator EVP_CIPHER_CTX*()
134         {
135             return _ctx;
136         }
137 
138     private:
139         Q_DISABLE_COPY(CipherCtx)
140 
141         EVP_CIPHER_CTX* _ctx;
142     };
143 
144     class Bio {
145     public:
Bio()146         Bio()
147             : _bio(BIO_new(BIO_s_mem()))
148         {
149         }
150 
~Bio()151         ~Bio()
152         {
153             BIO_free_all(_bio);
154         }
155 
operator BIO*()156         operator BIO*()
157         {
158             return _bio;
159         }
160 
161     private:
162         Q_DISABLE_COPY(Bio)
163 
164         BIO* _bio;
165     };
166 
167     class PKeyCtx {
168     public:
PKeyCtx(int id,ENGINE * e=nullptr)169         explicit PKeyCtx(int id, ENGINE *e = nullptr)
170             : _ctx(EVP_PKEY_CTX_new_id(id, e))
171         {
172         }
173 
~PKeyCtx()174         ~PKeyCtx()
175         {
176             EVP_PKEY_CTX_free(_ctx);
177         }
178 
179         // The move constructor is needed for pre-C++17 where
180         // return-value optimization (RVO) is not obligatory
181         // and we have a `forKey` static function that returns
182         // an instance of this class
PKeyCtx(PKeyCtx && other)183         PKeyCtx(PKeyCtx&& other)
184         {
185             std::swap(_ctx, other._ctx);
186         }
187 
188         PKeyCtx& operator=(PKeyCtx&& other) = delete;
189 
forKey(EVP_PKEY * pkey,ENGINE * e=nullptr)190         static PKeyCtx forKey(EVP_PKEY *pkey, ENGINE *e = nullptr)
191         {
192             PKeyCtx ctx;
193             ctx._ctx = EVP_PKEY_CTX_new(pkey, e);
194             return ctx;
195         }
196 
operator EVP_PKEY_CTX*()197         operator EVP_PKEY_CTX*()
198         {
199             return _ctx;
200         }
201 
202     private:
203         Q_DISABLE_COPY(PKeyCtx)
204 
205         PKeyCtx() = default;
206 
207         EVP_PKEY_CTX* _ctx = nullptr;
208     };
209 
210     class PKey {
211     public:
~PKey()212         ~PKey()
213         {
214             EVP_PKEY_free(_pkey);
215         }
216 
217         // The move constructor is needed for pre-C++17 where
218         // return-value optimization (RVO) is not obligatory
219         // and we have a static functions that return
220         // an instance of this class
PKey(PKey && other)221         PKey(PKey&& other)
222         {
223             std::swap(_pkey, other._pkey);
224         }
225 
226         PKey& operator=(PKey&& other) = delete;
227 
readPublicKey(Bio & bio)228         static PKey readPublicKey(Bio &bio)
229         {
230             PKey result;
231             result._pkey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr);
232             return result;
233         }
234 
readPrivateKey(Bio & bio)235         static PKey readPrivateKey(Bio &bio)
236         {
237             PKey result;
238             result._pkey = PEM_read_bio_PrivateKey(bio, nullptr, nullptr, nullptr);
239             return result;
240         }
241 
generate(PKeyCtx & ctx)242         static PKey generate(PKeyCtx& ctx)
243         {
244             PKey result;
245             if (EVP_PKEY_keygen(ctx, &result._pkey) <= 0) {
246                 result._pkey = nullptr;
247             }
248             return result;
249         }
250 
operator EVP_PKEY*()251         operator EVP_PKEY*()
252         {
253             return _pkey;
254         }
255 
operator EVP_PKEY*() const256         operator EVP_PKEY*() const
257         {
258             return _pkey;
259         }
260 
261     private:
262         Q_DISABLE_COPY(PKey)
263 
264         PKey() = default;
265 
266         EVP_PKEY* _pkey = nullptr;
267     };
268 
269     class X509Certificate {
270     public:
~X509Certificate()271         ~X509Certificate()
272         {
273             X509_free(_certificate);
274         }
275 
276         // The move constructor is needed for pre-C++17 where
277         // return-value optimization (RVO) is not obligatory
278         // and we have a static functions that return
279         // an instance of this class
X509Certificate(X509Certificate && other)280         X509Certificate(X509Certificate&& other)
281         {
282             std::swap(_certificate, other._certificate);
283         }
284 
285         X509Certificate& operator=(X509Certificate&& other) = delete;
286 
readCertificate(Bio & bio)287         static X509Certificate readCertificate(Bio &bio)
288         {
289             X509Certificate result;
290             result._certificate = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
291             return result;
292         }
293 
operator X509*()294         operator X509*()
295         {
296             return _certificate;
297         }
298 
operator X509*() const299         operator X509*() const
300         {
301             return _certificate;
302         }
303 
304     private:
305         Q_DISABLE_COPY(X509Certificate)
306 
307         X509Certificate() = default;
308 
309         X509* _certificate = nullptr;
310     };
311 
BIO2ByteArray(Bio & b)312     QByteArray BIO2ByteArray(Bio &b) {
313         auto pending = static_cast<int>(BIO_ctrl_pending(b));
314         QByteArray res(pending, '\0');
315         BIO_read(b, unsignedData(res), pending);
316         return res;
317     }
318 
handleErrors()319     QByteArray handleErrors()
320     {
321         Bio bioErrors;
322         ERR_print_errors(bioErrors); // This line is not printing anything.
323         return BIO2ByteArray(bioErrors);
324     }
325 }
326 
327 
328 namespace EncryptionHelper {
329 
330 
331 
332 
generateRandomFilename()333 QByteArray generateRandomFilename()
334 {
335     return QUuid::createUuid().toRfc4122().toHex();
336 }
337 
generateRandom(int size)338 QByteArray generateRandom(int size)
339 {
340     QByteArray result(size, '\0');
341 
342     int ret = RAND_bytes(unsignedData(result), size);
343     if (ret != 1) {
344         qCInfo(lcCse()) << "Random byte generation failed!";
345         // Error out?
346     }
347 
348     return result;
349 }
350 
generatePassword(const QString & wordlist,const QByteArray & salt)351 QByteArray generatePassword(const QString& wordlist, const QByteArray& salt) {
352     qCInfo(lcCse()) << "Start encryption key generation!";
353 
354     const int iterationCount = 1024;
355     const int keyStrength = 256;
356     const int keyLength = keyStrength/8;
357 
358     QByteArray secretKey(keyLength, '\0');
359 
360     int ret = PKCS5_PBKDF2_HMAC_SHA1(
361         wordlist.toLocal8Bit().constData(),     // const char *password,
362         wordlist.size(),                        // int password length,
363         (const unsigned char *)salt.constData(),// const unsigned char *salt,
364         salt.size(),                            // int saltlen,
365         iterationCount,                         // int iterations,
366         keyLength,                              // int keylen,
367         unsignedData(secretKey)                 // unsigned char *out
368     );
369 
370     if (ret != 1) {
371         qCInfo(lcCse()) << "Failed to generate encryption key";
372         // Error out?
373     }
374 
375     qCInfo(lcCse()) << "Encryption key generated!";
376 
377     return secretKey;
378 }
379 
encryptPrivateKey(const QByteArray & key,const QByteArray & privateKey,const QByteArray & salt)380 QByteArray encryptPrivateKey(
381         const QByteArray& key,
382         const QByteArray& privateKey,
383         const QByteArray& salt
384         ) {
385 
386     QByteArray iv = generateRandom(12);
387 
388     CipherCtx ctx;
389 
390     /* Create and initialise the context */
391     if(!ctx) {
392         qCInfo(lcCse()) << "Error creating cipher";
393         handleErrors();
394     }
395 
396     /* Initialise the decryption operation. */
397     if(!EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr)) {
398         qCInfo(lcCse()) << "Error initializing context with aes_256";
399         handleErrors();
400     }
401 
402     // No padding
403     EVP_CIPHER_CTX_set_padding(ctx, 0);
404 
405     /* Set IV length. */
406     if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size(), nullptr)) {
407         qCInfo(lcCse()) << "Error setting iv length";
408         handleErrors();
409     }
410 
411     /* Initialise key and IV */
412     if(!EVP_EncryptInit_ex(ctx, nullptr, nullptr, (unsigned char *)key.constData(), (unsigned char *)iv.constData())) {
413         qCInfo(lcCse()) << "Error initialising key and iv";
414         handleErrors();
415     }
416 
417     // We write the base64 encoded private key
418     QByteArray privateKeyB64 = privateKey.toBase64();
419 
420     // Make sure we have enough room in the cipher text
421     QByteArray ctext(privateKeyB64.size() + 32, '\0');
422 
423     // Do the actual encryption
424     int len = 0;
425     if(!EVP_EncryptUpdate(ctx, unsignedData(ctext), &len, (unsigned char *)privateKeyB64.constData(), privateKeyB64.size())) {
426         qCInfo(lcCse()) << "Error encrypting";
427         handleErrors();
428     }
429 
430     int clen = len;
431 
432     /* Finalise the encryption. Normally ciphertext bytes may be written at
433      * this stage, but this does not occur in GCM mode
434      */
435     if(1 != EVP_EncryptFinal_ex(ctx, unsignedData(ctext) + len, &len)) {
436         qCInfo(lcCse()) << "Error finalizing encryption";
437         handleErrors();
438     }
439     clen += len;
440 
441     /* Get the e2EeTag */
442     QByteArray e2EeTag(OCC::Constants::e2EeTagSize, '\0');
443     if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, OCC::Constants::e2EeTagSize, unsignedData(e2EeTag))) {
444         qCInfo(lcCse()) << "Error getting the e2EeTag";
445         handleErrors();
446     }
447 
448     QByteArray cipherTXT;
449     cipherTXT.reserve(clen + OCC::Constants::e2EeTagSize);
450     cipherTXT.append(ctext, clen);
451     cipherTXT.append(e2EeTag);
452 
453     QByteArray result = cipherTXT.toBase64();
454     result += '|';
455     result += iv.toBase64();
456     result += '|';
457     result += salt.toBase64();
458 
459     return result;
460 }
461 
decryptPrivateKey(const QByteArray & key,const QByteArray & data)462 QByteArray decryptPrivateKey(const QByteArray& key, const QByteArray& data) {
463     qCInfo(lcCse()) << "decryptStringSymmetric key: " << key;
464     qCInfo(lcCse()) << "decryptStringSymmetric data: " << data;
465 
466     const auto parts = splitCipherParts(data);
467     if (parts.size() < 2) {
468         qCInfo(lcCse()) << "Not enough parts found";
469         return QByteArray();
470     }
471 
472     QByteArray cipherTXT64 = parts.at(0);
473     QByteArray ivB64 = parts.at(1);
474 
475     qCInfo(lcCse()) << "decryptStringSymmetric cipherTXT: " << cipherTXT64;
476     qCInfo(lcCse()) << "decryptStringSymmetric IV: " << ivB64;
477 
478     QByteArray cipherTXT = QByteArray::fromBase64(cipherTXT64);
479     QByteArray iv = QByteArray::fromBase64(ivB64);
480 
481     const QByteArray e2EeTag = cipherTXT.right(OCC::Constants::e2EeTagSize);
482     cipherTXT.chop(OCC::Constants::e2EeTagSize);
483 
484     // Init
485     CipherCtx ctx;
486 
487     /* Create and initialise the context */
488     if(!ctx) {
489         qCInfo(lcCse()) << "Error creating cipher";
490         return QByteArray();
491     }
492 
493     /* Initialise the decryption operation. */
494     if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr)) {
495         qCInfo(lcCse()) << "Error initialising context with aes 256";
496         return QByteArray();
497     }
498 
499     /* Set IV length. Not necessary if this is 12 bytes (96 bits) */
500     if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size(), nullptr)) {
501         qCInfo(lcCse()) << "Error setting IV size";
502         return QByteArray();
503     }
504 
505     /* Initialise key and IV */
506     if(!EVP_DecryptInit_ex(ctx, nullptr, nullptr, (unsigned char *)key.constData(), (unsigned char *)iv.constData())) {
507         qCInfo(lcCse()) << "Error initialising key and iv";
508         return QByteArray();
509     }
510 
511     QByteArray ptext(cipherTXT.size() + OCC::Constants::e2EeTagSize, '\0');
512     int plen = 0;
513 
514     /* Provide the message to be decrypted, and obtain the plaintext output.
515      * EVP_DecryptUpdate can be called multiple times if necessary
516      */
517     if(!EVP_DecryptUpdate(ctx, unsignedData(ptext), &plen, (unsigned char *)cipherTXT.constData(), cipherTXT.size())) {
518         qCInfo(lcCse()) << "Could not decrypt";
519         return QByteArray();
520     }
521 
522     /* Set expected e2EeTag value. Works in OpenSSL 1.0.1d and later */
523     if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, e2EeTag.size(), (unsigned char *)e2EeTag.constData())) {
524         qCInfo(lcCse()) << "Could not set e2EeTag";
525         return QByteArray();
526     }
527 
528     /* Finalise the decryption. A positive return value indicates success,
529      * anything else is a failure - the plaintext is not trustworthy.
530      */
531     int len = plen;
532     if (EVP_DecryptFinal_ex(ctx, unsignedData(ptext) + plen, &len) == 0) {
533         qCInfo(lcCse()) << "Tag did not match!";
534         return QByteArray();
535     }
536 
537     QByteArray result(ptext, plen);
538     return QByteArray::fromBase64(result);
539 }
540 
extractPrivateKeySalt(const QByteArray & data)541 QByteArray extractPrivateKeySalt(const QByteArray &data)
542 {
543     const auto parts = splitCipherParts(data);
544     if (parts.size() < 3) {
545         qCInfo(lcCse()) << "Not enough parts found";
546         return QByteArray();
547     }
548 
549     return QByteArray::fromBase64(parts.at(2));
550 }
551 
decryptStringSymmetric(const QByteArray & key,const QByteArray & data)552 QByteArray decryptStringSymmetric(const QByteArray& key, const QByteArray& data) {
553     qCInfo(lcCse()) << "decryptStringSymmetric key: " << key;
554     qCInfo(lcCse()) << "decryptStringSymmetric data: " << data;
555 
556     const auto parts = splitCipherParts(data);
557     if (parts.size() < 2) {
558         qCInfo(lcCse()) << "Not enough parts found";
559         return QByteArray();
560     }
561 
562     QByteArray cipherTXT64 = parts.at(0);
563     QByteArray ivB64 = parts.at(1);
564 
565     qCInfo(lcCse()) << "decryptStringSymmetric cipherTXT: " << cipherTXT64;
566     qCInfo(lcCse()) << "decryptStringSymmetric IV: " << ivB64;
567 
568     QByteArray cipherTXT = QByteArray::fromBase64(cipherTXT64);
569     QByteArray iv = QByteArray::fromBase64(ivB64);
570 
571     const QByteArray e2EeTag = cipherTXT.right(OCC::Constants::e2EeTagSize);
572     cipherTXT.chop(OCC::Constants::e2EeTagSize);
573 
574     // Init
575     CipherCtx ctx;
576 
577     /* Create and initialise the context */
578     if(!ctx) {
579         qCInfo(lcCse()) << "Error creating cipher";
580         return QByteArray();
581     }
582 
583     /* Initialise the decryption operation. */
584     if(!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) {
585         qCInfo(lcCse()) << "Error initialising context with aes 128";
586         return QByteArray();
587     }
588 
589     /* Set IV length. Not necessary if this is 12 bytes (96 bits) */
590     if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size(), nullptr)) {
591         qCInfo(lcCse()) << "Error setting IV size";
592         return QByteArray();
593     }
594 
595     /* Initialise key and IV */
596     if(!EVP_DecryptInit_ex(ctx, nullptr, nullptr, (unsigned char *)key.constData(), (unsigned char *)iv.constData())) {
597         qCInfo(lcCse()) << "Error initialising key and iv";
598         return QByteArray();
599     }
600 
601     QByteArray ptext(cipherTXT.size() + OCC::Constants::e2EeTagSize, '\0');
602     int plen = 0;
603 
604     /* Provide the message to be decrypted, and obtain the plaintext output.
605      * EVP_DecryptUpdate can be called multiple times if necessary
606      */
607     if(!EVP_DecryptUpdate(ctx, unsignedData(ptext), &plen, (unsigned char *)cipherTXT.constData(), cipherTXT.size())) {
608         qCInfo(lcCse()) << "Could not decrypt";
609         return QByteArray();
610     }
611 
612     /* Set expected e2EeTag value. Works in OpenSSL 1.0.1d and later */
613     if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, e2EeTag.size(), (unsigned char *)e2EeTag.constData())) {
614         qCInfo(lcCse()) << "Could not set e2EeTag";
615         return QByteArray();
616     }
617 
618     /* Finalise the decryption. A positive return value indicates success,
619      * anything else is a failure - the plaintext is not trustworthy.
620      */
621     int len = plen;
622     if (EVP_DecryptFinal_ex(ctx, unsignedData(ptext) + plen, &len) == 0) {
623         qCInfo(lcCse()) << "Tag did not match!";
624         return QByteArray();
625     }
626 
627     return QByteArray::fromBase64(QByteArray(ptext, plen));
628 }
629 
privateKeyToPem(const QByteArray key)630 QByteArray privateKeyToPem(const QByteArray key) {
631     Bio privateKeyBio;
632     BIO_write(privateKeyBio, key.constData(), key.size());
633     auto pkey = PKey::readPrivateKey(privateKeyBio);
634 
635     Bio pemBio;
636     PEM_write_bio_PKCS8PrivateKey(pemBio, pkey, nullptr, nullptr, 0, nullptr, nullptr);
637     QByteArray pem = BIO2ByteArray(pemBio);
638 
639     return pem;
640 }
641 
encryptStringSymmetric(const QByteArray & key,const QByteArray & data)642 QByteArray encryptStringSymmetric(const QByteArray& key, const QByteArray& data) {
643     QByteArray iv = generateRandom(16);
644 
645     CipherCtx ctx;
646 
647     /* Create and initialise the context */
648     if(!ctx) {
649         qCInfo(lcCse()) << "Error creating cipher";
650         handleErrors();
651         return {};
652     }
653 
654     /* Initialise the decryption operation. */
655     if(!EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) {
656         qCInfo(lcCse()) << "Error initializing context with aes_128";
657         handleErrors();
658         return {};
659     }
660 
661     // No padding
662     EVP_CIPHER_CTX_set_padding(ctx, 0);
663 
664     /* Set IV length. */
665     if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size(), nullptr)) {
666         qCInfo(lcCse()) << "Error setting iv length";
667         handleErrors();
668         return {};
669     }
670 
671     /* Initialise key and IV */
672     if(!EVP_EncryptInit_ex(ctx, nullptr, nullptr, (unsigned char *)key.constData(), (unsigned char *)iv.constData())) {
673         qCInfo(lcCse()) << "Error initialising key and iv";
674         handleErrors();
675         return {};
676     }
677 
678     // We write the data base64 encoded
679     QByteArray dataB64 = data.toBase64();
680 
681     // Make sure we have enough room in the cipher text
682     QByteArray ctext(dataB64.size() + 16, '\0');
683 
684     // Do the actual encryption
685     int len = 0;
686     if(!EVP_EncryptUpdate(ctx, unsignedData(ctext), &len, (unsigned char *)dataB64.constData(), dataB64.size())) {
687         qCInfo(lcCse()) << "Error encrypting";
688         handleErrors();
689         return {};
690     }
691 
692     int clen = len;
693 
694     /* Finalise the encryption. Normally ciphertext bytes may be written at
695      * this stage, but this does not occur in GCM mode
696      */
697     if(1 != EVP_EncryptFinal_ex(ctx, unsignedData(ctext) + len, &len)) {
698         qCInfo(lcCse()) << "Error finalizing encryption";
699         handleErrors();
700         return {};
701     }
702     clen += len;
703 
704     /* Get the e2EeTag */
705     QByteArray e2EeTag(OCC::Constants::e2EeTagSize, '\0');
706     if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, OCC::Constants::e2EeTagSize, unsignedData(e2EeTag))) {
707         qCInfo(lcCse()) << "Error getting the e2EeTag";
708         handleErrors();
709         return {};
710     }
711 
712     QByteArray cipherTXT;
713     cipherTXT.reserve(clen + OCC::Constants::e2EeTagSize);
714     cipherTXT.append(ctext, clen);
715     cipherTXT.append(e2EeTag);
716 
717     QByteArray result = cipherTXT.toBase64();
718     result += '|';
719     result += iv.toBase64();
720 
721     return result;
722 }
723 
decryptStringAsymmetric(EVP_PKEY * privateKey,const QByteArray & data)724 QByteArray decryptStringAsymmetric(EVP_PKEY *privateKey, const QByteArray& data) {
725     int err = -1;
726 
727     qCInfo(lcCseDecryption()) << "Start to work the decryption.";
728     auto ctx = PKeyCtx::forKey(privateKey, ENGINE_get_default_RSA());
729     if (!ctx) {
730         qCInfo(lcCseDecryption()) << "Could not create the PKEY context.";
731         handleErrors();
732         return {};
733     }
734 
735     err = EVP_PKEY_decrypt_init(ctx);
736     if (err <= 0) {
737         qCInfo(lcCseDecryption()) << "Could not init the decryption of the metadata";
738         handleErrors();
739         return {};
740     }
741 
742     if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) {
743         qCInfo(lcCseDecryption()) << "Error setting the encryption padding.";
744         handleErrors();
745         return {};
746     }
747 
748     if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx, EVP_sha256()) <= 0) {
749         qCInfo(lcCseDecryption()) << "Error setting OAEP SHA 256";
750         handleErrors();
751         return {};
752     }
753 
754     if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, EVP_sha256()) <= 0) {
755         qCInfo(lcCseDecryption()) << "Error setting MGF1 padding";
756         handleErrors();
757         return {};
758     }
759 
760     size_t outlen = 0;
761     err = EVP_PKEY_decrypt(ctx, nullptr, &outlen,  (unsigned char *)data.constData(), data.size());
762     if (err <= 0) {
763         qCInfo(lcCseDecryption()) << "Could not determine the buffer length";
764         handleErrors();
765         return {};
766     } else {
767         qCInfo(lcCseDecryption()) << "Size of output is: " << outlen;
768         qCInfo(lcCseDecryption()) << "Size of data is: " << data.size();
769     }
770 
771     QByteArray out(static_cast<int>(outlen), '\0');
772 
773     if (EVP_PKEY_decrypt(ctx, unsignedData(out), &outlen, (unsigned char *)data.constData(), data.size()) <= 0) {
774         const auto error = handleErrors();
775         qCCritical(lcCseDecryption()) << "Could not decrypt the data." << error;
776         return {};
777     } else {
778         qCInfo(lcCseDecryption()) << "data decrypted successfully";
779     }
780 
781     qCInfo(lcCse()) << out;
782     return out;
783 }
784 
encryptStringAsymmetric(EVP_PKEY * publicKey,const QByteArray & data)785 QByteArray encryptStringAsymmetric(EVP_PKEY *publicKey, const QByteArray& data) {
786     int err = -1;
787 
788     auto ctx = PKeyCtx::forKey(publicKey, ENGINE_get_default_RSA());
789     if (!ctx) {
790         qCInfo(lcCse()) << "Could not initialize the pkey context.";
791         exit(1);
792     }
793 
794     if (EVP_PKEY_encrypt_init(ctx) != 1) {
795         qCInfo(lcCse()) << "Error initilaizing the encryption.";
796         exit(1);
797     }
798 
799     if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) {
800         qCInfo(lcCse()) << "Error setting the encryption padding.";
801         exit(1);
802     }
803 
804     if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx, EVP_sha256()) <= 0) {
805         qCInfo(lcCse()) << "Error setting OAEP SHA 256";
806         exit(1);
807     }
808 
809     if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, EVP_sha256()) <= 0) {
810         qCInfo(lcCse()) << "Error setting MGF1 padding";
811         exit(1);
812     }
813 
814     size_t outLen = 0;
815     if (EVP_PKEY_encrypt(ctx, nullptr, &outLen, (unsigned char *)data.constData(), data.size()) != 1) {
816         qCInfo(lcCse()) << "Error retrieving the size of the encrypted data";
817         exit(1);
818     } else {
819         qCInfo(lcCse()) << "Encryption Length:" << outLen;
820     }
821 
822     QByteArray out(static_cast<int>(outLen), '\0');
823     if (EVP_PKEY_encrypt(ctx, unsignedData(out), &outLen, (unsigned char *)data.constData(), data.size()) != 1) {
824         qCInfo(lcCse()) << "Could not encrypt key." << err;
825         exit(1);
826     }
827 
828     // Transform the encrypted data into base64.
829     qCInfo(lcCse()) << out.toBase64();
830     return out.toBase64();
831 }
832 
833 }
834 
835 
836 ClientSideEncryption::ClientSideEncryption() = default;
837 
initialize(const AccountPtr & account)838 void ClientSideEncryption::initialize(const AccountPtr &account)
839 {
840     Q_ASSERT(account);
841 
842     qCInfo(lcCse()) << "Initializing";
843     if (!account->capabilities().clientSideEncryptionAvailable()) {
844         qCInfo(lcCse()) << "No Client side encryption available on server.";
845         emit initializationFinished();
846         return;
847     }
848 
849     fetchFromKeyChain(account);
850 }
851 
fetchFromKeyChain(const AccountPtr & account)852 void ClientSideEncryption::fetchFromKeyChain(const AccountPtr &account)
853 {
854     const QString kck = AbstractCredentials::keychainKey(
855                 account->url().toString(),
856                 account->credentials()->user() + e2e_cert,
857                 account->id()
858     );
859 
860     auto *job = new ReadPasswordJob(Theme::instance()->appName());
861     job->setProperty(accountProperty, QVariant::fromValue(account));
862     job->setInsecureFallback(false);
863     job->setKey(kck);
864     connect(job, &ReadPasswordJob::finished, this, &ClientSideEncryption::publicKeyFetched);
865     job->start();
866 }
867 
checkPublicKeyValidity(const AccountPtr & account) const868 bool ClientSideEncryption::checkPublicKeyValidity(const AccountPtr &account) const
869 {
870     QByteArray data = EncryptionHelper::generateRandom(64);
871 
872     Bio publicKeyBio;
873     QByteArray publicKeyPem = account->e2e()->_publicKey.toPem();
874     BIO_write(publicKeyBio, publicKeyPem.constData(), publicKeyPem.size());
875     auto publicKey = PKey::readPublicKey(publicKeyBio);
876 
877     auto encryptedData = EncryptionHelper::encryptStringAsymmetric(publicKey, data.toBase64());
878 
879     Bio privateKeyBio;
880     QByteArray privateKeyPem = account->e2e()->_privateKey;
881     BIO_write(privateKeyBio, privateKeyPem.constData(), privateKeyPem.size());
882     auto key = PKey::readPrivateKey(privateKeyBio);
883 
884     QByteArray decryptResult = QByteArray::fromBase64(EncryptionHelper::decryptStringAsymmetric( key, QByteArray::fromBase64(encryptedData)));
885 
886     if (data != decryptResult) {
887         qCInfo(lcCse()) << "invalid private key";
888         return false;
889     }
890 
891     return true;
892 }
893 
checkServerPublicKeyValidity(const QByteArray & serverPublicKeyString) const894 bool ClientSideEncryption::checkServerPublicKeyValidity(const QByteArray &serverPublicKeyString) const
895 {
896     Bio serverPublicKeyBio;
897     BIO_write(serverPublicKeyBio, serverPublicKeyString.constData(), serverPublicKeyString.size());
898     const auto serverPublicKey = PKey::readPrivateKey(serverPublicKeyBio);
899 
900     Bio certificateBio;
901     const auto certificatePem = _certificate.toPem();
902     BIO_write(certificateBio, certificatePem.constData(), certificatePem.size());
903     const auto x509Certificate = X509Certificate::readCertificate(certificateBio);
904     if (!x509Certificate) {
905         qCInfo(lcCse()) << "Client certificate is invalid. Could not check it against the server public key";
906         return false;
907     }
908 
909     if (X509_verify(x509Certificate, serverPublicKey) == 0) {
910         qCInfo(lcCse()) << "Client certificate is not valid against the server public key";
911         return false;
912     }
913 
914     qCDebug(lcCse()) << "Client certificate is valid against server public key";
915     return true;
916 }
917 
publicKeyFetched(Job * incoming)918 void ClientSideEncryption::publicKeyFetched(Job *incoming)
919 {
920     auto *readJob = static_cast<ReadPasswordJob *>(incoming);
921     auto account = readJob->property(accountProperty).value<AccountPtr>();
922     Q_ASSERT(account);
923 
924     // Error or no valid public key error out
925     if (readJob->error() != NoError || readJob->binaryData().length() == 0) {
926         getPublicKeyFromServer(account);
927         return;
928     }
929 
930     _certificate = QSslCertificate(readJob->binaryData(), QSsl::Pem);
931 
932     if (_certificate.isNull()) {
933         getPublicKeyFromServer(account);
934         return;
935     }
936 
937     _publicKey = _certificate.publicKey();
938 
939     qCInfo(lcCse()) << "Public key fetched from keychain";
940 
941     const QString kck = AbstractCredentials::keychainKey(
942                 account->url().toString(),
943                 account->credentials()->user() + e2e_private,
944                 account->id()
945     );
946 
947     auto *job = new ReadPasswordJob(Theme::instance()->appName());
948     job->setProperty(accountProperty, QVariant::fromValue(account));
949     job->setInsecureFallback(false);
950     job->setKey(kck);
951     connect(job, &ReadPasswordJob::finished, this, &ClientSideEncryption::privateKeyFetched);
952     job->start();
953 }
954 
privateKeyFetched(Job * incoming)955 void ClientSideEncryption::privateKeyFetched(Job *incoming)
956 {
957     auto *readJob = static_cast<ReadPasswordJob *>(incoming);
958     auto account = readJob->property(accountProperty).value<AccountPtr>();
959     Q_ASSERT(account);
960 
961     // Error or no valid public key error out
962     if (readJob->error() != NoError || readJob->binaryData().length() == 0) {
963         _certificate = QSslCertificate();
964         _publicKey = QSslKey();
965         getPublicKeyFromServer(account);
966         return;
967     }
968 
969     //_privateKey = QSslKey(readJob->binaryData(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
970     _privateKey = readJob->binaryData();
971 
972     if (_privateKey.isNull()) {
973         getPrivateKeyFromServer(account);
974         return;
975     }
976 
977     qCInfo(lcCse()) << "Private key fetched from keychain";
978 
979     const QString kck = AbstractCredentials::keychainKey(
980                 account->url().toString(),
981                 account->credentials()->user() + e2e_mnemonic,
982                 account->id()
983     );
984 
985     auto *job = new ReadPasswordJob(Theme::instance()->appName());
986     job->setProperty(accountProperty, QVariant::fromValue(account));
987     job->setInsecureFallback(false);
988     job->setKey(kck);
989     connect(job, &ReadPasswordJob::finished, this, &ClientSideEncryption::mnemonicKeyFetched);
990     job->start();
991 }
992 
mnemonicKeyFetched(QKeychain::Job * incoming)993 void ClientSideEncryption::mnemonicKeyFetched(QKeychain::Job *incoming)
994 {
995     auto *readJob = static_cast<ReadPasswordJob *>(incoming);
996     auto account = readJob->property(accountProperty).value<AccountPtr>();
997     Q_ASSERT(account);
998 
999     // Error or no valid public key error out
1000     if (readJob->error() != NoError || readJob->textData().length() == 0) {
1001         _certificate = QSslCertificate();
1002         _publicKey = QSslKey();
1003         _privateKey = QByteArray();
1004         getPublicKeyFromServer(account);
1005         return;
1006     }
1007 
1008     _mnemonic = readJob->textData();
1009 
1010     qCInfo(lcCse()) << "Mnemonic key fetched from keychain: " << _mnemonic;
1011 
1012     emit initializationFinished();
1013 }
1014 
writePrivateKey(const AccountPtr & account)1015 void ClientSideEncryption::writePrivateKey(const AccountPtr &account)
1016 {
1017     const QString kck = AbstractCredentials::keychainKey(
1018                 account->url().toString(),
1019                 account->credentials()->user() + e2e_private,
1020                 account->id()
1021     );
1022 
1023     auto *job = new WritePasswordJob(Theme::instance()->appName());
1024     job->setInsecureFallback(false);
1025     job->setKey(kck);
1026     job->setBinaryData(_privateKey);
1027     connect(job, &WritePasswordJob::finished, [](Job *incoming) {
1028         Q_UNUSED(incoming);
1029         qCInfo(lcCse()) << "Private key stored in keychain";
1030     });
1031     job->start();
1032 }
1033 
writeCertificate(const AccountPtr & account)1034 void ClientSideEncryption::writeCertificate(const AccountPtr &account)
1035 {
1036     const QString kck = AbstractCredentials::keychainKey(
1037                 account->url().toString(),
1038                 account->credentials()->user() + e2e_cert,
1039                 account->id()
1040     );
1041 
1042     auto *job = new WritePasswordJob(Theme::instance()->appName());
1043     job->setInsecureFallback(false);
1044     job->setKey(kck);
1045     job->setBinaryData(_certificate.toPem());
1046     connect(job, &WritePasswordJob::finished, [](Job *incoming) {
1047         Q_UNUSED(incoming);
1048         qCInfo(lcCse()) << "Certificate stored in keychain";
1049     });
1050     job->start();
1051 }
1052 
writeMnemonic(const AccountPtr & account)1053 void ClientSideEncryption::writeMnemonic(const AccountPtr &account)
1054 {
1055     const QString kck = AbstractCredentials::keychainKey(
1056                 account->url().toString(),
1057                 account->credentials()->user() + e2e_mnemonic,
1058                 account->id()
1059     );
1060 
1061     auto *job = new WritePasswordJob(Theme::instance()->appName());
1062     job->setInsecureFallback(false);
1063     job->setKey(kck);
1064     job->setTextData(_mnemonic);
1065     connect(job, &WritePasswordJob::finished, [](Job *incoming) {
1066         Q_UNUSED(incoming);
1067         qCInfo(lcCse()) << "Mnemonic stored in keychain";
1068     });
1069     job->start();
1070 }
1071 
forgetSensitiveData(const AccountPtr & account)1072 void ClientSideEncryption::forgetSensitiveData(const AccountPtr &account)
1073 {
1074     _privateKey = QByteArray();
1075     _certificate = QSslCertificate();
1076     _publicKey = QSslKey();
1077     _mnemonic = QString();
1078 
1079     auto startDeleteJob = [account](QString user) {
1080         auto *job = new DeletePasswordJob(Theme::instance()->appName());
1081         job->setInsecureFallback(false);
1082         job->setKey(AbstractCredentials::keychainKey(account->url().toString(), user, account->id()));
1083         job->start();
1084     };
1085 
1086     auto user = account->credentials()->user();
1087     startDeleteJob(user + e2e_private);
1088     startDeleteJob(user + e2e_cert);
1089     startDeleteJob(user + e2e_mnemonic);
1090 }
1091 
slotRequestMnemonic()1092 void ClientSideEncryption::slotRequestMnemonic()
1093 {
1094     emit showMnemonic(_mnemonic);
1095 }
1096 
generateKeyPair(const AccountPtr & account)1097 void ClientSideEncryption::generateKeyPair(const AccountPtr &account)
1098 {
1099     // AES/GCM/NoPadding,
1100     // metadataKeys with RSA/ECB/OAEPWithSHA-256AndMGF1Padding
1101     qCInfo(lcCse()) << "No public key, generating a pair.";
1102     const int rsaKeyLen = 2048;
1103 
1104 
1105     // Init RSA
1106     PKeyCtx ctx(EVP_PKEY_RSA);
1107 
1108     if(EVP_PKEY_keygen_init(ctx) <= 0) {
1109         qCInfo(lcCse()) << "Couldn't initialize the key generator";
1110         return;
1111     }
1112 
1113     if(EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, rsaKeyLen) <= 0) {
1114         qCInfo(lcCse()) << "Couldn't initialize the key generator bits";
1115         return;
1116     }
1117 
1118     auto localKeyPair = PKey::generate(ctx);
1119     if(!localKeyPair) {
1120         qCInfo(lcCse()) << "Could not generate the key";
1121         return;
1122     }
1123 
1124     qCInfo(lcCse()) << "Key correctly generated";
1125     qCInfo(lcCse()) << "Storing keys locally";
1126 
1127     Bio privKey;
1128     if (PEM_write_bio_PrivateKey(privKey, localKeyPair, nullptr, nullptr, 0, nullptr, nullptr) <= 0) {
1129         qCInfo(lcCse()) << "Could not read private key from bio.";
1130         return;
1131     }
1132     QByteArray key = BIO2ByteArray(privKey);
1133     //_privateKey = QSslKey(key, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
1134     _privateKey = key;
1135 
1136     qCInfo(lcCse()) << "Keys generated correctly, sending to server.";
1137     generateCSR(account, localKeyPair);
1138 }
1139 
generateCSR(const AccountPtr & account,EVP_PKEY * keyPair)1140 void ClientSideEncryption::generateCSR(const AccountPtr &account, EVP_PKEY *keyPair)
1141 {
1142     // OpenSSL expects const char.
1143     auto cnArray = account->davUser().toLocal8Bit();
1144     qCInfo(lcCse()) << "Getting the following array for the account Id" << cnArray;
1145 
1146     auto certParams = std::map<const char *, const char*>{
1147       {"C", "DE"},
1148       {"ST", "Baden-Wuerttemberg"},
1149       {"L", "Stuttgart"},
1150       {"O","Nextcloud"},
1151       {"CN", cnArray.constData()}
1152     };
1153 
1154     int ret = 0;
1155     int nVersion = 1;
1156 
1157     // 2. set version of x509 req
1158     X509_REQ *x509_req = X509_REQ_new();
1159     auto release_on_exit_x509_req = qScopeGuard([&] {
1160                 X509_REQ_free(x509_req);
1161             });
1162 
1163     ret = X509_REQ_set_version(x509_req, nVersion);
1164 
1165     // 3. set subject of x509 req
1166     auto x509_name = X509_REQ_get_subject_name(x509_req);
1167 
1168     for(const auto& v : certParams) {
1169         ret = X509_NAME_add_entry_by_txt(x509_name, v.first,  MBSTRING_ASC, (const unsigned char*) v.second, -1, -1, 0);
1170         if (ret != 1) {
1171             qCInfo(lcCse()) << "Error Generating the Certificate while adding" << v.first << v.second;
1172             return;
1173         }
1174     }
1175 
1176     ret = X509_REQ_set_pubkey(x509_req, keyPair);
1177     if (ret != 1){
1178         qCInfo(lcCse()) << "Error setting the public key on the csr";
1179         return;
1180     }
1181 
1182     ret = X509_REQ_sign(x509_req, keyPair, EVP_sha1());    // return x509_req->signature->length
1183     if (ret <= 0){
1184         qCInfo(lcCse()) << "Error setting the public key on the csr";
1185         return;
1186     }
1187 
1188     Bio out;
1189     ret = PEM_write_bio_X509_REQ(out, x509_req);
1190     QByteArray output = BIO2ByteArray(out);
1191 
1192     qCInfo(lcCse()) << "Returning the certificate";
1193     qCInfo(lcCse()) << output;
1194 
1195     auto job = new SignPublicKeyApiJob(account, e2eeBaseUrl() + "public-key", this);
1196     job->setCsr(output);
1197 
1198     connect(job, &SignPublicKeyApiJob::jsonReceived, [this, account](const QJsonDocument& json, int retCode) {
1199         if (retCode == 200) {
1200             QString cert = json.object().value("ocs").toObject().value("data").toObject().value("public-key").toString();
1201             _certificate = QSslCertificate(cert.toLocal8Bit(), QSsl::Pem);
1202             _publicKey = _certificate.publicKey();
1203             fetchAndValidatePublicKeyFromServer(account);
1204         }
1205         qCInfo(lcCse()) << retCode;
1206     });
1207     job->start();
1208 }
1209 
encryptPrivateKey(const AccountPtr & account)1210 void ClientSideEncryption::encryptPrivateKey(const AccountPtr &account)
1211 {
1212     QStringList list = WordList::getRandomWords(12);
1213     _mnemonic = list.join(' ');
1214     _newMnemonicGenerated = true;
1215     qCInfo(lcCse()) << "mnemonic Generated:" << _mnemonic;
1216 
1217     emit mnemonicGenerated(_mnemonic);
1218 
1219     QString passPhrase = list.join(QString()).toLower();
1220     qCInfo(lcCse()) << "Passphrase Generated:" << passPhrase;
1221 
1222     auto salt = EncryptionHelper::generateRandom(40);
1223     auto secretKey = EncryptionHelper::generatePassword(passPhrase, salt);
1224     auto cryptedText = EncryptionHelper::encryptPrivateKey(secretKey, EncryptionHelper::privateKeyToPem(_privateKey), salt);
1225 
1226     // Send private key to the server
1227     auto job = new StorePrivateKeyApiJob(account, e2eeBaseUrl() + "private-key", this);
1228     job->setPrivateKey(cryptedText);
1229     connect(job, &StorePrivateKeyApiJob::jsonReceived, [this, account](const QJsonDocument& doc, int retCode) {
1230         Q_UNUSED(doc);
1231         switch(retCode) {
1232             case 200:
1233                 qCInfo(lcCse()) << "Private key stored encrypted on server.";
1234                 writePrivateKey(account);
1235                 writeCertificate(account);
1236                 writeMnemonic(account);
1237                 emit initializationFinished();
1238                 break;
1239             default:
1240                 qCInfo(lcCse()) << "Store private key failed, return code:" << retCode;
1241         }
1242     });
1243     job->start();
1244 }
1245 
newMnemonicGenerated() const1246 bool ClientSideEncryption::newMnemonicGenerated() const
1247 {
1248     return _newMnemonicGenerated;
1249 }
1250 
decryptPrivateKey(const AccountPtr & account,const QByteArray & key)1251 void ClientSideEncryption::decryptPrivateKey(const AccountPtr &account, const QByteArray &key) {
1252     QString msg = tr("Please enter your end to end encryption passphrase:<br>"
1253                      "<br>"
1254                      "User: %2<br>"
1255                      "Account: %3<br>")
1256                       .arg(Utility::escape(account->credentials()->user()),
1257                            Utility::escape(account->displayName()));
1258 
1259     QInputDialog dialog;
1260     dialog.setWindowTitle(tr("Enter E2E passphrase"));
1261     dialog.setLabelText(msg);
1262     dialog.setTextEchoMode(QLineEdit::Normal);
1263 
1264     QString prev;
1265 
1266     while(true) {
1267         if (!prev.isEmpty()) {
1268             dialog.setTextValue(prev);
1269         }
1270         bool ok = dialog.exec();
1271         if (ok) {
1272             qCInfo(lcCse()) << "Got mnemonic:" << dialog.textValue();
1273             prev = dialog.textValue();
1274 
1275             _mnemonic = prev;
1276             QString mnemonic = prev.split(" ").join(QString()).toLower();
1277             qCInfo(lcCse()) << "mnemonic:" << mnemonic;
1278 
1279             // split off salt
1280             const auto salt = EncryptionHelper::extractPrivateKeySalt(key);
1281 
1282             auto pass = EncryptionHelper::generatePassword(mnemonic, salt);
1283             qCInfo(lcCse()) << "Generated key:" << pass;
1284 
1285             QByteArray privateKey = EncryptionHelper::decryptPrivateKey(pass, key);
1286             //_privateKey = QSslKey(privateKey, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
1287             _privateKey = privateKey;
1288 
1289             qCInfo(lcCse()) << "Private key: " << _privateKey;
1290 
1291             if (!_privateKey.isNull() && checkPublicKeyValidity(account)) {
1292                 writePrivateKey(account);
1293                 writeCertificate(account);
1294                 writeMnemonic(account);
1295                 break;
1296             }
1297         } else {
1298             _mnemonic = QString();
1299             _privateKey = QByteArray();
1300             qCInfo(lcCse()) << "Cancelled";
1301             break;
1302         }
1303     }
1304 
1305     emit initializationFinished();
1306 }
1307 
getPrivateKeyFromServer(const AccountPtr & account)1308 void ClientSideEncryption::getPrivateKeyFromServer(const AccountPtr &account)
1309 {
1310     qCInfo(lcCse()) << "Retrieving private key from server";
1311     auto job = new JsonApiJob(account, e2eeBaseUrl() + "private-key", this);
1312     connect(job, &JsonApiJob::jsonReceived, [this, account](const QJsonDocument& doc, int retCode) {
1313             if (retCode == 200) {
1314                 QString key = doc.object()["ocs"].toObject()["data"].toObject()["private-key"].toString();
1315                 qCInfo(lcCse()) << key;
1316                 qCInfo(lcCse()) << "Found private key, lets decrypt it!";
1317                 decryptPrivateKey(account, key.toLocal8Bit());
1318             } else if (retCode == 404) {
1319                 qCInfo(lcCse()) << "No private key on the server: setup is incomplete.";
1320             } else {
1321                 qCInfo(lcCse()) << "Error while requesting public key: " << retCode;
1322             }
1323     });
1324     job->start();
1325 }
1326 
getPublicKeyFromServer(const AccountPtr & account)1327 void ClientSideEncryption::getPublicKeyFromServer(const AccountPtr &account)
1328 {
1329     qCInfo(lcCse()) << "Retrieving public key from server";
1330     auto job = new JsonApiJob(account, e2eeBaseUrl() + "public-key", this);
1331     connect(job, &JsonApiJob::jsonReceived, [this, account](const QJsonDocument& doc, int retCode) {
1332             if (retCode == 200) {
1333                 QString publicKey = doc.object()["ocs"].toObject()["data"].toObject()["public-keys"].toObject()[account->davUser()].toString();
1334                 _certificate = QSslCertificate(publicKey.toLocal8Bit(), QSsl::Pem);
1335                 _publicKey = _certificate.publicKey();
1336                 qCInfo(lcCse()) << "Found Public key, requesting Server Public Key. Public key:" << publicKey;
1337                 fetchAndValidatePublicKeyFromServer(account);
1338             } else if (retCode == 404) {
1339                 qCInfo(lcCse()) << "No public key on the server";
1340                 generateKeyPair(account);
1341             } else {
1342                 qCInfo(lcCse()) << "Error while requesting public key: " << retCode;
1343             }
1344     });
1345     job->start();
1346 }
1347 
fetchAndValidatePublicKeyFromServer(const AccountPtr & account)1348 void ClientSideEncryption::fetchAndValidatePublicKeyFromServer(const AccountPtr &account)
1349 {
1350     qCInfo(lcCse()) << "Retrieving public key from server";
1351     auto job = new JsonApiJob(account, e2eeBaseUrl() + "server-key", this);
1352     connect(job, &JsonApiJob::jsonReceived, [this, account](const QJsonDocument& doc, int retCode) {
1353         if (retCode == 200) {
1354             const auto serverPublicKey = doc.object()["ocs"].toObject()["data"].toObject()["public-key"].toString().toLatin1();
1355             qCInfo(lcCse()) << "Found Server Public key, checking it. Server public key:" << serverPublicKey;
1356             if (checkServerPublicKeyValidity(serverPublicKey)) {
1357                 if (_privateKey.isEmpty()) {
1358                     qCInfo(lcCse()) << "Valid Server Public key, requesting Private Key.";
1359                     getPrivateKeyFromServer(account);
1360                 } else {
1361                     qCInfo(lcCse()) << "Certificate saved, Encrypting Private Key.";
1362                     encryptPrivateKey(account);
1363                 }
1364             } else {
1365                 qCInfo(lcCse()) << "Error invalid server public key";
1366                 _certificate = QSslCertificate();
1367                 _publicKey = QSslKey();
1368                 _privateKey = QByteArray();
1369                 getPublicKeyFromServer(account);
1370                 return;
1371             }
1372         } else {
1373             qCInfo(lcCse()) << "Error while requesting server public key: " << retCode;
1374         }
1375     });
1376     job->start();
1377 }
1378 
FolderMetadata(AccountPtr account,const QByteArray & metadata,int statusCode)1379 FolderMetadata::FolderMetadata(AccountPtr account, const QByteArray& metadata, int statusCode) : _account(account)
1380 {
1381     if (metadata.isEmpty() || statusCode == 404) {
1382         qCInfo(lcCseMetadata()) << "Setupping Empty Metadata";
1383         setupEmptyMetadata();
1384     } else {
1385         qCInfo(lcCseMetadata()) << "Setting up existing metadata";
1386         setupExistingMetadata(metadata);
1387     }
1388 }
1389 
setupExistingMetadata(const QByteArray & metadata)1390 void FolderMetadata::setupExistingMetadata(const QByteArray& metadata)
1391 {
1392   /* This is the json response from the server, it contains two extra objects that we are *not* interested.
1393   * ocs and data.
1394   */
1395   QJsonDocument doc = QJsonDocument::fromJson(metadata);
1396   qCInfo(lcCseMetadata()) << doc.toJson(QJsonDocument::Compact);
1397 
1398   // The metadata is being retrieved as a string stored in a json.
1399   // This *seems* to be broken but the RFC doesn't explicits how it wants.
1400   // I'm currently unsure if this is error on my side or in the server implementation.
1401   // And because inside of the meta-data there's an object called metadata, without '-'
1402   // make it really different.
1403 
1404   QString metaDataStr = doc.object()["ocs"]
1405                          .toObject()["data"]
1406                          .toObject()["meta-data"]
1407                          .toString();
1408 
1409   QJsonDocument metaDataDoc = QJsonDocument::fromJson(metaDataStr.toLocal8Bit());
1410   QJsonObject metadataObj = metaDataDoc.object()["metadata"].toObject();
1411   QJsonObject metadataKeys = metadataObj["metadataKeys"].toObject();
1412   QByteArray sharing = metadataObj["sharing"].toString().toLocal8Bit();
1413   QJsonObject files = metaDataDoc.object()["files"].toObject();
1414 
1415   QJsonDocument debugHelper;
1416   debugHelper.setObject(metadataKeys);
1417   qCDebug(lcCse) << "Keys: " << debugHelper.toJson(QJsonDocument::Compact);
1418 
1419   // Iterate over the document to store the keys. I'm unsure that the keys are in order,
1420   // perhaps it's better to store a map instead of a vector, perhaps this just doesn't matter.
1421   for(auto it = metadataKeys.constBegin(), end = metadataKeys.constEnd(); it != end; it++) {
1422     QByteArray currB64Pass = it.value().toString().toLocal8Bit();
1423     /*
1424      * We have to base64 decode the metadatakey here. This was a misunderstanding in the RFC
1425      * Now we should be compatible with Android and IOS. Maybe we can fix it later.
1426      */
1427     QByteArray b64DecryptedKey = decryptMetadataKey(currB64Pass);
1428     if (b64DecryptedKey.isEmpty()) {
1429       qCDebug(lcCse()) << "Could not decrypt metadata for key" << it.key();
1430       continue;
1431     }
1432 
1433     QByteArray decryptedKey = QByteArray::fromBase64(b64DecryptedKey);
1434     _metadataKeys.insert(it.key().toInt(), decryptedKey);
1435   }
1436 
1437   // Cool, We actually have the key, we can decrypt the rest of the metadata.
1438   qCDebug(lcCse) << "Sharing: " << sharing;
1439   if (sharing.size()) {
1440       auto sharingDecrypted = decryptJsonObject(sharing, _metadataKeys.last());
1441       qCDebug(lcCse) << "Sharing Decrypted" << sharingDecrypted;
1442 
1443       //Sharing is also a JSON object, so extract it and populate.
1444       auto sharingDoc = QJsonDocument::fromJson(sharingDecrypted);
1445       auto sharingObj = sharingDoc.object();
1446       for (auto it = sharingObj.constBegin(), end = sharingObj.constEnd(); it != end; it++) {
1447         _sharing.push_back({it.key(), it.value().toString()});
1448       }
1449   } else {
1450       qCDebug(lcCse) << "Skipping sharing section since it is empty";
1451   }
1452 
1453     for (auto it = files.constBegin(), end = files.constEnd(); it != end; it++) {
1454         EncryptedFile file;
1455         file.encryptedFilename = it.key();
1456 
1457         auto fileObj = it.value().toObject();
1458         file.metadataKey = fileObj["metadataKey"].toInt();
1459         file.authenticationTag = QByteArray::fromBase64(fileObj["authenticationTag"].toString().toLocal8Bit());
1460         file.initializationVector = QByteArray::fromBase64(fileObj["initializationVector"].toString().toLocal8Bit());
1461 
1462         //Decrypt encrypted part
1463         QByteArray key = _metadataKeys[file.metadataKey];
1464         auto encryptedFile = fileObj["encrypted"].toString().toLocal8Bit();
1465         auto decryptedFile = decryptJsonObject(encryptedFile, key);
1466         auto decryptedFileDoc = QJsonDocument::fromJson(decryptedFile);
1467         auto decryptedFileObj = decryptedFileDoc.object();
1468 
1469         file.originalFilename = decryptedFileObj["filename"].toString();
1470         file.encryptionKey = QByteArray::fromBase64(decryptedFileObj["key"].toString().toLocal8Bit());
1471         file.mimetype = decryptedFileObj["mimetype"].toString().toLocal8Bit();
1472         file.fileVersion = decryptedFileObj["version"].toInt();
1473 
1474         // In case we wrongly stored "inode/directory" we try to recover from it
1475         if (file.mimetype == QByteArrayLiteral("inode/directory")) {
1476             file.mimetype = QByteArrayLiteral("httpd/unix-directory");
1477         }
1478 
1479         _files.push_back(file);
1480     }
1481 }
1482 
1483 // RSA/ECB/OAEPWithSHA-256AndMGF1Padding using private / public key.
encryptMetadataKey(const QByteArray & data) const1484 QByteArray FolderMetadata::encryptMetadataKey(const QByteArray& data) const
1485 {
1486     Bio publicKeyBio;
1487     QByteArray publicKeyPem = _account->e2e()->_publicKey.toPem();
1488     BIO_write(publicKeyBio, publicKeyPem.constData(), publicKeyPem.size());
1489     auto publicKey = PKey::readPublicKey(publicKeyBio);
1490 
1491     // The metadata key is binary so base64 encode it first
1492     return EncryptionHelper::encryptStringAsymmetric(publicKey, data.toBase64());
1493 }
1494 
decryptMetadataKey(const QByteArray & encryptedMetadata) const1495 QByteArray FolderMetadata::decryptMetadataKey(const QByteArray& encryptedMetadata) const
1496 {
1497     Bio privateKeyBio;
1498     QByteArray privateKeyPem = _account->e2e()->_privateKey;
1499     BIO_write(privateKeyBio, privateKeyPem.constData(), privateKeyPem.size());
1500     auto key = PKey::readPrivateKey(privateKeyBio);
1501 
1502     // Also base64 decode the result
1503     QByteArray decryptResult = EncryptionHelper::decryptStringAsymmetric(
1504                     key, QByteArray::fromBase64(encryptedMetadata));
1505 
1506     if (decryptResult.isEmpty())
1507     {
1508       qCDebug(lcCse()) << "ERROR. Could not decrypt the metadata key";
1509       return {};
1510     }
1511     return QByteArray::fromBase64(decryptResult);
1512 }
1513 
1514 // AES/GCM/NoPadding (128 bit key size)
encryptJsonObject(const QByteArray & obj,const QByteArray pass) const1515 QByteArray FolderMetadata::encryptJsonObject(const QByteArray& obj, const QByteArray pass) const
1516 {
1517     return EncryptionHelper::encryptStringSymmetric(pass, obj);
1518 }
1519 
decryptJsonObject(const QByteArray & encryptedMetadata,const QByteArray & pass) const1520 QByteArray FolderMetadata::decryptJsonObject(const QByteArray& encryptedMetadata, const QByteArray& pass) const
1521 {
1522     return EncryptionHelper::decryptStringSymmetric(pass, encryptedMetadata);
1523 }
1524 
setupEmptyMetadata()1525 void FolderMetadata::setupEmptyMetadata() {
1526     qCDebug(lcCse) << "Settint up empty metadata";
1527     QByteArray newMetadataPass = EncryptionHelper::generateRandom(16);
1528     _metadataKeys.insert(0, newMetadataPass);
1529 
1530     QString publicKey = _account->e2e()->_publicKey.toPem().toBase64();
1531     QString displayName = _account->displayName();
1532 
1533     _sharing.append({displayName, publicKey});
1534 }
1535 
encryptedMetadata()1536 QByteArray FolderMetadata::encryptedMetadata() {
1537     qCDebug(lcCse) << "Generating metadata";
1538 
1539     QJsonObject metadataKeys;
1540     for (auto it = _metadataKeys.constBegin(), end = _metadataKeys.constEnd(); it != end; it++) {
1541         /*
1542          * We have to already base64 encode the metadatakey here. This was a misunderstanding in the RFC
1543          * Now we should be compatible with Android and IOS. Maybe we can fix it later.
1544          */
1545         const QByteArray encryptedKey = encryptMetadataKey(it.value().toBase64());
1546         metadataKeys.insert(QString::number(it.key()), QString(encryptedKey));
1547     }
1548 
1549     /* NO SHARING IN V1
1550     QJsonObject recepients;
1551     for (auto it = _sharing.constBegin(), end = _sharing.constEnd(); it != end; it++) {
1552         recepients.insert(it->first, it->second);
1553     }
1554     QJsonDocument recepientDoc;
1555     recepientDoc.setObject(recepients);
1556     QString sharingEncrypted = encryptJsonObject(recepientDoc.toJson(QJsonDocument::Compact), _metadataKeys.last());
1557     */
1558 
1559     QJsonObject metadata = {
1560       {"metadataKeys", metadataKeys},
1561       // {"sharing", sharingEncrypted},
1562       {"version", 1}
1563     };
1564 
1565     QJsonObject files;
1566     for (auto it = _files.constBegin(), end = _files.constEnd(); it != end; it++) {
1567         QJsonObject encrypted;
1568         encrypted.insert("key", QString(it->encryptionKey.toBase64()));
1569         encrypted.insert("filename", it->originalFilename);
1570         encrypted.insert("mimetype", QString(it->mimetype));
1571         encrypted.insert("version", it->fileVersion);
1572         QJsonDocument encryptedDoc;
1573         encryptedDoc.setObject(encrypted);
1574 
1575         QString encryptedEncrypted = encryptJsonObject(encryptedDoc.toJson(QJsonDocument::Compact), _metadataKeys.last());
1576         if (encryptedEncrypted.isEmpty()) {
1577           qCDebug(lcCse) << "Metadata generation failed!";
1578         }
1579 
1580         QJsonObject file;
1581         file.insert("encrypted", encryptedEncrypted);
1582         file.insert("initializationVector", QString(it->initializationVector.toBase64()));
1583         file.insert("authenticationTag", QString(it->authenticationTag.toBase64()));
1584         file.insert("metadataKey", _metadataKeys.lastKey());
1585 
1586         files.insert(it->encryptedFilename, file);
1587     }
1588 
1589     QJsonObject metaObject = {
1590       {"metadata", metadata},
1591       {"files", files}
1592     };
1593 
1594     QJsonDocument internalMetadata;
1595     internalMetadata.setObject(metaObject);
1596     return internalMetadata.toJson();
1597 }
1598 
addEncryptedFile(const EncryptedFile & f)1599 void FolderMetadata::addEncryptedFile(const EncryptedFile &f) {
1600 
1601     for (int i = 0; i < _files.size(); i++) {
1602         if (_files.at(i).originalFilename == f.originalFilename) {
1603             _files.removeAt(i);
1604             break;
1605         }
1606     }
1607 
1608     _files.append(f);
1609 }
1610 
removeEncryptedFile(const EncryptedFile & f)1611 void FolderMetadata::removeEncryptedFile(const EncryptedFile &f)
1612 {
1613     for (int i = 0; i < _files.size(); i++) {
1614         if (_files.at(i).originalFilename == f.originalFilename) {
1615             _files.removeAt(i);
1616             break;
1617         }
1618     }
1619 }
1620 
removeAllEncryptedFiles()1621 void FolderMetadata::removeAllEncryptedFiles()
1622 {
1623     _files.clear();
1624 }
1625 
files() const1626 QVector<EncryptedFile> FolderMetadata::files() const {
1627     return _files;
1628 }
1629 
fileEncryption(const QByteArray & key,const QByteArray & iv,QFile * input,QFile * output,QByteArray & returnTag)1630 bool EncryptionHelper::fileEncryption(const QByteArray &key, const QByteArray &iv, QFile *input, QFile *output, QByteArray& returnTag)
1631 {
1632     if (!input->open(QIODevice::ReadOnly)) {
1633       qCDebug(lcCse) << "Could not open input file for reading" << input->errorString();
1634     }
1635     if (!output->open(QIODevice::WriteOnly)) {
1636       qCDebug(lcCse) << "Could not oppen output file for writing" << output->errorString();
1637     }
1638 
1639     // Init
1640     CipherCtx ctx;
1641 
1642     /* Create and initialise the context */
1643     if(!ctx) {
1644         qCInfo(lcCse()) << "Could not create context";
1645         return false;
1646     }
1647 
1648     /* Initialise the decryption operation. */
1649     if(!EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) {
1650         qCInfo(lcCse()) << "Could not init cipher";
1651         return false;
1652     }
1653 
1654     EVP_CIPHER_CTX_set_padding(ctx, 0);
1655 
1656     /* Set IV length. */
1657     if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size(), nullptr)) {
1658         qCInfo(lcCse()) << "Could not set iv length";
1659         return false;
1660     }
1661 
1662     /* Initialise key and IV */
1663     if(!EVP_EncryptInit_ex(ctx, nullptr, nullptr, (const unsigned char *)key.constData(), (const unsigned char *)iv.constData())) {
1664         qCInfo(lcCse()) << "Could not set key and iv";
1665         return false;
1666     }
1667 
1668     QByteArray out(blockSize + OCC::Constants::e2EeTagSize - 1, '\0');
1669     int len = 0;
1670     int total_len = 0;
1671 
1672     qCDebug(lcCse) << "Starting to encrypt the file" << input->fileName() << input->atEnd();
1673     while(!input->atEnd()) {
1674         const auto data = input->read(blockSize);
1675 
1676         if (data.size() == 0) {
1677             qCInfo(lcCse()) << "Could not read data from file";
1678             return false;
1679         }
1680 
1681         if(!EVP_EncryptUpdate(ctx, unsignedData(out), &len, (unsigned char *)data.constData(), data.size())) {
1682             qCInfo(lcCse()) << "Could not encrypt";
1683             return false;
1684         }
1685 
1686         output->write(out, len);
1687         total_len += len;
1688     }
1689 
1690     if(1 != EVP_EncryptFinal_ex(ctx, unsignedData(out), &len)) {
1691         qCInfo(lcCse()) << "Could finalize encryption";
1692         return false;
1693     }
1694     output->write(out, len);
1695     total_len += len;
1696 
1697     /* Get the e2EeTag */
1698     QByteArray e2EeTag(OCC::Constants::e2EeTagSize, '\0');
1699     if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, OCC::Constants::e2EeTagSize, unsignedData(e2EeTag))) {
1700         qCInfo(lcCse()) << "Could not get e2EeTag";
1701         return false;
1702     }
1703 
1704     returnTag = e2EeTag;
1705     output->write(e2EeTag, OCC::Constants::e2EeTagSize);
1706 
1707     input->close();
1708     output->close();
1709     qCDebug(lcCse) << "File Encrypted Successfully";
1710     return true;
1711 }
1712 
fileDecryption(const QByteArray & key,const QByteArray & iv,QFile * input,QFile * output)1713 bool EncryptionHelper::fileDecryption(const QByteArray &key, const QByteArray& iv,
1714                                QFile *input, QFile *output)
1715 {
1716     input->open(QIODevice::ReadOnly);
1717     output->open(QIODevice::WriteOnly);
1718 
1719     // Init
1720     CipherCtx ctx;
1721 
1722     /* Create and initialise the context */
1723     if(!ctx) {
1724         qCInfo(lcCse()) << "Could not create context";
1725         return false;
1726     }
1727 
1728     /* Initialise the decryption operation. */
1729     if(!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) {
1730         qCInfo(lcCse()) << "Could not init cipher";
1731         return false;
1732     }
1733 
1734     EVP_CIPHER_CTX_set_padding(ctx, 0);
1735 
1736     /* Set IV length. */
1737     if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN,  iv.size(), nullptr)) {
1738         qCInfo(lcCse()) << "Could not set iv length";
1739         return false;
1740     }
1741 
1742     /* Initialise key and IV */
1743     if(!EVP_DecryptInit_ex(ctx, nullptr, nullptr, (const unsigned char *) key.constData(), (const unsigned char *) iv.constData())) {
1744         qCInfo(lcCse()) << "Could not set key and iv";
1745         return false;
1746     }
1747 
1748     qint64 size = input->size() - OCC::Constants::e2EeTagSize;
1749 
1750     QByteArray out(blockSize + OCC::Constants::e2EeTagSize - 1, '\0');
1751     int len = 0;
1752 
1753     while(input->pos() < size) {
1754 
1755         auto toRead = size - input->pos();
1756         if (toRead > blockSize) {
1757             toRead = blockSize;
1758         }
1759 
1760         QByteArray data = input->read(toRead);
1761 
1762         if (data.size() == 0) {
1763             qCInfo(lcCse()) << "Could not read data from file";
1764             return false;
1765         }
1766 
1767         if(!EVP_DecryptUpdate(ctx, unsignedData(out), &len, (unsigned char *)data.constData(), data.size())) {
1768             qCInfo(lcCse()) << "Could not decrypt";
1769             return false;
1770         }
1771 
1772         output->write(out, len);
1773     }
1774 
1775     const QByteArray e2EeTag = input->read(OCC::Constants::e2EeTagSize);
1776 
1777     /* Set expected e2EeTag value. Works in OpenSSL 1.0.1d and later */
1778     if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, e2EeTag.size(), (unsigned char *)e2EeTag.constData())) {
1779         qCInfo(lcCse()) << "Could not set expected e2EeTag";
1780         return false;
1781     }
1782 
1783     if(1 != EVP_DecryptFinal_ex(ctx, unsignedData(out), &len)) {
1784         qCInfo(lcCse()) << "Could finalize decryption";
1785         return false;
1786     }
1787     output->write(out, len);
1788 
1789     input->close();
1790     output->close();
1791     return true;
1792 }
1793 
StreamingDecryptor(const QByteArray & key,const QByteArray & iv,quint64 totalSize)1794 EncryptionHelper::StreamingDecryptor::StreamingDecryptor(const QByteArray &key, const QByteArray &iv, quint64 totalSize) : _totalSize(totalSize)
1795 {
1796     if (_ctx && !key.isEmpty() && !iv.isEmpty() && totalSize > 0) {
1797         _isInitialized = true;
1798 
1799         /* Initialize the decryption operation. */
1800         if(!EVP_DecryptInit_ex(_ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) {
1801             qCritical(lcCse()) << "Could not init cipher";
1802             _isInitialized = false;
1803         }
1804 
1805         EVP_CIPHER_CTX_set_padding(_ctx, 0);
1806 
1807         /* Set IV length. */
1808         if(!EVP_CIPHER_CTX_ctrl(_ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size(), nullptr)) {
1809             qCritical(lcCse()) << "Could not set iv length";
1810             _isInitialized = false;
1811         }
1812 
1813         /* Initialize key and IV */
1814         if(!EVP_DecryptInit_ex(_ctx, nullptr, nullptr, reinterpret_cast<const unsigned char*>(key.constData()), reinterpret_cast<const unsigned char*>(iv.constData()))) {
1815             qCritical(lcCse()) << "Could not set key and iv";
1816             _isInitialized = false;
1817         }
1818     }
1819 }
1820 
chunkDecryption(const char * input,quint64 chunkSize)1821 QByteArray EncryptionHelper::StreamingDecryptor::chunkDecryption(const char *input, quint64 chunkSize)
1822 {
1823     QByteArray byteArray;
1824     QBuffer buffer(&byteArray);
1825     buffer.open(QIODevice::WriteOnly);
1826 
1827     Q_ASSERT(isInitialized());
1828     if (!isInitialized()) {
1829         qCritical(lcCse()) << "Decryption failed. Decryptor is not initialized!";
1830         return QByteArray();
1831     }
1832 
1833     Q_ASSERT(buffer.isOpen() && buffer.isWritable());
1834     if (!buffer.isOpen() || !buffer.isWritable()) {
1835         qCritical(lcCse()) << "Decryption failed. Incorrect output device!";
1836         return QByteArray();
1837     }
1838 
1839     Q_ASSERT(input);
1840     if (!input) {
1841         qCritical(lcCse()) << "Decryption failed. Incorrect input!";
1842         return QByteArray();
1843     }
1844 
1845     Q_ASSERT(chunkSize > 0);
1846     if (chunkSize <= 0) {
1847         qCritical(lcCse()) << "Decryption failed. Incorrect chunkSize!";
1848         return QByteArray();
1849     }
1850 
1851     if (_decryptedSoFar == 0) {
1852         qCDebug(lcCse()) << "Decryption started";
1853     }
1854 
1855     Q_ASSERT(_decryptedSoFar + chunkSize <= _totalSize);
1856     if (_decryptedSoFar + chunkSize > _totalSize) {
1857         qCritical(lcCse()) << "Decryption failed. Chunk is out of range!";
1858         return QByteArray();
1859     }
1860 
1861     Q_ASSERT(_decryptedSoFar + chunkSize < OCC::Constants::e2EeTagSize || _totalSize - OCC::Constants::e2EeTagSize >= _decryptedSoFar + chunkSize - OCC::Constants::e2EeTagSize);
1862     if (_decryptedSoFar + chunkSize > OCC::Constants::e2EeTagSize && _totalSize - OCC::Constants::e2EeTagSize < _decryptedSoFar + chunkSize - OCC::Constants::e2EeTagSize) {
1863         qCritical(lcCse()) << "Decryption failed. Incorrect chunk!";
1864         return QByteArray();
1865     }
1866 
1867     const bool isLastChunk = _decryptedSoFar + chunkSize == _totalSize;
1868 
1869     // last OCC::Constants::e2EeTagSize bytes is ALWAYS a e2EeTag!!!
1870     const qint64 size = isLastChunk ? chunkSize - OCC::Constants::e2EeTagSize : chunkSize;
1871 
1872     // either the size is more than 0 and an e2EeTag is at the end of chunk, or, chunk is the e2EeTag itself
1873     Q_ASSERT(size > 0 || chunkSize == OCC::Constants::e2EeTagSize);
1874     if (size <= 0 && chunkSize != OCC::Constants::e2EeTagSize) {
1875         qCritical(lcCse()) << "Decryption failed. Invalid input size: " << size << " !";
1876         return QByteArray();
1877     }
1878 
1879     qint64 bytesWritten = 0;
1880     qint64 inputPos = 0;
1881 
1882     QByteArray decryptedBlock(blockSize + OCC::Constants::e2EeTagSize - 1, '\0');
1883 
1884     while(inputPos < size) {
1885         // read blockSize or less bytes
1886         const QByteArray encryptedBlock(input + inputPos, qMin(size - inputPos, blockSize));
1887 
1888         if (encryptedBlock.size() == 0) {
1889             qCritical(lcCse()) << "Could not read data from the input buffer.";
1890             return QByteArray();
1891         }
1892 
1893         int outLen = 0;
1894 
1895         if(!EVP_DecryptUpdate(_ctx, unsignedData(decryptedBlock), &outLen, reinterpret_cast<const unsigned char*>(encryptedBlock.data()), encryptedBlock.size())) {
1896             qCritical(lcCse()) << "Could not decrypt";
1897             return QByteArray();
1898         }
1899 
1900         const auto writtenToOutput = buffer.write(decryptedBlock, outLen);
1901 
1902         Q_ASSERT(writtenToOutput == outLen);
1903         if (writtenToOutput != outLen) {
1904             qCritical(lcCse()) << "Failed to write decrypted data to device.";
1905             return QByteArray();
1906         }
1907 
1908         bytesWritten += writtenToOutput;
1909 
1910         // advance input position for further read
1911         inputPos += encryptedBlock.size();
1912 
1913         _decryptedSoFar += encryptedBlock.size();
1914     }
1915 
1916     if (isLastChunk) {
1917         // if it's a last chunk, we'd need to read a e2EeTag at the end and finalize the decryption
1918 
1919         Q_ASSERT(chunkSize - inputPos == OCC::Constants::e2EeTagSize);
1920         if (chunkSize - inputPos != OCC::Constants::e2EeTagSize) {
1921             qCritical(lcCse()) << "Decryption failed. e2EeTag is missing!";
1922             return QByteArray();
1923         }
1924 
1925         int outLen = 0;
1926 
1927         QByteArray e2EeTag = QByteArray(input + inputPos, OCC::Constants::e2EeTagSize);
1928 
1929         /* Set expected e2EeTag value. Works in OpenSSL 1.0.1d and later */
1930         if(!EVP_CIPHER_CTX_ctrl(_ctx, EVP_CTRL_GCM_SET_TAG, e2EeTag.size(), reinterpret_cast<unsigned char*>(e2EeTag.data()))) {
1931             qCritical(lcCse()) << "Could not set expected e2EeTag";
1932             return QByteArray();
1933         }
1934 
1935         if(1 != EVP_DecryptFinal_ex(_ctx, unsignedData(decryptedBlock), &outLen)) {
1936             qCritical(lcCse()) << "Could finalize decryption";
1937             return QByteArray();
1938         }
1939 
1940         const auto writtenToOutput = buffer.write(decryptedBlock, outLen);
1941 
1942         Q_ASSERT(writtenToOutput == outLen);
1943         if (writtenToOutput != outLen) {
1944             qCritical(lcCse()) << "Failed to write decrypted data to device.";
1945             return QByteArray();
1946         }
1947 
1948         bytesWritten += writtenToOutput;
1949 
1950         _decryptedSoFar += OCC::Constants::e2EeTagSize;
1951 
1952         _isFinished = true;
1953     }
1954 
1955     if (isFinished()) {
1956         qCDebug(lcCse()) << "Decryption complete";
1957     }
1958 
1959     return byteArray;
1960 }
1961 
isInitialized() const1962 bool EncryptionHelper::StreamingDecryptor::isInitialized() const
1963 {
1964     return _isInitialized;
1965 }
1966 
isFinished() const1967 bool EncryptionHelper::StreamingDecryptor::isFinished() const
1968 {
1969     return _isFinished;
1970 }
1971 }
1972