mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
Improve resilience against memory attacks
To reduce residual fragments of secret data in memory after deallocation, this patch replaces the global delete operator with a version that zeros out previously allocated memory. It makes use of the new C++14 sized deallocation, but provides an unsized fallback with platform-specific size deductions. This change is only a minor mitigation and cannot protect against buffer reallocations by the operating system or non-C++ libraries. Thus, we still cannot guarantee all memory to be wiped after free. As a further improvement, this patch uses libgcrypt and libsodium to write long-lived master key component hashes into a secure memory area and wipe it afterwards. The patch also fixes compiler flags not being set properly on macOS.
This commit is contained in:
parent
c7898fdeee
commit
13eb1c0bbd
@ -41,7 +41,7 @@ option(WITH_ASAN "Enable address sanitizer checks (Linux / macOS only)" OFF)
|
|||||||
option(WITH_COVERAGE "Use to build with coverage tests (GCC only)." OFF)
|
option(WITH_COVERAGE "Use to build with coverage tests (GCC only)." OFF)
|
||||||
option(WITH_APP_BUNDLE "Enable Application Bundle for macOS" ON)
|
option(WITH_APP_BUNDLE "Enable Application Bundle for macOS" ON)
|
||||||
|
|
||||||
set(WITH_XC_ALL OFF CACHE BOOLEAN "Build in all available plugins")
|
set(WITH_XC_ALL OFF CACHE BOOL "Build in all available plugins")
|
||||||
|
|
||||||
option(WITH_XC_AUTOTYPE "Include Auto-Type." ON)
|
option(WITH_XC_AUTOTYPE "Include Auto-Type." ON)
|
||||||
option(WITH_XC_NETWORKING "Include networking code (e.g. for downlading website icons)." OFF)
|
option(WITH_XC_NETWORKING "Include networking code (e.g. for downlading website icons)." OFF)
|
||||||
@ -163,11 +163,15 @@ if("${CMAKE_SIZEOF_VOID_P}" EQUAL "4")
|
|||||||
set(IS_32BIT TRUE)
|
set(IS_32BIT TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if("${CMAKE_C_COMPILER}" MATCHES "clang$" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
|
if("${CMAKE_C_COMPILER}" MATCHES "clang$"
|
||||||
|
OR "${CMAKE_EXTRA_GENERATOR_C_SYSTEM_DEFINED_MACROS}" MATCHES "__clang__"
|
||||||
|
OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
|
||||||
set(CMAKE_COMPILER_IS_CLANG 1)
|
set(CMAKE_COMPILER_IS_CLANG 1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if("${CMAKE_CXX_COMPILER}" MATCHES "clang(\\+\\+)?$" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
if("${CMAKE_CXX_COMPILER}" MATCHES "clang(\\+\\+)?$"
|
||||||
|
OR "${CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_DEFINED_MACROS}" MATCHES "__clang__"
|
||||||
|
OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||||
set(CMAKE_COMPILER_IS_CLANGXX 1)
|
set(CMAKE_COMPILER_IS_CLANGXX 1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -264,6 +268,11 @@ endif()
|
|||||||
add_gcc_compiler_cflags("-std=c99")
|
add_gcc_compiler_cflags("-std=c99")
|
||||||
add_gcc_compiler_cxxflags("-std=c++11")
|
add_gcc_compiler_cxxflags("-std=c++11")
|
||||||
|
|
||||||
|
if((CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9.99) OR
|
||||||
|
(CMAKE_COMPILER_IS_CLANGXX AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.6.99))
|
||||||
|
add_gcc_compiler_cxxflags("-fsized-deallocation")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
add_gcc_compiler_cxxflags("-stdlib=libc++")
|
add_gcc_compiler_cxxflags("-stdlib=libc++")
|
||||||
endif()
|
endif()
|
||||||
@ -387,6 +396,7 @@ find_package(Gcrypt 1.7.0 REQUIRED)
|
|||||||
find_package(Argon2 REQUIRED)
|
find_package(Argon2 REQUIRED)
|
||||||
find_package(ZLIB REQUIRED)
|
find_package(ZLIB REQUIRED)
|
||||||
find_package(QREncode REQUIRED)
|
find_package(QREncode REQUIRED)
|
||||||
|
find_package(sodium 1.0.12 REQUIRED)
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIR})
|
set(CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIR})
|
||||||
|
|
||||||
@ -394,7 +404,7 @@ if(ZLIB_VERSION_STRING VERSION_LESS "1.2.0")
|
|||||||
message(FATAL_ERROR "zlib 1.2.0 or higher is required to use the gzip format")
|
message(FATAL_ERROR "zlib 1.2.0 or higher is required to use the gzip format")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include_directories(SYSTEM ${ARGON2_INCLUDE_DIR})
|
include_directories(SYSTEM ${ARGON2_INCLUDE_DIR} ${sodium_INCLUDE_DIR})
|
||||||
|
|
||||||
# Optional
|
# Optional
|
||||||
if(WITH_XC_KEESHARE)
|
if(WITH_XC_KEESHARE)
|
||||||
|
@ -25,7 +25,7 @@ The following libraries are required:
|
|||||||
* zlib
|
* zlib
|
||||||
* libmicrohttpd
|
* libmicrohttpd
|
||||||
* libxi, libxtst, qtx11extras (optional for auto-type on X11)
|
* libxi, libxtst, qtx11extras (optional for auto-type on X11)
|
||||||
* libsodium (>= 1.0.12, optional for KeePassXC-Browser support)
|
* libsodium (>= 1.0.12)
|
||||||
* libargon2
|
* libargon2
|
||||||
|
|
||||||
Prepare the Building Environment
|
Prepare the Building Environment
|
||||||
|
@ -27,6 +27,7 @@ if(NOT ZXCVBN_LIBRARIES)
|
|||||||
endif(NOT ZXCVBN_LIBRARIES)
|
endif(NOT ZXCVBN_LIBRARIES)
|
||||||
|
|
||||||
set(keepassx_SOURCES
|
set(keepassx_SOURCES
|
||||||
|
core/Alloc.cpp
|
||||||
core/AutoTypeAssociations.cpp
|
core/AutoTypeAssociations.cpp
|
||||||
core/AutoTypeMatch.cpp
|
core/AutoTypeMatch.cpp
|
||||||
core/Compare.cpp
|
core/Compare.cpp
|
||||||
@ -254,6 +255,8 @@ endif()
|
|||||||
|
|
||||||
if(WITH_XC_TOUCHID)
|
if(WITH_XC_TOUCHID)
|
||||||
list(APPEND keepassx_SOURCES touchid/TouchID.mm)
|
list(APPEND keepassx_SOURCES touchid/TouchID.mm)
|
||||||
|
# TODO: Remove -Wno-error once deprecation warnings have been resolved.
|
||||||
|
set_source_files_properties(touchid/TouchID.mm PROPERTY COMPILE_FLAGS "-Wno-old-style-cast -Wno-error")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(autotype STATIC ${autotype_SOURCES})
|
add_library(autotype STATIC ${autotype_SOURCES})
|
||||||
@ -270,6 +273,7 @@ target_link_libraries(keepassx_core
|
|||||||
Qt5::Concurrent
|
Qt5::Concurrent
|
||||||
Qt5::Network
|
Qt5::Network
|
||||||
Qt5::Widgets
|
Qt5::Widgets
|
||||||
|
${sodium_LIBRARY_RELEASE}
|
||||||
${YUBIKEY_LIBRARIES}
|
${YUBIKEY_LIBRARIES}
|
||||||
${ZXCVBN_LIBRARIES}
|
${ZXCVBN_LIBRARIES}
|
||||||
${ARGON2_LIBRARIES}
|
${ARGON2_LIBRARIES}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
if(WITH_XC_BROWSER)
|
if(WITH_XC_BROWSER)
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
find_package(sodium 1.0.12 REQUIRED)
|
|
||||||
|
|
||||||
set(keepassxcbrowser_SOURCES
|
set(keepassxcbrowser_SOURCES
|
||||||
BrowserAccessControlDialog.cpp
|
BrowserAccessControlDialog.cpp
|
||||||
@ -33,5 +32,5 @@ if(WITH_XC_BROWSER)
|
|||||||
Variant.cpp)
|
Variant.cpp)
|
||||||
|
|
||||||
add_library(keepassxcbrowser STATIC ${keepassxcbrowser_SOURCES})
|
add_library(keepassxcbrowser STATIC ${keepassxcbrowser_SOURCES})
|
||||||
target_link_libraries(keepassxcbrowser Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network sodium)
|
target_link_libraries(keepassxcbrowser Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network ${sodium_LIBRARY_RELEASE})
|
||||||
endif()
|
endif()
|
||||||
|
@ -38,6 +38,7 @@ target_link_libraries(keepassxc-cli
|
|||||||
keepassx_core
|
keepassx_core
|
||||||
Qt5::Core
|
Qt5::Core
|
||||||
${GCRYPT_LIBRARIES}
|
${GCRYPT_LIBRARIES}
|
||||||
|
${sodium_LIBRARY_RELEASE}
|
||||||
${ARGON2_LIBRARIES}
|
${ARGON2_LIBRARIES}
|
||||||
${GPGERROR_LIBRARIES}
|
${GPGERROR_LIBRARIES}
|
||||||
${ZLIB_LIBRARIES}
|
${ZLIB_LIBRARIES}
|
||||||
|
89
src/core/Alloc.cpp
Normal file
89
src/core/Alloc.cpp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 KeePassXC Team <team@keepassxc.org>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 or (at your option)
|
||||||
|
* version 3 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <sodium.h>
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
#include <malloc/malloc.h>
|
||||||
|
#else
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(NDEBUG) && !defined(__cpp_sized_deallocation)
|
||||||
|
#warning "KeePassXC is being compiled without sized deallocation support. Deletes may be slow."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom sized delete operator which securely zeroes out allocated
|
||||||
|
* memory before freeing it (requires C++14 sized deallocation support).
|
||||||
|
*/
|
||||||
|
void operator delete(void* ptr, std::size_t size) noexcept
|
||||||
|
{
|
||||||
|
if (!ptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sodium_memzero(ptr, size);
|
||||||
|
std::free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete[](void* ptr, std::size_t size) noexcept
|
||||||
|
{
|
||||||
|
::operator delete(ptr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom delete operator which securely zeroes out
|
||||||
|
* allocated memory before freeing it.
|
||||||
|
*/
|
||||||
|
void operator delete(void* ptr) noexcept
|
||||||
|
{
|
||||||
|
if (!ptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
::operator delete(ptr, _msize(ptr));
|
||||||
|
#elif defined(Q_OS_MACOS)
|
||||||
|
::operator delete(ptr, malloc_size(ptr));
|
||||||
|
#elif defined(Q_OS_UNIX)
|
||||||
|
::operator delete(ptr, malloc_usable_size(ptr));
|
||||||
|
#else
|
||||||
|
// whatever OS this is, give up and simply free stuff
|
||||||
|
std::free(ptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete[](void* ptr) noexcept
|
||||||
|
{
|
||||||
|
::operator delete(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom insecure delete operator that does not zero out memory before
|
||||||
|
* freeing a buffer. Can be used for better performance.
|
||||||
|
*/
|
||||||
|
void operator delete(void* ptr, bool) noexcept
|
||||||
|
{
|
||||||
|
std::free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete[](void* ptr, bool) noexcept
|
||||||
|
{
|
||||||
|
::operator delete(ptr, false);
|
||||||
|
}
|
@ -18,19 +18,35 @@
|
|||||||
|
|
||||||
#include "FileKey.h"
|
#include "FileKey.h"
|
||||||
|
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
#include "core/Tools.h"
|
#include "core/Tools.h"
|
||||||
#include "crypto/CryptoHash.h"
|
#include "crypto/CryptoHash.h"
|
||||||
#include "crypto/Random.h"
|
#include "crypto/Random.h"
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
#include <sodium.h>
|
||||||
|
#include <gcrypt.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
QUuid FileKey::UUID("a584cbc4-c9b4-437e-81bb-362ca9709273");
|
QUuid FileKey::UUID("a584cbc4-c9b4-437e-81bb-362ca9709273");
|
||||||
|
|
||||||
|
constexpr int FileKey::SHA256_SIZE;
|
||||||
|
|
||||||
FileKey::FileKey()
|
FileKey::FileKey()
|
||||||
: Key(UUID)
|
: Key(UUID)
|
||||||
|
, m_key(static_cast<char*>(gcry_malloc_secure(SHA256_SIZE)))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileKey::~FileKey()
|
||||||
|
{
|
||||||
|
if (m_key) {
|
||||||
|
gcry_free(m_key);
|
||||||
|
m_key = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read key file from device while trying to detect its file format.
|
* Read key file from device while trying to detect its file format.
|
||||||
*
|
*
|
||||||
@ -148,7 +164,10 @@ bool FileKey::load(const QString& fileName, QString* errorMsg)
|
|||||||
*/
|
*/
|
||||||
QByteArray FileKey::rawKey() const
|
QByteArray FileKey::rawKey() const
|
||||||
{
|
{
|
||||||
return m_key;
|
if (!m_key) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return QByteArray::fromRawData(m_key, SHA256_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -223,12 +242,15 @@ bool FileKey::loadXml(QIODevice* device)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
if (!xmlReader.error() && correctMeta && !data.isEmpty()) {
|
if (!xmlReader.error() && correctMeta && !data.isEmpty()) {
|
||||||
m_key = data;
|
std::memcpy(m_key, data.data(), std::min(SHA256_SIZE, data.size()));
|
||||||
return true;
|
ok = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
sodium_memzero(data.data(), static_cast<std::size_t>(data.capacity()));
|
||||||
|
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -293,7 +315,8 @@ bool FileKey::loadBinary(QIODevice* device)
|
|||||||
if (!Tools::readAllFromDevice(device, data) || data.size() != 32) {
|
if (!Tools::readAllFromDevice(device, data) || data.size() != 32) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
m_key = data;
|
std::memcpy(m_key, data.data(), std::min(SHA256_SIZE, data.size()));
|
||||||
|
sodium_memzero(data.data(), static_cast<std::size_t>(data.capacity()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -321,12 +344,15 @@ bool FileKey::loadHex(QIODevice* device)
|
|||||||
}
|
}
|
||||||
|
|
||||||
QByteArray key = QByteArray::fromHex(data);
|
QByteArray key = QByteArray::fromHex(data);
|
||||||
|
sodium_memzero(data.data(), static_cast<std::size_t>(data.capacity()));
|
||||||
|
|
||||||
if (key.size() != 32) {
|
if (key.size() != 32) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_key = key;
|
std::memcpy(m_key, key.data(), std::min(SHA256_SIZE, key.size()));
|
||||||
|
sodium_memzero(key.data(), static_cast<std::size_t>(key.capacity()));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,7 +374,9 @@ bool FileKey::loadHashed(QIODevice* device)
|
|||||||
cryptoHash.addData(buffer);
|
cryptoHash.addData(buffer);
|
||||||
} while (!buffer.isEmpty());
|
} while (!buffer.isEmpty());
|
||||||
|
|
||||||
m_key = cryptoHash.result();
|
auto result = cryptoHash.result();
|
||||||
|
std::memcpy(m_key, result.data(), std::min(SHA256_SIZE, result.size()));
|
||||||
|
sodium_memzero(result.data(), static_cast<std::size_t>(result.capacity()));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
FileKey();
|
FileKey();
|
||||||
|
~FileKey() override;
|
||||||
bool load(QIODevice* device);
|
bool load(QIODevice* device);
|
||||||
bool load(const QString& fileName, QString* errorMsg = nullptr);
|
bool load(const QString& fileName, QString* errorMsg = nullptr);
|
||||||
QByteArray rawKey() const override;
|
QByteArray rawKey() const override;
|
||||||
@ -48,6 +49,8 @@ public:
|
|||||||
static bool create(const QString& fileName, QString* errorMsg = nullptr, int size = 128);
|
static bool create(const QString& fileName, QString* errorMsg = nullptr, int size = 128);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static constexpr int SHA256_SIZE = 32;
|
||||||
|
|
||||||
bool loadXml(QIODevice* device);
|
bool loadXml(QIODevice* device);
|
||||||
bool loadXmlMeta(QXmlStreamReader& xmlReader);
|
bool loadXmlMeta(QXmlStreamReader& xmlReader);
|
||||||
QByteArray loadXmlKey(QXmlStreamReader& xmlReader);
|
QByteArray loadXmlKey(QXmlStreamReader& xmlReader);
|
||||||
@ -55,7 +58,7 @@ private:
|
|||||||
bool loadHex(QIODevice* device);
|
bool loadHex(QIODevice* device);
|
||||||
bool loadHashed(QIODevice* device);
|
bool loadHashed(QIODevice* device);
|
||||||
|
|
||||||
QByteArray m_key;
|
char* m_key = nullptr;
|
||||||
Type m_type = None;
|
Type m_type = None;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
|
* Copyright (C) 2019 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -16,35 +16,51 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PasswordKey.h"
|
#include "PasswordKey.h"
|
||||||
|
#include "core/Tools.h"
|
||||||
|
|
||||||
#include "crypto/CryptoHash.h"
|
#include "crypto/CryptoHash.h"
|
||||||
|
#include <gcrypt.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
QUuid PasswordKey::UUID("77e90411-303a-43f2-b773-853b05635ead");
|
QUuid PasswordKey::UUID("77e90411-303a-43f2-b773-853b05635ead");
|
||||||
|
|
||||||
|
constexpr int PasswordKey::SHA256_SIZE;
|
||||||
|
|
||||||
PasswordKey::PasswordKey()
|
PasswordKey::PasswordKey()
|
||||||
: Key(UUID)
|
: Key(UUID)
|
||||||
|
, m_key(static_cast<char*>(gcry_malloc_secure(SHA256_SIZE)))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PasswordKey::PasswordKey(const QString& password)
|
PasswordKey::PasswordKey(const QString& password)
|
||||||
: Key(UUID)
|
: Key(UUID)
|
||||||
|
, m_key(static_cast<char*>(gcry_malloc_secure(SHA256_SIZE)))
|
||||||
{
|
{
|
||||||
setPassword(password);
|
setPassword(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PasswordKey::~PasswordKey()
|
||||||
|
{
|
||||||
|
if (m_key) {
|
||||||
|
gcry_free(m_key);
|
||||||
|
m_key = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QSharedPointer<PasswordKey> PasswordKey::fromRawKey(const QByteArray& rawKey)
|
QSharedPointer<PasswordKey> PasswordKey::fromRawKey(const QByteArray& rawKey)
|
||||||
{
|
{
|
||||||
auto result = QSharedPointer<PasswordKey>::create();
|
auto result = QSharedPointer<PasswordKey>::create();
|
||||||
result->m_key = rawKey;
|
std::memcpy(result->m_key, rawKey.data(), std::min(SHA256_SIZE, rawKey.size()));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray PasswordKey::rawKey() const
|
QByteArray PasswordKey::rawKey() const
|
||||||
{
|
{
|
||||||
return m_key;
|
return QByteArray::fromRawData(m_key, SHA256_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PasswordKey::setPassword(const QString& password)
|
void PasswordKey::setPassword(const QString& password)
|
||||||
{
|
{
|
||||||
m_key = CryptoHash::hash(password.toUtf8(), CryptoHash::Sha256);
|
std::memcpy(m_key, CryptoHash::hash(password.toUtf8(), CryptoHash::Sha256).data(), SHA256_SIZE);
|
||||||
}
|
}
|
||||||
|
@ -30,13 +30,16 @@ public:
|
|||||||
|
|
||||||
PasswordKey();
|
PasswordKey();
|
||||||
explicit PasswordKey(const QString& password);
|
explicit PasswordKey(const QString& password);
|
||||||
|
~PasswordKey() override;
|
||||||
QByteArray rawKey() const override;
|
QByteArray rawKey() const override;
|
||||||
void setPassword(const QString& password);
|
void setPassword(const QString& password);
|
||||||
|
|
||||||
static QSharedPointer<PasswordKey> fromRawKey(const QByteArray& rawKey);
|
static QSharedPointer<PasswordKey> fromRawKey(const QByteArray& rawKey);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QByteArray m_key;
|
static constexpr int SHA256_SIZE = 32;
|
||||||
|
|
||||||
|
char* m_key = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSX_PASSWORDKEY_H
|
#endif // KEEPASSX_PASSWORDKEY_H
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2019 KeePassXC Team <team@keepassxc.org>
|
||||||
* Copyright (C) 2014 Kyle Manna <kyle@kylemanna.com>
|
* Copyright (C) 2014 Kyle Manna <kyle@kylemanna.com>
|
||||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -32,6 +32,10 @@
|
|||||||
#include <QXmlStreamReader>
|
#include <QXmlStreamReader>
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
|
|
||||||
|
#include <gcrypt.h>
|
||||||
|
#include <sodium.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
QUuid YkChallengeResponseKey::UUID("e092495c-e77d-498b-84a1-05ae0d955508");
|
QUuid YkChallengeResponseKey::UUID("e092495c-e77d-498b-84a1-05ae0d955508");
|
||||||
|
|
||||||
YkChallengeResponseKey::YkChallengeResponseKey(int slot, bool blocking)
|
YkChallengeResponseKey::YkChallengeResponseKey(int slot, bool blocking)
|
||||||
@ -45,9 +49,18 @@ YkChallengeResponseKey::YkChallengeResponseKey(int slot, bool blocking)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
YkChallengeResponseKey::~YkChallengeResponseKey()
|
||||||
|
{
|
||||||
|
if (m_key) {
|
||||||
|
gcry_free(m_key);
|
||||||
|
m_keySize = 0;
|
||||||
|
m_key = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray YkChallengeResponseKey::rawKey() const
|
QByteArray YkChallengeResponseKey::rawKey() const
|
||||||
{
|
{
|
||||||
return m_key;
|
return QByteArray::fromRawData(m_key, static_cast<int>(m_keySize));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,14 +80,22 @@ bool YkChallengeResponseKey::challenge(const QByteArray& challenge, unsigned int
|
|||||||
emit userInteractionRequired();
|
emit userInteractionRequired();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray key;
|
||||||
auto result = AsyncTask::runAndWaitForFuture(
|
auto result = AsyncTask::runAndWaitForFuture(
|
||||||
[this, challenge]() { return YubiKey::instance()->challenge(m_slot, true, challenge, m_key); });
|
[this, challenge, &key]() { return YubiKey::instance()->challenge(m_slot, true, challenge, key); });
|
||||||
|
|
||||||
if (m_blocking) {
|
if (m_blocking) {
|
||||||
emit userConfirmed();
|
emit userConfirmed();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == YubiKey::SUCCESS) {
|
if (result == YubiKey::SUCCESS) {
|
||||||
|
if (m_key) {
|
||||||
|
gcry_free(m_key);
|
||||||
|
}
|
||||||
|
m_keySize = static_cast<std::size_t>(key.size());
|
||||||
|
m_key = static_cast<char*>(gcry_malloc_secure(m_keySize));
|
||||||
|
std::memcpy(m_key, key.data(), m_keySize);
|
||||||
|
sodium_memzero(key.data(), static_cast<std::size_t>(key.capacity()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} while (retries > 0);
|
} while (retries > 0);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
* Copyright (C) 2019 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -32,6 +32,7 @@ public:
|
|||||||
static QUuid UUID;
|
static QUuid UUID;
|
||||||
|
|
||||||
explicit YkChallengeResponseKey(int slot = -1, bool blocking = false);
|
explicit YkChallengeResponseKey(int slot = -1, bool blocking = false);
|
||||||
|
~YkChallengeResponseKey() override;
|
||||||
|
|
||||||
QByteArray rawKey() const override;
|
QByteArray rawKey() const override;
|
||||||
bool challenge(const QByteArray& challenge) override;
|
bool challenge(const QByteArray& challenge) override;
|
||||||
@ -52,7 +53,8 @@ signals:
|
|||||||
void userConfirmed();
|
void userConfirmed();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QByteArray m_key;
|
char* m_key = nullptr;
|
||||||
|
std::size_t m_keySize = 0;
|
||||||
int m_slot;
|
int m_slot;
|
||||||
bool m_blocking;
|
bool m_blocking;
|
||||||
};
|
};
|
||||||
|
@ -18,12 +18,13 @@ if(WITH_XC_BROWSER)
|
|||||||
include_directories(${BROWSER_SOURCE_DIR})
|
include_directories(${BROWSER_SOURCE_DIR})
|
||||||
|
|
||||||
set(proxy_SOURCES
|
set(proxy_SOURCES
|
||||||
|
../core/Alloc.cpp
|
||||||
keepassxc-proxy.cpp
|
keepassxc-proxy.cpp
|
||||||
${BROWSER_SOURCE_DIR}/NativeMessagingBase.cpp
|
${BROWSER_SOURCE_DIR}/NativeMessagingBase.cpp
|
||||||
NativeMessagingHost.cpp)
|
NativeMessagingHost.cpp)
|
||||||
|
|
||||||
add_library(proxy STATIC ${proxy_SOURCES})
|
add_library(proxy STATIC ${proxy_SOURCES})
|
||||||
target_link_libraries(proxy Qt5::Core Qt5::Network)
|
target_link_libraries(proxy Qt5::Core Qt5::Network ${sodium_LIBRARY_RELEASE})
|
||||||
add_executable(keepassxc-proxy keepassxc-proxy.cpp)
|
add_executable(keepassxc-proxy keepassxc-proxy.cpp)
|
||||||
target_link_libraries(keepassxc-proxy proxy)
|
target_link_libraries(keepassxc-proxy proxy)
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
inline void debug(const char* message, ...)
|
inline void debug(const char* message, ...)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(message);
|
||||||
// qWarning(...);
|
// qWarning(...);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,6 +259,7 @@ bool TouchID::authenticate(const QString& message) const
|
|||||||
NSString* authMessage = msg.toNSString(); // autoreleased
|
NSString* authMessage = msg.toNSString(); // autoreleased
|
||||||
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
|
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
|
||||||
localizedReason:authMessage reply:^(BOOL success, NSError* error) {
|
localizedReason:authMessage reply:^(BOOL success, NSError* error) {
|
||||||
|
Q_UNUSED(error);
|
||||||
result = success ? kTouchIDResultAllowed : kTouchIDResultFailed;
|
result = success ? kTouchIDResultAllowed : kTouchIDResultFailed;
|
||||||
CFRunLoopWakeUp(CFRunLoopGetCurrent());
|
CFRunLoopWakeUp(CFRunLoopGetCurrent());
|
||||||
}];
|
}];
|
||||||
|
Loading…
Reference in New Issue
Block a user