diff --git a/.codedocs b/.codedocs new file mode 100644 index 00000000..d29ae47f --- /dev/null +++ b/.codedocs @@ -0,0 +1,331 @@ +# CodeDocs.xyz Configuration File +# Doxyfile 1.8.11 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "The Kovri I2P Router Project" +PROJECT_NUMBER = "@PROJECT_VERSION@" +PROJECT_BRIEF = +PROJECT_LOGO = +OUTPUT_DIRECTORY = "@DOXYFILE_OUTPUT_DIR@" +CREATE_SUBDIRS = NO +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = +TCL_SUBST = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +GROUP_NESTED_COMPOUNDS = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO +SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_AS_ERROR = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = @DOXYFILE_SOURCE_DIRS@ +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c \ + *.cpp \ + *.h \ + *.py \ +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = "sed -e 's/\/\/.*TODO/\/\/\/ \\todo/'" +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = NO +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = YES +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +USE_MATHJAX = NO +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +LATEX_TIMESTAMP = NO +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +RTF_SOURCE_CODE = NO +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +DOCBOOK_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +DIA_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +DOT_NUM_THREADS = 0 +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +MSCFILE_DIRS = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +PLANTUML_INCLUDE_PATH = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/.gitignore b/.gitignore index f50a6df4..8a1263b0 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,9 @@ config.log config.status config.sub +# Monero-specific +github-merge.sh + ################# ## Eclipse ################# diff --git a/.travis.yml b/.travis.yml index 464e990c..2a1065c0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,8 @@ +env: + global: + # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created + # via the "travis encrypt" command using the project repo's public key + #- secure: "Z3IXrEUCV/gada+XZ0mMTnIIlto/rutD3aDKZhrGzwNT19U41bLr75aXmQC5I8FtXW49J3UtxsYa51sb/sqwBdCeCpD8xhXFbW4ekTl+colIE43xv9A0xSU+LU9Cyi9kS5TtAxLii/OhNk2GV0c3mcxQBCkQGeZmu9m46OeOc44hl1Xa7ujlvSbFb9ITiUqYSsj0PQAM7aPhntXTvuDnXbfhqp/MMs/mObVjEDvahUjUxN2TxIBBBnljMX9XKiYEL/UjHe4vamlX0AlB+7sY6sYVLLTp1g5MDxFaPyc3+a6UVGE3dieQOKnGuMDPC2iZfOL29scAJ0BcxI4yFxxZS0Ozb46LMYEUcUHQlX8llLSiA9ELtVxwUrLCtsXxDz/lzgzxx6eomOzHnOvymi5oo/pY3QpGuoPq+ikgpUKxXyN89ppH0d7tuemCcGdAwv32UGyPL2Kus08bRU12+bF3dEroCmkQ/aYpF9wL9ZTES7pUQBZPnuVsT6v0bSJd3iQiopUIgPNjPlmOaGaLtue+KExj5cu/pynjtFGTGGD21hKLxO8yXOTFmhxytuPb4jjEPddng5h7FKqcUJShqCPpOqoA6zOvp2U/D5btaySb/WfyghGVO/BuIoIdKkwIHClPV7e4Q7s8eWIfYk9R93MdQCmcoCziPgc5UrZ4ZoJ9rss=" sudo: required dist: trusty language: cpp @@ -14,7 +19,14 @@ addons: - libssl1.0.0 - libminiupnpc-dev - doxygen -script: cd build && cmake -DWITH_TESTS=ON -DWITH_BENCHMARKS=ON -DWITH_UPNP=ON -DWITH_DOXYGEN=ON ../ && make doc && make +coverity_scan: + project: + name: "monero-project/kovri" + description: "The Kovri I2P Router Project" + notification_email: anonimal@i2pmail.org + build_command: "cd build && cmake -DWITH_TESTS=ON -DWITH_BENCHMARKS=ON -DWITH_UPNP=ON -DWITH_DOXYGEN=ON ../ && make" + branch_pattern: coverity_scan +script: if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then cd build && cmake -DWITH_TESTS=ON -DWITH_BENCHMARKS=ON -DWITH_UPNP=ON -DWITH_DOXYGEN=ON ../ && make doc && make ; fi notifications: email: false irc: diff --git a/CMakeLists.txt b/CMakeLists.txt index f82e8c3c..b6d70da0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,6 @@ option(KOVRI_DATA_PATH "The path to the kovri data folder") option(WITH_AESNI "Use AES-NI instructions set" OFF) option(WITH_BENCHMARKS "Build with benchmarks" OFF) option(WITH_BINARY "Build binary" ON) -option(WITH_BOOST_LOG "Use Boost.Log for logging" ON) option(WITH_DOXYGEN "Enable support for Doxygen" OFF) option(WITH_HARDENING "Use hardening compiler flags" OFF) option(WITH_LIBRARY "Build library" ON) @@ -110,41 +109,28 @@ if(WITH_STATIC) set(CMAKE_THREAD_LIBS_INIT "gcc_eh -Wl,-u,pthread_create,-u,pthread_once,-u,pthread_mutex_lock,-u,pthread_mutex_unlock,-u,pthread_join,-u,pthread_equal,-u,pthread_detach,-u,pthread_cond_wait,-u,pthread_cond_signal,-u,pthread_cond_destroy,-u,pthread_cond_broadcast,-u,pthread_cancel") endif() -elseif(NOT WIN32) +endif() + +if(NOT WIN32) # TODO: Consider separate compilation for COMMON_SRC for library. # No need in -fPIC overhead for binary if not interested in library # HINT: revert c266cff CMakeLists.txt: compilation speed up set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") -else() # Not a static build - add_definitions(-DBOOST_ALL_DYN_LINK) - add_definitions(-DBOOST_LOG_DYN_LINK) endif() - -if(WITH_BOOST_LOG) - find_package( - Boost COMPONENTS + +find_package( + Boost + COMPONENTS chrono log - program_options date_time thread - system filesystem regex - REQUIRED) - if(NOT WITH_STATIC) - add_definitions(-DBOOST_ALL_DYN_LINK) - add_definitions(-DBOOST_LOG_DYN_LINK) - endif() -else() - find_package( - Boost COMPONENTS - system filesystem regex program_options date_time - thread chrono - REQUIRED) - if(NOT WITH_STATIC) - add_definitions(-DBOOST_ALL_DYN_LINK) - endif() -endif() + thread system + filesystem regex + REQUIRED) -if(NOT DEFINED Boost_INCLUDE_DIRS) +if(NOT Boost_FOUND) message(SEND_ERROR "Boost not found, or version below 1.46. Please download Boost!") +else() + add_definitions(-DBOOST_ALL_DYN_LINK) endif() find_package(CryptoPP REQUIRED) @@ -195,7 +181,6 @@ message(STATUS "Options:") message(STATUS " AESNI : ${WITH_AESNI}") message(STATUS " BENCHMARKS : ${WITH_BENCHMARKS}") message(STATUS " BINARY : ${WITH_BINARY}") -message(STATUS " BOOST LOG : ${WITH_BOOST_LOG}") message(STATUS " DOXYGEN : ${WITH_DOXYGEN}") message(STATUS " HARDENING : ${WITH_HARDENING}") message(STATUS " LIBRARY : ${WITH_LIBRARY}") diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ad95b14a..d0fa9eb3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,13 +8,52 @@ Join us in ```#kovri-dev``` on Irc2P or Freenode; we'll be happy to say hi! ## Style We ardently adhere to (or are in the process of adhering to) [Google's C++ Style Guide](https://google.github.io/styleguide/cppguide.html). - Please run [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint) on any applicable work before contributing to Kovri. In addition to the aforementioned, please consider the following: -- If function args newline break, ensure that *every* indent is 4 spaces (and not 2). +- Please keep in line with codebase's present style for consistency. +- Why a vertical style? It's easy to code things fast but doing things slower tends to reduce human error (slows the eye down + easier to count and compare datatypes + easier to maintain). +- But why this specific style? Anonymity. Doing things here that wouldn't be done elsewhere helps reduce the chance of programmer correlation. This allows any contributor to *blend-in* as long as they adhere to specifics. +- Lines should be <=80 spaces unless impossible to do so (see [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint)). +- ```XXX``` and any unassigned ```TODO```'s should be marked instead as ```TODO(unassigned):``` so Doxygen can catch them. +- Always use ```// C++ comments``` unless they span more than 10 lines (give or take). When that happens, a traditional +```c + /** + * should suffice + */ +``` +- Extensive code that *does* something (more than simply return or more than a hand-ful of lines) should go in a .cpp instead of .h unless it is absolutely necessary to fulfill some abstraction layer. +- ``if/else`` statements should never one-liner. Nothing bracketed should one-liner unless it is empty (see vertical theory above). +- Please remove EOL whitespace: ```'s/ *$//g'``` (see [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint)). +- New files should maintain consistency with other filename case, e.g., CryptoPP_rand.h instead of cryptopp_rand.h +- English punctuation will help clarify questions about the comments. For example: +```cpp +// key file does not exist, let's say it's new +// after we fall out of scope of the open file for the keys we'll add it +createTunnel = true; +``` +So, is it "let's say it's new after we fall out of scope" or a completely different thought? +The code that is commented on isn't a dead give-away and requires the reader to expend more time analyzing. A simple english consideration could help with review. +- Pointers: reference/dereference operators on the left (attached to datatype) when possible. +- Class member variables are prepended with m_ +- Enumerators are prepended with e_ +- Abstain from datatype declaration redundancy (e.g., use commas instead of repeating the datatype). +```cpp +uint32_t tunnelID, + nextTunnelID; + +uint8_t layerKey[32], + ivKey[32], + replyKey[32], + replyIV[16], + randPad[29]; + +bool isGateway, + isEndpoint; +``` +- If function args newline break, ensure that *every* indent is 4 spaces (and not 2). ```cpp if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) { // So, we send it to reply tunnel @@ -42,35 +81,16 @@ if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) { } ``` -- Pointers: reference/dereference operators on the left (attached to datatype) when possible. -- Abstain from datatype declaration redundancy (e.g., use commas instead of repeating the datatype). - -```cpp -uint32_t tunnelID, - nextTunnelID; - -uint8_t layerKey[32], - ivKey[32], - replyKey[32], - replyIV[16], - randPad[29]; - -bool isGateway, - isEndpoint; -``` - -- Class member variables are prepended with m_ -- Enumerators are prepended with e_ - ## TODO's -Do a quick search in the codebase for TODO(unassigned) and/or pick a ticket and start patching! +- Do a quick search in the codebase for ```TODO(unassigned):``` and/or pick a ticket and start patching! +- If you create a TODO, assign it to yourself or write in ```TODO(unassigned):``` ## Workflow To contribute a patch, consider the following: - Fork Kovri - Create a topic branch -- Commit your feature(s)/patch(es) +- Commit and [**sign**](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work) your feature(s)/patch(es) - Pull request to branch ```development``` In general, commits should be [atomic](https://en.wikipedia.org/wiki/Atomic_commit#Atomic_commit_convention) and diffs should be easy to read. For this reason, please try to not mix formatting fixes with non-formatting commits. diff --git a/README.md b/README.md index 7d558470..6e086e00 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ 2. The secure, private, untraceable C++ [I2P router](https://geti2p.net), forked from [i2pd](https://github.com/PurpleI2P/i2pd/tree/master). [![Build Status](https://travis-ci.org/monero-project/kovri.svg?branch=master)](https://travis-ci.org/monero-project/kovri) +[![Documentation](https://codedocs.xyz/monero-project/kovri.svg)](https://codedocs.xyz/monero-project/kovri/) ## Disclaimer - Currently pre-alpha software; under heavy overhaul and development! Stick to branch ```master``` for stability. diff --git a/src/api/Datagram.cpp b/src/api/Datagram.cpp index dcdb28a9..e4da501b 100644 --- a/src/api/Datagram.cpp +++ b/src/api/Datagram.cpp @@ -39,6 +39,7 @@ #include "RouterContext.h" #include "client/Destination.h" +#include "core/crypto/Rand.h" #include "tunnel/TunnelBase.h" #include "util/Log.h" @@ -103,8 +104,7 @@ void DatagramDestination::SendMsg( auto leases = remote->GetNonExpiredLeases(); if (!leases.empty() && outboundTunnel) { std::vector msgs; - uint32_t i = i2p::context.GetRandomNumberGenerator() - .GenerateWord32(0, leases.size() - 1); + uint32_t i = i2p::crypto::RandInRange(0, leases.size() - 1); auto garlic = m_Owner.WrapMessage(remote, ToSharedI2NPMessage(msg), true); msgs.push_back( i2p::tunnel::TunnelMessageBlock { diff --git a/src/api/I2PControl/I2PControlServer.cpp b/src/api/I2PControl/I2PControlServer.cpp index 981f8a3e..128b6490 100644 --- a/src/api/I2PControl/I2PControlServer.cpp +++ b/src/api/I2PControl/I2PControlServer.cpp @@ -46,21 +46,22 @@ namespace client { namespace i2pcontrol { I2PControlService::I2PControlService( + boost::asio::io_service& service, const std::string& address, int port, const std::string& password) : m_Session( std::make_shared( - m_Service, + service, password)), m_IsRunning(false), m_Thread(nullptr), + m_Service(service), m_Acceptor( - m_Service, - boost::asio::ip::tcp::endpoint( - boost::asio::ip::address::from_string( - address), - port)) {} + service, boost::asio::ip::tcp::endpoint( + boost::asio::ip::address::from_string( + address), + port)) {} I2PControlService::~I2PControlService() { Stop(); } @@ -83,7 +84,6 @@ void I2PControlService::Stop() { m_Session->Stop(); // Release ownership before the io_service is stopped and destroyed m_Session.reset(); - m_Service.stop(); if (m_Thread) { m_Thread->join(); delete m_Thread; @@ -122,7 +122,7 @@ void I2PControlService::HandleAccept( Accept(); if (!ecode) { LogPrint(eLogInfo, - "New I2PControl request from ", socket->remote_endpoint()); + "New I2PControl request from ", socket->remote_endpoint()); std::this_thread::sleep_for(std::chrono::milliseconds(5)); ReadRequest(socket); } else { diff --git a/src/api/I2PControl/I2PControlServer.h b/src/api/I2PControl/I2PControlServer.h index 565cfbb2..3f672e31 100644 --- a/src/api/I2PControl/I2PControlServer.h +++ b/src/api/I2PControl/I2PControlServer.h @@ -53,6 +53,7 @@ typedef std::array I2PControlBuffer; class I2PControlService { public: I2PControlService( + boost::asio::io_service& service, const std::string& address, int port, const std::string& password); @@ -96,7 +97,7 @@ class I2PControlService { bool m_IsRunning; std::thread* m_Thread; - boost::asio::io_service m_Service; + boost::asio::io_service& m_Service; boost::asio::ip::tcp::acceptor m_Acceptor; }; diff --git a/src/api/I2PTunnel/HTTPProxy.cpp b/src/api/I2PTunnel/HTTPProxy.cpp index bf1e5f8c..bae138a7 100644 --- a/src/api/I2PTunnel/HTTPProxy.cpp +++ b/src/api/I2PTunnel/HTTPProxy.cpp @@ -94,11 +94,11 @@ class HTTPProxyHandler uint8_t m_http_buff[HTTP_BUFFER_SIZE]; std::shared_ptr m_sock; std::string m_request, // Data left to be sent - m_url, // URL - m_method, // Method - m_version, // HTTP version - m_address, // Address - m_path; // Path + m_url, // URL + m_method, // Method + m_version, // HTTP version + m_address, // Address + m_path; // Path int m_port; // Port state m_state; // Parsing state @@ -379,15 +379,17 @@ void HTTPProxyHandler::HandleStreamRequestComplete( } HTTPProxyServer::HTTPProxyServer( + const std::string& name, const std::string& address, int port, std::shared_ptr localDestination) : TCPIPAcceptor( - address, - port, - localDestination ? - localDestination : - i2p::client::context.GetSharedLocalDestination()) {} + address, + port, + localDestination ? + localDestination : + i2p::client::context.GetSharedLocalDestination()), + m_Name(name) {} std::shared_ptr HTTPProxyServer::CreateHandler( std::shared_ptr socket) { diff --git a/src/api/I2PTunnel/HTTPProxy.h b/src/api/I2PTunnel/HTTPProxy.h index 90061718..49749f18 100644 --- a/src/api/I2PTunnel/HTTPProxy.h +++ b/src/api/I2PTunnel/HTTPProxy.h @@ -47,6 +47,7 @@ class HTTPProxyServer : public i2p::client::TCPIPAcceptor { public: HTTPProxyServer( + const std::string& name, const std::string& address, int port, std::shared_ptr localDestination = nullptr); @@ -56,7 +57,13 @@ class HTTPProxyServer // Implements TCPIPAcceptor std::shared_ptr CreateHandler( std::shared_ptr socket); - const char* GetName() { return "HTTP Proxy"; } + + std::string GetName() const { + return m_Name; + } + + private: + std::string m_Name; }; typedef HTTPProxyServer HTTPProxy; diff --git a/src/api/I2PTunnel/I2PTunnel.cpp b/src/api/I2PTunnel/I2PTunnel.cpp index bfb459b9..8eec1c07 100644 --- a/src/api/I2PTunnel/I2PTunnel.cpp +++ b/src/api/I2PTunnel/I2PTunnel.cpp @@ -163,13 +163,13 @@ void I2PTunnelConnection::StreamReceive() { if (m_Stream) m_Stream->AsyncReceive( boost::asio::buffer( - m_StreamBuffer, - I2P_TUNNEL_CONNECTION_BUFFER_SIZE), + m_StreamBuffer, + I2P_TUNNEL_CONNECTION_BUFFER_SIZE), std::bind( - &I2PTunnelConnection::HandleStreamReceive, - shared_from_this(), - std::placeholders::_1, - std::placeholders::_2), + &I2PTunnelConnection::HandleStreamReceive, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2), I2P_TUNNEL_CONNECTION_MAX_IDLE); } @@ -189,11 +189,13 @@ void I2PTunnelConnection::Write( const uint8_t* buf, size_t len) { m_Socket->async_send( - boost::asio::buffer(buf, len), + boost::asio::buffer( + buf, + len), std::bind( - &I2PTunnelConnection::HandleWrite, - shared_from_this(), - std::placeholders::_1)); + &I2PTunnelConnection::HandleWrite, + shared_from_this(), + std::placeholders::_1)); } void I2PTunnelConnection::HandleConnect( @@ -228,10 +230,10 @@ I2PTunnelConnectionHTTP::I2PTunnelConnectionHTTP( const boost::asio::ip::tcp::endpoint& target, const std::string& host) : I2PTunnelConnection( - owner, - stream, - socket, - target), + owner, + stream, + socket, + target), m_Host(host), m_HeaderSent(false) {} @@ -280,9 +282,9 @@ class I2PClientTunnelHandler int destinationPort, std::shared_ptr socket) : I2PServiceHandler(parent), - m_DestinationIdentHash(destination), - m_DestinationPort(destinationPort), - m_Socket(socket) {} + m_DestinationIdentHash(destination), + m_DestinationPort(destinationPort), + m_Socket(socket) {} void Handle(); void Terminate(); @@ -296,9 +298,9 @@ class I2PClientTunnelHandler void I2PClientTunnelHandler::Handle() { GetOwner()->GetLocalDestination()->CreateStream( std::bind( - &I2PClientTunnelHandler::HandleStreamRequestComplete, - shared_from_this(), - std::placeholders::_1), + &I2PClientTunnelHandler::HandleStreamRequestComplete, + shared_from_this(), + std::placeholders::_1), m_DestinationIdentHash, m_DestinationPort); } @@ -336,15 +338,17 @@ void I2PClientTunnelHandler::Terminate() { } I2PClientTunnel::I2PClientTunnel( + const std::string& name, const std::string& destination, const std::string& address, int port, std::shared_ptr localDestination, int destinationPort) : TCPIPAcceptor( - address, - port, - localDestination), + address, + port, + localDestination), + m_TunnelName(name), m_Destination(destination), m_DestinationIdentHash(nullptr), m_DestinationPort(destinationPort) {} @@ -374,6 +378,10 @@ const i2p::data::IdentHash* I2PClientTunnel::GetIdentHash() { return m_DestinationIdentHash; } +std::string I2PClientTunnel::GetName() { + return m_TunnelName; +} + std::shared_ptr I2PClientTunnel::CreateHandler( std::shared_ptr socket) { const i2p::data::IdentHash *identHash = GetIdentHash(); @@ -388,20 +396,30 @@ std::shared_ptr I2PClientTunnel::CreateHandler( } I2PServerTunnel::I2PServerTunnel( + const std::string& name, const std::string& address, int port, std::shared_ptr localDestination, int inport) : I2PService(localDestination), m_Address(address), + m_TunnelName(name), m_Port(port), m_IsAccessList(false) { m_PortDestination = localDestination->CreateStreamingDestination( - inport > 0 ? inport : port); + inport > 0 ? inport : port); } void I2PServerTunnel::Start() { + // TODO(unassigned): we don't resolve the dns entry each time we connect so + // we'd have to SIGHUP every time the entry changes + // OR, we could resolve each time + // BUT that would mean lots of dns queries + // HOWEVER if when we SIGHUP something changes we SHOULD NOT throw away + // the destination because that will discard the tunnel encryption keys which + // causes interruption. + // TODO(psi): implement a strategy for caching and looking up hostname ip addresses m_Endpoint.port(m_Port); boost::system::error_code ec; auto addr = @@ -417,14 +435,15 @@ void I2PServerTunnel::Start() { GetService()); resolver->async_resolve( boost::asio::ip::tcp::resolver::query( - m_Address, - ""), + m_Address, + ""), std::bind( - &I2PServerTunnel::HandleResolve, - this, - std::placeholders::_1, - std::placeholders::_2, - resolver)); + &I2PServerTunnel::HandleResolve, + this, + std::placeholders::_1, + std::placeholders::_2, + resolver, + true)); } } @@ -435,19 +454,69 @@ void I2PServerTunnel::Stop() { void I2PServerTunnel::HandleResolve( const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, - std::shared_ptr) { + std::shared_ptr, + bool acceptAfter) { if (!ecode) { auto addr = (*it).endpoint().address(); LogPrint(eLogInfo, "server tunnel ", (*it).host_name(), " has been resolved to ", addr); m_Endpoint.address(addr); - Accept(); + if (acceptAfter) { + Accept(); + } } else { LogPrint(eLogError, "Unable to resolve server tunnel address: ", ecode.message()); } } + +void I2PServerTunnel::UpdateAddress( + const std::string& addr) { + m_Address = addr; + boost::system::error_code ec; + auto a = + boost::asio::ip::address::from_string( + m_Address, + ec); + if (!ec) { + m_Endpoint.address(a); + } else { + auto resolver = + std::make_shared( + GetService()); + resolver->async_resolve( + boost::asio::ip::tcp::resolver::query( + m_Address, + ""), + std::bind( + &I2PServerTunnel::HandleResolve, + this, + std::placeholders::_1, + std::placeholders::_2, + resolver, + false)); + } +} + +void I2PServerTunnel::UpdatePort( + int port) { + if (port < 0) { + throw std::logic_error("I2P server tunnel < 0"); + } + m_Port = port; +} + +void I2PServerTunnel::UpdateStreamingPort( + int port) const { + if (port > 0) { + uint16_t localPort = port; + m_PortDestination->UpdateLocalPort(localPort); + } else { + throw std::logic_error("Streaming port cannot be negative"); + } +} + void I2PServerTunnel::SetAccessList( const std::set& accessList) { m_AccessList = accessList; @@ -504,16 +573,22 @@ void I2PServerTunnel::CreateI2PConnection( conn->Connect(); } +std::string I2PServerTunnel::GetName() { + return m_TunnelName; +} + I2PServerTunnelHTTP::I2PServerTunnelHTTP( + const std::string& name, const std::string& address, int port, std::shared_ptr localDestination, int inport) : I2PServerTunnel( - address, - port, - localDestination, - inport) {} + name, + address, + port, + localDestination, + inport) {} void I2PServerTunnelHTTP::CreateI2PConnection( std::shared_ptr stream) { @@ -528,6 +603,26 @@ void I2PServerTunnelHTTP::CreateI2PConnection( AddHandler(conn); conn->Connect(); } +void I2PServerTunnel::SetAccessListString( + const std::string& idents_str) { + std::set idents; + if (idents_str.length() > 0) { + size_t pos = 0, comma; + do { + comma = idents_str.find(',', pos); + i2p::data::IdentHash ident; + ident.FromBase32( + idents_str.substr( + pos, + comma != std::string::npos ? + comma - pos : + std::string::npos)); + idents.insert(ident); + pos = comma + 1; + } while (comma != std::string::npos); + } + SetAccessList(idents); +} } // namespace client } // namespace i2p diff --git a/src/api/I2PTunnel/I2PTunnel.h b/src/api/I2PTunnel/I2PTunnel.h index 0dee423a..d18d6265 100644 --- a/src/api/I2PTunnel/I2PTunnel.h +++ b/src/api/I2PTunnel/I2PTunnel.h @@ -141,10 +141,10 @@ class I2PClientTunnel : public TCPIPAcceptor { // Implements TCPIPAcceptor std::shared_ptr CreateHandler( std::shared_ptr socket); - const char* GetName() { return "I2P Client Tunnel"; } public: I2PClientTunnel( + const std::string& name, const std::string& destination, const std::string& address, int port, @@ -155,10 +155,11 @@ class I2PClientTunnel : public TCPIPAcceptor { void Start(); void Stop(); + std::string GetName(); private: const i2p::data::IdentHash* GetIdentHash(); - + std::string m_TunnelName; std::string m_Destination; const i2p::data::IdentHash* m_DestinationIdentHash; int m_DestinationPort; @@ -167,6 +168,7 @@ class I2PClientTunnel : public TCPIPAcceptor { class I2PServerTunnel : public I2PService { public: I2PServerTunnel( + const std::string& name, const std::string& address, int port, std::shared_ptr localDestination, @@ -179,23 +181,42 @@ class I2PServerTunnel : public I2PService { void SetAccessList( const std::set& accessList); - const std::string& GetAddress() const { + // set access list given csv + void SetAccessListString( + const std::string& idents_str); + + std::string GetAddress() const { return m_Address; } + // update the address of this server tunnel + void UpdateAddress( + const std::string& addr); + int GetPort() const { return m_Port; } + // update the out port of this server tunnel + void UpdatePort( + int port); + + // update the streaming destination's port + void UpdateStreamingPort( + int port) const; + const boost::asio::ip::tcp::endpoint& GetEndpoint() const { return m_Endpoint; } + std::string GetName(); + private: void HandleResolve( const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, - std::shared_ptr resolver); + std::shared_ptr resolver, + bool acceptAfter = true); void Accept(); @@ -207,6 +228,7 @@ class I2PServerTunnel : public I2PService { private: std::string m_Address; + std::string m_TunnelName; int m_Port; boost::asio::ip::tcp::endpoint m_Endpoint; std::shared_ptr m_PortDestination; @@ -217,6 +239,7 @@ class I2PServerTunnel : public I2PService { class I2PServerTunnelHTTP: public I2PServerTunnel { public: I2PServerTunnelHTTP( + const std::string& name, const std::string& address, int port, std::shared_ptr localDestination, diff --git a/src/api/I2PTunnel/SOCKS.h b/src/api/I2PTunnel/SOCKS.h index b0fbbab5..0f4d07bc 100644 --- a/src/api/I2PTunnel/SOCKS.h +++ b/src/api/I2PTunnel/SOCKS.h @@ -43,8 +43,7 @@ namespace i2p { namespace proxy { -class SOCKSServer - : public i2p::client::TCPIPAcceptor { +class SOCKSServer : public i2p::client::TCPIPAcceptor { public: SOCKSServer( const std::string& address, @@ -56,7 +55,10 @@ class SOCKSServer // Implements TCPIPAcceptor std::shared_ptr CreateHandler( std::shared_ptr socket); - const char* GetName() { return "SOCKS"; } + + std::string GetName() const { + return "SOCKS"; + } }; typedef SOCKSServer SOCKSProxy; diff --git a/src/api/Streaming.cpp b/src/api/Streaming.cpp index bc5150fd..af64d9fc 100644 --- a/src/api/Streaming.cpp +++ b/src/api/Streaming.cpp @@ -37,6 +37,7 @@ #include "RouterInfo.h" #include "Streaming.h" #include "client/Destination.h" +#include "crypto/Rand.h" #include "tunnel/Tunnel.h" #include "util/Log.h" #include "util/Timestamp.h" @@ -68,8 +69,7 @@ Stream::Stream( m_RTO(INITIAL_RTO), m_LastWindowSizeIncreaseTime(0), m_NumResendAttempts(0) { - m_RecvStreamID = - i2p::context.GetRandomNumberGenerator().GenerateWord32(); + m_RecvStreamID = i2p::crypto::Rand(); m_RemoteIdentity = remote->GetIdentity(); m_CurrentRemoteLease.endDate = 0; } @@ -95,8 +95,7 @@ Stream::Stream( m_RTO(INITIAL_RTO), m_LastWindowSizeIncreaseTime(0), m_NumResendAttempts(0) { - m_RecvStreamID = - i2p::context.GetRandomNumberGenerator().GenerateWord32(); + m_RecvStreamID = i2p::crypto::Rand(); } Stream::~Stream() { @@ -792,7 +791,7 @@ void Stream::UpdateCurrentRemoteLease( } if (!updated) { uint32_t i = - i2p::context.GetRandomNumberGenerator().GenerateWord32( + i2p::crypto::RandInRange( 0, leases.size() - 1); if (m_CurrentRemoteLease.endDate && leases[i].tunnelID == m_CurrentRemoteLease.tunnelID) diff --git a/src/api/Streaming.h b/src/api/Streaming.h index 3ba37126..a81038b8 100644 --- a/src/api/Streaming.h +++ b/src/api/Streaming.h @@ -384,6 +384,11 @@ class StreamingDestination { return m_LocalPort; } + void UpdateLocalPort( + uint16_t port) { + m_LocalPort = port; + } + void HandleDataMessagePayload( const uint8_t* buf, size_t len); diff --git a/src/client/ClientContext.cpp b/src/client/ClientContext.cpp index 12fa87ed..4f9061a3 100644 --- a/src/client/ClientContext.cpp +++ b/src/client/ClientContext.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "Identity.h" #include "util/Log.h" @@ -57,6 +58,7 @@ ClientContext::~ClientContext() { delete m_HttpProxy; delete m_SocksProxy; delete m_I2PControlService; + m_Service.stop(); } void ClientContext::Start() { @@ -74,6 +76,7 @@ void ClientContext::Start() { if (proxyKeys.length() > 0) localDestination = LoadLocalDestination(proxyKeys, false); m_HttpProxy = new i2p::proxy::HTTPProxy( + "HTTP Proxy", // TODO(unassigned): what if we want to change the name? i2p::util::config::varMap["httpproxyaddress"].as(), i2p::util::config::varMap["httpproxyport"].as(), localDestination); @@ -99,6 +102,7 @@ void ClientContext::Start() { localDestination = LoadLocalDestination(ircKeys, false); auto ircPort = i2p::util::config::varMap["ircport"].as(); auto ircTunnel = new I2PClientTunnel( + "IRC", // TODO(unassigned): what happens if we name a tunnel "IRC"? ircDestination, i2p::util::config::varMap["ircaddress"].as(), ircPort, @@ -118,6 +122,7 @@ void ClientContext::Start() { if (eepKeys.length() > 0) { // eepkeys are available localDestination = LoadLocalDestination(eepKeys, true); auto serverTunnel = new I2PServerTunnel( + "eepsite", // TODO(unassigned): what if have a tunnel called "eepsite"? i2p::util::config::varMap["eepaddress"].as(), i2p::util::config::varMap["eepport"].as(), localDestination); serverTunnel->Start(); @@ -135,6 +140,7 @@ void ClientContext::Start() { LogPrint("Starting I2PControlService ..."); m_I2PControlService = new i2pcontrol::I2PControlService( + m_Service, i2p::util::config::varMap["i2pcontroladdress"].as(), i2pcontrolPort, i2p::util::config::varMap["i2pcontrolpassword"].as()); @@ -286,6 +292,333 @@ std::shared_ptr ClientContext::FindLocalDestination( return nullptr; } +void ClientContext::ReloadTunnels() { + boost::property_tree::ptree pt; + std::string tunnelsConfigFile = + i2p::util::filesystem::GetTunnelsConfigFile().string(); + try { + boost::property_tree::read_ini(tunnelsConfigFile, pt); + } catch (const std::exception& ex) { + LogPrint(eLogWarning, "Can't read ", tunnelsConfigFile, + ": ", ex.what()); + return; + } + // existing tunnel names + std::vector existingTunnels; + // collect existing tunnels + { + // lock mutex while we collect the tunnels + std::lock_guard clock(m_ServerMutex); + std::lock_guard slock(m_ClientMutex); + for ( auto & item : m_ServerTunnels ) { + existingTunnels.push_back(item.second->GetName()); + } + for ( auto & item : m_ClientTunnels ) { + existingTunnels.push_back(item.second->GetName()); + } + } + // a list of tunnels that exist after config update + std::vector updatedTunnels; + // iterate over tunnels' ident hashes for what's in tunnels.cfg now + for (auto& section : pt) { + // TODO(unassigned): what if we switch a server from client to tunnel + // or vice versa? + bool createTunnel = false; + std::string tunnelName = section.first; + updatedTunnels.push_back(tunnelName); + std::string type = + section.second.get( + I2P_TUNNELS_SECTION_TYPE, + ""); + if (type == I2P_TUNNELS_SECTION_TYPE_SERVER || + type == I2P_TUNNELS_SECTION_TYPE_HTTP) { + // obtain server options + std::string keyfile = + section.second.get( + I2P_SERVER_TUNNEL_KEYS, + ""); + std::string keysFullPath = + i2p::util::filesystem::GetFullPath(keyfile); + std::string hostStr = + section.second.get( + I2P_SERVER_TUNNEL_HOST, + ""); + int port = + section.second.get( + I2P_SERVER_TUNNEL_PORT, + 0); + int inPort = + section.second.get( + I2P_SERVER_TUNNEL_INPORT, + 0); + std::string accessList = + section.second.get( + I2P_SERVER_TUNNEL_ACCESS_LIST, + ""); + { + i2p::data::PrivateKeys keys; + // get keyfile + std::ifstream s(keysFullPath.c_str(), std::ifstream::binary); + if (s.is_open()) { // keyfile exists already + // read private keys + s.seekg(0, std::ios::end); + size_t len = s.tellg(); + s.seekg(0, std::ios::beg); + uint8_t* buf = new uint8_t[len]; + s.read(reinterpret_cast(buf), len); + keys.FromBuffer(buf, len); + delete[] buf; + // get key's ident hash + i2p::data::IdentHash i = keys.GetPublic().GetIdentHash(); + // check if it exists in existing local servers + auto itrEnd = existingTunnels.end(); + auto itr = std::find(existingTunnels.begin(), itrEnd, tunnelName); + if (itr == itrEnd) { + // the server with this name exists locally + // we'll load it outside after we close the private key file when + // we fall out if the scope it's in + createTunnel = true; + } else { + // the server with this name is already locally running + // let's update the settings of it + // first we lock the server tunnels mutex + std::lock_guard lock(m_ServerMutex); + // update out port for this server tunnel + m_ServerTunnels[i]->UpdatePort(port); + // update host for this server tunnel + m_ServerTunnels[i]->UpdateAddress(hostStr); + // update in port for this server tunnel + m_ServerTunnels[i]->UpdateStreamingPort(inPort); + // update access list + m_ServerTunnels[i]->SetAccessListString(accessList); + // we don't want to stop existing connections on this tunnel so + // we DON'T call Stop() as it will call ClearHandlers() + // this updates the server tunnel stuff, + // it should really be called Apply() but whatever + m_ServerTunnels[i]->Start(); // apply changes + } + } else { + // key file does not exist, let's say it's new + // after we fall out of scope of the open file for the keys, + // we'll add it + createTunnel = true; + } + } + if (createTunnel) { + // we're going to create a new server tunnel + // load the destination + auto localDestination = LoadLocalDestination(keysFullPath, true); + I2PServerTunnel* serverTunnel = + (type == I2P_TUNNELS_SECTION_TYPE_HTTP) ? + new I2PServerTunnelHTTP( + tunnelName, + hostStr, + port, + localDestination, + inPort) : + new I2PServerTunnel( + tunnelName, + hostStr, + port, + localDestination, + inPort); + serverTunnel->SetAccessListString(accessList); + // add the server tunnel + { + // lock access to server tunnels + std::lock_guard lock(m_ServerMutex); + auto i = localDestination->GetIdentHash(); + if (m_ServerTunnels.insert( + std::make_pair( + i, + std::unique_ptr(serverTunnel))).second) { + // we added it + serverTunnel->Start(); + } else { + // wtf ? it's already there? + LogPrint(eLogError, + "WTF! NEW I2P Server Tunnel for destination ", + m_AddressBook.ToAddress(i), " exists?!"); + } + } + } + } else if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT) { + // get client tunnel parameters + std::string keyfile = + section.second.get( + I2P_CLIENT_TUNNEL_KEYS, + ""); + std::string keysFullPath = + i2p::util::filesystem::GetFullPath(keyfile); + std::string destination = + section.second.get( + I2P_CLIENT_TUNNEL_DESTINATION, + ""); + std::string hostStr = + section.second.get( + I2P_CLIENT_TUNNEL_ADDRESS, + "127.0.0.1"); + int port = + section.second.get( + I2P_CLIENT_TUNNEL_PORT, + 0); + int destPort = + section.second.get( + I2P_CLIENT_TUNNEL_DESTINATION_PORT, + 0); + { + auto itrEnd = existingTunnels.end(); + auto itr = std::find(existingTunnels.begin(), itrEnd, tunnelName); + createTunnel = itr == itrEnd; + } + // check if we have a conflicting port + { + // first we lock the client tunnels mutex + std::lock_guard lock(m_ClientMutex); + // check if we have someone with this port + auto itr = m_ClientTunnels.find(port); + if (itr != m_ClientTunnels.end() && + itr->second->GetName() != tunnelName) { + // conflicting port + // TODO(unassigned): what if we interchange two client tunnels' ports? + LogPrint(eLogError, + tunnelName, " will not be updated, Conflicting Port"); + continue; + } + } + // we're going to create a new client tunnel + if (createTunnel) { + // load the destination + auto localDestination = LoadLocalDestination(keysFullPath, true); + try { + I2PClientTunnel* clientTunnel = + new I2PClientTunnel( + tunnelName, + destination, + hostStr, + port, + localDestination, + destPort); + // add the client tunnel + { + // lock access to server tunnels + std::lock_guard lock(m_ClientMutex); + auto i = localDestination->GetIdentHash(); + if (m_ClientTunnels.insert( + std::make_pair( + port, + std::unique_ptr(clientTunnel))).second) { + // we added it + clientTunnel->Start(); + } else { + // wtf ? it's already there? + LogPrint(eLogError, + "WTF! NEW I2P Client Tunnel for destination ", + m_AddressBook.ToAddress(i), " exists?!"); + } + } + } catch (std::exception& err) { + // error happened while making new tunnel + LogPrint(eLogError, "failed to create new tunnel: ", err.what()); + continue; + } + } else { + // the client with this name is already locally running + // let's update the settings of it + // first we lock the client tunnels mutex + std::lock_guard lock(m_ClientMutex); + // get the tunnel given the name + auto itr = std::find_if( + m_ClientTunnels.begin(), + m_ClientTunnels.end(), + [&tunnelName](ClientTunnelEntry & e) -> bool { + return e.second->GetName() == tunnelName; + }); + // TODO(unassigned): we MUST have a tunnel given this tunnelName RIGHT!? + auto & tun = itr->second; + // check what we need to rebind if anything + auto currentEndpoint = tun->GetEndpoint(); + std::string currentAddr = tun->GetAddress(); + boost::system::error_code ec; + auto nextAddr = boost::asio::ip::address::from_string(hostStr, ec); + if (ec) { + // the next address is not an ip address + if (hostStr != currentAddr) { + // the new address is different + // let's rebind + try { + tun->Rebind(hostStr, port); + } catch (std::exception& err) { + LogPrint(eLogError, + "failed to rebind ", tunnelName, ": ", err.what()); + } + } + } else { + // the next address is an ip address + boost::asio::ip::tcp::endpoint nextEndpoint(nextAddr, port); + if ( currentEndpoint != nextEndpoint ) { + // the endpoints differ + // let's rebind + try { + tun->Rebind(hostStr, port); + } catch (std::exception& err) { + LogPrint(eLogError, + "failed to rebind ", tunnelName, ": ", err.what()); + } + } + } + } + } + } + { + // remove all non existant server tunnels + std::vector remove; + std::lock_guard lock(m_ServerMutex); + for (auto& entry : m_ServerTunnels) { + std::string tunnelName = entry.second->GetName(); + auto itrEnd = updatedTunnels.end(); + auto itr = std::find(updatedTunnels.begin(), itrEnd, tunnelName); + if (itr == itrEnd) { + remove.push_back(tunnelName); + } + } + for (auto& tunnelName : remove) { + auto itr = + std::find_if( + m_ServerTunnels.begin(), + m_ServerTunnels.end(), + [&tunnelName](ServerTunnelEntry & entry) -> bool { + return entry.second->GetName() == tunnelName; + }); + m_ServerTunnels.erase(itr); + } + } + { + // remove all non existant client tunnels + std::vector remove; + std::lock_guard lock(m_ClientMutex); + for (auto& entry : m_ClientTunnels) { + std::string tunnelName = entry.second->GetName(); + auto itrEnd = updatedTunnels.end(); + auto itr = std::find(updatedTunnels.begin(), itrEnd, tunnelName); + if (itr == itrEnd) { + remove.push_back(tunnelName); + } + } + for (auto & tunnelName : remove) { + LogPrint(eLogInfo, "Removing Tunnel ", tunnelName); + auto itr = + std::find_if( + m_ClientTunnels.begin(), + m_ClientTunnels.end(), + [&tunnelName](ClientTunnelEntry & entry) -> bool { + return entry.second->GetName() == tunnelName; + }); + m_ClientTunnels.erase(itr); + } + } +} + void ClientContext::ReadTunnels() { boost::property_tree::ptree pt; std::string pathTunnelsConfigFile = @@ -325,6 +658,7 @@ void ClientContext::ReadTunnels() { if (keys.length() > 0) localDestination = LoadLocalDestination(keys, false); auto clientTunnel = new I2PClientTunnel( + name, dest, address, port, @@ -365,23 +699,9 @@ void ClientContext::ReadTunnels() { auto localDestination = LoadLocalDestination(keys, true); I2PServerTunnel* serverTunnel = (type == I2P_TUNNELS_SECTION_TYPE_HTTP) ? - new I2PServerTunnelHTTP(host, port, localDestination, inPort) : - new I2PServerTunnel(host, port, localDestination, inPort); - if (accessList.length() > 0) { - std::set idents; - size_t pos = 0, comma; - do { - comma = accessList.find(',', pos); - i2p::data::IdentHash ident; - ident.FromBase32( - accessList.substr( - pos, - comma != std::string::npos ? comma - pos : std::string::npos)); - idents.insert(ident); - pos = comma + 1; - } while (comma != std::string::npos); - serverTunnel->SetAccessList(idents); - } + new I2PServerTunnelHTTP(name, host, port, localDestination, inPort) : + new I2PServerTunnel(name, host, port, localDestination, inPort); + serverTunnel->SetAccessListString(accessList); if (m_ServerTunnels.insert( std::make_pair( localDestination->GetIdentHash(), diff --git a/src/client/ClientContext.h b/src/client/ClientContext.h index ab75d290..93d6ec0c 100644 --- a/src/client/ClientContext.h +++ b/src/client/ClientContext.h @@ -35,6 +35,7 @@ #include #include #include +#include #include "AddressBook.h" #include "Destination.h" @@ -96,6 +97,11 @@ class ClientContext { AddressBook& GetAddressBook() { return m_AddressBook; } + // reload tunnels.cfg + // removes tunnels not in new tunnels.cfg + // adds tunnels that were previously not in tunnels.cfg + void ReloadTunnels(); + private: void ReadTunnels(); @@ -110,11 +116,23 @@ class ClientContext { i2p::proxy::HTTPProxy* m_HttpProxy; i2p::proxy::SOCKSProxy* m_SocksProxy; + std::mutex m_ClientMutex; std::map > m_ClientTunnels; // port->tunnel + + std::mutex m_ServerMutex; std::map > m_ServerTunnels; // destination->tunnel + + // types for accessing client / server tunnel map entries + typedef std::pair > + ClientTunnelEntry; + typedef std::pair > + ServerTunnelEntry; + + boost::asio::io_service m_Service; + i2pcontrol::I2PControlService* m_I2PControlService; public: diff --git a/src/client/Daemon.cpp b/src/client/Daemon.cpp index 57d545c4..9fe513f4 100644 --- a/src/client/Daemon.cpp +++ b/src/client/Daemon.cpp @@ -28,11 +28,12 @@ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "Daemon.h" + #include #include #include "ClientContext.h" -#include "Daemon.h" #include "Destination.h" #include "Garlic.h" #include "NetworkDatabase.h" @@ -40,6 +41,7 @@ #include "RouterInfo.h" #include "Version.h" #include "api/Streaming.h" +#include "core/util/Log.h" #include "transport/NTCPSession.h" #include "transport/Transports.h" #include "tunnel/Tunnel.h" @@ -49,7 +51,7 @@ namespace util { Daemon_Singleton::Daemon_Singleton() : m_IsRunning(1), - m_log(kovri::log::Log::Get()) {} + m_log(i2p::util::log::Log::Get()) {} Daemon_Singleton::~Daemon_Singleton() {} bool Daemon_Singleton::IsService() const { @@ -101,29 +103,31 @@ bool Daemon_Singleton::Start() { } else { StartLog(""); // write to stdout } - try { - LogPrint("Starting NetDB..."); - if (i2p::data::netdb.Start()) { - LogPrint("NetDB started"); - } else { - LogPrint("NetDB failed to start"); - return false; - } - LogPrint("Starting transports..."); - i2p::transport::transports.Start(); - LogPrint("Transports started"); - - LogPrint("Starting tunnels..."); - i2p::tunnel::tunnels.Start(); - LogPrint("Tunnels started"); - - LogPrint("Starting client..."); - i2p::client::context.Start(); - LogPrint("Client started"); - } catch (std::runtime_error& e) { - LogPrint(eLogError, e.what()); + } else { + m_log->Stop(); + } + try { + LogPrint("Starting NetDB..."); + if (i2p::data::netdb.Start()) { + LogPrint("NetDB started"); + } else { + LogPrint("NetDB failed to start"); return false; } + LogPrint("Starting transports..."); + i2p::transport::transports.Start(); + LogPrint("Transports started"); + + LogPrint("Starting tunnels..."); + i2p::tunnel::tunnels.Start(); + LogPrint("Tunnels started"); + + LogPrint("Starting client..."); + i2p::client::context.Start(); + LogPrint("Client started"); + } catch (std::runtime_error& e) { + LogPrint(eLogError, e.what()); + return false; } return true; } @@ -150,5 +154,13 @@ bool Daemon_Singleton::Stop() { return true; } +void Daemon_Singleton::Reload() { + // TODO(psi): do we want to add locking? + LogPrint("Reloading configuration"); + // reload tunnels.cfg + i2p::client::context.ReloadTunnels(); + // TODO(psi): reload kovri.conf +} + } // namespace util } // namespace i2p diff --git a/src/client/Daemon.h b/src/client/Daemon.h index 1c27f896..4109ef06 100644 --- a/src/client/Daemon.h +++ b/src/client/Daemon.h @@ -50,6 +50,7 @@ class Daemon_Singleton { virtual bool Init(); virtual bool Start(); virtual bool Stop(); + virtual void Reload() = 0; bool m_IsDaemon, m_IsLogging, m_IsRunning; @@ -58,7 +59,7 @@ class Daemon_Singleton { Daemon_Singleton(); virtual ~Daemon_Singleton(); bool IsService() const; - std::shared_ptr m_log; + std::shared_ptr m_log; }; #ifdef _WIN32 @@ -82,7 +83,7 @@ class DaemonLinux : public Daemon_Singleton { } virtual bool Start(); virtual bool Stop(); - + void Reload(); private: std::string m_pidFile; int m_pidFilehandle; diff --git a/src/client/DaemonLinux.cpp b/src/client/DaemonLinux.cpp index 80342770..961482e5 100644 --- a/src/client/DaemonLinux.cpp +++ b/src/client/DaemonLinux.cpp @@ -55,7 +55,7 @@ void handle_signal(int sig) { } } LogPrint("Reloading config..."); - // TODO(anonimal) rewrite ParseConfigFile() to respond to SIGHUP + Daemon.Reload(); LogPrint("Config reloaded"); break; case SIGABRT: @@ -133,6 +133,11 @@ bool DaemonLinux::Stop() { return Daemon_Singleton::Stop(); } +void DaemonLinux::Reload() { + // no linux specific reload operations + Daemon_Singleton::Reload(); +} + } // namespace util } // namespace i2p diff --git a/src/client/Destination.cpp b/src/client/Destination.cpp index e4461f6b..d5db215d 100644 --- a/src/client/Destination.cpp +++ b/src/client/Destination.cpp @@ -43,6 +43,7 @@ #include "AddressBook.h" #include "NetworkDatabase.h" #include "crypto/ElGamal.h" +#include "crypto/Rand.h" #include "util/Log.h" #include "util/Timestamp.h" @@ -63,7 +64,6 @@ ClientDestination::ClientDestination( m_PublishConfirmationTimer(m_Service), m_CleanupTimer(m_Service) { i2p::crypto::GenerateElGamalKeyPair( - i2p::context.GetRandomNumberGenerator(), m_EncryptionPrivateKey, m_EncryptionPublicKey); int inboundTunnelLen = DEFAULT_INBOUND_TUNNEL_LENGTH, @@ -449,8 +449,7 @@ void ClientDestination::Publish() { m_ExcludedFloodfills.insert(floodfill->GetIdentHash()); LogPrint(eLogDebug, "Publish LeaseSet of ", GetIdentHash().ToBase32()); - m_PublishReplyToken = - i2p::context.GetRandomNumberGenerator().GenerateWord32(); + m_PublishReplyToken = i2p::crypto::Rand(); auto msg = WrapMessage( floodfill, diff --git a/src/client/I2PService.cpp b/src/client/I2PService.cpp index a0a0d210..9979c3c2 100644 --- a/src/client/I2PService.cpp +++ b/src/client/I2PService.cpp @@ -85,6 +85,26 @@ void TCPIPAcceptor::Stop() { ClearHandlers(); } +void TCPIPAcceptor::Rebind( + const std::string& addr, + uint16_t port) { + LogPrint(eLogInfo, + "Rebind ", GetName(), " to ", addr, ":", port); + // stop everything with us + m_Acceptor.cancel(); + Stop(); + // make new acceptor + m_Acceptor = + boost::asio::ip::tcp::acceptor( + GetService(), + boost::asio::ip::tcp::endpoint( + boost::asio::ip::address::from_string( + addr), + port)); + // start everything again + Start(); +} + void TCPIPAcceptor::Accept() { auto newSocket = std::make_shared (GetService()); diff --git a/src/client/I2PService.h b/src/client/I2PService.h index 4f3e5a22..81c26ead 100644 --- a/src/client/I2PService.h +++ b/src/client/I2PService.h @@ -92,7 +92,8 @@ class I2PService { virtual void Start() = 0; virtual void Stop() = 0; - virtual const char* GetName() {return "Kovri I2P Router Service"; } + // everyone must override this + virtual std::string GetName() = 0; private: std::shared_ptr m_LocalDestination; @@ -147,12 +148,13 @@ class TCPIPAcceptor : public I2PService { int port, std::shared_ptr localDestination = nullptr) : I2PService(localDestination), + m_Address(address), m_Acceptor( GetService(), boost::asio::ip::tcp::endpoint( - boost::asio::ip::address::from_string( - address), - port)), + boost::asio::ip::address::from_string( + address), + port)), m_Timer( GetService()) {} @@ -161,16 +163,18 @@ class TCPIPAcceptor : public I2PService { int port, i2p::data::SigningKeyType kt) : I2PService(kt), + m_Address(address), m_Acceptor( GetService(), boost::asio::ip::tcp::endpoint( - boost::asio::ip::address::from_string( - address), - port)), - m_Timer( - GetService()) {} + boost::asio::ip::address::from_string( + address), + port)), + m_Timer(GetService()) {} - virtual ~TCPIPAcceptor() { TCPIPAcceptor::Stop(); } + virtual ~TCPIPAcceptor() { + TCPIPAcceptor::Stop(); + } // If you override this make sure you call it from the children void Start(); @@ -178,11 +182,27 @@ class TCPIPAcceptor : public I2PService { // If you override this make sure you call it from the children void Stop(); + // stop tunnel, change address, start tunnel + // will throw exception if the address is already in use + void Rebind( + const std::string& addr, + uint16_t port); + + // @return the endpoint this TCPIPAcceptor is bound on + boost::asio::ip::tcp::endpoint GetEndpoint() const { + return m_Acceptor.local_endpoint(); + } + protected: virtual std::shared_ptr CreateHandler( std::shared_ptr socket) = 0; - virtual const char* GetName() { return "Generic TCP/IP accepting daemon"; } + virtual std::string GetName() { + return "Generic TCP/IP accepting daemon"; + } + + protected: + std::string m_Address; private: void Accept(); @@ -192,6 +212,12 @@ class TCPIPAcceptor : public I2PService { boost::asio::ip::tcp::acceptor m_Acceptor; boost::asio::deadline_timer m_Timer; + + public: + // get our current address + std::string GetAddress() const { + return m_Address; + } }; } // namespace client diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f4d90125..6fa273f3 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,5 +1,5 @@ set(CORE_SRC - "tunnel/TunnelConfig.cpp" + "tunnel/TunnelConfig.cpp" "Garlic.cpp" "I2NPProtocol.cpp" "Identity.cpp" @@ -13,6 +13,8 @@ set(CORE_SRC "crypto/AES.cpp" "crypto/CryptoConst.cpp" "crypto/EdDSA25519.cpp" + "crypto/ElGamal.cpp" + "crypto/Rand.cpp" "crypto/Signature.cpp" "crypto/Tunnel.cpp" "transport/NTCP.cpp" @@ -29,8 +31,8 @@ set(CORE_SRC "tunnel/TunnelPool.cpp" "util/Base64.cpp" "util/HTTP.cpp" - "util/MTU.cpp" - "util/OldLog.cpp") + "util/Log.cpp" + "util/MTU.cpp") set(EDDSA_SRC "crypto/ed25519/fe_0.cpp" @@ -84,16 +86,6 @@ include_directories( set(EDDSA_LIB "ed25519-ref10") add_subdirectory(crypto/ed25519) -if(WITH_BOOST_LOG) - # using boost log backend - set(LOG_SRC "util/BoostLog.cpp") -else() - # print log backend - set(LOG_SRC "util/PrintLog.cpp") -endif() - -list(APPEND CORE_SRC ${LOG_SRC}) - # Library building if(WITH_LIBRARY) add_library(${CORE_NAME} ${CORE_SRC} ${EDDSA_SRC}) diff --git a/src/core/I2NPProtocol.cpp b/src/core/I2NPProtocol.cpp index 67554001..b934d196 100644 --- a/src/core/I2NPProtocol.cpp +++ b/src/core/I2NPProtocol.cpp @@ -30,7 +30,7 @@ #include "I2NPProtocol.h" -#include +#include // TODO(unassigned): use util/GZIP.h (?) #include @@ -38,6 +38,7 @@ #include #include +#include "crypto/Rand.h" #include "Garlic.h" #include "NetworkDatabase.h" #include "RouterContext.h" @@ -47,6 +48,10 @@ #include "util/I2PEndian.h" #include "util/Timestamp.h" +#ifndef NETWORK_ID +#define NETWORK_ID 2 +#endif + namespace i2p { I2NPMessage* NewI2NPMessage() { @@ -81,7 +86,7 @@ void I2NPMessage::FillI2NPMessageHeader( if (replyMsgID) // for tunnel creation SetMsgID(replyMsgID); else - SetMsgID(i2p::context.GetRandomNumberGenerator().GenerateWord32()); + SetMsgID(i2p::crypto::Rand()); SetExpiration( i2p::util::GetMillisecondsSinceEpoch() + I2NP_HEADER_DEFAULT_EXPIRATION_TIME); @@ -90,7 +95,7 @@ void I2NPMessage::FillI2NPMessageHeader( } void I2NPMessage::RenewI2NPMessageHeader() { - SetMsgID(i2p::context.GetRandomNumberGenerator().GenerateWord32()); + SetMsgID(i2p::crypto::Rand()); SetExpiration( i2p::util::GetMillisecondsSinceEpoch() + I2NP_HEADER_DEFAULT_EXPIRATION_TIME); @@ -138,10 +143,10 @@ std::shared_ptr CreateDeliveryStatusMsg( } else { // for SSU establishment htobe32buf( buf + DELIVERY_STATUS_MSGID_OFFSET, - i2p::context.GetRandomNumberGenerator().GenerateWord32()); + i2p::crypto::Rand()); htobe64buf( buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, - 2); // netID = 2 + NETWORK_ID); } m->len += DELIVERY_STATUS_SIZE; m->FillI2NPMessageHeader(e_I2NPDeliveryStatus); @@ -350,7 +355,7 @@ bool HandleBuildRequestRecords( // always reject with bandwidth reason (30) record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 30; } - // TODO(unassigned): fill filler + // TODO(anonimal): fill filler CryptoPP::SHA256().CalculateDigest( record + BUILD_RESPONSE_RECORD_SHA256HASH_OFFSET, record + BUILD_RESPONSE_RECORD_RANDPAD_OFFSET, @@ -360,7 +365,7 @@ bool HandleBuildRequestRecords( for (int j = 0; j < num; j++) { encryption.SetKey(clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET); encryption.SetIV(clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET); - // TODO(anonimal): records or record? + // TODO(anonimal): records or record? uint8_t* reply = records + j * TUNNEL_BUILD_RECORD_SIZE; encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply); } diff --git a/src/core/Identity.cpp b/src/core/Identity.cpp index 55bb0d5a..6166d96a 100644 --- a/src/core/Identity.cpp +++ b/src/core/Identity.cpp @@ -28,10 +28,13 @@ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// TODO(unassigned): use crypto/DSA.h #include -#include +// TODO(unassigned): use crypto/SHA.h #include +#include + #include #include @@ -40,7 +43,9 @@ #include "Identity.h" #include "RouterContext.h" #include "crypto/CryptoConst.h" +#include "crypto/CryptoPP_Rand.h" #include "crypto/ElGamal.h" +#include "crypto/Rand.h" #include "crypto/Signature.h" #include "util/Base64.h" #include "util/I2PEndian.h" @@ -91,7 +96,7 @@ IdentityEx::IdentityEx( case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: { size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64 - i2p::context.GetRandomNumberGenerator().GenerateBlock( + i2p::crypto::RandBytes( m_StandardIdentity.signingKey, padding); memcpy( @@ -103,7 +108,7 @@ IdentityEx::IdentityEx( case SIGNING_KEY_TYPE_ECDSA_SHA384_P384: { size_t padding = 128 - i2p::crypto::ECDSAP384_KEY_LENGTH; // 32 = 128 - 96 - i2p::context.GetRandomNumberGenerator().GenerateBlock( + i2p::crypto::RandBytes( m_StandardIdentity.signingKey, padding); memcpy( @@ -143,7 +148,7 @@ IdentityEx::IdentityEx( case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: { size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32 - i2p::context.GetRandomNumberGenerator().GenerateBlock( + i2p::crypto::RandBytes( m_StandardIdentity.signingKey, padding); memcpy( @@ -170,6 +175,7 @@ IdentityEx::IdentityEx( // calculate ident hash uint8_t* buf = new uint8_t[GetFullLen()]; ToBuffer(buf, GetFullLen()); + // TODO(unassigned): use i2p::crypto::SHA256() CryptoPP::SHA256().CalculateDigest(m_IdentHash, buf, GetFullLen()); delete[] buf; } else { // DSA-SHA1 @@ -495,7 +501,7 @@ void PrivateKeys::Sign( int len, uint8_t* signature) const { if (m_Signer) - m_Signer->Sign(i2p::context.GetRandomNumberGenerator(), buf, len, signature); + m_Signer->Sign(buf, len, signature); } void PrivateKeys::CreateSigner() { @@ -534,45 +540,38 @@ void PrivateKeys::CreateSigner() { PrivateKeys PrivateKeys::CreateRandomKeys(SigningKeyType type) { if (type != SIGNING_KEY_TYPE_DSA_SHA1) { PrivateKeys keys; - auto& rnd = i2p::context.GetRandomNumberGenerator(); // signature uint8_t signingPublicKey[512]; // signing public key is 512 bytes max switch (type) { case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: i2p::crypto::CreateECDSAP256RandomKeys( - rnd, keys.m_SigningPrivateKey, signingPublicKey); break; case SIGNING_KEY_TYPE_ECDSA_SHA384_P384: i2p::crypto::CreateECDSAP384RandomKeys( - rnd, keys.m_SigningPrivateKey, signingPublicKey); break; case SIGNING_KEY_TYPE_ECDSA_SHA512_P521: i2p::crypto::CreateECDSAP521RandomKeys( - rnd, keys.m_SigningPrivateKey, signingPublicKey); break; case SIGNING_KEY_TYPE_RSA_SHA256_2048: i2p::crypto::CreateRSARandomKeys( - rnd, i2p::crypto::RSASHA2562048_KEY_LENGTH, keys.m_SigningPrivateKey, signingPublicKey); break; case SIGNING_KEY_TYPE_RSA_SHA384_3072: i2p::crypto::CreateRSARandomKeys( - rnd, i2p::crypto::RSASHA3843072_KEY_LENGTH, keys.m_SigningPrivateKey, signingPublicKey); break; case SIGNING_KEY_TYPE_RSA_SHA512_4096: i2p::crypto::CreateRSARandomKeys( - rnd, i2p::crypto::RSASHA5124096_KEY_LENGTH, keys.m_SigningPrivateKey, signingPublicKey); @@ -584,8 +583,7 @@ PrivateKeys PrivateKeys::CreateRandomKeys(SigningKeyType type) { } // encryption uint8_t publicKey[256]; - CryptoPP::DH dh(i2p::crypto::elgp, i2p::crypto::elgg); - dh.GenerateKeyPair(rnd, keys.m_PrivateKey, publicKey); + i2p::crypto::GenerateElGamalKeyPair(keys.m_PrivateKey, publicKey); // identity keys.m_Public = IdentityEx(publicKey, signingPublicKey, type); keys.CreateSigner(); @@ -596,15 +594,12 @@ PrivateKeys PrivateKeys::CreateRandomKeys(SigningKeyType type) { Keys CreateRandomKeys() { Keys keys; - auto& rnd = i2p::context.GetRandomNumberGenerator(); // encryption i2p::crypto::GenerateElGamalKeyPair( - rnd, keys.privateKey, keys.publicKey); // signing i2p::crypto::CreateDSARandomKeys( - rnd, keys.signingPrivateKey, keys.signingKey); return keys; diff --git a/src/core/NetworkDatabase.cpp b/src/core/NetworkDatabase.cpp index 0b90b1eb..6dc34b8e 100644 --- a/src/core/NetworkDatabase.cpp +++ b/src/core/NetworkDatabase.cpp @@ -32,6 +32,7 @@ #include +// TODO(unassigned): use util/GZIP.h ? #include #include @@ -44,6 +45,7 @@ #include "Garlic.h" #include "I2NPProtocol.h" #include "RouterContext.h" +#include "crypto/Rand.h" #include "transport/Transports.h" #include "tunnel/Tunnel.h" #include "util/Base64.h" @@ -51,7 +53,7 @@ #include "util/Log.h" #include "util/Timestamp.h" -// TODO(unassigned): do not use namespace using-directives. +// TODO(anonimal): do not use namespace using-directives. using namespace i2p::transport; namespace i2p { @@ -760,16 +762,14 @@ void NetDb::Explore( auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel() : nullptr; bool throughTunnels = outbound && inbound; - // TODO(unassigned): docs - CryptoPP::RandomNumberGenerator& rnd = - i2p::context.GetRandomNumberGenerator(); + uint8_t randomHash[32]; std::vector msgs; std::set floodfills; // TODO(unassigned): docs LogPrint("Exploring new ", numDestinations, " routers ..."); for (int i = 0; i < numDestinations; i++) { - rnd.GenerateBlock(randomHash, 32); + i2p::crypto::RandBytes(randomHash, 32); auto dest = m_Requests.CreateRequest(randomHash, true); // exploratory if (!dest) { LogPrint(eLogWarning, "Exploratory destination is requested already"); @@ -819,8 +819,7 @@ void NetDb::Publish() { i2p::context.GetRouterInfo().GetIdentHash(), excluded); if (floodfill) { - uint32_t replyToken = - i2p::context.GetRandomNumberGenerator().GenerateWord32(); + uint32_t replyToken = i2p::crypto::Rand(); LogPrint("Publishing our RouterInfo to ", floodfill->GetIdentHashAbbreviation(), ". reply token=", replyToken); @@ -878,9 +877,7 @@ std::shared_ptr NetDb::GetHighBandwidthRandomRouter( template std::shared_ptr NetDb::GetRandomRouter( Filter filter) const { - CryptoPP::RandomNumberGenerator& rnd = - i2p::context.GetRandomNumberGenerator(); - uint32_t ind = rnd.GenerateWord32(0, m_RouterInfos.size() - 1); + uint32_t ind = i2p::crypto::RandInRange(0, m_RouterInfos.size() - 1); for (int j = 0; j < 2; j++) { uint32_t i = 0; std::unique_lock l(m_RouterInfosMutex); diff --git a/src/core/Reseed.cpp b/src/core/Reseed.cpp index d3f72dc3..35255206 100644 --- a/src/core/Reseed.cpp +++ b/src/core/Reseed.cpp @@ -36,14 +36,6 @@ #include #include -#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 -#include -#include -#include -#include -#include -#include - #include #include #include @@ -52,12 +44,22 @@ #include "Identity.h" #include "NetworkDatabase.h" #include "client/util/Filesystem.h" +#include "crypto/Rand.h" #include "crypto/CryptoConst.h" #include "crypto/Signature.h" #include "util/HTTP.h" #include "util/I2PEndian.h" #include "util/Log.h" +// do this AFTER other includes +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 +#include +#include +#include +#include +#include +#include + namespace i2p { namespace data { @@ -78,8 +80,8 @@ Reseeder::Reseeder() {} Reseeder::~Reseeder() {} int Reseeder::ReseedNowSU3() { - CryptoPP::AutoSeededRandomPool rnd; - int ind = rnd.GenerateWord32(0, reseedHosts.size() - 1); + size_t s = reseedHosts.size(); + size_t ind = i2p::crypto::RandInRange(size_t{0}, s - size_t{1}); std::string& reseedHost = reseedHosts[ind]; return ReseedFromSU3(reseedHost); } diff --git a/src/core/Reseed.h b/src/core/Reseed.h index a0bdbce6..8936c3e0 100644 --- a/src/core/Reseed.h +++ b/src/core/Reseed.h @@ -31,19 +31,13 @@ #ifndef SRC_CORE_RESEED_H_ #define SRC_CORE_RESEED_H_ -#include -#include - -#include #include #include #include #include -#include #include "Identity.h" -#include "crypto/AES.h" namespace i2p { namespace data { diff --git a/src/core/RouterContext.h b/src/core/RouterContext.h index d76a4509..233bd3e9 100644 --- a/src/core/RouterContext.h +++ b/src/core/RouterContext.h @@ -67,87 +67,134 @@ class RouterContext : public i2p::garlic::GarlicDestination { void Init(); + // @return This RouterContext's RouterInfo i2p::data::RouterInfo& GetRouterInfo() { return m_RouterInfo; } + // @return This RouterContext's RouterInfo wrapped in a smart pointer std::shared_ptr GetSharedRouterInfo() const { return std::shared_ptr( &m_RouterInfo, [](const i2p::data::RouterInfo *) {}); } - CryptoPP::RandomNumberGenerator& GetRandomNumberGenerator() { - return m_Rnd; - } - + // @return How long this RouterContext has been online in seconds since epoch uint32_t GetUptime() const; + // @return Time that this RouterContext started in seconds since epoch uint32_t GetStartupTime() const { return m_StartupTime; } + // @return Time this RouterContext last updated its RouterInfo uint64_t GetLastUpdateTime() const { return m_LastUpdateTime; } + // @return + // eRouterStatusOk - if the RouterContext is fully port forwarded, + // eRouterStatusTesting - if the RouterContext is testing connectivity + // eRouterStatusFirewalled - if the RouterContext detects being firewalled RouterStatus GetStatus() const { return m_Status; } + // Set RouterContext's Status + // @see GetStatus + // @param status the new status this RouterContext will have void SetStatus( RouterStatus status) { m_Status = status; } - void UpdatePort(int port); // called from Daemon + // Called from Daemon, updates this RouterContext's Port. + // Rebuilds RouterInfo + // @param port port number + void UpdatePort(int port); + // Called From SSU or Daemon. + // Update Our IP Address, external IP Address if behind NAT. + // Rebuilds RouterInfo + // @param host the ip address void UpdateAddress( - const boost::asio::ip::address& host); // called from SSU or Daemon + const boost::asio::ip::address& host); + // Add an SSU introducer to our RouterInfo. + // Rebuild RouterInfo. + // @param routerInfo the RouterInfo to use in the Introducer + // @param tag bool AddIntroducer( const i2p::data::RouterInfo& routerInfo, uint32_t tag); + // Remove and SSU introducer given its endpoint. + // Rebuilds RouterInfo. + // @param e the SSU introducer's endpoint void RemoveIntroducer( const boost::asio::ip::udp::endpoint& e); + // @return true if other routers cannot reach us otherwise false bool IsUnreachable() const; + // Set that other routers cannot reach us void SetUnreachable(); + // Set that other routers *can* reach us void SetReachable(); + // @return true if we are a floodfill router otherwise false bool IsFloodfill() const { return m_IsFloodfill; } + // Set if we are a floodfill router, rebuild RouterInfo. + // @param floodfill true if we want to become floodfill, false if we don't void SetFloodfill( bool floodfill); + // Mark ourselves as having high bandwidth. + // Changes caps flags. + // Rebuilds RouterInfo. void SetHighBandwidth(); + // Mark ourselves as having low (aka NOT high) Bandwidth. + // Changes Capacity Flags. + // Rebuilds RouterInfo. void SetLowBandwidth(); + // @return true if we are going to accept tunnels right now. bool AcceptsTunnels() const { return m_AcceptsTunnels; } + // Set explicitly if we want to accept tunnels right now. + // @param acceptTunnels true if we want to accept tunnels otherwise false void SetAcceptsTunnels( bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; } + // @return true if we support IPv6 connectivity otherwise false bool SupportsV6() const { return m_RouterInfo.IsV6(); } + // Set if we support IPv6 connectivity. + // Rebuilds RouterInfo. + // @param supportsV6 true if we support IPv6, false if we don't void SetSupportsV6( bool supportsV6); + // Called From NTCPSession. + // Update our NTCP IPv6 address. + // Rebuilds RouterInfo. + // @param host Our reachable IPv6 address for NTCP void UpdateNTCPV6Address( - const boost::asio::ip::address& host); // called from NTCP session + const boost::asio::ip::address& host); + // Update Stats in Router Info when floodfill. + // Rebuilds RouterInfo. void UpdateStats(); // implements LocalDestination @@ -194,7 +241,6 @@ class RouterContext : public i2p::garlic::GarlicDestination { private: i2p::data::RouterInfo m_RouterInfo; i2p::data::PrivateKeys m_Keys; - CryptoPP::AutoSeededRandomPool m_Rnd; uint64_t m_LastUpdateTime; bool m_AcceptsTunnels, m_IsFloodfill; uint64_t m_StartupTime; // in seconds since epoch diff --git a/src/core/crypto/CryptoConst.cpp b/src/core/crypto/CryptoConst.cpp index debbbb4b..b0fe3f1a 100644 --- a/src/core/crypto/CryptoConst.cpp +++ b/src/core/crypto/CryptoConst.cpp @@ -83,11 +83,11 @@ const uint8_t dsag_[128]= { const CryptoConstants& GetCryptoConstants() { static CryptoConstants cryptoConstants = { - {elgp_, 256}, // elgp - {2}, // elgg - {dsap_, 128}, // dsap - {dsaq_, 20}, // dsaq - {dsag_, 128} // dsag + CryptoPP::Integer(elgp_, 256), // elgp + CryptoPP::Integer(2), // elgg + CryptoPP::Integer(dsap_, 128), // dsap + CryptoPP::Integer(dsaq_, 20), // dsaq + CryptoPP::Integer(dsag_, 128) // dsag }; return cryptoConstants; } diff --git a/src/core/crypto/CryptoPP_Impl.h b/src/core/crypto/CryptoPP_Impl.h new file mode 100644 index 00000000..e3386819 --- /dev/null +++ b/src/core/crypto/CryptoPP_Impl.h @@ -0,0 +1,386 @@ +/** + * Copyright (c) 2015-2016, The Kovri I2P Router Project + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_CORE_CRYPTO_CRYPTOPP_IMPL_H_ +#define SRC_CORE_CRYPTO_CRYPTOPP_IMPL_H_ + +// CryptoPP Pimpl definitions + +#include +#include +#include +#include +#include +#include + +#include "CryptoPP_Rand.h" +#include "Signature.h" + +namespace i2p { +namespace crypto { + +class DSAVerifier_Pimpl { + public: + DSAVerifier_Pimpl( + const uint8_t* signingKey); + + bool Verify( + const uint8_t* buf, + size_t len, + const uint8_t* signature) const; + + private: + CryptoPP::DSA::PublicKey m_PublicKey; +}; + +class DSASigner_Pimpl { + public: + DSASigner_Pimpl( + const uint8_t* signingPrivateKey); + ~DSASigner_Pimpl(); + + void Sign( + const uint8_t* buf, + size_t len, + uint8_t* signature) const; + + private: + CryptoPP::DSA::PrivateKey m_PrivateKey; + uint8_t* m_PrivateKeyBuff; +}; + +template +class ECDSAVerifier { + public: + template + ECDSAVerifier( + Curve curve, + const uint8_t* signingKey) { + m_PublicKey.Initialize( + curve, + CryptoPP::ECP::Point( + CryptoPP::Integer( + signingKey, + keyLen / 2), + CryptoPP::Integer( + signingKey + keyLen / 2, + keyLen / 2))); + } + + bool Verify( + const uint8_t* buf, + size_t len, + const uint8_t * signature) const { + typename CryptoPP::ECDSA::Verifier + verifier(m_PublicKey); + return verifier.VerifyMessage( + buf, len, signature, keyLen); // signature length + } + + private: + typename CryptoPP::ECDSA::PublicKey m_PublicKey; +}; + + +template +class ECDSASigner : public Signer { + public: + typedef typename CryptoPP::ECDSA::PrivateKey SignKey; + template + ECDSASigner( + Curve curve, + const uint8_t* signingPrivateKey, + size_t keyLen) { + m_PrivateKey.Initialize( + curve, + CryptoPP::Integer( + signingPrivateKey, + keyLen / 2)); // private key length + } + + void Sign( + const uint8_t* buf, + size_t len, + uint8_t* signature) const { + typename CryptoPP::ECDSA::Signer + signer(m_PrivateKey); + PRNG& r = prng; + signer.SignMessage(r, buf, len, signature); + } + + private: + SignKey m_PrivateKey; +}; + +template +inline void CreateECDSARandomKeys( + Curve curve, + size_t keyLen, + uint8_t* signingPrivateKey, + uint8_t* signingPublicKey) { + typename CryptoPP::ECDSA::PrivateKey + privateKey; + typename CryptoPP::ECDSA::PublicKey + publicKey; + PRNG& r = prng; + privateKey.Initialize(r, curve); + privateKey.MakePublicKey(publicKey); + privateKey.GetPrivateExponent().Encode(signingPrivateKey, keyLen / 2); + auto q = publicKey.GetPublicElement(); + q.x.Encode(signingPublicKey, keyLen / 2); + q.y.Encode(signingPublicKey + keyLen / 2, keyLen / 2); +} + +class ECDSAP256Verifier_Pimpl + : public ECDSAVerifier { + public: + ECDSAP256Verifier_Pimpl( + const uint8_t* signingKey) + : ECDSAVerifier( + CryptoPP::ASN1::secp256r1(), + signingKey) {} +}; + +class ECDSAP256Signer_Pimpl + : public ECDSASigner { + public: + ECDSAP256Signer_Pimpl( + const uint8_t* signingPrivateKey) + : ECDSASigner( + CryptoPP::ASN1::secp256r1(), + signingPrivateKey, + ECDSAP256_KEY_LENGTH) {} +}; + +class ECDSAP384Verifier_Pimpl + : public ECDSAVerifier { + public: + ECDSAP384Verifier_Pimpl( + const uint8_t* signingKey) + : ECDSAVerifier( + CryptoPP::ASN1::secp384r1(), + signingKey) {} +}; + +class ECDSAP384Signer_Pimpl + : public ECDSASigner { + public: + ECDSAP384Signer_Pimpl( + const uint8_t* signingPrivateKey) + : ECDSASigner( + CryptoPP::ASN1::secp384r1(), + signingPrivateKey, + ECDSAP384_KEY_LENGTH) {} +}; + +class ECDSAP521Verifier_Pimpl + : public ECDSAVerifier { + public: + ECDSAP521Verifier_Pimpl( + const uint8_t* signingKey) + : ECDSAVerifier( + CryptoPP::ASN1::secp521r1(), + signingKey) {} +}; + +class ECDSAP521Signer_Pimpl + : public ECDSASigner { + public: + ECDSAP521Signer_Pimpl( + const uint8_t* signingPrivateKey) + : ECDSASigner( + CryptoPP::ASN1::secp521r1(), + signingPrivateKey, + ECDSAP521_KEY_LENGTH) {} +}; + +template +class RSAVerifier { + public: + explicit RSAVerifier( + const uint8_t* signingKey) { + m_PublicKey.Initialize( + CryptoPP::Integer( + signingKey, + keyLen), + CryptoPP::Integer( + rsae)); + } + bool Verify( + const uint8_t* buf, + size_t len, + const uint8_t* signature) const { + typename CryptoPP::RSASS::Verifier + verifier(m_PublicKey); + // signature length + return verifier.VerifyMessage(buf, len, signature, keyLen); + } + + private: + CryptoPP::RSA::PublicKey m_PublicKey; +}; + + +template +class RSASigner { + public: + RSASigner( + const uint8_t* signingPrivateKey, + size_t keyLen) { + m_PrivateKey.Initialize( + CryptoPP::Integer( + signingPrivateKey, + keyLen / 2), + rsae, + CryptoPP::Integer( + signingPrivateKey + keyLen / 2, + keyLen / 2)); + } + + void Sign( + const uint8_t* buf, + size_t len, + uint8_t* signature) const { + PRNG rnd; + typename CryptoPP::RSASS::Signer + signer(m_PrivateKey); + signer.SignMessage(rnd, buf, len, signature); + } + + private: + CryptoPP::RSA::PrivateKey m_PrivateKey; +}; + + +class RSASHA2562048Verifier_Pimpl + : public RSAVerifier { + public: + explicit RSASHA2562048Verifier_Pimpl( + const uint8_t* pubkey) + : RSAVerifier(pubkey) {} +}; + +class RSASHA3843072Verifier_Pimpl + : public RSAVerifier { + public: + explicit RSASHA3843072Verifier_Pimpl( + const uint8_t* pubkey) + : RSAVerifier(pubkey) {} +}; + +class RSASHA5124096Verifier_Pimpl + : public RSAVerifier { + public: + RSASHA5124096Verifier_Pimpl( + const uint8_t* pubkey) + : RSAVerifier(pubkey) {} +}; + +class RSASHA2562048Signer_Pimpl + : public RSASigner { + public: + RSASHA2562048Signer_Pimpl( + const uint8_t* privkey) + : RSASigner(privkey, RSASHA2562048_KEY_LENGTH * 2) {} +}; + +class RSASHA3843072Signer_Pimpl + : public RSASigner { + public: + RSASHA3843072Signer_Pimpl( + const uint8_t* privkey) + : RSASigner(privkey, RSASHA3843072_KEY_LENGTH * 2) {} +}; + +class RSASHA5124096Signer_Pimpl + : public RSASigner { + public: + RSASHA5124096Signer_Pimpl( + const uint8_t* privkey) + : RSASigner(privkey, RSASHA5124096_KEY_LENGTH * 2) {} +}; + +template +class RSARawVerifier { + public: + RSARawVerifier( + const uint8_t* signingKey) + : n(signingKey, keyLen) {} + + void Update( + const uint8_t* buf, + size_t len) { + m_Hash.Update(buf, len); + } + + bool Verify( + const uint8_t* signature) { + // RSA encryption first + CryptoPP::Integer enSig( + a_exp_b_mod_c( + CryptoPP::Integer( + signature, + keyLen), + CryptoPP::Integer( + i2p::crypto::rsae), + n)); // s^e mod n + + uint8_t EnSigBuf[keyLen]; + enSig.Encode(EnSigBuf, keyLen); + uint8_t digest[Hash::DIGESTSIZE]; + m_Hash.Final(digest); + + if (static_cast(keyLen) < Hash::DIGESTSIZE) + return false; // can't verify digest longer than key + // we assume digest is right aligned, at least for PKCS#1 v1.5 padding + return !memcmp( + EnSigBuf + (keyLen - Hash::DIGESTSIZE), + digest, + Hash::DIGESTSIZE); + } + + private: + CryptoPP::Integer n; // RSA modulus + Hash m_Hash; +}; + + +class RSASHA5124096RawVerifier_Pimpl + : public RSARawVerifier { + public: + RSASHA5124096RawVerifier_Pimpl( + const uint8_t* signingKey) + : RSARawVerifier(signingKey) {} +}; + +} // namespace crypto +} // namespace i2p + +#endif // SRC_CORE_CRYPTO_CRYPTOPP_IMPL_H_ diff --git a/src/core/crypto/CryptoPP_Rand.h b/src/core/crypto/CryptoPP_Rand.h new file mode 100644 index 00000000..bfc12735 --- /dev/null +++ b/src/core/crypto/CryptoPP_Rand.h @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2015-2016, The Kovri I2P Router Project + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_CORE_CRYPTO_CRYPTOPP_RAND_H_ +#define SRC_CORE_CRYPTO_CRYPTOPP_RAND_H_ + +// CryptoPP specific PRNG header + +#include + +namespace i2p { +namespace crypto { + +typedef CryptoPP::AutoSeededRandomPool PRNG; +static PRNG prng; + +} // namespace crypto +} // namespace i2p + +#endif // SRC_CORE_CRYPTO_CRYPTOPP_RAND_H_ diff --git a/src/core/crypto/EdDSA25519.cpp b/src/core/crypto/EdDSA25519.cpp index 114148d4..eaa2dc66 100644 --- a/src/core/crypto/EdDSA25519.cpp +++ b/src/core/crypto/EdDSA25519.cpp @@ -29,6 +29,7 @@ */ #include "EdDSA25519.h" +#include "Rand.h" #include @@ -56,14 +57,6 @@ bool EDDSA25519Verifier::Verify( m_PublicKey) >= 0; } -size_t EDDSA25519Verifier::GetPublicKeyLen() const { - return EDDSA25519_PUBLIC_KEY_LENGTH; -} - -size_t EDDSA25519Verifier::GetSignatureLen() const { - return EDDSA25519_SIGNATURE_LENGTH; -} - EDDSA25519Signer::EDDSA25519Signer( const uint8_t* signingPrivateKey, const uint8_t* signingPublicKey) { @@ -87,9 +80,8 @@ EDDSA25519Signer::EDDSA25519Signer( } void EDDSA25519Signer::Sign( - CryptoPP::RandomNumberGenerator&, const uint8_t* buf, - int len, + size_t len, uint8_t* signature) const { ed25519_ref10_sign( signature, @@ -100,10 +92,9 @@ void EDDSA25519Signer::Sign( } void CreateEDDSARandomKeys( - CryptoPP::RandomNumberGenerator& rnd, uint8_t* privateKey, uint8_t* publicKey) { - rnd.GenerateBlock( + i2p::crypto::RandBytes( privateKey, EDDSA25519_PRIVATE_KEY_LENGTH); ed25519_ref10_pubkey( diff --git a/src/core/crypto/EdDSA25519.h b/src/core/crypto/EdDSA25519.h index dbfe4358..eb6bfee2 100644 --- a/src/core/crypto/EdDSA25519.h +++ b/src/core/crypto/EdDSA25519.h @@ -51,8 +51,17 @@ class EDDSA25519Verifier : public Verifier { size_t len, const uint8_t* signature) const; - size_t GetPublicKeyLen() const; - size_t GetSignatureLen() const; + size_t GetPublicKeyLen() const { + return EDDSA25519_PUBLIC_KEY_LENGTH; + } + + size_t GetSignatureLen() const { + return EDDSA25519_SIGNATURE_LENGTH; + } + + size_t GetPrivateKeyLen() const { + return EDDSA25519_PRIVATE_KEY_LENGTH; + } private: uint8_t m_PublicKey[EDDSA25519_PUBLIC_KEY_LENGTH]; @@ -70,12 +79,9 @@ class EDDSA25519Signer : public Signer { EDDSA25519Signer( const uint8_t* signingPrivateKey); - // TODO(unassigned): do not pass random number generator. - // EdDSA does not require a random source void Sign( - CryptoPP::RandomNumberGenerator&, const uint8_t* buf, - int len, + size_t len, uint8_t* signature) const; uint8_t m_PrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH]; @@ -83,7 +89,6 @@ class EDDSA25519Signer : public Signer { }; void CreateEDDSARandomKeys( - CryptoPP::RandomNumberGenerator& rnd, uint8_t* privateKey, uint8_t* publicKey); diff --git a/src/core/crypto/ElGamal.cpp b/src/core/crypto/ElGamal.cpp new file mode 100644 index 00000000..e0f1affb --- /dev/null +++ b/src/core/crypto/ElGamal.cpp @@ -0,0 +1,143 @@ +/** + * Copyright (c) 2015-2016, The Kovri I2P Router Project + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ElGamal.h" + +#include +#include +#include +#include + +#include "CryptoConst.h" +#include "CryptoPP_Rand.h" +#include "Rand.h" +#include "util/Log.h" + +namespace i2p { +namespace crypto { + +class ElGamalEncryption_Pimpl { + public: + ElGamalEncryption_Pimpl( + const uint8_t* key); + + void Encrypt( + const uint8_t* data, + size_t len, + uint8_t* encrypted, + bool zeroPadding) const; + + private: + CryptoPP::Integer a, + b1; +}; + +ElGamalEncryption::ElGamalEncryption( + const uint8_t* key) + : m_Impl( + new ElGamalEncryption_Pimpl(key)) {} + +ElGamalEncryption::~ElGamalEncryption() { + delete m_Impl; +} + +void ElGamalEncryption::Encrypt( + const uint8_t* data, + size_t len, + uint8_t* encrypted, + bool zeroPadding) const { + m_Impl->Encrypt(data, len, encrypted, zeroPadding); +} + +ElGamalEncryption_Pimpl::ElGamalEncryption_Pimpl( + const uint8_t* key) { + PRNG rnd; + CryptoPP::Integer y(key, 256), + k(rnd, CryptoPP::Integer::One(), elgp-1); + a = a_exp_b_mod_c(elgg, k, elgp); + b1 = a_exp_b_mod_c(y, k, elgp); +} + +void ElGamalEncryption_Pimpl::Encrypt( + const uint8_t* data, + size_t len, + uint8_t* encrypted, + bool zeroPadding) const { + // calculate b = b1*m mod p + uint8_t m[255]; + m[0] = 0xFF; + memcpy(m + 33, data, len); + CryptoPP::SHA256().CalculateDigest(m + 1, m + 33, 222); + CryptoPP::Integer b(a_times_b_mod_c(b1, CryptoPP::Integer(m, 255), elgp)); + // copy a and b + if (zeroPadding) { + encrypted[0] = 0; + a.Encode(encrypted + 1, 256); + encrypted[257] = 0; + b.Encode(encrypted + 258, 256); + } else { + a.Encode(encrypted, 256); + b.Encode(encrypted + 256, 256); + } +} + +bool ElGamalDecrypt( + const uint8_t* key, + const uint8_t* encrypted, + uint8_t* data, + bool zeroPadding) { + CryptoPP::Integer + x(key, 256), + a(zeroPadding ? encrypted + 1 : encrypted, 256), + b(zeroPadding ? encrypted + 258 : encrypted + 256, 256); + uint8_t m[255]; + a_times_b_mod_c(b, a_exp_b_mod_c(a, elgp - x - 1, elgp), elgp).Encode(m, 255); + if (!CryptoPP::SHA256().VerifyDigest(m + 1, m + 33, 222)) { + return false; + } + memcpy(data, m + 33, 222); + return true; +} + +void GenerateElGamalKeyPair( + uint8_t* priv, + uint8_t* pub) { +#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER) + RandBytes(priv, 256); + a_exp_b_mod_c(elgg, CryptoPP::Integer(priv, 256), elgp).Encode(pub, 256); +#else + PRNG rnd; + CryptoPP::DH dh(elgp, elgg); + dh.GenerateKeyPair(rnd, priv, pub); +#endif +} + +} // namespace crypto +} // namespace i2p diff --git a/src/core/crypto/ElGamal.h b/src/core/crypto/ElGamal.h index 171bad7a..e205b7ed 100644 --- a/src/core/crypto/ElGamal.h +++ b/src/core/crypto/ElGamal.h @@ -31,88 +31,39 @@ #ifndef SRC_CORE_CRYPTO_ELGAMAL_H_ #define SRC_CORE_CRYPTO_ELGAMAL_H_ -#include -#include -#include -#include - #include - -#include "CryptoConst.h" -#include "util/Log.h" +#include namespace i2p { namespace crypto { +class ElGamalEncryption_Pimpl; + class ElGamalEncryption { public: ElGamalEncryption( - const uint8_t* key) { - CryptoPP::AutoSeededRandomPool rnd; - CryptoPP::Integer y(key, 256), - k(rnd, CryptoPP::Integer::One(), elgp-1); - a = a_exp_b_mod_c(elgg, k, elgp); - b1 = a_exp_b_mod_c(y, k, elgp); - } + const uint8_t* key); + ~ElGamalEncryption(); void Encrypt( const uint8_t* data, - int len, + size_t len, uint8_t* encrypted, - bool zeroPadding = false) const { - // calculate b = b1*m mod p - uint8_t m[255]; - m[0] = 0xFF; - memcpy(m + 33, data, len); - CryptoPP::SHA256().CalculateDigest(m + 1, m + 33, 222); - CryptoPP::Integer b(a_times_b_mod_c(b1, CryptoPP::Integer(m, 255), elgp)); - // copy a and b - if (zeroPadding) { - encrypted[0] = 0; - a.Encode(encrypted + 1, 256); - encrypted[257] = 0; - b.Encode(encrypted + 258, 256); - } else { - a.Encode(encrypted, 256); - b.Encode(encrypted + 256, 256); - } - } + bool zeroPadding = false) const; private: - CryptoPP::Integer a, b1; + ElGamalEncryption_Pimpl* m_Impl; }; -inline bool ElGamalDecrypt( +bool ElGamalDecrypt( const uint8_t* key, const uint8_t* encrypted, uint8_t* data, - bool zeroPadding = false) { - CryptoPP::Integer - x(key, 256), - a(zeroPadding ? encrypted + 1 : encrypted, 256), - b(zeroPadding ? encrypted + 258 : encrypted + 256, 256); - uint8_t m[255]; - a_times_b_mod_c(b, a_exp_b_mod_c(a, elgp - x - 1, elgp), elgp).Encode(m, 255); - if (!CryptoPP::SHA256().VerifyDigest(m + 1, m + 33, 222)) { - LogPrint("ElGamal decrypt hash doesn't match"); - return false; - } - memcpy(data, m + 33, 222); - return true; -} + bool zeroPadding = false); -inline void GenerateElGamalKeyPair( - CryptoPP::RandomNumberGenerator& rnd, +void GenerateElGamalKeyPair( uint8_t* priv, - uint8_t* pub) { -#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER) - rnd.GenerateBlock(priv, 256); - a_exp_b_mod_c(elgg, CryptoPP::Integer(priv, 256), elgp).Encode(pub, 256); -#else - CryptoPP::DH dh(elgp, elgg); - dh.GenerateKeyPair(rnd, priv, pub); -#endif -} + uint8_t* pub); } // namespace crypto } // namespace i2p diff --git a/src/core/util/OldLog.cpp b/src/core/crypto/Rand.cpp similarity index 81% rename from src/core/util/OldLog.cpp rename to src/core/crypto/Rand.cpp index 5215d9e4..40c7bfd1 100644 --- a/src/core/util/OldLog.cpp +++ b/src/core/crypto/Rand.cpp @@ -28,20 +28,20 @@ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include +#include "Rand.h" -#include +#include "CryptoPP_Rand.h" -#include "Log.h" +// implementation of i2p::crypto::Rand* functions -void DeprecatedStartLog( - const std::string& fullFilePath) { - std::cerr << "Not opening log file: " << fullFilePath << std::endl; -} +namespace i2p { +namespace crypto { -void DeprecatedStartLog( - std::ostream* s) { - *s << "Deprecated Logging not implemented" << std::endl; +void RandBytes( + uint8_t* dataptr, + size_t datalen) { + prng.GenerateBlock(dataptr, datalen); } - -void DeprecatedStopLog() {} + +} // namespace crypto +} // namespace i2p diff --git a/src/core/crypto/Rand.h b/src/core/crypto/Rand.h new file mode 100644 index 00000000..a2a9690e --- /dev/null +++ b/src/core/crypto/Rand.h @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2015-2016, The Kovri I2P Router Project + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_CORE_CRYPTO_RAND_H_ +#define SRC_CORE_CRYPTO_RAND_H_ +#include +#include + +namespace i2p { +namespace crypto { + + // generate random bytes + // @param dataptr buffer to store result + // @param datalen size of buffer + void RandBytes( + uint8_t* dataptr, + size_t datalen); + + // generate random of type T + template + T Rand() { + T ret; + //TODO(psi): alignment + RandBytes((uint8_t*)&ret, sizeof(ret)); + return ret; + } + + // generate a random of type T + // @param T integer type + // @param min lowerbound + // @param max upperbound + // @return random in range [min, max) + template + T RandInRange(T min, T max) { + if (min > max) { + throw std::logic_error("i2p::crypto::RandInRange() min <= max"); + } else if (min == max) { + return min; + } + T dlt = max - min; + T ret = Rand(); + ret %= dlt; + ret += min; + return ret; + } + +} // namespace crypto +} // namespace i2p + +#endif // SRC_CORE_CRYPTO_RAND_H_ diff --git a/src/core/crypto/Signature.cpp b/src/core/crypto/Signature.cpp index cb08b777..225c5b70 100644 --- a/src/core/crypto/Signature.cpp +++ b/src/core/crypto/Signature.cpp @@ -30,8 +30,9 @@ #include "Signature.h" -#include -#include +#include "CryptoConst.h" +#include "CryptoPP_Impl.h" +#include "Rand.h" #include @@ -40,33 +41,72 @@ namespace i2p { namespace crypto { +// DSA +DSAVerifier::DSAVerifier( + const uint8_t* signingKey) + : m_Impl( + new DSAVerifier_Pimpl(signingKey)) {} + +DSAVerifier::~DSAVerifier() { + delete m_Impl; +} + +bool DSAVerifier::Verify( + const uint8_t* buf, + size_t len, + const uint8_t* signature) const { + return m_Impl->Verify(buf, len, signature); +} + DSASigner::DSASigner( + const uint8_t* signingPrivateKey) + : m_Impl( + new DSASigner_Pimpl(signingPrivateKey)) {} + +DSASigner::~DSASigner() { + delete m_Impl; +} + +void DSASigner::Sign( + const uint8_t* buf, + size_t len, + uint8_t* signature) const { + m_Impl->Sign(buf, len, signature); +} + +DSASigner_Pimpl::DSASigner_Pimpl( const uint8_t* signingPrivateKey) { m_PrivateKey.Initialize( dsap, dsaq, dsag, CryptoPP::Integer( - signingPrivateKey, - DSA_PRIVATE_KEY_LENGTH)); + signingPrivateKey, + DSA_PRIVATE_KEY_LENGTH)); } +DSASigner_Pimpl::~DSASigner_Pimpl() {} -void DSASigner::Sign( - CryptoPP::RandomNumberGenerator& rnd, +void DSASigner_Pimpl::Sign( const uint8_t* buf, - int len, + size_t len, uint8_t* signature) const { CryptoPP::DSA::Signer signer(m_PrivateKey); - signer.SignMessage(rnd, buf, len, signature); + PRNG& r = prng; + signer.SignMessage(r, buf, len, signature); } void CreateDSARandomKeys( - CryptoPP::RandomNumberGenerator& rnd, uint8_t* signingPrivateKey, uint8_t* signingPublicKey) { + uint8_t keybuff[DSA_PRIVATE_KEY_LENGTH]; + CryptoPP::Integer dsax; + do { + i2p::crypto::RandBytes(keybuff, DSA_PRIVATE_KEY_LENGTH); + dsax = CryptoPP::Integer(keybuff, DSA_PRIVATE_KEY_LENGTH); + } while(dsax.IsZero() || dsax >= dsaq); CryptoPP::DSA::PrivateKey privateKey; CryptoPP::DSA::PublicKey publicKey; - privateKey.Initialize(rnd, dsap, dsaq, dsag); + privateKey.Initialize(dsap, dsaq, dsag, dsax); privateKey.MakePublicKey(publicKey); privateKey.GetPrivateExponent().Encode( signingPrivateKey, @@ -76,5 +116,300 @@ void CreateDSARandomKeys( DSA_PUBLIC_KEY_LENGTH); } +DSAVerifier_Pimpl::DSAVerifier_Pimpl( + const uint8_t* signingKey) { + m_PublicKey.Initialize( + dsap, + dsaq, + dsag, + CryptoPP::Integer( + signingKey, + DSA_PUBLIC_KEY_LENGTH)); +} + +bool DSAVerifier_Pimpl::Verify( + const uint8_t* buf, + size_t len, + const uint8_t* signature) const { + CryptoPP::DSA::Verifier verifier(m_PublicKey); + return verifier.VerifyMessage(buf, len, signature, DSA_SIGNATURE_LENGTH); +} + +// ECDSAP256 +ECDSAP256Verifier::ECDSAP256Verifier( + const uint8_t* signingKey) + : m_Impl( + new ECDSAP256Verifier_Pimpl(signingKey)) {} + +ECDSAP256Verifier::~ECDSAP256Verifier() { + delete m_Impl; +} + +bool ECDSAP256Verifier::Verify( + const uint8_t* buf, + size_t len, + const uint8_t* signature) const { + return m_Impl->Verify(buf, len, signature); +} + +ECDSAP256Signer::ECDSAP256Signer( + const uint8_t* signingPrivateKey) + : m_Impl( + new ECDSAP256Signer_Pimpl(signingPrivateKey)) {} + +ECDSAP256Signer::~ECDSAP256Signer() { + delete m_Impl; +} + +void ECDSAP256Signer::Sign( + const uint8_t* buf, + size_t len, + uint8_t* signature) const { + m_Impl->Sign(buf, len, signature); +} + +// ECDSAP384 +ECDSAP384Verifier::ECDSAP384Verifier( + const uint8_t* signingKey) + : m_Impl( + new ECDSAP384Verifier_Pimpl(signingKey)) {} + +ECDSAP384Verifier::~ECDSAP384Verifier() { + delete m_Impl; +} + +bool ECDSAP384Verifier::Verify( + const uint8_t* buf, + size_t len, + const uint8_t* signature) const { + return m_Impl->Verify(buf, len, signature); +} + +ECDSAP384Signer::ECDSAP384Signer( + const uint8_t* signingPrivateKey) + : m_Impl( + new ECDSAP384Signer_Pimpl(signingPrivateKey)) {} + +ECDSAP384Signer::~ECDSAP384Signer() { + delete m_Impl; +} + +void ECDSAP384Signer::Sign( + const uint8_t* buf, + size_t len, + uint8_t * signature) const { + m_Impl->Sign(buf, len, signature); +} + +// ECDSAP521 +ECDSAP521Verifier::ECDSAP521Verifier( + const uint8_t* signingKey) + : m_Impl( + new ECDSAP521Verifier_Pimpl(signingKey)) {} + +ECDSAP521Verifier::~ECDSAP521Verifier() { + delete m_Impl; +} + +bool ECDSAP521Verifier::Verify( + const uint8_t* buf, + size_t len, + const uint8_t* signature) const { + return m_Impl->Verify(buf, len, signature); +} + +ECDSAP521Signer::ECDSAP521Signer( + const uint8_t* signingPrivateKey) + : m_Impl( + new ECDSAP521Signer_Pimpl(signingPrivateKey)) {} + +ECDSAP521Signer::~ECDSAP521Signer() { + delete m_Impl; +} + +void ECDSAP521Signer::Sign( + const uint8_t* buf, + size_t len, + uint8_t* signature) const { + m_Impl->Sign(buf, len, signature); +} + +// ECDSAP256 +void CreateECDSAP256RandomKeys( + uint8_t* signingPrivateKey, + uint8_t* signingPublicKey) { + CreateECDSARandomKeys( + CryptoPP::ASN1::secp256r1(), + ECDSAP256_KEY_LENGTH, + signingPrivateKey, + signingPublicKey); +} + +// ECDSAP384 +void CreateECDSAP384RandomKeys( + uint8_t* signingPrivateKey, + uint8_t* signingPublicKey) { + CreateECDSARandomKeys( + CryptoPP::ASN1::secp384r1(), + ECDSAP384_KEY_LENGTH, + signingPrivateKey, + signingPublicKey); +} + +// ECDSAP521 +void CreateECDSAP521RandomKeys( + uint8_t* signingPrivateKey, + uint8_t* signingPublicKey) { + CreateECDSARandomKeys( + CryptoPP::ASN1::secp521r1(), + ECDSAP521_KEY_LENGTH, + signingPrivateKey, + signingPublicKey); +} + +// RSA +void CreateRSARandomKeys( + size_t publicKeyLen, + uint8_t* signingPrivateKey, + uint8_t* signingPublicKey) { + CryptoPP::RSA::PrivateKey privateKey; + privateKey.Initialize( + prng, + publicKeyLen * 8, + rsae); + privateKey.GetModulus().Encode( + signingPrivateKey, + publicKeyLen); + privateKey.GetPrivateExponent().Encode( + signingPrivateKey + publicKeyLen, + publicKeyLen); + privateKey.GetModulus().Encode( + signingPublicKey, + publicKeyLen); + } + +// RSASHA2562048 +RSASHA2562048Signer::RSASHA2562048Signer( + const uint8_t* privateKey) + : m_Impl( + new RSASHA2562048Signer_Pimpl(privateKey)) {} + +RSASHA2562048Signer::~RSASHA2562048Signer() { + delete m_Impl; +} + +void RSASHA2562048Signer::Sign( + const uint8_t* buf, + size_t len, + uint8_t* signature) const { + m_Impl->Sign(buf, len, signature); +} + +// RSASHA3843072 +RSASHA3843072Signer::RSASHA3843072Signer( + const uint8_t* privateKey) + : m_Impl( + new RSASHA3843072Signer_Pimpl(privateKey)) {} + +RSASHA3843072Signer::~RSASHA3843072Signer() { + delete m_Impl; +} + +void RSASHA3843072Signer::Sign( + const uint8_t* buf, + size_t len, + uint8_t* signature) const { + m_Impl->Sign(buf, len, signature); +} + +// RSASHA5124096 +RSASHA5124096Signer::RSASHA5124096Signer( + const uint8_t* privateKey) + : m_Impl( + new RSASHA5124096Signer_Pimpl(privateKey)) {} + +RSASHA5124096Signer::~RSASHA5124096Signer() { + delete m_Impl; +} + +void RSASHA5124096Signer::Sign( + const uint8_t* buf, + size_t len, + uint8_t* signature) const { + m_Impl->Sign(buf, len, signature); +} + +// RSASHA2562048 +RSASHA2562048Verifier::RSASHA2562048Verifier( + const uint8_t* pubKey) + : m_Impl( + new RSASHA2562048Verifier_Pimpl(pubKey)) {} + +RSASHA2562048Verifier::~RSASHA2562048Verifier() { + delete m_Impl; +} + +bool RSASHA2562048Verifier::Verify( + const uint8_t* buf, + size_t len, + const uint8_t* signature) const { + return m_Impl->Verify(buf, len, signature); +} + +// RSASHA3843072 +RSASHA3843072Verifier::RSASHA3843072Verifier( + const uint8_t* pubKey) + : m_Impl( + new RSASHA3843072Verifier_Pimpl(pubKey)) {} + +RSASHA3843072Verifier::~RSASHA3843072Verifier() { + delete m_Impl; +} + +bool RSASHA3843072Verifier::Verify( + const uint8_t* buf, + size_t len, + const uint8_t* signature) const { + return m_Impl->Verify(buf, len, signature); +} + +// RSASHA5124096 +RSASHA5124096Verifier::RSASHA5124096Verifier( + const uint8_t* pubKey) + : m_Impl( + new RSASHA5124096Verifier_Pimpl(pubKey)) {} + +RSASHA5124096Verifier::~RSASHA5124096Verifier() { + delete m_Impl; +} + +bool RSASHA5124096Verifier::Verify( + const uint8_t* buf, + size_t len, + const uint8_t* signature) const { + return m_Impl->Verify(buf, len, signature); +} + +// RSASHA5124096 +RSASHA5124096RawVerifier::RSASHA5124096RawVerifier( + const uint8_t* signingKey) + : m_Impl( + new RSASHA5124096RawVerifier_Pimpl(signingKey)) {} + +RSASHA5124096RawVerifier::~RSASHA5124096RawVerifier() { + delete m_Impl; +} + +void RSASHA5124096RawVerifier::Update( + const uint8_t* buf, + size_t len) { + m_Impl->Update(buf, len); +} + +bool RSASHA5124096RawVerifier::Verify( + const uint8_t* signature) { + return m_Impl->Verify(signature); +} + } // namespace crypto } // namespace i2p diff --git a/src/core/crypto/Signature.h b/src/core/crypto/Signature.h index 43c006c9..40c79436 100644 --- a/src/core/crypto/Signature.h +++ b/src/core/crypto/Signature.h @@ -31,16 +31,8 @@ #ifndef SRC_CORE_CRYPTO_SIGNATURE_H_ #define SRC_CORE_CRYPTO_SIGNATURE_H_ -#include -#include -#include -#include -#include -#include - #include -#include "CryptoConst.h" #include "EdDSA25519.h" #include "SignatureBase.h" @@ -51,27 +43,18 @@ const size_t DSA_PUBLIC_KEY_LENGTH = 128; const size_t DSA_SIGNATURE_LENGTH = 40; const size_t DSA_PRIVATE_KEY_LENGTH = DSA_SIGNATURE_LENGTH/2; -class DSAVerifier - : public Verifier { +// DSAVerifier +class DSAVerifier_Pimpl; +class DSAVerifier : public Verifier { public: DSAVerifier( - const uint8_t* signingKey) { - m_PublicKey.Initialize( - dsap, - dsaq, - dsag, - CryptoPP::Integer( - signingKey, - DSA_PUBLIC_KEY_LENGTH)); - } + const uint8_t* signingKey); + ~DSAVerifier(); bool Verify( const uint8_t* buf, size_t len, - const uint8_t* signature) const { - CryptoPP::DSA::Verifier verifier(m_PublicKey); - return verifier.VerifyMessage(buf, len, signature, DSA_SIGNATURE_LENGTH); - } + const uint8_t* signature) const; size_t GetPublicKeyLen() const { return DSA_PUBLIC_KEY_LENGTH; @@ -81,376 +64,339 @@ class DSAVerifier return DSA_SIGNATURE_LENGTH; } + size_t GetPrivateKeyLen() const { + return DSA_PRIVATE_KEY_LENGTH; + } + private: - CryptoPP::DSA::PublicKey m_PublicKey; + DSAVerifier_Pimpl* m_Impl; }; -class DSASigner - : public Signer { +// DSASigner +class DSASigner_Pimpl; +class DSASigner : public Signer { public: - DSASigner( + explicit DSASigner( const uint8_t* signingPrivateKey); + ~DSASigner(); void Sign( - CryptoPP::RandomNumberGenerator& rnd, const uint8_t* buf, - int len, + size_t len, uint8_t* signature) const; private: - CryptoPP::DSA::PrivateKey m_PrivateKey; + DSASigner_Pimpl* m_Impl; }; void CreateDSARandomKeys( - CryptoPP::RandomNumberGenerator& rnd, uint8_t* signingPrivateKey, uint8_t* signingPublicKey); -template -class ECDSAVerifier - : public Verifier { +// ECDSA_SHA256_P256 +const size_t ECDSAP256_KEY_LENGTH = 64; +// ECDSAP256Verifier +class ECDSAP256Verifier_Pimpl; +class ECDSAP256Verifier : public Verifier { public: - template - ECDSAVerifier( - Curve curve, - const uint8_t* signingKey) { - m_PublicKey.Initialize( - curve, - CryptoPP::ECP::Point( - CryptoPP::Integer( - signingKey, - keyLen / 2), - CryptoPP::Integer( - signingKey + keyLen / 2, keyLen / 2))); - } + ECDSAP256Verifier( + const uint8_t * signingKey); + ~ECDSAP256Verifier(); bool Verify( const uint8_t* buf, size_t len, - const uint8_t * signature) const { - typename CryptoPP::ECDSA::Verifier verifier(m_PublicKey); - return verifier.VerifyMessage( - buf, len, signature, keyLen); // signature length - } + const uint8_t* signature) const; size_t GetPublicKeyLen() const { - return keyLen; + return ECDSAP256_KEY_LENGTH; } size_t GetSignatureLen() const { - return keyLen; // signature length = key length + return ECDSAP256_KEY_LENGTH; + } + + size_t GetPrivateKeyLen() const { + return ECDSAP256_KEY_LENGTH / 2; } private: - typename CryptoPP::ECDSA::PublicKey m_PublicKey; + ECDSAP256Verifier_Pimpl* m_Impl; }; -template -class ECDSASigner - : public Signer { - public: - template - ECDSASigner( - Curve curve, - const uint8_t* signingPrivateKey, - size_t keyLen) { - m_PrivateKey.Initialize( - curve, - CryptoPP::Integer( - signingPrivateKey, - keyLen/2)); // private key length - } +// ECDSAP256Signer +class ECDSAP256Signer_Pimpl; +struct ECDSAP256Signer : public Signer { + explicit ECDSAP256Signer( + const uint8_t* signingPrivateKey); + ~ECDSAP256Signer(); void Sign( - CryptoPP::RandomNumberGenerator& rnd, const uint8_t* buf, - int len, - uint8_t* signature) const { - typename CryptoPP::ECDSA::Signer signer(m_PrivateKey); - signer.SignMessage(rnd, buf, len, signature); - } + size_t len, + uint8_t* signature) const; private: - typename CryptoPP::ECDSA::PrivateKey m_PrivateKey; -}; - -template -inline void CreateECDSARandomKeys( - CryptoPP::RandomNumberGenerator& rnd, - Curve curve, - size_t keyLen, - uint8_t* signingPrivateKey, - uint8_t* signingPublicKey) { - typename CryptoPP::ECDSA::PrivateKey privateKey; - typename CryptoPP::ECDSA::PublicKey publicKey; - privateKey.Initialize(rnd, curve); - privateKey.MakePublicKey(publicKey); - privateKey.GetPrivateExponent().Encode(signingPrivateKey, keyLen / 2); - auto q = publicKey.GetPublicElement(); - q.x.Encode(signingPublicKey, keyLen / 2); - q.y.Encode(signingPublicKey + keyLen / 2, keyLen / 2); -} - -// ECDSA_SHA256_P256 -const size_t ECDSAP256_KEY_LENGTH = 64; - -struct ECDSAP256Verifier - : public ECDSAVerifier { - ECDSAP256Verifier( - const uint8_t * signingKey) - : ECDSAVerifier( - CryptoPP::ASN1::secp256r1(), - signingKey) {} -}; - -struct ECDSAP256Signer - : public ECDSASigner { - explicit ECDSAP256Signer( - const uint8_t* signingPrivateKey) - : ECDSASigner( - CryptoPP::ASN1::secp256r1(), - signingPrivateKey, - ECDSAP256_KEY_LENGTH) {} + ECDSAP256Signer_Pimpl* m_Impl; }; -inline void CreateECDSAP256RandomKeys( - CryptoPP::RandomNumberGenerator& rnd, +void CreateECDSAP256RandomKeys( uint8_t* signingPrivateKey, - uint8_t* signingPublicKey) { - CreateECDSARandomKeys( - rnd, - CryptoPP::ASN1::secp256r1(), - ECDSAP256_KEY_LENGTH, - signingPrivateKey, - signingPublicKey); -} + uint8_t* signingPublicKey); // ECDSA_SHA384_P384 const size_t ECDSAP384_KEY_LENGTH = 96; -class ECDSAP384Verifier - : public ECDSAVerifier { +// ECDSAP384Verifier +class ECDSAP384Verifier_Pimpl; +class ECDSAP384Verifier : public Verifier { public: ECDSAP384Verifier( - const uint8_t * signingKey): - - ECDSAVerifier( - CryptoPP::ASN1::secp384r1(), - signingKey) {} -}; + const uint8_t * signingKey); + ~ECDSAP384Verifier(); -class ECDSAP384Signer - : public ECDSASigner { - public: - ECDSAP384Signer( - const uint8_t * signingPrivateKey): + bool Verify( + const uint8_t* buf, + size_t len, + const uint8_t* signature) const; - ECDSASigner( - CryptoPP::ASN1::secp384r1(), - signingPrivateKey, - ECDSAP384_KEY_LENGTH) {} -}; + size_t GetPublicKeyLen() const { + return ECDSAP384_KEY_LENGTH; + } -inline void CreateECDSAP384RandomKeys( - CryptoPP::RandomNumberGenerator& rnd, - uint8_t* signingPrivateKey, - uint8_t* signingPublicKey) { - CreateECDSARandomKeys( - rnd, - CryptoPP::ASN1::secp384r1(), - ECDSAP384_KEY_LENGTH, - signingPrivateKey, - signingPublicKey); -} + size_t GetSignatureLen() const { + return ECDSAP384_KEY_LENGTH; + } -// ECDSA_SHA512_P521 -const size_t ECDSAP521_KEY_LENGTH = 132; -class ECDSAP521Verifier - : public ECDSAVerifier { - public: - ECDSAP521Verifier( - const uint8_t * signingKey): + size_t GetPrivateKeyLen() const { + return ECDSAP384_KEY_LENGTH / 2; + } - ECDSAVerifier( - CryptoPP::ASN1::secp521r1(), - signingKey) {} + private: + ECDSAP384Verifier_Pimpl* m_Impl; }; -class ECDSAP521Signer - : public ECDSASigner { - public: - ECDSAP521Signer( - const uint8_t * signingPrivateKey): +// ECDSAP384Signer +class ECDSAP384Signer_Pimpl; +struct ECDSAP384Signer : public Signer { + explicit ECDSAP384Signer( + const uint8_t* signingPrivateKey); + ~ECDSAP384Signer(); - ECDSASigner( - CryptoPP::ASN1::secp521r1(), - signingPrivateKey, - ECDSAP521_KEY_LENGTH) {} + void Sign( + const uint8_t* buf, + size_t len, + uint8_t* signature) const; + + private: + ECDSAP384Signer_Pimpl* m_Impl; }; -inline void CreateECDSAP521RandomKeys( - CryptoPP::RandomNumberGenerator& rnd, +void CreateECDSAP384RandomKeys( uint8_t* signingPrivateKey, - uint8_t* signingPublicKey) { - CreateECDSARandomKeys( - rnd, - CryptoPP::ASN1::secp521r1(), - ECDSAP521_KEY_LENGTH, - signingPrivateKey, - signingPublicKey); -} - -// RSA -template -class RSAVerifier - : public Verifier { + uint8_t* signingPublicKey); + +// ECDSA_SHA512_P521 +const size_t ECDSAP521_KEY_LENGTH = 132; +// ECDSAP521Verifier +class ECDSAP521Verifier_Pimpl; +class ECDSAP521Verifier : public Verifier { public: - explicit RSAVerifier( - const uint8_t* signingKey) { - m_PublicKey.Initialize( - CryptoPP::Integer( - signingKey, - keyLen), - CryptoPP::Integer( - rsae)); - } + ECDSAP521Verifier( + const uint8_t* signingKey); + ~ECDSAP521Verifier(); bool Verify( const uint8_t* buf, size_t len, - const uint8_t* signature) const { - typename CryptoPP::RSASS::Verifier verifier(m_PublicKey); - return verifier.VerifyMessage(buf, len, signature, keyLen); // signature length - } + const uint8_t* signature) const; size_t GetPublicKeyLen() const { - return keyLen; + return ECDSAP521_KEY_LENGTH; } size_t GetSignatureLen() const { - return keyLen; + return ECDSAP521_KEY_LENGTH; } size_t GetPrivateKeyLen() const { - return GetSignatureLen() * 2; + return ECDSAP521_KEY_LENGTH / 2; } private: - CryptoPP::RSA::PublicKey m_PublicKey; + ECDSAP521Verifier_Pimpl* m_Impl; }; - -template -class RSASigner - : public Signer { - public: - RSASigner( - const uint8_t* signingPrivateKey, - size_t keyLen) { - m_PrivateKey.Initialize( - CryptoPP::Integer( - signingPrivateKey, - keyLen / 2), - rsae, - CryptoPP::Integer( - signingPrivateKey + keyLen/2, - keyLen/2)); - } +// ECDSAP521Signer +class ECDSAP521Signer_Pimpl; +struct ECDSAP521Signer : public Signer { + explicit ECDSAP521Signer( + const uint8_t* signingPrivateKey); + ~ECDSAP521Signer(); void Sign( - CryptoPP::RandomNumberGenerator& rnd, const uint8_t* buf, - int len, - uint8_t* signature) const { - typename CryptoPP::RSASS::Signer signer(m_PrivateKey); - signer.SignMessage(rnd, buf, len, signature); - } + size_t len, + uint8_t* signature) const; private: - CryptoPP::RSA::PrivateKey m_PrivateKey; + ECDSAP521Signer_Pimpl* m_Impl; }; -inline void CreateRSARandomKeys( - CryptoPP::RandomNumberGenerator& rnd, - size_t publicKeyLen, +void CreateECDSAP521RandomKeys( uint8_t* signingPrivateKey, - uint8_t* signingPublicKey) { - CryptoPP::RSA::PrivateKey privateKey; - privateKey.Initialize( - rnd, - publicKeyLen * 8, - rsae); - privateKey.GetModulus().Encode( - signingPrivateKey, - publicKeyLen); - privateKey.GetPrivateExponent().Encode( - signingPrivateKey + publicKeyLen, - publicKeyLen); - privateKey.GetModulus().Encode( - signingPublicKey, - publicKeyLen); -} - - -// RSA_SHA256_2048 + uint8_t* signingPublicKey); + +// RSA_SHA256_2048 const size_t RSASHA2562048_KEY_LENGTH = 256; -class RSASHA2562048Verifier - : public RSAVerifier { +// RSASHA2562048Verifier +class RSASHA2562048Verifier_Pimpl; +class RSASHA2562048Verifier : public Verifier { public: - RSASHA2562048Verifier( - const uint8_t* signingKey) - : RSAVerifier(signingKey) {} + explicit RSASHA2562048Verifier( + const uint8_t* signingKey); + ~RSASHA2562048Verifier(); + + size_t GetPublicKeyLen() const { + return RSASHA2562048_KEY_LENGTH; + } + + size_t GetSignatureLen() const { + return RSASHA2562048_KEY_LENGTH; + } + + size_t GetPrivateKeyLen() const { + return RSASHA2562048_KEY_LENGTH * 2; + } + + bool Verify( + const uint8_t* buf, + size_t len, + const uint8_t* signature) const; + + private: + RSASHA2562048Verifier_Pimpl* m_Impl; }; -class RSASHA2562048Signer - : public RSASigner { +// RSASHA2562048Signer +class RSASHA2562048Signer_Pimpl; +class RSASHA2562048Signer : public Signer { public: - RSASHA2562048Signer( - const uint8_t* signingPrivateKey) - : RSASigner( - signingPrivateKey, - RSASHA2562048_KEY_LENGTH * 2) {} + explicit RSASHA2562048Signer( + const uint8_t* signingPrivateKey); + ~RSASHA2562048Signer(); + + void Sign( + const uint8_t* buf, + size_t len, + uint8_t* signature) const; + + private: + RSASHA2562048Signer_Pimpl* m_Impl; }; // RSA_SHA384_3072 const size_t RSASHA3843072_KEY_LENGTH = 384; -class RSASHA3843072Verifier - : public RSAVerifier { +// RSASHA3843072Verifier +class RSASHA3843072Verifier_Pimpl; +class RSASHA3843072Verifier : public Verifier { public: - RSASHA3843072Verifier( - const uint8_t* signingKey) - : RSAVerifier(signingKey) {} + explicit RSASHA3843072Verifier( + const uint8_t* signingKey); + ~RSASHA3843072Verifier(); + + size_t GetPublicKeyLen() const { + return RSASHA3843072_KEY_LENGTH; + } + + size_t GetSignatureLen() const { + return RSASHA3843072_KEY_LENGTH; + } + + size_t GetPrivateKeyLen() const { + return RSASHA3843072_KEY_LENGTH * 2; + } + + bool Verify( + const uint8_t* buf, + size_t len, + const uint8_t* signature) const; + + private: + RSASHA3843072Verifier_Pimpl* m_Impl; }; -class RSASHA3843072Signer - : public RSASigner { +// RSASHA3843072Signer +class RSASHA3843072Signer_Pimpl; +class RSASHA3843072Signer : public Signer { public: - RSASHA3843072Signer( - const uint8_t * signingPrivateKey) - : RSASigner( - signingPrivateKey, - RSASHA3843072_KEY_LENGTH * 2) {} + explicit RSASHA3843072Signer( + const uint8_t* signingPrivateKey); + ~RSASHA3843072Signer(); + + void Sign( + const uint8_t* buf, + size_t len, + uint8_t* signature) const; + + private: + RSASHA3843072Signer_Pimpl* m_Impl; }; // RSA_SHA512_4096 const size_t RSASHA5124096_KEY_LENGTH = 512; -class RSASHA5124096Verifier - : public RSAVerifier { +// RSASHA5124096Verifier +class RSASHA5124096Verifier_Pimpl; +class RSASHA5124096Verifier : public Verifier { public: - RSASHA5124096Verifier( - const uint8_t* signingKey) - : RSAVerifier(signingKey) {} + explicit RSASHA5124096Verifier( + const uint8_t* signingKey); + ~RSASHA5124096Verifier(); + + size_t GetPublicKeyLen() const { + return RSASHA5124096_KEY_LENGTH; + } + + size_t GetSignatureLen() const { + return RSASHA5124096_KEY_LENGTH; + } + + size_t GetPrivateKeyLen() const { + return RSASHA5124096_KEY_LENGTH * 2; + } + + bool Verify( + const uint8_t* buf, + size_t len, + const uint8_t* signature) const; + + private: + RSASHA5124096Verifier_Pimpl* m_Impl; }; -class RSASHA5124096Signer - : public RSASigner { +// RSASHA5124096Signer +class RSASHA5124096Signer_Pimpl; +class RSASHA5124096Signer : public Signer { public: - RSASHA5124096Signer( - const uint8_t* signingPrivateKey) - : RSASigner( - signingPrivateKey, - RSASHA5124096_KEY_LENGTH * 2) {} + explicit RSASHA5124096Signer( + const uint8_t* signingPrivateKey); + ~RSASHA5124096Signer(); + + void Sign( + const uint8_t* buf, + size_t len, + uint8_t * signature) const; + + private: + RSASHA5124096Signer_Pimpl* m_Impl; }; +void CreateRSARandomKeys( + size_t publicKeyLen, + uint8_t* signingPrivateKey, + uint8_t* signingPublicKey); + +// TODO(unassigned): ??? +/* // Raw verifiers class RawVerifier { public: @@ -506,13 +452,26 @@ class RSARawVerifier CryptoPP::Integer n; // RSA modulus Hash m_Hash; }; +*/ -class RSASHA5124096RawVerifier - : public RSARawVerifier { +// RSASHA5124096RawVerifier +class RSASHA5124096RawVerifier_Pimpl; +class RSASHA5124096RawVerifier : public RawVerifier { +// public RSARawVerifier { public: - RSASHA5124096RawVerifier( - const uint8_t* signingKey) - : RSARawVerifier(signingKey) {} + explicit RSASHA5124096RawVerifier( + const uint8_t* signingKey); + ~RSASHA5124096RawVerifier(); + + bool Verify( + const uint8_t* signature); + + void Update( + const uint8_t* signature, + size_t len); + + private: + RSASHA5124096RawVerifier_Pimpl* m_Impl; }; } // namespace crypto diff --git a/src/core/crypto/SignatureBase.h b/src/core/crypto/SignatureBase.h index 0a8ed7c9..0a9096eb 100644 --- a/src/core/crypto/SignatureBase.h +++ b/src/core/crypto/SignatureBase.h @@ -45,21 +45,30 @@ class Verifier { const uint8_t* signature) const = 0; virtual size_t GetPublicKeyLen() const = 0; virtual size_t GetSignatureLen() const = 0; - virtual size_t GetPrivateKeyLen() const { - return GetSignatureLen() / 2; - } + virtual size_t GetPrivateKeyLen() const = 0; }; class Signer { public: virtual ~Signer() {} virtual void Sign( - CryptoPP::RandomNumberGenerator& rnd, const uint8_t* buf, - int len, + size_t len, uint8_t* signature) const = 0; }; +class RawVerifier { + public: + virtual ~RawVerifier() {} + + virtual void Update( + const uint8_t* buf, + size_t len) = 0; + + virtual bool Verify( + const uint8_t* signature) = 0; +}; + } // namespace crypto } // namespace i2p diff --git a/src/core/transport/SSU.cpp b/src/core/transport/SSU.cpp index a275d2c4..5b418e44 100644 --- a/src/core/transport/SSU.cpp +++ b/src/core/transport/SSU.cpp @@ -38,6 +38,7 @@ #include #include +#include "crypto/Rand.h" #include "NetworkDatabase.h" #include "RouterContext.h" #include "util/Log.h" @@ -481,10 +482,11 @@ std::shared_ptr SSUServer::GetRandomSession( if (filter (s.second)) filteredSessions.push_back(s.second); if (filteredSessions.size() > 0) { - auto ind = - i2p::context.GetRandomNumberGenerator().GenerateWord32( - 0, - filteredSessions.size() - 1); + size_t s = filteredSessions.size(); + size_t ind = + i2p::crypto::RandInRange( + size_t{0}, + s - 1); return filteredSessions[ind]; } return nullptr; diff --git a/src/core/transport/SSUSession.cpp b/src/core/transport/SSUSession.cpp index 46ea64e5..9cdd9c2a 100644 --- a/src/core/transport/SSUSession.cpp +++ b/src/core/transport/SSUSession.cpp @@ -40,6 +40,7 @@ #include "RouterContext.h" #include "SSU.h" #include "Transports.h" +#include "crypto/Rand.h" #include "crypto/CryptoConst.h" #include "util/Log.h" #include "util/Timestamp.h" @@ -448,9 +449,8 @@ void SSUSession::SendSessionRequest() { 16); } uint8_t iv[16]; - CryptoPP::RandomNumberGenerator& rnd = - i2p::context.GetRandomNumberGenerator(); - rnd.GenerateBlock(iv, 16); // random iv + i2p::crypto::RandBytes(iv, 16); + FillHeaderAndEncrypt( PAYLOAD_TYPE_SESSION_REQUEST, buf, @@ -484,11 +484,9 @@ void SSUSession::SendRelayRequest( payload++; memcpy(payload, (const uint8_t *)address->key, 32); payload += 32; - CryptoPP::RandomNumberGenerator& rnd = - i2p::context.GetRandomNumberGenerator(); - htobe32buf(payload, rnd.GenerateWord32()); // nonce + htobe32buf(payload, i2p::crypto::Rand()); // nonce uint8_t iv[16]; - rnd.GenerateBlock(iv, 16); // random iv + i2p::crypto::RandBytes(iv, 16); if (m_State == eSessionStateEstablished) { FillHeaderAndEncrypt( PAYLOAD_TYPE_RELAY_REQUEST, @@ -522,8 +520,6 @@ void SSUSession::SendSessionCreated( LogPrint(eLogError, "SSU is not supported"); return; } - CryptoPP::RandomNumberGenerator& rnd = - i2p::context.GetRandomNumberGenerator(); // x,y, remote IP, remote port, our IP, our port, relayTag, signed on time SignedData s; s.Insert(x, 256); // x @@ -563,7 +559,7 @@ void SSUSession::SendSessionCreated( s.Insert (htobe16(address->port)); // our port uint32_t relayTag = 0; if (i2p::context.GetRouterInfo().IsIntroducer()) { - relayTag = rnd.GenerateWord32(); + relayTag = i2p::crypto::Rand(); if (!relayTag) relayTag = 1; m_Server.AddRelay(relayTag, m_RemoteEndpoint); @@ -577,14 +573,15 @@ void SSUSession::SendSessionCreated( m_SessionConfirmData = std::unique_ptr(new SignedData(s)); s.Insert(payload - 4, 4); // put timestamp s.Sign(i2p::context.GetPrivateKeys(), payload); // DSA signature - // TODO(unassigned): fill padding with random data uint8_t iv[16]; - rnd.GenerateBlock(iv, 16); // random iv + i2p::crypto::RandBytes(iv, 16); // encrypt signature and padding with newly created session key size_t signatureLen = i2p::context.GetIdentity().GetSignatureLen(); size_t paddingSize = signatureLen & 0x0F; // %16 - if (paddingSize > 0) + if (paddingSize > 0) { signatureLen += (16 - paddingSize); + i2p::crypto::RandBytes(payload, paddingSize); + } m_SessionKeyEncryption.SetIV(iv); m_SessionKeyEncryption.Encrypt( payload, @@ -592,16 +589,18 @@ void SSUSession::SendSessionCreated( payload); payload += signatureLen; size_t msgLen = payload - buf; - // encrypt message with intro key - FillHeaderAndEncrypt( + if (msgLen <= SSU_MTU_V4 ) { + // encrypt message with intro key + FillHeaderAndEncrypt( PAYLOAD_TYPE_SESSION_CREATED, buf, msgLen, introKey, iv, introKey); - // send it - Send(buf, msgLen); + // send it + Send(buf, msgLen); + } } void SSUSession::SendSessionConfirmed( @@ -646,9 +645,7 @@ void SSUSession::SendSessionConfirmed( payload += signatureLen; size_t msgLen = payload - buf; uint8_t iv[16]; - CryptoPP::RandomNumberGenerator& rnd = - i2p::context.GetRandomNumberGenerator(); - rnd.GenerateBlock(iv, 16); // random iv + i2p::crypto::RandBytes(iv, 16); // encrypt message with session key FillHeaderAndEncrypt( PAYLOAD_TYPE_SESSION_CONFIRMED, @@ -735,9 +732,7 @@ void SSUSession::SendRelayResponse( } else { // encrypt with Alice's intro key uint8_t iv[16]; - CryptoPP::RandomNumberGenerator& rnd = - i2p::context.GetRandomNumberGenerator(); - rnd.GenerateBlock(iv, 16); // random iv + i2p::crypto::RandBytes(iv, 16); FillHeaderAndEncrypt( PAYLOAD_TYPE_RELAY_RESPONSE, buf, @@ -773,9 +768,7 @@ void SSUSession::SendRelayIntro( payload += 2; // port *payload = 0; // challenge size uint8_t iv[16]; - CryptoPP::RandomNumberGenerator& rnd = - i2p::context.GetRandomNumberGenerator(); - rnd.GenerateBlock(iv, 16); // random iv + i2p::crypto::RandBytes(iv, 16); // random iv FillHeaderAndEncrypt( PAYLOAD_TYPE_RELAY_INTRO, buf, @@ -882,9 +875,7 @@ void SSUSession::FillHeaderAndEncrypt( return; } SSUSessionPacket pkt(buf, len); - i2p::context.GetRandomNumberGenerator().GenerateBlock( - pkt.IV(), - 16); // random iv + i2p::crypto::RandBytes(pkt.IV(), 16); // random iv m_SessionKeyEncryption.SetIV(pkt.IV()); pkt.PutFlag(payloadType << 4); // MSB is 0 pkt.PutTime(i2p::util::GetSecondsSinceEpoch()); @@ -1286,10 +1277,8 @@ void SSUSession::SendPeerTest( memcpy(payload, introKey, 32); // intro key } // send - CryptoPP::RandomNumberGenerator& rnd = - i2p::context.GetRandomNumberGenerator(); uint8_t iv[16]; - rnd.GenerateBlock(iv, 16); // random iv + i2p::crypto::RandBytes(iv, 16); if (toAddress) { // encrypt message with specified intro key FillHeaderAndEncrypt( @@ -1322,7 +1311,7 @@ void SSUSession::SendPeerTest() { LogPrint(eLogError, "SSU is not supported. Can't send peer test"); return; } - uint32_t nonce = i2p::context.GetRandomNumberGenerator().GenerateWord32(); + uint32_t nonce = i2p::crypto::Rand(); if (!nonce) nonce = 1; m_PeerTest = false; diff --git a/src/core/transport/Transports.cpp b/src/core/transport/Transports.cpp index 8a4c49fb..415313a1 100644 --- a/src/core/transport/Transports.cpp +++ b/src/core/transport/Transports.cpp @@ -36,10 +36,12 @@ #include #include + #include "I2NPProtocol.h" #include "NetworkDatabase.h" #include "RouterContext.h" #include "crypto/CryptoConst.h" +#include "crypto/Rand.h" #include "util/Log.h" // TODO(anonimal): don't use using-directive @@ -552,14 +554,11 @@ void Transports::HandlePeerCleanupTimer( std::shared_ptr Transports::GetRandomPeer() const { if (m_Peers.empty()) // ensure m.Peers.size() >= 1 return nullptr; - CryptoPP::RandomNumberGenerator& rnd = - i2p::context.GetRandomNumberGenerator(); + size_t s = m_Peers.size(); auto it = m_Peers.begin(); std::advance( it, - rnd.GenerateWord32( - 0, - m_Peers.size() - 1)); + i2p::crypto::RandInRange(0, s - 1)); return it->second.router; } diff --git a/src/core/tunnel/Tunnel.cpp b/src/core/tunnel/Tunnel.cpp index db4b2128..2b646c8b 100644 --- a/src/core/tunnel/Tunnel.cpp +++ b/src/core/tunnel/Tunnel.cpp @@ -37,6 +37,7 @@ #include #include +#include "crypto/Rand.h" #include "I2NPProtocol.h" #include "NetworkDatabase.h" #include "RouterContext.h" @@ -61,8 +62,6 @@ Tunnel::~Tunnel() {} void Tunnel::Build( uint32_t replyMsgID, std::shared_ptr outboundTunnel) { - CryptoPP::RandomNumberGenerator& rnd = - i2p::context.GetRandomNumberGenerator(); auto numHops = m_Config->GetNumHops(); int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : @@ -84,7 +83,7 @@ void Tunnel::Build( hop->CreateBuildRequestRecord( records + idx * TUNNEL_BUILD_RECORD_SIZE, // we set replyMsgID for last hop only - hop->next ? rnd.GenerateWord32() : replyMsgID); + hop->next ? i2p::crypto::Rand() : replyMsgID); hop->recordIndex = idx; i++; hop = hop->next; @@ -92,7 +91,7 @@ void Tunnel::Build( // fill up fake records with random data for (int i = numHops; i < numRecords; i++) { int idx = recordIndicies[i]; - rnd.GenerateBlock( + i2p::crypto::RandBytes( records + idx * TUNNEL_BUILD_RECORD_SIZE, TUNNEL_BUILD_RECORD_SIZE); } @@ -310,9 +309,9 @@ std::shared_ptr Tunnels::GetNextInboundTunnel() { } std::shared_ptr Tunnels::GetNextOutboundTunnel() { - CryptoPP::RandomNumberGenerator& rnd = - i2p::context.GetRandomNumberGenerator(); - uint32_t ind = rnd.GenerateWord32(0, m_OutboundTunnels.size() - 1); + // TODO(unassigned): integer size + uint32_t s = m_OutboundTunnels.size(); + uint32_t ind = i2p::crypto::RandInRange(uint32_t{0}, s - 1); uint32_t i = 0; std::shared_ptr tunnel; for (auto it : m_OutboundTunnels) { @@ -677,8 +676,7 @@ std::shared_ptr Tunnels::CreateTunnel( std::shared_ptr config, std::shared_ptr outboundTunnel) { auto newTunnel = std::make_shared (config); - uint32_t replyMsgID = - i2p::context.GetRandomNumberGenerator().GenerateWord32(); + uint32_t replyMsgID = i2p::crypto::Rand(); AddPendingTunnel(replyMsgID, newTunnel); newTunnel->Build(replyMsgID, outboundTunnel); return newTunnel; diff --git a/src/core/tunnel/TunnelConfig.cpp b/src/core/tunnel/TunnelConfig.cpp index 2c80e6fd..020c8d31 100644 --- a/src/core/tunnel/TunnelConfig.cpp +++ b/src/core/tunnel/TunnelConfig.cpp @@ -30,6 +30,9 @@ #include "TunnelConfig.h" +#include + +#include "crypto/Rand.h" #include "I2NPProtocol.h" #include "RouterContext.h" #include "util/Timestamp.h" @@ -39,14 +42,12 @@ namespace tunnel { TunnelHopConfig::TunnelHopConfig( std::shared_ptr r) { - CryptoPP::RandomNumberGenerator& rnd = - i2p::context.GetRandomNumberGenerator(); - rnd.GenerateBlock(layerKey, 32); - rnd.GenerateBlock(ivKey, 32); - rnd.GenerateBlock(replyKey, 32); - rnd.GenerateBlock(replyIV, 16); - rnd.GenerateBlock(randPad, 29); - tunnelID = rnd.GenerateWord32(); + i2p::crypto::RandBytes(layerKey, 32); + i2p::crypto::RandBytes(ivKey, 32); + i2p::crypto::RandBytes(replyKey, 32); + i2p::crypto::RandBytes(replyIV, 16); + i2p::crypto::RandBytes(randPad, 29); + tunnelID = i2p::crypto::Rand(); isGateway = true; isEndpoint = true; router = r; @@ -60,9 +61,7 @@ void TunnelHopConfig::SetNextRouter( std::shared_ptr r) { nextRouter = r; isEndpoint = false; - CryptoPP::RandomNumberGenerator& rnd = - i2p::context.GetRandomNumberGenerator(); - nextTunnelID = rnd.GenerateWord32(); + nextTunnelID = i2p::crypto::Rand(); } void TunnelHopConfig::SetReplyHop( diff --git a/src/core/tunnel/TunnelGateway.cpp b/src/core/tunnel/TunnelGateway.cpp index 6b456e8e..09844366 100644 --- a/src/core/tunnel/TunnelGateway.cpp +++ b/src/core/tunnel/TunnelGateway.cpp @@ -34,6 +34,7 @@ #include "RouterContext.h" #include "TunnelGateway.h" +#include "crypto/Rand.h" #include "transport/Transports.h" #include "util/I2PEndian.h" #include "util/Log.h" @@ -46,7 +47,7 @@ TunnelGatewayBuffer::TunnelGatewayBuffer( : m_TunnelID(tunnelID), m_CurrentTunnelDataMsg(nullptr), m_RemainingSize(0) { - context.GetRandomNumberGenerator().GenerateBlock( + i2p::crypto::RandBytes( m_NonZeroRandomBuffer, TUNNEL_DATA_MAX_PAYLOAD_SIZE); for (size_t i = 0; i < TUNNEL_DATA_MAX_PAYLOAD_SIZE; i++) @@ -193,19 +194,18 @@ void TunnelGatewayBuffer::CompleteCurrentTunnelDataMessage() { m_CurrentTunnelDataMsg->len - TUNNEL_DATA_MSG_SIZE - I2NP_HEADER_SIZE; uint8_t* buf = m_CurrentTunnelDataMsg->GetPayload(); htobe32buf(buf, m_TunnelID); - CryptoPP::RandomNumberGenerator& rnd = - i2p::context.GetRandomNumberGenerator(); - rnd.GenerateBlock(buf + 4, 16); // original IV + i2p::crypto::RandBytes(buf + 4, 16); // original IV memcpy(payload + size, buf + 4, 16); // copy IV for checksum uint8_t hash[32]; CryptoPP::SHA256().CalculateDigest(hash, payload, size + 16); memcpy(buf + 20, hash, 4); // checksum + // XXX: WTF?! payload[-1] = 0; // zero ptrdiff_t paddingSize = payload - buf - 25; // 25 = 24 + 1 if (paddingSize > 0) { // non-zero padding - auto randomOffset = - rnd.GenerateWord32( + uint32_t randomOffset = + i2p::crypto::RandInRange( 0, TUNNEL_DATA_MAX_PAYLOAD_SIZE - paddingSize); memcpy( diff --git a/src/core/tunnel/TunnelPool.cpp b/src/core/tunnel/TunnelPool.cpp index 373d0aea..a180ed64 100644 --- a/src/core/tunnel/TunnelPool.cpp +++ b/src/core/tunnel/TunnelPool.cpp @@ -37,6 +37,7 @@ #include "NetworkDatabase.h" #include "Tunnel.h" #include "crypto/CryptoConst.h" +#include "crypto/Rand.h" #include "transport/Transports.h" #include "util/I2PEndian.h" #include "util/Timestamp.h" @@ -180,10 +181,8 @@ typename TTunnels::value_type TunnelPool::GetNextTunnel( typename TTunnels::value_type excluded) const { if (tunnels.empty ()) return nullptr; - CryptoPP::RandomNumberGenerator& rnd = - i2p::context.GetRandomNumberGenerator(); - uint32_t ind = rnd.GenerateWord32(0, tunnels.size() / 2), - i = 0; + uint32_t ind = i2p::crypto::RandInRange(0, tunnels.size() / 2); + uint32_t i = 0; typename TTunnels::value_type tunnel = nullptr; for (auto it : tunnels) { if (it->IsEstablished() && it != excluded) { @@ -240,7 +239,6 @@ void TunnelPool::CreateTunnels() { } void TunnelPool::TestTunnels() { - auto& rnd = i2p::context.GetRandomNumberGenerator(); for (auto it : m_Tests) { LogPrint("Tunnel test ", static_cast(it.first), " failed"); // if test failed again with another tunnel we consider it failed @@ -282,7 +280,7 @@ void TunnelPool::TestTunnels() { it2++; } if (!failed) { - uint32_t msgID = rnd.GenerateWord32(); + uint32_t msgID = i2p::crypto::Rand(); m_Tests[msgID] = std::make_pair(*it1, *it2); (*it1)->SendTunnelDataMsg( (*it2)->GetNextIdentHash(), diff --git a/src/core/util/BoostLog.h b/src/core/util/BoostLog.h deleted file mode 100644 index d38f3f3f..00000000 --- a/src/core/util/BoostLog.h +++ /dev/null @@ -1,184 +0,0 @@ -/** - * Copyright (c) 2015-2016, The Kovri I2P Router Project - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SRC_CORE_UTIL_BOOSTLOG_H_ -#define SRC_CORE_UTIL_BOOSTLOG_H_ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "Log.h" - -namespace kovri { -namespace log { - -// core -typedef boost::log::core_ptr core_ptr; -// backend -typedef boost::log::sinks::text_ostream_backend backend_t; -typedef boost::shared_ptr backend_ptr; -// sink -typedef boost::log::sinks::asynchronous_sink< backend_t > sink_t; -typedef boost::shared_ptr sink_ptr; -// level -typedef boost::log::sources::severity_channel_logger_mt log_t; - -class LogStreamImpl : public std::streambuf { - public: - using int_type = typename std::streambuf::int_type; - - LogStreamImpl( - std::mutex& access, - log_t& l, - LogLevel levelno); - ~LogStreamImpl(); - - void MetaImpl( - const std::string& key, - std::string value); - - bool IsEnabled() { - return m_Enable; - } - - void Disable() { - m_Enable = false; - } - - void Enable() { - m_Enable = true; - } - - int_type overflow( - int_type ch); - - void WaitForReady(); - - protected: - using char_type = typename std::streambuf::char_type; - int sync(); - std::streamsize xsputn( - const char_type* s, - std::streamsize count); - - private: - void Flush(); - std::stringbuf* m_Str; - std::mutex& m_Access; - log_t& m_Log; - LogLevel m_Level; - bool m_Enable; -}; - -/** - * // TODO(unassigned): implement (currently unfinished) - * class BoostEventStream : public EventStream { - * public: - * virtual EventStream& Flush() const {} - * virtual EventStream& operator <<( - * const std::vector& strs) const {} - * }; - */ - -class LoggerImpl { - public: - // Construct default Logger - LoggerImpl(); - // Construct logger with a name that belongs in 1 log channel - LoggerImpl( - const std::string& name, - const std::string& channel); - - LogStream& Debug(); - - LogStream& Info(); - - LogStream& Warning(); - - LogStream& Error(); - - // TODO(unassigned): implement (currently unfinished) - //EventStream& UI() { - // return m_Events; - //} - - log_t log; - - private: - LogStream& GetLogger( - LogStream& log, - std::mutex& mtx); - - std::mutex m_DebugMtx, - m_InfoMtx, - m_WarnMtx, - m_ErrorMtx; - - LogStream m_Debug, - m_Info, - m_Warn, - m_Error; - - // TODO(unassigned): implement (currently unfinished) - //BoostEventStream m_Events; -}; - -class LogImpl { - public: - LogImpl( - LogLevel minLevel, - std::ostream* out); - LogImpl() - : LogImpl( - eLogDebug, - &std::clog) {} - - void Flush(); - - private: - backend_ptr m_LogBackend; - core_ptr m_LogCore; - static void Format( - boost::log::record_view const& rec, - boost::log::formatting_ostream &s); -}; - -} // namespace log -} // namespace kovri - -#endif // SRC_CORE_UTIL_BOOSTLOG_H_ diff --git a/src/core/util/BoostLog.cpp b/src/core/util/Log.cpp similarity index 79% rename from src/core/util/BoostLog.cpp rename to src/core/util/Log.cpp index 01730b13..5eba131e 100644 --- a/src/core/util/BoostLog.cpp +++ b/src/core/util/Log.cpp @@ -28,91 +28,21 @@ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// -// Boost.Log logging implementation -// -#include "BoostLog.h" - -#include - -#if BOOST_VERSION >= 105600 -#include -#else -// defines null_deleter here if we don't have the right boost version -#include -namespace boost { -struct null_deleter { - typedef void result_type; - template void operator() (T*) const {} -}; -} -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "Log.h" #include #include -namespace kovri { +namespace i2p { +namespace util { namespace log { -std::shared_ptr g_Log = nullptr; +static std::shared_ptr g_Log = nullptr; sink_ptr g_LogSink; -typedef boost::null_deleter boost_deleter_t; - -LogImpl::LogImpl( - LogLevel minlev, - std::ostream* out) { - m_LogCore = boost::log::core::get(); - m_LogBackend = boost::make_shared(); - m_LogBackend->add_stream( - boost::shared_ptr( - out, - boost_deleter_t())); - g_LogSink = boost::shared_ptr( - new sink_t( - m_LogBackend)); - g_LogSink->set_filter( - boost::log::expressions::attr( - "Severity") >= minlev); - g_LogSink->set_formatter(&LogImpl::Format); - m_LogCore->add_sink(g_LogSink); - m_LogCore->add_global_attribute( - "Timestamp", - boost::log::attributes::local_clock()); -} - -Log::Log( - LogLevel minlev, - std::ostream* out) { - m_LogImpl = std::make_shared(minlev, out); - m_DefaultLogger = std::make_shared(new LoggerImpl); -} - -LoggerImpl::LoggerImpl( - const std::string& name, - const std::string& channel) - : log(boost::log::keywords::channel = channel), - m_Debug(new LogStreamImpl(m_DebugMtx, log, eLogDebug)), - m_Info(new LogStreamImpl(m_InfoMtx, log, eLogInfo)), - m_Warn(new LogStreamImpl(m_WarnMtx, log, eLogWarning)), - m_Error(new LogStreamImpl(m_ErrorMtx, log, eLogError)) { - log.add_attribute( - "LogName", - boost::log::attributes::constant< std::string >(name)); -} - -LoggerImpl::LoggerImpl() : LoggerImpl("default", "default") {} - +// +// LogStreamImpl <- LogStream +// LogStreamImpl::LogStreamImpl( std::mutex& mtx, log_t& l, @@ -122,41 +52,79 @@ LogStreamImpl::LogStreamImpl( m_Log(l), m_Level(level), m_Enable(true) { - // m_Log.add_global_attribute("Logger", m_ParentName); + // m_Log.add_global_attribute("Logger", m_ParentName); } -LogStream & Logger::Error() { - return m_Impl->Error(); +LogStreamImpl::~LogStreamImpl() { + delete m_Str; } -LogStream & Logger::Warning() { - return m_Impl->Warning(); +void LogStreamImpl::WaitForReady() { + { + std::lock_guard lock(m_Access); + } } -LogStream & Logger::Info() { - return m_Impl->Info(); +LogStreamImpl::int_type LogStreamImpl::overflow( + int_type ch) { + return std::streambuf::overflow(ch); } -LogStream & Logger::Debug() { - return m_Impl->Debug(); +int LogStreamImpl::sync() { + int ret = 0; + ret = m_Str->pubsync(); + Flush(); + m_Access.unlock(); + return ret; } -void Logger::Flush() { - g_LogSink->flush(); +// not thread safe +std::streamsize LogStreamImpl::xsputn( + const LogStreamImpl::char_type* s, + std::streamsize count) { + return m_Str->sputn(s, count); } -Logger::Logger(LoggerImpl* impl) : m_Impl(impl) {} - -Logger::~Logger() { - delete m_Impl; +// not thread safe +void LogStreamImpl::Flush() { + if (g_Log->Silent()) { + // don't log if we are silent + return; + } + BOOST_LOG_SEV(m_Log, m_Level) << m_Str; + delete m_Str; + m_Str = new std::stringbuf; + g_LogSink->flush(); } +// +// LogStream +// LogStream::LogStream( LogStreamImpl* impl) : std::ostream(impl), m_Impl(impl) {} -LogStream::~LogStream() { delete m_Impl; } +LogStream::~LogStream() { + delete m_Impl; +} + +LogStream& LogStream::Flush() { + g_LogSink->flush(); + return *this; +} + +bool LogStream::IsEnabled() { + return m_Impl->IsEnabled(); +} + +void LogStream::Disable() { + m_Impl->Disable(); +} + +void LogStream::Enable() { + m_Impl->Enable(); +} /** * TODO(unassigned): implement @@ -169,99 +137,103 @@ LogStream::~LogStream() { delete m_Impl; } * } */ -LogStream & LoggerImpl::Debug() { +// +// LoggerImpl <- Logger +// +LoggerImpl::LoggerImpl( + const std::string& name, + const std::string& channel) + : log(boost::log::keywords::channel = channel), + m_Debug(new LogStreamImpl(m_DebugMtx, log, eLogDebug)), + m_Info(new LogStreamImpl(m_InfoMtx, log, eLogInfo)), + m_Warn(new LogStreamImpl(m_WarnMtx, log, eLogWarning)), + m_Error(new LogStreamImpl(m_ErrorMtx, log, eLogError)) { + log.add_attribute( + "LogName", + boost::log::attributes::constant< std::string >(name)); +} + +LoggerImpl::LoggerImpl() + : LoggerImpl("default", "default") {} + +LogStream& LoggerImpl::Debug() { return GetLogger(m_Debug, m_DebugMtx); } -LogStream & LoggerImpl::Info() { +LogStream& LoggerImpl::Info() { return GetLogger(m_Info, m_InfoMtx); } -LogStream & LoggerImpl::Warning() { +LogStream& LoggerImpl::Warning() { return GetLogger(m_Warn, m_WarnMtx); } -LogStream & LoggerImpl::Error() { +LogStream& LoggerImpl::Error() { return GetLogger(m_Error, m_ErrorMtx); } -LogStream & LoggerImpl::GetLogger( +LogStream& LoggerImpl::GetLogger( LogStream& l, std::mutex & mtx) { mtx.lock(); return l; } -void LogStreamImpl::WaitForReady() { - { - std::lock_guard lock(m_Access); - } -} - -LogStreamImpl::int_type LogStreamImpl::overflow( - int_type ch) { - return std::streambuf::overflow(ch); -} - -int LogStreamImpl::sync() { - int ret; - ret = m_Str->pubsync(); - Flush(); - m_Access.unlock(); - return ret; -} +// +// Logger +// +Logger::Logger( + LoggerImpl* impl) + : m_Impl(impl) {} -// not thread safe -std::streamsize LogStreamImpl::xsputn( - const LogStreamImpl::char_type* s, - std::streamsize count) { - return m_Str->sputn(s, count); +Logger::~Logger() { + delete m_Impl; } -LogStreamImpl::~LogStreamImpl() { - delete m_Str; -} - -// not thread safe -void LogStreamImpl::Flush() { - BOOST_LOG_SEV(m_Log, m_Level) << m_Str; - delete m_Str; - m_Str = new std::stringbuf; - g_LogSink->flush(); +LogStream& Logger::Error() { + return m_Impl->Error(); } -LogStream & LogStream::Flush() { - g_LogSink->flush(); - return *this; +LogStream& Logger::Warning() { + return m_Impl->Warning(); } -bool LogStream::IsEnabled() { - return m_Impl->IsEnabled(); +LogStream& Logger::Info() { + return m_Impl->Info(); } -void LogStream::Disable() { - m_Impl->Disable(); +LogStream& Logger::Debug() { + return m_Impl->Debug(); } -void LogStream::Enable() { - m_Impl->Enable(); +void Logger::Flush() { + g_LogSink->flush(); } -std::ostream& operator<<( - std::ostream& out, - LogLevel lev) { - static const char* levels[] = { - "DBG", // debug - "NFO", // info - "WRN", // warning - "ERR" // error - }; - if (static_cast(lev) < sizeof(levels) / sizeof(*levels)) { - out << levels[lev]; - } else { - out << "?" << static_cast(lev) << "?"; - } - return out; +// +// LogImpl <- Log +// +LogImpl::LogImpl( + LogLevel minlev, + std::ostream* out) { + m_Silent = false; + m_LogCore = boost::log::core::get(); + m_LogBackend = boost::make_shared(); + m_LogBackend->add_stream( + boost::shared_ptr( + out, + boost::null_deleter())); + g_LogSink = boost::shared_ptr( + new sink_t( + m_LogBackend)); + g_LogSink->set_filter( + boost::log::expressions::attr( + "Severity") >= minlev); + g_LogSink->set_formatter(&LogImpl::Format); + m_LogCore->add_sink(g_LogSink); + m_LogCore->add_global_attribute( + "Timestamp", + boost::log::attributes::local_clock()); } void LogImpl::Format( @@ -285,6 +257,24 @@ void LogImpl::Flush() { g_LogSink->flush(); } +void LogImpl::Stop() { + m_Silent = true; +} + +bool LogImpl::IsSilent() { + return m_Silent; +} + +// +// Log +// +Log::Log( + LogLevel minlev, + std::ostream* out) { + m_LogImpl = std::make_shared(minlev, out); + m_DefaultLogger = std::make_shared(new LoggerImpl); +} + std::shared_ptr Log::Get() { // make default logger if we don't have a logger if (g_Log == nullptr) @@ -301,10 +291,51 @@ std::unique_ptr Log::New( const std::string& channel) { return std::unique_ptr( new Logger( - new LoggerImpl( - name, - channel))); + new LoggerImpl( + name, + channel))); +} + +void Log::Stop() { + m_LogImpl->Stop(); +} + +bool Log::Silent() { + return m_LogImpl->IsSilent(); +} + +std::ostream& operator<<( + std::ostream& out, + LogLevel lev) { + static const char* levels[] = { + "DBG", // debug + "NFO", // info + "WRN", // warning + "ERR" // error + }; + if (static_cast(lev) < sizeof(levels) / sizeof(*levels)) { + out << levels[lev]; + } else { + out << "?" << static_cast(lev) << "?"; + } + return out; } } // namespace log -} // namespace kovri +} // namespace util +} // namespace i2p + +// +// Deprecated +// +void DeprecatedStartLog( + const std::string& fullFilePath) { + std::cerr << "Not opening log file: " << fullFilePath << std::endl; +} + +void DeprecatedStartLog( + std::ostream* s) { + *s << "Deprecated Logging not implemented" << std::endl; +} + +void DeprecatedStopLog() {} diff --git a/src/core/util/Log.h b/src/core/util/Log.h index d3faa5c0..d48f9e81 100644 --- a/src/core/util/Log.h +++ b/src/core/util/Log.h @@ -31,12 +31,50 @@ #ifndef SRC_CORE_UTIL_LOG_H_ #define SRC_CORE_UTIL_LOG_H_ +#include + +#if BOOST_VERSION >= 105600 +#include +#else +// defines null_deleter here if we don't have the right boost version +#include +namespace boost { +struct null_deleter { + typedef void result_type; + template void operator() (T*) const {} +}; +} +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include #include +#include #include #include -namespace kovri { +// TODO(unassigned): remove these when removing deprecated logger +#define eLogDebug i2p::util::log::eLogLevelDebug +#define eLogInfo i2p::util::log::eLogLevelInfo +#define eLogWarning i2p::util::log::eLogLevelWarning +#define eLogError i2p::util::log::eLogLevelError + +namespace i2p { +namespace util { namespace log { enum LogLevel { @@ -46,23 +84,75 @@ enum LogLevel { eLogLevelError }; -// private implemenation of LogStream -class LogStreamImpl; +// core +typedef boost::log::core_ptr core_ptr; +// backend +typedef boost::log::sinks::text_ostream_backend backend_t; +typedef boost::shared_ptr backend_ptr; +// sink +typedef boost::log::sinks::asynchronous_sink sink_t; +typedef boost::shared_ptr sink_ptr; +// level +typedef boost::log::sources::severity_channel_logger_mt log_t; + +// +// LogStreamImpl <- LogStream +// +class LogStreamImpl : public std::streambuf { + public: + LogStreamImpl( + std::mutex& access, + log_t& l, + LogLevel levelno); + ~LogStreamImpl(); + + void MetaImpl( + const std::string& key, + std::string value); + + bool IsEnabled() { + return m_Enable; + } + + void Disable() { + m_Enable = false; + } + + void Enable() { + m_Enable = true; + } + + std::streambuf::int_type overflow( + std::streambuf::int_type ch); + + void WaitForReady(); + + protected: + int sync(); + std::streamsize xsputn( + const std::streambuf::char_type* s, + std::streamsize count); + + private: + void Flush(); + std::stringbuf* m_Str; + std::mutex& m_Access; + log_t& m_Log; + LogLevel m_Level; + bool m_Enable; +}; -// Generic Log stream class LogStream : public std::ostream { public: explicit LogStream( LogStreamImpl* impl); ~LogStream(); - /** - * TODO(unassigned): implement (currently unfinished) - * // attach metadata to the current logger's next entries until flushed - * LogStream& Meta( - * const std::string& key, - * std::string value); - */ + // TODO(unassigned): implement (currently unfinished) + // // attach metadata to the current logger's next entries until flushed + // LogStream& Meta( + // const std::string& key, + // std::string value); // flush this log stream LogStream& Flush(); @@ -81,22 +171,56 @@ class LogStream : public std::ostream { LogStreamImpl* m_Impl; }; -/** - * // TODO(unassigned): implement (currently unfinished) - * // Stream for sending events to live UI - * class EventStream { - * public: - * // flush events - * virtual EventStream& Flush() const = 0; - * // operator overload for << - * // queue an event - * virtual EventStream& operator <<( - * const std::vector & strs) const = 0; - * }; - */ +// // TODO(unassigned): implement (currently unfinished) +// class BoostEventStream : public EventStream { +// public: +// virtual EventStream& Flush() const {} +// virtual EventStream& operator <<( +// const std::vector& strs) const {} +// }; + +// +// LoggerImpl <- Logger +// +class LoggerImpl { + public: + // Construct default Logger + LoggerImpl(); + // Construct logger with a name that belongs in 1 log channel + LoggerImpl( + const std::string& name, + const std::string& channel); + + LogStream& Debug(); + LogStream& Info(); + LogStream& Warning(); + LogStream& Error(); + + // TODO(unassigned): implement (currently unfinished) + // EventStream& UI() { + // return m_Events; + //} -// private implementation of Logger -class LoggerImpl; + log_t log; + + private: + LogStream& GetLogger( + LogStream& log, + std::mutex& mtx); + + std::mutex m_DebugMtx, + m_InfoMtx, + m_WarnMtx, + m_ErrorMtx; + + LogStream m_Debug, + m_Info, + m_Warn, + m_Error; + + // TODO(unassigned): implement (currently unfinished) + // BoostEventStream m_Events; +}; class Logger { public: @@ -104,21 +228,14 @@ class Logger { LoggerImpl* impl); ~Logger(); - // get error level log stream LogStream& Error(); - - // get warning level log stream LogStream& Warning(); - - // get info level log stream LogStream& Info(); - - // get debug level log stream LogStream& Debug(); // TODO(unassigned): implement (currently unfinished) // get EventStream to send events to UI - //EventStream& UI(); + // EventStream& UI(); // flush pending log events void Flush(); @@ -127,7 +244,47 @@ class Logger { LoggerImpl* m_Impl; }; -class LogImpl; +// +// LogImpl <- Log +// +class LogImpl { + public: + LogImpl( + LogLevel minLevel, + std::ostream* out); + LogImpl() + : LogImpl( + eLogDebug, + &std::clog) {} + + void Flush(); + + void Stop(); + + bool IsSilent(); + + private: + bool m_Silent; + backend_ptr m_LogBackend; + core_ptr m_LogCore; + static void Format( + boost::log::record_view const& rec, + boost::log::formatting_ostream &s); +}; + +/** + * // TODO(unassigned): implement (currently unfinished) + * // Stream for sending events to live UI + * class EventStream { + * public: + * // flush events + * virtual EventStream& Flush() const = 0; + * // operator overload for << + * // queue an event + * virtual EventStream& operator <<( + * const std::vector & strs) const = 0; + * }; + */ class Log { public: @@ -142,24 +299,99 @@ class Log { // Get global log engine static std::shared_ptr Get(); - // get default logger + // Get default logger std::shared_ptr Default(); - // create a logger given name + // Create a logger's given name std::unique_ptr New( const std::string& name, const std::string& channel); + // turn off logging forever + void Stop(); + + // is logging silent right now? + bool Silent(); + private: std::shared_ptr m_LogImpl; std::shared_ptr m_DefaultLogger; }; } // namespace log -} // namespace kovri - -#include "util/OldLog.h" - -typedef std::unique_ptr Logger_t; +} // namespace util +} // namespace i2p + +// +// Deprecated Logger +// + +#include + +void DeprecatedStartLog( + const std::string& fullFilePath); + +void DeprecatedStartLog( + std::ostream* s); + +void DeprecatedStopLog(); + +template +void DeprecatedLog( + std::ostream& s, + TValue arg) { + s << arg; +} + +template +void DeprecatedLog( + std::ostream& s, + TValue arg, + TArgs... args) { + DeprecatedLog(s, arg); + DeprecatedLog(s, args...); +} + +template +void DeprecatedLogPrint( + i2p::util::log::LogLevel level, + TArgs... args) { + auto l = i2p::util::log::Log::Get(); + if (l == nullptr) { + // fallback logging to std::clog + std::clog << "!!! "; + DeprecatedLog(std::clog, args...); + std::clog << std::endl; + } else { + auto log = l->Default(); + if (level == eLogDebug) { + auto& s = log->Debug(); + DeprecatedLog(s, args...); + s << std::flush; + } else if (level == eLogInfo) { + auto& s = log->Info(); + DeprecatedLog(s, args...); + s << std::flush; + } else if (level == eLogWarning) { + auto& s = log->Warning(); + DeprecatedLog(s, args...); + s << std::flush; + } else { + auto& s = log->Error(); + DeprecatedLog(s, args...); + s << std::flush; + } + } +} + +template +void DeprecatedLogPrint( + TArgs... args) { + DeprecatedLogPrint(eLogInfo, args...); +} + +#define StopLog DeprecatedStopLog +#define StartLog DeprecatedStartLog +#define LogPrint DeprecatedLogPrint #endif // SRC_CORE_UTIL_LOG_H_ diff --git a/src/core/util/OldLog.h b/src/core/util/OldLog.h deleted file mode 100644 index 9b4fbcb7..00000000 --- a/src/core/util/OldLog.h +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (c) 2015-2016, The Kovri I2P Router Project - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SRC_CORE_UTIL_OLDLOG_H_ -#define SRC_CORE_UTIL_OLDLOG_H_ - -// Old Logging API - -#include -#include -#include - -#define eLogDebug kovri::log::eLogLevelDebug -#define eLogInfo kovri::log::eLogLevelInfo -#define eLogWarning kovri::log::eLogLevelWarning -#define eLogError kovri::log::eLogLevelError - -void DeprecatedStartLog( - const std::string& fullFilePath); - -void DeprecatedStartLog( - std::ostream* s); - -void DeprecatedStopLog(); - -template -void DeprecatedLog( - std::ostream& s, - TValue arg) { - s << arg; -} - - -template -void DeprecatedLog( - std::ostream& s, - TValue arg, - TArgs... args) { - DeprecatedLog(s, arg); - DeprecatedLog(s, args...); -} - - -template -void DeprecatedLogPrint( - kovri::log::LogLevel level, - TArgs... args) { - auto l = kovri::log::Log::Get(); - if (l == nullptr) { - // fallback logging to std::clog - std::clog << "!!! "; - DeprecatedLog(std::clog, args...); - std::clog << std::endl; - } else { - auto log = l->Default(); - if (level == eLogDebug) { - auto & s = log->Debug(); - DeprecatedLog(s, args...); - s << std::flush; - } else if (level == eLogInfo) { - auto & s = log->Info(); - DeprecatedLog(s, args...); - s << std::flush; - } else if (level == eLogWarning) { - auto & s = log->Warning(); - DeprecatedLog(s, args...); - s << std::flush; - } else { - auto & s = log->Error(); - DeprecatedLog(s, args...); - s << std::flush; - } - } -} - -template -void DeprecatedLogPrint( - TArgs... args) { - DeprecatedLogPrint(eLogInfo, args...); -} -#define StopLog DeprecatedStopLog -#define StartLog DeprecatedStartLog -#define LogPrint DeprecatedLogPrint - -#endif // SRC_CORE_UTIL_OLDLOG_H_ diff --git a/src/core/util/PrintLog.cpp b/src/core/util/PrintLog.cpp deleted file mode 100644 index 8f70b91d..00000000 --- a/src/core/util/PrintLog.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/** - * Copyright (c) 2015-2016, The Kovri I2P Router Project - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// std::ostream logging backend - -#include "PrintLog.h" - -#include - -namespace kovri { -namespace log { - -std::shared_ptr g_Log = nullptr; - -Logger::Logger( - LoggerImpl* impl) - : m_Impl(impl) {} -Logger::~Logger() { delete m_Impl; } - -LogStream::LogStream( - LogStreamImpl* impl) - : std::ostream(impl), - m_Impl(impl) {} -LogStream::~LogStream() { delete m_Impl; } - -LogStream& LogStream::Flush() { - // we don't want to flush anything here - return *this; -} - -LogStream& LoggerImpl::GetLogStream( - const std::string& name) { - m_LogMtx.lock(); - m_LogStream << m_LogName << "\t" << name << "\t"; - return m_LogStream; -} - -LogStreamImpl::int_type LogStreamImpl::overflow( - int_type ch) { - return std::streambuf::overflow(ch); -} - -LogStreamImpl::~LogStreamImpl() { - delete m_Str; -} - -// called when we get std::flush -int LogStreamImpl::sync() { - int ret; - // sync out std::stringbuf - ret = m_Str->pubsync(); - // flush to std::ostream - m_Out << m_Str; - m_Out << std::endl; - delete m_Str; - m_Str = new std::stringbuf; - // unlock our access mutex so that others can now acquire the log stream - m_Access.unlock(); - return ret; -} - -// not thread safe -std::streamsize LogStreamImpl::xsputn( - const LogStreamImpl::char_type* s, - std::streamsize count) { - return m_Str->sputn(s, count); -} - -bool LogStream::IsEnabled() { - return m_Impl->IsEnabled(); -} - -void LogStream::Disable() { - m_Impl->Disable(); -} - -void LogStream::Enable() { - m_Impl->Enable(); -} - -LogStream & Logger::Debug() { - return m_Impl->GetLogStream("DBG"); -} - -LogStream & Logger::Info() { - return m_Impl->GetLogStream("NFO"); -} - -LogStream & Logger::Warning() { - return m_Impl->GetLogStream("WRN"); -} - -LogStream & Logger::Error() { - return m_Impl->GetLogStream("ERR"); -} - -void Logger::Flush() {} - -Log::Log( - LogLevel minLev, - std::ostream* out) { - m_LogImpl = std::make_shared(minLev, *out); - m_DefaultLogger = - std::make_shared( - new LoggerImpl( - minLev, - "default", - *out)); -} - -LogImpl::LogImpl( - LogLevel minLev, - std::ostream & out) - : m_LogLevel(minLev), - m_Out(out) {} - -std::shared_ptr Log::Get() { - // make default logger if we don't have a logger - if (g_Log == nullptr) - g_Log = std::make_shared(eLogDebug, &std::clog); - return g_Log; -} - -std::shared_ptr Log::Default() { - return m_DefaultLogger; -} - -std::unique_ptr Log::New( - const std::string& name, - const std::string & channel) { - return std::unique_ptr( - new Logger( - new LoggerImpl( - m_LogImpl->CurrentLevel(), - name, - m_LogImpl->Out()))); -} - -} // namespace log -} // namespace kovri diff --git a/src/core/util/PrintLog.h b/src/core/util/PrintLog.h deleted file mode 100644 index e2a777cf..00000000 --- a/src/core/util/PrintLog.h +++ /dev/null @@ -1,145 +0,0 @@ -/** - * Copyright (c) 2015-2016, The Kovri I2P Router Project - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SRC_CORE_UTIL_PRINTLOG_H_ -#define SRC_CORE_UTIL_PRINTLOG_H_ - -#include "Log.h" - -#include -#include - -/* TODO(unassigned): implement */ - -namespace kovri { -namespace log { - -class LogStreamImpl : public std::streambuf { - public: - LogStreamImpl( - std::ostream& out, - std::mutex& mtx) - : m_Str(new std::stringbuf), - m_Out(out), - m_Access(mtx), - m_Enable(true) {} - ~LogStreamImpl(); - - void MetaImpl( - const std::string& key, - std::string& value) {} - - bool IsEnabled() { - return m_Enable; - } - - void Disable() { - m_Enable = false; - } - - void Enable() { - m_Enable = true; - } - - int_type overflow(int_type ch); - - protected: - using char_type = typename std::streambuf::char_type; - - int sync(); - - std::streamsize xsputn( - const char_type* s, - std::streamsize count); - - private: - std::stringbuf * m_Str; - std::ostream& m_Out; - std::mutex& m_Access; - bool m_Enable; -}; - -class LoggerImpl { - public: - LoggerImpl( - LogLevel minlev, - const std::string& name, - std::ostream & out) - : m_MinLevel(minlev), - m_LogName(name), - m_Out(out), - m_LogStream( - new LogStreamImpl( - m_Out, - m_LogMtx)) {} - - LogStream& GetLogStream( - const std::string & name); - - void SetMinLevel( - LogLevel lev) { - m_MinLevel = lev; - } - - private: - LogLevel m_MinLevel; - std::string m_LogName; - std::mutex m_LogMtx; - std::ostream& m_Out; - LogStream m_LogStream; -}; - -class LogImpl { - public: - LogImpl( - LogLevel minLevel, - std::ostream& out); - LogImpl() - : LogImpl( - eLogDebug, - std::clog) {} - - std::ostream& Out() { - return m_Out; - } - - LogLevel CurrentLevel() { - return m_LogLevel; - } - - private: - LogLevel m_LogLevel; - std::ostream& m_Out; -}; - -} // namespace log -} // namespace kovri - -#endif // SRC_CORE_UTIL_PRINTLOG_H_ diff --git a/src/tests/benchmarks/Crypto.cpp b/src/tests/benchmarks/Crypto.cpp index a657d70f..d6235d57 100644 --- a/src/tests/benchmarks/Crypto.cpp +++ b/src/tests/benchmarks/Crypto.cpp @@ -31,15 +31,12 @@ #include #include -#include #include +#include "crypto/Rand.h" #include "crypto/Signature.h" -typedef std::function KeyGenerator; +typedef void (*KeyGenerator)(uint8_t*,uint8_t*) ; template void benchmark( @@ -49,10 +46,9 @@ void benchmark( std::size_t signature_size, KeyGenerator generator) { typedef std::chrono::time_point TimePoint; - CryptoPP::AutoSeededRandomPool rng; uint8_t private_key[private_key_size]; uint8_t public_key[public_key_size]; - generator(rng, private_key, public_key); + generator(private_key, public_key); Verifier verifier(public_key); Signer signer(private_key); uint8_t message[512] = {}; @@ -60,17 +56,22 @@ void benchmark( std::chrono::nanoseconds sign_duration(0); std::chrono::nanoseconds verify_duration(0); for (std::size_t i = 0; i < count; ++i) { - rng.GenerateBlock(message, 512); - TimePoint begin1 = std::chrono::high_resolution_clock::now(); - signer.Sign(rng, message, 512, output); - TimePoint end1 = std::chrono::high_resolution_clock::now(); - sign_duration += - std::chrono::duration_cast(end1 - begin1); - TimePoint begin2 = std::chrono::high_resolution_clock::now(); - verifier.Verify(message, 512, output); - TimePoint end2 = std::chrono::high_resolution_clock::now(); - verify_duration += - std::chrono::duration_cast(end2 - begin2); + try { + i2p::crypto::RandBytes(message, 512); + TimePoint begin1 = std::chrono::high_resolution_clock::now(); + signer.Sign(message, 512, output); + TimePoint end1 = std::chrono::high_resolution_clock::now(); + sign_duration += + std::chrono::duration_cast(end1 - begin1); + TimePoint begin2 = std::chrono::high_resolution_clock::now(); + verifier.Verify(message, 512, output); + TimePoint end2 = std::chrono::high_resolution_clock::now(); + verify_duration += + std::chrono::duration_cast(end2 - begin2); + } catch (CryptoPP::Exception& ex) { + std::cout << "!!! " << ex.what() << std::endl; + break; + } } std::cout << "Conducted " << count << " experiments." << std::endl; std::cout << "Total sign time: " << @@ -81,33 +82,33 @@ void benchmark( verify_duration).count() << std::endl; } - int main() { // TODO(unassigned): don't use namespace using-directives + const size_t benchmark_count = 1000; using namespace i2p::crypto; std::cout << "--------DSA---------" << std::endl; benchmark( - 1000, DSA_PUBLIC_KEY_LENGTH, + benchmark_count, DSA_PUBLIC_KEY_LENGTH, DSA_PRIVATE_KEY_LENGTH, DSA_SIGNATURE_LENGTH, - &CreateDSARandomKeys); + CreateDSARandomKeys); std::cout << "-----ECDSAP256------" << std::endl; benchmark( - 1000, ECDSAP256_KEY_LENGTH, - ECDSAP256_KEY_LENGTH, 64, - &CreateECDSAP256RandomKeys); + benchmark_count, ECDSAP256_KEY_LENGTH, + ECDSAP256_KEY_LENGTH / 2, ECDSAP256_KEY_LENGTH, + CreateECDSAP256RandomKeys); std::cout << "-----ECDSAP384------" << std::endl; benchmark( - 1000, ECDSAP384_KEY_LENGTH, - ECDSAP384_KEY_LENGTH, 64, - &CreateECDSAP384RandomKeys); + benchmark_count, ECDSAP384_KEY_LENGTH, + ECDSAP384_KEY_LENGTH / 2, ECDSAP384_KEY_LENGTH, + CreateECDSAP384RandomKeys); std::cout << "-----ECDSAP521------" << std::endl; benchmark( - 1000, ECDSAP521_KEY_LENGTH, - ECDSAP521_KEY_LENGTH, 64, - &CreateECDSAP521RandomKeys); + benchmark_count, ECDSAP521_KEY_LENGTH, + ECDSAP521_KEY_LENGTH / 2, ECDSAP521_KEY_LENGTH, + CreateECDSAP521RandomKeys); std::cout << "-----EDDSA25519-----" << std::endl; benchmark( - 1000, EDDSA25519_PUBLIC_KEY_LENGTH, - EDDSA25519_PRIVATE_KEY_LENGTH, 64, - &CreateEDDSARandomKeys); + benchmark_count, EDDSA25519_PUBLIC_KEY_LENGTH, + EDDSA25519_PRIVATE_KEY_LENGTH, EDDSA25519_SIGNATURE_LENGTH, + CreateEDDSARandomKeys); } diff --git a/src/tests/unit_tests/Crypto.cpp b/src/tests/unit_tests/Crypto.cpp index 42f2cf28..0ebb5716 100644 --- a/src/tests/unit_tests/Crypto.cpp +++ b/src/tests/unit_tests/Crypto.cpp @@ -218,8 +218,7 @@ BOOST_FIXTURE_TEST_CASE(AesCbcDecrypt, AesCbcFixture) { struct EDDSAFixture { EDDSAFixture() : verifier(public_key), - signer(private_key), - dummy_rng() {} + signer(private_key) {} uint8_t private_key[32] = { 0xe1, 0xec, 0xff, 0xa6, 0xcd, 0x4e, 0xc7, 0x09, 0x2f, 0x87, @@ -237,7 +236,6 @@ struct EDDSAFixture { EDDSA25519Verifier verifier; EDDSA25519Signer signer; - CryptoPP::RandomNumberGenerator dummy_rng; }; BOOST_FIXTURE_TEST_CASE(EdDSA25519KeyLength, EDDSAFixture) { @@ -266,7 +264,7 @@ BOOST_FIXTURE_TEST_CASE(EdDSA25519Sign, EDDSAFixture) { 0x5c, 0x94, 0x7e, 0x0d }; uint8_t output[64] = {}; - signer.Sign(dummy_rng, message, 33, output); + signer.Sign(message, 33, output); BOOST_CHECK_EQUAL_COLLECTIONS(output, output + 64, signature, signature + 64); }