#include "signing_key.h" #include #include "json.hpp" #include "sodium_helpers.h" namespace BareMinimumCrypto { using nlohmann::json; vector SigningKeyFile::to_msgpack () const { const auto j = json { {"salt", json::binary (salt)}, {"time_created", time_created.x}, {"pubkey", json::binary (pubkey)}, }; return json::to_msgpack (j); } // The whole process for a passphrased key is like this: // Passphrase + random salt --> // Seed --> // Secret key + Public key // Passphrases should be mandatory for keys that can sign other keys. optional SigningKey::generate_to_file (const string & file_path, const string & passphrase) { if (passphrase.size () < 8) { return nullopt; } vector seed; seed.resize (crypto_sign_SEEDBYTES); vector salt; salt.resize (crypto_pwhash_SALTBYTES); randombytes_buf (salt.data (), salt.size ()); if (crypto_pwhash ( seed.data (), seed.size (), passphrase.data (), passphrase.size (), salt.data (), crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE, crypto_pwhash_ALG_DEFAULT ) != 0) { return nullopt; } SigningKey key; key.pk.resize (crypto_sign_PUBLICKEYBYTES); key.sk.resize (crypto_sign_SECRETKEYBYTES); if (crypto_sign_seed_keypair (key.pk.data (), key.sk.data (), seed.data ()) != 0) { return nullopt; } SigningKeyFile key_on_disk { salt, Instant::now (), key.pk }; const auto msg = key_on_disk.to_msgpack (); ofstream f; f.open (file_path, ofstream::binary); if (! f.is_open ()) { return nullopt; } f.write ((const char *)msg.data (), msg.size ()); f.close (); return key; } SigningKey::SigningKey () { try_sodium_init (); pk.resize (crypto_sign_PUBLICKEYBYTES); sk.resize (crypto_sign_SECRETKEYBYTES); crypto_sign_keypair (pk.data (), sk.data ()); } vector SigningKey::pubkey () const { return pk; } vector SigningKey::pub_to_msgpack () const { const json j = { {"key", json::binary (pk)}, }; return json::to_msgpack (j); } optional SigningKey::sign ( const vector & payload, TimeRange tr ) const { try_sodium_init (); if (tr.duration () > about_1_year) { return nullopt; } const json j { {"not_before", tr.not_before}, {"not_after", tr.not_after}, {"payload", json::binary (payload)}, }; const auto cert = json::to_msgpack (j); vector sig; sig.resize (crypto_sign_BYTES); crypto_sign_detached (sig.data (), nullptr, cert.data (), cert.size (), sk.data ()); return ExpiringSignature { cert, sig, }; } optional SigningKey::sign_key (const SigningKey & k, Instant now) const { return sign (k.pub_to_msgpack (), TimeRange::from_start_and_dur (now, about_3_months)); } optional SigningKey::sign_data (const vector & v, Instant now) const { return sign (v, TimeRange::from_start_and_dur (now, about_1_week)); } }