diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d6c5c88..a4389c2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -147,26 +147,43 @@ set(HEADERS config.h imagewriter.h networkaccessmanagerfactory.h nan.h drivelist # Add dependencies if (APPLE) 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 - mac/macwlancredentials.h mac/macwlancredentials.cpp - dependencies/drivelist/src/darwin/list.mm dependencies/drivelist/src/darwin/REDiskList.m icons/rpi-imager.icns) + set(PLATFORM_SOURCES + mac/acceleratedcryptographichash_commoncrypto.cpp + 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) 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) - set(EXTRALIBS ${EXTRALIBS} idn2 nettle) - find_package(GnuTLS) - if (GnuTLS_FOUND) - set(DEPENDENCIES ${DEPENDENCIES} acceleratedcryptographichash_gnutls.cpp) - set(EXTRALIBS ${EXTRALIBS} GnuTLS::GnuTLS) - add_definitions(-DHAVE_GNUTLS) - else() - find_package(OpenSSL REQUIRED) - set(DEPENDENCIES ${DEPENDENCIES} acceleratedcryptographichash.cpp) - endif() + find_package(GnuTLS REQUIRED) + set(PLATFORM_SOURCES + dependencies/mountutils/src/linux/functions.cpp + linux/linuxdrivelist.cpp + linux/networkmanagerapi.h + 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) elseif (WIN32) - set(DEPENDENCIES acceleratedcryptographichash.cpp dependencies/mountutils/src/windows/functions.cpp dependencies/drivelist/src/windows/list.cpp - windows/winfile.cpp windows/winfile.h windows/winwlancredentials.h windows/winwlancredentials.cpp - windows/rpi-imager.rc wlanapi_delayed.lib) + set(PLATFORM_SOURCES + windows/acceleratedcryptographichash_cng.cpp + 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) add_custom_command( OUTPUT wlanapi_delayed.lib @@ -204,7 +221,7 @@ if( IS_BIG_ENDIAN ) message( FATAL_ERROR "We currently only support 'little endian' CPU architectures" ) 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" "devicewrapper.cpp" "devicewrapperblockcacheentry.cpp" "devicewrapperpartition.cpp" "devicewrapperfatpartition.cpp" "driveformatthread.cpp" "localfileextractthread.cpp" "powersaveblocker.cpp" "downloadstatstelemetry.cpp" "qml.qrc" "dependencies/sha256crypt/sha256crypt.c" "cli.cpp") diff --git a/src/acceleratedcryptographichash.cpp b/src/acceleratedcryptographichash.cpp deleted file mode 100644 index d03053f..0000000 --- a/src/acceleratedcryptographichash.cpp +++ /dev/null @@ -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); -} diff --git a/src/acceleratedcryptographichash.h b/src/acceleratedcryptographichash.h index 1b31a9a..a4c4952 100644 --- a/src/acceleratedcryptographichash.h +++ b/src/acceleratedcryptographichash.h @@ -7,37 +7,20 @@ */ #include +#include -#ifdef Q_OS_DARWIN -#include -#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 +struct AcceleratedCryptographicHash { +private: + struct impl; + std::unique_ptr p_Impl; + public: explicit AcceleratedCryptographicHash(QCryptographicHash::Algorithm method); - virtual ~AcceleratedCryptographicHash(); + ~AcceleratedCryptographicHash(); void addData(const char *data, int length); void addData(const QByteArray &data); QByteArray result(); - -protected: -#ifdef HAVE_GNUTLS - gnutls_hash_hd_t _sha256; -#else - SHA256_CTX _sha256; -#endif }; #endif // ACCELERATEDCRYPTOGRAPHICHASH_H diff --git a/src/acceleratedcryptographichash_gnutls.cpp b/src/acceleratedcryptographichash_gnutls.cpp deleted file mode 100644 index 4aeb646..0000000 --- a/src/acceleratedcryptographichash_gnutls.cpp +++ /dev/null @@ -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); -} diff --git a/src/linux/acceleratedcryptographichash_gnutls.cpp b/src/linux/acceleratedcryptographichash_gnutls.cpp new file mode 100644 index 0000000..7ce28ca --- /dev/null +++ b/src/linux/acceleratedcryptographichash_gnutls.cpp @@ -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(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(); +} diff --git a/src/mac/acceleratedcryptographichash_commoncrypto.cpp b/src/mac/acceleratedcryptographichash_commoncrypto.cpp new file mode 100644 index 0000000..7782b9b --- /dev/null +++ b/src/mac/acceleratedcryptographichash_commoncrypto.cpp @@ -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 + +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(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(); +} diff --git a/src/windows/acceleratedcryptographichash_cng.cpp b/src/windows/acceleratedcryptographichash_cng.cpp new file mode 100644 index 0000000..042d076 --- /dev/null +++ b/src/windows/acceleratedcryptographichash_cng.cpp @@ -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 +#include + +#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(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(); +}