From 6858f632c5d5c791d3b58121e0033f091c1f10d1 Mon Sep 17 00:00:00 2001 From: Phatcat Date: Thu, 1 May 2025 02:08:11 +0200 Subject: [PATCH 1/3] Delete FindBotan.cmake Removal of FindBotan and using supplied config target_link_libraries: srp6 need botan and doesn't have it linked libs/shared need to be linked to botan as well --- CMakeLists.txt | 13 +++- Dockerfile | 8 +-- cmake/FindBotan.cmake | 106 --------------------------------- src/libs/shared/CMakeLists.txt | 4 +- src/libs/srp6/CMakeLists.txt | 2 +- 5 files changed, 17 insertions(+), 116 deletions(-) delete mode 100644 cmake/FindBotan.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 245d68a8a..9451571b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,8 +95,17 @@ set(version_file "${CMAKE_CURRENT_BINARY_DIR}/Version.cpp") ############################## # Botan # ############################## -find_package(Botan 2.14.0 REQUIRED) -include_directories(${BOTAN_INCLUDE_DIRS}) +find_package(Botan 3.7.0 REQUIRED) +# Check if the static target exists; otherwise fallback to the shared target. +if(TARGET Botan::Botan-static) + set(BOTAN_LIBRARY Botan::Botan-static) + message(STATUS "Using Botan static library") +elseif(TARGET Botan::Botan) + set(BOTAN_LIBRARY Botan::Botan) + message(STATUS "Using Botan shared library") +else() + message(FATAL_ERROR "No valid Botan target found") +endif() ############################## # MySQL Connector C++ # diff --git a/Dockerfile b/Dockerfile index c65783879..41eb6da23 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,7 +22,7 @@ RUN apt-get -y update && apt-get -y upgrade \ && apt-get -y install cmake \ && apt-get -y install git \ # Install required library packages - && apt-get install -y libbotan-2-dev \ + && apt-get install -y libbotan-3-dev \ && apt-get install -y libmysqlcppconn-dev \ && apt-get install -y zlib1g-dev \ && apt-get install -y libpcre3-dev \ @@ -52,8 +52,6 @@ RUN --mount=type=cache,target=build \ -DCMAKE_INSTALL_PREFIX=${install_dir} \ -DBUILD_OPT_TOOLS=${build_optional_tools} \ -DDISABLE_EMBER_THREADS=${disable_threads} \ - -DBOTAN_ROOT_DIR=/usr/include/botan-2/ \ - -DBOTAN_LIBRARY=/usr/lib/x86_64-linux-gnu/libbotan-2.so \ && cd build && make -j$(nproc) install \ && make test @@ -62,11 +60,11 @@ ARG install_dir=/usr/local/bin ARG working_dir=/usr/src/ember WORKDIR ${install_dir} RUN apt-get -y update \ - && apt-get install -y libbotan-2-19 \ + && apt-get install -y libbotan-3-7 \ && apt-get install -y libmysqlcppconn7v5 \ && apt-get install -y mysql-client COPY --from=builder ${install_dir} ${install_dir} RUN cp configs/*.dist . COPY ./sql ${install_dir}/sql COPY ./scripts ${install_dir} -COPY ./dbcs ${install_dir}/dbcs \ No newline at end of file +COPY ./dbcs ${install_dir}/dbcs diff --git a/cmake/FindBotan.cmake b/cmake/FindBotan.cmake deleted file mode 100644 index ed1b583b4..000000000 --- a/cmake/FindBotan.cmake +++ /dev/null @@ -1,106 +0,0 @@ -# Module for locating the Botan cryptographic library. -# -# Customizable variables: -# BOTAN_ROOT_DIR -# This variable points to the Botan root directory. On Windows the -# library location typically will have to be provided explicitly using the -# -D command-line option. -# -# Read-only variables: -# BOTAN_FOUND -# Indicates whether the library has been found. -# -# BOTAN_INCLUDE_DIRS -# Points to the Botan include directory. -# -# BOTAN_LIBRARIES -# Points to the Botan libraries that should be passed to -# target_link_libararies. -# -# -# Copyright (c) 2012 Sergiu Dotenco -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -INCLUDE (FindPackageHandleStandardArgs) - -SET (_BOTAN_POSSIBLE_LIB_SUFFIXES lib) - -FIND_PATH (BOTAN_ROOT_DIR - NAMES include/botan/botan.h - PATHS ENV BOTANROOT - DOC "Botan root directory") - -FIND_PATH (BOTAN_INCLUDE_DIR - NAMES botan/botan.h - HINTS ${BOTAN_ROOT_DIR} - PATH_SUFFIXES include - DOC "Botan include directory") - -FIND_LIBRARY (BOTAN_LIBRARY_DEBUG - NAMES botand - HINTS ${BOTAN_ROOT_DIR} - PATH_SUFFIXES ${_BOTAN_POSSIBLE_LIB_SUFFIXES} - DOC "Botan debug library") - -FIND_LIBRARY (BOTAN_LIBRARY_RELEASE - NAMES botan - HINTS ${BOTAN_ROOT_DIR} - PATH_SUFFIXES ${_BOTAN_POSSIBLE_LIB_SUFFIXES} - DOC "Botan release library") - -IF (BOTAN_LIBRARY_DEBUG AND BOTAN_LIBRARY_RELEASE) - SET (BOTAN_LIBRARY - optimized ${BOTAN_LIBRARY_RELEASE} - debug ${BOTAN_LIBRARY_DEBUG} CACHE DOC "Botan library") -ELSEIF (BOTAN_LIBRARY_RELEASE) - SET (BOTAN_LIBRARY ${BOTAN_LIBRARY_RELEASE} CACHE STRING "Botan library") -ENDIF (BOTAN_LIBRARY_DEBUG AND BOTAN_LIBRARY_RELEASE) - -IF (BOTAN_INCLUDE_DIR) - SET (_BOTAN_VERSION_HEADER ${BOTAN_INCLUDE_DIR}/botan/build.h) - - IF (EXISTS ${_BOTAN_VERSION_HEADER}) - FILE (STRINGS ${_BOTAN_VERSION_HEADER} _BOTAN_VERSION_TMP REGEX - "#define BOTAN_VERSION_(MAJOR|MINOR|PATCH)[ \t]+[0-9]+") - - STRING (REGEX REPLACE - ".*#define BOTAN_VERSION_MAJOR[ \t]+([0-9]+).*" "\\1" BOTAN_VERSION_MAJOR - ${_BOTAN_VERSION_TMP}) - STRING (REGEX REPLACE - ".*#define BOTAN_VERSION_MINOR[ \t]+([0-9]+).*" "\\1" BOTAN_VERSION_MINOR - ${_BOTAN_VERSION_TMP}) - STRING (REGEX REPLACE - ".*#define BOTAN_VERSION_PATCH[ \t]+([0-9]+).*" "\\1" BOTAN_VERSION_PATCH - ${_BOTAN_VERSION_TMP}) - - SET (BOTAN_VERSION_COUNT 3) - SET (BOTAN_VERSION - ${BOTAN_VERSION_MAJOR}.${BOTAN_VERSION_MINOR}.${BOTAN_VERSION_PATCH}) - ENDIF (EXISTS ${_BOTAN_VERSION_HEADER}) -ENDIF (BOTAN_INCLUDE_DIR) - -SET (BOTAN_INCLUDE_DIRS ${BOTAN_INCLUDE_DIR}) -SET (BOTAN_LIBRARIES ${BOTAN_LIBRARY}) - -MARK_AS_ADVANCED (BOTAN_ROOT_DIR BOTAN_INCLUDE_DIR BOTAN_LIBRARY - BOTAN_LIBRARY_DEBUG BOTAN_LIBRARY_RELEASE) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS (Botan REQUIRED_VARS BOTAN_ROOT_DIR - BOTAN_INCLUDE_DIR BOTAN_LIBRARY VERSION_VAR BOTAN_VERSION) \ No newline at end of file diff --git a/src/libs/shared/CMakeLists.txt b/src/libs/shared/CMakeLists.txt index 955a8b380..aa35810da 100644 --- a/src/libs/shared/CMakeLists.txt +++ b/src/libs/shared/CMakeLists.txt @@ -137,5 +137,5 @@ source_group("Metrics" FILES ${METRICS_SRC}) include_directories(${CMAKE_SOURCE_DIR}/deps/utf8cpp ${PROJECT_BINARY_DIR}/src) add_library(${LIBRARY_NAME} ${LIBRARY_SRC}) target_include_directories(${LIBRARY_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/) -target_link_libraries(${LIBRARY_NAME} PUBLIC logger conpool ${PCRE_LIBRARY}) -set_target_properties(${LIBRARY_NAME} PROPERTIES FOLDER "Common Libraries") \ No newline at end of file +target_link_libraries(${LIBRARY_NAME} PUBLIC logger conpool ${BOTAN_LIBRARY} ${PCRE_LIBRARY}) +set_target_properties(${LIBRARY_NAME} PROPERTIES FOLDER "Common Libraries") diff --git a/src/libs/srp6/CMakeLists.txt b/src/libs/srp6/CMakeLists.txt index 4722e9965..6c4756124 100644 --- a/src/libs/srp6/CMakeLists.txt +++ b/src/libs/srp6/CMakeLists.txt @@ -19,6 +19,6 @@ add_library(${LIBRARY_NAME} include/srp6/detail/Primes.h ) -target_link_libraries(${LIBRARY_NAME} PRIVATE ${Boost_LIBRARIES}) +target_link_libraries(${LIBRARY_NAME} PRIVATE ${Boost_LIBRARIES} ${BOTAN_LIBRARY}) target_include_directories(${LIBRARY_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) set_target_properties(${LIBRARY_NAME} PROPERTIES FOLDER "Common Libraries") From efababa692ded7494cddd7cfcf97df9d05b9104e Mon Sep 17 00:00:00 2001 From: Phatcat Date: Thu, 1 May 2025 02:08:42 +0200 Subject: [PATCH 2/3] Botan-3 Migration Complete Botan-3 migration targeting: Migrate from marked as deprecated functions -1363 padding needs to be done manually now -No serialization directly on the hasher -no declaration of functions with a serialization. --- src/account/AccountService.cpp | 5 ++-- src/gateway/AccountClient.cpp | 4 +-- src/gateway/PacketCrypto.h | 4 +-- src/gateway/states/Authentication.cpp | 2 +- .../shared/database/daos/mysql/PatchDAO.h | 7 +++-- src/libs/srp6/src/Client.cpp | 6 ++-- src/libs/srp6/src/Server.cpp | 6 ++-- src/libs/srp6/src/Util.cpp | 29 +++++++++++-------- src/login/AccountClient.cpp | 4 +-- src/login/Authenticator.cpp | 4 +-- src/login/LoginHandler.cpp | 2 +- src/login/grunt/client/LoginProof.h | 8 +++-- src/login/grunt/server/LoginChallenge.h | 13 +++++---- src/login/grunt/server/LoginProof.h | 7 +++-- src/tools/srpgen/main.cpp | 6 ++-- tests/MPQ.cpp | 20 ++++++------- tests/SRP6.cpp | 18 ++++++------ 17 files changed, 79 insertions(+), 66 deletions(-) diff --git a/src/account/AccountService.cpp b/src/account/AccountService.cpp index 1e18a7225..05b69e982 100644 --- a/src/account/AccountService.cpp +++ b/src/account/AccountService.cpp @@ -46,7 +46,8 @@ AccountService::handle_session_fetch(const SessionLookup& msg, const Link& link, return response; } - auto key = Botan::BigInt::encode(*session); + std::vector key((*session).bytes()); + (*session).serialize_to(std::span(key.data(), key.size())); response.status = Status::OK; response.account_id = msg.account_id(); @@ -120,4 +121,4 @@ AccountService::handle_disconnect_by_id(const DisconnectID& msg, const Link& lin return std::nullopt; } -} // ember \ No newline at end of file +} // ember diff --git a/src/gateway/AccountClient.cpp b/src/gateway/AccountClient.cpp index cfa5aeb4b..1d4fc7061 100644 --- a/src/gateway/AccountClient.cpp +++ b/src/gateway/AccountClient.cpp @@ -87,8 +87,8 @@ void AccountClient::handle_locate_response(std::expectedkey()->data(), msg->key()->size()); + auto key = Botan::BigInt::from_bytes(std::span(msg->key()->data(), msg->key()->size())); cb(msg->status(), std::move(key)); } -} // gateway, ember \ No newline at end of file +} // gateway, ember diff --git a/src/gateway/PacketCrypto.h b/src/gateway/PacketCrypto.h index 15fb0c1dd..70ce7a3b0 100644 --- a/src/gateway/PacketCrypto.h +++ b/src/gateway/PacketCrypto.h @@ -44,7 +44,7 @@ class PacketCrypto final { ); key_.resize(key.bytes(), boost::container::default_init); - key.binary_encode(key_.data(), key_.size()); + key.serialize_to(std::span( key_.data() + (key_.size() - key.bytes()), key.bytes() )); } inline void encrypt(auto& data) { @@ -77,4 +77,4 @@ class PacketCrypto final { } }; -} // gateway, ember \ No newline at end of file +} // gateway, ember diff --git a/src/gateway/states/Authentication.cpp b/src/gateway/states/Authentication.cpp index f6b167f5b..59a6c5d6a 100644 --- a/src/gateway/states/Authentication.cpp +++ b/src/gateway/states/Authentication.cpp @@ -164,7 +164,7 @@ void prove_session(ClientContext& ctx, const Botan::BigInt& key) { key.bytes(), boost::container::default_init ); - key.binary_encode(k_bytes.data(), k_bytes.size()); + key.serialize_to(std::span(k_bytes.data() + (k_bytes.size() - key.bytes()), key.bytes())); const std::uint32_t protocol_id = 0; // best guess, this is hardcoded to zero in the client auto& auth_ctx = std::get(ctx.state_ctx); diff --git a/src/libs/shared/shared/database/daos/mysql/PatchDAO.h b/src/libs/shared/shared/database/daos/mysql/PatchDAO.h index 880cae936..21c13a2d0 100644 --- a/src/libs/shared/shared/database/daos/mysql/PatchDAO.h +++ b/src/libs/shared/shared/database/daos/mysql/PatchDAO.h @@ -64,7 +64,8 @@ class MySQLPatchDAO final : public PatchDAO { const auto md5 = res->getString("md5"); Botan::BigInt md5_int(md5.asStdString()); - Botan::BigInt::encode_1363(meta.file_meta.md5.data(), meta.file_meta.md5.size(), md5_int); + std::fill(meta.file_meta.md5.begin(), meta.file_meta.md5.end(), 0); // 1363 style padding + md5_int.serialize_to({ meta.file_meta.md5.data() + meta.file_meta.md5.size() - md5_int.bytes(), md5_int.bytes() }); patches.emplace_back(std::move(meta)); } @@ -87,8 +88,8 @@ class MySQLPatchDAO final : public PatchDAO { stmt->setBoolean(3, meta.mpq); stmt->setString(4, meta.file_meta.name); stmt->setUInt64(5, meta.file_meta.size); - auto md5 = Botan::BigInt::decode(reinterpret_cast(meta.file_meta.md5.data()), - meta.file_meta.md5.size()); + auto md5 = Botan::BigInt::from_bytes(std::span(reinterpret_cast( + meta.file_meta.md5.data()), meta.file_meta.md5.size())); stmt->setString(6, md5.to_hex_string()); stmt->setUInt(7, meta.locale_id); diff --git a/src/libs/srp6/src/Client.cpp b/src/libs/srp6/src/Client.cpp index edc9af153..6830e0a35 100644 --- a/src/libs/srp6/src/Client.cpp +++ b/src/libs/srp6/src/Client.cpp @@ -23,7 +23,7 @@ Client::Client(std::string identifier, std::string password, Generator gen, std: : Client(std::move(identifier), std::move(password), gen, - BigInt::decode((AutoSeeded_RNG()).random_vec(key_size)) % gen.prime(), + BigInt::from_bytes(std::span{ (AutoSeeded_RNG().random_vec(key_size)).data(), key_size }) % gen.prime(), srp6a) { } Client::Client(std::string identifier, std::string password, Generator gen, BigInt a, bool srp6a) @@ -64,7 +64,7 @@ SessionKey Client::session_key(const BigInt& B, std::span sa return SessionKey(detail::interleaved_hash(detail::encode_flip_1363(S, N.bytes()))); } else { KeyType key(S.bytes(), boost::container::default_init); - S.binary_encode(key.data(), key.size()); + S.serialize_to(std::span(key.data(), key.size())); return SessionKey(key); } } @@ -74,4 +74,4 @@ BigInt Client::generate_proof(const SessionKey& key, const Botan::BigInt& B, return generate_client_proof(identifier_, key, gen_.prime(), gen_.generator(), A_, B, salt); } -} // srp6, ember \ No newline at end of file +} // srp6, ember diff --git a/src/libs/srp6/src/Server.cpp b/src/libs/srp6/src/Server.cpp index 08cbb3db8..61ec77bab 100644 --- a/src/libs/srp6/src/Server.cpp +++ b/src/libs/srp6/src/Server.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 - 2024 Ember + * Copyright (c) 2014 - 2025 Ember * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -48,7 +48,7 @@ SessionKey Server::session_key(const BigInt& A, Compliance mode, bool interleave return SessionKey(detail::interleaved_hash(detail::encode_flip_1363(S, N_.bytes()))); } else { KeyType key(N_.bytes(), boost::container::default_init); - S.binary_encode(key.data(), key.size()); + S.serialize_to(std::span(key.data(), key.size())); return SessionKey(key); } } @@ -58,4 +58,4 @@ BigInt Server::generate_proof(const SessionKey& key, const Botan::BigInt& A, return generate_server_proof(A, client_proof, key, N_.bytes()); } -} // srp6, ember \ No newline at end of file +} // srp6, ember diff --git a/src/libs/srp6/src/Util.cpp b/src/libs/srp6/src/Util.cpp index 9962bd440..66420f179 100644 --- a/src/libs/srp6/src/Util.cpp +++ b/src/libs/srp6/src/Util.cpp @@ -21,19 +21,20 @@ namespace detail { Botan::BigInt decode_flip(std::span val) { std::ranges::reverse(val); - return Botan::BigInt::decode(val.data(), val.size()); + return Botan::BigInt::from_bytes(std::span(val.data(), val.size())); } SmallVec encode_flip(const Botan::BigInt& val) { SmallVec res(val.bytes(), boost::container::default_init); - val.binary_encode(res.data(), res.size()); + val.serialize_to(std::span(res.data(), res.size())); std::ranges::reverse(res); return res; } SmallVec encode_flip_1363(const Botan::BigInt& val, std::size_t padding) { SmallVec res(padding, boost::container::default_init); - Botan::BigInt::encode_1363(res.data(), res.size(), val); + std::fill(res.begin(), res.end(), 0); // 1363 style padding + val.serialize_to({ res.data() + res.size() - val.bytes(), val.bytes() }); std::ranges::reverse(res); return res; } @@ -69,15 +70,15 @@ Botan::BigInt scrambler(const Botan::BigInt& A, const Botan::BigInt& B, std::siz auto hasher = Botan::HashFunction::create_or_throw("SHA-1"); BOOST_ASSERT_MSG(SHA1_LEN == hasher->output_length(), "Bad hash length"); std::array hash_out; - SmallVec vec(padding, boost::container::default_init); + SmallVec vec(padding, 0); // 1363 style padding if(mode == Compliance::RFC5054) { - Botan::BigInt::encode_1363(vec.data(), vec.size(), A); + A.serialize_to(std::span(vec.data(), vec.size())); hasher->update(vec.data(), vec.size()); - Botan::BigInt::encode_1363(vec.data(), vec.size(), B); + B.serialize_to(std::span(vec.data(), vec.size())); hasher->update(vec.data(), vec.size()); hasher->final(hash_out.data()); - return Botan::BigInt::decode(hash_out.data(), hash_out.size()); + return Botan::BigInt::from_bytes(std::span(hash_out.data(), hash_out.size())); } else { const auto& a_enc = encode_flip_1363(A, padding); const auto& b_enc = encode_flip_1363(B, padding); @@ -93,10 +94,14 @@ Botan::BigInt compute_k(const Botan::BigInt& g, const Botan::BigInt& N) { std::array hash; auto hasher = Botan::HashFunction::create_or_throw("SHA-1"); BOOST_ASSERT_MSG(SHA1_LEN == hasher->output_length(), "Bad hash length"); - hasher->update(Botan::BigInt::encode(N)); - hasher->update(Botan::BigInt::encode_1363(g, N.bytes())); + std::vector n_buf(N.bytes(), 0); // 1363 style padding + N.serialize_to({ n_buf.data() + n_buf.size() - N.bytes(), N.bytes() }); + std::vector g_buf(N.bytes(), 0); // 1363 style padding + g.serialize_to({ g_buf.data() + g_buf.size() - g.bytes(), g.bytes() }); + hasher->update(n_buf.data(), n_buf.size()); + hasher->update(g_buf.data(), g_buf.size()); hasher->final(hash.data()); - return Botan::BigInt::decode(hash.data(), hash.size()); + return Botan::BigInt::from_bytes(std::span(hash.data(), hash.size())); } Botan::BigInt compute_x(std::string_view identifier, std::string_view password, @@ -123,7 +128,7 @@ Botan::BigInt compute_x(std::string_view identifier, std::string_view password, hasher->final(hash.data()); if(mode == Compliance::RFC5054) { - return Botan::BigInt::decode(hash.data(), hash.size()); + return Botan::BigInt::from_bytes(std::span(hash.data(), hash.size())); } else { return detail::decode_flip(hash); } @@ -194,4 +199,4 @@ Botan::BigInt generate_verifier(std::string_view identifier, std::string_view pa return detail::generate(identifier, password, generator, salt, mode); } -} // srp6, ember \ No newline at end of file +} // srp6, ember diff --git a/src/login/AccountClient.cpp b/src/login/AccountClient.cpp index 3f16ca8df..e786ed017 100644 --- a/src/login/AccountClient.cpp +++ b/src/login/AccountClient.cpp @@ -90,8 +90,8 @@ void AccountClient::handle_locate_response(std::expectedkey()->data(), msg->key()->size()); + auto key = Botan::BigInt::from_bytes(std::span(msg->key()->data(), msg->key()->size())); cb(msg->status(), std::move(key)); } -} // ember \ No newline at end of file +} // ember diff --git a/src/login/Authenticator.cpp b/src/login/Authenticator.cpp index ffb382831..e93d20508 100644 --- a/src/login/Authenticator.cpp +++ b/src/login/Authenticator.cpp @@ -53,7 +53,7 @@ ReconnectAuthenticator::ReconnectAuthenticator(utf8_string username, : username_(std::move(username)) { std::ranges::copy(salt, salt_.data()); sess_key_.t.resize(session_key.bytes()); - session_key.binary_encode(sess_key_.t.data(), sess_key_.t.size()); + session_key.serialize_to(std::span(sess_key_.t.data() + (sess_key_.t.size() - session_key.bytes()), session_key.bytes())); } bool ReconnectAuthenticator::proof_check(std::span salt, @@ -69,4 +69,4 @@ bool ReconnectAuthenticator::proof_check(std::span salt, return std::ranges::equal(res, proof); } -} // ember \ No newline at end of file +} // ember diff --git a/src/login/LoginHandler.cpp b/src/login/LoginHandler.cpp index 6399cefb7..dd65dfaf1 100644 --- a/src/login/LoginHandler.cpp +++ b/src/login/LoginHandler.cpp @@ -360,7 +360,7 @@ bool LoginHandler::validate_client_integrity(std::span hash, salt.bytes(), boost::container::default_init ); - salt.binary_encode(bytes.data(), bytes.size()); + salt.serialize_to(std::span(bytes.data(), salt.bytes())); std::ranges::reverse(bytes); return validate_client_integrity(hash, bytes, reconnect); } diff --git a/src/login/grunt/client/LoginProof.h b/src/login/grunt/client/LoginProof.h index 8a7919434..6fb091838 100644 --- a/src/login/grunt/client/LoginProof.h +++ b/src/login/grunt/client/LoginProof.h @@ -166,11 +166,13 @@ class LoginProof final : public Packet { stream << opcode; std::array a_bytes; - Botan::BigInt::encode_1363(a_bytes.data(), a_bytes.size(), A); + std::fill(a_bytes.begin(), a_bytes.end(), 0); // 1363 style padding + A.serialize_to({ a_bytes.data() + a_bytes.size() - A.bytes(), A.bytes() }); stream.put(a_bytes.rbegin(), a_bytes.rend()); std::array m1_bytes; - Botan::BigInt::encode_1363(m1_bytes.data(), m1_bytes.size(), M1); + std::fill(m1_bytes.begin(), m1_bytes.end(), 0); // 1363 style padding + M1.serialize_to({ m1_bytes.data() + m1_bytes.size() - M1.bytes(), M1.bytes() }); stream.put(m1_bytes.rbegin(), m1_bytes.rend()); stream.put(client_checksum.data(), client_checksum.size()); @@ -193,4 +195,4 @@ class LoginProof final : public Packet { } }; -} // client, grunt, ember \ No newline at end of file +} // client, grunt, ember diff --git a/src/login/grunt/server/LoginChallenge.h b/src/login/grunt/server/LoginChallenge.h index 524852151..bab21dcb7 100644 --- a/src/login/grunt/server/LoginChallenge.h +++ b/src/login/grunt/server/LoginChallenge.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 - 2024 Ember + * Copyright (c) 2015 - 2025 Ember * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -132,7 +132,8 @@ class LoginChallenge final : public Packet { } std::array bytes{}; - Botan::BigInt::encode_1363(bytes.data(), bytes.size(), B); + std::fill(bytes.begin(), bytes.end(), 0); // 1363 style padding + B.serialize_to({ bytes.data() + (bytes.size() - B.bytes()), B.bytes() }); stream.put(bytes.rbegin(), bytes.rend()); stream << g_len; @@ -140,11 +141,13 @@ class LoginChallenge final : public Packet { stream << n_len; static_assert(bytes.size() == PRIME_LENGTH); - Botan::BigInt::encode_1363(bytes.data(), bytes.size(), N); + std::fill(bytes.begin(), bytes.end(), 0); // 1363 style padding + N.serialize_to({ bytes.data() + (bytes.size() - N.bytes()), N.bytes() }); stream.put(bytes.rbegin(), bytes.rend()); static_assert(bytes.size() == SALT_LENGTH); - Botan::BigInt::encode_1363(bytes.data(), bytes.size(), s); + std::fill(bytes.begin(), bytes.end(), 0); // 1363 style padding + s.serialize_to({ bytes.data() + (bytes.size() - s.bytes()), s.bytes() }); stream.put(bytes.rbegin(), bytes.rend()); stream.put(checksum_salt.data(), checksum_salt.size()); @@ -157,4 +160,4 @@ class LoginChallenge final : public Packet { } }; -} // server, grunt, ember \ No newline at end of file +} // server, grunt, ember diff --git a/src/login/grunt/server/LoginProof.h b/src/login/grunt/server/LoginProof.h index a061bafb1..ee95c982e 100644 --- a/src/login/grunt/server/LoginProof.h +++ b/src/login/grunt/server/LoginProof.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 - 2024 Ember + * Copyright (c) 2015 - 2025 Ember * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -93,11 +93,12 @@ class LoginProof final : public Packet { } std::array bytes{}; - Botan::BigInt::encode_1363(bytes.data(), bytes.size(), M2); + std::fill(bytes.begin(), bytes.end(), 0); // 1363 style padding + M2.serialize_to({ bytes.data() + (bytes.size() - M2.bytes()), M2.bytes() }); stream.put(bytes.rbegin(), bytes.rend()); stream << survey_id; } }; -} // server, grunt, ember \ No newline at end of file +} // server, grunt, ember diff --git a/src/tools/srpgen/main.cpp b/src/tools/srpgen/main.cpp index 880b5cbe9..758e6f4f6 100644 --- a/src/tools/srpgen/main.cpp +++ b/src/tools/srpgen/main.cpp @@ -84,7 +84,7 @@ void launch(const po::variables_map& args) { void plaintext_output(std::string_view username, const Botan::BigInt& verifier, std::span salt) { std::cout << "Username: " << username << "\n"; - std::cout << "Verifier: " << "0x" << std::hex << verifier << "\n"; + std::cout << "Verifier: " << "0x" << verifier.to_hex_string() << "\n"; std::cout << "Salt: "; for(auto byte : salt) { @@ -94,7 +94,7 @@ void plaintext_output(std::string_view username, const Botan::BigInt& verifier, void json_output(std::string_view username, const Botan::BigInt& verifier, std::span salt) { const auto vstr = std::format("0x{}", verifier.to_hex_string()); - const auto saltdec = Botan::BigInt::decode(salt.data(), salt.size()); + const auto saltdec = Botan::BigInt::from_bytes(std::span(salt.data(), salt.size())); const auto sstr = std::format("0x{}", saltdec.to_hex_string()); json data; @@ -123,4 +123,4 @@ po::variables_map parse_arguments(const int argc, const char* argv[]) { po::notify(options); return options; -} \ No newline at end of file +} diff --git a/tests/MPQ.cpp b/tests/MPQ.cpp index a8411f9e1..27b7c3688 100644 --- a/tests/MPQ.cpp +++ b/tests/MPQ.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Ember + * Copyright (c) 2024 - 2025 Ember * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -122,7 +122,7 @@ TEST(MPQ, Extract_WAV) { mpq::DynamicMemorySink sink; ASSERT_NO_THROW(archive->extract_file("owl.wav", sink)); const auto md5_buf = util::generate_md5(sink.data()); - const auto md5 = Botan::BigInt::decode(md5_buf.data(), md5_buf.size()); + const auto md5 = Botan::BigInt::from_bytes(std::span(md5_buf.data(), md5_buf.size())); Botan::BigInt expected("0x3a66b4b718686cb4d5aa143895290d84"); ASSERT_EQ(md5, expected); } @@ -137,7 +137,7 @@ TEST(MPQ, Extract_MP3) { mpq::DynamicMemorySink sink; ASSERT_NO_THROW(archive->extract_file("owl.mp3", sink)); const auto md5_buf = util::generate_md5(sink.data()); - const auto md5 = Botan::BigInt::decode(md5_buf.data(), md5_buf.size()); + const auto md5 = Botan::BigInt::from_bytes(std::span(md5_buf.data(), md5_buf.size())); Botan::BigInt expected("0x2f7b030648e1f7ec77109c659bbea3ce"); ASSERT_EQ(md5, expected); } @@ -152,7 +152,7 @@ TEST(MPQ, Extract_Binary) { mpq::DynamicMemorySink sink; ASSERT_NO_THROW(archive->extract_file("elevated_1920_1080.ex_", sink)); const auto md5_buf = util::generate_md5(sink.data()); - const auto md5 = Botan::BigInt::decode(md5_buf.data(), md5_buf.size()); + const auto md5 = Botan::BigInt::from_bytes(std::span(md5_buf.data(), md5_buf.size())); Botan::BigInt expected("0xf3b82b404a36a9714bb266007cacd489"); ASSERT_EQ(md5, expected); } @@ -167,7 +167,7 @@ TEST(MPQ, Extract_JPG) { mpq::DynamicMemorySink sink; ASSERT_NO_THROW(archive->extract_file("ember.jpg", sink)); const auto md5_buf = util::generate_md5(sink.data()); - const auto md5 = Botan::BigInt::decode(md5_buf.data(), md5_buf.size()); + const auto md5 = Botan::BigInt::from_bytes(std::span(md5_buf.data(), md5_buf.size())); Botan::BigInt expected("0x8a623acdf09f9388719010d76a5c7a52"); ASSERT_EQ(md5, expected); } @@ -182,7 +182,7 @@ TEST(MPQ, Extract_PNG) { mpq::DynamicMemorySink sink; ASSERT_NO_THROW(archive->extract_file("ember.png", sink)); const auto md5_buf = util::generate_md5(sink.data()); - const auto md5 = Botan::BigInt::decode(md5_buf.data(), md5_buf.size()); + const auto md5 = Botan::BigInt::from_bytes(std::span(md5_buf.data(), md5_buf.size())); Botan::BigInt expected("0xb29a1ad8ebeef28de68fa9bb0325b893"); ASSERT_EQ(md5, expected); } @@ -196,7 +196,7 @@ TEST(MPQ, Extract_Listfile) { mpq::DynamicMemorySink sink; ASSERT_NO_THROW(archive->extract_file("(listfile)", sink)); const auto md5_buf = util::generate_md5(sink.data()); - const auto md5 = Botan::BigInt::decode(md5_buf.data(), md5_buf.size()); + const auto md5 = Botan::BigInt::from_bytes(std::span(md5_buf.data(), md5_buf.size())); Botan::BigInt expected("0xc4185e8d87a01ac3057a6498deccab1e"); ASSERT_EQ(md5, expected); } @@ -210,7 +210,7 @@ TEST(MPQ, Extract_Attributes) { mpq::DynamicMemorySink sink; ASSERT_NO_THROW(archive->extract_file("(attributes)", sink)); const auto md5_buf = util::generate_md5(sink.data()); - const auto md5 = Botan::BigInt::decode(md5_buf.data(), md5_buf.size()); + const auto md5 = Botan::BigInt::from_bytes(std::span(md5_buf.data(), md5_buf.size())); Botan::BigInt expected("0x44fd6bad334ea24d8901e80ab20c07ba"); ASSERT_EQ(md5, expected); } @@ -224,7 +224,7 @@ TEST(MPQ, Extract_Text) { mpq::DynamicMemorySink sink; ASSERT_NO_THROW(archive->extract_file("compressed.txt", sink)); const auto md5_buf = util::generate_md5(sink.data()); - const auto md5 = Botan::BigInt::decode(md5_buf.data(), md5_buf.size()); + const auto md5 = Botan::BigInt::from_bytes(std::span(md5_buf.data(), md5_buf.size())); Botan::BigInt expected("0xf13fad545731a0b71b2cc17e1acd48f4"); ASSERT_EQ(md5, expected); } @@ -234,4 +234,4 @@ TEST(MPQ, Locate_BadAlignment) { std::span span(data + 1, sizeof(data) - 1); // force misaligned buffer auto result = mpq::locate_archive(span); ASSERT_EQ(result.error(), mpq::ErrorCode::BAD_ALIGNMENT); -} \ No newline at end of file +} diff --git a/tests/SRP6.cpp b/tests/SRP6.cpp index bf40469d2..3fdcee960 100644 --- a/tests/SRP6.cpp +++ b/tests/SRP6.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 - 2024 Ember + * Copyright (c) 2014 - 2025 Ember * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -43,7 +43,7 @@ class srp6SessionTest : public ::testing::Test { TEST(srp6a, RFC5054_TestVectors) { std::string identifier { "alice" }; std::string password { "password123" }; - const auto salt = Botan::BigInt::encode(Botan::BigInt(("0xBEB25379D1A8581EB5A727673A2441EE"))); + const auto salt = Botan::BigInt("0xBEB25379D1A8581EB5A727673A2441EE").serialize(); srp6::Generator gen(srp6::Generator::Group::_1024_BIT); Botan::BigInt expected_k("0x7556AA045AEF2CDD07ABAF0F665C3E818913186F"); @@ -97,9 +97,9 @@ TEST(srp6a, RFC5054_TestVectors) { const auto& c_sess_key = client.session_key(expected_B, salt, srp6::Compliance::RFC5054).t; const auto& s_sess_key = server.session_key(expected_A, srp6::Compliance::RFC5054).t; - EXPECT_EQ(expected_key, Botan::BigInt::decode(c_sess_key.data(), c_sess_key.size())) + EXPECT_EQ(expected_key, Botan::BigInt::from_bytes(std::span(c_sess_key.data(), c_sess_key.size()))) << "Client key did not match expected value!"; - EXPECT_EQ(expected_key, Botan::BigInt::decode(s_sess_key.data(), s_sess_key.size())) + EXPECT_EQ(expected_key, Botan::BigInt::from_bytes(std::span(s_sess_key.data(), s_sess_key.size()))) << "Server key did not match expected value!"; } @@ -142,7 +142,7 @@ TEST_F(srp6SessionTest, GameAuthentication) { srp6::SessionKey key = server.session_key(A); Botan::BigInt M1_S = srp6::generate_client_proof("CHAOSVEX", key, gen.prime(), gen.generator(), A, - server.public_ephemeral(), Botan::BigInt::encode(salt)); + server.public_ephemeral(), salt.serialize()); Botan::BigInt M2_S = server.generate_proof(key, A, M1); EXPECT_EQ(M1, M1_S) << "Server's calculated client proof did not match the replayed proof!"; @@ -176,7 +176,7 @@ TEST(srp6Regressions, SaltZeroPad_ComputeX) { srp6::Generator gen(srp6::Generator::Group::_1024_BIT); Botan::BigInt expected_x("0x7E5250F2CB894FD9703611318C387A773FD52C09"); - Botan::BigInt x = srp6::detail::compute_x(username, password, Botan::BigInt::encode(salt), srp6::Compliance::GAME); + Botan::BigInt x = srp6::detail::compute_x(username, password, salt.serialize(), srp6::Compliance::GAME); ASSERT_EQ(expected_x, x) << "x was calculated incorrectly!"; } @@ -186,7 +186,7 @@ TEST(srp6Regressions, SaltZeroPad_GenerateUser) { Botan::BigInt salt("0xBEB25379D1A8581EB5A727673A2441EE"); auto gen = srp6::Generator(srp6::Generator::Group::_256_BIT); - auto verifier = srp6::generate_verifier(username, password, gen, Botan::BigInt::encode(salt), srp6::Compliance::GAME); + auto verifier = srp6::generate_verifier(username, password, gen, salt.serialize(), srp6::Compliance::GAME); Botan::BigInt expected_v("0x399CF53C149F220F4AA88F7F2F6CA9CB6E4C44EA5240AC0F65601F392F32A16A"); ASSERT_EQ(expected_v, verifier) << "Verifier was calculated incorrectly!"; @@ -199,7 +199,7 @@ TEST(srp6Regressions, NPad_GenerateClientProof) { const Botan::BigInt b("0x809C1BC78BDB3873D286FDADF38D1524348C9CA5AB63E7793EF6A7944C5A8D"); Botan::BigInt session_val("0x42C6518D6F338C050717427B18F7C6B6131C968B0CFC20C43AAAD61625F286DA55E24BF6A2CBDC79"); srp6::KeyType kt(session_val.bytes(), boost::container::default_init); - session_val.binary_encode(kt.data(), kt.size()); + session_val.serialize_to({ kt.data() + (kt.size() - session_val.bytes()), session_val.bytes() }); const srp6::SessionKey key(std::move(kt)); const std::array salt { @@ -223,4 +223,4 @@ TEST(srp6Regressions, SPad_VerifyKey) { const Botan::BigInt sbytes(key.t.data(), key.t.size()); const Botan::BigInt correct_key("0xEE57F5996D4EEDFFDE38EE79492AB4A5E57CD25C3CE98B035D4BA9A7E05D56C0DAF0F30D9797C216"); EXPECT_EQ(correct_key, sbytes) << "Computed key incorrectly"; -} \ No newline at end of file +} From acf25af30e2a957389961276d6bb14b3aa88275e Mon Sep 17 00:00:00 2001 From: Phatcat Date: Fri, 25 Apr 2025 20:23:29 +0200 Subject: [PATCH 3/3] [DOCKER]: botan-config.cmake patch for libbotan-3-dev Patch the botan config file for libbotan-3-dev. It is expecting the header files in a wrong location Same goes for the library files, it is not considering multi architecture. --- Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Dockerfile b/Dockerfile index 41eb6da23..291fb0076 100644 --- a/Dockerfile +++ b/Dockerfile @@ -45,6 +45,12 @@ ARG disable_threads=0 ARG build_type=Rel ARG install_dir=/usr/local/bin +# Patch the Botan config file for header paths: (THIS IS FIXED IN BOTAN 3.8 - REMOVE WHEN apt-get HAS UPDATED) +RUN sh -c 'arch=$(dpkg-architecture -qDEB_HOST_MULTIARCH) && \ + BOTAN_CFG=$(find / -type f -iname "botan-config.cmake" 2>/dev/null | grep "/usr/lib/$arch" | head -n1) && \ + [ -n "$BOTAN_CFG" ] && \ + sed -i -e "s|\${_Botan_PREFIX}/include|/usr/include|g" -e "s|\${_Botan_PREFIX}/lib|/usr/lib/$arch|g" "$BOTAN_CFG"' + # Generate Makefile & compile RUN --mount=type=cache,target=build \ cmake -S . -B build \