diff --git a/README.asciidoc b/README.asciidoc index ce50154e..7a47eae6 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -96,9 +96,9 @@ Dependency |==================================================== |features |dependency |HTTPS |GnuTLS or OpenSSL -|BitTorrent |GnuTLS+Libgcrypt or OpenSSL +|BitTorrent |libnettle+libgmp or libgcrypt or OpenSSL |Metalink |libxml2 or Expat. -|Checksum |GnuTLS+Libgcrypt or OpenSSL +|Checksum |libnettle or libgcrypt or OpenSSL |gzip, deflate in HTTP |zlib |Async DNS |C-Ares |Firefox3/Chromium cookie|libsqlite3 @@ -106,9 +106,15 @@ Dependency |==================================================== Note;; - GNU TLS has precedence over OpenSSL if both libraries are installed. + GnuTLS has precedence over OpenSSL if both libraries are installed. If you prefer OpenSSL, run configure with \--without-gnutls. +Note;; + libnettle has precedence over libgcrypt and libgcrypt has precedence + over OpenSSL. If you prefer libgcrypt, run configure with + \--without-libnettle. If you prefer \--without-libnettle + \--without-libgcrypt. + Note;; libxml2 has precedence over Expat if both libraries are installed. If you prefer Expat, run configure with \--without-libxml2. @@ -128,15 +134,20 @@ development packages(package name may vary depending on the distribution you use): * libgnutls-dev (Required for HTTPS, BitTorrent, Checksum support) -* libgpg-error-dev (Required for BitTorrent, Checksum support) -* libgcrypt-dev (Required for BitTorrent, Checksum support) +* nettle-dev (Required for BitTorrent, Checksum support) +* libgmp-dev (Required for BitTorrent) * libc-ares-dev (Required for async DNS support) * libxml2-dev (Required for Metalink support) * zlib1g-dev (Required for gzip, deflate decoding support in HTTP) * libsqlite3-dev (Required for Firefox3/Chromium cookie support) +You can use libgcrypt-dev instead of nettle-dev and libgmp-dev: + +* libgpg-error-dev (Required for BitTorrent, Checksum support) +* libgcrypt-dev (Required for BitTorrent, Checksum support) + You can use libssl-dev instead of -libgnutls-dev,libgpg-error-dev,libgcrypt-dev: +libgnutls-dev, nettle-dev, libgmp-dev, libgpg-error-dev and libgcrypt-dev: * libssl-dev (Required for HTTPS, BitTorrent, Checksum support) diff --git a/configure.ac b/configure.ac index e75e53d5..328d2260 100644 --- a/configure.ac +++ b/configure.ac @@ -21,6 +21,9 @@ AC_DEFINE_UNQUOTED([TARGET], ["$target"], [Define target-type]) # Checks for arguments. ARIA2_ARG_WITH([gnutls]) +ARIA2_ARG_WITH([libnettle]) +ARIA2_ARG_WITH([libgmp]) +ARIA2_ARG_WITH([libgcrypt]) ARIA2_ARG_WITH([openssl]) ARIA2_ARG_WITH([sqlite3]) ARIA2_ARG_WITH([libxml2]) @@ -113,15 +116,6 @@ if test "x$with_gnutls" = "xyes"; then fi fi -if test "x$have_libgnutls" = "xyes"; then - AM_PATH_LIBGCRYPT([1.2.2], [have_libgcrypt=yes]) - if test "x$have_libgcrypt" = "xyes"; then - AC_DEFINE([HAVE_LIBGCRYPT], [1], [Define to 1 if you have libgcrypt.]) - LIBS="$LIBGCRYPT_LIBS $LIBS" - CPPFLAGS="$LIBGCRYPT_CFLAGS $CPPFLAGS" - fi -fi - if test "x$with_openssl" = "xyes" && test "x$have_libgnutls" != "xyes"; then AM_PATH_OPENSSL if test "x$have_openssl" = "xyes"; then @@ -132,6 +126,33 @@ if test "x$with_openssl" = "xyes" && test "x$have_libgnutls" != "xyes"; then fi fi +if test "x$have_openssl" != "xyes"; then + if test "x$with_libnettle" = "xyes"; then + AC_SEARCH_LIBS([nettle_sha1_init], [nettle], + [have_libnettle=yes], [have_libnettle=no]) + if test "x$have_libnettle" = "xyes"; then + AC_DEFINE([HAVE_LIBNETTLE], [1], [Define to 1 if you have libnettle.]) + fi + fi + if test "x$with_libgmp" = "xyes" && + test "x$have_libnettle" = "xyes" && + test "x$enable_bittorrent" = "xyes"; then + AC_SEARCH_LIBS([__gmpz_init], [gmp], [have_libgmp=yes], [have_libgmp=no]) + if test "x$have_libgmp" = "xyes"; then + AC_DEFINE([HAVE_LIBGMP], [1], [Define to 1 if you have libgmp.]) + fi + fi + if test "x$with_libgcrypt" = "xyes" && + test "x$have_libnettle" != "xyes"; then + AM_PATH_LIBGCRYPT([1.2.2], [have_libgcrypt=yes]) + if test "x$have_libgcrypt" = "xyes"; then + AC_DEFINE([HAVE_LIBGCRYPT], [1], [Define to 1 if you have libgcrypt.]) + LIBS="$LIBGCRYPT_LIBS $LIBS" + CPPFLAGS="$LIBGCRYPT_CFLAGS $CPPFLAGS" + fi + fi +fi + if test "x$with_libcares" = "xyes"; then AM_PATH_LIBCARES if test "x$have_libcares" = "xyes"; then @@ -163,9 +184,13 @@ else fi AM_CONDITIONAL([HAVE_LIBGNUTLS], [ test "x$have_libgnutls" = "xyes" ]) +AM_CONDITIONAL([HAVE_LIBNETTLE], [ test "x$have_libnettle" = "xyes" ]) +AM_CONDITIONAL([HAVE_LIBGMP], [ test "x$have_libgmp" = "xyes" ]) +AM_CONDITIONAL([HAVE_LIBGCRYPT], [ test "x$have_libgcrypt" = "xyes" ]) AM_CONDITIONAL([HAVE_OPENSSL], [ test "x$have_openssl" = "xyes" ]) -if test "x$have_libgcrypt" = "xyes" || test "x$have_openssl" = "xyes"; then +if test "x$have_libnettle" = "xyes" || test "x$have_libgcrypt" = "xyes" || + test "x$have_openssl" = "xyes"; then AC_DEFINE([ENABLE_MESSAGE_DIGEST], [1], [Define to 1 if message digest support is enabled.]) AM_CONDITIONAL([ENABLE_MESSAGE_DIGEST], true) @@ -174,8 +199,14 @@ else AM_CONDITIONAL([ENABLE_MESSAGE_DIGEST], false) fi +if test "x$have_libnettle" = "xyes" && test "x$have_libgmp" = "xyes" || + test "x$have_libgcrypt" = "xyes" || test "x$have_openssl" = "xyes"; then + enable_bignum=yes +fi + if test "x$enable_bittorrent" = "xyes" && - test "x$enable_message_digest" = "xyes"; then + test "x$enable_message_digest" = "xyes" && + test "x$enable_bignum" = "xyes"; then AC_DEFINE([ENABLE_BITTORRENT], [1], [Define to 1 if BitTorrent support is enabled.]) AM_CONDITIONAL([ENABLE_BITTORRENT], true) diff --git a/src/ARC4Decryptor.h b/src/ARC4Decryptor.h index 20254c31..c2cb4c29 100644 --- a/src/ARC4Decryptor.h +++ b/src/ARC4Decryptor.h @@ -36,7 +36,9 @@ #define D_ARC4_DECRYPTOR_H #include "common.h" -#ifdef HAVE_LIBGCRYPT +#ifdef HAVE_LIBNETTLE +# include "LibnettleARC4Decryptor.h" +#elif HAVE_LIBGCRYPT # include "LibgcryptARC4Decryptor.h" #elif HAVE_OPENSSL # include "LibsslARC4Decryptor.h" diff --git a/src/ARC4Encryptor.h b/src/ARC4Encryptor.h index 84a0f049..c9df2d50 100644 --- a/src/ARC4Encryptor.h +++ b/src/ARC4Encryptor.h @@ -36,7 +36,9 @@ #define D_ARC4_ENCRYPTOR_H #include "common.h" -#ifdef HAVE_LIBGCRYPT +#ifdef HAVE_LIBNETTLE +# include "LibnettleARC4Encryptor.h" +#elif HAVE_LIBGCRYPT # include "LibgcryptARC4Encryptor.h" #elif HAVE_OPENSSL # include "LibsslARC4Encryptor.h" diff --git a/src/DHKeyExchange.h b/src/DHKeyExchange.h index 91e12ff0..1fd7b86f 100644 --- a/src/DHKeyExchange.h +++ b/src/DHKeyExchange.h @@ -36,7 +36,9 @@ #define D_DH_KEY_EXCHANGE_H #include "common.h" -#ifdef HAVE_LIBGCRYPT +#ifdef HAVE_LIBGMP +# include "LibgmpDHKeyExchange.h" +#elif HAVE_LIBGCRYPT # include "LibgcryptDHKeyExchange.h" #elif HAVE_OPENSSL # include "LibsslDHKeyExchange.h" diff --git a/src/LibnettleARC4Context.cc b/src/LibnettleARC4Context.cc new file mode 100644 index 00000000..926d708f --- /dev/null +++ b/src/LibnettleARC4Context.cc @@ -0,0 +1,53 @@ +/* */ +#include "LibnettleARC4Context.h" + +namespace aria2 { + +LibnettleARC4Context::LibnettleARC4Context() + : cipherCtx_(new arcfour_ctx()) +{} + +LibnettleARC4Context::~LibnettleARC4Context() +{ + delete cipherCtx_; +} + +void LibnettleARC4Context::init(const unsigned char* key, size_t keyLength) +{ + arcfour_set_key(cipherCtx_, keyLength, key); +} + +} // namespace aria2 diff --git a/src/LibnettleARC4Context.h b/src/LibnettleARC4Context.h new file mode 100644 index 00000000..a7cb094f --- /dev/null +++ b/src/LibnettleARC4Context.h @@ -0,0 +1,64 @@ +/* */ +#ifndef D_LIBNETTLE_ARC4_CONTEXT_H +#define D_LIBNETTLE_ARC4_CONTEXT_H + +#include "common.h" + +#include + +#include + +namespace aria2 { + +class LibnettleARC4Context { +private: + arcfour_ctx* cipherCtx_; +public: + LibnettleARC4Context(); + + ~LibnettleARC4Context(); + + arcfour_ctx* getCipherContext() const + { + return cipherCtx_; + } + + void init(const unsigned char* key, size_t keyLength); +}; + +} // namespace aria2 + +#endif // D_LIBNETTLE_ARC4_CONTEXT_H diff --git a/src/LibnettleARC4Decryptor.cc b/src/LibnettleARC4Decryptor.cc new file mode 100644 index 00000000..e79a21bf --- /dev/null +++ b/src/LibnettleARC4Decryptor.cc @@ -0,0 +1,57 @@ +/* */ +#include "LibnettleARC4Decryptor.h" + +#include + +namespace aria2 { + +ARC4Decryptor::ARC4Decryptor() {} + +ARC4Decryptor::~ARC4Decryptor() {} + +void ARC4Decryptor::init(const unsigned char* key, size_t keyLength) +{ + ctx_.init(key, keyLength); +} + +void ARC4Decryptor::decrypt(unsigned char* out, size_t outLength, + const unsigned char* in, size_t inLength) +{ + assert(outLength == inLength); + arcfour_crypt(ctx_.getCipherContext(), outLength, out, in); +} + +} // namespace aria2 diff --git a/src/LibnettleARC4Decryptor.h b/src/LibnettleARC4Decryptor.h new file mode 100644 index 00000000..fab17cdb --- /dev/null +++ b/src/LibnettleARC4Decryptor.h @@ -0,0 +1,59 @@ +/* */ +#ifndef D_LIBNETTLE_ARC4_DECRYPTOR_H +#define D_LIBNETTLE_ARC4_DECRYPTOR_H + +#include "common.h" +#include "LibnettleARC4Context.h" + +namespace aria2 { + +class ARC4Decryptor { +private: + LibnettleARC4Context ctx_; +public: + ARC4Decryptor(); + + ~ARC4Decryptor(); + + void init(const unsigned char* key, size_t keyLength); + + void decrypt(unsigned char* out, size_t outLength, + const unsigned char* in, size_t inLength); +}; + +} // namespace aria2 + +#endif // D_LIBNETTLE_ARC4_DECRYPTOR_H diff --git a/src/LibnettleARC4Encryptor.cc b/src/LibnettleARC4Encryptor.cc new file mode 100644 index 00000000..fc1dab4e --- /dev/null +++ b/src/LibnettleARC4Encryptor.cc @@ -0,0 +1,57 @@ +/* */ +#include "LibnettleARC4Encryptor.h" + +#include + +namespace aria2 { + +ARC4Encryptor::ARC4Encryptor() {} + +ARC4Encryptor::~ARC4Encryptor() {} + +void ARC4Encryptor::init(const unsigned char* key, size_t keyLength) +{ + ctx_.init(key, keyLength); +} + +void ARC4Encryptor::encrypt(unsigned char* out, size_t outLength, + const unsigned char* in, size_t inLength) +{ + assert(outLength == inLength); + arcfour_crypt(ctx_.getCipherContext(), outLength, out, in); +} + +} // namespace aria2 diff --git a/src/LibnettleARC4Encryptor.h b/src/LibnettleARC4Encryptor.h new file mode 100644 index 00000000..bc71f781 --- /dev/null +++ b/src/LibnettleARC4Encryptor.h @@ -0,0 +1,59 @@ +/* */ +#ifndef D_LIBNETTLE_ARC4_ENCRYPTOR_H +#define D_LIBNETTLE_ARC4_ENCRYPTOR_H + +#include "common.h" +#include "LibnettleARC4Context.h" + +namespace aria2 { + +class ARC4Encryptor { +private: + LibnettleARC4Context ctx_; +public: + ARC4Encryptor(); + + ~ARC4Encryptor(); + + void init(const unsigned char* key, size_t keyLength); + + void encrypt(unsigned char* out, size_t outLength, + const unsigned char* in, size_t inLength); +}; + +} // namespace aria2 + +#endif // D_LIBNETTLE_ARC4_ENCRYPTOR_H diff --git a/src/LibnettleMessageDigestImpl.cc b/src/LibnettleMessageDigestImpl.cc new file mode 100644 index 00000000..d8eac9b7 --- /dev/null +++ b/src/LibnettleMessageDigestImpl.cc @@ -0,0 +1,115 @@ +/* */ +#include "LibnettleMessageDigestImpl.h" + +#include + +#include "array_fun.h" +#include "HashFuncEntry.h" + +namespace aria2 { + +MessageDigestImpl::MessageDigestImpl(const nettle_hash* hashInfo) + : hashInfo_(hashInfo), + ctx_(new char[hashInfo->context_size]) +{ + reset(); +} + +MessageDigestImpl::~MessageDigestImpl() +{ + delete [] ctx_; +} + +SharedHandle MessageDigestImpl::sha1() +{ + return SharedHandle(new MessageDigestImpl(&nettle_sha1)); +} + +typedef HashFuncEntry CHashFuncEntry; +typedef FindHashFunc CFindHashFunc; + +namespace { +CHashFuncEntry hashFuncs[] = { + CHashFuncEntry("sha-1", &nettle_sha1), + CHashFuncEntry("sha-224", &nettle_sha224), + CHashFuncEntry("sha-256", &nettle_sha256), + CHashFuncEntry("sha-384", &nettle_sha384), + CHashFuncEntry("sha-512", &nettle_sha512), + CHashFuncEntry("md5", &nettle_md5) +}; +} // namespace + +SharedHandle MessageDigestImpl::create +(const std::string& hashType) +{ + const nettle_hash* hashInfo = + getHashFunc(vbegin(hashFuncs), vend(hashFuncs), hashType); + return SharedHandle(new MessageDigestImpl(hashInfo)); +} + +bool MessageDigestImpl::supports(const std::string& hashType) +{ + return vend(hashFuncs) != std::find_if(vbegin(hashFuncs), vend(hashFuncs), + CFindHashFunc(hashType)); +} + +size_t MessageDigestImpl::getDigestLength(const std::string& hashType) +{ + const nettle_hash* hashInfo = + getHashFunc(vbegin(hashFuncs), vend(hashFuncs), hashType); + return hashInfo->digest_size; +} + +size_t MessageDigestImpl::getDigestLength() const +{ + return hashInfo_->digest_size; +} + +void MessageDigestImpl::reset() +{ + hashInfo_->init(ctx_); +} +void MessageDigestImpl::update(const void* data, size_t length) +{ + hashInfo_->update(ctx_, length, static_cast(data)); +} + +void MessageDigestImpl::digest(unsigned char* md) +{ + hashInfo_->digest(ctx_, getDigestLength(), md); +} + +} // namespace aria2 diff --git a/src/LibnettleMessageDigestImpl.h b/src/LibnettleMessageDigestImpl.h new file mode 100644 index 00000000..3c6a86d6 --- /dev/null +++ b/src/LibnettleMessageDigestImpl.h @@ -0,0 +1,75 @@ +/* */ +#ifndef D_LIBNETTLE_MESSAGE_DIGEST_IMPL_H +#define D_LIBNETTLE_MESSAGE_DIGEST_IMPL_H + +#include "common.h" + +#include + +#include + +#include "SharedHandle.h" + +namespace aria2 { + +class MessageDigestImpl { +private: + const nettle_hash* hashInfo_; + char* ctx_; + + MessageDigestImpl(const nettle_hash* hashInfo); + // We don't implement copy ctor. + MessageDigestImpl(const MessageDigestImpl&); + // We don't implement assignment operator. + MessageDigestImpl& operator==(const MessageDigestImpl&); +public: + ~MessageDigestImpl(); + + static SharedHandle sha1(); + static SharedHandle create(const std::string& hashType); + + static bool supports(const std::string& hashType); + static size_t getDigestLength(const std::string& hashType); + + size_t getDigestLength() const; + void reset(); + void update(const void* data, size_t length); + void digest(unsigned char* md); +}; + +} // namespace aria2 + +#endif // D_LIBNETTLE_MESSAGE_DIGEST_IMPL_H diff --git a/src/Makefile.am b/src/Makefile.am index c3c47b7c..87f5265d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -266,13 +266,28 @@ SRCS += TLSContext.h endif # ENABLE_SSL if HAVE_LIBGNUTLS -SRCS += LibgnutlsTLSContext.cc LibgnutlsTLSContext.h\ - LibgcryptMessageDigestImpl.cc LibgcryptMessageDigestImpl.h\ +SRCS += LibgnutlsTLSContext.cc LibgnutlsTLSContext.h +endif # HAVE_LIBGNUTLS + +if HAVE_LIBGCRYPT +SRCS += LibgcryptMessageDigestImpl.cc LibgcryptMessageDigestImpl.h\ LibgcryptARC4Context.cc LibgcryptARC4Context.h\ LibgcryptARC4Decryptor.cc LibgcryptARC4Decryptor.h\ LibgcryptARC4Encryptor.cc LibgcryptARC4Encryptor.h\ LibgcryptDHKeyExchange.cc LibgcryptDHKeyExchange.h -endif # HAVE_LIBGNUTLS +endif # HAVE_LIBGCRYPT + +if HAVE_LIBNETTLE +SRCS += LibnettleMessageDigestImpl.cc LibnettleMessageDigestImpl.h\ + LibnettleARC4Context.cc LibnettleARC4Context.h\ + LibnettleARC4Decryptor.cc LibnettleARC4Decryptor.h\ + LibnettleARC4Encryptor.cc LibnettleARC4Encryptor.h +endif # HAVE_LIBNETTLE + +if HAVE_LIBGMP +SRCS += a2gmp.cc a2gmp.h\ + LibgmpDHKeyExchange.cc LibgmpDHKeyExchange.h +endif # HAVE_LIBGMP if HAVE_OPENSSL SRCS += LibsslTLSContext.cc LibsslTLSContext.h\ diff --git a/src/MessageDigestImpl.h b/src/MessageDigestImpl.h index 91a901d6..0da4e41f 100644 --- a/src/MessageDigestImpl.h +++ b/src/MessageDigestImpl.h @@ -35,7 +35,9 @@ #ifndef D_MESSAGE_DIGEST_IMPL_H #define D_MESSAGE_DIGEST_IMPL_H -#ifdef HAVE_LIBGCRYPT +#ifdef HAVE_LIBNETTLE +# include "LibnettleMessageDigestImpl.h" +#elif HAVE_LIBGCRYPT # include "LibgcryptMessageDigestImpl.h" #elif HAVE_OPENSSL # include "LibsslMessageDigestImpl.h" diff --git a/src/Platform.cc b/src/Platform.cc index 0e5bc416..ebfe7a6f 100644 --- a/src/Platform.cc +++ b/src/Platform.cc @@ -73,6 +73,9 @@ #include "message.h" #include "fmt.h" #include "console.h" +#ifdef HAVE_LIBGMP +# include "a2gmp.h" +#endif // HAVE_LIBGMP namespace aria2 { @@ -94,7 +97,9 @@ bool Platform::setUp() return false; } initialized_ = true; - +#ifdef HAVE_LIBGMP + global::initGmp(); +#endif // HAVE_LIBGMP #ifdef ENABLE_NLS setlocale (LC_CTYPE, ""); setlocale (LC_MESSAGES, ""); diff --git a/src/a2gmp.cc b/src/a2gmp.cc new file mode 100644 index 00000000..f78bb170 --- /dev/null +++ b/src/a2gmp.cc @@ -0,0 +1,50 @@ +/* */ +#include "a2gmp.h" + +namespace aria2 { + +namespace global { + +gmp_randstate_t gmpRandstate; + +void initGmp() +{ + gmp_randinit_default(gmpRandstate); +} + +} // namespace global + +} // namespace aria2 diff --git a/src/a2gmp.h b/src/a2gmp.h index bd6e9eb6..5ac63ee9 100644 --- a/src/a2gmp.h +++ b/src/a2gmp.h @@ -32,6 +32,9 @@ * files in the program, then also delete it here. */ /* copyright --> */ +#ifndef D_A2GMP_H +#define D_A2GMP_H + #include namespace aria2 { @@ -40,6 +43,10 @@ namespace global { extern gmp_randstate_t gmpRandstate; +void initGmp(); + } // namespace global } // namespace aria2 + +#endif // D_A2GMP_H diff --git a/src/util.cc b/src/util.cc index d24b8dfb..1f9e6d5c 100644 --- a/src/util.cc +++ b/src/util.cc @@ -49,13 +49,7 @@ #include #include -#ifdef HAVE_LIBGCRYPT -# include -#elif HAVE_OPENSSL -# include -# include "SimpleRandomizer.h" -#endif // HAVE_OPENSSL - +#include "SimpleRandomizer.h" #include "File.h" #include "message.h" #include "Randomizer.h" @@ -1396,18 +1390,10 @@ std::map createIndexPathMap(std::istream& i) void generateRandomData(unsigned char* data, size_t length) { -#ifdef HAVE_LIBGCRYPT - gcry_randomize(data, length, GCRY_STRONG_RANDOM); -#elif HAVE_OPENSSL - if(RAND_bytes(data, length) != 1) { - for(size_t i = 0; i < length; ++i) { - data[i] = SimpleRandomizer::getInstance()->getRandomNumber(UINT8_MAX+1); - } + const SharedHandle& rd = SimpleRandomizer::getInstance(); + for(size_t i = 0; i < length; ++i) { + data[i] = static_cast(rd->getRandomNumber(256)); } -#else - std::ifstream i("/dev/urandom", std::ios::binary); - i.read(reinterpret_cast(data), length); -#endif // HAVE_OPENSSL } bool saveAs