|
@@ -63,6 +63,39 @@ static bool hextobuf(unsigned char *buf, const char *str, size_t len)
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+void displayMessage(unsigned char *msg, uint16_t msg_size) {
|
|
|
+ clientid_t sid, rid;
|
|
|
+ unsigned char *ptr = msg;
|
|
|
+ sid = *((clientid_t*) ptr);
|
|
|
+ ptr+=sizeof(sid);
|
|
|
+ rid = *((clientid_t*) ptr);
|
|
|
+ printf("Sender ID: %d, Receiver ID: %d, Token: N/A\n", sid, rid );
|
|
|
+ printf("Message: ");
|
|
|
+ for(int j = 0; j<msg_size - sizeof(sid)*2; j++) {
|
|
|
+ printf("%x", (*ptr));
|
|
|
+ ptr++;
|
|
|
+ }
|
|
|
+ printf("\n");
|
|
|
+}
|
|
|
+
|
|
|
+void displayMessageBundle(unsigned char *bundle, uint16_t priv_out, uint16_t msg_size) {
|
|
|
+ unsigned char *ptr = bundle;
|
|
|
+ uint64_t header = *((uint64_t*) ptr);
|
|
|
+ ptr+=sizeof(uint64_t);
|
|
|
+
|
|
|
+ for(int i=0; i<priv_out; i++) {
|
|
|
+ displayMessage(ptr, msg_size);
|
|
|
+ printf("\n");
|
|
|
+ ptr+=msg_size;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+#define HEADER_SIZE 8
|
|
|
+static inline uint32_t messageBundleSize(uint16_t priv_out, uint16_t msg_size) {
|
|
|
+ return(HEADER_SIZE + (priv_out * msg_size) + SGX_AESGCM_MAC_SIZE);
|
|
|
+}
|
|
|
+
|
|
|
bool config_parse(Config &config, const std::string configstr,
|
|
|
std::vector<NodeConfig> &ingestion_nodes,
|
|
|
std::vector<NodeConfig> &storage_nodes)
|
|
@@ -160,11 +193,11 @@ static void usage(const char *argv0)
|
|
|
|
|
|
/*
|
|
|
|
|
|
- Generate ESK (Encryption master Secret Key) and TSK (Token master Secret Key)
|
|
|
+ Generate EMK (Encryption master Secret Key) and TMK (Token master Secret Key)
|
|
|
|
|
|
*/
|
|
|
int generateMasterKeys(sgx_aes_gcm_128bit_key_t master_secret,
|
|
|
- aes_key &ESK, aes_key &TSK )
|
|
|
+ aes_key &EMK, aes_key &TMK )
|
|
|
{
|
|
|
unsigned char zeroes[SGX_AESGCM_KEY_SIZE];
|
|
|
unsigned char iv[SGX_AESGCM_IV_SIZE];
|
|
@@ -174,30 +207,30 @@ int generateMasterKeys(sgx_aes_gcm_128bit_key_t master_secret,
|
|
|
memcpy(iv, "Encryption", sizeof("Encryption"));
|
|
|
|
|
|
if (sizeof(zeroes) != gcm_encrypt(zeroes, SGX_AESGCM_KEY_SIZE, NULL, 0,
|
|
|
- master_secret, iv, SGX_AESGCM_IV_SIZE, ESK, mac)) {
|
|
|
+ master_secret, iv, SGX_AESGCM_IV_SIZE, EMK, mac)) {
|
|
|
printf("Client: generateMasterKeys FAIL\n");
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
- printf("Encryption Master Key: ");
|
|
|
+ printf("\n\nEncryption Master Key: ");
|
|
|
for(int i=0;i<SGX_AESGCM_KEY_SIZE;i++) {
|
|
|
- printf("%x", ESK[i]);
|
|
|
+ printf("%x", EMK[i]);
|
|
|
}
|
|
|
- printf("\n\n");
|
|
|
+ printf("\n");
|
|
|
|
|
|
memset(iv, 0, SGX_AESGCM_IV_SIZE);
|
|
|
memcpy(iv, "Token", sizeof("Token"));
|
|
|
if (sizeof(zeroes) != gcm_encrypt(zeroes, SGX_AESGCM_KEY_SIZE, NULL, 0,
|
|
|
- master_secret, iv, SGX_AESGCM_IV_SIZE, TSK, mac)) {
|
|
|
+ master_secret, iv, SGX_AESGCM_IV_SIZE, TMK, mac)) {
|
|
|
printf("generateMasterKeys failed\n");
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
printf("Token Master Key: ");
|
|
|
for(int i=0;i<SGX_AESGCM_KEY_SIZE;i++) {
|
|
|
- printf("%x", TSK[i]);
|
|
|
+ printf("%x", TMK[i]);
|
|
|
}
|
|
|
- printf("\n");
|
|
|
+ printf("\n\n");
|
|
|
|
|
|
return 1;
|
|
|
}
|
|
@@ -206,26 +239,139 @@ int generateMasterKeys(sgx_aes_gcm_128bit_key_t master_secret,
|
|
|
Takes the client_number, the master aes_key for generating client encryption keys,
|
|
|
and the client aes_key to be generated.
|
|
|
*/
|
|
|
-int generateClientEncryptionKey(clientid_t client_number, aes_key &ESK, aes_key &client_key)
|
|
|
+int generateClientEncryptionKey(clientid_t client_number, aes_key &EMK, aes_key &client_key)
|
|
|
{
|
|
|
unsigned char zeroes[SGX_AESGCM_KEY_SIZE];
|
|
|
- unsigned char mac[SGX_AESGCM_MAC_SIZE];
|
|
|
unsigned char iv[SGX_AESGCM_IV_SIZE];
|
|
|
- memset(zeroes, 0, SGX_AESGCM_KEY_SIZE);
|
|
|
+ unsigned char tag[SGX_AESGCM_MAC_SIZE];
|
|
|
memset(iv, 0, SGX_AESGCM_IV_SIZE);
|
|
|
- memcpy(iv, (unsigned char*) (&client_number), sizeof(client_number));
|
|
|
+ memset(zeroes, 0, SGX_AESGCM_KEY_SIZE);
|
|
|
+ memset(tag, 0, SGX_AESGCM_KEY_SIZE);
|
|
|
+ memcpy(iv, &client_number, sizeof(client_number));
|
|
|
+
|
|
|
+ printf("Client Key: (before Gen) ");
|
|
|
+ for(int i=0;i<SGX_AESGCM_KEY_SIZE;i++) {
|
|
|
+ printf("%x", client_key[i]);
|
|
|
+ }
|
|
|
+ printf("\n");
|
|
|
|
|
|
- // GCM-encrypt, using the chunk key as the associated data
|
|
|
- if (sizeof(zeroes) != gcm_encrypt(zeroes, SGX_AESGCM_KEY_SIZE, NULL, 0, ESK,
|
|
|
- iv, SGX_AESGCM_IV_SIZE, client_key, mac)) {
|
|
|
+
|
|
|
+ if (sizeof(zeroes) != gcm_encrypt(zeroes, SGX_AESGCM_KEY_SIZE, NULL, 0, EMK,
|
|
|
+ iv, SGX_AESGCM_IV_SIZE, client_key, tag)) {
|
|
|
printf("generateClientEncryptionKey failed\n");
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ printf("Client Key: (after Gen) ");
|
|
|
+ for(int i=0;i<SGX_AESGCM_KEY_SIZE;i++) {
|
|
|
+ printf("%x", client_key[i]);
|
|
|
+ }
|
|
|
+ printf("\n");
|
|
|
+
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
|
|
|
+void Client::initializeSocket(boost::asio::io_context &ioc,
|
|
|
+ NodeConfig &ing_server) {
|
|
|
+
|
|
|
+ boost::system::error_code err;
|
|
|
+ boost::asio::ip::tcp::resolver resolver(ioc);
|
|
|
+
|
|
|
+ while(1) {
|
|
|
+#ifdef VERBOSE_NET
|
|
|
+ std::cerr << "Connecting to " << ing_server.name << "...\n";
|
|
|
+ std::cout << ing_server.clistenhost << ":" << ing_server.clistenport;
|
|
|
+#endif
|
|
|
+ // ingestion_sock needs io_context
|
|
|
+ ingestion_sock = new boost::asio::ip::tcp::socket(ioc);
|
|
|
+ boost::asio::connect(*ingestion_sock,
|
|
|
+ resolver.resolve(ing_server.clistenhost,
|
|
|
+ ing_server.clistenport), err);
|
|
|
+ if (!err) break;
|
|
|
+ std::cerr << "Connection to " << ing_server.name <<
|
|
|
+ " refused, will retry.\n";
|
|
|
+ sleep(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ // Test write 7 to the socket
|
|
|
+ nodenum_t node_num = 7;
|
|
|
+ boost::asio::write(*ingestion_sock,
|
|
|
+ boost::asio::buffer(&node_num, sizeof(node_num)));
|
|
|
+ */
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+
|
|
|
+ Populates the buffer payload with a valid message payload.
|
|
|
+ Assumes that it is supplied with a payload buffer of the correct length
|
|
|
+
|
|
|
+ Correct length for payload = 8 + (priv_out)*(msg_size) + 16 bytes
|
|
|
+
|
|
|
+*/
|
|
|
+void Client::generateMessageBundle(uint8_t priv_out, uint32_t msg_size,
|
|
|
+ unsigned char *payload)
|
|
|
+{
|
|
|
+ unsigned char *ptr = payload;
|
|
|
+ uint64_t header = (id << 8) + CLIENT_MESSAGE_BUNDLE;
|
|
|
+
|
|
|
+ // Setup header
|
|
|
+ memcpy(ptr, (uint8_t*) &header, sizeof(header));
|
|
|
+ ptr+=sizeof(header);
|
|
|
+
|
|
|
+ // Setup message payload
|
|
|
+ for(uint32_t i = 0; i < priv_out; i++) {
|
|
|
+ memcpy(ptr, &id, sizeof(id));
|
|
|
+ ptr+=(sizeof(id));
|
|
|
+ memcpy(ptr, &i, sizeof(i));
|
|
|
+ ptr+=(sizeof(i));
|
|
|
+
|
|
|
+ uint32_t remaining_message_size = msg_size - (sizeof(id)*2);
|
|
|
+ memset(ptr, 0, remaining_message_size);
|
|
|
+ ptr+=(remaining_message_size);
|
|
|
+ }
|
|
|
+
|
|
|
+ memset(ptr, 0, SGX_AESGCM_MAC_SIZE);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void Client::encryptMessageBundle(uint32_t bundle_size, unsigned char *payload)
|
|
|
+{
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+
|
|
|
+ Assumes payload is a buffer of size messageBundleSize(priv_out, msg_size)
|
|
|
+*/
|
|
|
+
|
|
|
+void Client::sendMessageBundle(uint16_t priv_out, uint16_t msg_size,
|
|
|
+ unsigned char *payload)
|
|
|
+{
|
|
|
+ uint32_t bundle_size = messageBundleSize(priv_out, msg_size);
|
|
|
+
|
|
|
+ generateMessageBundle(priv_out, msg_size, payload);
|
|
|
+
|
|
|
+ //encryptMessageBundle(bundle_size, payload);
|
|
|
+
|
|
|
+ displayMessageBundle(payload, priv_out, msg_size);
|
|
|
+ //Send over the ingestion_sock
|
|
|
+
|
|
|
+ boost::asio::write(*ingestion_sock,
|
|
|
+ boost::asio::buffer(payload, bundle_size));
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+ Spin config.user_client actual clients. Each client:
|
|
|
+ 1) Retrieve messages and tokens from their storage server
|
|
|
+ 2) Send all their messages to the ingestion server
|
|
|
+ 3) Wait for a predetermined EPOCH_DURATION time
|
|
|
+ 4) Repeat from 1)
|
|
|
+*/
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
{
|
|
@@ -250,6 +396,7 @@ int main(int argc, char **argv)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ printf("nthreads = %d\n", nthreads);
|
|
|
// Read the config.json from the first line of stdin. We have to do
|
|
|
// this before outputting anything to avoid potential deadlock with
|
|
|
// the launch program.
|
|
@@ -257,87 +404,68 @@ int main(int argc, char **argv)
|
|
|
std::getline(std::cin, configstr);
|
|
|
|
|
|
Config config;
|
|
|
- aes_key ESK, TSK;
|
|
|
- Client *clients = new Client[config.user_count];
|
|
|
+ aes_key EMK, TMK, client_key;
|
|
|
+ boost::asio::io_context io_context;
|
|
|
+ boost::asio::ip::tcp::resolver resolver(io_context);
|
|
|
|
|
|
if (!config_parse(config, configstr, ingestion_nodes, storage_nodes)) {
|
|
|
exit(1);
|
|
|
}
|
|
|
|
|
|
+ Client *clients = new Client[config.user_count];
|
|
|
printf("Number of ingestion_nodes = %ld, Number of storage_node = %ld\n",
|
|
|
ingestion_nodes.size(), storage_nodes.size());
|
|
|
|
|
|
- generateMasterKeys(config.master_secret, ESK, TSK);
|
|
|
+ generateMasterKeys(config.master_secret, EMK, TMK);
|
|
|
|
|
|
- uint32_t clients_per_ing = CEILDIV(config.user_count, ingestion_nodes.size());
|
|
|
- aes_key client_key;
|
|
|
+ uint32_t num_clients_total = config.user_count;
|
|
|
+ uint16_t num_ing_nodes = ingestion_nodes.size();
|
|
|
+ uint32_t clients_per_ing = CEILDIV(num_clients_total, num_ing_nodes);
|
|
|
+ uint16_t ing_with_additional = num_clients_total % num_ing_nodes;
|
|
|
+ uint16_t priv_out = config.m_priv_out;
|
|
|
+ uint16_t msg_size = config.msg_size;
|
|
|
|
|
|
- for(uint32_t i=0; i<config.user_count; i++) {
|
|
|
- generateClientEncryptionKey(i, ESK, client_key);
|
|
|
- clients[i].setKey(client_key);
|
|
|
+ uint32_t bundle_size = messageBundleSize(priv_out, msg_size);
|
|
|
+ unsigned char *payload = (unsigned char*) malloc (bundle_size);
|
|
|
|
|
|
- printf("Client %d key: ", i);
|
|
|
- for(int i=0;i<SGX_AESGCM_KEY_SIZE;i++) {
|
|
|
- printf("%x", client_key[i]);
|
|
|
- }
|
|
|
- printf("\n");
|
|
|
- }
|
|
|
|
|
|
+ uint64_t epoch = 1;
|
|
|
+ while(epoch<3) {
|
|
|
|
|
|
- /*
|
|
|
- // Attempt sending a data packet to one of the ingestion servers
|
|
|
- boost::asio::io_context io_context;
|
|
|
- boost::system::error_code err;
|
|
|
- boost::asio::ip::tcp::socket nodesock(io_context);
|
|
|
- boost::asio::ip::tcp::resolver resolver(io_context);
|
|
|
+ for(uint32_t i=0; i<num_clients_total; i++) {
|
|
|
+ if(epoch==1) {
|
|
|
+ uint16_t ing_node_this_client = i/clients_per_ing;
|
|
|
+ if(ing_node_this_client > ing_with_additional && ing_with_additional!=0) {
|
|
|
+ uint16_t leftover = num_clients_total - (ing_with_additional * clients_per_ing);
|
|
|
+ ing_node_this_client = ing_with_additional + (leftover / (clients_per_ing-1));
|
|
|
+ }
|
|
|
|
|
|
- while(1) {
|
|
|
-#ifdef VERBOSE_NET
|
|
|
- std::cerr << "Connecting to " << ingestion_nodes[0].name << "...\n";
|
|
|
-#endif
|
|
|
- std::cout << ingestion_nodes[0].clistenhost << ":" << ingestion_nodes[0].clistenport;
|
|
|
- boost::asio::connect(nodesock,
|
|
|
- resolver.resolve(ingestion_nodes[0].clistenhost,
|
|
|
- ingestion_nodes[0].clistenport), err);
|
|
|
- if (!err) break;
|
|
|
- std::cerr << "Connection to " << ingestion_nodes[0].name <<
|
|
|
- " refused, will retry.\n";
|
|
|
- sleep(1);
|
|
|
- }
|
|
|
+ int ret = generateClientEncryptionKey(i, EMK, client_key);
|
|
|
+ clients[i].initClient(i, client_key);
|
|
|
|
|
|
- nodenum_t node_num = 7;
|
|
|
- boost::asio::write(nodesock,
|
|
|
- boost::asio::buffer(&node_num, sizeof(node_num)));
|
|
|
- */
|
|
|
+ clients[i].initializeSocket(io_context, ingestion_nodes[ing_node_this_client]);
|
|
|
+ //clients[i].sendAuthMessage();
|
|
|
|
|
|
- /*
|
|
|
- int randfd = open("/dev/urandom", O_RDONLY);
|
|
|
- if (randfd < 0) {
|
|
|
- throw std::runtime_error("Cannot open /dev/urandom");
|
|
|
- }
|
|
|
|
|
|
- unsigned char zeroes[config.msg_size];
|
|
|
- unsigned char buffer[config.msg_size+4+12+16];
|
|
|
- memset(zeroes, 0, sizeof(zeroes));
|
|
|
- // An AES key for constructing and verifying the _plaintext_ of the blocks
|
|
|
- // so that we can ensure that the blocks come out unaltered
|
|
|
- unsigned char datakey[16];
|
|
|
- read(randfd, datakey, 16);
|
|
|
-
|
|
|
- // GCM-encrypt, using the chunk key as the associated data
|
|
|
- if (sizeof(zeroes) != gcm_encrypt(zeroes, sizeof(zeroes), buffer, 4, datakey,
|
|
|
- buffer+4, 12, buffer+4+12, buffer+4+12+sizeof(zeroes))) {
|
|
|
- printf("Inner encryption failed\n");
|
|
|
- }
|
|
|
- */
|
|
|
+ /*
|
|
|
+ // Test that the keys generated match those generated within
|
|
|
+ // enclave config
|
|
|
+ unsigned char *ckey;
|
|
|
+ ckey = clients[i].getKey();
|
|
|
+ printf("Client %d, id = %d, key: ", i, clients[i].getid());
|
|
|
+ for(int j=0;j<SGX_AESGCM_KEY_SIZE;j++) {
|
|
|
+ printf("%x", ckey[j]);
|
|
|
+ }
|
|
|
+ printf("\n\n");
|
|
|
+ */
|
|
|
+ }
|
|
|
|
|
|
- /*
|
|
|
- Spin config.user_client actual clients. Each client:
|
|
|
- 1) Retrieve messages and tokens from their storage server
|
|
|
- 2) Send all their messages to the ingestion server
|
|
|
- 3) Wait for a predetermined EPOCH_DURATION time
|
|
|
- 4) Repeat from 1)
|
|
|
- */
|
|
|
+ clients[i].sendMessageBundle(priv_out, msg_size, payload);
|
|
|
+ }
|
|
|
+ epoch++;
|
|
|
+ sleep(1);
|
|
|
+ }
|
|
|
|
|
|
+ free(payload);
|
|
|
delete [] clients;
|
|
|
}
|