diff --git a/src/Identity.cpp b/src/Identity.cpp index 83298928..56cf7bfd 100644 --- a/src/Identity.cpp +++ b/src/Identity.cpp @@ -43,7 +43,6 @@ LocalIdentity::LocalIdentity(const char* prv_hex, const char* pub_hex) : Identit } LocalIdentity::LocalIdentity(RNG* rng) { - uint8_t seed[SEED_SIZE]; rng->random(seed, SEED_SIZE); ed25519_create_keypair(pub_key, prv_key, seed); } @@ -51,12 +50,17 @@ LocalIdentity::LocalIdentity(RNG* rng) { bool LocalIdentity::readFrom(Stream& s) { bool success = (s.readBytes(pub_key, PUB_KEY_SIZE) == PUB_KEY_SIZE); success = success && (s.readBytes(prv_key, PRV_KEY_SIZE) == PRV_KEY_SIZE); + memset(seed, 0, SEED_SIZE); + if (success) { + s.readBytes(seed, SEED_SIZE); + } return success; } bool LocalIdentity::writeTo(Stream& s) const { bool success = (s.write(pub_key, PUB_KEY_SIZE) == PUB_KEY_SIZE); success = success && (s.write(prv_key, PRV_KEY_SIZE) == PRV_KEY_SIZE); + success = success && (s.write(seed, SEED_SIZE) == SEED_SIZE); return success; } @@ -65,26 +69,38 @@ void LocalIdentity::printTo(Stream& s) const { s.print("prv_key: "); Utils::printHex(s, prv_key, PRV_KEY_SIZE); s.println(); } -size_t LocalIdentity::writeTo(uint8_t* dest, size_t max_len) { +size_t LocalIdentity::writePubkeyTo(uint8_t* dest, size_t max_len) { + if (max_len < PUB_KEY_SIZE) return 0; // not big enough + memcpy(dest, pub_key, PUB_KEY_SIZE); + return PUB_KEY_SIZE; +} + +size_t LocalIdentity::writePrvkeyTo(uint8_t* dest, size_t max_len) { if (max_len < PRV_KEY_SIZE) return 0; // not big enough + memcpy(dest, prv_key, PRV_KEY_SIZE); + return PRV_KEY_SIZE; +} - if (max_len < PRV_KEY_SIZE + PUB_KEY_SIZE) { // only room for prv_key - memcpy(dest, prv_key, PRV_KEY_SIZE); - return PRV_KEY_SIZE; - } - memcpy(dest, prv_key, PRV_KEY_SIZE); // otherwise can fit prv + pub keys - memcpy(&dest[PRV_KEY_SIZE], pub_key, PUB_KEY_SIZE); - return PRV_KEY_SIZE + PUB_KEY_SIZE; +size_t LocalIdentity::writeSeedTo(uint8_t* dest, size_t max_len) { + if (max_len < SEED_SIZE) return 0; // not big enough + memcpy(dest, seed, SEED_SIZE); + return SEED_SIZE; } void LocalIdentity::readFrom(const uint8_t* src, size_t len) { if (len == PRV_KEY_SIZE + PUB_KEY_SIZE) { // has prv + pub keys memcpy(prv_key, src, PRV_KEY_SIZE); memcpy(pub_key, &src[PRV_KEY_SIZE], PUB_KEY_SIZE); + memset(seed, 0, SEED_SIZE); } else if (len == PRV_KEY_SIZE) { memcpy(prv_key, src, PRV_KEY_SIZE); // now need to re-calculate the pub_key ed25519_derive_pub(pub_key, prv_key); + memset(seed, 0, SEED_SIZE); + } else if (len == SEED_SIZE) { + memcpy(seed, src, SEED_SIZE); + // re-generate the keypair from the given seed + ed25519_create_keypair(pub_key, prv_key, seed); } } @@ -96,4 +112,4 @@ void LocalIdentity::calcSharedSecret(uint8_t* secret, const uint8_t* other_pub_k ed25519_key_exchange(secret, other_pub_key, prv_key); } -} \ No newline at end of file +} diff --git a/src/Identity.h b/src/Identity.h index 42fb9d9a..885055fb 100644 --- a/src/Identity.h +++ b/src/Identity.h @@ -46,6 +46,7 @@ class Identity { */ class LocalIdentity : public Identity { uint8_t prv_key[PRV_KEY_SIZE]; + uint8_t seed[SEED_SIZE]; public: LocalIdentity(); LocalIdentity(const char* prv_hex, const char* pub_hex); @@ -76,7 +77,19 @@ class LocalIdentity : public Identity { bool readFrom(Stream& s); bool writeTo(Stream& s) const; void printTo(Stream& s) const; - size_t writeTo(uint8_t* dest, size_t max_len); + size_t writePubkeyTo(uint8_t* dest, size_t max_len); + size_t writePrvkeyTo(uint8_t* dest, size_t max_len); + size_t writeSeedTo(uint8_t* dest, size_t max_len); + /** + * \brief Set the Ed25519 keypair. + * \param src IN - the source for the key(s) or seed + * \param len IN - length of the input; if equal to SEED_SIZE, src is + * assumed to be a new seed, from which new private and public keys + * will be generated. If equal to PRV_KEY_SIZE, the corresponding + * public key will be re-generated. If equal to PRV_KEY_SIZE+ + * PUB_KEY_SIZE, no key regen is needed. The seed can only later + * be obtained via the `get prv.seed` CLI if SEED_SIZE is used. + */ void readFrom(const uint8_t* src, size_t len); }; diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index 88327aa8..aa007716 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -268,9 +268,14 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch sprintf(reply, "> %s", _prefs->guest_password); } else if (sender_timestamp == 0 && memcmp(config, "prv.key", 7) == 0) { // from serial command line only uint8_t prv_key[PRV_KEY_SIZE]; - int len = _callbacks->getSelfId().writeTo(prv_key, PRV_KEY_SIZE); + int len = _callbacks->getSelfId().writePrvkeyTo(prv_key, PRV_KEY_SIZE); mesh::Utils::toHex(tmp, prv_key, len); sprintf(reply, "> %s", tmp); + } else if (sender_timestamp == 0 && memcmp(config, "prv.seed", 8) == 0) { // from serial command line only + uint8_t seed[SEED_SIZE]; + int len = _callbacks->getSelfId().writeSeedTo(seed, SEED_SIZE); + mesh::Utils::toHex(tmp, seed, len); + sprintf(reply, "> %s", tmp); } else if (memcmp(config, "name", 4) == 0) { sprintf(reply, "> %s", _prefs->node_name); } else if (memcmp(config, "repeat", 6) == 0) { @@ -393,6 +398,17 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch } else { strcpy(reply, "Error, invalid key"); } + } else if (sender_timestamp == 0 && memcmp(config, "prv.seed ", 9) == 0) { // from serial command line only + uint8_t seed[SEED_SIZE]; + bool success = mesh::Utils::fromHex(seed, SEED_SIZE, &config[9]); + if (success) { + mesh::LocalIdentity new_id; + new_id.readFrom(seed, SEED_SIZE); + _callbacks->saveIdentity(new_id); + strcpy(reply, "OK"); + } else { + strcpy(reply, "Error, invalid seed"); + } } else if (memcmp(config, "name ", 5) == 0) { StrHelper::strncpy(_prefs->node_name, &config[5], sizeof(_prefs->node_name)); savePrefs();