Browse Source

Merge pull request #242 from EinMByte/master

Tests for AES + Improvements to i2pcontrol
pull/247/head
EinMByte 9 years ago
parent
commit
86b83ca614
  1. 3
      ClientContext.cpp
  2. 2
      ClientContext.h
  3. 418
      I2PControl.cpp
  4. 149
      I2PControl.h
  5. 3
      Makefile
  6. 1
      README.md
  7. 3
      build/CMakeLists.txt
  8. 0
      crypto/AESNIMacros.h
  9. 18
      crypto/aes.cpp
  10. 29
      crypto/aes.h
  11. 8
      filelist.mk
  12. 405
      i2pcontrol/I2PControl.cpp
  13. 204
      i2pcontrol/I2PControl.h
  14. 170
      i2pcontrol/I2PControlServer.cpp
  15. 56
      i2pcontrol/I2PControlServer.h
  16. 204
      tests/Crypto.cpp
  17. 10
      tunnel/TunnelCrypto.cpp

3
ClientContext.cpp

@ -116,7 +116,8 @@ namespace client
if(i2pcontrolPort) { if(i2pcontrolPort) {
m_I2PControlService = new I2PControlService( m_I2PControlService = new I2PControlService(
i2p::util::config::GetArg("-i2pcontroladdress", "127.0.0.1"), i2p::util::config::GetArg("-i2pcontroladdress", "127.0.0.1"),
i2pcontrolPort i2pcontrolPort,
i2p::util::config::GetArg("-i2pcontrolpassword", I2P_CONTROL_DEFAULT_PASSWORD)
); );
m_I2PControlService->Start(); m_I2PControlService->Start();
LogPrint("I2PControl started"); LogPrint("I2PControl started");

2
ClientContext.h

@ -11,7 +11,7 @@
#include "SAM.h" #include "SAM.h"
#include "BOB.h" #include "BOB.h"
#include "AddressBook.h" #include "AddressBook.h"
#include "I2PControl.h" #include "i2pcontrol/I2PControlServer.h"
namespace i2p namespace i2p
{ {

418
I2PControl.cpp

@ -1,418 +0,0 @@
// There is bug in boost 1.49 with gcc 4.7 coming with Debian Wheezy
#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 7))
#include "I2PControl.h"
#include <sstream>
#include <boost/lexical_cast.hpp>
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#if !GCC47_BOOST149
#include <boost/property_tree/json_parser.hpp>
#endif
#include "util/Log.h"
#include "NetDb.h"
#include "RouterContext.h"
#include "Daemon.h"
#include "tunnel/Tunnel.h"
#include "util/Timestamp.h"
#include "transport/Transports.h"
#include "version.h"
namespace i2p
{
namespace client
{
I2PControlService::I2PControlService(const std::string& address, int port)
: m_Password(I2P_CONTROL_DEFAULT_PASSWORD), m_IsRunning(false),
m_Thread(nullptr), m_Acceptor(m_Service, boost::asio::ip::tcp::endpoint(
boost::asio::ip::address::from_string(address), port)
),
m_ShutdownTimer (m_Service)
{
m_MethodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlService::AuthenticateHandler;
m_MethodHandlers[I2P_CONTROL_METHOD_ECHO] = &I2PControlService::EchoHandler;
m_MethodHandlers[I2P_CONTROL_METHOD_I2PCONTROL] = &I2PControlService::I2PControlHandler;
m_MethodHandlers[I2P_CONTROL_METHOD_ROUTER_INFO] = &I2PControlService::RouterInfoHandler;
m_MethodHandlers[I2P_CONTROL_METHOD_ROUTER_MANAGER] = &I2PControlService::RouterManagerHandler;
m_MethodHandlers[I2P_CONTROL_METHOD_NETWORK_SETTING] = &I2PControlService::NetworkSettingHandler;
// RouterInfo
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_UPTIME] = &I2PControlService::UptimeHandler;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_VERSION] = &I2PControlService::VersionHandler;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_STATUS] = &I2PControlService::StatusHandler;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS] = &I2PControlService::NetDbKnownPeersHandler;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS] = &I2PControlService::NetDbActivePeersHandler;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NET_STATUS] = &I2PControlService::NetStatusHandler;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING] = &I2PControlService::TunnelsParticipatingHandler;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_IB_1S] = &I2PControlService::InboundBandwidth1S ;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_OB_1S] = &I2PControlService::OutboundBandwidth1S ;
// RouterManager
m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN] = &I2PControlService::ShutdownHandler;
m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL] = &I2PControlService::ShutdownGracefulHandler;
m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_RESEED] = &I2PControlService::ReseedHandler;
}
I2PControlService::~I2PControlService ()
{
Stop ();
}
void I2PControlService::Start ()
{
if (!m_IsRunning)
{
Accept ();
m_IsRunning = true;
m_Thread = new std::thread (std::bind (&I2PControlService::Run, this));
}
}
void I2PControlService::Stop ()
{
if (m_IsRunning)
{
m_IsRunning = false;
m_Acceptor.cancel ();
m_Service.stop ();
if (m_Thread)
{
m_Thread->join ();
delete m_Thread;
m_Thread = nullptr;
}
}
}
void I2PControlService::Run ()
{
while (m_IsRunning)
{
try
{
m_Service.run ();
}
catch (std::exception& ex)
{
LogPrint (eLogError, "I2PControl: ", ex.what ());
}
}
}
void I2PControlService::Accept ()
{
auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (m_Service);
m_Acceptor.async_accept (*newSocket, std::bind (&I2PControlService::HandleAccept, this,
std::placeholders::_1, newSocket));
}
void I2PControlService::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket)
{
if (ecode != boost::asio::error::operation_aborted)
Accept ();
if (!ecode)
{
LogPrint (eLogInfo, "New I2PControl request from ", socket->remote_endpoint ());
std::this_thread::sleep_for (std::chrono::milliseconds(5));
ReadRequest (socket);
}
else
LogPrint (eLogError, "I2PControl accept error: ", ecode.message ());
}
void I2PControlService::ReadRequest (std::shared_ptr<boost::asio::ip::tcp::socket> socket)
{
auto request = std::make_shared<I2PControlBuffer>();
socket->async_read_some (
#if BOOST_VERSION >= 104900
boost::asio::buffer (*request),
#else
boost::asio::buffer (request->data (), request->size ()),
#endif
std::bind(&I2PControlService::HandleRequestReceived, this,
std::placeholders::_1, std::placeholders::_2, socket, request));
}
void I2PControlService::HandleRequestReceived (const boost::system::error_code& ecode,
size_t bytes_transferred, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<I2PControlBuffer> buf)
{
if (ecode)
{
LogPrint (eLogError, "I2PControl read error: ", ecode.message ());
}
else
{
try
{
bool isHtml = !memcmp (buf->data (), "POST", 4);
std::stringstream ss;
ss.write (buf->data (), bytes_transferred);
if (isHtml)
{
std::string header;
while (!ss.eof () && header != "\r")
std::getline(ss, header);
if (ss.eof ())
{
LogPrint (eLogError, "Malformed I2PControl request. HTTP header expected");
return; // TODO:
}
}
#if GCC47_BOOST149
LogPrint (eLogError, "json_read is not supported due bug in boost 1.49 with gcc 4.7");
#else
boost::property_tree::ptree pt;
boost::property_tree::read_json (ss, pt);
std::string method = pt.get<std::string>(I2P_CONTROL_PROPERTY_METHOD);
auto it = m_MethodHandlers.find (method);
if (it != m_MethodHandlers.end ())
{
std::ostringstream response;
response << "{\"id\":" << pt.get<std::string>(I2P_CONTROL_PROPERTY_ID) << ",\"result\":{";
(this->*(it->second))(pt.get_child (I2P_CONTROL_PROPERTY_PARAMS), response);
response << "},\"jsonrpc\":\"2.0\"}";
SendResponse (socket, buf, response, isHtml);
}
else
LogPrint (eLogWarning, "Unknown I2PControl method ", method);
#endif
}
catch (std::exception& ex)
{
LogPrint (eLogError, "I2PControl handle request: ", ex.what ());
}
catch (...)
{
LogPrint (eLogError, "I2PControl handle request unknown exception");
}
}
}
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, int value) const
{
ss << "\"" << name << "\":" << value;
}
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value) const
{
ss << "\"" << name << "\":";
if (value.length () > 0)
ss << "\"" << value << "\"";
else
ss << "null";
}
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, double value) const
{
ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value;
}
void I2PControlService::SendResponse (std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml)
{
size_t len = response.str ().length (), offset = 0;
if (isHtml)
{
std::ostringstream header;
header << "HTTP/1.1 200 OK\r\n";
header << "Connection: close\r\n";
header << "Content-Length: " << boost::lexical_cast<std::string>(len) << "\r\n";
header << "Content-Type: application/json\r\n";
header << "Date: ";
auto facet = new boost::local_time::local_time_facet ("%a, %d %b %Y %H:%M:%S GMT");
header.imbue(std::locale (header.getloc(), facet));
header << boost::posix_time::second_clock::local_time() << "\r\n";
header << "\r\n";
offset = header.str ().size ();
memcpy (buf->data (), header.str ().c_str (), offset);
}
memcpy (buf->data () + offset, response.str ().c_str (), len);
boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), offset + len),
boost::asio::transfer_all (),
std::bind(&I2PControlService::HandleResponseSent, this,
std::placeholders::_1, std::placeholders::_2, socket, buf));
}
void I2PControlService::HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf)
{
if (ecode)
LogPrint (eLogError, "I2PControl write error: ", ecode.message ());
socket->close ();
}
// handlers
void I2PControlService::AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{
int api = params.get<int> (I2P_CONTROL_PARAM_API);
auto password = params.get<std::string> (I2P_CONTROL_PARAM_PASSWORD);
LogPrint (eLogDebug, "I2PControl Authenticate API=", api, " Password=", password);
if (password != m_Password)
LogPrint (eLogError, "I2PControl Authenticate Invalid password ", password, " expected ", m_Password);
InsertParam (results, I2P_CONTROL_PARAM_API, api);
results << ",";
std::string token = boost::lexical_cast<std::string>(i2p::util::GetSecondsSinceEpoch ());
m_Tokens.insert (token);
InsertParam (results, I2P_CONTROL_PARAM_TOKEN, token);
}
void I2PControlService::EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{
auto echo = params.get<std::string> (I2P_CONTROL_PARAM_ECHO);
LogPrint (eLogDebug, "I2PControl Echo Echo=", echo);
InsertParam (results, I2P_CONTROL_PARAM_RESULT, echo);
}
// I2PControl
void I2PControlService::I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{
LogPrint (eLogDebug, "I2PControl I2PControl");
for (auto& it: params)
{
LogPrint (eLogDebug, it.first);
auto it1 = m_I2PControlHandlers.find (it.first);
if (it1 != m_I2PControlHandlers.end ())
(this->*(it1->second))(it.second.data ());
else
LogPrint (eLogError, "I2PControl NetworkSetting unknown request ", it.first);
}
}
// RouterInfo
void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{
LogPrint (eLogDebug, "I2PControl RouterInfo");
for (auto it = params.begin (); it != params.end (); it++)
{
if (it != params.begin ()) results << ",";
LogPrint (eLogDebug, it->first);
auto it1 = m_RouterInfoHandlers.find (it->first);
if (it1 != m_RouterInfoHandlers.end ())
(this->*(it1->second))(results);
else
LogPrint (eLogError, "I2PControl RouterInfo unknown request ", it->first);
}
}
void I2PControlService::UptimeHandler (std::ostringstream& results)
{
InsertParam (results, I2P_CONTROL_ROUTER_INFO_UPTIME, (int)i2p::context.GetUptime ()*1000);
}
void I2PControlService::VersionHandler (std::ostringstream& results)
{
InsertParam (results, I2P_CONTROL_ROUTER_INFO_VERSION, VERSION);
}
void I2PControlService::StatusHandler (std::ostringstream& results)
{
InsertParam (results, I2P_CONTROL_ROUTER_INFO_STATUS, "???"); // TODO:
}
void I2PControlService::NetDbKnownPeersHandler (std::ostringstream& results)
{
InsertParam (results, I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS, i2p::data::netdb.GetNumRouters ());
}
void I2PControlService::NetDbActivePeersHandler (std::ostringstream& results)
{
InsertParam (results, I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS, (int)i2p::transport::transports.GetPeers ().size ());
}
void I2PControlService::NetStatusHandler (std::ostringstream& results)
{
InsertParam (results, I2P_CONTROL_ROUTER_INFO_NET_STATUS, (int)i2p::context.GetStatus ());
}
void I2PControlService::TunnelsParticipatingHandler (std::ostringstream& results)
{
InsertParam (results, I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING, (int)i2p::tunnel::tunnels.GetTransitTunnels ().size ());
}
void I2PControlService::InboundBandwidth1S (std::ostringstream& results)
{
InsertParam (results, I2P_CONTROL_ROUTER_INFO_BW_IB_1S, (double)i2p::transport::transports.GetInBandwidth ());
}
void I2PControlService::OutboundBandwidth1S (std::ostringstream& results)
{
InsertParam (results, I2P_CONTROL_ROUTER_INFO_BW_OB_1S, (double)i2p::transport::transports.GetOutBandwidth ());
}
// RouterManager
void I2PControlService::RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{
LogPrint (eLogDebug, "I2PControl RouterManager");
for (auto it = params.begin (); it != params.end (); it++)
{
if (it != params.begin ()) results << ",";
LogPrint (eLogDebug, it->first);
auto it1 = m_RouterManagerHandlers.find (it->first);
if (it1 != m_RouterManagerHandlers.end ())
(this->*(it1->second))(results);
else
LogPrint (eLogError, "I2PControl RouterManager unknown request ", it->first);
}
}
void I2PControlService::ShutdownHandler (std::ostringstream& results)
{
LogPrint (eLogInfo, "Shutdown requested");
InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, "");
m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(1)); // 1 second to make sure response has been sent
m_ShutdownTimer.async_wait (
[](const boost::system::error_code& ecode)
{
Daemon.running = 0;
});
}
void I2PControlService::ShutdownGracefulHandler (std::ostringstream& results)
{
i2p::context.SetAcceptsTunnels (false);
int timeout = i2p::tunnel::tunnels.GetTransitTunnelsExpirationTimeout ();
LogPrint (eLogInfo, "Graceful shutdown requested. Will shutdown after ", timeout, " seconds");
InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL, "");
m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(timeout + 1)); // + 1 second
m_ShutdownTimer.async_wait (
[](const boost::system::error_code& ecode)
{
Daemon.running = 0;
});
}
void I2PControlService::ReseedHandler (std::ostringstream& results)
{
LogPrint (eLogInfo, "Reseed requested");
InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, "");
i2p::data::netdb.Reseed ();
}
// network setting
void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{
LogPrint (eLogDebug, "I2PControl NetworkSetting");
for (auto it = params.begin (); it != params.end (); it++)
{
if (it != params.begin ()) results << ",";
LogPrint (eLogDebug, it->first);
auto it1 = m_NetworkSettingHandlers.find (it->first);
if (it1 != m_NetworkSettingHandlers.end ())
(this->*(it1->second))(it->second.data (), results);
else
LogPrint (eLogError, "I2PControl NetworkSetting unknown request ", it->first);
}
}
}
}

