Files
RTNode-HeltecV4/lib/microReticulum/src/Cryptography/Fernet.cpp
James L 5ed70dcca9 v1.0.0: Boundary mode with bidirectional LoRa↔TCP transport
Vendor microReticulum library with boundary mode transport fixes:
- Two-whitelist system gates backbone traffic (local addresses +
  mentioned addresses from local devices)
- Allow control_hashes and local destinations through boundary filter
  (fixes backbone→LoRa path discovery)
- Fix get_cached_packet() to call unpack() instead of update_hash()
  (fixes empty destination_hash in path responses)
- LRPROOF Identity::recall null guard
- remaining_hops HEADER_1/BROADCAST fix for final-hop delivery
- PROOF packets excluded from boundary wrapping
- Iterator invalidation fix in transport table cleanup
- is_backbone flag replaces string matching for interface identification

Firmware changes:
- Set is_backbone(true) on backbone TCP interface
- Rename default TcpInterface name to BackboneInterface
- Update comments for dual-use TcpInterface (backbone + local AP)
- Use vendored lib/microReticulum instead of PlatformIO registry
2026-02-23 18:08:29 -05:00

116 lines
3.2 KiB
C++
Executable File

#include "Fernet.h"
#include "HMAC.h"
#include "PKCS7.h"
#include "AES.h"
#include "../Log.h"
#include <stdexcept>
#include <time.h>
using namespace RNS;
using namespace RNS::Cryptography;
Fernet::Fernet(const Bytes& key) {
if (!key) {
throw std::invalid_argument("Fernet key cannot be None");
}
if (key.size() != 32) {
throw std::invalid_argument("Fernet key must be 32 bytes, not " + std::to_string(key.size()));
}
//self._signing_key = key[:16]
_signing_key = key.left(16);
//self._encryption_key = key[16:]
_encryption_key = key.mid(16);
MEM("Fernet object created");
}
Fernet::~Fernet() {
MEM("Fernet object destroyed");
}
bool Fernet::verify_hmac(const Bytes& token) {
if (token.size() <= 32) {
throw std::invalid_argument("Cannot verify HMAC on token of only " + std::to_string(token.size()) + " bytes");
}
//received_hmac = token[-32:]
Bytes received_hmac = token.right(32);
DEBUG("Fernet::verify_hmac: received_hmac: " + received_hmac.toHex());
//expected_hmac = HMAC.new(self._signing_key, token[:-32]).digest()
Bytes expected_hmac = HMAC::generate(_signing_key, token.left(token.size()-32))->digest();
DEBUG("Fernet::verify_hmac: expected_hmac: " + expected_hmac.toHex());
return (received_hmac == expected_hmac);
}
const Bytes Fernet::encrypt(const Bytes& data) {
DEBUG("Fernet::encrypt: plaintext length: " + std::to_string(data.size()));
Bytes iv = random(16);
//double current_time = OS::time();
TRACE("Fernet::encrypt: iv: " + iv.toHex());
TRACE("Fernet::encrypt: plaintext: " + data.toHex());
Bytes ciphertext = AES_128_CBC::encrypt(
PKCS7::pad(data),
_encryption_key,
iv
);
DEBUG("Fernet::encrypt: padded ciphertext length: " + std::to_string(ciphertext.size()));
TRACE("Fernet::encrypt: ciphertext: " + ciphertext.toHex());
Bytes signed_parts = iv + ciphertext;
//return signed_parts + HMAC::generate(_signing_key, signed_parts)->digest();
Bytes sig(HMAC::generate(_signing_key, signed_parts)->digest());
TRACE("Fernet::encrypt: sig: " + sig.toHex());
Bytes token(signed_parts + sig);
DEBUG("Fernet::encrypt: token length: " + std::to_string(token.size()));
return token;
}
const Bytes Fernet::decrypt(const Bytes& token) {
DEBUG("Fernet::decrypt: token length: " + std::to_string(token.size()));
if (token.size() < 48) {
throw std::invalid_argument("Cannot decrypt token of only " + std::to_string(token.size()) + " bytes");
}
if (!verify_hmac(token)) {
throw std::invalid_argument("Fernet token HMAC was invalid");
}
//iv = token[:16]
Bytes iv = token.left(16);
TRACE("Fernet::decrypt: iv: " + iv.toHex());
//ciphertext = token[16:-32]
Bytes ciphertext = token.mid(16, token.size()-48);
TRACE("Fernet::decrypt: ciphertext: " + ciphertext.toHex());
try {
Bytes plaintext = PKCS7::unpad(
AES_128_CBC::decrypt(
ciphertext,
_encryption_key,
iv
)
);
DEBUG("Fernet::encrypt: unpadded plaintext length: " + std::to_string(plaintext.size()));
TRACE("Fernet::decrypt: plaintext: " + plaintext.toHex());
DEBUG("Fernet::decrypt: plaintext length: " + std::to_string(plaintext.size()));
return plaintext;
}
catch (std::exception& e) {
WARNING("Could not decrypt Fernet token");
throw std::runtime_error("Could not decrypt Fernet token");
}
}