diff options
| author | Brian Potchik <brian@vector35.com> | 2025-09-09 14:32:46 -0400 |
|---|---|---|
| committer | Brian Potchik <brian@vector35.com> | 2025-09-09 14:32:46 -0400 |
| commit | 2bd92004ccf545173e5076780791241e096be8b4 (patch) | |
| tree | 23a22b9dcc3f7f0b283f804cbeecf007e701ef88 /examples | |
| parent | 10d9cb90e6f2904259bb4fb4f8bf05b9817df95d (diff) | |
Fix and optimize triage view hash calculations for large files.
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/triage/fileinfo.cpp | 73 | ||||
| -rw-r--r-- | examples/triage/fileinfo.h | 2 |
2 files changed, 54 insertions, 21 deletions
diff --git a/examples/triage/fileinfo.cpp b/examples/triage/fileinfo.cpp index 5a9ba743..b6359fbf 100644 --- a/examples/triage/fileinfo.cpp +++ b/examples/triage/fileinfo.cpp @@ -32,30 +32,70 @@ void FileInfoWidget::addField(const QString& name, const QVariant& value) this->m_layout->addWidget(valueLabel, row++, column + 1); } -void FileInfoWidget::addHashField( - const QString& hashName, const QCryptographicHash::Algorithm& algorithm, const QByteArray& data) +void FileInfoWidget::addHashFields(BinaryViewRef view) { auto& [row, column] = this->m_fieldPosition; const auto hashFieldColor = getThemeColor(AlphanumericHighlightColor); - auto hashLabel = new CopyableLabel("Calculating...", hashFieldColor); - hashLabel->setFont(getMonospaceFont(this)); + auto md5Label = new CopyableLabel("Calculating...", hashFieldColor); + auto sha1Label = new CopyableLabel("Calculating...", hashFieldColor); + auto sha256Label = new CopyableLabel("Calculating...", hashFieldColor); + md5Label->setFont(getMonospaceFont(this)); + sha1Label->setFont(getMonospaceFont(this)); + sha256Label->setFont(getMonospaceFont(this)); - this->m_layout->addWidget(new QLabel(hashName), row, column); - this->m_layout->addWidget(hashLabel, row++, column + 1); + this->m_layout->addWidget(new QLabel("MD5: "), row, column); + this->m_layout->addWidget(md5Label, row++, column + 1); + this->m_layout->addWidget(new QLabel("SHA-1: "), row, column); + this->m_layout->addWidget(sha1Label, row++, column + 1); + this->m_layout->addWidget(new QLabel("SHA-256: "), row, column); + this->m_layout->addWidget(sha256Label, row++, column + 1); - // Process the hash calculations in a separate thread and update the label when done - QPointer<QFutureWatcher<QByteArray>> watcher = new QFutureWatcher<QByteArray>(this); - connect(watcher, &QFutureWatcher<QByteArray>::finished, this, [watcher, hashLabel]() { + // Process the hash calculations in a separate thread and update the labels when done + QPointer<QFutureWatcher<QStringList>> watcher = new QFutureWatcher<QStringList>(this); + connect(watcher, &QFutureWatcher<QStringList>::finished, this, [watcher, md5Label, sha1Label, sha256Label]() { if (watcher) { - hashLabel->setText(watcher->result().toHex()); + if (const auto results = watcher->result(); results.size() == 3) + { + md5Label->setText(results[0]); + sha1Label->setText(results[1]); + sha256Label->setText(results[2]); + } watcher->deleteLater(); } }); - QFuture<QByteArray> future = QtConcurrent::run([data, algorithm]() { - return QCryptographicHash::hash(data, algorithm); + + uint64_t totalSize = view->GetLength(); + QFuture<QStringList> future = QtConcurrent::run([view, totalSize, watcher]() { + QCryptographicHash md5(QCryptographicHash::Md5); + QCryptographicHash sha1(QCryptographicHash::Sha1); + QCryptographicHash sha256(QCryptographicHash::Sha256); + + uint64_t offset = 0; + const uint64_t maxChunkSize = 128 * 1024 * 1024; + auto chunkBuffer = std::make_unique<char[]>(maxChunkSize); + while (offset < totalSize) + { + if (watcher->isCanceled()) + return QStringList(); + + const auto remainingBytes = totalSize - offset; + const auto currentChunkSize = std::min(maxChunkSize, remainingBytes); + const auto bytesRead = view->Read(chunkBuffer.get(), offset, currentChunkSize); + if (bytesRead != currentChunkSize) + return QStringList{"Error", "Error", "Error"}; + + const auto chunkView = QByteArrayView(chunkBuffer.get(), currentChunkSize); + md5.addData(chunkView); + sha1.addData(chunkView); + sha256.addData(chunkView); + offset += currentChunkSize; + } + + return QStringList {md5.result().toHex(), sha1.result().toHex(), sha256.result().toHex()}; }); + watcher->setFuture(future); connect(this, &QObject::destroyed, this, [watcher]() { if (watcher && watcher->isRunning()) { @@ -87,14 +127,7 @@ FileInfoWidget::FileInfoWidget(QWidget* parent, BinaryViewRef bv) const auto fileSize = QString::number(view->GetLength(), 16).prepend("0x"); this->addCopyableField("Size: ", fileSize); - const auto bufferSize = fileSize.toUInt(nullptr, 16); - const auto fileBuffer = std::make_unique<char[]>(bufferSize); - view->Read(fileBuffer.get(), 0, bufferSize); - - const auto fileBytes = QByteArray(fileBuffer.get(), bufferSize); - this->addHashField("MD5: ", QCryptographicHash::Md5, fileBytes); - this->addHashField("SHA-1: ", QCryptographicHash::Sha1, fileBytes); - this->addHashField("SHA-256: ", QCryptographicHash::Sha256, fileBytes); + this->addHashFields(view); const auto scaledWidth = UIContext::getScaledWindowSize(20, 20).width(); this->m_layout->setColumnMinimumWidth(FileInfoWidget::m_maxColumns * 3 - 1, scaledWidth); diff --git a/examples/triage/fileinfo.h b/examples/triage/fileinfo.h index 1896188a..4134ba45 100644 --- a/examples/triage/fileinfo.h +++ b/examples/triage/fileinfo.h @@ -13,7 +13,7 @@ class FileInfoWidget : public QWidget void addField(const QString& name, const QVariant& value); void addCopyableField(const QString& name, const QVariant& value); - void addHashField(const QString& hashName, const QCryptographicHash::Algorithm& algorithm, const QByteArray& data); + void addHashFields(BinaryViewRef view); public: FileInfoWidget(QWidget* parent, BinaryViewRef bv); |