149
I2PControl.h

@ -1,149 +0,0 @@
#ifndef I2P_CONTROL_H__
#define I2P_CONTROL_H__
#include <inttypes.h>
#include <thread>
#include <memory>
#include <array>
#include <string>
#include <sstream>
#include <map>
#include <set>
#include <boost/asio.hpp>
#include <boost/property_tree/ptree.hpp>
namespace i2p
{
namespace client
{
const size_t I2P_CONTROL_MAX_REQUEST_SIZE = 1024;
typedef std::array<char, I2P_CONTROL_MAX_REQUEST_SIZE> I2PControlBuffer;
const char I2P_CONTROL_DEFAULT_PASSWORD[] = "itoopie";
const char I2P_CONTROL_PROPERTY_ID[] = "id";
const char I2P_CONTROL_PROPERTY_METHOD[] = "method";
const char I2P_CONTROL_PROPERTY_PARAMS[] = "params";
const char I2P_CONTROL_PROPERTY_RESULT[] = "result";
// methods
const char I2P_CONTROL_METHOD_AUTHENTICATE[] = "Authenticate";
const char I2P_CONTROL_METHOD_ECHO[] = "Echo";
const char I2P_CONTROL_METHOD_I2PCONTROL[] = "I2PControl";
const char I2P_CONTROL_METHOD_ROUTER_INFO[] = "RouterInfo";
const char I2P_CONTROL_METHOD_ROUTER_MANAGER[] = "RouterManager";
const char I2P_CONTROL_METHOD_NETWORK_SETTING[] = "NetworkSetting";
// params
const char I2P_CONTROL_PARAM_API[] = "API";
const char I2P_CONTROL_PARAM_PASSWORD[] = "Password";
const char I2P_CONTROL_PARAM_TOKEN[] = "Token";
const char I2P_CONTROL_PARAM_ECHO[] = "Echo";
const char I2P_CONTROL_PARAM_RESULT[] = "Result";
// I2PControl
const char I2P_CONTROL_I2PCONTROL_ADDRESS[] = "i2pcontrol.address";
const char I2P_CONTROL_I2PCONTROL_PASSWORD[] = "i2pcontrol.password";
const char I2P_CONTROL_I2PCONTROL_PORT[] = "i2pcontrol.port";
// RouterInfo requests
const char I2P_CONTROL_ROUTER_INFO_UPTIME[] = "i2p.router.uptime";
const char I2P_CONTROL_ROUTER_INFO_VERSION[] = "i2p.router.version";
const char I2P_CONTROL_ROUTER_INFO_STATUS[] = "i2p.router.status";
const char I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS[] = "i2p.router.netdb.knownpeers";
const char I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS[] = "i2p.router.netdb.activepeers";
const char I2P_CONTROL_ROUTER_INFO_NET_STATUS[] = "i2p.router.net.status";
const char I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING[] = "i2p.router.net.tunnels.participating";
const char I2P_CONTROL_ROUTER_INFO_BW_IB_1S[] = "i2p.router.net.bw.inbound.1s";
const char I2P_CONTROL_ROUTER_INFO_BW_OB_1S[] = "i2p.router.net.bw.outbound.1s";
// RouterManager requests
const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN[] = "Shutdown";
const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL[] = "ShutdownGraceful";
const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed";
class I2PControlService
{
public:
I2PControlService(const std::string& address, int port);
~I2PControlService ();
void Start ();
void Stop ();
private:
void Run ();
void Accept ();
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
void ReadRequest (std::shared_ptr<boost::asio::ip::tcp::socket> socket);
void HandleRequestReceived (const boost::system::error_code& ecode, size_t bytes_transferred,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf);
void SendResponse (std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml);
void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf);
private:
void InsertParam (std::ostringstream& ss, const std::string& name, int value) const;
void InsertParam (std::ostringstream& ss, const std::string& name, double value) const;
void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value) const;
// methods
typedef void (I2PControlService::*MethodHandler)(const boost::property_tree::ptree& params, std::ostringstream& results);
void AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
void EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
void I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
void RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
void RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
void NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
// I2PControl
typedef void (I2PControlService::*I2PControlRequestHandler)(const std::string& value);
// RouterInfo
typedef void (I2PControlService::*RouterInfoRequestHandler)(std::ostringstream& results);
void UptimeHandler (std::ostringstream& results);
void VersionHandler (std::ostringstream& results);
void StatusHandler (std::ostringstream& results);
void NetDbKnownPeersHandler (std::ostringstream& results);
void NetDbActivePeersHandler (std::ostringstream& results);
void NetStatusHandler (std::ostringstream& results);
void TunnelsParticipatingHandler (std::ostringstream& results);
void InboundBandwidth1S (std::ostringstream& results);
void OutboundBandwidth1S (std::ostringstream& results);
// RouterManager
typedef void (I2PControlService::*RouterManagerRequestHandler)(std::ostringstream& results);
void ShutdownHandler (std::ostringstream& results);
void ShutdownGracefulHandler (std::ostringstream& results);
void ReseedHandler (std::ostringstream& results);
// NetworkSetting
typedef void (I2PControlService::*NetworkSettingRequestHandler)(const std::string& value, std::ostringstream& results);
private:
std::string m_Password;
bool m_IsRunning;
std::thread * m_Thread;
boost::asio::io_service m_Service;
boost::asio::ip::tcp::acceptor m_Acceptor;
boost::asio::deadline_timer m_ShutdownTimer;
std::set<std::string> m_Tokens;
std::map<std::string, MethodHandler> m_MethodHandlers;
std::map<std::string, I2PControlRequestHandler> m_I2PControlHandlers;
std::map<std::string, RouterInfoRequestHandler> m_RouterInfoHandlers;
std::map<std::string, RouterManagerRequestHandler> m_RouterManagerHandlers;
std::map<std::string, NetworkSettingRequestHandler> m_NetworkSettingHandlers;
};
}
}
#endif

