commit libfilezilla for openSUSE:Factory
Hello community, here is the log from the commit of package libfilezilla for openSUSE:Factory checked in at 2018-10-29 14:22:31 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libfilezilla (Old) and /work/SRC/openSUSE:Factory/.libfilezilla.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "libfilezilla" Mon Oct 29 14:22:31 2018 rev:21 rq:645011 version:0.15.0 Changes: -------- --- /work/SRC/openSUSE:Factory/libfilezilla/libfilezilla.changes 2018-10-15 09:48:06.123059274 +0200 +++ /work/SRC/openSUSE:Factory/.libfilezilla.new/libfilezilla.changes 2018-10-29 14:58:52.738017542 +0100 @@ -1,0 +2,17 @@ +Sat Oct 27 08:35:12 UTC 2018 - ecsos@opensuse.org + +- update to 0.15.0 + * New features: + - libfilezilla now depends on Nettle >= 3.1 + - Added fz::sha512, fz::sha256, fz::sha1 and fz::md5 hash + functions + - Added fz::hash_accumulator + - Added fz::hmac_sha256 HMAC function + - Added asymmetric encryption scheme using X25519 + - Added signature scheme using Ed25519 + * Bugfixes and minor changes: + - Changed and documented semantics of the return value of + fz::remove_file, removing a non-existing file is not an error +- Drop extra COPYING file and use it from upstream + +------------------------------------------------------------------- Old: ---- COPYING libfilezilla-0.14.0.tar.bz2 New: ---- libfilezilla-0.15.0.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libfilezilla.spec ++++++ --- /var/tmp/diff_new_pack.ZNyW9V/_old 2018-10-29 14:58:53.326018313 +0100 +++ /var/tmp/diff_new_pack.ZNyW9V/_new 2018-10-29 14:58:53.330018318 +0100 @@ -20,14 +20,13 @@ %define libname %{name}%{major} %define develname %{name}-devel Name: libfilezilla -Version: 0.14.0 +Version: 0.15.0 Release: 0 Summary: C++ library for filezilla License: GPL-2.0-or-later Group: Development/Libraries/C and C++ Url: https://lib.filezilla-project.org/ Source0: https://download.filezilla-project.org/libfilezilla/%{name}-%{version}.tar.bz2 -Source1: COPYING Patch0: %{name}-date-time.patch BuildRequires: autoconf BuildRequires: automake @@ -37,6 +36,7 @@ BuildRequires: libtool BuildRequires: pkg-config BuildRequires: pkgconfig(cppunit) +BuildRequires: pkgconfig(nettle) >= 3.1 %if 0%{?suse_version} <= 1500 # FileZilla requires C++14 support. BuildRequires: gcc7-c++ @@ -77,8 +77,6 @@ %prep %setup -q %patch0 -#copy in up to date GPL-2.0 license. -cp -v %{SOURCE1} . %build %if 0%{?suse_version} <= 1500 @@ -111,7 +109,8 @@ %files -n %{libname} %defattr(-,root,root) -%doc AUTHORS ChangeLog NEWS README COPYING +%license COPYING +%doc AUTHORS ChangeLog NEWS README %{_libdir}/%{name}.so.%{major}* %files -n %{develname} ++++++ libfilezilla-0.14.0.tar.bz2 -> libfilezilla-0.15.0.tar.bz2 ++++++ ++++ 2167 lines of diff (skipped) ++++ retrying with extended exclude list diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/INSTALL new/libfilezilla-0.15.0/INSTALL --- old/libfilezilla-0.14.0/INSTALL 2017-07-10 19:43:37.000000000 +0200 +++ new/libfilezilla-0.15.0/INSTALL 2018-10-19 12:13:12.000000000 +0200 @@ -8,6 +8,7 @@ To compile libfilezilla, the following tools need to be installed: - A C++14 compiler, e.g. a recent GCC or Clang - GNU make +- Nettle >= 3.1 Optional tools: - recent automake, autoconf, libtool if you plan to change configure.in or diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/NEWS new/libfilezilla-0.15.0/NEWS --- old/libfilezilla-0.14.0/NEWS 2018-10-04 13:17:12.000000000 +0200 +++ new/libfilezilla-0.15.0/NEWS 2018-10-19 12:12:06.000000000 +0200 @@ -1,3 +1,13 @@ +0.15.0 (2018-10-19) + ++ libfilezilla now depends on Nettle >= 3.1 ++ Added fz::sha512, fz::sha256, fz::sha1 and fz::md5 hash functions ++ Added fz::hash_accumulator ++ Added fz::hmac_sha256 HMAC function ++ Added asymmetric encryption scheme using X25519 ++ Added signature scheme using Ed25519 +- Changed and documented semantics of the return value of fz::remove_file, removing a non-existing file is not an error + 0.14.0 (2018-10-04) + Added fz::equal_insensitive_ascii diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/configure.ac new/libfilezilla-0.15.0/configure.ac --- old/libfilezilla-0.14.0/configure.ac 2018-10-04 13:17:12.000000000 +0200 +++ new/libfilezilla-0.15.0/configure.ac 2018-10-19 12:00:57.000000000 +0200 @@ -1,4 +1,4 @@ -AC_INIT([libfilezilla],[0.14.0],[tim.kosse@filezilla-project.org],[],[https://lib.filezilla-project.org/]) +AC_INIT([libfilezilla],[0.15.0],[tim.kosse@filezilla-project.org],[],[https://lib.filezilla-project.org/]) AC_CONFIG_HEADERS([lib/libfilezilla/private/config.hpp]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR(config) @@ -100,6 +100,23 @@ fi +# Nettle +# ------ + +PKG_CHECK_MODULES([NETTLE], [nettle >= 3.1],, [ + AC_MSG_ERROR([nettle 3.1 greater was not found. You can get it from https://www.lysator.liu.se/~nisse/nettle/]) +]) + +AC_SUBST(NETTLE_LIBS) +AC_SUBST(NETTLE_CFLAGS) + +PKG_CHECK_MODULES([HOGWEED], [hogweed >= 3.1],, [ + AC_MSG_ERROR([hogweed 3.1 greater was not found. You can get it from https://www.lysator.liu.se/~nisse/nettle/]) +]) + +AC_SUBST(HOGWEED_LIBS) +AC_SUBST(HOGWEED_CFLAGS) + # Check for windres on MinGW builds # --------------------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/lib/Makefile.am new/libfilezilla-0.15.0/lib/Makefile.am --- old/libfilezilla-0.14.0/lib/Makefile.am 2017-09-29 10:41:58.000000000 +0200 +++ new/libfilezilla-0.15.0/lib/Makefile.am 2018-10-19 12:00:50.000000000 +0200 @@ -3,15 +3,18 @@ libfilezilla_la_SOURCES = \ buffer.cpp \ encode.cpp \ + encryption.cpp \ event.cpp \ event_handler.cpp \ event_loop.cpp \ file.cpp \ + hash.cpp \ iputils.cpp \ local_filesys.cpp \ mutex.cpp \ process.cpp \ recursive_remove.cpp \ + signature.cpp \ string.cpp \ thread.cpp \ thread_pool.cpp \ @@ -24,11 +27,13 @@ libfilezilla/apply.hpp \ libfilezilla/buffer.hpp \ libfilezilla/encode.hpp \ + libfilezilla/encryption.hpp \ libfilezilla/event.hpp \ libfilezilla/event_handler.hpp \ libfilezilla/event_loop.hpp \ libfilezilla/file.hpp \ libfilezilla/format.hpp \ + libfilezilla/hash.hpp \ libfilezilla/iputils.hpp \ libfilezilla/libfilezilla.hpp \ libfilezilla/local_filesys.hpp \ @@ -37,6 +42,7 @@ libfilezilla/process.hpp \ libfilezilla/recursive_remove.hpp \ libfilezilla/shared.hpp \ + libfilezilla/signature.hpp \ libfilezilla/string.hpp \ libfilezilla/thread.hpp \ libfilezilla/thread_pool.hpp \ @@ -51,6 +57,7 @@ libfilezilla_la_CPPFLAGS = $(AM_CPPFLAGS) libfilezilla_la_CPPFLAGS += -DBUILDING_LIBFILEZILLA +libfilezilla_la_CPPFLAGS += $(NETTLE_CFLAGS) # Needed for version.hpp in out-of-tree builds libfilezilla_la_CPPFLAGS += -I$(srcdir)/libfilezilla @@ -62,6 +69,8 @@ libfilezilla_la_LDFLAGS += -no-undefined libfilezilla_la_LIBADD = $(libdeps) +libfilezilla_la_LIBADD += $(NETTLE_LIBS) $(HOGWEED_LIBS) + pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libfilezilla.pc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/lib/encode.cpp new/libfilezilla-0.15.0/lib/encode.cpp --- old/libfilezilla-0.14.0/lib/encode.cpp 2018-05-06 11:22:43.000000000 +0200 +++ new/libfilezilla-0.15.0/lib/encode.cpp 2018-10-19 12:00:50.000000000 +0200 @@ -1,8 +1,13 @@ #include "libfilezilla/encode.hpp" namespace fz { -std::string base64_encode(std::string const& in, base64_type type, bool pad) + +namespace { +template<typename DataContainer> +std::string base64_encode_impl(DataContainer const& in, base64_type type, bool pad) { + static_assert(sizeof(typename DataContainer::value_type) == 1, "Bad container type"); + std::string::value_type const* const base64_chars = (type == base64_type::standard) ? "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" @@ -47,6 +52,17 @@ return ret; } +} + +std::string base64_encode(std::string const& in, base64_type type, bool pad) +{ + return base64_encode_impl(in, type, pad); +} + +std::string base64_encode(std::vector<uint8_t> const& in, base64_type type, bool pad) +{ + return base64_encode_impl(in, type, pad); +} std::string base64_decode(std::string const& in) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/lib/encryption.cpp new/libfilezilla-0.15.0/lib/encryption.cpp --- old/libfilezilla-0.14.0/lib/encryption.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/libfilezilla-0.15.0/lib/encryption.cpp 2018-10-19 12:00:50.000000000 +0200 @@ -0,0 +1,271 @@ +#include "libfilezilla/encryption.hpp" + +#include "libfilezilla/encode.hpp" +#include "libfilezilla/hash.hpp" +#include "libfilezilla/util.hpp" + +#include <cstring> + +#include <nettle/aes.h> +#include <nettle/ctr.h> +#include <nettle/curve25519.h> +#include <nettle/gcm.h> +#include <nettle/memops.h> +#include <nettle/pbkdf2.h> +#include <nettle/sha2.h> + +namespace fz { + +std::string public_key::to_base64() const +{ + auto raw = std::string(key_.cbegin(), key_.cend()); + raw += std::string(salt_.cbegin(), salt_.cend()); + return fz::base64_encode(raw); +} + +public_key public_key::from_base64(std::string const& base64) +{ + public_key ret; + + auto raw = fz::base64_decode(base64); + if (raw.size() == key_size + salt_size) { + auto p = reinterpret_cast<uint8_t const*>(&raw[0]); + ret.key_.assign(p, p + key_size); + ret.salt_.assign(p + key_size, p + key_size + salt_size); + } + + return ret; +} + +private_key private_key::generate() +{ + private_key ret; + + ret.key_ = fz::random_bytes(key_size); + ret.key_[0] &= 248; + ret.key_[31] &= 127; + ret.key_[31] |= 64; + + ret.salt_ = fz::random_bytes(salt_size); + + return ret; +} + +public_key private_key::pubkey() const +{ + public_key ret; + + if (*this) { + static const uint8_t nine[32]{ + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; + + ret.key_.resize(32); + nettle_curve25519_mul(&ret.key_[0], &key_[0], nine); + + ret.salt_ = salt_; + } + + return ret; +} + +private_key private_key::from_password(std::vector<uint8_t> const& password, std::vector<uint8_t> const& salt) +{ + private_key ret; + + if (!password.empty() && salt.size() == salt_size) { + + std::vector<uint8_t> key; + key.resize(key_size); + nettle_pbkdf2_hmac_sha256(password.size(), &password[0], 100000, salt_size, &salt[0], 32, &key[0]); + key[0] &= 248; + key[31] &= 127; + key[31] |= 64; + + ret.key_ = std::move(key); + ret.salt_ = salt; + } + + return ret; +} + +std::string private_key::to_base64() const +{ + auto raw = std::string(key_.cbegin(), key_.cend()); + raw += std::string(salt_.cbegin(), salt_.cend()); + return fz::base64_encode(raw); +} + +private_key private_key::from_base64(std::string const& base64) +{ + private_key ret; + + auto raw = fz::base64_decode(base64); + if (raw.size() == key_size + salt_size) { + auto p = reinterpret_cast<uint8_t const*>(&raw[0]); + ret.key_.assign(p, p + key_size); + ret.key_[0] &= 248; + ret.key_[31] &= 127; + ret.key_[31] |= 64; + ret.salt_.assign(p + key_size, p + key_size + salt_size); + } + + return ret; +} + + +std::vector<uint8_t> private_key::shared_secret(public_key const& pub) const +{ + std::vector<uint8_t> ret; + + if (*this && pub) { + ret.resize(32); + + nettle_curve25519_mul(&ret[0], &key_[0], &pub.key_[0]); + } + + return ret; +} + +std::vector<uint8_t> encrypt(uint8_t const* plain, size_t size, public_key const& pub, bool authenticated) +{ + std::vector<uint8_t> ret; + + private_key ephemeral = private_key::generate(); + public_key ephemeral_pub = ephemeral.pubkey(); + + if (pub && ephemeral && ephemeral_pub) { + // Generate shared secret from pub and ephemeral + std::vector<uint8_t> secret = ephemeral.shared_secret(pub); + + // Derive AES2556 key and CTR nonce from shared secret + std::vector<uint8_t> const aes_key = hash_accumulator(hash_algorithm::sha256) << ephemeral_pub.salt_ << 0 << secret << ephemeral_pub.key_ << pub.key_ << pub.salt_; + + if (authenticated) { + std::vector<uint8_t> iv = hash_accumulator(hash_algorithm::sha256) << ephemeral_pub.salt_ << 2 << secret << ephemeral_pub.key_ << pub.key_ << pub.salt_; + static_assert(SHA256_DIGEST_SIZE >= GCM_IV_SIZE, "iv too small"); + iv.resize(GCM_IV_SIZE); + + gcm_aes256_ctx ctx; + nettle_gcm_aes256_set_key(&ctx, &aes_key[0]); + nettle_gcm_aes256_set_iv(&ctx, GCM_IV_SIZE, &iv[0]); + + // Encrypt plaintext with AES256-GCM + ret.resize(public_key::key_size + public_key::salt_size + size + GCM_DIGEST_SIZE); + if (size) { + nettle_gcm_aes256_encrypt(&ctx, size, &ret[public_key::key_size + public_key::salt_size], plain); + } + + // Return ephemeral_pub.key_||ephemeral_pub.salt_||ciphertext||tag + memcpy(&ret[0], &ephemeral_pub.key_[0], public_key::key_size); + memcpy(&ret[public_key::key_size], &ephemeral_pub.salt_[0], public_key::salt_size); + nettle_gcm_aes256_digest(&ctx, GCM_DIGEST_SIZE, &ret[public_key::key_size + public_key::salt_size + size]); + } + else { + std::vector<uint8_t> ctr = hash_accumulator(hash_algorithm::sha256) << ephemeral_pub.salt_ << 1 << secret << ephemeral_pub.key_ << pub.key_ << pub.salt_; + + aes256_ctx ctx; + nettle_aes256_set_encrypt_key(&ctx, &aes_key[0]); + + // Encrypt plaintext with AES256-CTR + ret.resize(public_key::key_size + public_key::salt_size + size); + if (size) { + nettle_ctr_crypt(&ctx, reinterpret_cast<nettle_cipher_func*>(nettle_aes256_encrypt), 16, &ctr[0], size, &ret[public_key::key_size + public_key::salt_size], plain); + } + + // Return ephemeral_pub.key_||ephemeral_pub.salt_||ciphertext + memcpy(&ret[0], &ephemeral_pub.key_[0], public_key::key_size); + memcpy(&ret[public_key::key_size], &ephemeral_pub.salt_[0], public_key::salt_size); + } + } + + return ret; +} + +std::vector<uint8_t> encrypt(std::vector<uint8_t> const& plain, public_key const& pub, bool authenticated) +{ + return encrypt(plain.data(), plain.size(), pub, authenticated); +} + +std::vector<uint8_t> encrypt(std::string const& plain, public_key const& pub, bool authenticated) +{ + return encrypt(reinterpret_cast<uint8_t const*>(plain.c_str()), plain.size(), pub, authenticated); +} + +std::vector<uint8_t> decrypt(uint8_t const* cipher, size_t size, private_key const& priv, bool authenticated) +{ + size_t const overhead = public_key::key_size + public_key::salt_size + (authenticated ? GCM_DIGEST_SIZE : 0); + + std::vector<uint8_t> ret; + + if (priv && size >= overhead && cipher) { + size_t const message_size = size - overhead; + + // Extract ephemeral_pub from cipher + public_key ephemeral_pub; + ephemeral_pub.key_.resize(public_key::key_size); + ephemeral_pub.salt_.resize(public_key::salt_size); + memcpy(&ephemeral_pub.key_[0], cipher, public_key::key_size); + memcpy(&ephemeral_pub.salt_[0], cipher + public_key::key_size, public_key::salt_size); + + // Generate shared secret from ephemeral_pub and priv + std::vector<uint8_t> const secret = priv.shared_secret(ephemeral_pub); + + public_key const pub = priv.pubkey(); + std::vector<uint8_t> const aes_key = hash_accumulator(hash_algorithm::sha256) << ephemeral_pub.salt_ << 0 << secret << ephemeral_pub.key_ << pub.key_ << pub.salt_; + + if (authenticated) { + // Derive AES2556 key and GCM IV from shared secret + std::vector<uint8_t> iv = hash_accumulator(hash_algorithm::sha256) << ephemeral_pub.salt_ << 2 << secret << ephemeral_pub.key_ << pub.key_ << pub.salt_; + static_assert(SHA256_DIGEST_SIZE >= GCM_IV_SIZE, "iv too small"); + iv.resize(GCM_IV_SIZE); + + gcm_aes256_ctx ctx; + nettle_gcm_aes256_set_key(&ctx, &aes_key[0]); + nettle_gcm_aes256_set_iv(&ctx, GCM_IV_SIZE, &iv[0]); + + // Decrypt ciphertext with AES256-GCM + ret.resize(message_size); + if (message_size) { + nettle_gcm_aes256_decrypt(&ctx, message_size, &ret[0], cipher +public_key::key_size + public_key::salt_size); + } + + // Last but not least, verify the tag + uint8_t tag[GCM_DIGEST_SIZE]; + nettle_gcm_aes256_digest(&ctx, GCM_DIGEST_SIZE, tag); + if (!nettle_memeql_sec(tag, cipher + size - GCM_DIGEST_SIZE, GCM_DIGEST_SIZE)) { + ret.clear(); + } + } + else { + // Derive AES2556 key and CTR nonce from shared secret + std::vector<uint8_t> ctr = hash_accumulator(hash_algorithm::sha256) << ephemeral_pub.salt_ << 1 << secret << ephemeral_pub.key_ << pub.key_ << pub.salt_; + + aes256_ctx ctx; + nettle_aes256_set_encrypt_key(&ctx, &aes_key[0]); + + // Decrypt ciphertext with AES256-CTR + ret.resize(message_size); + if (message_size) { + nettle_ctr_crypt(&ctx, reinterpret_cast<nettle_cipher_func*>(nettle_aes256_encrypt), 16, &ctr[0], ret.size(), &ret[0], &cipher[public_key::key_size + public_key::salt_size]); + } + } + } + + // Return the plaintext + return ret; +} + +std::vector<uint8_t> decrypt(std::vector<uint8_t> const& cipher, private_key const& priv, bool authenticated) +{ + return decrypt(cipher.data(), cipher.size(), priv, authenticated); +} + +std::vector<uint8_t> decrypt(std::string const& cipher, private_key const& priv, bool authenticated) +{ + return decrypt(reinterpret_cast<uint8_t const*>(cipher.c_str()), cipher.size(), priv, authenticated); +} + +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/lib/file.cpp new/libfilezilla-0.15.0/lib/file.cpp --- old/libfilezilla-0.14.0/lib/file.cpp 2017-10-30 18:14:16.000000000 +0100 +++ new/libfilezilla-0.15.0/lib/file.cpp 2018-10-19 12:00:50.000000000 +0200 @@ -126,7 +126,12 @@ bool remove_file(fz::native_string const& name) { - return DeleteFileW(name.c_str()) != 0; + bool ret = DeleteFileW(name.c_str()) != 0; + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) { + ret = true; + } + + return ret; } bool file::fsync() @@ -242,7 +247,11 @@ bool remove_file(fz::native_string const& name) { - return unlink(name.c_str()) == 0; + bool ret = unlink(name.c_str()) == 0; + if (!ret && errno == ENOENT) { + ret = true; + } + return ret; } bool file::fsync() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/lib/hash.cpp new/libfilezilla-0.15.0/lib/hash.cpp --- old/libfilezilla-0.14.0/lib/hash.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/libfilezilla-0.15.0/lib/hash.cpp 2018-10-19 12:00:50.000000000 +0200 @@ -0,0 +1,311 @@ +#include "libfilezilla/libfilezilla.hpp" + +#include "libfilezilla/hash.hpp" + +#include <nettle/md5.h> +#include <nettle/sha2.h> +#include <nettle/hmac.h> + +namespace fz { + +class hash_accumulator::impl +{ +public: + virtual ~impl() = default; + + virtual void update(uint8_t const* data, size_t size) = 0; + virtual void reinit() = 0; + virtual std::vector<uint8_t> digest() = 0; +}; + +class hash_accumulator_md5 final : public hash_accumulator::impl +{ +public: + virtual void update(uint8_t const* data, size_t size) override + { + nettle_md5_update(&ctx_, size, data); + } + + virtual void reinit() override + { + nettle_md5_init(&ctx_); + } + + virtual std::vector<uint8_t> digest() override + { + std::vector<uint8_t> ret; + ret.resize(MD5_DIGEST_SIZE); + nettle_md5_digest(&ctx_, ret.size(), &ret[0]); + return ret; + } + +private: + md5_ctx ctx_; +}; + +class hash_accumulator_sha1 final : public hash_accumulator::impl +{ +public: + virtual void update(uint8_t const* data, size_t size) override + { + nettle_sha1_update(&ctx_, size, data); + } + + virtual void reinit() override + { + nettle_sha1_init(&ctx_); + } + + virtual std::vector<uint8_t> digest() override + { + std::vector<uint8_t> ret; + ret.resize(SHA1_DIGEST_SIZE); + nettle_sha1_digest(&ctx_, ret.size(), &ret[0]); + return ret; + } + +private: + sha1_ctx ctx_; +}; + +class hash_accumulator_sha256 final : public hash_accumulator::impl +{ +public: + virtual void update(uint8_t const* data, size_t size) override + { + nettle_sha256_update(&ctx_, size, data); + } + + virtual void reinit() override + { + nettle_sha256_init(&ctx_); + } + + virtual std::vector<uint8_t> digest() override + { + std::vector<uint8_t> ret; + ret.resize(SHA256_DIGEST_SIZE); + nettle_sha256_digest(&ctx_, ret.size(), &ret[0]); + return ret; + } + +private: + sha256_ctx ctx_; +}; + +class hash_accumulator_sha512 final : public hash_accumulator::impl +{ +public: + virtual void update(uint8_t const* data, size_t size) override + { + nettle_sha512_update(&ctx_, size, data); + } + + virtual void reinit() override + { + nettle_sha512_init(&ctx_); + } + + virtual std::vector<uint8_t> digest() override + { + std::vector<uint8_t> ret; + ret.resize(SHA512_DIGEST_SIZE); + nettle_sha512_digest(&ctx_, ret.size(), &ret[0]); + return ret; + } + +private: + sha512_ctx ctx_; +}; + +hash_accumulator::hash_accumulator(hash_algorithm algorithm) +{ + switch (algorithm) { + case hash_algorithm::md5: + impl_ = new hash_accumulator_md5; + break; + case hash_algorithm::sha1: + impl_ = new hash_accumulator_sha1; + break; + case hash_algorithm::sha256: + impl_ = new hash_accumulator_sha256; + break; + case hash_algorithm::sha512: + impl_ = new hash_accumulator_sha512; + break; + } + + impl_->reinit(); +} + +hash_accumulator::~hash_accumulator() +{ + delete impl_; +} + +void hash_accumulator::reinit() +{ + impl_->reinit(); +} + +void hash_accumulator::update(std::string const& data) +{ + if (!data.empty()) { + impl_->update(reinterpret_cast<uint8_t const*>(&data[0]), data.size()); + } +} + +void hash_accumulator::update(std::vector<uint8_t> const& data) +{ + if (!data.empty()) { + impl_->update(&data[0], data.size()); + } +} + +void hash_accumulator::update(uint8_t const* data, size_t size) +{ + impl_->update(data, size); +} + +std::vector<uint8_t> hash_accumulator::digest() +{ + return impl_->digest(); +} + +namespace { +// In C++17, require ContiguousContainer +template<typename DataContainer> +std::vector<uint8_t> md5_impl(DataContainer const& in) +{ + static_assert(sizeof(typename DataContainer::value_type) == 1, "Bad container type"); + + hash_accumulator_md5 acc; + acc.reinit(); + if (!in.empty()) { + acc.update(reinterpret_cast<uint8_t const*>(&in[0]), in.size()); + } + return acc.digest(); +} + +template<typename DataContainer> +std::vector<uint8_t> sha1_impl(DataContainer const& in) +{ + static_assert(sizeof(typename DataContainer::value_type) == 1, "Bad container type"); + + hash_accumulator_sha1 acc; + acc.reinit(); + if (!in.empty()) { + acc.update(reinterpret_cast<uint8_t const*>(&in[0]), in.size()); + } + return acc.digest(); +} + +template<typename DataContainer> +std::vector<uint8_t> sha256_impl(DataContainer const& in) +{ + static_assert(sizeof(typename DataContainer::value_type) == 1, "Bad container type"); + + hash_accumulator_sha256 acc; + acc.reinit(); + if (!in.empty()) { + acc.update(reinterpret_cast<uint8_t const*>(&in[0]), in.size()); + } + return acc.digest(); +} + +template<typename DataContainer> +std::vector<uint8_t> sha512_impl(DataContainer const& in) +{ + static_assert(sizeof(typename DataContainer::value_type) == 1, "Bad container type"); + + hash_accumulator_sha512 acc; + acc.reinit(); + if (!in.empty()) { + acc.update(reinterpret_cast<uint8_t const*>(&in[0]), in.size()); + } + return acc.digest(); +} + +template<typename KeyContainer, typename DataContainer> +std::vector<uint8_t> hmac_sha256_impl(KeyContainer const& key, DataContainer const& data) +{ + static_assert(sizeof(typename KeyContainer::value_type) == 1, "Bad container type"); + static_assert(sizeof(typename DataContainer::value_type) == 1, "Bad container type"); + + std::vector<uint8_t> ret; + + hmac_sha256_ctx ctx; + nettle_hmac_sha256_set_key(&ctx, key.size(), key.empty() ? nullptr : reinterpret_cast<uint8_t const*>(&key[0])); + + if (!data.empty()) { + nettle_hmac_sha256_update(&ctx, data.size(), reinterpret_cast<uint8_t const*>(&data[0])); + } + + ret.resize(SHA256_DIGEST_SIZE); + nettle_hmac_sha256_digest(&ctx, ret.size(), &ret[0]); + + return ret; +} +} + +std::vector<uint8_t> md5(std::vector<uint8_t> const& data) +{ + return md5_impl(data); +} + +std::vector<uint8_t> md5(std::string const& data) +{ + return md5_impl(data); +} + +std::vector<uint8_t> sha1(std::vector<uint8_t> const& data) +{ + return sha1_impl(data); +} + +std::vector<uint8_t> sha1(std::string const& data) +{ + return sha1_impl(data); +} + +std::vector<uint8_t> sha256(std::vector<uint8_t> const& data) +{ + return sha256_impl(data); +} + +std::vector<uint8_t> sha256(std::string const& data) +{ + return sha256_impl(data); +} + +std::vector<uint8_t> sha512(std::vector<uint8_t> const& data) +{ + return sha512_impl(data); +} + +std::vector<uint8_t> sha512(std::string const& data) +{ + return sha512_impl(data); +} + +std::vector<uint8_t> hmac_sha256(std::string const& key, std::string const& data) +{ + return hmac_sha256_impl(key, data); +} + +std::vector<uint8_t> hmac_sha256(std::vector<uint8_t> const& key, std::vector<uint8_t> const& data) +{ + return hmac_sha256_impl(key, data); +} + +std::vector<uint8_t> hmac_sha256(std::vector<uint8_t> const& key, std::string const& data) +{ + return hmac_sha256_impl(key, data); +} + +std::vector<uint8_t> hmac_sha256(std::string const& key, std::vector<uint8_t> const& data) +{ + return hmac_sha256_impl(key, data); +} + +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/lib/libfilezilla/encode.hpp new/libfilezilla-0.15.0/lib/libfilezilla/encode.hpp --- old/libfilezilla-0.14.0/lib/libfilezilla/encode.hpp 2018-05-06 11:22:43.000000000 +0200 +++ new/libfilezilla-0.15.0/lib/libfilezilla/encode.hpp 2018-10-19 12:00:50.000000000 +0200 @@ -98,6 +98,7 @@ /// \brief Encodes raw input string to base64 std::string FZ_PUBLIC_SYMBOL base64_encode(std::string const& in, base64_type type = base64_type::standard, bool pad = true); +std::string FZ_PUBLIC_SYMBOL base64_encode(std::vector<uint8_t> const& in, base64_type type = base64_type::standard, bool pad = true); /** * \brief Decodes base64, ignores whitespace. Returns empty string on invalid input. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/lib/libfilezilla/encryption.hpp new/libfilezilla-0.15.0/lib/libfilezilla/encryption.hpp --- old/libfilezilla-0.14.0/lib/libfilezilla/encryption.hpp 1970-01-01 01:00:00.000000000 +0100 +++ new/libfilezilla-0.15.0/lib/libfilezilla/encryption.hpp 2018-10-19 12:14:34.000000000 +0200 @@ -0,0 +1,153 @@ +#ifndef LIBFILEZILLA_ENCRYPTION_HEADER +#define LIBFILEZILLA_ENCRYPTION_HEADER + +/** \file + * \brief Asymmetric encryption scheme using X25519 + * + * See RFC 7748 for the X22519 specs. + */ + +#include "libfilezilla.hpp" + +#include <vector> +#include <string> + +namespace fz { + +/** \brief Represents a X25519 public key with associated salt + * + * \sa private_key + */ +class FZ_PUBLIC_SYMBOL public_key +{ +public: + /// Size in octets of key and salt. + enum { + key_size = 32, + salt_size = 32 + }; + + explicit operator bool() const { + return key_.size() == key_size && salt_.size() == salt_size; + } + + bool operator==(public_key const& rhs) const { + return key_ == rhs.key_ && salt_ == rhs.salt_; + } + + bool operator!=(public_key const& rhs) const { + return !(*this == rhs); + } + + bool operator<(public_key const& rhs) const { + return key_ < rhs.key_ || (key_ == rhs.key_ && salt_ < rhs.salt_); + } + + std::string to_base64() const; + static public_key from_base64(std::string const& base64); + + std::vector<uint8_t> key_; + std::vector<uint8_t> salt_; +}; + +/** \brief Represents a X25519 private key with associated salt + * + * \sa public_key + */ +class FZ_PUBLIC_SYMBOL private_key +{ +public: + /// Size in octets of key an salt. + enum { + key_size = 32, + salt_size = 32 + }; + + /// Generates a random private key + static private_key generate(); + + /// Derives a private key using PKBDF2-SHA256 from the given password and salt + static private_key from_password(std::vector<uint8_t> const& password, std::vector<uint8_t> const& salt); + static private_key from_password(std::string const& password, std::vector<uint8_t> const& salt) + { + return from_password(std::vector<uint8_t>(password.begin(), password.end()), salt); + } + + explicit operator bool() const { + return key_.size() == key_size && salt_.size() == salt_size; + } + + std::vector<uint8_t> const& salt() const { + return salt_; + } + + /// Calculates the public key corresponding to the private key + public_key pubkey() const; + + /// Calculates a shared secret using Elliptic Curve Diffie-Hellman on Curve25519 (X25519) + std::vector<uint8_t> shared_secret(public_key const& pub) const; + + std::string to_base64() const; + static private_key from_base64(std::string const& base64); + +private: + std::vector<uint8_t> key_; + std::vector<uint8_t> salt_; +}; + +/** \brief Encrypt the plaintext to the given public key. + * + * \param authenticated if true, authenticated encryption is used. + * + * \par Encryption algorithm: + * + * Let \e M_pub be the key portion, S_e be the salt portion of the pub parameter and \e P be the plaintext. + * + * - First an ephemeral private key \e E_priv with corresponding public key \e E_pub and \e S_e is randomly generated + * - Using ECDH on Curve25519 (X25519), a shared secret \e R is derived:\n + * <tt>R := X25519(E_priv, M_pub)</tt> + * - From \e R, a symmetric AES256 key \e K and a nonce \e IV are derived: + * * <tt>K := SHA256(S_e || 0 || S || E_pub || M_pub || S_m)</tt> + * * <tt>IV := SHA256(S_e || 2 || S || E_pub || M_pub || S_m)</tt> if authenticated,\n + * <tt>IV := SHA256(S_e || 1 || S || E_pub || M_pub || S_m)</tt> otherwise + * - The plaintext is encrypted into the ciphertext \e C' and authentication tag \e T using\n + * <tt>C', T := AES256-GCM(K, IV, P)</tt> if authenticated,\n + * <tt>C' := AES256-CTR(K, IV, P)</tt> T:='' otherwise + * - The ciphertext \e C is returned, containing \e E_pub, \e S_e and \e T: \n + * <tt>C := E_pub || S_e || C' || T</tt> + */ +std::vector<uint8_t> FZ_PUBLIC_SYMBOL encrypt(std::vector<uint8_t> const& plain, public_key const& pub, bool authenticated = true); +std::vector<uint8_t> FZ_PUBLIC_SYMBOL encrypt(std::string const& plain, public_key const& pub, bool authenticated = true); +std::vector<uint8_t> FZ_PUBLIC_SYMBOL encrypt(uint8_t const* plain, size_t size, public_key const& pub, bool authenticated = true); + +/** \brief Decrypt the ciphertext using the given private key. + * + * \param priv The private matching the public key that was originally used to encrypt the data + * \param authenticated if true, authenticated encryption is used. + * + * \returns plaintext on success, empty container on failure + * + * \par Decryption algorithm: + * + * Let \e M_priv be the key portion and \e S_m be the salt portion of the priv parameter and \e C the ciphertext. + * + * - First \e C is split into \e E_pub, \e S_e, \e C' and \e T such that\n + * <tt>C: = E_pub || S_e || C1 || T</tt> + * - \e M_pub is calculated from \e M_priv + * - Using ECDH on Curve25519 (X25519), the shared secret \e R is recovered:\n + * <tt>R := X25519(M_priv, E_pub)</tt> + * - From \e R, a symmetric AES256 key \e K and a nonce \e IV are derived: + * * <tt>K := SHA256(S_e || 0 || S || E_pub || M_pub || S_m)</tt> + * * <tt>IV := SHA256(S_e || 2 || S || E_pub || M_pub || S_m)</tt> if authenticated,\n + * <tt>IV := SHA256(S_e || 1 || S || E_pub || M_pub || S_m)</tt> otherwise + * - The ciphertext is decrypted into the plaintext \e P using\n + * <tt>P, T' := AES256-GCM(K, IV, C')</tt> if authenticated,\n + * <tt>P := AES256-CTR(K, IV, C'), T:=''</tt> otherwise + * - If the calculated \e T' matches \e T, then \e P is returned, otherwise decryption has failed and nothing is returned. + */ +std::vector<uint8_t> FZ_PUBLIC_SYMBOL decrypt(std::vector<uint8_t> const& chiper, private_key const& priv, bool authenticated = true); +std::vector<uint8_t> FZ_PUBLIC_SYMBOL decrypt(std::string const& chiper, private_key const& priv, bool authenticated = true); +std::vector<uint8_t> FZ_PUBLIC_SYMBOL decrypt(uint8_t const* cipher, size_t size, private_key const& priv, bool authenticated = true); + +} +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/lib/libfilezilla/file.hpp new/libfilezilla-0.15.0/lib/libfilezilla/file.hpp --- old/libfilezilla-0.14.0/lib/libfilezilla/file.hpp 2017-10-30 18:14:16.000000000 +0100 +++ new/libfilezilla-0.15.0/lib/libfilezilla/file.hpp 2018-10-19 12:00:50.000000000 +0200 @@ -142,6 +142,10 @@ #endif }; +/** \brief remove the specified file. + * + * \return true iff the file has been removed or did not exist to begin with. + */ bool FZ_PUBLIC_SYMBOL remove_file(native_string const& name); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/lib/libfilezilla/hash.hpp new/libfilezilla-0.15.0/lib/libfilezilla/hash.hpp --- old/libfilezilla-0.14.0/lib/libfilezilla/hash.hpp 1970-01-01 01:00:00.000000000 +0100 +++ new/libfilezilla-0.15.0/lib/libfilezilla/hash.hpp 2018-10-19 12:00:50.000000000 +0200 @@ -0,0 +1,81 @@ +#ifndef LIBFILEZILLA_HASH_HEADER +#define LIBFILEZILLA_HASH_HEADER + +/** \file + * \brief Collection of cryptographic hash and MAC functions + */ + +#include "libfilezilla.hpp" + +#include <vector> +#include <string> + +namespace fz { + +/// List of supported hashing algorithms +enum class hash_algorithm +{ + md5, + sha1, + sha256, + sha512 +}; + +/// Accumulator for hashing large amounts of data +class FZ_PUBLIC_SYMBOL hash_accumulator final +{ +public: + /// Creates an initialized accumulator for the passed algorithm + hash_accumulator(hash_algorithm algorithm); + ~hash_accumulator(); + + hash_accumulator(hash_accumulator const&) = delete; + hash_accumulator& operator=(hash_accumulator const&) = delete; + + void reinit(); + + void update(std::string const& data); + void update(std::vector<uint8_t> const& data); + void update(uint8_t const* data, size_t size); + void update(uint8_t in) { + update(&in, 1); + } + + /// Returns the raw digest and reinitalizes the accumulator + std::vector<uint8_t> digest(); + + operator std::vector<uint8_t>() { + return digest(); + } + + template<typename T> + hash_accumulator& operator<<(T && in) { + update(std::forward<T>(in)); + return *this; + } + + class impl; +private: + impl* impl_; +}; + +/** \brief Standard MD5 + * + * Insecure, avoid using this + */ +std::vector<uint8_t> FZ_PUBLIC_SYMBOL md5(std::string const& data); +std::vector<uint8_t> FZ_PUBLIC_SYMBOL md5(std::vector<uint8_t> const& data); + +/// \brief Standard SHA256 +std::vector<uint8_t> FZ_PUBLIC_SYMBOL sha256(std::string const& data); +std::vector<uint8_t> FZ_PUBLIC_SYMBOL sha256(std::vector<uint8_t> const& data); + +/// \brief Standard HMAC using SHA256 +std::vector<uint8_t> FZ_PUBLIC_SYMBOL hmac_sha256(std::string const& key, std::string const& data); +std::vector<uint8_t> FZ_PUBLIC_SYMBOL hmac_sha256(std::vector<uint8_t> const& key, std::vector<uint8_t> const& data); +std::vector<uint8_t> FZ_PUBLIC_SYMBOL hmac_sha256(std::vector<uint8_t> const& key, std::string const& data); +std::vector<uint8_t> FZ_PUBLIC_SYMBOL hmac_sha256(std::string const& key, std::vector<uint8_t> const& data); + +} + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/lib/libfilezilla/signature.hpp new/libfilezilla-0.15.0/lib/libfilezilla/signature.hpp --- old/libfilezilla-0.14.0/lib/libfilezilla/signature.hpp 1970-01-01 01:00:00.000000000 +0100 +++ new/libfilezilla-0.15.0/lib/libfilezilla/signature.hpp 2018-10-19 12:00:50.000000000 +0200 @@ -0,0 +1,98 @@ +#ifndef LIBFILEZILLA_SIGNATURE_HEADER +#define LIBFILEZILLA_SIGNATURE_HEADER + +/** \file + * \brief Signature scheme using Ed25519 + * + * See RFC 8032 for the X22519 specs. + */ + +#include "libfilezilla.hpp" + +#include <vector> +#include <string> + +namespace fz { + +/** \brief Represents a public key to verify messages signed using Ed25519. + * + * \sa private_signing_key + */ +class FZ_PUBLIC_SYMBOL public_verification_key +{ +public: + enum { + key_size = 32 + }; + + explicit operator bool() const { + return key_.size() == key_size; + } + + bool operator==(public_verification_key const& rhs) const { + return key_ == rhs.key_; + } + + bool operator!=(public_verification_key const& rhs) const { + return !(*this == rhs); + } + + bool operator<(public_verification_key const& rhs) const { + return key_ < rhs.key_; + } + + std::string to_base64() const; + static public_verification_key from_base64(std::string const& base64); + + std::vector<uint8_t> key_; +}; + +/** \brief Represents a private key to sign message with using Ed25519. + * + * \sa public_verification_key + */ +class FZ_PUBLIC_SYMBOL private_signing_key +{ +public: + enum { + key_size = 32 + }; + + /// Generates a random private key + static private_signing_key generate(); + + explicit operator bool() const { + return key_.size() == key_size; + } + + /// Gets the public key corresponding to the private key + public_verification_key pubkey() const; + + std::vector<uint8_t> const& data() const { + return key_; + } + + std::string to_base64() const; // Keep secret! + static private_signing_key from_base64(std::string const& base64); + +private: + std::vector<uint8_t> key_; +}; + +enum { + signature_size = 64 +}; + +/// Returns the message with the signature appended, created using the passed private key +std::vector<uint8_t> FZ_PUBLIC_SYMBOL sign(std::vector<uint8_t> const& message, private_signing_key const& priv); +std::vector<uint8_t> FZ_PUBLIC_SYMBOL sign(std::string const& message, private_signing_key const& priv); +std::vector<uint8_t> FZ_PUBLIC_SYMBOL sign(uint8_t const& message, size_t const size, private_signing_key const& priv); + +/// Verify the message. Returns true iff it has been signed by the private key corresponding to the passed public key +bool FZ_PUBLIC_SYMBOL verify(std::vector<uint8_t> const& message, public_verification_key const& pub); +bool FZ_PUBLIC_SYMBOL verify(std::string const& message, public_verification_key const& pub); +bool FZ_PUBLIC_SYMBOL verify(uint8_t const* message, size_t const size, public_verification_key const& pub); + +} + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/lib/libfilezilla/version.hpp new/libfilezilla-0.15.0/lib/libfilezilla/version.hpp --- old/libfilezilla-0.14.0/lib/libfilezilla/version.hpp 2018-10-04 13:17:21.000000000 +0200 +++ new/libfilezilla-0.15.0/lib/libfilezilla/version.hpp 2018-10-19 12:14:45.000000000 +0200 @@ -9,15 +9,15 @@ #include <tuple> /// \brief Version string of the libfilezilla headers -#define LIBFILEZILLA_VERSION "0.14.0" +#define LIBFILEZILLA_VERSION "0.15.0" #define LIBFILEZILLA_VERSION_MAJOR 0 -#define LIBFILEZILLA_VERSION_MINOR 14 +#define LIBFILEZILLA_VERSION_MINOR 15 #define LIBFILEZILLA_VERSION_MICRO 0 #define LIBFILEZILLA_VERSION_NANO 0 /// \brief Suffix string, e.g. "rc1" -#define LIBFILEZILLA_VERSION_SUFFIX "0.14.0" +#define LIBFILEZILLA_VERSION_SUFFIX "0.15.0" namespace fz { /// \brief Get version string of libfilezilla diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/lib/libfilezilla.pc.in new/libfilezilla-0.15.0/lib/libfilezilla.pc.in --- old/libfilezilla-0.14.0/lib/libfilezilla.pc.in 2015-11-02 14:47:31.000000000 +0100 +++ new/libfilezilla-0.15.0/lib/libfilezilla.pc.in 2018-10-19 12:00:50.000000000 +0200 @@ -9,3 +9,4 @@ Version: @PACKAGE_VERSION@ CFlags: -I${includedir} Libs: -L${libdir} -lfilezilla @libdeps@ +Requires.private: nettle >= 3.1, hogweed >= 3.1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/lib/libfilezilla.vcxproj new/libfilezilla-0.15.0/lib/libfilezilla.vcxproj --- old/libfilezilla-0.14.0/lib/libfilezilla.vcxproj 2017-09-29 10:41:58.000000000 +0200 +++ new/libfilezilla-0.15.0/lib/libfilezilla.vcxproj 2018-10-19 12:00:50.000000000 +0200 @@ -66,6 +66,9 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <ImportGroup Label="ExtensionSettings"> </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="..\Dependencies.props" /> + </ImportGroup> <PropertyGroup Label="UserMacros" /> <PropertyGroup> <OutDir>$(ProjectDir)$(Platform)_$(Configuration)\</OutDir> @@ -81,7 +84,7 @@ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> - <WarningLevel>Level3</WarningLevel> + <WarningLevel>Level4</WarningLevel> <DebugInformationFormat>EditAndContinue</DebugInformationFormat> <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> @@ -137,7 +140,6 @@ <OmitFramePointers>true</OmitFramePointers> <PreprocessorDefinitions>BUILDING_LIBFILEZILLA;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <MultiProcessorCompilation>true</MultiProcessorCompilation> @@ -188,10 +190,12 @@ <ItemGroup> <ClCompile Include="buffer.cpp" /> <ClCompile Include="encode.cpp" /> + <ClCompile Include="encryption.cpp" /> <ClCompile Include="event.cpp" /> <ClCompile Include="event_handler.cpp" /> <ClCompile Include="event_loop.cpp" /> <ClCompile Include="file.cpp" /> + <ClCompile Include="hash.cpp" /> <ClCompile Include="iputils.cpp" /> <ClCompile Include="local_filesys.cpp" /> <ClCompile Include="mutex.cpp" /> @@ -209,11 +213,13 @@ <ClInclude Include="libfilezilla\apply.hpp" /> <ClInclude Include="libfilezilla\buffer.hpp" /> <ClInclude Include="libfilezilla\encode.hpp" /> + <ClInclude Include="libfilezilla\encryption.hpp" /> <ClInclude Include="libfilezilla\event.hpp" /> <ClInclude Include="libfilezilla\event_handler.hpp" /> <ClInclude Include="libfilezilla\event_loop.hpp" /> <ClInclude Include="libfilezilla\file.hpp" /> <ClInclude Include="libfilezilla\format.hpp" /> + <ClInclude Include="libfilezilla\hash.hpp" /> <ClInclude Include="libfilezilla\iputils.hpp" /> <ClInclude Include="libfilezilla\libfilezilla.hpp" /> <ClInclude Include="libfilezilla\local_filesys.hpp" /> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/lib/signature.cpp new/libfilezilla-0.15.0/lib/signature.cpp --- old/libfilezilla-0.14.0/lib/signature.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/libfilezilla-0.15.0/lib/signature.cpp 2018-10-19 12:00:50.000000000 +0200 @@ -0,0 +1,115 @@ +#include "libfilezilla/signature.hpp" + +#include "libfilezilla/encode.hpp" +#include "libfilezilla/util.hpp" + +#include <nettle/eddsa.h> + +namespace fz { + +std::string public_verification_key::to_base64() const +{ + auto raw = std::string(key_.cbegin(), key_.cend()); + return fz::base64_encode(raw); +} + +public_verification_key public_verification_key::from_base64(std::string const& base64) +{ + public_verification_key ret; + + auto raw = fz::base64_decode(base64); + if (raw.size() == key_size) { + auto p = reinterpret_cast<uint8_t const*>(&raw[0]); + ret.key_.assign(p, p + key_size); + } + + return ret; +} + +private_signing_key private_signing_key::generate() +{ + private_signing_key ret; + + ret.key_ = fz::random_bytes(key_size); + return ret; +} + +std::string private_signing_key::to_base64() const +{ + auto raw = std::string(key_.cbegin(), key_.cend()); + return fz::base64_encode(raw); +} + +private_signing_key private_signing_key::from_base64(std::string const& base64) +{ + private_signing_key ret; + + auto raw = fz::base64_decode(base64); + if (raw.size() == key_size) { + auto p = reinterpret_cast<uint8_t const*>(&raw[0]); + ret.key_.assign(p, p + key_size); + } + + return ret; +} + +public_verification_key private_signing_key::pubkey() const +{ + public_verification_key ret; + + if (*this) { + ret.key_.resize(public_verification_key::key_size); + nettle_ed25519_sha512_public_key(ret.key_.data(), key_.data()); + } + + return ret; +} + + +std::vector<uint8_t> sign(uint8_t const* message, size_t const size, private_signing_key const& priv) +{ + std::vector<uint8_t> ret; + + auto const pub = priv.pubkey(); + if (priv && pub && size) { + ret.reserve(size + signature_size); + ret.assign(message, message + size); + ret.resize(size + signature_size); + + nettle_ed25519_sha512_sign(pub.key_.data(), priv.data().data(), size, ret.data(), ret.data() + size); + } + + return ret; +} + +std::vector<uint8_t> sign(std::vector<uint8_t> const& message, private_signing_key const& priv) +{ + return sign(message.data(), message.size(), priv); +} + +std::vector<uint8_t> sign(std::string const& message, private_signing_key const& priv) +{ + return sign(reinterpret_cast<uint8_t const*>(message.c_str()), message.size(), priv); +} + + +// Verify the message. Returns true iff it has been signed by the private key corresponding to the passed public key +bool verify(uint8_t const* message, size_t const size, public_verification_key const& pub) +{ + if (!message || size < signature_size) { + return false; + } + return nettle_ed25519_sha512_verify(pub.key_.data(), size - signature_size, message, message + size - signature_size) == 1; +} + +bool verify(std::vector<uint8_t> const& message, public_verification_key const& pub) +{ + return verify(message.data(), message.size(), pub); +} + +bool verify(std::string const& message, public_verification_key const& pub) +{ + return verify(reinterpret_cast<uint8_t const*>(message.c_str()), message.size(), pub); +} + +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/tests/Makefile.am new/libfilezilla-0.15.0/tests/Makefile.am --- old/libfilezilla-0.14.0/tests/Makefile.am 2018-02-23 09:29:01.000000000 +0100 +++ new/libfilezilla-0.15.0/tests/Makefile.am 2018-10-19 12:00:50.000000000 +0200 @@ -5,6 +5,7 @@ test_SOURCES = test.cpp \ buffer.cpp \ + crypto.cpp \ dispatch.cpp \ eventloop.cpp \ format.cpp \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/tests/crypto.cpp new/libfilezilla-0.15.0/tests/crypto.cpp --- old/libfilezilla-0.14.0/tests/crypto.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/libfilezilla-0.15.0/tests/crypto.cpp 2018-10-19 12:00:50.000000000 +0200 @@ -0,0 +1,63 @@ +#include "libfilezilla/encryption.hpp" +#include "libfilezilla/util.hpp" + +#include "test_utils.hpp" + +#include <string.h> + +class crypto_test final : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(crypto_test); + CPPUNIT_TEST(test_encryption); + CPPUNIT_TEST(test_encryption_with_password); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp() {} + void tearDown() {} + + void test_encryption(); + void test_encryption_with_password(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(crypto_test); + +void crypto_test::test_encryption() +{ + auto priv = fz::private_key::generate(); + priv.generate(); + + auto const pub = priv.pubkey(); + + std::string const plain = "Hello world"; + + auto cipher = fz::encrypt(plain, pub); + CPPUNIT_ASSERT(fz::decrypt(cipher, priv) == std::vector<uint8_t>(plain.cbegin(), plain.cend())); +} + + +void crypto_test::test_encryption_with_password() +{ + auto const salt = fz::random_bytes(fz::private_key::salt_size); + + std::string const plain = "Hello world"; + std::vector<uint8_t> cipher; + + { + auto priv = fz::private_key::from_password("super secret", salt); + CPPUNIT_ASSERT(priv); + + auto const pub = priv.pubkey(); + + cipher = fz::encrypt(plain, pub); + } + + + { + auto priv = fz::private_key::from_password("super secret", salt); + CPPUNIT_ASSERT(priv); + + CPPUNIT_ASSERT(fz::decrypt(cipher, priv) == std::vector<uint8_t>(plain.cbegin(), plain.cend())); + } + +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libfilezilla-0.14.0/tests/string.cpp new/libfilezilla-0.15.0/tests/string.cpp --- old/libfilezilla-0.14.0/tests/string.cpp 2018-10-04 13:17:12.000000000 +0200 +++ new/libfilezilla-0.15.0/tests/string.cpp 2018-10-19 12:00:50.000000000 +0200 @@ -99,9 +99,9 @@ CPPUNIT_ASSERT_EQUAL(std::string("Zm9vbA"), fz::base64_encode("fool", fz::base64_type::standard, false)); CPPUNIT_ASSERT_EQUAL(std::string("Zm9vbHM"), fz::base64_encode("fools", fz::base64_type::standard, false)); - CPPUNIT_ASSERT_EQUAL(std::string("AAECA/3+/w=="), fz::base64_encode({0, 1, 2, 3, '\xfd', '\xfe', '\xff'})); + CPPUNIT_ASSERT_EQUAL(std::string("AAECA/3+/w=="), fz::base64_encode(std::string({0, 1, 2, 3, '\xfd', '\xfe', '\xff'}))); - CPPUNIT_ASSERT_EQUAL(std::string("AAECA_3-_w=="), fz::base64_encode({0, 1, 2, 3, '\xfd', '\xfe', '\xff'}, fz::base64_type::url)); + CPPUNIT_ASSERT_EQUAL(std::string("AAECA_3-_w=="), fz::base64_encode(std::string({0, 1, 2, 3, '\xfd', '\xfe', '\xff'}), fz::base64_type::url)); // decode CPPUNIT_ASSERT_EQUAL(std::string(""), fz::base64_decode(""));
participants (1)
-
root