Use accelerated hashing for verification

Modern CPUs have special instructions to accelerate computing
SHA hashes.
The Qt QCryptographicHash code is standard C, so not taking
advantage of those though.
Outsource the hashing to OpenSSL that does.

Shaves off some seconds during verification stage.
This commit is contained in:
Floris Bos 2020-05-23 17:50:59 +02:00
parent 2c5432fe7f
commit 8048b5e47c
6 changed files with 73 additions and 7 deletions

View file

@ -20,7 +20,7 @@ set(CMAKE_AUTORCC ON)
# Adding headers explicity so they are displayed in Qt Creator # Adding headers explicity so they are displayed in Qt Creator
set(HEADERS config.h imagewriter.h networkaccessmanagerfactory.h nan.h drivelistitem.h drivelistmodel.h driveformatthread.h powersaveblocker.h set(HEADERS config.h imagewriter.h networkaccessmanagerfactory.h nan.h drivelistitem.h drivelistmodel.h driveformatthread.h powersaveblocker.h
downloadthread.h downloadextractthread.h dependencies/mountutils/src/mountutils.hpp) downloadthread.h downloadextractthread.h acceleratedcryptographichash.h dependencies/mountutils/src/mountutils.hpp)
# Add 3rd-party dependencies # Add 3rd-party dependencies
if (APPLE) if (APPLE)
@ -60,8 +60,9 @@ endif()
set(SOURCES "main.cpp" "imagewriter.cpp" "networkaccessmanagerfactory.cpp" set(SOURCES "main.cpp" "imagewriter.cpp" "networkaccessmanagerfactory.cpp"
"drivelistitem.cpp" "drivelistmodel.cpp" "downloadthread.cpp" "downloadextractthread.cpp" "drivelistitem.cpp" "drivelistmodel.cpp" "downloadthread.cpp" "downloadextractthread.cpp"
"driveformatthread.cpp" "powersaveblocker.cpp" "qml.qrc") "driveformatthread.cpp" "powersaveblocker.cpp" "acceleratedcryptographichash.cpp" "qml.qrc")
find_package(OpenSSL REQUIRED)
find_package(Qt5 COMPONENTS Core Quick Widgets LinguistTools REQUIRED) find_package(Qt5 COMPONENTS Core Quick Widgets LinguistTools REQUIRED)
#qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} i18n/rpi-imager_nl.ts i18n/rpi-imager_zh_cn.ts) #qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} i18n/rpi-imager_nl.ts i18n/rpi-imager_zh_cn.ts)
@ -233,5 +234,5 @@ else()
install(FILES linux/rpi-imager.desktop DESTINATION share/applications) install(FILES linux/rpi-imager.desktop DESTINATION share/applications)
endif() endif()
include_directories(${CURL_INCLUDE_DIR} ${LibArchive_INCLUDE_DIR}) include_directories(${CURL_INCLUDE_DIR} ${LibArchive_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Quick Qt5::Widgets ${CURL_LIBRARIES} ${LibArchive_LIBRARIES} ${ATOMIC_LIBRARY} ${EXTRALIBS}) target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Quick Qt5::Widgets ${CURL_LIBRARIES} ${LibArchive_LIBRARIES} ${OPENSSL_LIBRARIES} ${ATOMIC_LIBRARY} ${EXTRALIBS})

View file

@ -0,0 +1,37 @@
/*
* Use OpenSSL for hashing as their code is more optimized than Qt's
*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2020 Raspberry Pi (Trading) Limited
*/
#include "acceleratedcryptographichash.h"
AcceleratedCryptographicHash::AcceleratedCryptographicHash(QCryptographicHash::Algorithm method)
{
if (method != QCryptographicHash::Sha256)
throw std::runtime_error("Only sha256 implemented");
SHA256_Init(&_sha256);
}
AcceleratedCryptographicHash::~AcceleratedCryptographicHash()
{
}
void AcceleratedCryptographicHash::addData(const char *data, int length)
{
SHA256_Update(&_sha256, data, length);
}
void AcceleratedCryptographicHash::addData(const QByteArray &data)
{
addData(data.constData(), data.size());
}
QByteArray AcceleratedCryptographicHash::result()
{
unsigned char binhash[SHA256_DIGEST_LENGTH];
SHA256_Final(binhash, &_sha256);
return QByteArray((char *) binhash, sizeof binhash);
}

View file

@ -0,0 +1,25 @@
#ifndef ACCELERATEDCRYPTOGRAPHICHASH_H
#define ACCELERATEDCRYPTOGRAPHICHASH_H
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2020 Raspberry Pi (Trading) Limited
*/
#include <QCryptographicHash>
#include "openssl/sha.h"
class AcceleratedCryptographicHash
{
public:
explicit AcceleratedCryptographicHash(QCryptographicHash::Algorithm method);
virtual ~AcceleratedCryptographicHash();
void addData(const char *data, int length);
void addData(const QByteArray &data);
QByteArray result();
protected:
SHA256_CTX _sha256;
};
#endif // ACCELERATEDCRYPTOGRAPHICHASH_H

View file

@ -41,7 +41,7 @@ protected:
std::mutex _queueMutex; std::mutex _queueMutex;
std::condition_variable _cv; std::condition_variable _cv;
bool _ethreadStarted, _isImage; bool _ethreadStarted, _isImage;
QCryptographicHash _inputHash; AcceleratedCryptographicHash _inputHash;
int _activeBuf; int _activeBuf;
bool _writeThreadStarted; bool _writeThreadStarted;
QFuture<size_t> _writeFuture; QFuture<size_t> _writeFuture;

View file

@ -600,6 +600,8 @@ bool DownloadThread::_verify()
char *verifyBuf = (char *) qMallocAligned(IMAGEWRITER_VERIFY_BLOCKSIZE, 4096); char *verifyBuf = (char *) qMallocAligned(IMAGEWRITER_VERIFY_BLOCKSIZE, 4096);
_lastVerifyNow = 0; _lastVerifyNow = 0;
_verifyTotal = _file.pos(); _verifyTotal = _file.pos();
QElapsedTimer t1;
t1.start();
if (!_firstBlock) if (!_firstBlock)
{ {
@ -627,6 +629,7 @@ bool DownloadThread::_verify()
} }
qFreeAligned(verifyBuf); qFreeAligned(verifyBuf);
qDebug() << "Verify done in" << t1.elapsed() / 1000.0 << "seconds";
qDebug() << "Verify hash:" << _verifyhash.result().toHex(); qDebug() << "Verify hash:" << _verifyhash.result().toHex();
if (_verifyhash.result() == _writehash.result() || !_verifyEnabled || _cancelled) if (_verifyhash.result() == _writehash.result() || !_verifyEnabled || _cancelled)

View file

@ -9,12 +9,12 @@
#include <QString> #include <QString>
#include <QThread> #include <QThread>
#include <QFile> #include <QFile>
#include <QCryptographicHash>
#include <QElapsedTimer> #include <QElapsedTimer>
#include <fstream> #include <fstream>
#include <atomic> #include <atomic>
#include <time.h> #include <time.h>
#include <curl/curl.h> #include <curl/curl.h>
#include "acceleratedcryptographichash.h"
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include "windows/winfile.h" #include "windows/winfile.h"
@ -172,7 +172,7 @@ protected:
#endif #endif
QFile _cachefile; QFile _cachefile;
QCryptographicHash _writehash, _verifyhash; AcceleratedCryptographicHash _writehash, _verifyhash;
}; };
#endif // DOWNLOADTHREAD_H #endif // DOWNLOADTHREAD_H