3
Makefile

@ -32,6 +32,7 @@ mk_build_dir:
mkdir -p obj/util mkdir -p obj/util
mkdir -p obj/crypto mkdir -p obj/crypto
mkdir -p obj/tunnel mkdir -p obj/tunnel
mkdir -p obj/i2pcontrol
mk_build_test_dir: mk_build_test_dir:
mkdir -p obj/tests mkdir -p obj/tests
@ -51,6 +52,7 @@ deps:
@mkdir -p obj/util @mkdir -p obj/util
@mkdir -p obj/crypto @mkdir -p obj/crypto
@mkdir -p obj/tunnel @mkdir -p obj/tunnel
@mkdir -p obj/i2pcontrol
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) -MM *.cpp > $(DEPS) $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) -MM *.cpp > $(DEPS)
@sed -i -e '/\.o:/ s/^/obj\//' $(DEPS) @sed -i -e '/\.o:/ s/^/obj\//' $(DEPS)
@ -61,6 +63,7 @@ obj/%.o : %.cpp
@mkdir -p obj/util @mkdir -p obj/util
@mkdir -p obj/crypto @mkdir -p obj/crypto
@mkdir -p obj/tunnel @mkdir -p obj/tunnel
@mkdir -p obj/i2pcontrol
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS) -c -o $@ $<
# '-' is 'ignore if missing' on first run # '-' is 'ignore if missing' on first run

1
README.md

@ -111,6 +111,7 @@ Cmdline options
* --bobaddress= - Address of BOB service, 127.0.0.1 by default (only used if BOB is on) * --bobaddress= - Address of BOB service, 127.0.0.1 by default (only used if BOB is on)
* --i2pcontrolport= - Port of I2P control service. Usually 7650. I2PControl is off if not specified * --i2pcontrolport= - Port of I2P control service. Usually 7650. I2PControl is off if not specified
* --i2pcontroladdress= - Address of I2P control service, 127.0.0.1 by default (only used if I2PControl is on) * --i2pcontroladdress= - Address of I2P control service, 127.0.0.1 by default (only used if I2PControl is on)
* --i2pcontrolpassword= - I2P control service password, "itoopie" by default
* --conf= - Config file (default: ~/.i2pd/i2p.conf or /var/lib/i2pd/i2p.conf) * --conf= - Config file (default: ~/.i2pd/i2p.conf or /var/lib/i2pd/i2p.conf)
This parameter will be silently ignored if the specified config file does not exist. This parameter will be silently ignored if the specified config file does not exist.
Options specified on the command line take precedence over those in the config file. Options specified on the command line take precedence over those in the config file.

3
build/CMakeLists.txt

