From ab7985a34b8a4de59dc9a6e6c4c40fbb564797b8 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Fri, 16 Mar 2018 16:53:48 -0700 Subject: [PATCH] [vcpkg-hash] Use BCrypt on Windows --- toolsrc/include/vcpkg/base/strings.h | 4 +- toolsrc/include/vcpkg/base/util.h | 12 +- toolsrc/src/vcpkg/base/strings.cpp | 13 +- toolsrc/src/vcpkg/commands.hash.cpp | 124 ++++++++++++++++-- toolsrc/vcpkg/vcpkg.vcxproj | 8 +- .../vcpkgmetricsuploader.vcxproj | 8 +- toolsrc/vcpkgtest/vcpkgtest.vcxproj | 4 + 7 files changed, 146 insertions(+), 27 deletions(-) diff --git a/toolsrc/include/vcpkg/base/strings.h b/toolsrc/include/vcpkg/base/strings.h index 6294853afb..c32e81ac24 100644 --- a/toolsrc/include/vcpkg/base/strings.h +++ b/toolsrc/include/vcpkg/base/strings.h @@ -46,7 +46,9 @@ namespace vcpkg::Strings bool case_insensitive_ascii_equals(const CStringView left, const CStringView right); - std::string ascii_to_lowercase(std::string input); + std::string ascii_to_lowercase(std::string s); + + std::string ascii_to_uppercase(std::string s); bool case_insensitive_ascii_starts_with(const std::string& s, const std::string& pattern); diff --git a/toolsrc/include/vcpkg/base/util.h b/toolsrc/include/vcpkg/base/util.h index b129199515..c73345719e 100644 --- a/toolsrc/include/vcpkg/base/util.h +++ b/toolsrc/include/vcpkg/base/util.h @@ -6,8 +6,6 @@ #include #include -#include - namespace vcpkg::Util { template @@ -158,6 +156,8 @@ namespace vcpkg::Util MoveOnlyBase& operator=(const MoveOnlyBase&) = delete; MoveOnlyBase& operator=(MoveOnlyBase&&) = default; + + ~MoveOnlyBase() = default; }; struct ResourceBase @@ -168,6 +168,8 @@ namespace vcpkg::Util ResourceBase& operator=(const ResourceBase&) = delete; ResourceBase& operator=(ResourceBase&&) = delete; + + ~ResourceBase() = default; }; template @@ -214,4 +216,10 @@ namespace vcpkg::Util return e == E::YES; } } + + template + void unused(T&& param) + { + (void)param; + } } diff --git a/toolsrc/src/vcpkg/base/strings.cpp b/toolsrc/src/vcpkg/base/strings.cpp index a08512c9f8..5fedf3e1fb 100644 --- a/toolsrc/src/vcpkg/base/strings.cpp +++ b/toolsrc/src/vcpkg/base/strings.cpp @@ -7,10 +7,11 @@ namespace vcpkg::Strings::details { // To disambiguate between two overloads - static const auto isspace = [](const char c) { return std::isspace(c); }; + static bool IS_SPACE(const char c) { return std::isspace(c) != 0; }; // Avoids C4244 warnings because of char<->int conversion that occur when using std::tolower() static char tolower_char(const char c) { return static_cast(std::tolower(c)); } + static char toupper_char(const char c) { return static_cast(std::toupper(c)); } #if defined(_WIN32) static _locale_t& c_locale() @@ -114,6 +115,12 @@ namespace vcpkg::Strings return s; } + std::string ascii_to_uppercase(std::string s) + { + std::transform(s.begin(), s.end(), s.begin(), &details::toupper_char); + return s; + } + bool case_insensitive_ascii_starts_with(const std::string& s, const std::string& pattern) { #if defined(_WIN32) @@ -136,8 +143,8 @@ namespace vcpkg::Strings std::string trim(std::string&& s) { - s.erase(std::find_if_not(s.rbegin(), s.rend(), details::isspace).base(), s.end()); - s.erase(s.begin(), std::find_if_not(s.begin(), s.end(), details::isspace)); + s.erase(std::find_if_not(s.rbegin(), s.rend(), details::IS_SPACE).base(), s.end()); + s.erase(s.begin(), std::find_if_not(s.begin(), s.end(), details::IS_SPACE)); return std::move(s); } diff --git a/toolsrc/src/vcpkg/commands.hash.cpp b/toolsrc/src/vcpkg/commands.hash.cpp index cb0a8cc519..9e1b54390d 100644 --- a/toolsrc/src/vcpkg/commands.hash.cpp +++ b/toolsrc/src/vcpkg/commands.hash.cpp @@ -1,13 +1,114 @@ #include "pch.h" +#include +#include #include #include #include #include +#if defined(_WIN32) +#include + +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +#endif + namespace vcpkg::Commands::Hash { - std::string get_file_hash(const VcpkgPaths& paths, fs::path const& path, std::string const& hash_type) + namespace + { + static std::string to_hex(const unsigned char* string, const size_t bytes) + { + static constexpr char HEX_MAP[] = "0123456789abcdef"; + + std::string output; + output.resize(2 * bytes); + + size_t current_char = 0; + for (size_t i = 0; i < bytes; i++) + { + // high + output[current_char] = HEX_MAP[(string[i] & 0xF0) >> 4]; + ++current_char; + // low + output[current_char] = HEX_MAP[(string[i] & 0x0F)]; + ++current_char; + } + + return output; + } + + struct BCryptAlgorithmHandle : Util::ResourceBase + { + BCRYPT_ALG_HANDLE handle = nullptr; + + ~BCryptAlgorithmHandle() + { + if (handle) BCryptCloseAlgorithmProvider(handle, 0); + } + }; + + struct BCryptHashHandle : Util::ResourceBase + { + BCRYPT_HASH_HANDLE handle = nullptr; + + ~BCryptHashHandle() + { + if (handle) BCryptDestroyHash(handle); + } + }; + } + + std::string get_file_hash(const VcpkgPaths&, const fs::path& path, const std::string& hash_type) + { + BCryptAlgorithmHandle algorithm_handle; + + NTSTATUS error_code = BCryptOpenAlgorithmProvider( + &algorithm_handle.handle, Strings::to_utf16(Strings::ascii_to_uppercase(hash_type)).c_str(), nullptr, 0); + Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to open the algorithm provider"); + + DWORD hash_buffer_bytes; + DWORD cb_data; + error_code = BCryptGetProperty(algorithm_handle.handle, + BCRYPT_HASH_LENGTH, + reinterpret_cast(&hash_buffer_bytes), + sizeof(DWORD), + &cb_data, + 0); + Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to get hash length"); + const ULONG length_in_bytes = hash_buffer_bytes; + + BCryptHashHandle hash_handle; + + error_code = BCryptCreateHash(algorithm_handle.handle, &hash_handle.handle, nullptr, 0, nullptr, 0, 0); + Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to initialize the hasher"); + + FILE* file = nullptr; + const auto ec = _wfopen_s(&file, path.c_str(), L"rb"); + Checks::check_exit(VCPKG_LINE_INFO, ec == 0, "Failed to open file: %s", path.u8string()); + unsigned char buffer[4096]; + while (const auto actual_size = fread(buffer, 1, sizeof(buffer), file)) + { + error_code = BCryptHashData(hash_handle.handle, buffer, static_cast(actual_size), 0); + Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to hash data"); + } + + fclose(file); + + std::unique_ptr hash_buffer = std::make_unique(length_in_bytes); + + error_code = BCryptFinishHash(hash_handle.handle, hash_buffer.get(), length_in_bytes, 0); + Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to finalize the hash"); + + return to_hex(hash_buffer.get(), length_in_bytes); + } +} + +#else +namespace vcpkg::Commands::Hash +{ + std::string get_file_hash(const VcpkgPaths& paths, const fs::path& path, const std::string& hash_type) { const std::string cmd_line = Strings::format( R"("%s" -E %ssum "%s")", @@ -32,7 +133,11 @@ namespace vcpkg::Commands::Hash Util::erase_remove_if(hash, isspace); return hash; } +} +#endif +namespace vcpkg::Commands::Hash +{ const CommandStructure COMMAND_STRUCTURE = { Strings::format("The argument should be a file path\n%s", Help::create_example_string("hash boost_1_62_0.tar.bz2")), @@ -44,19 +149,12 @@ namespace vcpkg::Commands::Hash void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) { - args.parse_arguments(COMMAND_STRUCTURE); - - if (args.command_arguments.size() == 1) - { - auto hash = get_file_hash(paths, args.command_arguments[0], "SHA512"); - System::println(hash); - } - if (args.command_arguments.size() == 2) - { - auto hash = get_file_hash(paths, args.command_arguments[0], args.command_arguments[1]); - System::println(hash); - } + Util::unused(args.parse_arguments(COMMAND_STRUCTURE)); + const fs::path file_to_hash = args.command_arguments[0]; + const std::string algorithm = args.command_arguments.size() == 2 ? args.command_arguments[1] : "SHA512"; + const std::string hash = get_file_hash(paths, file_to_hash, algorithm); + System::println(hash); Checks::exit_success(VCPKG_LINE_INFO); } } diff --git a/toolsrc/vcpkg/vcpkg.vcxproj b/toolsrc/vcpkg/vcpkg.vcxproj index 4def6a74bd..2ab94eb0aa 100644 --- a/toolsrc/vcpkg/vcpkg.vcxproj +++ b/toolsrc/vcpkg/vcpkg.vcxproj @@ -77,7 +77,7 @@ false - winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Bcrypt.lib;%(AdditionalDependencies) @@ -91,7 +91,7 @@ false - winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Bcrypt.lib;%(AdditionalDependencies) @@ -109,7 +109,7 @@ true true - winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Bcrypt.lib;%(AdditionalDependencies) @@ -127,7 +127,7 @@ true true - winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Bcrypt.lib;%(AdditionalDependencies) diff --git a/toolsrc/vcpkgmetricsuploader/vcpkgmetricsuploader.vcxproj b/toolsrc/vcpkgmetricsuploader/vcpkgmetricsuploader.vcxproj index d78e48e137..a2ceef9ce8 100644 --- a/toolsrc/vcpkgmetricsuploader/vcpkgmetricsuploader.vcxproj +++ b/toolsrc/vcpkgmetricsuploader/vcpkgmetricsuploader.vcxproj @@ -77,7 +77,7 @@ false - winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Bcrypt.lib;%(AdditionalDependencies) @@ -91,7 +91,7 @@ false - winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Bcrypt.lib;%(AdditionalDependencies) @@ -109,7 +109,7 @@ true true - winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Bcrypt.lib;%(AdditionalDependencies) @@ -127,7 +127,7 @@ true true - winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Bcrypt.lib;%(AdditionalDependencies) diff --git a/toolsrc/vcpkgtest/vcpkgtest.vcxproj b/toolsrc/vcpkgtest/vcpkgtest.vcxproj index d61b15a71b..a0d44918d2 100644 --- a/toolsrc/vcpkgtest/vcpkgtest.vcxproj +++ b/toolsrc/vcpkgtest/vcpkgtest.vcxproj @@ -120,6 +120,7 @@ Windows $(VCInstallDir)UnitTest\lib;$(VsInstallRoot)\VC\Auxiliary\VS\UnitTest\lib;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Bcrypt.lib;%(AdditionalDependencies) @@ -138,6 +139,7 @@ Windows $(VCInstallDir)UnitTest\lib;$(VsInstallRoot)\VC\Auxiliary\VS\UnitTest\lib;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Bcrypt.lib;%(AdditionalDependencies) @@ -159,6 +161,7 @@ true true $(VCInstallDir)UnitTest\lib;$(VsInstallRoot)\VC\Auxiliary\VS\UnitTest\lib;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Bcrypt.lib;%(AdditionalDependencies) @@ -180,6 +183,7 @@ true true $(VCInstallDir)UnitTest\lib;$(VsInstallRoot)\VC\Auxiliary\VS\UnitTest\lib;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Bcrypt.lib;%(AdditionalDependencies)