Skip to content

Commit 816c17d

Browse files
committed
Adjust encryption flow
Signed-off-by: Raul Metsma <raul@metsma.ee>
1 parent 118065e commit 816c17d

7 files changed

Lines changed: 124 additions & 142 deletions

File tree

client/CDocSupport.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ struct DDConfiguration : public libcdoc::Configuration {
5252
//
5353

5454
struct DDCryptoBackend final : public libcdoc::CryptoBackend {
55-
static constexpr int BACKEND_ERROR = -303;
56-
static constexpr int PIN_CANCELED = -304;
57-
static constexpr int PIN_INCORRECT = -305;
58-
static constexpr int PIN_LOCKED = -306;
55+
static constexpr int BACKEND_ERROR = -503;
56+
static constexpr int PIN_CANCELED = -504;
57+
static constexpr int PIN_INCORRECT = -505;
58+
static constexpr int PIN_LOCKED = -506;
5959
libcdoc::result_t decryptRSA(std::vector<uint8_t> &result,
6060
const std::vector<uint8_t> &data, bool oaep,
6161
unsigned int idx) final;

client/CryptoDoc.cpp

Lines changed: 62 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -48,69 +48,16 @@ using namespace ria::qdigidoc4;
4848

4949
Q_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-
5551
struct 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

206144
QString 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

211149
quint64 CDocumentModel::fileSize(int row) const
212150
{
213-
return d->getFiles().at(row).size;
151+
return d->files.at(row).size;
214152
}
215153

216154
QString 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

221159
void CDocumentModel::open(int row)
@@ -255,7 +193,7 @@ bool CDocumentModel::removeRow(int row)
255193

256194
int CDocumentModel::rowCount() const
257195
{
258-
return int(d->getFiles().size());
196+
return int(d->files.size());
259197
}
260198

261199
QString 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

435371
bool 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

493463
bool 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, {}});

client/MainWindow.cpp

Lines changed: 3 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -223,38 +223,6 @@ QStringList MainWindow::dropEventFiles(QDropEvent *event)
223223
return files;
224224
}
225225

226-
bool MainWindow::encrypt(bool askForKey)
227-
{
228-
if(!cryptoDoc)
229-
return false;
230-
231-
if(!FileDialog::fileIsWritable(cryptoDoc->fileName()))
232-
{
233-
auto *dlg = WarningDialog::create(this)
234-
->withTitle(CryptoDoc::tr("Failed to encrypt document"))
235-
->withText(tr("Cannot alter container %1. Save different location?").arg(FileDialog::normalized(cryptoDoc->fileName())))
236-
->addButton(WarningDialog::YES, QMessageBox::Yes);
237-
if(dlg->exec() != QMessageBox::Yes)
238-
return false;
239-
QString to = FileDialog::getSaveFileName(this, FileDialog::tr("Save file"), cryptoDoc->fileName());
240-
if(to.isNull() || !cryptoDoc->move(to))
241-
return false;
242-
ui->cryptoContainerPage->setHeader(to);
243-
}
244-
245-
if(!askForKey) {
246-
WaitDialogHolder waitDialog(this, tr("Encrypting"));
247-
return cryptoDoc->encrypt();
248-
}
249-
250-
PasswordDialog p(PasswordDialog::Mode::ENCRYPT, this);
251-
if(!p.exec())
252-
return false;
253-
254-
WaitDialogHolder waitDialog(this, tr("Encrypting"));
255-
return cryptoDoc->encrypt(cryptoDoc->fileName(), p.label(), p.secret());
256-
}
257-
258226
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
259227
{
260228
if(auto *cardPopup = findChild<CardPopup*>())
@@ -408,21 +376,11 @@ void MainWindow::onCryptoAction(int action, const QString &/*id*/, const QString
408376
if(cryptoDoc && wrap(cryptoDoc->fileName(), false))
409377
FadeInNotification::success(ui->topBar, tr("Converted to signed document!"));
410378
break;
411-
case DecryptedContainer:
379+
case DecryptContainerSuccess:
412380
FadeInNotification::success(ui->topBar, tr("Decryption succeeded!"));
413381
break;
414-
case EncryptContainer:
415-
if(encrypt())
416-
{
417-
ui->cryptoContainerPage->transition(cryptoDoc.get(), qApp->signer()->tokenauth().cert());
418-
FadeInNotification::success(ui->topBar, tr("Encryption succeeded!"));
419-
}
420-
break;
421-
case EncryptLT:
422-
if(encrypt(true)) {
423-
ui->cryptoContainerPage->transition(cryptoDoc.get(), qApp->signer()->tokenauth().cert());
424-
FadeInNotification::success(ui->topBar, tr("Encryption succeeded!"));
425-
}
382+
case EncryptContainerSuccess:
383+
FadeInNotification::success(ui->topBar, tr("Encryption succeeded!"));
426384
break;
427385
case ClearCryptoWarning:
428386
ui->crypto->warningIcon(false);

client/MainWindow.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ class MainWindow final : public QWidget
5858
void changePinClicked(QSmartCardData::PinType type, QSmartCard::PinAction action);
5959
void convertToCDoc();
6060
ria::qdigidoc4::ContainerState currentState();
61-
bool encrypt(bool askForKey = false);
62-
void loadPicture();
6361
void navigateToPage( ria::qdigidoc4::Pages page, const QStringList &files = QStringList(), bool create = true );
6462
void onCryptoAction(int action, const QString &id, const QString &phone);
6563
void onSignAction(int action, const QString &idCode, const QString &info2);

client/common_enums.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ enum Actions : unsigned char {
4242
ContainerEncrypt,
4343

4444
EncryptContainer,
45+
EncryptContainerSuccess,
4546
DecryptContainer,
4647
DecryptToken,
47-
DecryptedContainer,
48+
DecryptContainerSuccess,
4849

4950
SignatureAdd,
5051
SignatureMobile,

0 commit comments

Comments
 (0)