@ -62,7 +62,8 @@ set (DAEMON_SRC
"${CMAKE_SOURCE_DIR}/HTTPProxy.cpp" "${CMAKE_SOURCE_DIR}/HTTPProxy.cpp"
"${CMAKE_SOURCE_DIR}/HTTPServer.cpp" "${CMAKE_SOURCE_DIR}/HTTPServer.cpp"
"${CMAKE_SOURCE_DIR}/I2PService.cpp" "${CMAKE_SOURCE_DIR}/I2PService.cpp"
"${CMAKE_SOURCE_DIR}/I2PControl.cpp" "${CMAKE_SOURCE_DIR}/i2pcontrol/I2PControl.cpp"
"${CMAKE_SOURCE_DIR}/i2pcontrol/I2PControlServer.cpp"
"${CMAKE_SOURCE_DIR}/I2PTunnel.cpp" "${CMAKE_SOURCE_DIR}/I2PTunnel.cpp"
"${CMAKE_SOURCE_DIR}/SAM.cpp" "${CMAKE_SOURCE_DIR}/SAM.cpp"
"${CMAKE_SOURCE_DIR}/SOCKS.cpp" "${CMAKE_SOURCE_DIR}/SOCKS.cpp"

0
AESNIMacros.h → crypto/AESNIMacros.h

18
crypto/aes.cpp

@ -45,7 +45,7 @@ void ECBCryptoAESNI::ExpandKey (const AESKey& key)
); );
} }
void ECBEncryptionAESNI::Encrypt (const ChipherBlock * in, ChipherBlock * out) void ECBEncryptionAESNI::Encrypt (const CipherBlock * in, CipherBlock * out)
{ {
__asm__ __asm__
( (
@ -57,7 +57,7 @@ void ECBEncryptionAESNI::Encrypt (const ChipherBlock * in, ChipherBlock * out)
} }
void ECBDecryptionAESNI::Decrypt (const ChipherBlock * in, ChipherBlock * out) void ECBDecryptionAESNI::Decrypt (const CipherBlock * in, CipherBlock * out)
{ {
__asm__ __asm__
( (
@ -94,7 +94,7 @@ void ECBDecryptionAESNI::SetKey (const AESKey& key)
#endif #endif
void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) void CBCEncryption::Encrypt (int numBlocks, const CipherBlock * in, CipherBlock * out)
{ {
#ifdef AESNI #ifdef AESNI
__asm__ __asm__
@ -131,7 +131,7 @@ void CBCEncryption::Encrypt (const uint8_t * in, std::size_t len, uint8_t * out)
// len/16 // len/16
int numBlocks = len >> 4; int numBlocks = len >> 4;
if (numBlocks > 0) if (numBlocks > 0)
Encrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out); Encrypt (numBlocks, (const CipherBlock *)in, (CipherBlock *)out);
} }
void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out) void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out)
@ -151,11 +151,11 @@ void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out)
: "%xmm0", "%xmm1", "memory" : "%xmm0", "%xmm1", "memory"
); );
#else #else
Encrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out); Encrypt (1, (const CipherBlock *)in, (CipherBlock *)out);
#endif #endif
} }
void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) void CBCDecryption::Decrypt (int numBlocks, const CipherBlock * in, CipherBlock * out)
{ {
#ifdef AESNI #ifdef AESNI
__asm__ __asm__
@ -181,7 +181,7 @@ void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBloc
#else #else
for (int i = 0; i < numBlocks; i++) for (int i = 0; i < numBlocks; i++)
{ {
ChipherBlock tmp = in[i]; CipherBlock tmp = in[i];
m_ECBDecryption.Decrypt (in + i, out + i); m_ECBDecryption.Decrypt (in + i, out + i);
out[i] ^= m_IV; out[i] ^= m_IV;
m_IV = tmp; m_IV = tmp;
@ -193,7 +193,7 @@ void CBCDecryption::Decrypt (const uint8_t * in, std::size_t len, uint8_t * out)
{ {
int numBlocks = len >> 4; int numBlocks = len >> 4;
if (numBlocks > 0) if (numBlocks > 0)
Decrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out); Decrypt (numBlocks, (const CipherBlock *)in, (CipherBlock *)out);
} }
void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out) void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out)
@ -213,7 +213,7 @@ void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out)
: "%xmm0", "%xmm1", "memory" : "%xmm0", "%xmm1", "memory"
); );
#else #else
Decrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out); Decrypt (1, (const CipherBlock *)in, (CipherBlock *)out);
#endif #endif
} }

29
crypto/aes.h

@ -10,11 +10,11 @@ namespace i2p
{ {
namespace crypto namespace crypto
{ {
struct ChipherBlock struct CipherBlock
{ {
uint8_t buf[16]; uint8_t buf[16];
void operator^=(const ChipherBlock& other) // XOR void operator^=(const CipherBlock& other) // XOR
{ {
#if defined(__x86_64__) // for Intel x64 #if defined(__x86_64__) // for Intel x64
__asm__ __asm__
@ -81,7 +81,7 @@ namespace crypto
public: public:
void SetKey (const AESKey& key) { ExpandKey (key); }; void SetKey (const AESKey& key) { ExpandKey (key); };
void Encrypt (const ChipherBlock * in, ChipherBlock * out); void Encrypt (const CipherBlock * in, CipherBlock * out);
}; };
class ECBDecryptionAESNI: public ECBCryptoAESNI class ECBDecryptionAESNI: public ECBCryptoAESNI
@ -89,7 +89,7 @@ namespace crypto
public: public:
void SetKey (const AESKey& key); void SetKey (const AESKey& key);
void Decrypt (const ChipherBlock * in, ChipherBlock * out); void Decrypt (const CipherBlock * in, CipherBlock * out);
}; };
typedef ECBEncryptionAESNI ECBEncryption; typedef ECBEncryptionAESNI ECBEncryption;
@ -105,7 +105,7 @@ namespace crypto
{ {
m_Encryption.SetKey (key, 32); m_Encryption.SetKey (key, 32);
} }
void Encrypt (const ChipherBlock * in, ChipherBlock * out) void Encrypt (const CipherBlock * in, CipherBlock * out)
{ {
m_Encryption.ProcessData (out->buf, in->buf, 16); m_Encryption.ProcessData (out->buf, in->buf, 16);
} }
@ -123,7 +123,7 @@ namespace crypto
{ {
m_Decryption.SetKey (key, 32); m_Decryption.SetKey (key, 32);
} }
void Decrypt (const ChipherBlock * in, ChipherBlock * out) void Decrypt (const CipherBlock * in, CipherBlock * out)
{ {
m_Decryption.ProcessData (out->buf, in->buf, 16); m_Decryption.ProcessData (out->buf, in->buf, 16);
} }
@ -146,18 +146,18 @@ namespace crypto
{ {
SetKey(key); SetKey(key);
SetIV(iv); SetIV(iv);
}; }
void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes
void SetIV (const uint8_t * iv) { memcpy (m_LastBlock.buf, iv, 16); }; // 16 bytes void SetIV (const uint8_t * iv) { memcpy (m_LastBlock.buf, iv, 16); }; // 16 bytes
void Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out); void Encrypt (int numBlocks, const CipherBlock * in, CipherBlock * out);
void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out); void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out);
void Encrypt (const uint8_t * in, uint8_t * out); // one block void Encrypt (const uint8_t * in, uint8_t * out); // one block
private: private:
ChipherBlock m_LastBlock; CipherBlock m_LastBlock;
ECBEncryption m_ECBEncryption; ECBEncryption m_ECBEncryption;
}; };
@ -168,16 +168,23 @@ namespace crypto
CBCDecryption () { memset (m_IV.buf, 0, 16); }; CBCDecryption () { memset (m_IV.buf, 0, 16); };
CBCDecryption(const AESKey& key, const uint8_t* iv)
: CBCDecryption()
{
SetKey(key);
SetIV(iv);
}
void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes
void SetIV (const uint8_t * iv) { memcpy (m_IV.buf, iv, 16); }; // 16 bytes void SetIV (const uint8_t * iv) { memcpy (m_IV.buf, iv, 16); }; // 16 bytes
void Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out); void Decrypt (int numBlocks, const CipherBlock * in, CipherBlock * out);
void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out); void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out);
void Decrypt (const uint8_t * in, uint8_t * out); // one block void Decrypt (const uint8_t * in, uint8_t * out); // one block
private: private:
ChipherBlock m_IV; CipherBlock m_IV;
ECBDecryption m_ECBDecryption; ECBDecryption m_ECBDecryption;
}; };

8
filelist.mk

@ -16,7 +16,8 @@ ifeq ($(UNAME),Darwin)
# Else will get linker error about unknown symbols. - torkel # Else will get linker error about unknown symbols. - torkel
COMMON_SRC += \ COMMON_SRC += \
AddressBook.cpp BOB.cpp ClientContext.cpp Daemon.cpp I2PTunnel.cpp I2PService.cpp \ AddressBook.cpp BOB.cpp ClientContext.cpp Daemon.cpp I2PTunnel.cpp I2PService.cpp \
SAM.cpp SOCKS.cpp UPnP.cpp HTTPProxy.cpp i2p.cpp DaemonLinux.cpp I2PControl.cpp \ SAM.cpp SOCKS.cpp UPnP.cpp HTTPProxy.cpp i2p.cpp DaemonLinux.cpp \
i2pcontrol/I2PControlServer.cpp i2pcontrol/I2PControl.cpp \
HTTPServer.cpp HTTPServer.cpp
endif endif
@ -24,10 +25,11 @@ endif
# also: Daemon{Linux,Win32}.cpp will be added later # also: Daemon{Linux,Win32}.cpp will be added later
DAEMON_SRC = $(COMMON_SRC) \ DAEMON_SRC = $(COMMON_SRC) \
AddressBook.cpp BOB.cpp ClientContext.cpp Daemon.cpp I2PTunnel.cpp I2PService.cpp \ AddressBook.cpp BOB.cpp ClientContext.cpp Daemon.cpp I2PTunnel.cpp I2PService.cpp \
SAM.cpp SOCKS.cpp HTTPServer.cpp HTTPProxy.cpp I2PControl.cpp i2p.cpp SAM.cpp SOCKS.cpp HTTPServer.cpp HTTPProxy.cpp i2pcontrol/I2PControl.cpp \
i2pcontrol/I2PControlServer.cpp i2p.cpp
LIB_SRC := $(COMMON_SRC) \ LIB_SRC := $(COMMON_SRC) \
api.cpp api.cpp
TESTS_SRC := $(COMMON_SRC) \ TESTS_SRC := $(COMMON_SRC) \
tests/Utility.cpp tests/Identity.cpp tests/Base64.cpp tests/Utility.cpp tests/Identity.cpp tests/Base64.cpp tests/Crypto.cpp

