From 41449cd5d9c6bafece6e962d197e4a058dffe974 Mon Sep 17 00:00:00 2001 From: Marcel Keller Date: Mon, 5 Nov 2018 16:00:29 +1100 Subject: [PATCH] Encrypted communication for replicated secret sharing. --- Auth/MAC_Check.cpp | 2 +- Auth/MAC_Check.h | 4 +- BMR/Party.cpp | 2 +- BMR/Register.cpp | 2 +- CHANGELOG.md | 3 ++ CONFIG | 1 + FHEOffline/PairwiseGenerator.h | 2 +- FHEOffline/PairwiseMachine.h | 2 +- FHEOffline/SimpleGenerator.h | 2 +- FHEOffline/SimpleMachine.cpp | 2 +- GC/Machine.h | 2 + GC/Machine.hpp | 1 + GC/ReplicatedParty.cpp | 14 ++++- GC/Thread.hpp | 8 ++- GC/ThreadMaster.hpp | 2 +- Networking/CryptoPlayer.cpp | 66 ++++++++++++++++++++++++ Networking/CryptoPlayer.h | 28 ++++++++++ Networking/Player.cpp | 75 ++++++++++++++++----------- Networking/Player.h | 94 ++++++++++++++++++++++------------ Networking/sockets.cpp | 18 +------ Networking/sockets.h | 35 +++++++++++-- Networking/ssl_sockets.h | 44 ++++++++++++++++ OT/NPartyTripleGenerator.h | 2 +- Player-Online.cpp | 2 +- Processor/Machine.cpp | 6 ++- Processor/Machine.h | 3 +- Processor/Online-Thread.cpp | 11 +++- Processor/Replicated.cpp | 3 +- README.md | 15 +++++- Scripts/setup-online.sh | 2 + Scripts/setup-ssl.sh | 11 ++++ Tools/ezOptionParser.h | 5 ++ Tools/octetStream.cpp | 8 +-- Tools/octetStream.h | 18 ++++--- Yao/YaoCommon.h | 3 ++ Yao/YaoEvaluator.cpp | 13 ++--- Yao/YaoEvaluator.h | 4 +- Yao/YaoGarbler.cpp | 3 +- replicated-ring-party.cpp | 15 +++++- spdz2-offline.cpp | 4 +- 40 files changed, 412 insertions(+), 125 deletions(-) create mode 100644 Networking/CryptoPlayer.cpp create mode 100644 Networking/CryptoPlayer.h create mode 100644 Networking/ssl_sockets.h create mode 100755 Scripts/setup-ssl.sh diff --git a/Auth/MAC_Check.cpp b/Auth/MAC_Check.cpp index 3d95ef21..46242201 100644 --- a/Auth/MAC_Check.cpp +++ b/Auth/MAC_Check.cpp @@ -224,7 +224,7 @@ Parallel_MAC_Check::Parallel_MAC_Check(const T& ai, Names& Nms, if (sum_players == 0) break; Player* summer_receive_player = summer_send_player; - summer_send_player = new Player(Nms, mc_base_id(3, thread_num)); + summer_send_player = new PlainPlayer(Nms, mc_base_id(3, thread_num)); summers.push_back(new Summer(sum_players, last_sum_players, next_sum_players, summer_send_player, summer_receive_player, *this)); pthread_create(&(summers[i]->thread), 0, run_summer_thread, summers[i]); diff --git a/Auth/MAC_Check.h b/Auth/MAC_Check.h index 04a17f9d..ca60a76f 100644 --- a/Auth/MAC_Check.h +++ b/Auth/MAC_Check.h @@ -122,7 +122,7 @@ template class Separate_MAC_Check: public MAC_Check { // Different channel for checks - Player check_player; + PlainPlayer check_player; protected: // No sense to expose this @@ -138,7 +138,7 @@ template class Parallel_MAC_Check: public Separate_MAC_Check { // Different channel for every round - Player send_player; + PlainPlayer send_player; // Managed by Summer Player* receive_player; diff --git a/BMR/Party.cpp b/BMR/Party.cpp index 19942cdf..5c6fb905 100644 --- a/BMR/Party.cpp +++ b/BMR/Party.cpp @@ -768,7 +768,7 @@ ProgramParty::ProgramParty(int argc, char** argv) : getline(schfile, curr); } cout << "Compiler: " << prev << endl; - P = new Player(N, 0); + P = new PlainPlayer(N, 0); if (argc > 4) threshold = atoi(argv[4]); else diff --git a/BMR/Register.cpp b/BMR/Register.cpp index 8b2c9966..5fd63785 100644 --- a/BMR/Register.cpp +++ b/BMR/Register.cpp @@ -925,7 +925,7 @@ void EvalRegister::store(GC::Memory& mem, Share tmp; gf2n ext = (int)reg.get_external(); //cout << "ext:" << ext << "/" << (int)reg.get_external() << " " << endl; - tmp.add(spdz_wire.mask, ext, party.get_id() - 1, party.get_mac_key()); + tmp.add(spdz_wire.mask, ext, (int)party.get_id() - 1, party.get_mac_key()); S.push_back(tmp); tmp *= gf2n(1) << i; dest += tmp; diff --git a/CHANGELOG.md b/CHANGELOG.md index 33801bb9..3fc607ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ The changelog explains changes pulled through from the private development repository. Bug fixes and small enchancements are committed between releases and not documented here. +## 0.0.5 (Nov 5, 2018) +- Encrypted communication for replicated secret sharing + ## 0.0.4 (Oct 11, 2018) - Added BMR, Yao's garbled circuits, and semi-honest 3-party replicated secret sharing for arithmetic and binary circuits. diff --git a/CONFIG b/CONFIG index f00df696..c67996bc 100644 --- a/CONFIG +++ b/CONFIG @@ -31,6 +31,7 @@ endif # MOD = -DMAX_MOD_SZ=2 LDLIBS = -lmpirxx -lmpir -lsodium $(MY_LDLIBS) -lm -lpthread +LDLIBS += -lboost_system -lssl -lcrypto ifeq ($(USE_NTL),1) LDLIBS := -lntl $(LDLIBS) diff --git a/FHEOffline/PairwiseGenerator.h b/FHEOffline/PairwiseGenerator.h index 830d12e1..58fea7d3 100644 --- a/FHEOffline/PairwiseGenerator.h +++ b/FHEOffline/PairwiseGenerator.h @@ -33,7 +33,7 @@ class PairwiseGenerator : public GeneratorBase public: PairwiseMachine& machine; - Player global_player; + PlainPlayer global_player; PairwiseGenerator(int thread_num, PairwiseMachine& machine); ~PairwiseGenerator(); diff --git a/FHEOffline/PairwiseMachine.h b/FHEOffline/PairwiseMachine.h index 0a3fd80b..f435e48d 100644 --- a/FHEOffline/PairwiseMachine.h +++ b/FHEOffline/PairwiseMachine.h @@ -15,7 +15,7 @@ class PairwiseMachine : public MachineBase public: PairwiseSetup setup_p; PairwiseSetup setup_2; - Player P; + PlainPlayer P; vector other_pks; FHE_PK& pk; diff --git a/FHEOffline/SimpleGenerator.h b/FHEOffline/SimpleGenerator.h index dc36afdd..bd52db14 100644 --- a/FHEOffline/SimpleGenerator.h +++ b/FHEOffline/SimpleGenerator.h @@ -22,7 +22,7 @@ protected: int thread_num; public: - Player P; + PlainPlayer P; pthread_t thread; long long total; diff --git a/FHEOffline/SimpleMachine.cpp b/FHEOffline/SimpleMachine.cpp index 7264681e..e66a5ee5 100644 --- a/FHEOffline/SimpleMachine.cpp +++ b/FHEOffline/SimpleMachine.cpp @@ -208,7 +208,7 @@ void MultiplicativeMachine::generate_setup(int slack) template void MultiplicativeMachine::fake_keys(int slack) { - Player P(N, -1 * N.num_players() * N.num_players()); + PlainPlayer P(N, -1 * N.num_players() * N.num_players()); octetStream os; PartSetup& part_setup = setup.part(); if (P.my_num() == 0) diff --git a/GC/Machine.h b/GC/Machine.h index d65a38bd..411f38d2 100644 --- a/GC/Machine.h +++ b/GC/Machine.h @@ -31,6 +31,8 @@ public: vector > progs; + bool use_encryption; + Machine(Memory& MD); ~Machine(); diff --git a/GC/Machine.hpp b/GC/Machine.hpp index 97678e12..f1b6ca59 100644 --- a/GC/Machine.hpp +++ b/GC/Machine.hpp @@ -16,6 +16,7 @@ namespace GC template Machine::Machine(Memory& dynamic_memory) : MD(dynamic_memory) { + use_encryption = false; start_timer(); } diff --git a/GC/ReplicatedParty.cpp b/GC/ReplicatedParty.cpp index 34b80a0b..eab0a996 100644 --- a/GC/ReplicatedParty.cpp +++ b/GC/ReplicatedParty.cpp @@ -42,6 +42,15 @@ ReplicatedParty::ReplicatedParty(int argc, const char** argv) "-pn", // Flag token. "--portnum" // Flag token. ); + opt.add( + "", // Default. + 0, // Required? + 0, // Number of args expected. + 0, // Delimiter if expecting multiple args. + "Unencrypted communication.", // Help description. + "-u", // Flag token. + "--unencrypted" // Flag token. + ); opt.parse(argc, argv); opt.syntax = "./replicated-bin-party.x [OPTIONS] "; if (opt.lastArgs.size() == 1) @@ -62,11 +71,14 @@ ReplicatedParty::ReplicatedParty(int argc, const char** argv) opt.get("-p")->getInt(my_num); opt.get("-pn")->getInt(pnb); opt.get("-h")->getString(hostname); + machine.use_encryption = not opt.get("-u")->isSet; if (my_num != 0) ReplicatedSecret::out.activate(false); - insecure("unencrypted communication"); + if (not machine.use_encryption) + insecure("unencrypted communication"); + Server* server = Server::start_networking(N, my_num, 3, hostname, pnb); run(); diff --git a/GC/Thread.hpp b/GC/Thread.hpp index e6e15bdb..16ab32dd 100644 --- a/GC/Thread.hpp +++ b/GC/Thread.hpp @@ -9,6 +9,8 @@ #include "ReplicatedSecret.h" #include "Secret.h" +#include "Networking/CryptoPlayer.h" + namespace GC { @@ -16,6 +18,7 @@ template void* Thread::run_thread(void* thread) { ((Thread*)thread)->run(); + OPENSSL_thread_stop(); return 0; } @@ -43,7 +46,10 @@ void Thread::run() throw runtime_error("there can only be one"); singleton = this; secure_prng.ReSeed(); - P = new Player(N, thread_num << 16); + if (machine.use_encryption) + P = new CryptoPlayer(N, thread_num << 16); + else + P = new PlainPlayer(N, thread_num << 16); protocol = new typename T::Protocol(*P); string input_file = "Player-Data/Input-P" + to_string(N.my_num()) + "-" + to_string(thread_num); processor.open_input_file(input_file); diff --git a/GC/ThreadMaster.hpp b/GC/ThreadMaster.hpp index c57ca169..e2a9eba3 100644 --- a/GC/ThreadMaster.hpp +++ b/GC/ThreadMaster.hpp @@ -53,7 +53,7 @@ Thread* ThreadMaster::new_thread(int i) template void ThreadMaster::run() { - P = new Player(N, 1 << 24); + P = new PlainPlayer(N, 1 << 24); machine.load_schedule(progname); for (int i = 0; i < machine.nthreads; i++) diff --git a/Networking/CryptoPlayer.cpp b/Networking/CryptoPlayer.cpp new file mode 100644 index 00000000..79848654 --- /dev/null +++ b/Networking/CryptoPlayer.cpp @@ -0,0 +1,66 @@ +/* + * CryptoPlayer.cpp + * + */ + +#include "CryptoPlayer.h" +#include "Math/Setup.h" + +CryptoPlayer::CryptoPlayer(const Names& Nms, int id_base) : + MultiPlayer(Nms, id_base), plaintext_player(Nms, id_base), + ctx(boost::asio::ssl::context::tls) +{ + string prefix = PREP_DIR "P" + to_string(my_num()); + ctx.use_certificate_file(prefix + ".pem", ctx.pem); + ctx.use_private_key_file(prefix + ".key", ctx.pem); + ctx.add_verify_path("Player-Data"); + + sockets.resize(num_players()); + + for (int i = 0; i < (int)sockets.size(); i++) + { + if (i == my_num()) + { + sockets[i] = 0; + continue; + } + + sockets[i] = new ssl_socket(io_service, ctx); + sockets[i]->lowest_layer().assign(boost::asio::ip::tcp::v4(), plaintext_player.socket(i)); + sockets[i]->set_verify_mode(boost::asio::ssl::verify_peer); + sockets[i]->set_verify_callback(boost::asio::ssl::rfc2818_verification("P" + to_string(i))); + if (i < my_num()) + sockets[i]->handshake(ssl_socket::client); + if (i > my_num()) + sockets[i]->handshake(ssl_socket::server); + } +} + +CryptoPlayer::~CryptoPlayer() +{ + plaintext_player.sockets.clear(); + for (int i = 0; i < num_players(); i++) + delete sockets[i]; +} + +template<> +void MultiPlayer::setup_sockets(const vector& names, + const vector& ports, int id_base, ServerSocket& server) +{ + (void)names, (void)ports, (void)id_base, (void)server; +} + +template<> +void send(ssl_socket* socket, int a) +{ + octet x = a; + send(socket, &x, 1); +} + +template<> +void receive(ssl_socket* socket, int& a) +{ + octet x; + receive(socket, &x, 1); + a = x; +} diff --git a/Networking/CryptoPlayer.h b/Networking/CryptoPlayer.h new file mode 100644 index 00000000..4fe5dde6 --- /dev/null +++ b/Networking/CryptoPlayer.h @@ -0,0 +1,28 @@ +/* + * CryptoPlayer.h + * + */ + +#ifndef NETWORKING_CRYPTOPLAYER_H_ +#define NETWORKING_CRYPTOPLAYER_H_ + +#include "ssl_sockets.h" +#include "Networking/Player.h" + +#include +#include + +class CryptoPlayer : public MultiPlayer +{ + PlainPlayer plaintext_player; + boost::asio::ssl::context ctx; + boost::asio::io_service io_service; + +public: + CryptoPlayer(const Names& Nms, int id_base=0); + ~CryptoPlayer(); + + bool is_encrypted() { return true; } +}; + +#endif /* NETWORKING_CRYPTOPLAYER_H_ */ diff --git a/Networking/Player.cpp b/Networking/Player.cpp index 3e7a1569..315165e5 100644 --- a/Networking/Player.cpp +++ b/Networking/Player.cpp @@ -1,5 +1,6 @@ #include "Player.h" +#include "ssl_sockets.h" #include "Exceptions/Exceptions.h" #include "Networking/STS.h" #include "Tools/int.h" @@ -166,23 +167,34 @@ Names::~Names() } - -Player::Player(const Names& Nms, int id) : - PlayerBase(Nms.my_num()), send_to_self_socket(-1) +Player::Player(const Names& Nms) : + PlayerBase(Nms.my_num()) { nplayers=Nms.nplayers; player_no=Nms.player_no; - setup_sockets(Nms.names, Nms.ports, id, *Nms.server); blk_SHA1_Init(&ctx); } +template +MultiPlayer::MultiPlayer(const Names& Nms, int id) : + Player(Nms), send_to_self_socket(0) +{ + setup_sockets(Nms.names, Nms.ports, id, *Nms.server); +} + + +template<> +MultiPlayer::~MultiPlayer() +{ + /* Close down the sockets */ + for (int i=0; ifirst << " " << 1e-6 * it->second.data << " MB in " << it->second.rounds << " rounds, taking " << it->second.timer.elapsed() @@ -195,7 +207,8 @@ Player::~Player() // Set up nmachines client and server sockets to send data back and fro // A machine is a server between it and player i if i<=my_number // Can also communicate with myself, but only with send_to and receive_from -void Player::setup_sockets(const vector& names,const vector& ports,int id_base,ServerSocket& server) +template<> +void MultiPlayer::setup_sockets(const vector& names,const vector& ports,int id_base,ServerSocket& server) { sockets.resize(nplayers); // Set up the client side @@ -231,30 +244,26 @@ void Player::setup_sockets(const vector& names,const vector& ports, } -void Player::send_long(int i, long a) const +template +void MultiPlayer::send_long(int i, long a) const { send(sockets[i], (octet*)&a, sizeof(long)); } -long Player::receive_long(int i) const +template +long MultiPlayer::receive_long(int i) const { long res; receive(sockets[i], (octet*)&res, sizeof(long)); return res; } -long Player::peek_long(int i) const + +template +void MultiPlayer::send_to(int player,const octetStream& o,bool donthash) const { - long res; - recv(sockets[i], &res, sizeof(res), MSG_PEEK); - return res; -} - - -void Player::send_to(int player,const octetStream& o,bool donthash) const -{ TimeScope ts(comm_stats["Sending directly"].add(o)); - int socket = socket_to_send(player); + T socket = socket_to_send(player); o.Send(socket); if (!donthash) { blk_SHA1_Update(&ctx,o.get_data(),o.get_length()); } @@ -262,7 +271,8 @@ void Player::send_to(int player,const octetStream& o,bool donthash) const } -void Player::send_all(const octetStream& o,bool donthash) const +template +void MultiPlayer::send_all(const octetStream& o,bool donthash) const { TimeScope ts(comm_stats["Sending to all"].add(o)); for (int i=0; i +void MultiPlayer::receive_player(int i,octetStream& o,bool donthash) const { TimeScope ts(timer); o.reset_write_head(); @@ -316,8 +327,8 @@ void Player::receive_relative(int offset, octetStream& o) const receive_player(positive_modulo(my_num() + offset, num_players()), o, true); } - -void Player::exchange(int other, octetStream& o) const +template +void MultiPlayer::exchange(int other, octetStream& o) const { TimeScope ts(comm_stats["Exchanging"].add(o)); o.exchange(sockets[other], sockets[other]); @@ -325,7 +336,8 @@ void Player::exchange(int other, octetStream& o) const } -void Player::pass_around(octetStream& o, int offset) const +template +void MultiPlayer::pass_around(octetStream& o, int offset) const { TimeScope ts(comm_stats["Passing around"].add(o)); o.exchange(sockets.at((my_num() + offset) % num_players()), @@ -337,7 +349,8 @@ void Player::pass_around(octetStream& o, int offset) const /* This is deliberately weird to avoid problems with OS max buffer * size getting in the way */ -void Player::Broadcast_Receive(vector& o,bool donthash) const +template +void MultiPlayer::Broadcast_Receive(vector& o,bool donthash) const { if (o.size() != sockets.size()) throw runtime_error("player numbers don't match"); @@ -373,7 +386,8 @@ void Player::Check_Broadcast() const blk_SHA1_Init(&ctx); } -void Player::wait_for_available(vector& players, vector& result) const +template<> +void MultiPlayer::wait_for_available(vector& players, vector& result) const { fd_set rfds; FD_ZERO(&rfds); @@ -409,7 +423,7 @@ void Player::wait_for_available(vector& players, vector& result) const } -ThreadPlayer::ThreadPlayer(const Names& Nms, int id_base) : Player(Nms, id_base) +ThreadPlayer::ThreadPlayer(const Names& Nms, int id_base) : PlainPlayer(Nms, id_base) { for (int i = 0; i < Nms.num_players(); i++) { @@ -622,3 +636,6 @@ void TwoPartyPlayer::exchange(octetStream& o) const sent += o.get_length(); o.exchange(socket, socket); } + +template class MultiPlayer; +template class MultiPlayer; diff --git a/Networking/Player.h b/Networking/Player.h index 6faf3023..3bd365db 100644 --- a/Networking/Player.h +++ b/Networking/Player.h @@ -40,6 +40,8 @@ public: ~CommsecKeysPackage(); }; +template class MultiPlayer; + /* Class to get the names off the server */ class Names { @@ -91,6 +93,7 @@ class Names friend class PlayerBase; friend class Player; + template friend class MultiPlayer; friend class TwoPartyPlayer; }; @@ -127,34 +130,76 @@ struct CommStats class Player : public PlayerBase { protected: - vector sockets; - int send_to_self_socket; - - void setup_sockets(const vector& names,const vector& ports,int id_base,ServerSocket& server); - int nplayers; mutable blk_SHA_CTX ctx; - map socket_players; - - int socket_to_send(int player) const { return player == player_no ? send_to_self_socket : sockets[player]; } - mutable map comm_stats; public: - // The offset is used for the multi-threaded call, to ensure different - // portnum bases in each thread - Player(const Names& Nms,int id_base=0); - + Player(const Names& Nms); virtual ~Player(); int num_players() const { return nplayers; } int my_num() const { return player_no; } - int socket(int i) const { return sockets[i]; } int get_offset(int other_player) const { return positive_modulo(other_player - my_num(), num_players()); } + virtual bool is_encrypted() { return false; } + + virtual void send_long(int i, long a) const = 0; + virtual long receive_long(int i) const = 0; + + virtual void send_all(const octetStream& o,bool donthash=false) const = 0; + virtual void send_to(int player,const octetStream& o,bool donthash=false) const = 0; + virtual void receive_player(int i,octetStream& o,bool donthash=false) const = 0; + virtual void receive_player(int i,FlexBuffer& buffer) const; + + // Communication relative to my number + void send_relative(const vector& o) const; + void send_relative(int offset, const octetStream& o) const; + void receive_relative(vector& o) const; + void receive_relative(int offset, octetStream& o) const; + + /* Broadcast and Receive data to/from all players + * - Assumes o[player_no] contains the thing broadcast by me + */ + virtual void Broadcast_Receive(vector& o,bool donthash=false) const = 0; + + /* Run Protocol To Verify Broadcast Is Correct + * - Resets the blk_SHA_CTX at the same time + */ + virtual void Check_Broadcast() const; + + // dummy functions for compatibility + virtual void request_receive(int i, octetStream& o) const { (void)i; (void)o; } + virtual void wait_receive(int i, octetStream& o, bool donthash=false) const { receive_player(i, o, donthash); } +}; + +template +class MultiPlayer : public Player +{ +protected: + vector sockets; + T send_to_self_socket; + + void setup_sockets(const vector& names,const vector& ports,int id_base,ServerSocket& server); + + map socket_players; + + T socket_to_send(int player) const { return player == player_no ? send_to_self_socket : sockets[player]; } + + friend class CryptoPlayer; + +public: + // The offset is used for the multi-threaded call, to ensure different + // portnum bases in each thread + MultiPlayer(const Names& Nms,int id_base=0); + + virtual ~MultiPlayer() {} + + T socket(int i) const { return sockets[i]; } + // Send/Receive data to/from player i // 8-bit ints only (mainly for testing) void send_int(int i,int a) const { send(sockets[i],a); } @@ -162,20 +207,12 @@ public: void send_long(int i, long a) const; long receive_long(int i) const; - long peek_long(int i) const; // Send an octetStream to all other players // -- And corresponding receive virtual void send_all(const octetStream& o,bool donthash=false) const; void send_to(int player,const octetStream& o,bool donthash=false) const; virtual void receive_player(int i,octetStream& o,bool donthash=false) const; - void receive_player(int i,FlexBuffer& buffer) const; - - // Communication relative to my number - void send_relative(const vector& o) const; - void send_relative(int offset, const octetStream& o) const; - void receive_relative(vector& o) const; - void receive_relative(int offset, octetStream& o) const; // exchange data with minimal memory usage void exchange(int other, octetStream& o) const; @@ -190,21 +227,14 @@ public: */ void Broadcast_Receive(vector& o,bool donthash=false) const; - /* Run Protocol To Verify Broadcast Is Correct - * - Resets the blk_SHA_CTX at the same time - */ - void Check_Broadcast() const; - // wait for available inputs void wait_for_available(vector& players, vector& result) const; - - // dummy functions for compatibility - virtual void request_receive(int i, octetStream& o) const { sockets[i]; o.get_length(); } - virtual void wait_receive(int i, octetStream& o, bool donthash=false) const { receive_player(i, o, donthash); } }; +typedef MultiPlayer PlainPlayer; -class ThreadPlayer : public Player + +class ThreadPlayer : public MultiPlayer { public: mutable vector receivers; diff --git a/Networking/sockets.cpp b/Networking/sockets.cpp index 18da7e28..ed704292 100644 --- a/Networking/sockets.cpp +++ b/Networking/sockets.cpp @@ -162,6 +162,7 @@ void close_client_socket(int socket) unsigned long long sent_amount = 0, sent_counter = 0; +template<> void send(int socket,int a) { unsigned char msg[1]; @@ -171,6 +172,7 @@ void send(int socket,int a) } +template<> void receive(int socket,int& a) { unsigned char msg[1]; @@ -183,22 +185,6 @@ void receive(int socket,int& a) } -void send(int socket, size_t a, size_t len) -{ - octet blen[len]; - encode_length(blen, a, len); - send(socket, blen, len); -} - - -void receive(int socket, size_t& a, size_t len) -{ - octet blen[len]; - receive(socket, blen, len); - a = decode_length(blen, len); -} - - void send_ack(int socket) { diff --git a/Networking/sockets.h b/Networking/sockets.h index 1f0e45f5..3e3069d5 100644 --- a/Networking/sockets.h +++ b/Networking/sockets.h @@ -34,12 +34,21 @@ void set_up_client_socket(int& mysocket,const char* hostname,int Portnum); void close_client_socket(int socket); /* Send and receive 8 bit integers */ -void send(int socket,int a); -void receive(int socket,int& a); +template +void send(T socket,int a); +template +void receive(T socket,int& a); // same for words -void send(int socket, size_t a, size_t len); -void receive(int socket, size_t& a, size_t len); +template +void send(T& socket, size_t a, size_t len); +template +void receive(T& socket, size_t& a, size_t len); + +template +void send(T socket, octet* msg, size_t len); +template +void receive(T socket, octet* msg, size_t len); void send_ack(int socket); int get_ack(int socket); @@ -47,6 +56,7 @@ int get_ack(int socket); extern unsigned long long sent_amount, sent_counter; +template<> inline void send(int socket,octet *msg,size_t len) { size_t i = 0; @@ -62,6 +72,15 @@ inline void send(int socket,octet *msg,size_t len) sent_counter++; } +template +inline void send(T& socket, size_t a, size_t len) +{ + octet blen[len]; + encode_length(blen, a, len); + send(socket, blen, len); +} + +template<> inline void receive(int socket,octet *msg,size_t len) { size_t i=0; @@ -88,6 +107,14 @@ inline void receive(int socket,octet *msg,size_t len) } } +template +inline void receive(T& socket, size_t& a, size_t len) +{ + octet blen[len]; + receive(socket, blen, len); + a = decode_length(blen, len); +} + inline size_t check_non_blocking_result(int res) { if (res < 0) diff --git a/Networking/ssl_sockets.h b/Networking/ssl_sockets.h new file mode 100644 index 00000000..197f41cf --- /dev/null +++ b/Networking/ssl_sockets.h @@ -0,0 +1,44 @@ +/* + * sockets.h + * + */ + +#ifndef CRYPTO_SSL_SOCKETS_H_ +#define CRYPTO_SSL_SOCKETS_H_ + +#include "Tools/int.h" +#include "sockets.h" + +#include +#include + +typedef boost::asio::ssl::stream ssl_socket; + +template<> +inline void send(ssl_socket* socket, octet* data, size_t length) +{ + size_t sent = 0; + while (sent < length) + sent += socket->write_some(boost::asio::buffer(data + sent, length - sent)); +} + +template<> +inline void receive(ssl_socket* socket, octet* data, size_t length) +{ + size_t received = 0; + while (received < length) + received += socket->read_some(boost::asio::buffer(data + received, length - received)); +} + +inline size_t receive_non_blocking(ssl_socket* socket, octet* data, int length) +{ + return socket->read_some(boost::asio::buffer(data, length)); +} + +inline size_t receive_all_or_nothing(ssl_socket* socket, octet* data, size_t length) +{ + receive(socket, data, length); + return length; +} + +#endif /* CRYPTO_SSL_SOCKETS_H_ */ diff --git a/OT/NPartyTripleGenerator.h b/OT/NPartyTripleGenerator.h index 44888bfe..9777d825 100644 --- a/OT/NPartyTripleGenerator.h +++ b/OT/NPartyTripleGenerator.h @@ -23,7 +23,7 @@ class ShareTriple; class NPartyTripleGenerator { //OTTripleSetup* setup; - Player globalPlayer; + PlainPlayer globalPlayer; int thread_num; int my_num; diff --git a/Player-Online.cpp b/Player-Online.cpp index f1eb06e5..0d435dbf 100644 --- a/Player-Online.cpp +++ b/Player-Online.cpp @@ -255,7 +255,7 @@ int main(int argc, const char** argv) { Machine(playerno, playerNames, progname, memtype, lgp, lg2, opt.get("--direct")->isSet, opening_sum, opt.get("--parallel")->isSet, - opt.get("--threads")->isSet, max_broadcast).run(); + opt.get("--threads")->isSet, max_broadcast, false).run(); if (server) delete server; diff --git a/Processor/Machine.cpp b/Processor/Machine.cpp index c81abf2e..f6c21079 100644 --- a/Processor/Machine.cpp +++ b/Processor/Machine.cpp @@ -34,10 +34,12 @@ BaseMachine::BaseMachine() : nthreads(0) template Machine::Machine(int my_number, Names& playerNames, string progname_str, string memtype, int lgp, int lg2, bool direct, - int opening_sum, bool parallel, bool receive_threads, int max_broadcast) + int opening_sum, bool parallel, bool receive_threads, int max_broadcast, + bool use_encryption) : my_number(my_number), N(playerNames), tn(0), numt(0), usage_unknown(false), direct(direct), opening_sum(opening_sum), parallel(parallel), - receive_threads(receive_threads), max_broadcast(max_broadcast) + receive_threads(receive_threads), max_broadcast(max_broadcast), + use_encryption(use_encryption) { if (opening_sum < 2) this->opening_sum = N.num_players(); diff --git a/Processor/Machine.h b/Processor/Machine.h index 3015e5b8..eab3f44d 100644 --- a/Processor/Machine.h +++ b/Processor/Machine.h @@ -97,10 +97,11 @@ class Machine : public BaseMachine bool parallel; bool receive_threads; int max_broadcast; + bool use_encryption; Machine(int my_number, Names& playerNames, string progname, string memtype, int lgp, int lg2, bool direct, int opening_sum, bool parallel, - bool receive_threads, int max_broadcast); + bool receive_threads, int max_broadcast, bool use_encryption); DataPositions run_tape(int thread_number, int tape_number, int arg, int line_number); void join_tape(int thread_number); diff --git a/Processor/Online-Thread.cpp b/Processor/Online-Thread.cpp index 3ba5f7b3..4bb0183b 100644 --- a/Processor/Online-Thread.cpp +++ b/Processor/Online-Thread.cpp @@ -5,6 +5,7 @@ #include "Processor/Data_Files.h" #include "Processor/Machine.h" #include "Processor/Processor.h" +#include "Networking/CryptoPlayer.h" #include #include @@ -25,10 +26,15 @@ void* Sub_Main_Func(void* ptr) int num=tinfo->thread_num; fprintf(stderr, "\tI am in thread %d\n",num); Player* player; - if (!machine.receive_threads or machine.direct or machine.parallel) + if (machine.use_encryption) + { + cerr << "Using encrypted single-threaded communication" << endl; + player = new CryptoPlayer(*(tinfo->Nms), num << 16); + } + else if (!machine.receive_threads or machine.direct or machine.parallel) { cerr << "Using single-threaded receiving" << endl; - player = new Player(*(tinfo->Nms), num << 16); + player = new PlainPlayer(*(tinfo->Nms), num << 16); } else { @@ -164,6 +170,7 @@ void* Sub_Main_Func(void* ptr) delete MCp; delete player; + OPENSSL_thread_stop(); return NULL; } diff --git a/Processor/Replicated.cpp b/Processor/Replicated.cpp index 27a33e52..88ce5bcf 100644 --- a/Processor/Replicated.cpp +++ b/Processor/Replicated.cpp @@ -17,7 +17,8 @@ Replicated::Replicated(Player& P) : ReplicatedBase(P), counter(0) ReplicatedBase::ReplicatedBase(Player& P) { - insecure("unencrypted communication"); + if (not P.is_encrypted()) + insecure("unencrypted communication"); shared_prngs[0].ReSeed(); octetStream os; diff --git a/README.md b/README.md index 9e38395c..e3f6e024 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,9 @@ compute the preprocessing time for a particulor computation. - GCC (tested with 7.3) or LLVM (tested with 6.0; remove `-no-pie` from `CONFIG`) - MPIR library, compiled with C++ support (use flag --enable-cxx when running configure) - libsodium library, tested against 1.0.16 + - OpenSSL, tested against 1.1.0 + - Boost.Asio with SSL support, tested against 1.65 + - Boost.Thread for BMR, tested against 1.65 - CPU supporting AES-NI, PCLMUL, AVX2 - Python 2.x - NTL library for the SPDZ-2 and Overdrive offline phases (optional; tested with NTL 10.5) @@ -93,10 +96,10 @@ compute the preprocessing time for a particulor computation. 1) Edit `CONFIG` or `CONFIG.mine` to your needs: - - To benchmark anything other than Yao's garbled circuits, add the following line at the top: `MY_CFLAGS = -DINSECURE` + - To benchmark anything other than replicated secret sharing for binary circuits, Yao's garbled circuits, or covertly secure SPDZ, add the following line at the top: `MY_CFLAGS = -DINSECURE` - `PREP_DIR` should point to should be a local, unversioned directory to store preprocessing data (default is `Player-Data` in the current directory). - For the SPDZ-2 and Overdrive offline phases, set `USE_NTL = 1` and `MOD = -DMAX_MOD_SZ=6`. - - To use GF(2^40), set `USE_GF2N_LONG = 0`. This will deactive anything that requires GF(2^128) such as MASCOT. + - To use GF(2^40), in particular for the SPDZ-2 offline phase, set `USE_GF2N_LONG = 0`. This will deactive anything that requires GF(2^128) such as MASCOT. 2) Run make to compile all the software (use the flag -j for faster compilation multiple threads). See below on how to compile specific @@ -201,6 +204,8 @@ Run setup to create necessary files and random bits (needed for comparisons etc. `Scripts/setup-online.sh 3` +This will also generate SSL keys and certificates. See the section replicated secret sharing for binary circuits below for details. + In order to compile a program, use `./compile.py -R 64`, for example: `./compile.py -R 64 tutorial` @@ -231,6 +236,12 @@ Compile the virtual machine: `make -j 8 replicated-bin-party.x` +Set up SSL certificate and keys: + +`Scripts/setup-ssl.sh` + +The programs expect the keys and certificates to be in `Player-Data/P.key` and Player-Data/P.pem`, respectively, and the certificates to have the common name 'P' for player ``. Furthermore, the relevant root certificates have to be in `Player-Data` such that OpenSSL can find them (run `c_rehash Player-Data`). The script above takes care of all this by generating self-signed certificates. Therefore, if you are running the programs on different hosts you will need to copy the certificate files. + After compilating the mpc file, run as follows: `replicated-bin-party.x -h -p <0/1/2> gc_tutorial` diff --git a/Scripts/setup-online.sh b/Scripts/setup-online.sh index cafd03b2..0b1cec88 100755 --- a/Scripts/setup-online.sh +++ b/Scripts/setup-online.sh @@ -28,6 +28,8 @@ do echo "$arg" | grep -E -q '^[0-9]+$' || die "Integer argument required, $arg provided" done +$HERE/setup-ssl.sh ${players} + $SPDZROOT/Fake-Offline.x ${players} -lgp ${bits} -lg2 ${g} --default ${default} for i in $(seq 0 $[players-1]) ; do diff --git a/Scripts/setup-ssl.sh b/Scripts/setup-ssl.sh new file mode 100755 index 00000000..a85006bf --- /dev/null +++ b/Scripts/setup-ssl.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +n=${1:-3} + +echo Setting up SSL for $n parties + +for i in `seq 0 $[n-1]`; do + openssl req -nodes -x509 -out Player-Data/P$i.pem -keyout Player-Data/P$i.key -subj "/CN=P$i" +done + +c_rehash Player-Data diff --git a/Tools/ezOptionParser.h b/Tools/ezOptionParser.h index e76d606c..500ffee7 100644 --- a/Tools/ezOptionParser.h +++ b/Tools/ezOptionParser.h @@ -1319,6 +1319,7 @@ public: // How to layout usage descriptions with the option flags. enum Layout { ALIGN, INTERLEAVE, STAGGER }; + inline ezOptionParser(); inline ~ezOptionParser(); inline void add(const char * defaults, bool required, int expectArgs, char delim, const char * help, const char * flag1, ezOptionValidator* validator=0); @@ -1368,6 +1369,10 @@ public: std::map< int, int > groupValidators; }; /* ################################################################### */ +ezOptionParser::ezOptionParser() { + reset(); +} +/* ################################################################### */ ezOptionParser::~ezOptionParser() { reset(); } diff --git a/Tools/octetStream.cpp b/Tools/octetStream.cpp index 7408f667..978b796e 100644 --- a/Tools/octetStream.cpp +++ b/Tools/octetStream.cpp @@ -5,6 +5,7 @@ #include "octetStream.h" #include #include "Networking/sockets.h" +#include "Networking/ssl_sockets.h" #include "Tools/sha1.h" #include "Exceptions/Exceptions.h" #include "Networking/data.h" @@ -184,7 +185,8 @@ void octetStream::get(bigint& ans) } -void octetStream::exchange(int send_socket, int receive_socket, octetStream& receive_stream) +template +void octetStream::exchange(T send_socket, T receive_socket, octetStream& receive_stream) { send(send_socket, len, LENGTH_SIZE); const size_t buffer_size = 100000; @@ -372,5 +374,5 @@ ostream& operator<<(ostream& s,const octetStream& o) } - - +template void octetStream::exchange(int, int); +template void octetStream::exchange(ssl_socket*, ssl_socket*); diff --git a/Tools/octetStream.h b/Tools/octetStream.h index c9c2dfcd..36435f27 100644 --- a/Tools/octetStream.h +++ b/Tools/octetStream.h @@ -133,8 +133,10 @@ class octetStream s.len=l; } - void Send(int socket_num) const; - void Receive(int socket_num); + template + void Send(T& socket_num) const; + template + void Receive(T& socket_num); void ReceiveExpected(int socket_num, size_t expected); // In-place authenticated encryption using sodium; key of length crypto_generichash_BYTES @@ -153,8 +155,10 @@ class octetStream void input(istream& s); void output(ostream& s); - void exchange(int send_socket, int receive_socket) { exchange(send_socket, receive_socket, *this); } - void exchange(int send_socket, int receive_socket, octetStream& receive_stream); + template + void exchange(T send_socket, T receive_socket) { exchange(send_socket, receive_socket, *this); } + template + void exchange(T send_socket, T receive_socket, octetStream& receive_stream); friend ostream& operator<<(ostream& s,const octetStream& o); friend class PRNG; @@ -226,14 +230,16 @@ inline size_t octetStream::get_int(int n_bytes) } -inline void octetStream::Send(int socket_num) const +template +inline void octetStream::Send(T& socket_num) const { send(socket_num,len,LENGTH_SIZE); send(socket_num,data,len); } -inline void octetStream::Receive(int socket_num) +template +inline void octetStream::Receive(T& socket_num) { size_t nlen=0; receive(socket_num,nlen,LENGTH_SIZE); diff --git a/Yao/YaoCommon.h b/Yao/YaoCommon.h index 1c52ebde..95fbcb28 100644 --- a/Yao/YaoCommon.h +++ b/Yao/YaoCommon.h @@ -13,6 +13,9 @@ class YaoCommon int log_n_threads; public: + static const int DONE = -1; + static const int MORE = -2; + long counter; YaoCommon() : diff --git a/Yao/YaoEvaluator.cpp b/Yao/YaoEvaluator.cpp index c772245e..5c5f107c 100644 --- a/Yao/YaoEvaluator.cpp +++ b/Yao/YaoEvaluator.cpp @@ -18,7 +18,7 @@ YaoEvaluator::YaoEvaluator(int thread_num, YaoEvalMaster& master) : void YaoEvaluator::pre_run() { - if (not continous()) + if (not continuous()) receive_to_store(*P); } @@ -26,7 +26,7 @@ void YaoEvaluator::run(GC::Program>& program) { singleton = this; - if (continous()) + if (continuous()) run(program, *P); else { @@ -52,19 +52,20 @@ void YaoEvaluator::run_from_store(GC::Program>& program) while(GC::DONE_BREAK != program.execute(processor, -1)); } -void YaoEvaluator::receive(Player& P) +bool YaoEvaluator::receive(Player& P) { + if (P.receive_long(0) == YaoCommon::DONE) + return false; P.receive_player(0, gates); P.receive_player(0, output_masks); + return true; } void YaoEvaluator::receive_to_store(Player& P) { - while (P.peek_long(0) != -1) + while (receive(P)) { - receive(P); gates_store.push(gates); output_masks_store.push(output_masks); } - P.receive_long(0); } diff --git a/Yao/YaoEvaluator.h b/Yao/YaoEvaluator.h index b8773d88..062f9cf0 100644 --- a/Yao/YaoEvaluator.h +++ b/Yao/YaoEvaluator.h @@ -39,13 +39,13 @@ public: YaoEvaluator(int thread_num, YaoEvalMaster& master); - bool continous() { return master.continuous and thread_num == 0; } + bool continuous() { return master.continuous and thread_num == 0; } void pre_run(); void run(GC::Program>& program); void run(GC::Program>& program, Player& P); void run_from_store(GC::Program>& program); - void receive(Player& P); + bool receive(Player& P); void receive_to_store(Player& P); void load_gate(YaoGate& gate); diff --git a/Yao/YaoGarbler.cpp b/Yao/YaoGarbler.cpp index 5f74d40d..36d72b83 100644 --- a/Yao/YaoGarbler.cpp +++ b/Yao/YaoGarbler.cpp @@ -67,13 +67,14 @@ void YaoGarbler::post_run() { if (not (master.continuous and thread_num == 0)) { - P->send_long(1, -1); + P->send_long(1, YaoCommon::DONE); process_receiver_inputs(); } } void YaoGarbler::send(Player& P) { + P.send_long(1, YaoCommon::MORE); P.send_to(1, gates, true); P.send_to(1, output_masks, true); } diff --git a/replicated-ring-party.cpp b/replicated-ring-party.cpp index e9324e19..66864a65 100644 --- a/replicated-ring-party.cpp +++ b/replicated-ring-party.cpp @@ -30,6 +30,15 @@ int main(int argc, const char** argv) "-pn", // Flag token. "--portnum" // Flag token. ); + opt.add( + "", // Default. + 0, // Required? + 0, // Number of args expected. + 0, // Delimiter if expecting multiple args. + "Unencrypted communication.", // Help description. + "-u", // Flag token. + "--unencrypted" // Flag token. + ); opt.syntax = "./replicated-ring-party.x [OPTIONS] "; opt.parse(argc, argv); vector allArgs(opt.firstArgs); @@ -60,13 +69,15 @@ int main(int argc, const char** argv) string hostname; opt.get("-pn")->getInt(pnb); opt.get("-h")->getString(hostname); + bool use_encryption = not opt.get("-u")->isSet; - insecure("unencrypted communication"); + if (not use_encryption) + insecure("unencrypted communication"); Names N; Server* server = Server::start_networking(N, playerno, 3, hostname, pnb); Machine(playerno, N, progname, "empty", 128, - gf2n::default_degree(), 0, 0, 0, 0, 0).run(); + gf2n::default_degree(), 0, 0, 0, 0, 0, use_encryption).run(); if (server) delete server; diff --git a/spdz2-offline.cpp b/spdz2-offline.cpp index 6ea48bdc..bdcfd509 100644 --- a/spdz2-offline.cpp +++ b/spdz2-offline.cpp @@ -60,7 +60,7 @@ public: { PartSetup& setup = setup_thread.setup; const Spdz2& spdz2 = setup_thread.spdz2; - Player P(spdz2.N, ((id + 1) << 8) + FD::T::type_char()); + PlainPlayer P(spdz2.N, ((id + 1) << 8) + FD::T::type_char()); EncCommit_ EC(P, setup.pk, spdz2.covert, producer.required_randomness()); DistDecrypt dd(P, setup.sk, setup.pk, setup.FieldD); MAC_Check MC(setup.alphai); @@ -120,7 +120,7 @@ public: void* run() { - Player P(spdz2.N, FD::T::type_char()); + PlainPlayer P(spdz2.N, FD::T::type_char()); setup.generate_setup(P.num_players(), plaintext_length, spdz2.sec, 0, false); Run_Gen_Protocol(setup.pk, setup.sk, P, spdz2.covert, false); generate_mac_key(setup.alphai, setup.calpha, setup.FieldD, setup.pk, P, spdz2.covert);