diff --git a/CMakeLists.txt b/CMakeLists.txt
index 06eba07a..869e3205 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -61,6 +61,7 @@ if(UNIX AND NOT APPLE)
option(WITH_XC_FDOSECRETS "Implement freedesktop.org Secret Storage Spec server side API." OFF)
endif()
option(WITH_XC_DOCS "Enable building of documentation" ON)
+option(KPXC_DEV_BOTAN3 "Build against Botan3" OFF)
set(WITH_XC_X11 ON CACHE BOOL "Enable building with X11 deps")
@@ -298,6 +299,10 @@ if(CMAKE_BUILD_TYPE_LOWER STREQUAL "debug")
check_add_gcc_compiler_flag("-Wshadow-compatible-local")
check_add_gcc_compiler_flag("-Wshadow-local")
add_gcc_compiler_flags("-Werror")
+ # This is needed since compiling aginst Botan3 requires compiling against C++20
+ if(KPXC_DEV_BOTAN3)
+ add_gcc_compiler_cxxflags("-Wno-error=deprecated-enum-enum-conversion -Wno-error=deprecated")
+ endif()
endif()
if (NOT HAIKU)
@@ -343,7 +348,11 @@ if(UNIX AND NOT APPLE)
endif()
set(CMAKE_C_STANDARD 99)
-set(CMAKE_CXX_STANDARD 17)
+if(KPXC_DEV_BOTAN3)
+ set(CMAKE_CXX_STANDARD 20)
+else()
+ set(CMAKE_CXX_STANDARD 17)
+endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
check_cxx_compiler_flag("-fsized-deallocation" CXX_HAS_fsized_deallocation)
@@ -529,12 +538,26 @@ endif()
# Make sure we don't enable asserts there.
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_NONE QT_NO_DEBUG)
-# Find Botan2
-find_package(Botan2 REQUIRED)
-if(BOTAN2_VERSION VERSION_LESS "2.11.0")
- message(FATAL_ERROR "Botan2 2.11.0 or higher is required")
+if(KPXC_DEV_BOTAN3)
+ # Find Botan3
+ find_package(Botan3 REQUIRED)
+ if(BOTAN3_VERSION VERSION_LESS "3.0.0")
+ message(FATAL_ERROR "Botan3 3.0.0 or higher is required")
+ endif()
+ set(BOTAN_VERSION "${BOTAN3_VERSION}")
+ set(BOTAN_INCLUDE_DIR "${BOTAN3_INCLUDE_DIR}")
+ set(BOTAN_LIBRARIES "${BOTAN3_LIBRARIES}")
+else()
+ # Find Botan2
+ find_package(Botan2 REQUIRED)
+ if(BOTAN2_VERSION VERSION_LESS "2.11.0")
+ message(FATAL_ERROR "Botan2 2.11.0 or higher is required")
+ endif()
+ set(BOTAN_VERSION "${BOTAN2_VERSION}")
+ set(BOTAN_INCLUDE_DIR "${BOTAN2_INCLUDE_DIR}")
+ set(BOTAN_LIBRARIES "${BOTAN2_LIBRARIES}")
endif()
-include_directories(SYSTEM ${BOTAN2_INCLUDE_DIR})
+include_directories(SYSTEM ${BOTAN_INCLUDE_DIR})
# Find Argon2 -- Botan 2.18 and below does not support threaded Argon2
find_library(ARGON2_LIBRARIES NAMES argon2)
find_path(ARGON2_INCLUDE_DIR NAMES argon2.h PATH_SUFFIXES local/include)
diff --git a/cmake/FindBotan3.cmake b/cmake/FindBotan3.cmake
new file mode 100644
index 00000000..f59eb414
--- /dev/null
+++ b/cmake/FindBotan3.cmake
@@ -0,0 +1,106 @@
+# Copyright (c) 2018 Ribose Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+#.rst:
+# FindBotan3
+# -----------
+#
+# Find the botan-3 library.
+#
+# IMPORTED Targets
+# ^^^^^^^^^^^^^^^^
+#
+# This module defines :prop_tgt:`IMPORTED` targets:
+#
+# ``Botan3::Botan3``
+# The botan-3 library, if found.
+#
+# Result variables
+# ^^^^^^^^^^^^^^^^
+#
+# This module defines the following variables:
+#
+# ::
+#
+# BOTAN3_FOUND - true if the headers and library were found
+# BOTAN3_INCLUDE_DIRS - where to find headers
+# BOTAN3_LIBRARIES - list of libraries to link
+# BOTAN3_VERSION - library version that was found, if any
+
+# find the headers
+find_path(BOTAN3_INCLUDE_DIR
+ NAMES botan/version.h
+ PATH_SUFFIXES botan-3
+)
+
+# find the library
+find_library(BOTAN3_LIBRARY NAMES botan-3 libbotan-3 botan)
+
+# determine the version
+if(BOTAN3_INCLUDE_DIR AND EXISTS "${BOTAN3_INCLUDE_DIR}/botan/build.h")
+ file(STRINGS "${BOTAN3_INCLUDE_DIR}/botan/build.h" botan3_version_str
+ REGEX "^#define[\t ]+(BOTAN_VERSION_[A-Z]+)[\t ]+[0-9]+")
+
+ string(REGEX REPLACE ".*#define[\t ]+BOTAN_VERSION_MAJOR[\t ]+([0-9]+).*"
+ "\\1" _botan3_version_major "${botan3_version_str}")
+ string(REGEX REPLACE ".*#define[\t ]+BOTAN_VERSION_MINOR[\t ]+([0-9]+).*"
+ "\\1" _botan3_version_minor "${botan3_version_str}")
+ string(REGEX REPLACE ".*#define[\t ]+BOTAN_VERSION_PATCH[\t ]+([0-9]+).*"
+ "\\1" _botan3_version_patch "${botan3_version_str}")
+ set(BOTAN3_VERSION "${_botan3_version_major}.${_botan3_version_minor}.${_botan3_version_patch}"
+ CACHE INTERNAL "The version of Botan which was detected")
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Botan3
+ REQUIRED_VARS BOTAN3_LIBRARY BOTAN3_INCLUDE_DIR
+ VERSION_VAR BOTAN3_VERSION
+)
+
+if(BOTAN3_FOUND)
+ set(BOTAN3_INCLUDE_DIRS ${BOTAN3_INCLUDE_DIR} ${PC_BOTAN3_INCLUDE_DIRS})
+ set(BOTAN3_LIBRARIES ${BOTAN3_LIBRARY})
+endif()
+
+if(BOTAN3_FOUND AND NOT TARGET Botan3::Botan3)
+ # create the new library target
+ add_library(Botan3::Botan3 UNKNOWN IMPORTED)
+ # set the required include dirs for the target
+ if(BOTAN3_INCLUDE_DIRS)
+ set_target_properties(Botan3::Botan3
+ PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${BOTAN3_INCLUDE_DIRS}"
+ )
+ endif()
+ # set the required libraries for the target
+ if(EXISTS "${BOTAN3_LIBRARY}")
+ set_target_properties(Botan3::Botan3
+ PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${BOTAN3_LIBRARY}"
+ )
+ endif()
+endif()
+
+mark_as_advanced(BOTAN3_INCLUDE_DIR BOTAN3_LIBRARY)
diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts
index 62db8cf5..af7b9de6 100644
--- a/share/translations/keepassxc_en.ts
+++ b/share/translations/keepassxc_en.ts
@@ -7594,7 +7594,7 @@ Kernel: %3 %4
- Botan library must be at least 2.11.x, found %1.%2.%3
+ Botan library must be at least %1, found %2.%3.%4
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3a589842..8b5c4b58 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -338,7 +338,7 @@ target_link_libraries(keepassx_core
Qt5::Concurrent
Qt5::Network
Qt5::Widgets
- ${BOTAN2_LIBRARIES}
+ ${BOTAN_LIBRARIES}
${PCSC_LIBRARIES}
${ZXCVBN_LIBRARIES}
${ZLIB_LIBRARIES}
diff --git a/src/browser/CMakeLists.txt b/src/browser/CMakeLists.txt
index 98715cb1..9bd05385 100755
--- a/src/browser/CMakeLists.txt
+++ b/src/browser/CMakeLists.txt
@@ -33,5 +33,5 @@ if(WITH_XC_BROWSER)
)
add_library(keepassxcbrowser STATIC ${keepassxcbrowser_SOURCES})
- target_link_libraries(keepassxcbrowser Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network ${BOTAN2_LIBRARIES})
+ target_link_libraries(keepassxcbrowser Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network ${BOTAN_LIBRARIES})
endif()
diff --git a/src/config-keepassx.h.cmake b/src/config-keepassx.h.cmake
index a67b1b3a..92605588 100644
--- a/src/config-keepassx.h.cmake
+++ b/src/config-keepassx.h.cmake
@@ -14,6 +14,7 @@
#cmakedefine WITH_XC_AUTOTYPE
#cmakedefine WITH_XC_NETWORKING
+#cmakedefine KPXC_DEV_BOTAN3
#cmakedefine WITH_XC_BROWSER
#cmakedefine WITH_XC_YUBIKEY
#cmakedefine WITH_XC_SSHAGENT
diff --git a/src/crypto/Crypto.cpp b/src/crypto/Crypto.cpp
index 85d84649..c5972d82 100644
--- a/src/crypto/Crypto.cpp
+++ b/src/crypto/Crypto.cpp
@@ -18,6 +18,8 @@
#include "Crypto.h"
+#include "config-keepassx.h"
+
#include "crypto/CryptoHash.h"
#include "crypto/SymmetricCipher.h"
@@ -237,8 +239,16 @@ namespace Crypto
{
bool init()
{
- if (Botan::version_major() != 2 || Botan::version_minor() < 11) {
- g_cryptoError = QObject::tr("Botan library must be at least 2.11.x, found %1.%2.%3")
+#ifdef KPXC_DEV_BOTAN3
+ unsigned int version_major = 3, min_version_minor = 0;
+ QString versionString = "3.x";
+#else
+ unsigned int version_major = 2, min_version_minor = 11;
+ QString versionString = "2.11.x";
+#endif
+ if (Botan::version_major() != version_major || Botan::version_minor() < min_version_minor) {
+ g_cryptoError = QObject::tr("Botan library must be at least %1, found %2.%3.%4")
+ .arg(versionString)
.arg(Botan::version_major())
.arg(Botan::version_minor())
.arg(Botan::version_patch());
diff --git a/src/fdosecrets/CMakeLists.txt b/src/fdosecrets/CMakeLists.txt
index fec3f99d..ecdac8dc 100644
--- a/src/fdosecrets/CMakeLists.txt
+++ b/src/fdosecrets/CMakeLists.txt
@@ -31,5 +31,5 @@ if(WITH_XC_FDOSECRETS)
objects/Prompt.cpp
dbus/DBusTypes.cpp
)
- target_link_libraries(fdosecrets Qt5::Core Qt5::Widgets Qt5::DBus ${BOTAN2_LIBRARIES})
+ target_link_libraries(fdosecrets Qt5::Core Qt5::Widgets Qt5::DBus ${BOTAN_LIBRARIES})
endif()
diff --git a/src/fdosecrets/objects/SessionCipher.cpp b/src/fdosecrets/objects/SessionCipher.cpp
index 147e820b..8bc526a1 100644
--- a/src/fdosecrets/objects/SessionCipher.cpp
+++ b/src/fdosecrets/objects/SessionCipher.cpp
@@ -17,12 +17,19 @@
#include "SessionCipher.h"
+#include "config-keepassx.h"
+
#include "crypto/Random.h"
#include "crypto/SymmetricCipher.h"
#include
#include
+
+#ifdef KPXC_DEV_BOTAN3
+#include
+#else
#include
+#endif
namespace FdoSecrets
{
@@ -50,6 +57,15 @@ namespace FdoSecrets
try {
Botan::secure_vector salt(32, '\0');
+#ifdef KPXC_DEV_BOTAN3
+ Botan::PK_Key_Agreement dhka(*m_privateKey, *randomGen()->getRng(), "HKDF(SHA-256)", "");
+ auto aesKey = dhka.derive_key(16,
+ reinterpret_cast(clientPublicKey.constData()),
+ clientPublicKey.size(),
+ salt.data(),
+ salt.size());
+ m_aesKey = QByteArray(reinterpret_cast(aesKey.begin()), aesKey.size());
+#else
auto dhka = m_privateKey->create_key_agreement_op(*randomGen()->getRng(), "HKDF(SHA-256)", "");
auto aesKey = dhka->agree(16,
reinterpret_cast(clientPublicKey.constData()),
@@ -57,6 +73,7 @@ namespace FdoSecrets
salt.data(),
salt.size());
m_aesKey = QByteArray(reinterpret_cast(aesKey.data()), aesKey.size());
+#endif
return true;
} catch (std::exception& e) {
qCritical("Failed to update client public key: %s", e.what());
diff --git a/src/keeshare/CMakeLists.txt b/src/keeshare/CMakeLists.txt
index a108b784..3adf272a 100644
--- a/src/keeshare/CMakeLists.txt
+++ b/src/keeshare/CMakeLists.txt
@@ -16,6 +16,6 @@ if(WITH_XC_KEESHARE)
find_package(Minizip REQUIRED)
add_library(keeshare STATIC ${keeshare_SOURCES})
- target_link_libraries(keeshare PUBLIC Qt5::Core Qt5::Widgets ${BOTAN2_LIBRARIES} ${ZLIB_LIBRARIES} PRIVATE ${MINIZIP_LIBRARIES})
+ target_link_libraries(keeshare PUBLIC Qt5::Core Qt5::Widgets ${BOTAN_LIBRARIES} ${ZLIB_LIBRARIES} PRIVATE ${MINIZIP_LIBRARIES})
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
endif(WITH_XC_KEESHARE)
diff --git a/src/proxy/CMakeLists.txt b/src/proxy/CMakeLists.txt
index 15137f5b..be756672 100755
--- a/src/proxy/CMakeLists.txt
+++ b/src/proxy/CMakeLists.txt
@@ -21,7 +21,7 @@ if(WITH_XC_BROWSER)
# Alloc must be defined in a static library to prevent clashing with clang ASAN definitions
add_library(proxy_alloc STATIC ../core/Alloc.cpp)
- target_link_libraries(proxy_alloc PRIVATE Qt5::Core ${BOTAN2_LIBRARIES})
+ target_link_libraries(proxy_alloc PRIVATE Qt5::Core ${BOTAN_LIBRARIES})
add_executable(keepassxc-proxy ${proxy_SOURCES})
target_link_libraries(keepassxc-proxy proxy_alloc Qt5::Core Qt5::Network)