MeshCore/src/Identity.cpp

146 lines
4.9 KiB
C++
Raw Normal View History

2025-01-13 14:07:48 +11:00
#include "Identity.h"
#include <string.h>
#define ED25519_NO_SEED 1
#include <ed_25519.h>
// For weaker ESP32 boards, we use libsodium for cryptographic operations to reduce stack usage
2025-03-04 18:55:51 -08:00
#ifdef USE_ESP32_ENCRYPTION
#include <sodium.h>
#endif
2025-01-13 14:07:48 +11:00
namespace mesh {
Identity::Identity() {
memset(pub_key, 0, sizeof(pub_key));
}
Identity::Identity(const char* pub_hex) {
Utils::fromHex(pub_key, PUB_KEY_SIZE, pub_hex);
}
bool Identity::verify(const uint8_t* sig, const uint8_t* message, int msg_len) const {
2025-03-04 18:55:51 -08:00
#ifdef USE_ESP32_ENCRYPTION
return crypto_sign_ed25519_verify_detached(sig, message, msg_len, pub_key) == 0;
#else
return ed25519_verify(sig, message, msg_len, pub_key);
#endif
2025-01-13 14:07:48 +11:00
}
bool Identity::readFrom(Stream& s) {
return (s.readBytes(pub_key, PUB_KEY_SIZE) == PUB_KEY_SIZE);
}
bool Identity::writeTo(Stream& s) const {
return (s.write(pub_key, PUB_KEY_SIZE) == PUB_KEY_SIZE);
}
void Identity::printTo(Stream& s) const {
Utils::printHex(s, pub_key, PUB_KEY_SIZE);
}
LocalIdentity::LocalIdentity() {
memset(prv_key, 0, sizeof(prv_key));
}
2025-03-04 18:55:51 -08:00
2025-01-13 14:07:48 +11:00
LocalIdentity::LocalIdentity(const char* prv_hex, const char* pub_hex) : Identity(pub_hex) {
Utils::fromHex(prv_key, PRV_KEY_SIZE, prv_hex);
}
LocalIdentity::LocalIdentity(RNG* rng) {
uint8_t seed[SEED_SIZE];
rng->random(seed, SEED_SIZE);
2025-03-04 18:55:51 -08:00
#ifdef USE_ESP32_ENCRYPTION
// Use libsodium for keypair generation on ESP32 to reduce stack usage
// NOTE: Format differences between implementations:
// - The current ed25519 implementation (orlp/ed25519) uses a 64-byte private key format
// - Libsodium also uses a 64-byte format for Ed25519 secret keys, where:
// * First 32 bytes: the actual private key seed
// * Last 32 bytes: the corresponding public key
// Generate keypair using libsodium with the provided seed
// This avoids the deep stack usage of the default implementation
crypto_sign_ed25519_seed_keypair(pub_key, prv_key, seed);
#else
ed25519_create_keypair(pub_key, prv_key, seed);
#endif
2025-01-13 14:07:48 +11:00
}
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);
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);
return success;
}
void LocalIdentity::printTo(Stream& s) const {
s.print("pub_key: "); Utils::printHex(s, pub_key, PUB_KEY_SIZE); s.println();
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) {
if (max_len < PRV_KEY_SIZE) return 0; // not big enough
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;
}
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);
} else if (len == PRV_KEY_SIZE) {
memcpy(prv_key, src, PRV_KEY_SIZE);
2025-03-04 18:55:51 -08:00
#ifdef USE_ESP32_ENCRYPTION
// In libsodium, the private key already contains the public key in its last 32 bytes
// We can just extract it directly, avoiding the expensive derivation calculation
memcpy(pub_key, prv_key + 32, 32);
#else
// now need to re-calculate the pub_key
ed25519_derive_pub(pub_key, prv_key);
#endif
}
}
2025-01-13 14:07:48 +11:00
void LocalIdentity::sign(uint8_t* sig, const uint8_t* message, int msg_len) const {
2025-03-04 18:55:51 -08:00
#ifdef USE_ESP32_ENCRYPTION
crypto_sign_ed25519_detached(sig, NULL, message, msg_len, prv_key);
#else
ed25519_sign(sig, message, msg_len, pub_key, prv_key);
#endif
2025-01-13 14:07:48 +11:00
}
2025-01-15 00:39:32 +11:00
void LocalIdentity::calcSharedSecret(uint8_t* secret, const uint8_t* other_pub_key) {
2025-03-04 18:55:51 -08:00
#ifdef USE_ESP32_ENCRYPTION
// NOTE: To calculate a shared secret with Ed25519 keys and libsodium, we need to:
// Convert the Ed25519 keys to Curve25519 (X25519) format
// Perform the key exchange using the converted keys
2025-03-04 18:55:51 -08:00
//
// The default implementation handles this conversion internally,
// but with libsodium we need to do these steps explicitly.
2025-03-04 18:55:51 -08:00
unsigned char x25519_pk[crypto_scalarmult_curve25519_BYTES];
unsigned char x25519_sk[crypto_scalarmult_curve25519_BYTES];
// Convert Ed25519 keys to Curve25519 keys for ECDH
crypto_sign_ed25519_pk_to_curve25519(x25519_pk, other_pub_key);
crypto_sign_ed25519_sk_to_curve25519(x25519_sk, prv_key);
// Calculate shared secret using X25519
crypto_scalarmult_curve25519(secret, x25519_sk, x25519_pk);
#else
ed25519_key_exchange(secret, other_pub_key, prv_key);
#endif
2025-01-13 14:07:48 +11:00
}
}