405
i2pcontrol/I2PControl.cpp

@ -0,0 +1,405 @@
// There is bug in boost 1.49 with gcc 4.7 coming with Debian Wheezy
// #define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 7))
// TODO: handle this somewhere, but definitely not here
#include "I2PControl.h"
#include <iomanip>
#include <sstream>
#include <cryptopp/osrng.h>
#include <cryptopp/hex.h>
#include <cryptopp/filters.h>
#include <boost/property_tree/json_parser.hpp>
#include "util/Log.h"
#include "util/Timestamp.h"
#include "transport/Transports.h"
#include "tunnel/Tunnel.h"
#include "NetDb.h"
#include "version.h"
#include "Daemon.h"
namespace i2p {
namespace client {
I2PControlSession::Response::Response(const std::string& version)
: id(), version(version), error(ErrorCode::None), parameters()
{
}
std::string I2PControlSession::Response::toJsonString() const
{
std::ostringstream oss;
oss << "{\"id\":" << id << ",\"result\":{";
for(auto it = parameters.begin(); it != parameters.end(); ++it) {
if(it != parameters.begin())
oss << ',';
oss << '"' << it->first << "\":" << it->second;
}
oss << "},\"jsonrpc\":\"" << version << '"';
if(error != ErrorCode::None)
oss << ",\"error\":{\"code\":" << -static_cast<int>(error)
<< ",\"message\":\"" << getErrorMsg() << "\"" << "}";
oss << "}";
return oss.str();
}
std::string I2PControlSession::Response::getErrorMsg() const
{
switch(error) {
case ErrorCode::MethodNotFound:
return "Method not found.";
case ErrorCode::InvalidParameters:
return "Invalid parameters.";
case ErrorCode::InvalidRequest:
return "Invalid request.";
case ErrorCode::ParseError:
return "Json parse error.";
case ErrorCode::InvalidPassword:
return "Invalid password.";
case ErrorCode::NoToken:
return "No authentication token given.";
case ErrorCode::NonexistentToken:
return "Nonexistent authentication token given.";
case ErrorCode::ExpiredToken:
return "Exipred authentication token given.";
case ErrorCode::UnspecifiedVersion:
return "Version not specified.";
case ErrorCode::UnsupportedVersion:
return "Version not supported.";
default:
return "";
};
}
void I2PControlSession::Response::setParam(const std::string& param, const std::string& value)
{
parameters[param] = value.empty() ? "null" : "\"" + value + "\"";
}
void I2PControlSession::Response::setParam(const std::string& param, int value)
{
parameters[param] = std::to_string(value);
}
void I2PControlSession::Response::setParam(const std::string& param, double value)
{
std::ostringstream oss;
oss << std::fixed << std::setprecision(2) << value;
parameters[param] = oss.str();
}
void I2PControlSession::Response::setError(ErrorCode code)
{
error = code;
}
void I2PControlSession::Response::setId(const std::string& identifier)
{
id = identifier;
}
I2PControlSession::I2PControlSession(boost::asio::io_service& ios, const std::string& pass)
: password(pass), tokens(), tokensMutex(),
service(ios), shutdownTimer(ios), expireTokensTimer(ios)
{
// Method handlers
methodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlSession::handleAuthenticate;
methodHandlers[I2P_CONTROL_METHOD_ECHO] = &I2PControlSession::handleEcho;
methodHandlers[I2P_CONTROL_METHOD_I2PCONTROL] = &I2PControlSession::handleI2PControl;
methodHandlers[I2P_CONTROL_METHOD_ROUTER_INFO] = &I2PControlSession::handleRouterInfo;
methodHandlers[I2P_CONTROL_METHOD_ROUTER_MANAGER] = &I2PControlSession::handleRouterManager;
methodHandlers[I2P_CONTROL_METHOD_NETWORK_SETTING] = &I2PControlSession::handleNetworkSetting;
// RouterInfo handlers
routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_UPTIME] = &I2PControlSession::handleUptime;
routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_VERSION] = &I2PControlSession::handleVersion;
routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_STATUS] = &I2PControlSession::handleStatus;
routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS]= &I2PControlSession::handleNetDbKnownPeers;
routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS] = &I2PControlSession::handleNetDbActivePeers;
routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_NET_STATUS] = &I2PControlSession::handleNetStatus;
routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING] = &I2PControlSession::handleTunnelsParticipating;
routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_IB_1S] = &I2PControlSession::handleInBandwidth1S;
routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_OB_1S] = &I2PControlSession::handleOutBandwidth1S;
// RouterManager handlers
routerManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN] = &I2PControlSession::handleShutdown;
routerManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL] = &I2PControlSession::handleShutdownGraceful;
routerManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_RESEED] = &I2PControlSession::handleReseed;
}
void I2PControlSession::start()
{
startExpireTokensJob();
}
void I2PControlSession::stop()
{
boost::system::error_code e; // Make sure this doesn't throw
shutdownTimer.cancel(e);
expireTokensTimer.cancel(e);
}
I2PControlSession::Response I2PControlSession::handleRequest(std::stringstream& request)
{
boost::property_tree::ptree pt;
boost::property_tree::read_json(request, pt);
Response response;
try {
response.setId(pt.get<std::string>(I2P_CONTROL_PROPERTY_ID));
std::string method = pt.get<std::string>(I2P_CONTROL_PROPERTY_METHOD);
auto it = methodHandlers.find(method);
if(it == methodHandlers.end()) { // Not found
LogPrint(eLogWarning, "Unknown I2PControl method ", method);
response.setError(ErrorCode::MethodNotFound);
return response;
}
PropertyTree params = pt.get_child(I2P_CONTROL_PROPERTY_PARAMS);
if(method != I2P_CONTROL_METHOD_AUTHENTICATE && !authenticate(params, response)) {
LogPrint(eLogWarning, "I2PControl invalid token presented");
return response;
}
// Call the appropriate handler
(this->*(it->second))(params, response);
} catch(const boost::property_tree::ptree_error& error) {
response.setError(ErrorCode::ParseError);
} catch(...) {
response.setError(ErrorCode::InternalError);
}
return response;
}
bool I2PControlSession::authenticate(const PropertyTree& pt, Response& response)
{
try {
std::string token = pt.get<std::string>(I2P_CONTROL_PARAM_TOKEN);
std::lock_guard<std::mutex> lock(tokensMutex);
auto it = tokens.find(token);
if(it == tokens.end()) {
response.setError(ErrorCode::NonexistentToken);
return false;
} else if(util::GetSecondsSinceEpoch() - it->second > I2P_CONTROL_TOKEN_LIFETIME) {
response.setError(ErrorCode::ExpiredToken);
return false;
}
} catch(const boost::property_tree::ptree_error& error) {
response.setError(ErrorCode::NoToken);
return false;
}
return true;
}
std::string I2PControlSession::generateToken() const
{
byte random_data[I2P_CONTROL_TOKEN_SIZE] = {};
CryptoPP::AutoSeededRandomPool rng;
rng.GenerateBlock(random_data, I2P_CONTROL_TOKEN_SIZE);
std::string token;
CryptoPP::StringSource ss(
random_data, I2P_CONTROL_TOKEN_SIZE, true,
new CryptoPP::HexEncoder(new CryptoPP::StringSink(token))
);
return token;
}
void I2PControlSession::handleAuthenticate(const PropertyTree& pt, Response& response)
{
const int api = pt.get<int>(I2P_CONTROL_PARAM_API);
const std::string given_pass = pt.get<std::string>(I2P_CONTROL_PARAM_PASSWORD);
LogPrint(eLogDebug, "I2PControl Authenticate API = ", api, " Password = ", given_pass);
if(given_pass != password) {
LogPrint(
eLogError, "I2PControl Authenticate Invalid password ", given_pass,
" expected ", password
);
response.setError(ErrorCode::InvalidPassword);
return;
}
const std::string token = generateToken();
response.setParam(I2P_CONTROL_PARAM_API, api);
response.setParam(I2P_CONTROL_PARAM_TOKEN, token);
std::lock_guard<std::mutex> lock(tokensMutex);
tokens.insert(std::make_pair(token, util::GetSecondsSinceEpoch()));
}
void I2PControlSession::handleEcho(const PropertyTree& pt, Response& response)
{
const std::string echo = pt.get<std::string>(I2P_CONTROL_PARAM_ECHO);
LogPrint(eLogDebug, "I2PControl Echo Echo = ", echo);
response.setParam(I2P_CONTROL_PARAM_RESULT, echo);
}
void I2PControlSession::handleI2PControl(const PropertyTree& pt, Response& response)
{
LogPrint(eLogDebug, "I2PControl I2PControl");
// TODO: implement
}
void I2PControlSession::handleRouterInfo(const PropertyTree& pt, Response& response)
{
LogPrint(eLogDebug, "I2PControl RouterInfo");
for(const auto& pair : pt) {
if(pair.first == I2P_CONTROL_PARAM_TOKEN)
continue;
LogPrint(eLogDebug, pair.first);
auto it = routerInfoHandlers.find(pair.first);
if(it != routerInfoHandlers.end()) {
(this->*(it->second))(response);
} else {
LogPrint(eLogError, "I2PControl RouterInfo unknown request ", pair.first);
response.setError(ErrorCode::InvalidRequest);
}
}
}
void I2PControlSession::handleRouterManager(const PropertyTree& pt, Response& response)
{
LogPrint(eLogDebug, "I2PControl RouterManager");
for(const auto& pair : pt) {
if(pair.first == I2P_CONTROL_PARAM_TOKEN)
continue;
LogPrint(eLogDebug, pair.first);
auto it = routerManagerHandlers.find(pair.first);
if(it != routerManagerHandlers.end()) {
(this->*(it->second))(response);
} else {
LogPrint(eLogError, "I2PControl RouterManager unknown request ", pair.first);
response.setError(ErrorCode::InvalidRequest);
}
}
}
void I2PControlSession::handleNetworkSetting(const PropertyTree& pt, Response& response)
{
}
void I2PControlSession::handleUptime(Response& response)
{
response.setParam(I2P_CONTROL_ROUTER_INFO_UPTIME, (int)i2p::context.GetUptime()*1000);
}
void I2PControlSession::handleVersion(Response& response)
{
response.setParam(I2P_CONTROL_ROUTER_INFO_VERSION, VERSION);
}
void I2PControlSession::handleStatus(Response& response)
{
response.setParam(I2P_CONTROL_ROUTER_INFO_STATUS, "???"); // TODO:
}
void I2PControlSession::handleNetDbKnownPeers(Response& response)
{
response.setParam(
I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS, i2p::data::netdb.GetNumRouters()
);
}
void I2PControlSession::handleNetDbActivePeers(Response& response)
{
response.setParam(
I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS,
i2p::data::netdb.GetNumRouters()
);
}
void I2PControlSession::handleNetStatus(Response& response)
{
response.setParam(
I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS,
(int)i2p::transport::transports.GetPeers().size()
);
}
void I2PControlSession::handleTunnelsParticipating(Response& response)
{
response.setParam(
I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING,
(int)i2p::tunnel::tunnels.GetTransitTunnels().size()
);
}
void I2PControlSession::handleInBandwidth1S(Response& response)
{
response.setParam(
I2P_CONTROL_ROUTER_INFO_BW_IB_1S,
(double)i2p::transport::transports.GetInBandwidth()
);
}
void I2PControlSession::handleOutBandwidth1S(Response& response)
{
response.setParam(
I2P_CONTROL_ROUTER_INFO_BW_OB_1S,
(double)i2p::transport::transports.GetOutBandwidth()
);
}
void I2PControlSession::handleShutdown(Response& response)
{
LogPrint(eLogInfo, "Shutdown requested");
response.setParam(I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, "");
// 1 second to make sure response has been sent
shutdownTimer.expires_from_now(boost::posix_time::seconds(1));
shutdownTimer.async_wait([](const boost::system::error_code& ecode) {
Daemon.running = 0;
});
}
void I2PControlSession::handleShutdownGraceful(Response& response)
{
i2p::context.SetAcceptsTunnels(false);
int timeout = i2p::tunnel::tunnels.GetTransitTunnelsExpirationTimeout();
LogPrint(eLogInfo, "Graceful shutdown requested. Will shutdown after ", timeout, " seconds");
response.setParam(I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL, "");
shutdownTimer.expires_from_now(boost::posix_time::seconds(timeout + 1));
shutdownTimer.async_wait([](const boost::system::error_code& ecode) {
Daemon.running = 0;
});
}
void I2PControlSession::handleReseed(Response& response)
{
LogPrint(eLogInfo, "Reseed requested");
response.setParam(I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, "");
i2p::data::netdb.Reseed();
}
void I2PControlSession::expireTokens(const boost::system::error_code& error)
{
if(error == boost::asio::error::operation_aborted)
return; // Do not restart timer, shutting down
startExpireTokensJob();
LogPrint(eLogDebug, "I2PControl is expiring tokens.");
const uint64_t now = util::GetSecondsSinceEpoch();
std::lock_guard<std::mutex> lock(tokensMutex);
for(auto it = tokens.begin(); it != tokens.end(); ) {
if(now - it->second > I2P_CONTROL_TOKEN_LIFETIME)
it = tokens.erase(it);
else
++it;
}
}
void I2PControlSession::startExpireTokensJob()
{
expireTokensTimer.expires_from_now(boost::posix_time::seconds(I2P_CONTROL_TOKEN_LIFETIME));
expireTokensTimer.async_wait(std::bind(
&I2PControlSession::expireTokens, shared_from_this(), std::placeholders::_1
));
}
}
}

