summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorBrian Potchik <brian@vector35.com>2025-09-09 14:32:46 -0400
committerBrian Potchik <brian@vector35.com>2025-09-09 14:32:46 -0400
commit2bd92004ccf545173e5076780791241e096be8b4 (patch)
tree23a22b9dcc3f7f0b283f804cbeecf007e701ef88 /examples
parent10d9cb90e6f2904259bb4fb4f8bf05b9817df95d (diff)
Fix and optimize triage view hash calculations for large files.
Diffstat (limited to 'examples')
-rw-r--r--examples/triage/fileinfo.cpp73
-rw-r--r--examples/triage/fileinfo.h2
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);