Merge branch 'PowerSaving-v17' of https://github.com/IoTThinks/MeshCore into keymindCascade
# Conflicts: # examples/companion_radio/MyMesh.cpp # examples/companion_radio/NodePrefs.h # examples/simple_repeater/MyMesh.cpp # examples/simple_room_server/MyMesh.cpp # examples/simple_sensor/SensorMesh.cpp # platformio.ini # src/MeshCore.h # src/helpers/CommonCLI.cpp # src/helpers/CommonCLI.h # src/helpers/radiolib/CustomSX1262Wrapper.h # src/helpers/radiolib/CustomSX1268Wrapper.h # src/helpers/radiolib/LR11x0Reset.h # src/helpers/radiolib/SX126xReset.h
This commit is contained in:
commit
ea3843e0b4
33 files changed
+679
-204
No files matched your search
+21
-11
@@ -5,8 +5,9 @@
|
||||
#include <Ed25519.h>
|
||||
|
||||
#ifdef USE_CC310_HW_CRYPTO
|
||||
#include <Adafruit_nRFCrypto.h>
|
||||
#include "helpers/NRF52Crypto.h"
|
||||
#include "nrf_cc310/include/crys_ec_edw_api.h"
|
||||
#include "nrf_cc310/include/crys_ec_mont_edw_error.h"
|
||||
#endif
|
||||
|
||||
namespace mesh {
|
||||
@@ -21,20 +22,29 @@ Identity::Identity(const char* pub_hex) {
|
||||
}
|
||||
|
||||
bool Identity::verify(const uint8_t* sig, const uint8_t* message, int msg_len) const {
|
||||
if (sig == NULL || message == NULL || msg_len < 0) return false;
|
||||
|
||||
#ifdef USE_CC310_HW_CRYPTO
|
||||
// nRF52840 CryptoCell CC310 hardware Ed25519 verification. The software
|
||||
// implementations need ~3KB of stack (which can overflow the Adafruit core's
|
||||
// 4KB loop task stack from the advert receive path); the hardware path
|
||||
// needs much less, around 600-700bytes. The CC310 workspace is static, faster,
|
||||
// should save power at scale as well.
|
||||
static CRYS_ECEDW_TempBuff_t cc310_tmp;
|
||||
nRFCrypto.begin();
|
||||
CRYSError_t rc = CRYS_ECEDW_Verify((uint8_t*)sig, CRYS_ECEDW_SIGNATURE_BYTES,
|
||||
(uint8_t*)pub_key, CRYS_ECEDW_MOD_SIZE_IN_BYTES,
|
||||
(uint8_t*)message, (size_t)msg_len, &cc310_tmp);
|
||||
nRFCrypto.end();
|
||||
return rc == CRYS_OK;
|
||||
#elif 0
|
||||
// needs much less, around 600-700 bytes. Access is serialized because the
|
||||
// workspace and the CC310 driver are not reentrant.
|
||||
CC310CryptoSession session;
|
||||
if (session) {
|
||||
static CRYS_ECEDW_TempBuff_t cc310_tmp;
|
||||
const CRYSError_t rc = CRYS_ECEDW_Verify(
|
||||
const_cast<uint8_t*>(sig), CRYS_ECEDW_SIGNATURE_BYTES,
|
||||
const_cast<uint8_t*>(pub_key), CRYS_ECEDW_MOD_SIZE_IN_BYTES,
|
||||
const_cast<uint8_t*>(message), static_cast<size_t>(msg_len), &cc310_tmp);
|
||||
if (rc == CRYS_OK) return true;
|
||||
// A normal signature mismatch is a conclusive hardware result. Other
|
||||
// CC310 errors fall through to the correctness-preserving software path.
|
||||
if (rc == CRYS_ECEDW_SIGN_VERIFY_FAILED_ERROR) return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// NOTE: memory corruption bug was found in this function!!
|
||||
return ed25519_verify(sig, message, msg_len, pub_key);
|
||||
#else
|
||||
|
||||
@@ -93,6 +93,10 @@ public:
|
||||
virtual bool setLoRaFemLnaEnabled(bool enable) { return false; }
|
||||
virtual bool canControlLoRaFemLna() const { return false; }
|
||||
virtual bool isLoRaFemLnaEnabled() const { return false; }
|
||||
// Software-selectable external FEM transmit gain. This is not a PA power switch.
|
||||
virtual bool setLoRaFemPaGainEnabled(bool enable) { return false; }
|
||||
virtual bool canControlLoRaFemPaGain() const { return false; }
|
||||
virtual bool isLoRaFemPaGainEnabled() const { return false; }
|
||||
#if defined(ENABLE_OTA)
|
||||
// 4-byte build-target discriminator for OTA-over-LoRa (docs/ota_protocol.md Section 9). Default is the
|
||||
// MOTA_TARGET_ID build flag injected by build.sh; 0 when unset (e.g. a bare IDE build).
|
||||
|
||||
+199
-120
@@ -3,7 +3,7 @@
|
||||
#include <SHA256.h>
|
||||
|
||||
#ifdef USE_CC310_HW_CRYPTO
|
||||
#include <Adafruit_nRFCrypto.h>
|
||||
#include "helpers/NRF52Crypto.h"
|
||||
#include "nrf_cc310/include/crys_hash.h"
|
||||
#include "nrf_cc310/include/crys_hmac.h"
|
||||
#include "nrf_cc310/include/ssi_aes.h"
|
||||
@@ -13,6 +13,142 @@
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
void sha256Software(uint8_t* hash, size_t hash_len, const uint8_t* msg, int msg_len) {
|
||||
SHA256 sha;
|
||||
sha.update(msg, msg_len);
|
||||
sha.finalize(hash, hash_len);
|
||||
}
|
||||
|
||||
void sha256Software(uint8_t* hash, size_t hash_len,
|
||||
const uint8_t* frag1, int frag1_len,
|
||||
const uint8_t* frag2, int frag2_len) {
|
||||
SHA256 sha;
|
||||
sha.update(frag1, frag1_len);
|
||||
sha.update(frag2, frag2_len);
|
||||
sha.finalize(hash, hash_len);
|
||||
}
|
||||
|
||||
int decryptSoftware(const uint8_t* shared_secret, uint8_t* dest,
|
||||
const uint8_t* src, int src_len) {
|
||||
AES128 aes;
|
||||
uint8_t* dp = dest;
|
||||
const uint8_t* sp = src;
|
||||
|
||||
aes.setKey(shared_secret, CIPHER_KEY_SIZE);
|
||||
while (sp - src < src_len) {
|
||||
aes.decryptBlock(dp, sp);
|
||||
dp += CIPHER_BLOCK_SIZE;
|
||||
sp += CIPHER_BLOCK_SIZE;
|
||||
}
|
||||
return static_cast<int>(sp - src);
|
||||
}
|
||||
|
||||
int encryptSoftware(const uint8_t* shared_secret, uint8_t* dest,
|
||||
const uint8_t* src, int src_len) {
|
||||
AES128 aes;
|
||||
uint8_t* dp = dest;
|
||||
|
||||
aes.setKey(shared_secret, CIPHER_KEY_SIZE);
|
||||
while (src_len >= CIPHER_BLOCK_SIZE) {
|
||||
aes.encryptBlock(dp, src);
|
||||
dp += CIPHER_BLOCK_SIZE;
|
||||
src += CIPHER_BLOCK_SIZE;
|
||||
src_len -= CIPHER_BLOCK_SIZE;
|
||||
}
|
||||
if (src_len > 0) {
|
||||
uint8_t tmp[CIPHER_BLOCK_SIZE] = {};
|
||||
memcpy(tmp, src, src_len);
|
||||
aes.encryptBlock(dp, tmp);
|
||||
dp += CIPHER_BLOCK_SIZE;
|
||||
}
|
||||
return static_cast<int>(dp - dest);
|
||||
}
|
||||
|
||||
void hmacSoftware(const uint8_t* shared_secret, uint8_t* dest,
|
||||
const uint8_t* src, int src_len) {
|
||||
SHA256 sha;
|
||||
sha.resetHMAC(shared_secret, PUB_KEY_SIZE);
|
||||
sha.update(src, src_len);
|
||||
sha.finalizeHMAC(shared_secret, PUB_KEY_SIZE, dest, CIPHER_MAC_SIZE);
|
||||
}
|
||||
|
||||
#ifdef USE_CC310_HW_CRYPTO
|
||||
|
||||
bool rangesOverlap(const uint8_t* first, size_t first_len,
|
||||
const uint8_t* second, size_t second_len) {
|
||||
const uintptr_t first_addr = reinterpret_cast<uintptr_t>(first);
|
||||
const uintptr_t second_addr = reinterpret_cast<uintptr_t>(second);
|
||||
if (first_addr <= second_addr) return second_addr - first_addr < first_len;
|
||||
return first_addr - second_addr < second_len;
|
||||
}
|
||||
|
||||
// Returns -1 when the hardware path is unavailable or any CC310 call fails.
|
||||
// Callers retain the original input and can recompute the complete result in
|
||||
// software.
|
||||
int aesHardware(bool encrypting, const uint8_t* shared_secret, uint8_t* dest,
|
||||
const uint8_t* src, int src_len) {
|
||||
mesh::CC310CryptoSession session;
|
||||
if (!session) return -1;
|
||||
|
||||
static SaSiAesUserContext_t ctx;
|
||||
SaSiAesUserKeyData_t key_data = {
|
||||
const_cast<uint8_t*>(shared_secret), CIPHER_KEY_SIZE
|
||||
};
|
||||
SaSiError_t rc = SaSi_AesInit(
|
||||
&ctx, encrypting ? SASI_AES_ENCRYPT : SASI_AES_DECRYPT,
|
||||
SASI_AES_MODE_ECB, SASI_AES_PADDING_NONE);
|
||||
const bool initialized = rc == SASI_OK;
|
||||
if (rc == SASI_OK) {
|
||||
rc = SaSi_AesSetKey(&ctx, SASI_AES_USER_KEY, &key_data, sizeof(key_data));
|
||||
}
|
||||
|
||||
uint8_t* dp = dest;
|
||||
const uint8_t* sp = src;
|
||||
int remaining = src_len;
|
||||
while (rc == SASI_OK && remaining >= CIPHER_BLOCK_SIZE) {
|
||||
rc = SaSi_AesBlock(&ctx, const_cast<uint8_t*>(sp), CIPHER_BLOCK_SIZE, dp);
|
||||
if (rc == SASI_OK) {
|
||||
dp += CIPHER_BLOCK_SIZE;
|
||||
sp += CIPHER_BLOCK_SIZE;
|
||||
remaining -= CIPHER_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
if (rc == SASI_OK && encrypting && remaining > 0) {
|
||||
uint8_t padded[CIPHER_BLOCK_SIZE] = {};
|
||||
memcpy(padded, sp, remaining);
|
||||
rc = SaSi_AesBlock(&ctx, padded, CIPHER_BLOCK_SIZE, dp);
|
||||
if (rc == SASI_OK) dp += CIPHER_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
size_t final_size = 0;
|
||||
if (rc == SASI_OK) {
|
||||
rc = SaSi_AesFinish(&ctx, 0, NULL, 0, NULL, &final_size);
|
||||
}
|
||||
const SaSiError_t free_rc = initialized ? SaSi_AesFree(&ctx) : SASI_OK;
|
||||
if (rc != SASI_OK || free_rc != SASI_OK) return -1;
|
||||
return static_cast<int>(dp - dest);
|
||||
}
|
||||
|
||||
bool hmacHardware(const uint8_t* shared_secret, uint8_t* dest,
|
||||
const uint8_t* src, int src_len) {
|
||||
mesh::CC310CryptoSession session;
|
||||
if (!session) return false;
|
||||
|
||||
static CRYS_HASH_Result_t result;
|
||||
const CRYSError_t rc = CRYS_HMAC(
|
||||
CRYS_HASH_SHA256_mode, const_cast<uint8_t*>(shared_secret), PUB_KEY_SIZE,
|
||||
const_cast<uint8_t*>(src), static_cast<size_t>(src_len), result);
|
||||
if (rc != CRYS_OK) return false;
|
||||
memcpy(dest, result, CIPHER_MAC_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mesh {
|
||||
|
||||
uint32_t RNG::nextInt(uint32_t _min, uint32_t _max) {
|
||||
@@ -23,35 +159,53 @@ uint32_t RNG::nextInt(uint32_t _min, uint32_t _max) {
|
||||
|
||||
void Utils::sha256(uint8_t *hash, size_t hash_len, const uint8_t* msg, int msg_len) {
|
||||
#ifdef USE_CC310_HW_CRYPTO
|
||||
static CRYS_HASH_Result_t result;
|
||||
nRFCrypto.begin();
|
||||
CRYS_HASH(CRYS_HASH_SHA256_mode, (uint8_t*)msg, (size_t)msg_len, result);
|
||||
nRFCrypto.end();
|
||||
memcpy(hash, result, hash_len);
|
||||
#else
|
||||
SHA256 sha;
|
||||
sha.update(msg, msg_len);
|
||||
sha.finalize(hash, hash_len);
|
||||
if (hash_len <= SHA256::HASH_SIZE && msg_len >= 0) {
|
||||
CC310CryptoSession session;
|
||||
if (session) {
|
||||
static CRYS_HASH_Result_t result;
|
||||
const CRYSError_t rc = CRYS_HASH(
|
||||
CRYS_HASH_SHA256_mode, const_cast<uint8_t*>(msg),
|
||||
static_cast<size_t>(msg_len), result);
|
||||
if (rc == CRYS_OK) {
|
||||
memcpy(hash, result, hash_len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
sha256Software(hash, hash_len, msg, msg_len);
|
||||
}
|
||||
|
||||
void Utils::sha256(uint8_t *hash, size_t hash_len, const uint8_t* frag1, int frag1_len, const uint8_t* frag2, int frag2_len) {
|
||||
#ifdef USE_CC310_HW_CRYPTO
|
||||
static CRYS_HASHUserContext_t ctx;
|
||||
static CRYS_HASH_Result_t result;
|
||||
nRFCrypto.begin();
|
||||
CRYS_HASH_Init(&ctx, CRYS_HASH_SHA256_mode);
|
||||
CRYS_HASH_Update(&ctx, (uint8_t*)frag1, (size_t)frag1_len);
|
||||
CRYS_HASH_Update(&ctx, (uint8_t*)frag2, (size_t)frag2_len);
|
||||
CRYS_HASH_Finish(&ctx, result);
|
||||
nRFCrypto.end();
|
||||
memcpy(hash, result, hash_len);
|
||||
#else
|
||||
SHA256 sha;
|
||||
sha.update(frag1, frag1_len);
|
||||
sha.update(frag2, frag2_len);
|
||||
sha.finalize(hash, hash_len);
|
||||
if (hash_len <= SHA256::HASH_SIZE && frag1_len > 0 && frag2_len > 0) {
|
||||
CC310CryptoSession session;
|
||||
if (session) {
|
||||
static CRYS_HASHUserContext_t ctx;
|
||||
static CRYS_HASH_Result_t result;
|
||||
CRYSError_t rc = CRYS_HASH_Init(&ctx, CRYS_HASH_SHA256_mode);
|
||||
const bool initialized = rc == CRYS_OK;
|
||||
if (rc == CRYS_OK) {
|
||||
rc = CRYS_HASH_Update(&ctx, const_cast<uint8_t*>(frag1),
|
||||
static_cast<size_t>(frag1_len));
|
||||
}
|
||||
if (rc == CRYS_OK) {
|
||||
rc = CRYS_HASH_Update(&ctx, const_cast<uint8_t*>(frag2),
|
||||
static_cast<size_t>(frag2_len));
|
||||
}
|
||||
if (rc == CRYS_OK) rc = CRYS_HASH_Finish(&ctx, result);
|
||||
if (rc == CRYS_OK) {
|
||||
memcpy(hash, result, hash_len);
|
||||
return;
|
||||
}
|
||||
if (initialized) {
|
||||
const bool context_freed = CRYS_HASH_Free(&ctx) == CRYS_OK;
|
||||
(void) context_freed;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
sha256Software(hash, hash_len, frag1, frag1_len, frag2, frag2_len);
|
||||
}
|
||||
|
||||
int Utils::decrypt(const uint8_t* shared_secret, uint8_t* dest, const uint8_t* src, int src_len) {
|
||||
@@ -61,100 +215,38 @@ int Utils::decrypt(const uint8_t* shared_secret, uint8_t* dest, const uint8_t* s
|
||||
}
|
||||
|
||||
#ifdef USE_CC310_HW_CRYPTO
|
||||
static SaSiAesUserContext_t ctx;
|
||||
SaSiAesUserKeyData_t keyData = { (uint8_t*)shared_secret, CIPHER_KEY_SIZE };
|
||||
uint8_t* dp = dest;
|
||||
const uint8_t* sp = src;
|
||||
size_t dummy_out = 0;
|
||||
|
||||
nRFCrypto.begin();
|
||||
SaSi_AesInit(&ctx, SASI_AES_DECRYPT, SASI_AES_MODE_ECB, SASI_AES_PADDING_NONE);
|
||||
SaSi_AesSetKey(&ctx, SASI_AES_USER_KEY, &keyData, sizeof(keyData));
|
||||
while (sp - src < src_len) {
|
||||
SaSi_AesBlock(&ctx, (uint8_t*)sp, 16, dp);
|
||||
dp += 16; sp += 16;
|
||||
if (!rangesOverlap(dest, static_cast<size_t>(src_len),
|
||||
src, static_cast<size_t>(src_len))) {
|
||||
const int hardware_len = aesHardware(false, shared_secret, dest, src, src_len);
|
||||
if (hardware_len >= 0) return hardware_len;
|
||||
}
|
||||
SaSi_AesFinish(&ctx, 0, NULL, 0, NULL, &dummy_out);
|
||||
SaSi_AesFree(&ctx);
|
||||
nRFCrypto.end();
|
||||
return sp - src;
|
||||
#else
|
||||
AES128 aes;
|
||||
uint8_t* dp = dest;
|
||||
const uint8_t* sp = src;
|
||||
|
||||
aes.setKey(shared_secret, CIPHER_KEY_SIZE);
|
||||
while (sp - src < src_len) {
|
||||
aes.decryptBlock(dp, sp);
|
||||
dp += 16; sp += 16;
|
||||
}
|
||||
|
||||
return sp - src; // will always be multiple of 16
|
||||
#endif
|
||||
return decryptSoftware(shared_secret, dest, src, src_len);
|
||||
}
|
||||
|
||||
int Utils::encrypt(const uint8_t* shared_secret, uint8_t* dest, const uint8_t* src, int src_len) {
|
||||
if (shared_secret == NULL || dest == NULL || src == NULL || src_len <= 0) return 0;
|
||||
|
||||
#ifdef USE_CC310_HW_CRYPTO
|
||||
static SaSiAesUserContext_t ctx;
|
||||
SaSiAesUserKeyData_t keyData = { (uint8_t*)shared_secret, CIPHER_KEY_SIZE };
|
||||
uint8_t* dp = dest;
|
||||
size_t dummy_out = 0;
|
||||
|
||||
nRFCrypto.begin();
|
||||
SaSi_AesInit(&ctx, SASI_AES_ENCRYPT, SASI_AES_MODE_ECB, SASI_AES_PADDING_NONE);
|
||||
SaSi_AesSetKey(&ctx, SASI_AES_USER_KEY, &keyData, sizeof(keyData));
|
||||
while (src_len >= 16) {
|
||||
SaSi_AesBlock(&ctx, (uint8_t*)src, 16, dp);
|
||||
dp += 16; src += 16; src_len -= 16;
|
||||
const size_t output_len = static_cast<size_t>(
|
||||
(src_len + CIPHER_BLOCK_SIZE - 1) / CIPHER_BLOCK_SIZE * CIPHER_BLOCK_SIZE);
|
||||
if (!rangesOverlap(dest, output_len, src, static_cast<size_t>(src_len))) {
|
||||
const int hardware_len = aesHardware(true, shared_secret, dest, src, src_len);
|
||||
if (hardware_len >= 0) return hardware_len;
|
||||
}
|
||||
if (src_len > 0) { // remaining partial block — zero-pad to 16 bytes
|
||||
uint8_t tmp[16] = {};
|
||||
memcpy(tmp, src, src_len);
|
||||
SaSi_AesBlock(&ctx, tmp, 16, dp);
|
||||
dp += 16;
|
||||
}
|
||||
SaSi_AesFinish(&ctx, 0, NULL, 0, NULL, &dummy_out);
|
||||
SaSi_AesFree(&ctx);
|
||||
nRFCrypto.end();
|
||||
return dp - dest;
|
||||
#else
|
||||
AES128 aes;
|
||||
uint8_t* dp = dest;
|
||||
|
||||
aes.setKey(shared_secret, CIPHER_KEY_SIZE);
|
||||
while (src_len >= 16) {
|
||||
aes.encryptBlock(dp, src);
|
||||
dp += 16; src += 16; src_len -= 16;
|
||||
}
|
||||
if (src_len > 0) { // remaining partial block
|
||||
uint8_t tmp[16];
|
||||
memset(tmp, 0, 16);
|
||||
memcpy(tmp, src, src_len);
|
||||
aes.encryptBlock(dp, tmp);
|
||||
dp += 16;
|
||||
}
|
||||
return dp - dest; // will always be multiple of 16
|
||||
#endif
|
||||
return encryptSoftware(shared_secret, dest, src, src_len);
|
||||
}
|
||||
|
||||
int Utils::encryptThenMAC(const uint8_t* shared_secret, uint8_t* dest, const uint8_t* src, int src_len) {
|
||||
int enc_len = encrypt(shared_secret, dest + CIPHER_MAC_SIZE, src, src_len);
|
||||
|
||||
#ifdef USE_CC310_HW_CRYPTO
|
||||
static CRYS_HMACUserContext_t hmac_ctx;
|
||||
static CRYS_HASH_Result_t hmac_result;
|
||||
nRFCrypto.begin();
|
||||
CRYS_HMAC_Init(&hmac_ctx, CRYS_HASH_SHA256_mode, (uint8_t*)shared_secret, PUB_KEY_SIZE);
|
||||
CRYS_HMAC_Update(&hmac_ctx, dest + CIPHER_MAC_SIZE, enc_len);
|
||||
CRYS_HMAC_Finish(&hmac_ctx, hmac_result);
|
||||
nRFCrypto.end();
|
||||
memcpy(dest, hmac_result, CIPHER_MAC_SIZE);
|
||||
#else
|
||||
SHA256 sha;
|
||||
sha.resetHMAC(shared_secret, PUB_KEY_SIZE);
|
||||
sha.update(dest + CIPHER_MAC_SIZE, enc_len);
|
||||
sha.finalizeHMAC(shared_secret, PUB_KEY_SIZE, dest, CIPHER_MAC_SIZE);
|
||||
if (!hmacHardware(shared_secret, dest, dest + CIPHER_MAC_SIZE, enc_len))
|
||||
#endif
|
||||
{
|
||||
hmacSoftware(shared_secret, dest, dest + CIPHER_MAC_SIZE, enc_len);
|
||||
}
|
||||
|
||||
return CIPHER_MAC_SIZE + enc_len;
|
||||
}
|
||||
@@ -167,24 +259,11 @@ int Utils::MACThenDecrypt(const uint8_t* shared_secret, uint8_t* dest, const uin
|
||||
|
||||
uint8_t hmac[CIPHER_MAC_SIZE];
|
||||
#ifdef USE_CC310_HW_CRYPTO
|
||||
{
|
||||
static CRYS_HMACUserContext_t hmac_ctx;
|
||||
static CRYS_HASH_Result_t hmac_result;
|
||||
nRFCrypto.begin();
|
||||
CRYS_HMAC_Init(&hmac_ctx, CRYS_HASH_SHA256_mode, (uint8_t*)shared_secret, PUB_KEY_SIZE);
|
||||
CRYS_HMAC_Update(&hmac_ctx, (uint8_t*)(src + CIPHER_MAC_SIZE), src_len - CIPHER_MAC_SIZE);
|
||||
CRYS_HMAC_Finish(&hmac_ctx, hmac_result);
|
||||
nRFCrypto.end();
|
||||
memcpy(hmac, hmac_result, CIPHER_MAC_SIZE);
|
||||
}
|
||||
#else
|
||||
{
|
||||
SHA256 sha;
|
||||
sha.resetHMAC(shared_secret, PUB_KEY_SIZE);
|
||||
sha.update(src + CIPHER_MAC_SIZE, enc_len);
|
||||
sha.finalizeHMAC(shared_secret, PUB_KEY_SIZE, hmac, CIPHER_MAC_SIZE);
|
||||
}
|
||||
if (!hmacHardware(shared_secret, hmac, src + CIPHER_MAC_SIZE, enc_len))
|
||||
#endif
|
||||
{
|
||||
hmacSoftware(shared_secret, hmac, src + CIPHER_MAC_SIZE, enc_len);
|
||||
}
|
||||
if (memcmp(hmac, src, CIPHER_MAC_SIZE) == 0) {
|
||||
return decrypt(shared_secret, dest, src + CIPHER_MAC_SIZE, enc_len);
|
||||
}
|
||||
|
||||
@@ -909,6 +909,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
||||
// Defaults for the trailing fields that older/shorter files may not contain.
|
||||
// Build-profile defaults - overwritten below when the saved field is present.
|
||||
_prefs->radio_fem_rxgain = 1;
|
||||
_prefs->radio_fem_txgain = 0;
|
||||
_prefs->cad_enabled = DEFAULT_CAD_ENABLED;
|
||||
memset(_prefs->extra_sf, 0, sizeof(_prefs->extra_sf));
|
||||
_prefs->rx_powersaving_enabled = 0;
|
||||
@@ -1193,6 +1194,10 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
||||
}
|
||||
if (file.available() >= (int)sizeof(_prefs->extra_sf)) {
|
||||
file.read((uint8_t *)_prefs->extra_sf, sizeof(_prefs->extra_sf));
|
||||
if (file.available() >= (int)sizeof(_prefs->radio_fem_txgain)) {
|
||||
file.read((uint8_t *)&_prefs->radio_fem_txgain,
|
||||
sizeof(_prefs->radio_fem_txgain));
|
||||
}
|
||||
} else if (file.available() > 0) {
|
||||
// Never accept a torn append as a partial detector list.
|
||||
_com_prefs_needs_upgrade = true;
|
||||
@@ -1261,6 +1266,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
||||
|
||||
_prefs->rx_boosted_gain = constrain(_prefs->rx_boosted_gain, 0, 1); // boolean
|
||||
_prefs->radio_fem_rxgain = constrain(_prefs->radio_fem_rxgain, 0, 1); // boolean
|
||||
_prefs->radio_fem_txgain = constrain(_prefs->radio_fem_txgain, 0, 1); // boolean
|
||||
_prefs->cad_enabled = constrain(_prefs->cad_enabled, 0, 1); // boolean
|
||||
if (!directRetryPrefsValid(_prefs)) {
|
||||
setDefaultDirectRetryPrefs(_prefs);
|
||||
@@ -1467,6 +1473,7 @@ static bool writeCommonPrefsImage(Writer& writer, NodePrefs* prefs) {
|
||||
WRITE_COMMON_PREFS(&prefs->rx_watchdog_enabled); // 854
|
||||
WRITE_COMMON_PREFS(&prefs->system_watchdog_enabled); // 855
|
||||
WRITE_COMMON_PREFS(&prefs->extra_sf); // 856
|
||||
WRITE_COMMON_PREFS(&prefs->radio_fem_txgain); // 860
|
||||
|
||||
#undef WRITE_COMMON_PREFS_BYTES
|
||||
#undef WRITE_COMMON_PREFS
|
||||
@@ -1617,7 +1624,8 @@ void CommonCLI::savePrefs(FILESYSTEM* fs, PrefsSaveRouting::Scope scope) {
|
||||
file.write((uint8_t *)&_prefs->system_watchdog_enabled,
|
||||
sizeof(_prefs->system_watchdog_enabled)); // 855
|
||||
file.write((uint8_t *)_prefs->extra_sf, sizeof(_prefs->extra_sf)); // 856
|
||||
// next: 860
|
||||
file.write((uint8_t *)&_prefs->radio_fem_txgain, sizeof(_prefs->radio_fem_txgain)); // 860
|
||||
// next: 861
|
||||
|
||||
#if defined(NRF52_PLATFORM)
|
||||
if (!file.commit()) {
|
||||
@@ -3208,6 +3216,23 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
strcpy(reply, "Error: failed to apply LoRa FEM RX gain");
|
||||
}
|
||||
}
|
||||
} else if (memcmp(config, "radio.fem.txgain ", 17) == 0) {
|
||||
const char* value = &config[17];
|
||||
if (!_board->canControlLoRaFemPaGain()) {
|
||||
strcpy(reply, "Error: unsupported");
|
||||
} else if (strcmp(value, "on") != 0 && strcmp(value, "off") != 0) {
|
||||
strcpy(reply, "Error: state must be on or off");
|
||||
} else {
|
||||
const bool enabled = strcmp(value, "on") == 0;
|
||||
if (_board->setLoRaFemPaGainEnabled(enabled)) {
|
||||
_prefs->radio_fem_txgain = enabled ? 1 : 0;
|
||||
savePrefs();
|
||||
strcpy(reply, enabled
|
||||
? "OK - LoRa FEM TX gain on" : "OK - LoRa FEM TX gain off");
|
||||
} else {
|
||||
strcpy(reply, "Error: failed to apply LoRa FEM TX gain");
|
||||
}
|
||||
}
|
||||
} else if (memcmp(config, "radio ", 6) == 0) {
|
||||
strcpy(tmp, &config[6]);
|
||||
const char* parts[4];
|
||||
@@ -3508,6 +3533,28 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
} else {
|
||||
strcpy(reply, "Error: state must be on or off");
|
||||
}
|
||||
} else if (memcmp(config, "radio.fem.txgain ", 17) == 0) {
|
||||
if (!_board->canControlLoRaFemPaGain()) {
|
||||
strcpy(reply, "Error: unsupported");
|
||||
} else if (memcmp(&config[17], "on", 2) == 0) {
|
||||
if (_board->setLoRaFemPaGainEnabled(true)) {
|
||||
_prefs->radio_fem_txgain = 1;
|
||||
savePrefs();
|
||||
strcpy(reply, "OK - LoRa FEM TX gain on");
|
||||
} else {
|
||||
strcpy(reply, "Error: failed to apply LoRa FEM TX gain");
|
||||
}
|
||||
} else if (memcmp(&config[17], "off", 3) == 0) {
|
||||
if (_board->setLoRaFemPaGainEnabled(false)) {
|
||||
_prefs->radio_fem_txgain = 0;
|
||||
savePrefs();
|
||||
strcpy(reply, "OK - LoRa FEM TX gain off");
|
||||
} else {
|
||||
strcpy(reply, "Error: failed to apply LoRa FEM TX gain");
|
||||
}
|
||||
} else {
|
||||
strcpy(reply, "Error: state must be on or off");
|
||||
}
|
||||
} else if (memcmp(config, "radio.rxps ", 11) == 0) { // RX PowerSaving
|
||||
const char* value = &config[11];
|
||||
uint8_t enable = _prefs->rx_powersaving_enabled;
|
||||
@@ -4249,6 +4296,13 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
sprintf(reply, "> %s",
|
||||
_board->isLoRaFemLnaEnabled() ? "on" : "off");
|
||||
}
|
||||
} else if (strcmp(config, "radio.fem.txgain") == 0) {
|
||||
if (!_board->canControlLoRaFemPaGain()) {
|
||||
strcpy(reply, "Error: unsupported");
|
||||
} else {
|
||||
sprintf(reply, "> %s",
|
||||
_board->isLoRaFemPaGainEnabled() ? "on" : "off");
|
||||
}
|
||||
} else if (strcmp(config, "radio") == 0) {
|
||||
char freq[16], bw[16];
|
||||
strcpy(freq, StrHelper::ftoa(_prefs->freq));
|
||||
@@ -4359,6 +4413,12 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
} else {
|
||||
sprintf(reply, "> %s", _board->isLoRaFemLnaEnabled() ? "on" : "off");
|
||||
}
|
||||
} else if (memcmp(config, "radio.fem.txgain", 16) == 0) {
|
||||
if (!_board->canControlLoRaFemPaGain()) {
|
||||
strcpy(reply, "Error: unsupported");
|
||||
} else {
|
||||
sprintf(reply, "> %s", _board->isLoRaFemPaGainEnabled() ? "on" : "off");
|
||||
}
|
||||
} else if (memcmp(config, "tempradioat", 11) == 0 && (config[11] == 0 || config[11] == ' ')) {
|
||||
_callbacks->formatScheduledRadioParams(true, skipSpacesConst(&config[11]), reply);
|
||||
} else if (memcmp(config, "radioat", 7) == 0 && (config[7] == 0 || config[7] == ' ')) {
|
||||
|
||||
@@ -160,6 +160,7 @@ struct NodePrefs { // persisted to file
|
||||
// LR2021 side-detector SFs are appended at /com_prefs offset 856. Their
|
||||
// in-memory placement here does not shift the established binary layout.
|
||||
uint8_t extra_sf[4] = {};
|
||||
uint8_t radio_fem_txgain; // LoRa FEM TX gain; persisted at /com_prefs offset 860
|
||||
uint8_t retry_preset;
|
||||
uint8_t direct_retry_attempts;
|
||||
uint16_t direct_retry_base_ms;
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
#include "NRF52Crypto.h"
|
||||
|
||||
#if defined(USE_CC310_HW_CRYPTO)
|
||||
|
||||
#include <Adafruit_nRFCrypto.h>
|
||||
#include <Arduino.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace {
|
||||
|
||||
enum CC310State : uint8_t {
|
||||
CC310_UNINITIALIZED,
|
||||
CC310_AVAILABLE,
|
||||
CC310_UNAVAILABLE
|
||||
};
|
||||
|
||||
StaticSemaphore_t cc310_mutex_storage;
|
||||
SemaphoreHandle_t cc310_mutex = NULL;
|
||||
CC310State cc310_state = CC310_UNINITIALIZED;
|
||||
|
||||
SemaphoreHandle_t getCC310Mutex() {
|
||||
if (cc310_mutex == NULL) {
|
||||
// nRF52840 is single-core. The critical section makes the lazy static
|
||||
// mutex construction safe if two tasks make their first crypto call at
|
||||
// the same time.
|
||||
taskENTER_CRITICAL();
|
||||
if (cc310_mutex == NULL) {
|
||||
cc310_mutex = xSemaphoreCreateMutexStatic(&cc310_mutex_storage);
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
return cc310_mutex;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mesh {
|
||||
|
||||
CC310CryptoSession::CC310CryptoSession()
|
||||
: _locked(false), _available(false) {
|
||||
// FreeRTOS mutex APIs and the CC310 driver are not ISR-safe.
|
||||
if (isInISR()) return;
|
||||
|
||||
SemaphoreHandle_t mutex = getCC310Mutex();
|
||||
if (mutex == NULL || xSemaphoreTake(mutex, portMAX_DELAY) != pdTRUE) return;
|
||||
_locked = true;
|
||||
|
||||
if (cc310_state == CC310_UNINITIALIZED) {
|
||||
// Adafruit_nRFCrypto::begin() also initializes its DRBG. Keep it alive for
|
||||
// the process lifetime: end()/begin() would repeatedly reset that state.
|
||||
cc310_state = nRFCrypto.begin() ? CC310_AVAILABLE : CC310_UNAVAILABLE;
|
||||
}
|
||||
_available = cc310_state == CC310_AVAILABLE;
|
||||
}
|
||||
|
||||
CC310CryptoSession::~CC310CryptoSession() {
|
||||
if (_locked) xSemaphoreGive(cc310_mutex);
|
||||
}
|
||||
|
||||
bool initializeCC310Crypto() {
|
||||
CC310CryptoSession session;
|
||||
return static_cast<bool>(session);
|
||||
}
|
||||
|
||||
void mixCC310Random(uint8_t* dest, size_t size) {
|
||||
if (dest == NULL || size == 0) return;
|
||||
|
||||
CC310CryptoSession session;
|
||||
if (!session) return;
|
||||
|
||||
uint8_t hardware_random[32];
|
||||
size_t offset = 0;
|
||||
while (offset < size) {
|
||||
const size_t remaining = size - offset;
|
||||
const uint16_t chunk = static_cast<uint16_t>(
|
||||
remaining < sizeof(hardware_random) ? remaining : sizeof(hardware_random));
|
||||
if (!nRFCrypto.Random.generate(hardware_random, chunk)) break;
|
||||
for (uint16_t i = 0; i < chunk; ++i) {
|
||||
dest[offset + i] ^= hardware_random[i];
|
||||
}
|
||||
offset += chunk;
|
||||
}
|
||||
memset(hardware_random, 0, sizeof(hardware_random));
|
||||
}
|
||||
|
||||
} // namespace mesh
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(USE_CC310_HW_CRYPTO)
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
// Serializes access to the CC310 and performs its process-lifetime
|
||||
// initialization. A session is unavailable in interrupt context or when the
|
||||
// one-time hardware initialization failed; callers must then use software.
|
||||
class CC310CryptoSession {
|
||||
public:
|
||||
CC310CryptoSession();
|
||||
~CC310CryptoSession();
|
||||
|
||||
explicit operator bool() const { return _available; }
|
||||
|
||||
CC310CryptoSession(const CC310CryptoSession&) = delete;
|
||||
CC310CryptoSession& operator=(const CC310CryptoSession&) = delete;
|
||||
|
||||
private:
|
||||
bool _locked;
|
||||
bool _available;
|
||||
};
|
||||
|
||||
// Initialize the CC310 once during normal system startup. Sessions also call
|
||||
// this lazily so early crypto users remain safe.
|
||||
bool initializeCC310Crypto();
|
||||
|
||||
// XOR CC310 random output into bytes already populated by another entropy
|
||||
// source. A hardware failure leaves those existing bytes usable.
|
||||
void mixCC310Random(uint8_t* dest, size_t size);
|
||||
|
||||
} // namespace mesh
|
||||
|
||||
#endif
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
}
|
||||
uint8_t getSpreadingFactor() const override { return ((CustomLLCC68 *)_radio)->spreadingFactor; }
|
||||
|
||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio, getRxBoostedGainMode()); }
|
||||
|
||||
protected:
|
||||
bool radioDeepInit() override {
|
||||
|
||||
@@ -40,7 +40,6 @@ public:
|
||||
return ((CustomLR1110 *)_radio)->setCodingRate(cr) == RADIOLIB_ERR_NONE;
|
||||
}
|
||||
|
||||
void doResetAGC() override { lr11x0ResetAGC((LR11x0 *)_radio, ((CustomLR1110 *)_radio)->getFreqMHz()); }
|
||||
bool isReceivingPacket() override {
|
||||
return ((CustomLR1110 *)_radio)->isReceiving();
|
||||
}
|
||||
@@ -133,4 +132,6 @@ public:
|
||||
bool getRxBoostedGainMode() const override {
|
||||
return ((CustomLR1110 *)_radio)->getRxBoostedGainMode();
|
||||
}
|
||||
|
||||
void doResetAGC() override { lr11x0ResetAGC((LR11x0 *)_radio, ((CustomLR1110 *)_radio)->getFreqMHz(), getRxBoostedGainMode()); }
|
||||
};
|
||||
@@ -35,5 +35,5 @@ public:
|
||||
}
|
||||
uint8_t getSpreadingFactor() const override { return ((CustomSTM32WLx *)_radio)->spreadingFactor; }
|
||||
|
||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio, getRxBoostedGainMode()); }
|
||||
};
|
||||
@@ -99,8 +99,6 @@ protected:
|
||||
}
|
||||
bool supportsRadioDeepInit() const override { return true; }
|
||||
|
||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
||||
|
||||
protected:
|
||||
bool applyRxBoostedGainMode(bool en) override {
|
||||
return ((CustomSX1262 *)_radio)->setRxBoostedGainMode(en) == RADIOLIB_ERR_NONE;
|
||||
@@ -109,4 +107,6 @@ public:
|
||||
bool getRxBoostedGainMode() const override {
|
||||
return ((CustomSX1262 *)_radio)->getRxBoostedGainMode();
|
||||
}
|
||||
|
||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio, getRxBoostedGainMode()); }
|
||||
};
|
||||
@@ -46,8 +46,6 @@ public:
|
||||
}
|
||||
uint8_t getSpreadingFactor() const override { return ((CustomSX1268 *)_radio)->spreadingFactor; }
|
||||
|
||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
||||
|
||||
protected:
|
||||
bool radioDeepInit() override {
|
||||
return ((CustomSX1268 *)_radio)->std_init();
|
||||
@@ -62,4 +60,6 @@ public:
|
||||
bool getRxBoostedGainMode() const override {
|
||||
return ((CustomSX1268 *)_radio)->getRxBoostedGainMode();
|
||||
}
|
||||
|
||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio, getRxBoostedGainMode()); }
|
||||
};
|
||||
@@ -5,7 +5,7 @@
|
||||
// Full receiver reset for LR11x0-family chips (LR1110, LR1120, LR1121).
|
||||
// Warm sleep powers down analog, calibrate(0x3F) refreshes all calibration blocks,
|
||||
// then re-applies RX settings that calibration may reset.
|
||||
inline void lr11x0ResetAGC(LR11x0* radio, float freqMHz) {
|
||||
inline void lr11x0ResetAGC(LR11x0* radio, float freqMHz, bool rx_boost_gain) {
|
||||
radio->sleep(true, 0);
|
||||
radio->standby(RADIOLIB_LR11X0_STANDBY_RC, true);
|
||||
|
||||
@@ -16,8 +16,6 @@ inline void lr11x0ResetAGC(LR11x0* radio, float freqMHz) {
|
||||
radio->calibrateImageRejection(freqMHz - 4.0f, freqMHz + 4.0f);
|
||||
|
||||
#ifdef RX_BOOSTED_GAIN
|
||||
// Fallback for callers without a runtime override. RadioLibWrapper::resetAGC()
|
||||
// reapplies its cached radio.rxgain selection before receive mode resumes.
|
||||
radio->setRxBoostedGainMode(RX_BOOSTED_GAIN);
|
||||
radio->setRxBoostedGainMode(rx_boost_gain);
|
||||
#endif
|
||||
}
|
||||
@@ -32,6 +32,11 @@ void setFlag(void) {
|
||||
}
|
||||
|
||||
void RadioLibWrapper::begin() {
|
||||
#ifdef USE_CC310_HW_CRYPTO
|
||||
// Initialize CryptoCell once from normal task context. The session helper
|
||||
// still initializes lazily if an earlier crypto operation runs first.
|
||||
(void) mesh::initializeCC310Crypto();
|
||||
#endif
|
||||
_radio->setPacketReceivedAction(setFlag); // this is also SentComplete interrupt
|
||||
_preamble_sf = getSpreadingFactor();
|
||||
_radio->setPreambleLength(preambleLengthForSF(_preamble_sf)); // longer preamble for lower SF improves reliability
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#define RX_PS_FALLBACK_SLEEP_US 60000UL
|
||||
|
||||
#ifdef USE_CC310_HW_CRYPTO
|
||||
#include <Adafruit_nRFCrypto.h>
|
||||
#include "../NRF52Crypto.h"
|
||||
#endif
|
||||
struct PacketMillis {
|
||||
uint32_t preambleMillis; // preamble-detect -> header-valid deadline
|
||||
@@ -217,15 +217,14 @@ public:
|
||||
RadioNoiseListener(PhysicalLayer& radio): _radio(&radio) { }
|
||||
|
||||
void random(uint8_t* dest, size_t sz) override {
|
||||
#ifdef USE_CC310_HW_CRYPTO
|
||||
// CC310 TRNG is higher quality and environment-independent vs radio RSSI noise.
|
||||
nRFCrypto.begin();
|
||||
nRFCrypto.Random.generate(dest, (uint16_t)sz);
|
||||
nRFCrypto.end();
|
||||
#else
|
||||
for (int i = 0; i < sz; i++) {
|
||||
// Preserve the existing radio/PRNG entropy on every platform. On nRF52840,
|
||||
// independently generated CC310 bytes are mixed in without becoming the
|
||||
// sole source of randomness.
|
||||
for (size_t i = 0; i < sz; i++) {
|
||||
dest[i] = _radio->randomByte() ^ (::random(0, 256) & 0xFF);
|
||||
}
|
||||
#ifdef USE_CC310_HW_CRYPTO
|
||||
mesh::mixCC310Random(dest, sz);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
@@ -5,7 +5,7 @@
|
||||
// Full receiver reset for all SX126x-family chips (SX1262, SX1268, LLCC68, STM32WLx).
|
||||
// Warm sleep powers down analog, Calibrate(0x7F) refreshes ADC/PLL/image calibration,
|
||||
// then re-applies RX settings that calibration may reset.
|
||||
inline void sx126xResetAGC(SX126x* radio) {
|
||||
inline void sx126xResetAGC(SX126x* radio, bool rx_boost_gain) {
|
||||
radio->sleep(true);
|
||||
radio->standby(RADIOLIB_SX126X_STANDBY_RC, true);
|
||||
|
||||
@@ -26,9 +26,7 @@ inline void sx126xResetAGC(SX126x* radio) {
|
||||
radio->setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
|
||||
#endif
|
||||
#ifdef SX126X_RX_BOOSTED_GAIN
|
||||
// Fallback for callers without a runtime override. RadioLibWrapper::resetAGC()
|
||||
// reapplies its cached radio.rxgain selection before receive mode resumes.
|
||||
radio->setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
|
||||
radio->setRxBoostedGainMode(rx_boost_gain);
|
||||
#endif
|
||||
#ifdef SX126X_REGISTER_PATCH
|
||||
uint8_t r_data = 0;
|
||||
|
||||
Reference in new issue
Block a user