204
i2pcontrol/I2PControl.h

@ -0,0 +1,204 @@
#ifndef I2PCONTROL_H__
#define I2PCONTROL_H__
#include <boost/property_tree/ptree.hpp>
#include <string>
#include <map>
#include <functional>
#include <mutex>
#include <boost/asio.hpp>
namespace i2p {
namespace client {
const char I2P_CONTROL_DEFAULT_PASSWORD[] = "itoopie";
const uint64_t I2P_CONTROL_TOKEN_LIFETIME = 600; // Token lifetime in seconds
const std::size_t I2P_CONTROL_TOKEN_SIZE = 8; // Token size in bytes
const char I2P_CONTROL_PROPERTY_ID[] = "id";
const char I2P_CONTROL_PROPERTY_METHOD[] = "method";
const char I2P_CONTROL_PROPERTY_PARAMS[] = "params";
const char I2P_CONTROL_PROPERTY_RESULT[] = "result";
// methods
const char I2P_CONTROL_METHOD_AUTHENTICATE[] = "Authenticate";
const char I2P_CONTROL_METHOD_ECHO[] = "Echo";
const char I2P_CONTROL_METHOD_I2PCONTROL[] = "I2PControl";
const char I2P_CONTROL_METHOD_ROUTER_INFO[] = "RouterInfo";
const char I2P_CONTROL_METHOD_ROUTER_MANAGER[] = "RouterManager";
const char I2P_CONTROL_METHOD_NETWORK_SETTING[] = "NetworkSetting";
// params
const char I2P_CONTROL_PARAM_API[] = "API";
const char I2P_CONTROL_PARAM_PASSWORD[] = "Password";
const char I2P_CONTROL_PARAM_TOKEN[] = "Token";
const char I2P_CONTROL_PARAM_ECHO[] = "Echo";
const char I2P_CONTROL_PARAM_RESULT[] = "Result";
// I2PControl
const char I2P_CONTROL_I2PCONTROL_ADDRESS[] = "i2pcontrol.address";
const char I2P_CONTROL_I2PCONTROL_PASSWORD[] = "i2pcontrol.password";
const char I2P_CONTROL_I2PCONTROL_PORT[] = "i2pcontrol.port";
// RouterInfo requests
const char I2P_CONTROL_ROUTER_INFO_UPTIME[] = "i2p.router.uptime";
const char I2P_CONTROL_ROUTER_INFO_VERSION[] = "i2p.router.version";
const char I2P_CONTROL_ROUTER_INFO_STATUS[] = "i2p.router.status";
const char I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS[] = "i2p.router.netdb.knownpeers";
const char I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS[] = "i2p.router.netdb.activepeers";
const char I2P_CONTROL_ROUTER_INFO_NET_STATUS[] = "i2p.router.net.status";
const char I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING[] = "i2p.router.net.tunnels.participating";
const char I2P_CONTROL_ROUTER_INFO_BW_IB_1S[] = "i2p.router.net.bw.inbound.1s";
const char I2P_CONTROL_ROUTER_INFO_BW_OB_1S[] = "i2p.router.net.bw.outbound.1s";
// RouterManager requests
const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN[] = "Shutdown";
const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL[] = "ShutdownGraceful";
const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed";
/**
* "Null" I2P control implementation, does not do actual networking.
* @note authentication tokens are per-session
* @note I2PControlSession must always be used as a std::shared_ptr
* @warning an I2PControlSession must be destroyed before its io_service
*/
class I2PControlSession : public std::enable_shared_from_this<I2PControlSession> {
public:
enum class ErrorCode {
None = 0,
// JSON-RPC2
MethodNotFound = 32601,
InvalidParameters = 32602,
InvalidRequest = 32600,
InternalError = 32603,
ParseError = 32700,
// I2PControl specific
InvalidPassword = 32001,
NoToken = 32002,
NonexistentToken = 32003,
ExpiredToken = 32004,
UnspecifiedVersion = 32005,
UnsupportedVersion = 32006
};
class Response {
std::string id;
std::string version;
ErrorCode error;
std::map<std::string, std::string> parameters;
public:
Response(const std::string& version = "2.0");
std::string toJsonString() const;
/**
* Set an ouptut parameter to a specified string.
* @todo escape quotes
*/
void setParam(const std::string& param, const std::string& value);
void setParam(const std::string& param, int value);
void setParam(const std::string& param, double value);
void setError(ErrorCode code);
void setId(const std::string& identifier);
std::string getErrorMsg() const;
};
/**
* Sets up the appropriate handlers.
* @param pass the password required to authenticate (i.e. obtains a token)
* @param ios the parent io_service object, must remain valid throughout
* the lifetime of this I2PControlSession.
*/
I2PControlSession(boost::asio::io_service& ios,
const std::string& pass = I2P_CONTROL_DEFAULT_PASSWORD);
/**
* Starts the I2PControlSession.
* In essence, this starts the expireTokensTimer.
* @note should always be called after construction
*/
void start();
/**
* Cancels all operations that are waiting.
* @note it's a good idea to call this before destruction (shared_ptr reset)
*/
void stop();
/**
* Handle a json string with I2PControl instructions.
*/
Response handleRequest(std::stringstream& request);
private:
// For convenience
typedef boost::property_tree::ptree PropertyTree;
// Handler types
typedef void (I2PControlSession::*MethodHandler)(
const PropertyTree& pt, Response& results
);
typedef void (I2PControlSession::*RequestHandler)(Response& results);
/**
* Tries to authenticate by checking whether the given token is valid.
* Sets the appropriate error code in the given response.
*/
bool authenticate(const PropertyTree& pt, Response& response);
/**
* Generate a random authentication token.
* @return 8 random bytes as a hexadecimal string
*/
std::string generateToken() const;
void startExpireTokensJob();
/**
* Expire tokens that are too old.
*/
void expireTokens(const boost::system::error_code& error);
// Method handlers
void handleAuthenticate(const PropertyTree& pt, Response& response);
void handleEcho(const PropertyTree& pt, Response& response);
void handleI2PControl(const PropertyTree& pt, Response& response);
void handleRouterInfo(const PropertyTree& pt, Response& response);
void handleRouterManager(const PropertyTree& pt, Response& response);
void handleNetworkSetting(const PropertyTree& pt, Response& response);
// RouterInfo handlers
void handleUptime(Response& response);
void handleVersion(Response& response);
void handleStatus(Response& response);
void handleNetDbKnownPeers(Response& response);
void handleNetDbActivePeers(Response& response);
void handleNetStatus(Response& response);
void handleTunnelsParticipating(Response& response);
void handleInBandwidth1S(Response& response);
void handleOutBandwidth1S(Response& response);
// RouterManager handlers
void handleShutdown(Response& response);
void handleShutdownGraceful(Response& response);
void handleReseed(Response& response);
std::string password;
std::map<std::string, uint64_t> tokens;
std::mutex tokensMutex;
std::map<std::string, MethodHandler> methodHandlers;
std::map<std::string, RequestHandler> routerInfoHandlers;
std::map<std::string, RequestHandler> routerManagerHandlers;
std::map<std::string, RequestHandler> networkSettingHandlers;
boost::asio::io_service& service;
boost::asio::deadline_timer shutdownTimer;
boost::asio::deadline_timer expireTokensTimer;
};
}
}
#endif // I2PCONTROL_H__

