From 4404fce369f5a45fd9b89127ff0e4f31c9401ec3 Mon Sep 17 00:00:00 2001 From: Irastris Date: Wed, 6 May 2026 16:08:48 -0400 Subject: [PATCH] Do hash-based verification of disc images --- src/dusk/iso_validate.cpp | 17 +++++++++-------- src/dusk/iso_validate.hpp | 8 ++++---- src/dusk/ui/prelaunch.cpp | 13 ++++++------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/dusk/iso_validate.cpp b/src/dusk/iso_validate.cpp index 0816bba562..a2064102de 100644 --- a/src/dusk/iso_validate.cpp +++ b/src/dusk/iso_validate.cpp @@ -1,8 +1,8 @@ #include "iso_validate.hpp" #include - -#include "SDL3/SDL_iostream.h" +#include +#include namespace { @@ -147,7 +147,7 @@ ValidationError verify_disc(NodHandle* disc, VerificationStatus& status) { const auto hashState = XXH3_createState(); XXH3_128bits_reset(hashState); - while (!status.shouldCancel) { + while (true) { size_t bytesAvail; const auto buf = nod_buf_read(disc, &bytesAvail); if (!bytesAvail) @@ -159,13 +159,9 @@ ValidationError verify_disc(NodHandle* disc, VerificationStatus& status) { nod_buf_consume(disc, bytesAvail); } - if (status.shouldCancel) { - return ValidationError::Cancelled; - } - const auto hash = XXH3_128bits_digest(hashState); if (!XXH128_isEqual(hash, status.knownDisc->hash)) { - return ValidationError::DiscHashMismatch; + return ValidationError::HashMismatch; } return ValidationError::Success; @@ -214,6 +210,11 @@ ValidationError validate(const char* path, VerificationStatus& status) { return verify_disc(disc.handle, status); } +ValidationError validate(const char* path) { + VerificationStatus status{}; + return validate(path, status); +} + bool isPal(const char* path) { NodHandleWrapper disc; diff --git a/src/dusk/iso_validate.hpp b/src/dusk/iso_validate.hpp index 65ae53c8fe..23e5489d71 100644 --- a/src/dusk/iso_validate.hpp +++ b/src/dusk/iso_validate.hpp @@ -7,14 +7,13 @@ namespace dusk::iso { struct KnownDisc; enum class ValidationError : u8 { - Success = 0, + Unknown = 0, IOError, InvalidImage, WrongGame, WrongVersion, - Cancelled, - DiscHashMismatch, - Unknown + HashMismatch, + Success }; struct VerificationStatus { @@ -25,6 +24,7 @@ namespace dusk::iso { }; ValidationError validate(const char* path, VerificationStatus& status); + ValidationError validate(const char* path); bool isPal(const char* path); } diff --git a/src/dusk/ui/prelaunch.cpp b/src/dusk/ui/prelaunch.cpp index f4cf78c9d3..b091239bc2 100644 --- a/src/dusk/ui/prelaunch.cpp +++ b/src/dusk/ui/prelaunch.cpp @@ -56,6 +56,8 @@ constexpr std::array kDiscFileFilters{{ static std::string get_error_msg(iso::ValidationError error) { switch (error) { + default: + return "The selected disc image could not be validated."; case iso::ValidationError::IOError: return "Unable to read the selected file."; case iso::ValidationError::InvalidImage: @@ -64,22 +66,19 @@ static std::string get_error_msg(iso::ValidationError error) { return "The selected game is not supported by Dusk."; case iso::ValidationError::WrongVersion: return "Dusk currently supports GameCube USA and PAL disc images only."; + case iso::ValidationError::HashMismatch: + return "The selected disc image did not pass hash verification, it may be corrupt or modified."; case iso::ValidationError::Success: return "The selected disc image is valid."; - default: - return "The selected disc image could not be validated."; } } void file_dialog_callback(void*, const char* path, const char* error) { - auto& state = prelaunch_state(); - if (error != nullptr) { - return; - } - if (path == nullptr) { + if (path == nullptr || error != nullptr) { return; } + auto& state = prelaunch_state(); const auto validation = iso::validate(path); if (validation != iso::ValidationError::Success) { state.errorString = escape(get_error_msg(validation));