From d1d59ddf63756a1273275a72f77fb0c34b578a87 Mon Sep 17 00:00:00 2001 From: Ravin Perera <33562092+ravinsp@users.noreply.github.com> Date: Sat, 5 Oct 2019 09:08:57 +0530 Subject: [PATCH] Refactored conf and crypto namespaces. --- src/conf.cpp | 280 ++++++++++++++++++++++++++++--------------------- src/conf.h | 8 +- src/crypto.cpp | 108 ++++--------------- src/crypto.h | 20 ++-- src/main.cpp | 26 ++--- src/shared.cpp | 52 +++++++-- src/shared.h | 4 +- 7 files changed, 258 insertions(+), 240 deletions(-) diff --git a/src/conf.cpp b/src/conf.cpp index 26b5a968..392e76f9 100644 --- a/src/conf.cpp +++ b/src/conf.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -8,6 +9,8 @@ #include #include #include "conf.h" +#include "crypto.h" +#include "shared.h" using namespace std; using namespace rapidjson; @@ -18,74 +21,34 @@ namespace conf ContractCtx ctx; ContractConfig cfg; -const char *cfg_schema = - "{" - "\"type\": \"object\"," - "\"required\": [ \"version\", \"pubkeyb64\", \"seckeyb64\", \"binary\", \"binargs\", \"listenip\"" - ", \"peers\", \"unl\", \"peerport\", \"roundtime\", \"pubport\", \"pubmaxsize\", \"pubmaxcpm\" ]," - "\"properties\": {" - "\"version\": { \"type\": \"string\" }," - "\"pubkeyb64\": { \"type\": \"string\" }," - "\"seckeyb64\": { \"type\": \"string\" }," - "\"binary\": { \"type\": \"string\" }," - "\"binargs\": { \"type\": \"string\" }," - "\"listenip\": { \"type\": \"string\" }," - "\"peers\": {" - "\"type\": \"array\"," - "\"items\": { \"type\": \"string\" }" - "}," - "\"unl\": {" - "\"type\": \"array\"," - "\"items\": { \"type\": \"string\" }" - "}," - "\"peerport\": { \"type\": \"integer\" }," - "\"roundtime\": { \"type\": \"integer\" }," - "\"pubport\": { \"type\": \"integer\" }," - "\"pubmaxsize\": { \"type\": \"integer\" }," - "\"pubmaxcpm\": { \"type\": \"integer\" }" - "}" - "}"; +bool validate_config(); +int load_config(); +void save_config(); +void binpair_to_b64(); +int b64pair_to_bin(); +bool validate_contract_dir_paths(); +bool is_schema_valid(Document &d); -// v1 < v2 -> -1 -// v1 == v2 -> 0 -// v1 > v2 -> +1 -int version_compare(std::string v1, std::string v2) +int init() { - size_t i = 0, j = 0; - while (i < v1.length() || j < v2.length()) - { - int acc1 = 0, acc2 = 0; - - while (i < v1.length() && v1[i] != '.') - { - acc1 = acc1 * 10 + (v1[i] - '0'); - i++; - } - while (j < v2.length() && v2[j] != '.') - { - acc2 = acc2 * 10 + (v2[j] - '0'); - j++; - } - - if (acc1 < acc2) - return -1; - if (acc1 > acc2) - return +1; - - ++i; - ++j; - } + if (!validate_contract_dir_paths() || load_config() != 0 || validate_config() != 0) + return -1; return 0; } -bool is_schema_valid(Document &d) +int rekey() { - Document sd; - sd.Parse(cfg_schema); - SchemaDocument schema(sd); + if (load_config() != 0) + return -1; - SchemaValidator validator(schema); - return d.Accept(validator); + crypto::generate_signing_keys(cfg.pubkey, cfg.seckey); + binpair_to_b64(); + + save_config(); + + cout << "New signing keys generated at " << ctx.configFile << endl; + + return 0; } int load_config() @@ -106,18 +69,19 @@ int load_config() } //Check contract version. - string cfgVersion = d["version"].GetString(); - if (cfgVersion.empty()) + string cfgversion = d["version"].GetString(); + if (cfgversion.empty()) { cerr << "Contract config version missing.\n"; return -1; } - if (version_compare(cfgVersion, _HP_MIN_CONTRACT_VERSION_) == -1) + string minversion = string(_HP_MIN_CONTRACT_VERSION_); + if (shared::version_compare(cfgversion, minversion) == -1) { cerr << "Contract version too old. Minimum " << _HP_MIN_CONTRACT_VERSION_ << " required. " - << cfgVersion << " found.\n"; + << cfgversion << " found.\n"; return -1; } @@ -141,6 +105,8 @@ int load_config() cfg.pubmaxsize = d["pubmaxsize"].GetInt(); cfg.pubmaxcpm = d["pubmaxcpm"].GetInt(); + b64pair_to_bin(); + return 0; } @@ -187,6 +153,100 @@ void save_config() d.Accept(writer); } +int create_contract() +{ + if (boost::filesystem::exists(ctx.contractDir)) + { + cerr << "Contract dir already exists. Cannot create contract at the same location.\n"; + return -1; + } + + boost::filesystem::create_directories(ctx.configDir); + boost::filesystem::create_directories(ctx.histDir); + boost::filesystem::create_directories(ctx.stateDir); + + //Create config file with default settings. + + crypto::generate_signing_keys(cfg.pubkey, cfg.seckey); + binpair_to_b64(); + + cfg.listenip = "0.0.0.0"; + cfg.peerport = 22860; + cfg.roundtime = 1000; + cfg.pubport = 8080; + cfg.pubmaxsize = 65536; + cfg.pubmaxcpm = 100; + save_config(); + + cout << "Contract directory created at " << ctx.contractDir << endl; + + if (load_config() != 0) + return -1; + + return 0; +} + +void binpair_to_b64() +{ + shared::base64_encode((unsigned char *)cfg.pubkey.data(), crypto_sign_PUBLICKEYBYTES, cfg.pubkeyb64); + shared::base64_encode((unsigned char *)cfg.seckey.data(), crypto_sign_SECRETKEYBYTES, cfg.seckeyb64); +} + +int b64pair_to_bin() +{ + unsigned char decoded_pubkey[crypto_sign_PUBLICKEYBYTES]; + unsigned char decoded_seckey[crypto_sign_SECRETKEYBYTES]; + + if (shared::base64_decode(cfg.pubkeyb64, decoded_pubkey, crypto_sign_PUBLICKEYBYTES) != 0) + { + cerr << "Error decoding base64 public key.\n"; + return -1; + } + + if (shared::base64_decode(cfg.seckeyb64, decoded_seckey, crypto_sign_SECRETKEYBYTES) != 0) + { + cerr << "Error decoding base64 secret key.\n"; + return -1; + } + + shared::replace_string_contents(cfg.pubkey, (char *)decoded_pubkey, crypto_sign_PUBLICKEYBYTES); + shared::replace_string_contents(cfg.seckey, (char *)decoded_seckey, crypto_sign_SECRETKEYBYTES); + return 0; +} + +bool validate_config() +{ + if (cfg.pubkeyb64.empty() || cfg.seckeyb64.empty()) + { + cerr << "Signing keys missing. Run with 'rekey' to generate new keys.\n"; + return false; + } + + if (cfg.binary.empty() || cfg.listenip.empty() || + cfg.peerport == 0 || cfg.roundtime == 0 || cfg.pubport == 0 || cfg.pubmaxsize == 0 || cfg.pubmaxcpm == 0) + { + cerr << "Required configuration fields missing at " << ctx.configFile << endl; + return false; + } + + if (!boost::filesystem::exists(cfg.binary)) + { + cerr << "Contract binary does not exist: " << cfg.binary << endl; + return false; + } + + //Sign and verify a sample to ensure we have a matching signing key pair. + string msg = "hotpocket"; + string sigb64 = crypto::sign_b64(msg, cfg.seckeyb64); + if (!crypto::verify_b64(msg, sigb64, cfg.pubkeyb64)) + { + cerr << "Invalid signing keys. Run with 'rekey' to generate new keys.\n"; + return false; + } + + return true; +} + void set_contract_dir_paths(string basedir) { if (basedir[basedir.size() - 1] == '/') @@ -215,66 +275,42 @@ bool validate_contract_dir_paths() return true; } -int create_contract() +bool is_schema_valid(Document &d) { - if (boost::filesystem::exists(ctx.contractDir)) - { - cerr << "Contract dir already exists. Cannot create contract at the same location.\n"; - return -1; - } + const char *cfg_schema = + "{" + "\"type\": \"object\"," + "\"required\": [ \"version\", \"pubkeyb64\", \"seckeyb64\", \"binary\", \"binargs\", \"listenip\"" + ", \"peers\", \"unl\", \"peerport\", \"roundtime\", \"pubport\", \"pubmaxsize\", \"pubmaxcpm\" ]," + "\"properties\": {" + "\"version\": { \"type\": \"string\" }," + "\"pubkeyb64\": { \"type\": \"string\" }," + "\"seckeyb64\": { \"type\": \"string\" }," + "\"binary\": { \"type\": \"string\" }," + "\"binargs\": { \"type\": \"string\" }," + "\"listenip\": { \"type\": \"string\" }," + "\"peers\": {" + "\"type\": \"array\"," + "\"items\": { \"type\": \"string\" }" + "}," + "\"unl\": {" + "\"type\": \"array\"," + "\"items\": { \"type\": \"string\" }" + "}," + "\"peerport\": { \"type\": \"integer\" }," + "\"roundtime\": { \"type\": \"integer\" }," + "\"pubport\": { \"type\": \"integer\" }," + "\"pubmaxsize\": { \"type\": \"integer\" }," + "\"pubmaxcpm\": { \"type\": \"integer\" }" + "}" + "}"; - boost::filesystem::create_directories(ctx.configDir); - boost::filesystem::create_directories(ctx.histDir); - boost::filesystem::create_directories(ctx.stateDir); + Document sd; + sd.Parse(cfg_schema); + SchemaDocument schema(sd); - //Create config file with default settings. - cfg.listenip = "0.0.0.0"; - cfg.peerport = 22860; - cfg.roundtime = 1000; - cfg.pubport = 8080; - cfg.pubmaxsize = 65536; - cfg.pubmaxcpm = 100; - save_config(); - - cout << "Contract directory created at " << ctx.contractDir << endl; - - if (load_config() != 0) - return -1; - - return 0; -} - -int clear_keys() -{ - cfg.pubkeyb64 = ""; - cfg.seckeyb64 = ""; - save_config(); - return 0; -} - -bool validate_config() -{ - if (cfg.pubkeyb64.empty() || cfg.seckeyb64.empty() || cfg.binary.empty() || cfg.listenip.empty() || - cfg.peerport == 0 || cfg.roundtime == 0 || cfg.pubport == 0 || cfg.pubmaxsize == 0 || cfg.pubmaxcpm == 0) - { - cerr << "Required configuration fields missing.\n"; - return false; - } - - if (!boost::filesystem::exists(cfg.binary)) - { - cerr << "Contract binary does not exist: " << cfg.binary << endl; - return false; - } - - return true; -} - -int init() -{ - if (!validate_contract_dir_paths() || load_config() != 0 || !validate_config()) - return -1; - return 0; + SchemaValidator validator(schema); + return d.Accept(validator); } } // namespace conf \ No newline at end of file diff --git a/src/conf.h b/src/conf.h index 262d9bf4..b137a8ed 100644 --- a/src/conf.h +++ b/src/conf.h @@ -34,9 +34,9 @@ struct ContractConfig Config elements which are only initialized in memory (these are not loaded from the config file) */ //public key bytes - unsigned char *pubkey; + string pubkey; //secret key bytes - unsigned char *seckey; + string seckey; /* Config elements which are loaded from the config file. @@ -58,10 +58,10 @@ struct ContractConfig extern ContractCtx ctx; extern ContractConfig cfg; int init(); +int rekey(); int create_contract(); -int load_config(); -int clear_keys(); void set_contract_dir_paths(string basedir); +int load_config(); void save_config(); } // namespace conf diff --git a/src/crypto.cpp b/src/crypto.cpp index bba8749f..973b3746 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -1,37 +1,42 @@ #include #include #include -#include "conf.h" #include "crypto.h" #include "shared.h" using namespace std; -using namespace rapidjson; namespace crypto { -void generate_crypto_keys(); +void generate_signing_keys(); void binpair_to_b64(); int b64pair_to_bin(); -void sign(const unsigned char *msg, unsigned long long msg_len, unsigned char *sig) +string sign(string &msg, string &seckey) { - crypto_sign_detached(sig, NULL, msg, msg_len, conf::cfg.seckey); + unsigned char sigchars[crypto_sign_BYTES]; + crypto_sign_detached(sigchars, NULL, (unsigned char *)msg.data(), msg.length(), (unsigned char *)seckey.data()); + string sig((char *)sigchars, crypto_sign_BYTES); + return sig; } -string sign_b64(string &msg) +string sign_b64(string &msg, string &seckeyb64) { + unsigned char seckey[crypto_sign_SECRETKEYBYTES]; + shared::base64_decode(seckeyb64, seckey, crypto_sign_SECRETKEYBYTES); + unsigned char sig[crypto_sign_BYTES]; - crypto_sign_detached(sig, NULL, (unsigned char *)msg.data(), msg.size() + 1, conf::cfg.seckey); + crypto_sign_detached(sig, NULL, (unsigned char *)msg.data(), msg.length(), seckey); string sigb64; shared::base64_encode(sig, crypto_sign_BYTES, sigb64); return sigb64; } -bool verify(const unsigned char *msg, unsigned long long msg_len, const unsigned char *sig, const unsigned char *pubkey) +bool verify(string &msg, string &sig, string &pubkey) { - int result = crypto_sign_verify_detached(sig, msg, msg_len, pubkey); + int result = crypto_sign_verify_detached( + (unsigned char *)sig.data(), (unsigned char *)msg.data(), msg.length(), (unsigned char *)pubkey.data()); return result == 0; } @@ -43,7 +48,7 @@ bool verify_b64(string &msg, string &sigb64, string &pubkeyb64) unsigned char decoded_sig[crypto_sign_BYTES]; shared::base64_decode(sigb64, decoded_sig, crypto_sign_BYTES); - int result = crypto_sign_verify_detached(decoded_sig, (unsigned char *)msg.data(), msg.size() + 1, decoded_pubkey); + int result = crypto_sign_verify_detached(decoded_sig, (unsigned char *)msg.data(), msg.length(), decoded_pubkey); return result == 0; } @@ -52,89 +57,20 @@ int init() if (sodium_init() < 0) { cerr << "sodium_init failed.\n"; - return 0; - } - - if (conf::ctx.command == "new" || conf::ctx.command == "rekey") - { - cout << "Generating new keys.\n"; - generate_crypto_keys(); - binpair_to_b64(); - - conf::save_config(); - } - else if (conf::ctx.command == "run") - { - if (conf::cfg.pubkeyb64.empty() || conf::cfg.seckeyb64.empty()) - { - cerr << "Signing keys missing. Run with 'rekey' to generate new keys.\n"; - return -1; - } - else - { - //Decode b64 keys into bytes and store in memory. - if (b64pair_to_bin() != 0) - return -1; - - //Sign and verify a sample to ensure we have a matching key pair. - string msg = "hotpocket"; - string sigb64 = sign_b64(msg); - if (!verify_b64(msg, sigb64, conf::cfg.pubkeyb64)) - { - cerr << "Invalid signing keys. Run with 'rekey' to generate new keys.\n"; - return -1; - } - } + return -1; } return 0; } -void generate_crypto_keys() +void generate_signing_keys(string &pubkey, string &seckey) { - if (conf::cfg.pubkey != NULL) - free(conf::cfg.pubkey); + unsigned char pubkeychars[crypto_sign_PUBLICKEYBYTES]; + unsigned char seckeychars[crypto_sign_SECRETKEYBYTES]; + crypto_sign_keypair(pubkeychars, seckeychars); - if (conf::cfg.seckey != NULL) - free(conf::cfg.seckey); - - conf::cfg.pubkey = (unsigned char *)malloc(crypto_sign_PUBLICKEYBYTES); - conf::cfg.seckey = (unsigned char *)malloc(crypto_sign_SECRETKEYBYTES); - crypto_sign_keypair(conf::cfg.pubkey, conf::cfg.seckey); -} - -void binpair_to_b64() -{ - shared::base64_encode(conf::cfg.pubkey, crypto_sign_PUBLICKEYBYTES, conf::cfg.pubkeyb64); - shared::base64_encode(conf::cfg.seckey, crypto_sign_SECRETKEYBYTES, conf::cfg.seckeyb64); -} - -int b64pair_to_bin() -{ - unsigned char *decoded_pubkey = (unsigned char *)malloc(crypto_sign_PUBLICKEYBYTES); - unsigned char *decoded_seckey = (unsigned char *)malloc(crypto_sign_SECRETKEYBYTES); - - if (shared::base64_decode(conf::cfg.pubkeyb64, decoded_pubkey, crypto_sign_PUBLICKEYBYTES) != 0) - { - cerr << "Error decoding public key.\n"; - return -1; - } - - if (shared::base64_decode(conf::cfg.seckeyb64, decoded_seckey, crypto_sign_SECRETKEYBYTES) != 0) - { - cerr << "Error decoding secret key.\n"; - return -1; - } - - if (conf::cfg.pubkey != NULL) - free(conf::cfg.pubkey); - - if (conf::cfg.seckey != NULL) - free(conf::cfg.seckey); - - conf::cfg.pubkey = decoded_pubkey; - conf::cfg.seckey = decoded_seckey; - return 0; + shared::replace_string_contents(pubkey, (char *)pubkeychars, crypto_sign_PUBLICKEYBYTES); + shared::replace_string_contents(seckey, (char *)seckeychars, crypto_sign_SECRETKEYBYTES); } } // namespace crypto \ No newline at end of file diff --git a/src/crypto.h b/src/crypto.h index d8fd8933..dd6e0e14 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -8,23 +8,25 @@ namespace crypto int init(); -/** - * Generates the signature for the given message using the contract's secret key. - */ -void sign(const unsigned char *msg, unsigned long long msg_len, unsigned char *sig); +void generate_signing_keys(string &pubkey, string &seckey); /** - * Returns the base64 signature for the given message using the contract's secret key. + * Returns the signature bytes for the given message bytes using the provided secret key bytes. */ -string sign_b64(string &msg); +string sign(string &msg, string &seckey); /** - * Verifies the given signature with the message using the provided public key. + * Returns the base64 signature for the given message bytes using the provided base64 secret key. */ -bool verify(const unsigned char *msg, unsigned long long msg_len, const unsigned char *sig, const unsigned char *pubkey); +string sign_b64(string &msg, string &seckeyb64); /** - * Verifies the given base64 signature with the message using the provided base64 public key. + * Verifies the given signature bytes for the message bytes using the provided public key bytes. + */ +bool verify(string &msg, string &sig, string &pubkey); + +/** + * Verifies the given base64 signature with the message bytes using the provided base64 public key. */ bool verify_b64(string &msg, string &sigb64, string &pubkeyb64); diff --git a/src/main.cpp b/src/main.cpp index cf6c989d..5a9a4f06 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,26 +22,28 @@ int main(int argc, char **argv) { cout << _HP_VERSION_ << endl; } - else if (conf::ctx.command == "new") - { - if (conf::create_contract() != 0 || crypto::init() != 0) - return -1; - } else { - if (conf::init() != 0) + if (crypto::init() != 0) return -1; - if (conf::ctx.command == "rekey") + if (conf::ctx.command == "new") { - //Clear the keys. crpyto::init will init the keys. - if (conf::clear_keys() != 0 || crypto::init() != 0) + if (conf::create_contract() != 0) return -1; } - else if (conf::ctx.command == "run") + else { - if (crypto::init() != 0 || usr::init() != 0) - return -1; + if (conf::ctx.command == "rekey") + { + if (conf::rekey() != 0) + return -1; + } + else if (conf::ctx.command == "run") + { + if (conf::init() != 0 || usr::init() != 0) + return -1; + } } } diff --git a/src/shared.cpp b/src/shared.cpp index c961037e..f5beba17 100644 --- a/src/shared.cpp +++ b/src/shared.cpp @@ -6,25 +6,26 @@ using namespace std; namespace shared { +void replace_string_contents(string &str, const char *bytes, size_t bytes_len); + int base64_encode(unsigned char *bin, size_t bin_len, string &encoded_string) { - const size_t base64_max_len = sodium_base64_encoded_len(bin_len, sodium_base64_VARIANT_ORIGINAL); - char base64_str[base64_max_len]; + const size_t base64_len = sodium_base64_encoded_len(bin_len, sodium_base64_VARIANT_ORIGINAL); + char base64chars[base64_len]; char *encoded_str_char = sodium_bin2base64( - base64_str, base64_max_len, + base64chars, base64_len, bin, bin_len, sodium_base64_VARIANT_ORIGINAL); if (encoded_str_char == NULL) return -1; - encoded_string.clear(); - encoded_string.append(base64_str, base64_max_len); + replace_string_contents(encoded_string, base64chars, base64_len); return 0; } -int base64_decode(string base64_str, unsigned char *decoded, size_t decoded_len) +int base64_decode(string &base64_str, unsigned char *decoded, size_t decoded_len) { const char *b64_end; size_t bin_len; @@ -40,4 +41,43 @@ int base64_decode(string base64_str, unsigned char *decoded, size_t decoded_len) return 0; } +void replace_string_contents(string &str, const char *bytes, size_t bytes_len) +{ + if (str.length() > 0) + str.clear(); + str.append(bytes, bytes_len); +} + +// v1 < v2 -> -1 +// v1 == v2 -> 0 +// v1 > v2 -> +1 +int version_compare(string &v1, string &v2) +{ + size_t i = 0, j = 0; + while (i < v1.length() || j < v2.length()) + { + int acc1 = 0, acc2 = 0; + + while (i < v1.length() && v1[i] != '.') + { + acc1 = acc1 * 10 + (v1[i] - '0'); + i++; + } + while (j < v2.length() && v2[j] != '.') + { + acc2 = acc2 * 10 + (v2[j] - '0'); + j++; + } + + if (acc1 < acc2) + return -1; + if (acc1 > acc2) + return +1; + + ++i; + ++j; + } + return 0; +} + } // namespace shared \ No newline at end of file diff --git a/src/shared.h b/src/shared.h index 4655bdef..35156053 100644 --- a/src/shared.h +++ b/src/shared.h @@ -27,7 +27,9 @@ struct ContractUser }; int base64_encode(unsigned char *bin, size_t bin_len, string &encoded_string); -int base64_decode(string base64_str, unsigned char *decoded, size_t decoded_len); +int base64_decode(string &base64_str, unsigned char *decoded, size_t decoded_len); +void replace_string_contents(string &str, const char* bytes, size_t bytes_len); +int version_compare(string &v1, string &v2); } // namespace usr