170
i2pcontrol/I2PControlServer.cpp

@ -0,0 +1,170 @@
#include "I2PControlServer.h"
#include <sstream>
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include "util/Log.h"
#include "util/Timestamp.h"
#include "version.h"
namespace i2p {
namespace client {
I2PControlService::I2PControlService(const std::string& address, int port, const std::string& pass)
: m_Session(std::make_shared<I2PControlSession>(m_Service, pass)),
m_IsRunning(false), m_Thread(nullptr),
m_Acceptor(m_Service, boost::asio::ip::tcp::endpoint(
boost::asio::ip::address::from_string(address), port)
)
{
}
I2PControlService::~I2PControlService()
{
Stop();
}
void I2PControlService::Start()
{
if(!m_IsRunning) {
Accept();
m_Session->start();
m_IsRunning = true;
m_Thread = new std::thread(std::bind(&I2PControlService::Run, this));
}
}
void I2PControlService::Stop()
{
if(m_IsRunning) {
m_IsRunning = false;
m_Acceptor.cancel();
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;
m_Thread = nullptr;
}
}
}
void I2PControlService::Run()
{
while(m_IsRunning) {
try {
m_Service.run();
} catch(const std::exception& ex) {
LogPrint(eLogError, "I2PControl: ", ex.what());
}
}
}
void I2PControlService::Accept()
{
auto newSocket = std::make_shared<boost::asio::ip::tcp::socket>(m_Service);
m_Acceptor.async_accept(*newSocket, std::bind(&I2PControlService::HandleAccept, this,
std::placeholders::_1, newSocket));
}
void I2PControlService::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket)
{
if(ecode != boost::asio::error::operation_aborted)
Accept();
if(!ecode)
{
LogPrint(eLogInfo, "New I2PControl request from ", socket->remote_endpoint());
std::this_thread::sleep_for(std::chrono::milliseconds(5));
ReadRequest(socket);
}
else
LogPrint(eLogError, "I2PControl accept error: ", ecode.message());
}
void I2PControlService::ReadRequest(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
{
auto request = std::make_shared<I2PControlBuffer>();
socket->async_read_some(
#if BOOST_VERSION >= 104900
boost::asio::buffer(*request),
#else
boost::asio::buffer(request->data(), request->size()),
#endif
std::bind(&I2PControlService::HandleRequestReceived, this,
std::placeholders::_1, std::placeholders::_2, socket, request));
}
void I2PControlService::HandleRequestReceived(const boost::system::error_code& ecode,
size_t bytes_transferred, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<I2PControlBuffer> buf)
{
if(ecode) {
LogPrint(eLogError, "I2PControl read error: ", ecode.message());
return;
}
try {
bool isHtml = !memcmp(buf->data(), "POST", 4);
std::stringstream ss;
ss.write(buf->data(), bytes_transferred);
if(isHtml) {
std::string header;
while(!ss.eof() && header != "\r")
std::getline(ss, header);
if(ss.eof()) {
LogPrint(eLogError, "Malformed I2PControl request. HTTP header expected");
return; // TODO:
}
}
I2PControlSession::Response response = m_Session->handleRequest(ss);
SendResponse(socket, buf, response.toJsonString(), isHtml);
} catch(const std::exception& ex) {
LogPrint(eLogError, "I2PControl handle request: ", ex.what());
} catch(...) {
LogPrint(eLogError, "I2PControl handle request unknown exception");
}
}
void I2PControlService::SendResponse(std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<I2PControlBuffer> buf, const std::string& response, bool isHtml)
{
size_t len = response.length(), offset = 0;
if(isHtml) {
std::ostringstream header;
header << "HTTP/1.1 200 OK\r\n";
header << "Connection: close\r\n";
header << "Content-Length: " << boost::lexical_cast<std::string>(len) << "\r\n";
header << "Content-Type: application/json\r\n";
header << "Date: ";
auto facet = new boost::local_time::local_time_facet("%a, %d %b %Y %H:%M:%S GMT");
header.imbue(std::locale(header.getloc(), facet));
header << boost::posix_time::second_clock::local_time() << "\r\n";
header << "\r\n";
offset = header.str().size();
memcpy(buf->data(), header.str().c_str(), offset);
}
memcpy(buf->data() + offset, response.c_str(), len);
boost::asio::async_write(
*socket, boost::asio::buffer(buf->data(), offset + len),
boost::asio::transfer_all(), std::bind(
&I2PControlService::HandleResponseSent, this,
std::placeholders::_1, std::placeholders::_2, socket, buf
)
);
}
void I2PControlService::HandleResponseSent(const boost::system::error_code& ecode, std::size_t bytes_transferred,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf)
{
if(ecode)
LogPrint(eLogError, "I2PControl write error: ", ecode.message());
socket->close();
}
}
}

