mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-08-14 07:19:46 +00:00
feat: add more crypto
After soaking for a bit on the adverts without issue on multiple nodes, I added more hardware crypto. Supported nodes is unchanged in this PR addition, but if others can verify, they can easily be added. Some info on the CC310: https://docs.nordicsemi.com/r/bundle/ps_nrf9151/page/cryptocell.html **Added:** - AES-128 packet encryption/decryption now use hardware crypto - HMAC-SHA-256 authentication now uses hardware crypto - ACK hash computation and channel ID derivation now use hardware crypto - RNG (random number generator) now uses hardware crypto rather than radio noise + weak software RNG (which can have issues if there's no surrounding radio noise.) NIST SP 800-90B certified. - Runs hardware self-tests on startup - Runs continuous health tests during operation - Uses thermal noise/shot noise for randomness **Unchanged:** - calcSharedSecret remains software - it would be a split hw/sw solution and added complexity for likely not a lot of gains. This only happens when establishing a new contact, so not too frequent to be worth it. - ed25519_create_keypair remains software. This is only called when a node is first initialized. It does use the hardware RNG change, however, so better randomization. Tested on (so far): - Heltec t096 Build test on: - Heltec t096 companion ble - t1000e companion ble - RAK 4631 repeater - RAK 3401 companion BLE - Heltec v3 companion wifi
This commit is contained in:
+97
-1
@@ -2,6 +2,13 @@
|
||||
#include <AES.h>
|
||||
#include <SHA256.h>
|
||||
|
||||
#ifdef USE_CC310_ED25519
|
||||
#include <Adafruit_nRFCrypto.h>
|
||||
#include "nrf_cc310/include/crys_hash.h"
|
||||
#include "nrf_cc310/include/crys_hmac.h"
|
||||
#include "nrf_cc310/include/ssi_aes.h"
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
@@ -15,19 +22,58 @@ 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_ED25519
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
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_ED25519
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
int Utils::decrypt(const uint8_t* shared_secret, uint8_t* dest, const uint8_t* src, int src_len) {
|
||||
#ifdef USE_CC310_ED25519
|
||||
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;
|
||||
}
|
||||
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;
|
||||
@@ -39,9 +85,34 @@ int Utils::decrypt(const uint8_t* shared_secret, uint8_t* dest, const uint8_t* s
|
||||
}
|
||||
|
||||
return sp - src; // will always be multiple of 16
|
||||
#endif
|
||||
}
|
||||
|
||||
int Utils::encrypt(const uint8_t* shared_secret, uint8_t* dest, const uint8_t* src, int src_len) {
|
||||
#ifdef USE_CC310_ED25519
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -58,15 +129,27 @@ int Utils::encrypt(const uint8_t* shared_secret, uint8_t* dest, const uint8_t* s
|
||||
dp += 16;
|
||||
}
|
||||
return dp - dest; // will always be multiple of 16
|
||||
#endif
|
||||
}
|
||||
|
||||
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_ED25519
|
||||
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);
|
||||
#endif
|
||||
|
||||
return CIPHER_MAC_SIZE + enc_len;
|
||||
}
|
||||
@@ -75,12 +158,25 @@ int Utils::MACThenDecrypt(const uint8_t* shared_secret, uint8_t* dest, const uin
|
||||
if (src_len <= CIPHER_MAC_SIZE) return 0; // invalid src bytes
|
||||
|
||||
uint8_t hmac[CIPHER_MAC_SIZE];
|
||||
#ifdef USE_CC310_ED25519
|
||||
{
|
||||
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, src_len - CIPHER_MAC_SIZE);
|
||||
sha.finalizeHMAC(shared_secret, PUB_KEY_SIZE, hmac, CIPHER_MAC_SIZE);
|
||||
}
|
||||
#endif
|
||||
if (memcmp(hmac, src, CIPHER_MAC_SIZE) == 0) {
|
||||
return decrypt(shared_secret, dest, src + CIPHER_MAC_SIZE, src_len - CIPHER_MAC_SIZE);
|
||||
}
|
||||
@@ -150,4 +246,4 @@ int Utils::parseTextParts(char* text, const char* parts[], int max_num, char sep
|
||||
return num;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
#include <Mesh.h>
|
||||
#include <RadioLib.h>
|
||||
|
||||
#ifdef USE_CC310_ED25519
|
||||
#include <Adafruit_nRFCrypto.h>
|
||||
#endif
|
||||
|
||||
class RadioLibWrapper : public mesh::Radio {
|
||||
protected:
|
||||
PhysicalLayer* _radio;
|
||||
@@ -80,8 +84,15 @@ public:
|
||||
RadioNoiseListener(PhysicalLayer& radio): _radio(&radio) { }
|
||||
|
||||
void random(uint8_t* dest, size_t sz) override {
|
||||
#ifdef USE_CC310_ED25519
|
||||
// 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++) {
|
||||
dest[i] = _radio->randomByte() ^ (::random(0, 256) & 0xFF);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user