@@ -48,69 +48,16 @@ using namespace ria::qdigidoc4;
4848
4949Q_LOGGING_CATEGORY (CRYPTO, " CRYPTO" )
5050
51- auto toHex = [](const std::vector<uint8_t >& data) -> QString {
52- return QByteArray::fromRawData (reinterpret_cast <const char *>(data.data ()), data.size ()).toHex ();
53- };
54-
5551struct CryptoDoc::Private
5652{
5753 bool isEncryptedWarning (const QString &title) const ;
5854
59- inline libcdoc::result_t encrypt () {
60- libcdoc::result_t res = waitFor ([&]{
61- qCDebug (CRYPTO) << " CryptoDoc::Private::encrypt, thread id: " << QThread::currentThreadId ();
62- qCDebug (CRYPTO) << " Encrypt" << fileName;
63- libcdoc::OStreamConsumer ofs (fileName.toStdString ());
64- if (ofs.isError ())
65- return (libcdoc::result_t ) libcdoc::OUTPUT_ERROR;
66- StreamListSource slsrc (files);
67- std::vector<libcdoc::Recipient> enc_keys;
68- std::string keyserver_id;
69- if (Settings::CDOC2_DEFAULT && Settings::CDOC2_USE_KEYSERVER) {
70- keyserver_id = Settings::CDOC2_DEFAULT_KEYSERVER;
71- }
72- for (auto &key : keys) {
73- QByteArray ba = key.rcpt_cert .toDer ();
74- if (keyserver_id.empty ()) {
75- enc_keys.push_back (
76- libcdoc::Recipient::makeCertificate ({}, {ba.cbegin (), ba.cend ()}));
77- } else {
78- enc_keys.push_back (
79- libcdoc::Recipient::makeServer ({}, {ba.cbegin (), ba.cend ()}, keyserver_id));
80- }
81- }
82- if (!crypto.secret .empty ()) {
83- auto key = libcdoc::Recipient::makeSymmetric (label.toStdString (), 65536 );
84- enc_keys.push_back (key);
85- }
86- libcdoc::CDocWriter *writer = libcdoc::CDocWriter::createWriter (
87- Settings::CDOC2_DEFAULT ? 2 : 1 , &ofs, false , &conf, &crypto, &network);
88- libcdoc::result_t result = writer->encrypt (slsrc, enc_keys);
89- if (result != libcdoc::OK) {
90- writer_last_error = writer->getLastErrorStr ();
91- std::filesystem::remove (std::filesystem::path (fileName.toStdString ()));
92- }
93- qCDebug (CRYPTO) << " Encryption result: " << result << " " << QString::fromStdString (writer->getLastErrorStr ());
94- delete writer;
95- ofs.close ();
96- if (result == libcdoc::OK) {
97- // Encryption successful, open new reader
98- reader = createCDocReader (fileName.toStdString ());
99- }
100- return result;
101- });
102- return res;
103- }
104-
10555 std::unique_ptr<libcdoc::CDocReader> reader;
106- std::string writer_last_error;
10756
10857 QString fileName;
10958 bool isEncrypted () const { return reader != nullptr ; }
11059 CDocumentModel *documents = new CDocumentModel (this );
11160 QStringList tempFiles;
112- // Encryption data
113- QString label;
11461
11562 // libcdoc handlers
11663 DDConfiguration conf;
@@ -120,23 +67,14 @@ struct CryptoDoc::Private
12067 std::vector<IOEntry> files;
12168 std::vector<CDKey> keys;
12269
123- const std::vector<IOEntry> &getFiles () {
124- return files;
125- }
126- std::unique_ptr<libcdoc::CDocReader> createCDocReader (const std::string& filename) {
127- std::unique_ptr<libcdoc::CDocReader> r (libcdoc::CDocReader::createReader (filename, &conf, &crypto, &network));
128- if (!r) {
129- WarningDialog::create ()
130- ->withTitle (CryptoDoc::tr (" Failed to open document" ))
131- ->withText (CryptoDoc::tr (" Unsupported file format" ))
132- ->open ();
133- return nullptr ;
134- }
70+ void createCDocReader (const QString &filename) {
71+ reader = std::unique_ptr<libcdoc::CDocReader>(libcdoc::CDocReader::createReader (filename.toStdString (), &conf, &crypto, &network));
72+ if (!reader)
73+ return ;
13574 keys.clear ();
136- for (auto & key : r ->getLocks ()) {
75+ for (auto & key : reader ->getLocks ()) {
13776 keys.push_back ({key, QSslCertificate ()});
13877 }
139- return r;
14078 }
14179};
14280
@@ -205,17 +143,17 @@ QString CDocumentModel::copy(int row, const QString &dst) const
205143
206144QString CDocumentModel::data (int row) const
207145{
208- return FileDialog::normalized (QString::fromStdString (d->getFiles () .at (row).name ));
146+ return FileDialog::normalized (QString::fromStdString (d->files .at (row).name ));
209147}
210148
211149quint64 CDocumentModel::fileSize (int row) const
212150{
213- return d->getFiles () .at (row).size ;
151+ return d->files .at (row).size ;
214152}
215153
216154QString CDocumentModel::mime (int row) const
217155{
218- return FileDialog::normalized (QString::fromStdString (d->getFiles () .at (row).mime ));
156+ return FileDialog::normalized (QString::fromStdString (d->files .at (row).mime ));
219157}
220158
221159void CDocumentModel::open (int row)
@@ -255,7 +193,7 @@ bool CDocumentModel::removeRow(int row)
255193
256194int CDocumentModel::rowCount () const
257195{
258- return int (d->getFiles () .size ());
196+ return int (d->files .size ());
259197}
260198
261199QString CDocumentModel::save (int row, const QString &path) const
@@ -322,7 +260,6 @@ void CryptoDoc::clear( const QString &file )
322260 d->tempFiles .clear ();
323261 d->reader .reset ();
324262 d->fileName = file;
325- d->writer_last_error .clear ();
326263 d->files .clear ();
327264}
328265
@@ -425,7 +362,6 @@ bool CryptoDoc::decrypt(const libcdoc::Lock *lock, const QByteArray& secret)
425362 d->files = std::move (cons.files );
426363 // Success, immediately create writer from reader
427364 d->keys .clear ();
428- d->writer_last_error .clear ();
429365 d->reader .reset ();
430366 return !d->isEncrypted ();
431367}
@@ -434,6 +370,9 @@ DocumentModel *CryptoDoc::documentModel() const { return d->documents; }
434370
435371bool CryptoDoc::encrypt ( const QString &filename, const QString& label, const QByteArray& secret)
436372{
373+ // I think the correct semantics is to fail if container is already encrypted
374+ if (d->reader )
375+ return false ;
437376 if ( !filename.isEmpty () )
438377 d->fileName = filename;
439378 if ( d->fileName .isEmpty () )
@@ -444,31 +383,62 @@ bool CryptoDoc::encrypt( const QString &filename, const QString& label, const QB
444383 ->open ();
445384 return false ;
446385 }
447- // I think the correct semantics is to fail if container is already encrypted
448- if (d->reader ) return false ;
449- if (!secret.isEmpty ()) {
450- // Encrypt with symmetric key
451- d->label = label;
452- d->crypto .secret .assign (secret.cbegin (), secret.cend ());
453- }
454- // Encrypt for address list
455- else if (d->keys .empty ())
386+ if (secret.isEmpty () && d->keys .empty ())
456387 {
457388 WarningDialog::create ()
458389 ->withTitle (tr (" Failed to encrypt document" ))
459390 ->withText (tr (" No keys specified" ))
460391 ->open ();
461392 return false ;
462393 }
463- libcdoc::result_t result = d->encrypt ();
464- d->label .clear ();
394+ QString writer_last_error;
395+ libcdoc::result_t result = waitFor ([&] -> libcdoc::result_t {
396+ qCDebug (CRYPTO) << " Encrypt" << d->fileName ;
397+ auto writer = std::unique_ptr<libcdoc::CDocWriter>(libcdoc::CDocWriter::createWriter (
398+ Settings::CDOC2_DEFAULT ? 2 : 1 , d->fileName .toStdString (), &d->conf , &d->crypto , &d->network ));
399+ if (!writer)
400+ return libcdoc::OUTPUT_ERROR;
401+ std::vector<libcdoc::Recipient> enc_keys;
402+ std::string keyserver_id;
403+ if (Settings::CDOC2_DEFAULT && Settings::CDOC2_USE_KEYSERVER) {
404+ keyserver_id = Settings::CDOC2_DEFAULT_KEYSERVER;
405+ }
406+ // Encrypt for address list
407+ for (const auto &key : d->keys ) {
408+ QByteArray ba = key.rcpt_cert .toDer ();
409+ enc_keys.push_back (keyserver_id.empty () ?
410+ libcdoc::Recipient::makeCertificate ({}, {ba.cbegin (), ba.cend ()}) :
411+ libcdoc::Recipient::makeServer ({}, {ba.cbegin (), ba.cend ()}, keyserver_id));
412+ }
413+ // Encrypt with symmetric key
414+ if (!secret.isEmpty ()) {
415+ // NIST recommends at least 600000 iterations for PBKDF2 with SHA-256, see https://csrc.nist.gov/publications/detail/sp/800-132/final
416+ d->crypto .secret .assign (secret.cbegin (), secret.cend ());
417+ enc_keys.push_back (libcdoc::Recipient::makeSymmetric (label.toStdString (), 600000 ));
418+ }
419+ StreamListSource slsrc (d->files );
420+ libcdoc::result_t result = writer->encrypt (slsrc, enc_keys);
421+ writer_last_error = QString::fromStdString (writer->getLastErrorStr ());
422+ qCDebug (CRYPTO) << " Encryption result: " << result << ' ' << writer_last_error;
423+ if (result == libcdoc::OK) // Encryption successful, open new reader
424+ d->createCDocReader (d->fileName );
425+ else if (QFile::exists (d->fileName ))
426+ QFile::remove (d->fileName );
427+ return result;
428+ });
465429 d->crypto .secret .clear ();
466430 if (result != libcdoc::OK) {
467431 WarningDialog::create ()
468432 ->withTitle (tr (" Failed to encrypt document" ))
469433 ->withText (tr (" Please check your internet connection and network settings." ))
470- ->withDetails (QString::fromStdString (d->writer_last_error ))
434+ ->withDetails (writer_last_error)
435+ ->open ();
436+ } else if (!d->reader ) {
437+ WarningDialog::create ()
438+ ->withTitle (CryptoDoc::tr (" Failed to open document" ))
439+ ->withText (CryptoDoc::tr (" Unsupported file format" ))
471440 ->open ();
441+ return false ;
472442 }
473443
474444 return d->isEncrypted ();
@@ -492,11 +462,15 @@ bool CryptoDoc::move(const QString &to)
492462
493463bool CryptoDoc::open (const QString &file)
494464{
495- d->writer_last_error .clear ();
496465 clear (file);
497- d->reader = d->createCDocReader (file.toStdString ());
498- if (!d->reader )
466+ d->createCDocReader (file);
467+ if (!d->reader ) {
468+ WarningDialog::create ()
469+ ->withTitle (CryptoDoc::tr (" Failed to open document" ))
470+ ->withText (CryptoDoc::tr (" Unsupported file format" ))
471+ ->open ();
499472 return false ;
473+ }
500474 std::vector<libcdoc::FileInfo> files = CDocSupport::getCDocFileList (file);
501475 for (auto & f : files) {
502476 d->files .push_back ({f.name , {}, f.size , {}});
0 commit comments