56
i2pcontrol/I2PControlServer.h

@ -0,0 +1,56 @@
#ifndef I2P_CONTROL_SERVER_H__
#define I2P_CONTROL_SERVER_H__
#include "I2PControl.h"
#include <inttypes.h>
#include <thread>
#include <memory>
#include <array>
#include <string>
#include <sstream>
#include <boost/asio.hpp>
namespace i2p {
namespace client {
const size_t I2P_CONTROL_MAX_REQUEST_SIZE = 1024;
typedef std::array<char, I2P_CONTROL_MAX_REQUEST_SIZE> I2PControlBuffer;
class I2PControlService {
public:
I2PControlService(const std::string& address, int port, const std::string& pass);
~I2PControlService();
void Start();
void Stop();
private:
void Run();
void Accept();
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
void ReadRequest(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
void HandleRequestReceived(const boost::system::error_code& ecode, size_t bytes_transferred,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf);
void SendResponse(std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<I2PControlBuffer> buf, const std::string& response, bool isHtml);
void HandleResponseSent(const boost::system::error_code& ecode, std::size_t bytes_transferred,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf);
private:
bool m_IsRunning;
std::thread * m_Thread;
boost::asio::io_service m_Service;
boost::asio::ip::tcp::acceptor m_Acceptor;
std::shared_ptr<I2PControlSession> m_Session;
};
}
}
#endif

204
tests/Crypto.cpp

@ -0,0 +1,204 @@
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#include "crypto/aes.h"
using namespace i2p::crypto;
BOOST_AUTO_TEST_SUITE(CryptographyTests)
BOOST_AUTO_TEST_CASE(XorZeroCipherBlocks)
{
CipherBlock block = {};
block ^= block;
const CipherBlock result = {};
BOOST_CHECK_EQUAL_COLLECTIONS(result.buf, result.buf + 16, block.buf, block.buf + 16);
}
BOOST_AUTO_TEST_CASE(XorSelfCipherBlocks)
{
CipherBlock block = {
0xc9, 0x4c, 0xaf, 0x5, 0x9c, 0x1c, 0x10, 0x1e, 0x20, 0xb3, 0x7e,
0xcf, 0xf5, 0xbf, 0xf0, 0xd6
};
block ^= block;
const CipherBlock result = {};
BOOST_CHECK_EQUAL_COLLECTIONS(result.buf, result.buf + 16, block.buf, block.buf + 16);
}
BOOST_AUTO_TEST_CASE(XorCipherBlocks)
{
const CipherBlock block1 = {
0xc9, 0x4c, 0xaf, 0x5, 0x9c, 0x1c, 0x10, 0x1e, 0x20, 0xb3, 0x7e,
0xcf, 0xf5, 0xbf, 0xf0, 0xd6
};
CipherBlock block2 = {
0x2e, 0xfb, 0x26, 0xa9, 0x90, 0x3b, 0xf7, 0xc8, 0x5c, 0xfe, 0x20,
0x23, 0x1d, 0xaf, 0x67, 0xac
};
block2 ^= block1;
const CipherBlock result = {
0xe7, 0xb7, 0x89, 0xac, 0xc, 0x27, 0xe7, 0xd6, 0x7c, 0x4d, 0x5e,
0xec, 0xe8, 0x10, 0x97, 0x7a
};
BOOST_CHECK_EQUAL_COLLECTIONS(block2.buf, block2.buf + 16, result.buf, result.buf + 16);
}
// NIST test parameters
// see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
struct AesCbcFixture {
AesCbcFixture()
: cbc_encrypt(AESKey(key), iv), cbc_decrypt(AESKey(key), iv) {}
uint8_t key[32] = {
0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73,
0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07,
0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14,
0xdf, 0xf4
};
uint8_t iv[16] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
CBCEncryption cbc_encrypt;
CBCDecryption cbc_decrypt;
};
BOOST_FIXTURE_TEST_CASE(AesCbcSingleBlockEncrypt, AesCbcFixture)
{
uint8_t output[16] = {};
const uint8_t input[] = {
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d,
0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a
};
const uint8_t result[] = {
0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e,
0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6
};
cbc_encrypt.Encrypt(input, output);
BOOST_CHECK_EQUAL_COLLECTIONS(output, output + 16, result, result + 16);
}
BOOST_FIXTURE_TEST_CASE(AesCbcSingleBlockDecrypt, AesCbcFixture)
{
uint8_t output[16] = {};
const uint8_t input[] = {
0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e,
0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6
};
const uint8_t result[] = {
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d,
0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a
};
cbc_decrypt.Decrypt(input, output);
BOOST_CHECK_EQUAL_COLLECTIONS(output, output + 16, result, result + 16);
}
BOOST_FIXTURE_TEST_CASE(AesCbcEncrypt, AesCbcFixture)
{
CipherBlock output[4] = {};
CipherBlock input[4] = {};
input[0] = {
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d,
0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a
};
input[1] = {
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7,
0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51
};
input[2] = {
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb,
0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef
};
input[3] = {
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b,
0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
};
CipherBlock result[4] = {};
result[0] = {
0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e,
0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6
};
result[1] = {
0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f,
0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d
};
result[2] = {
0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30,
0xe2, 0x63, 0x04, 0x23, 0x14, 0x61
};
result[3] = {
0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c,
0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b
};
cbc_encrypt.Encrypt(4, input, output);
for(int i = 0; i < 3; ++i) {
BOOST_CHECK_EQUAL_COLLECTIONS(
output[i].buf, output[i].buf + 16,
result[i].buf, result[i].buf + 16
);
}
}
BOOST_FIXTURE_TEST_CASE(AesCbcDecrypt, AesCbcFixture)
{
CipherBlock output[4] = {};
CipherBlock input[4] = {};
input[0] = {
0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e,
0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6
};
input[1] = {
0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f,
0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d
};
input[2] = {
0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30,
0xe2, 0x63, 0x04, 0x23, 0x14, 0x61
};
input[3] = {
0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c,
0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b
};
CipherBlock result[4] = {};
result[0] = {
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d,
0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a
};
result[1] = {
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7,
0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51
};
result[2] = {
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb,
0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef
};
result[3] = {
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b,
0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
};
cbc_decrypt.Decrypt(4, input, output);
for(int i = 0; i < 3; ++i) {
BOOST_CHECK_EQUAL_COLLECTIONS(
output[i].buf, output[i].buf + 16,
result[i].buf, result[i].buf + 16
);
}
}
BOOST_AUTO_TEST_SUITE_END()

10
tunnel/TunnelCrypto.cpp

@ -1,6 +1,6 @@
#include "TunnelCrypto.h" #include "TunnelCrypto.h"
#include "TunnelBase.h" #include "TunnelBase.h"
#include "AESNIMacros.h" #include "crypto/AESNIMacros.h"
namespace i2p { namespace i2p {
namespace crypto { namespace crypto {
@ -40,10 +40,10 @@ void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out)
: "%xmm0", "%xmm1", "cc", "memory" : "%xmm0", "%xmm1", "cc", "memory"
); );
#else #else
m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv m_IVEncryption.Encrypt ((const CipherBlock *)in, (CipherBlock *)out); // iv
m_LayerEncryption.SetIV (out); m_LayerEncryption.SetIV (out);
m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv m_IVEncryption.Encrypt ((CipherBlock *)out, (CipherBlock *)out); // double iv
#endif #endif
} }
@ -77,10 +77,10 @@ void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out)
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory" : "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
); );
#else #else
m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv m_IVDecryption.Decrypt ((const CipherBlock *)in, (CipherBlock *)out); // iv
m_LayerDecryption.SetIV (out); m_LayerDecryption.SetIV (out);
m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv m_IVDecryption.Decrypt ((CipherBlock *)out, (CipherBlock *)out); // double iv
#endif #endif
} }

Loading…
Cancel
Save