AcceleratedCryptographicHash: Use platform capabilities

Introduce a CNG version for Windows, a CommonCrypto
version for macOS and a GnuTLS version for Linux, as
we're using gnutls _anyway_.
This commit is contained in:
Tom Dewey 2024-07-30 15:03:11 +01:00 committed by Tom Dewey
parent 7074a5e389
commit d9082f8abd
7 changed files with 334 additions and 118 deletions

View file

@ -147,26 +147,43 @@ set(HEADERS config.h imagewriter.h networkaccessmanagerfactory.h nan.h drivelist
# Add dependencies # Add dependencies
if (APPLE) if (APPLE)
set_source_files_properties("icons/rpi-imager.icns" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") set_source_files_properties("icons/rpi-imager.icns" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
set(DEPENDENCIES acceleratedcryptographichash.cpp mac/macfile.cpp mac/macfile.h dependencies/mountutils/src/darwin/functions.cpp set(PLATFORM_SOURCES
mac/macwlancredentials.h mac/macwlancredentials.cpp mac/acceleratedcryptographichash_commoncrypto.cpp
dependencies/drivelist/src/darwin/list.mm dependencies/drivelist/src/darwin/REDiskList.m icons/rpi-imager.icns) mac/macfile.cpp
mac/macfile.h
dependencies/mountutils/src/darwin/functions.cpp
mac/macwlancredentials.h
mac/macwlancredentials.cpp
dependencies/drivelist/src/darwin/list.mm
dependencies/drivelist/src/darwin/REDiskList.m
)
set(DEPENDENCIES icons/rpi-imager.icns)
enable_language(OBJC C) enable_language(OBJC C)
elseif (UNIX) elseif (UNIX)
set(DEPENDENCIES dependencies/mountutils/src/linux/functions.cpp linux/linuxdrivelist.cpp linux/networkmanagerapi.h linux/networkmanagerapi.cpp linux/stpanalyzer.h linux/stpanalyzer.cpp) find_package(GnuTLS REQUIRED)
set(EXTRALIBS ${EXTRALIBS} idn2 nettle) set(PLATFORM_SOURCES
find_package(GnuTLS) dependencies/mountutils/src/linux/functions.cpp
if (GnuTLS_FOUND) linux/linuxdrivelist.cpp
set(DEPENDENCIES ${DEPENDENCIES} acceleratedcryptographichash_gnutls.cpp) linux/networkmanagerapi.h
set(EXTRALIBS ${EXTRALIBS} GnuTLS::GnuTLS) linux/networkmanagerapi.cpp
linux/stpanalyzer.h
linux/stpanalyzer.cpp
linux/acceleratedcryptographichash_gnutls.cpp
)
set(EXTRALIBS ${EXTRALIBS} GnuTLS::GnuTLS idn2 nettle)
set(DEPENDENCIES "")
add_definitions(-DHAVE_GNUTLS) add_definitions(-DHAVE_GNUTLS)
else()
find_package(OpenSSL REQUIRED)
set(DEPENDENCIES ${DEPENDENCIES} acceleratedcryptographichash.cpp)
endif()
elseif (WIN32) elseif (WIN32)
set(DEPENDENCIES acceleratedcryptographichash.cpp dependencies/mountutils/src/windows/functions.cpp dependencies/drivelist/src/windows/list.cpp set(PLATFORM_SOURCES
windows/winfile.cpp windows/winfile.h windows/winwlancredentials.h windows/winwlancredentials.cpp windows/acceleratedcryptographichash_cng.cpp
windows/rpi-imager.rc wlanapi_delayed.lib) dependencies/mountutils/src/windows/functions.cpp
dependencies/drivelist/src/windows/list.cpp
windows/winfile.cpp
windows/winfile.h
windows/winwlancredentials.h
windows/winwlancredentials.cpp
)
set(DEPENDENCIES windows/rpi-imager.rc wlanapi_delayed.lib)
set(EXTRALIBS setupapi ${CMAKE_CURRENT_BINARY_DIR}/wlanapi_delayed.lib) set(EXTRALIBS setupapi ${CMAKE_CURRENT_BINARY_DIR}/wlanapi_delayed.lib)
add_custom_command( add_custom_command(
OUTPUT wlanapi_delayed.lib OUTPUT wlanapi_delayed.lib
@ -204,7 +221,7 @@ if( IS_BIG_ENDIAN )
message( FATAL_ERROR "We currently only support 'little endian' CPU architectures" ) message( FATAL_ERROR "We currently only support 'little endian' CPU architectures" )
endif( IS_BIG_ENDIAN ) endif( IS_BIG_ENDIAN )
set(SOURCES "main.cpp" "imagewriter.cpp" "networkaccessmanagerfactory.cpp" set(SOURCES ${PLATFORM_SOURCES} "main.cpp" "imagewriter.cpp" "networkaccessmanagerfactory.cpp"
"drivelistitem.cpp" "drivelistmodel.cpp" "drivelistmodelpollthread.cpp" "downloadthread.cpp" "downloadextractthread.cpp" "drivelistitem.cpp" "drivelistmodel.cpp" "drivelistmodelpollthread.cpp" "downloadthread.cpp" "downloadextractthread.cpp"
"devicewrapper.cpp" "devicewrapperblockcacheentry.cpp" "devicewrapperpartition.cpp" "devicewrapperfatpartition.cpp" "devicewrapper.cpp" "devicewrapperblockcacheentry.cpp" "devicewrapperpartition.cpp" "devicewrapperfatpartition.cpp"
"driveformatthread.cpp" "localfileextractthread.cpp" "powersaveblocker.cpp" "downloadstatstelemetry.cpp" "qml.qrc" "dependencies/sha256crypt/sha256crypt.c" "cli.cpp") "driveformatthread.cpp" "localfileextractthread.cpp" "powersaveblocker.cpp" "downloadstatstelemetry.cpp" "qml.qrc" "dependencies/sha256crypt/sha256crypt.c" "cli.cpp")

View file

@ -1,37 +0,0 @@
/*
* Use OpenSSL for hashing as their code is more optimized than Qt's
*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2020 Raspberry Pi Ltd
*/
#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

@ -7,37 +7,20 @@
*/ */
#include <QCryptographicHash> #include <QCryptographicHash>
#include <memory>
#ifdef Q_OS_DARWIN struct AcceleratedCryptographicHash
#include <CommonCrypto/CommonDigest.h>
#define SHA256_CTX CC_SHA256_CTX
#define SHA256_DIGEST_LENGTH CC_SHA256_DIGEST_LENGTH
#define SHA256_Init CC_SHA256_Init
#define SHA256_Update CC_SHA256_Update
#define SHA256_Final CC_SHA256_Final
#else
#ifdef HAVE_GNUTLS
#include "gnutls/crypto.h"
#else
#include "openssl/sha.h"
#endif
#endif
class AcceleratedCryptographicHash
{ {
private:
struct impl;
std::unique_ptr<impl> p_Impl;
public: public:
explicit AcceleratedCryptographicHash(QCryptographicHash::Algorithm method); explicit AcceleratedCryptographicHash(QCryptographicHash::Algorithm method);
virtual ~AcceleratedCryptographicHash(); ~AcceleratedCryptographicHash();
void addData(const char *data, int length); void addData(const char *data, int length);
void addData(const QByteArray &data); void addData(const QByteArray &data);
QByteArray result(); QByteArray result();
protected:
#ifdef HAVE_GNUTLS
gnutls_hash_hd_t _sha256;
#else
SHA256_CTX _sha256;
#endif
}; };
#endif // ACCELERATEDCRYPTOGRAPHICHASH_H #endif // ACCELERATEDCRYPTOGRAPHICHASH_H

View file

@ -1,39 +0,0 @@
/*
* Use GnuTLS for hashing as their code is more optimized than Qt's
*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2022 Raspberry Pi Ltd
*/
#include "acceleratedcryptographichash.h"
AcceleratedCryptographicHash::AcceleratedCryptographicHash(QCryptographicHash::Algorithm method)
{
if (method != QCryptographicHash::Sha256)
throw std::runtime_error("Only sha256 implemented");
gnutls_hash_init(&_sha256, GNUTLS_DIG_SHA256);
}
AcceleratedCryptographicHash::~AcceleratedCryptographicHash()
{
gnutls_hash_deinit(_sha256, NULL);
}
void AcceleratedCryptographicHash::addData(const char *data, int length)
{
gnutls_hash(_sha256, data, length);
}
void AcceleratedCryptographicHash::addData(const QByteArray &data)
{
addData(data.constData(), data.size());
}
QByteArray AcceleratedCryptographicHash::result()
{
unsigned char binhash[gnutls_hash_get_len(GNUTLS_DIG_SHA256)];
gnutls_hash_output(_sha256, binhash);
return QByteArray((char *) binhash, sizeof binhash);
}

View file

@ -0,0 +1,60 @@
/*
* Use GnuTLS for SHA256
*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2024 Raspberry Pi Ltd
*/
#include "acceleratedcryptographichash.h"
#include "gnutls/crypto.h"
struct AcceleratedCryptographicHash::impl {
explicit impl(QCryptographicHash::Algorithm method)
{
if (method != QCryptographicHash::Sha256)
throw std::runtime_error("Only sha256 implemented");
gnutls_hash_init(&_sha256, GNUTLS_DIG_SHA256);
}
~impl()
{
gnutls_hash_deinit(_sha256, NULL);
}
void addData(const char *data, int length)
{
gnutls_hash(_sha256, data, length);
}
void addData(const QByteArray &data)
{
addData(data.constData(), data.size());
}
QByteArray result()
{
unsigned char binhash[gnutls_hash_get_len(GNUTLS_DIG_SHA256)];
gnutls_hash_output(_sha256, binhash);
return QByteArray((char *) binhash, sizeof binhash);
}
private:
gnutls_hash_hd_t _sha256;
};
AcceleratedCryptographicHash::AcceleratedCryptographicHash(QCryptographicHash::Algorithm method)
: p_Impl(std::make_unique<impl>(method)) {}
AcceleratedCryptographicHash::~AcceleratedCryptographicHash() = default;
void AcceleratedCryptographicHash::addData(const char *data, int length) {
p_Impl->addData(data, length);
}
void AcceleratedCryptographicHash::addData(const QByteArray &data) {
p_Impl->addData(data);
}
QByteArray AcceleratedCryptographicHash::result() {
return p_Impl->result();
}

View file

@ -0,0 +1,53 @@
/*
* Use CommonCrypto on macOS for SHA256
*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2024 Raspberry Pi Ltd
*/
#include "acceleratedcryptographichash.h"
#include <CommonCrypto/CommonDigest.h>
struct AcceleratedCryptographicHash::Impl {
explicit Impl(QCryptographicHash::Algorithm algo) {
if (method != QCryptographicHash::Sha256)
throw std::runtime_error("Only sha256 implemented");
CC_SHA256_Init(&_sha256);
}
void addData(const char *data, int length)
{
CC_SHA256_Update(&_sha256, data, length);
}
void addData(const QByteArray &data)
{
addData(data.constData(), data.size());
}
QByteArray result() {
unsigned char binhash[CC_SHA256_DIGEST_LENGTH];
CC_SHA256_Final(binhash, &_sha256);
return QByteArray((char *) binhash, sizeof binhash);
}
private:
CC_SHA256_CTX _sha256;
};
AcceleratedCryptographicHash::AcceleratedCryptographicHash(QCryptographicHash::Algorithm method)
: p_Impl(std::make_unique<impl>(method)) {}
AcceleratedCryptographicHash::~AcceleratedCryptographicHash() = default;
void AcceleratedCryptographicHash::addData(const char *data, int length) {
p_Impl->addData(data, length);
}
void AcceleratedCryptographicHash::addData(const QByteArray &data) {
p_Impl->addData(data);
}
QByteArray AcceleratedCryptographicHash::result() {
return p_Impl->result();
}

View file

@ -0,0 +1,179 @@
/*
* Use Cryptography API: Next Generation for SHA256
*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2024 Raspberry Pi Ltd
*/
#include "acceleratedcryptographichash.h"
#include <windows.h>
#include <bcrypt.h>
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
struct AcceleratedCryptographicHash::Impl {
explicit Impl(QCryptographicHash::Algorithm algo) {
if (method != QCryptographicHash::Sha256)
throw std::runtime_error("Only sha256 implemented");
//open an algorithm handle
if(!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(
&hAlg,
BCRYPT_SHA256_ALGORITHM,
NULL,
0)))
{
qDebug() << "BCryptOpenAlgorithmProvider returned Error " << status;
goto Cleanup;
}
//calculate the size of the buffer to hold the hash object
if(!NT_SUCCESS(status = BCryptGetProperty(
hAlg,
BCRYPT_OBJECT_LENGTH,
(PBYTE)&cbHashObject,
sizeof(DWORD),
&cbData,
0)))
{
qDebug() << "BCryptGetProperty returned Error " << status;
goto Cleanup;
}
//allocate the hash object on the heap
pbHashObject = (PBYTE)HeapAlloc (GetProcessHeap(), 0, cbHashObject);
if(NULL == pbHashObject)
{
qDebug() << "memory allocation failed";
goto Cleanup;
}
//calculate the length of the hash
if(!NT_SUCCESS(status = BCryptGetProperty(
hAlg,
BCRYPT_HASH_LENGTH,
(PBYTE)&cbHash,
sizeof(DWORD),
&cbData,
0)))
{
qDebug() << "BCryptGetProperty returned Error " << status;
goto Cleanup;
}
//allocate the hash buffer on the heap
pbHash = (PBYTE)HeapAlloc (GetProcessHeap(), 0, cbHash);
if(NULL == pbHash)
{
qDebug() << "memory allocation failed";
cleanup();
return;
}
//create a hash
if(!NT_SUCCESS(status = BCryptCreateHash(
hAlg,
&hHash,
pbHashObject,
cbHashObject,
NULL,
0,
0)))
{
qDebug() << "BCryptCreateHash returned Error " << status;
cleanup();
return;
}
}
~Impl() {
cleanup()
}
void cleanup() {
if(hAlg)
{
BCryptCloseAlgorithmProvider(hAlg,0);
}
if (hHash)
{
BCryptDestroyHash(hHash);
}
if(pbHashObject)
{
HeapFree(GetProcessHeap(), 0, pbHashObject);
}
if(pbHash)
{
HeapFree(GetProcessHeap(), 0, pbHash);
}
}
void addData(const char *data, int length)
{
//hash some data
if(!NT_SUCCESS(status = BCryptHashData(
hHash,
(PBYTE)data,
length,
0)))
{
qDebug() << "BCryptHashData returned Error " << status;
goto Cleanup;
}
}
void addData(const QByteArray &data)
{
addData(data.constData(), data.size());
}
QByteArray result() {
//close the hash
if(!NT_SUCCESS(status = BCryptFinishHash(
hHash,
pbHash,
cbHash,
0)))
{
qDebug() << "BCryptFinishHash returned Error " << status;
cleanup()
return {};
} else {
// No cleanup required, as the dtor of this class will do so.
auto returnArray = QByteArray(pbHash, cbHash);
return returnArray;
}
}
private:
BCRYPT_ALG_HANDLE hAlg = NULL;
BCRYPT_HASH_HANDLE hHash = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL;
DWORD cbData = 0,
cbHash = 0,
cbHashObject = 0;
PBYTE pbHashObject = NULL;
PBYTE pbHash = NULL;
};
AcceleratedCryptographicHash::AcceleratedCryptographicHash(QCryptographicHash::Algorithm method)
: p_Impl(std::make_unique<impl>(method)) {}
AcceleratedCryptographicHash::~AcceleratedCryptographicHash() = default;
void AcceleratedCryptographicHash::addData(const char *data, int length) {
p_Impl->addData(data, length);
}
void AcceleratedCryptographicHash::addData(const QByteArray &data) {
p_Impl->addData(data);
}
QByteArray AcceleratedCryptographicHash::result() {
return p_Impl->result();
}