WIP update

Implemented X25519.
This commit is contained in:
attermann 2023-10-07 15:03:21 -06:00
parent 1b919a9489
commit 4b062aa485
22 changed files with 490 additions and 165 deletions

View file

@ -39,27 +39,6 @@ int8_t Bytes::compare(const Bytes &bytes) const {
} }
} }
char const hex_upper_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
char const hex_lower_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
std::string Bytes::toHex(bool upper /*= true*/) const {
if (!_data) {
return "";
}
std::string hex;
for (uint8_t byte : *_data) {
if (upper) {
hex += hex_upper_chars[ (byte & 0xF0) >> 4];
hex += hex_upper_chars[ (byte & 0x0F) >> 0];
}
else {
hex += hex_lower_chars[ (byte & 0xF0) >> 4];
hex += hex_lower_chars[ (byte & 0x0F) >> 0];
}
}
return hex;
}
void Bytes::assignHex(const char* hex) { void Bytes::assignHex(const char* hex) {
// if assignment is empty then clear data and don't bother creating new // if assignment is empty then clear data and don't bother creating new
if (hex == nullptr || hex[0] == 0) { if (hex == nullptr || hex[0] == 0) {
@ -86,3 +65,34 @@ void Bytes::appendHex(const char* hex) {
_data->push_back(byte); _data->push_back(byte);
} }
} }
char const hex_upper_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
char const hex_lower_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
std::string Bytes::toHex(bool upper /*= true*/) const {
if (!_data) {
return "";
}
std::string hex;
for (uint8_t byte : *_data) {
if (upper) {
hex += hex_upper_chars[ (byte & 0xF0) >> 4];
hex += hex_upper_chars[ (byte & 0x0F) >> 0];
}
else {
hex += hex_lower_chars[ (byte & 0xF0) >> 4];
hex += hex_lower_chars[ (byte & 0x0F) >> 0];
}
}
return hex;
}
Bytes Bytes::mid(size_t pos, size_t len) const {
if (!_data || pos >= size()) {
return NONE;
}
if ((pos + len) >= size()) {
len = (size() - pos);
}
return {data() + pos, len};
}

View file

@ -12,6 +12,8 @@
namespace RNS { namespace RNS {
#define COW
class Bytes { class Bytes {
private: private:
@ -34,8 +36,7 @@ namespace RNS {
} }
Bytes(const Bytes &bytes) { Bytes(const Bytes &bytes) {
//extreme("Bytes is using shared data"); //extreme("Bytes is using shared data");
_data = bytes.shareData(); assign(bytes);
_owner = false;
//extreme("Bytes object copy created from bytes \"" + toString() + "\", this: " + std::to_string((ulong)this) + ", data: " + std::to_string((ulong)_data.get())); //extreme("Bytes object copy created from bytes \"" + toString() + "\", this: " + std::to_string((ulong)this) + ", data: " + std::to_string((ulong)_data.get()));
} }
Bytes(const uint8_t *chunk, size_t size) { Bytes(const uint8_t *chunk, size_t size) {
@ -103,21 +104,11 @@ namespace RNS {
void ownData(); void ownData();
public: public:
int8_t compare(const Bytes &bytes) const;
inline size_t size() const { if (!_data) return 0; return _data->size(); }
inline bool empty() const { if (!_data) return true; return _data->empty(); }
inline size_t capacity() const { if (!_data) return 0; return _data->capacity(); }
inline const uint8_t *data() const { if (!_data) return nullptr; return _data->data(); }
inline std::string toString() const { if (!_data) return ""; return {(const char*)data(), size()}; }
std::string toHex(bool upper = true) const;
inline uint8_t *writable(size_t size) {
newData(size);
return _data->data();
}
inline void assign(const Bytes& bytes) { inline void assign(const Bytes& bytes) {
#ifdef COW
_data = bytes.shareData();
_owner = false;
#else
// if assignment is empty then clear data and don't bother creating new // if assignment is empty then clear data and don't bother creating new
if (bytes.size() <= 0) { if (bytes.size() <= 0) {
_data = nullptr; _data = nullptr;
@ -125,6 +116,7 @@ namespace RNS {
} }
newData(); newData();
_data->insert(_data->begin(), bytes._data->begin(), bytes._data->end()); _data->insert(_data->begin(), bytes._data->begin(), bytes._data->end());
#endif
} }
inline void assign(const uint8_t *chunk, size_t size) { inline void assign(const uint8_t *chunk, size_t size) {
// if assignment is empty then clear data and don't bother creating new // if assignment is empty then clear data and don't bother creating new
@ -178,6 +170,24 @@ namespace RNS {
} }
void appendHex(const char* hex); void appendHex(const char* hex);
public:
int8_t compare(const Bytes &bytes) const;
inline size_t size() const { if (!_data) return 0; return _data->size(); }
inline bool empty() const { if (!_data) return true; return _data->empty(); }
inline size_t capacity() const { if (!_data) return 0; return _data->capacity(); }
inline const uint8_t *data() const { if (!_data) return nullptr; return _data->data(); }
inline std::string toString() const { if (!_data) return ""; return {(const char*)data(), size()}; }
std::string toHex(bool upper = true) const;
Bytes mid(size_t pos, size_t len) const;
inline Bytes left(size_t len) const { if (!_data) return NONE; if (len > size()) len = size(); return {data(), len}; }
inline Bytes right(size_t len) const { if (!_data) return NONE; if (len > size()) len = size(); return {data() + (size() - len), len}; }
inline uint8_t *writable(size_t size) {
newData(size);
return _data->data();
}
private: private:
SharedData _data; SharedData _data;
mutable bool _owner = true; mutable bool _owner = true;

View file

@ -55,6 +55,7 @@ namespace RNS { namespace Cryptography {
// create random private key // create random private key
Ed25519::generatePrivateKey(_privateKey.writable(32)); Ed25519::generatePrivateKey(_privateKey.writable(32));
} }
// derive public key from private key
Ed25519::derivePublicKey(_publicKey.writable(32), _privateKey.data()); Ed25519::derivePublicKey(_publicKey.writable(32), _privateKey.data());
} }
~Ed25519PrivateKey() {} ~Ed25519PrivateKey() {}

View file

@ -1,11 +1,12 @@
#include "Hashes.h" #include "Hashes.h"
#include "../Log.h" #include "../Log.h"
#include "../Bytes.h"
#include <SHA256.h> #include <SHA256.h>
#include <SHA512.h> #include <SHA512.h>
using namespace RNS::Cryptography; using namespace RNS;
/* /*
The SHA primitives are abstracted here to allow platform- The SHA primitives are abstracted here to allow platform-
@ -14,18 +15,23 @@ uses Python's internal SHA-256 implementation. All SHA-256
calls in RNS end up here. calls in RNS end up here.
*/ */
void RNS::Cryptography::sha256(uint8_t *hash, const uint8_t *data, uint16_t data_len) { Bytes RNS::Cryptography::sha256(const Bytes &data) {
//extreme("Cryptography::sha256: data: " + data.toHex() ); //extreme("Cryptography::sha256: data: " + data.toHex() );
SHA256 digest; SHA256 digest;
digest.reset(); digest.reset();
digest.update(data, data_len); digest.update(data.data(), data.size());
digest.finalize(hash, 32); Bytes hash;
digest.finalize(hash.writable(32), 32);
//extreme("Cryptography::sha256: hash: " + hash.toHex() ); //extreme("Cryptography::sha256: hash: " + hash.toHex() );
return hash;
} }
void RNS::Cryptography::sha512(uint8_t *hash, const uint8_t *data, uint16_t data_len) { Bytes RNS::Cryptography::sha512(const Bytes &data) {
SHA512 digest; SHA512 digest;
digest.reset(); digest.reset();
digest.update(data, data_len); digest.update(data.data(), data.size());
digest.finalize(hash, 64); Bytes hash;
digest.finalize(hash.writable(64), 64);
//extreme("Cryptography::sha512: hash: " + hash.toHex() );
return hash;
} }

View file

@ -1,10 +1,12 @@
#pragma once #pragma once
#include "../Bytes.h"
#include <stdint.h> #include <stdint.h>
namespace RNS { namespace Cryptography { namespace RNS { namespace Cryptography {
void sha256(uint8_t *hash, const uint8_t *data, uint16_t data_len); Bytes sha256(const Bytes &data);
void sha512(uint8_t *hash, const uint8_t *data, uint16_t data_len); Bytes sha512(const Bytes &data);
} } } }

View file

@ -2,6 +2,8 @@
#include "Bytes.h" #include "Bytes.h"
#include <Curve25519.h>
#include <memory> #include <memory>
#include <stdint.h> #include <stdint.h>
@ -10,29 +12,41 @@ namespace RNS { namespace Cryptography {
class X25519PublicKey { class X25519PublicKey {
public: public:
/*
X25519PublicKey(const Bytes &x) { X25519PublicKey(const Bytes &x) {
_x = x; _x = x;
} }
*/
X25519PublicKey(const Bytes &publicKey) {
_publicKey = publicKey;
}
~X25519PublicKey() {} ~X25519PublicKey() {}
using Ptr = std::shared_ptr<X25519PublicKey>; using Ptr = std::shared_ptr<X25519PublicKey>;
public: public:
// creates a new instance with specified seed // creates a new instance with specified seed
/*
static inline Ptr from_public_bytes(const Bytes &data) { static inline Ptr from_public_bytes(const Bytes &data) {
//return Ptr(new X25519PublicKey(_unpack_number(data))); return Ptr(new X25519PublicKey(_unpack_number(data)));
// MOCK }
return Ptr(new X25519PublicKey(nullptr)); */
static inline Ptr from_public_bytes(const Bytes &publicKey) {
return Ptr(new X25519PublicKey(publicKey));
} }
/*
Bytes public_bytes() { Bytes public_bytes() {
//return _pack_number(_x); return _pack_number(_x);
// MOCK }
return nullptr; */
Bytes public_bytes() {
return _publicKey;
} }
private: private:
Bytes _x; //Bytes _x;
Bytes _publicKey;
}; };
@ -47,43 +61,74 @@ namespace RNS { namespace Cryptography {
const uint8_t T_MAX = 0; const uint8_t T_MAX = 0;
public: public:
/*
X25519PrivateKey(const Bytes &a) { X25519PrivateKey(const Bytes &a) {
_a = a; _a = a;
} }
*/
X25519PrivateKey(const Bytes &privateKey) {
if (privateKey) {
// use specified private key
_privateKey = privateKey;
// similar to derive public key from private key
// second param "f" is secret
//eval(uint8_t result[32], const uint8_t s[32], const uint8_t x[32])
// derive public key from private key
Curve25519::eval(_publicKey.writable(32), _privateKey.data(), 0);
}
else {
// create random private key and derive public key
// second param "f" is secret
//dh1(uint8_t k[32], uint8_t f[32])
Curve25519::dh1(_publicKey.writable(32), _privateKey.writable(32));
}
}
~X25519PrivateKey() {} ~X25519PrivateKey() {}
using Ptr = std::shared_ptr<X25519PrivateKey>; using Ptr = std::shared_ptr<X25519PrivateKey>;
public: public:
// creates a new instance with a random seed // creates a new instance with a random seed
/*
static inline Ptr generate() { static inline Ptr generate() {
//return from_private_bytes(os.urandom(32)); return from_private_bytes(os.urandom(32));
// MOCK }
return from_private_bytes(nullptr); */
static inline Ptr generate() {
return from_private_bytes(Bytes::NONE);
} }
// creates a new instance with specified seed // creates a new instance with specified seed
/*
static inline Ptr from_private_bytes(const Bytes &data) { static inline Ptr from_private_bytes(const Bytes &data) {
//return Ptr(new X25519PrivateKey(_fix_secret(_unpack_number(data)))); return Ptr(new X25519PrivateKey(_fix_secret(_unpack_number(data))));
// MOCK }
return Ptr(new X25519PrivateKey(nullptr)); */
static inline Ptr from_private_bytes(const Bytes &privateKey) {
return Ptr(new X25519PrivateKey(privateKey));
} }
/*
inline Bytes private_bytes() { inline Bytes private_bytes() {
//return _pack_number(_a); return _pack_number(_a);
// MOCK }
return nullptr; */
inline Bytes private_bytes() {
return _privateKey;
} }
// creates a new instance of public key for this private key // creates a new instance of public key for this private key
/*
inline X25519PublicKey::Ptr public_key() { inline X25519PublicKey::Ptr public_key() {
//return X25519PublicKey::from_public_bytes(_pack_number(_raw_curve25519(9, _a))); return X25519PublicKey::from_public_bytes(_pack_number(_raw_curve25519(9, _a)));
// MOCK }
return X25519PublicKey::from_public_bytes(nullptr); */
inline X25519PublicKey::Ptr public_key() {
return X25519PublicKey::from_public_bytes(_publicKey);
} }
inline Bytes exchange(const Bytes &peer_public_key) {
/* /*
inline Bytes exchange(const Bytes &peer_public_key) {
if isinstance(peer_public_key, bytes): if isinstance(peer_public_key, bytes):
peer_public_key = X25519PublicKey.from_public_bytes(peer_public_key) peer_public_key = X25519PublicKey.from_public_bytes(peer_public_key)
@ -119,12 +164,18 @@ namespace RNS { namespace Cryptography {
X25519PrivateKey.T_MAX = duration X25519PrivateKey.T_MAX = duration
return shared return shared
}
*/ */
return nullptr; inline Bytes exchange(const Bytes &peer_public_key) {
Bytes sharedKey(peer_public_key);
Curve25519::dh2(sharedKey.writable(32), _privateKey.writable(32));
return sharedKey;
} }
private: private:
Bytes _a; //Bytes _a;
Bytes _privateKey;
Bytes _publicKey;
}; };

View file

@ -272,15 +272,15 @@ Bytes Destination::encrypt(const Bytes &data) {
assert(_object); assert(_object);
debug("Destination::encrypt: encrypting bytes"); debug("Destination::encrypt: encrypting bytes");
/*
if (_object->_type == Destination::PLAIN) { if (_object->_type == Destination::PLAIN) {
return data; return data;
} }
if (_object->_type == Destination::SINGLE && _object->_identity) { if (_object->_type == Destination::SINGLE && _object->_identity) {
return _object->_identity.encrypt(data) return _object->_identity.encrypt(data);
} }
/*
if (_object->_type == Destination::GROUP { if (_object->_type == Destination::GROUP {
if hasattr(self, "prv") and self.prv != None: if hasattr(self, "prv") and self.prv != None:
try: try:
@ -292,9 +292,8 @@ Bytes Destination::encrypt(const Bytes &data) {
raise ValueError("No private key held by GROUP destination. Did you create or load one?") raise ValueError("No private key held by GROUP destination. Did you create or load one?")
} }
*/ */
// MOCK // MOCK
return data; return Bytes::NONE;
} }
/* /*
@ -307,15 +306,15 @@ Bytes Destination::decrypt(const Bytes &data) {
assert(_object); assert(_object);
debug("Destination::decrypt: decrypting bytes"); debug("Destination::decrypt: decrypting bytes");
/*
if (_object->_type == Destination::PLAIN) { if (_object->_type == Destination::PLAIN) {
return data; return data;
} }
if (_object->_type == Destination::SINGLE && _object->_identity) { if (_object->_type == Destination::SINGLE && _object->_identity) {
return identity.decrypt(data); return _object->_identity.decrypt(data);
} }
/*
if (_object->_type == Destination::GROUP) { if (_object->_type == Destination::GROUP) {
if hasattr(self, "prv") and self.prv != None: if hasattr(self, "prv") and self.prv != None:
try: try:
@ -327,9 +326,8 @@ Bytes Destination::decrypt(const Bytes &data) {
raise ValueError("No private key held by GROUP destination. Did you create or load one?") raise ValueError("No private key held by GROUP destination. Did you create or load one?")
} }
*/ */
// MOCK // MOCK
return data; return Bytes::NONE;
} }
/* /*
@ -343,5 +341,5 @@ Bytes Destination::sign(const Bytes &message) {
if (_object->_type == Destination::SINGLE && _object->_identity) { if (_object->_type == Destination::SINGLE && _object->_identity) {
return _object->_identity.sign(message); return _object->_identity.sign(message);
} }
return nullptr; return Bytes::NONE;
} }

View file

@ -1,7 +1,10 @@
#include "Identity.h" #include "Identity.h"
#include "Reticulum.h"
#include "Packet.h"
#include "Log.h" #include "Log.h"
#include "Cryptography/Hashes.h" #include "Cryptography/Hashes.h"
#include "Cryptography/X25519.h"
#include <string.h> #include <string.h>
@ -45,8 +48,6 @@ void Identity::createKeys() {
Bytes Identity::get_public_key() { Bytes Identity::get_public_key() {
assert(_object); assert(_object);
return _object->_pub_bytes + _object->_sig_pub_bytes; return _object->_pub_bytes + _object->_sig_pub_bytes;
// MOCK
return "abc123";
} }
void Identity::update_hashes() { void Identity::update_hashes() {
@ -57,6 +58,112 @@ void Identity::update_hashes() {
debug("Identity::update_hashes: hexhash: " + _object->_hexhash); debug("Identity::update_hashes: hexhash: " + _object->_hexhash);
}; };
/*
Get a SHA-256 hash of passed data.
:param data: Data to be hashed as *bytes*.
:returns: SHA-256 hash as *bytes*
*/
/*static*/ Bytes Identity::full_hash(const Bytes &data) {
return Cryptography::sha256(data);
}
/*
Get a truncated SHA-256 hash of passed data.
:param data: Data to be hashed as *bytes*.
:returns: Truncated SHA-256 hash as *bytes*
*/
/*static*/ Bytes Identity::truncated_hash(const Bytes &data) {
return full_hash(data).right(TRUNCATED_HASHLENGTH/8);
}
/*
Encrypts information for the identity.
:param plaintext: The plaintext to be encrypted as *bytes*.
:returns: Ciphertext token as *bytes*.
:raises: *KeyError* if the instance does not hold a public key.
*/
Bytes Identity::encrypt(const Bytes &plaintext) {
assert(_object);
if (_object->_pub) {
Cryptography::X25519PrivateKey::Ptr ephemeral_key = Cryptography::X25519PrivateKey::generate();
Bytes ephemeral_pub_bytes = ephemeral_key->public_key()->public_bytes();
/*
Bytes shared_key = ephemeral_key->exchange(_object->_pub);
Bytes derived_key = RNS.Cryptography.hkdf(
length=32,
derive_from=shared_key,
salt=get_salt(),
context=get_context(),
)
fernet = Fernet(derived_key)
ciphertext = fernet.encrypt(plaintext)
return ephemeral_pub_bytes + ciphertext;
*/
// MOCK
return Bytes::NONE;
}
else {
throw std::runtime_error("Encryption failed because identity does not hold a public key");
}
}
/*
Decrypts information for the identity.
:param ciphertext: The ciphertext to be decrypted as *bytes*.
:returns: Plaintext as *bytes*, or *None* if decryption fails.
:raises: *KeyError* if the instance does not hold a private key.
*/
Bytes Identity::decrypt(const Bytes &ciphertext_token) {
assert(_object);
if (_object->_prv) {
if (ciphertext_token.size() > Identity::KEYSIZE/8/2) {
Bytes plaintext;
try {
Bytes peer_pub_bytes = ciphertext_token.right(Identity::KEYSIZE/8/2);
Cryptography::X25519PublicKey::Ptr peer_pub = Cryptography::X25519PublicKey::from_public_bytes(peer_pub_bytes);
/*
Bytes shared_key = _object->_prv->exchange(peer_pub);
Bytes derived_key = RNS.Cryptography.hkdf(
length=32,
derive_from=shared_key,
salt=get_salt(),
context=get_context(),
)
fernet = Fernet(derived_key)
ciphertext = ciphertext_token[Identity.KEYSIZE//8//2:]
plaintext = fernet.decrypt(ciphertext)
*/
}
catch (std::exception &e) {
debug("Decryption by " + _object->_hash.toHex() + " failed: " + e.what());
}
return plaintext;
}
else {
debug("Decryption failed because the token size was invalid.");
return Bytes::NONE;
}
}
else {
throw std::runtime_error("Decryption failed because identity does not hold a private key");
}
}
/* /*
Signs information by the identity. Signs information by the identity.
@ -70,7 +177,7 @@ Bytes Identity::sign(const Bytes &message) {
try { try {
return _object->_sig_prv->sign(message); return _object->_sig_prv->sign(message);
} }
catch (std::exception e) { catch (std::exception &e) {
error("The identity " + toString() + " could not sign the requested message. The contained exception was: " + e.what()); error("The identity " + toString() + " could not sign the requested message. The contained exception was: " + e.what());
throw e; throw e;
} }
@ -80,29 +187,45 @@ Bytes Identity::sign(const Bytes &message) {
} }
} }
/* /*
Get a SHA-256 hash of passed data. Validates the signature of a signed message.
:param data: Data to be hashed as *bytes*. :param signature: The signature to be validated as *bytes*.
:returns: SHA-256 hash as *bytes* :param message: The message to be validated as *bytes*.
:returns: True if the signature is valid, otherwise False.
:raises: *KeyError* if the instance does not hold a public key.
*/ */
/*static*/ Bytes Identity::full_hash(const Bytes &data) { bool Identity::validate(const Bytes &signature, const Bytes &message) {
Bytes hash; assert(_object);
Cryptography::sha256(hash.writable(HASHLENGTH/8), data.data(), data.size()); if (_object->_pub) {
//debug("Identity::full_hash: hash: " + hash.toHex()); try {
return hash; _object->_sig_pub->verify(signature, message);
return true;
}
catch (std::exception &e) {
return false;
}
}
else {
throw std::runtime_error("Signature validation failed because identity does not hold a public key");
}
} }
/* void Identity::prove(const Packet &packet, const Destination &destination /*= Destination::NONE*/) {
Get a truncated SHA-256 hash of passed data. assert(_object);
Bytes signature(sign(packet._packet_hash));
:param data: Data to be hashed as *bytes*. Bytes proof_data;
:returns: Truncated SHA-256 hash as *bytes* if (RNS::Reticulum::should_use_implicit_proof()) {
*/ proof_data = signature;
/*static*/ Bytes Identity::truncated_hash(const Bytes &data) { }
Bytes hash = full_hash(data); else {
//Bytes truncated_hash(hash.data() + (TRUNCATED_HASHLENGTH/8), TRUNCATED_HASHLENGTH/8); proof_data = packet._packet_hash + signature;
//debug("Identity::truncated_hash: truncated hash: " + truncated_hash.toHex()); }
return Bytes(hash.data() + (TRUNCATED_HASHLENGTH/8), TRUNCATED_HASHLENGTH/8);
//zif (!destination) {
//z destination = packet.generate_proof_destination();
//z}
Packet proof(destination, packet.receiving_interface(), proof_data, RNS::Packet::PROOF);
proof.send();
} }

View file

@ -1,6 +1,8 @@
#pragma once #pragma once
#include "Reticulum.h" #include "Reticulum.h"
// CBA TODO determine why including Destination.h here causes build errors
//#include "Destination.h"
#include "Log.h" #include "Log.h"
#include "Bytes.h" #include "Bytes.h"
#include "Cryptography/Fernet.h" #include "Cryptography/Fernet.h"
@ -13,6 +15,9 @@
namespace RNS { namespace RNS {
class Destination;
class Packet;
class Identity { class Identity {
public: public:
@ -66,8 +71,15 @@ namespace RNS {
static Bytes full_hash(const Bytes &data); static Bytes full_hash(const Bytes &data);
static Bytes truncated_hash(const Bytes &data); static Bytes truncated_hash(const Bytes &data);
Bytes sign(const Bytes &message);
Bytes encrypt(const Bytes &plaintext);
Bytes decrypt(const Bytes &ciphertext_token);
Bytes sign(const Bytes &message);
bool validate(const Bytes &signature, const Bytes &message);
//void prove(const Packet &packet, const Destination &destination = Destination::NONE);
void prove(const Packet &packet, const Destination &destination);
// getters/setters
inline Bytes encryptionPrivateKey() const { assert(_object); return _object->_prv_bytes; } inline Bytes encryptionPrivateKey() const { assert(_object); return _object->_prv_bytes; }
inline Bytes signingPrivateKey() const { assert(_object); return _object->_sig_prv_bytes; } inline Bytes signingPrivateKey() const { assert(_object); return _object->_sig_prv_bytes; }
inline Bytes encryptionPublicKey() const { assert(_object); return _object->_prv_bytes; } inline Bytes encryptionPublicKey() const { assert(_object); return _object->_prv_bytes; }

View file

@ -5,10 +5,10 @@
using namespace RNS; using namespace RNS;
Interface::Interface() { Interface::Interface() {
log("Interface object created", LOG_EXTREME); extreme("Interface object created");
} }
Interface::~Interface() { Interface::~Interface() {
log("Interface object destroyed", LOG_EXTREME); extreme("Interface object destroyed");
} }

View file

@ -1,11 +1,18 @@
#pragma once #pragma once
//#include <Arduino.h> #include "../Log.h"
#include <memory>
namespace RNS { namespace RNS {
class Interface { class Interface {
public:
enum NoneConstructor {
NONE
};
public: public:
// Interface mode definitions // Interface mode definitions
enum modes { enum modes {
@ -22,9 +29,33 @@ namespace RNS {
//zDISCOVER_PATHS_FOR = [MODE_ACCESS_POINT, MODE_GATEWAY] //zDISCOVER_PATHS_FOR = [MODE_ACCESS_POINT, MODE_GATEWAY]
public: public:
Interface(NoneConstructor none) {
extreme("Interface object NONE created");
}
Interface(const Interface &interface) : _object(interface._object) {
extreme("Interface object copy created");
}
Interface(); Interface();
~Interface(); ~Interface();
inline Interface& operator = (const Interface &interface) {
_object = interface._object;
extreme("Interface object copy created by assignment, this: " + std::to_string((ulong)this) + ", data: " + std::to_string((uint32_t)_object.get()));
return *this;
}
inline operator bool() const {
return _object.get() != nullptr;
}
private:
class Object {
private:
friend class Interface;
};
std::shared_ptr<Object> _object;
}; };
} }

View file

@ -8,8 +8,8 @@
using namespace RNS; using namespace RNS;
Packet::Packet(const Destination &destination, const Bytes &data, types packet_type, context_types context, Transport::types transport_type, header_types header_type, const uint8_t *transport_id, Interface *attached_interface, bool create_receipt) : _object(new Object(destination)) { //Packet::Packet(const Destination &destination, const Bytes &data, types packet_type, context_types context, Transport::types transport_type, header_types header_type, const uint8_t *transport_id, Interface *attached_interface, bool create_receipt) : _object(new Object(destination)) {
assert(_object); Packet::Packet(const Destination &destination, const Interface &attached_interface, const Bytes &data, types packet_type /*= DATA*/, context_types context /*= CONTEXT_NONE*/, Transport::types transport_type /*= Transport::BROADCAST*/, header_types header_type /*= HEADER_1*/, const uint8_t *transport_id /*= nullptr*/, bool create_receipt /*= true*/) : _object(new Object(destination, attached_interface)) {
if (_object->_destination) { if (_object->_destination) {
// CBA TODO handle NONE // CBA TODO handle NONE
@ -52,7 +52,6 @@ Packet::Packet(const Destination &destination, const Bytes &data, types packet_t
_fromPacked = true; _fromPacked = true;
_create_receipt = false; _create_receipt = false;
} }
_attached_interface = attached_interface;
extreme("Packet object created"); extreme("Packet object created");
} }
@ -427,8 +426,8 @@ bool Packet::unpack() {
_packed = false; _packed = false;
update_hash(); update_hash();
} }
catch (std::exception& ex) { catch (std::exception& e) {
log(std::string("Received malformed packet, dropping it. The contained exception was: ") + ex.what(), LOG_EXTREME); error(std::string("Received malformed packet, dropping it. The contained exception was: ") + e.what());
return false; return false;
} }
@ -530,3 +529,10 @@ Bytes Packet::get_hashable_part() {
hashable_part.append(_data-Reticulum::DESTINATION_LENGTH-1, _data_len+Reticulum::DESTINATION_LENGTH+1); hashable_part.append(_data-Reticulum::DESTINATION_LENGTH-1, _data_len+Reticulum::DESTINATION_LENGTH+1);
return hashable_part; return hashable_part;
} }
// Generates a special destination that allows Reticulum
// to direct the proof back to the proved packet's sender
//ProofDestination &Packet::generate_proof_destination() {
// return ProofDestination();
//}

View file

@ -14,6 +14,7 @@ namespace RNS {
class Packet; class Packet;
class PacketProof; class PacketProof;
class ProofDestination;
class PacketReceipt; class PacketReceipt;
class PacketReceiptCallbacks; class PacketReceiptCallbacks;
@ -84,7 +85,9 @@ namespace RNS {
uint8_t EMPTY_DESTINATION[Reticulum::DESTINATION_LENGTH] = {0}; uint8_t EMPTY_DESTINATION[Reticulum::DESTINATION_LENGTH] = {0};
public: public:
Packet(const Destination &destination, const Bytes &data, types packet_type = DATA, context_types context = CONTEXT_NONE, Transport::types transport_type = Transport::BROADCAST, header_types header_type = HEADER_1, const uint8_t *transport_id = nullptr, Interface *attached_interface = nullptr, bool create_receipt = true); Packet(const Destination &destination, const Interface &attached_interface, const Bytes &data, types packet_type = DATA, context_types context = CONTEXT_NONE, Transport::types transport_type = Transport::BROADCAST, header_types header_type = HEADER_1, const uint8_t *transport_id = nullptr, bool create_receipt = true);
Packet(const Destination &destination, const Bytes &data, types packet_type = DATA, context_types context = CONTEXT_NONE, Transport::types transport_type = Transport::BROADCAST, header_types header_type = HEADER_1, const uint8_t *transport_id = nullptr, bool create_receipt = true) : Packet(destination, Interface::NONE, data, DATA, CONTEXT_NONE, Transport::BROADCAST, HEADER_1, nullptr, create_receipt) {
}
Packet(NoneConstructor none) { Packet(NoneConstructor none) {
extreme("Packet NONE object created"); extreme("Packet NONE object created");
} }
@ -110,16 +113,6 @@ namespace RNS {
void setData(const uint8_t* rata, uint16_t len); void setData(const uint8_t* rata, uint16_t len);
*/ */
private:
class Object {
public:
Object(const Destination &destination) : _destination(destination) {}
private:
Destination _destination;
friend class Packet;
};
std::shared_ptr<Object> _object;
public: public:
uint8_t get_packed_flags(); uint8_t get_packed_flags();
void pack(); void pack();
@ -130,8 +123,12 @@ namespace RNS {
Bytes get_hash(); Bytes get_hash();
Bytes getTruncatedHash(); Bytes getTruncatedHash();
Bytes get_hashable_part(); Bytes get_hashable_part();
//zProofDestination &generate_proof_destination();
private: // getters/setters
inline const Interface& receiving_interface() const { assert(_object); return _object->_receiving_interface; }
public:
types _packet_type; types _packet_type;
header_types _header_type; header_types _header_type;
context_types _context; context_types _context;
@ -151,9 +148,6 @@ namespace RNS {
uint16_t _mtu = Reticulum::MTU; uint16_t _mtu = Reticulum::MTU;
time_t _sent_at = 0; time_t _sent_at = 0;
Interface *_attached_interface = nullptr;
Interface *_receiving_interface = nullptr;
float _rssi = 0.0; float _rssi = 0.0;
float _snr = 0.0; float _snr = 0.0;
@ -166,6 +160,21 @@ namespace RNS {
uint8_t _header[Reticulum::HEADER_MAXSIZE]; uint8_t _header[Reticulum::HEADER_MAXSIZE];
uint8_t *_data = _raw + Reticulum::HEADER_MAXSIZE; uint8_t *_data = _raw + Reticulum::HEADER_MAXSIZE;
uint16_t _data_len = 0; uint16_t _data_len = 0;
private:
class Object {
public:
Object(const Destination &destination, const Interface &attached_interface) : _destination(destination), _attached_interface(attached_interface) {}
private:
Destination _destination;
Interface _attached_interface;
Interface _receiving_interface;
friend class Packet;
};
std::shared_ptr<Object> _object;
}; };

View file

@ -18,6 +18,15 @@ Reticulum::~Reticulum() {
extreme("Reticulum object destroyed"); extreme("Reticulum object destroyed");
} }
/*
Returns whether proofs sent are explicit or implicit.
:returns: True if the current running configuration specifies to use implicit proofs. False if not.
*/
/*static*/ bool Reticulum::should_use_implicit_proof() {
return __use_implicit_proof;
}
void Reticulum::loop() { void Reticulum::loop() {
// Perform random number gnerator housekeeping // Perform random number gnerator housekeeping
RNG.loop(); RNG.loop();

View file

@ -10,12 +10,6 @@ namespace RNS {
class Reticulum { class Reticulum {
private:
class Object {
private:
friend class Reticulum;
};
public: public:
enum NoneConstructor { enum NoneConstructor {
NONE NONE
@ -85,6 +79,12 @@ namespace RNS {
static const uint8_t DESTINATION_LENGTH = TRUNCATED_HASHLENGTH/8; // In bytes static const uint8_t DESTINATION_LENGTH = TRUNCATED_HASHLENGTH/8; // In bytes
static const bool __transport_enabled = false;
static const bool __use_implicit_proof = true;
static const bool __allow_probes = false;
static const bool panic_on_interface_error = false;
public: public:
Reticulum(); Reticulum();
Reticulum(NoneConstructor none) { Reticulum(NoneConstructor none) {
@ -105,9 +105,14 @@ namespace RNS {
} }
public: public:
static bool should_use_implicit_proof();
void loop(); void loop();
private: private:
class Object {
private:
friend class Reticulum;
};
std::shared_ptr<Object> _object; std::shared_ptr<Object> _object;
}; };

View file

@ -10,7 +10,6 @@ void test() {
testMap(); testMap();
testBytes(); testBytes();
testCowBytes(); testCowBytes();
testObjects();
testBytesConversion(); testBytesConversion();
testReference(); testReference();

View file

@ -6,8 +6,6 @@ void testBytes();
void testCowBytes(); void testCowBytes();
void testBytesConversion(); void testBytesConversion();
void testObjects();
void testReference(); void testReference();
void testCrypto(); void testCrypto();

View file

@ -105,6 +105,56 @@ void testBytes() {
assert(bytes.size() == 11); assert(bytes.size() == 11);
assert(memcmp(bytes.data(), "Hello World", bytes.size()) == 0); assert(memcmp(bytes.data(), "Hello World", bytes.size()) == 0);
// test left in range
{
RNS::Bytes left(bytes.left(5));
RNS::extreme("left: " + left.toString());
assert(left.size() == 5);
assert(memcmp(left.data(), "Hello", left.size()) == 0);
}
// test left oob
{
RNS::Bytes left(bytes.left(20));
RNS::extreme("oob left: " + left.toString());
assert(left.size() == 11);
assert(memcmp(left.data(), "Hello World", left.size()) == 0);
}
// test right in range
{
RNS::Bytes right(bytes.right(5));
RNS::extreme("right: " + right.toString());
assert(right.size() == 5);
assert(memcmp(right.data(), "World", right.size()) == 0);
}
// test right oob
{
RNS::Bytes right(bytes.right(20));
RNS::extreme("oob right: " + right.toString());
assert(right.size() == 11);
assert(memcmp(right.data(), "Hello World", right.size()) == 0);
}
// test mid in range
{
RNS::Bytes mid(bytes.mid(3, 5));
RNS::extreme("mid: " + mid.toString());
assert(mid.size() == 5);
assert(memcmp(mid.data(), "lo Wo", mid.size()) == 0);
}
// test mid oob pos
{
RNS::Bytes mid(bytes.mid(20, 5));
RNS::extreme("oob pos mid: " + mid.toString());
assert(!mid);
assert(mid.size() == 0);
}
// test mid oob pos
{
RNS::Bytes mid(bytes.mid(3, 20));
RNS::extreme("oob len mid: " + mid.toString());
assert(mid.size() == 8);
assert(memcmp(mid.data(), "lo World", mid.size()) == 0);
}
// stream into empty bytes // stream into empty bytes
{ {
RNS::Bytes strmbuf; RNS::Bytes strmbuf;

View file

@ -25,7 +25,7 @@ void testCrypto() {
int main(void) int main(void)
{ {
UNITY_BEGIN(); UNITY_BEGIN();
RUN_TEST(testObjects); RUN_TEST(testCrypto);
return UNITY_END(); return UNITY_END();
} }
*/ */

View file

@ -23,7 +23,7 @@ void testReference() {
int main(void) int main(void)
{ {
UNITY_BEGIN(); UNITY_BEGIN();
RUN_TEST(testObjects); RUN_TEST(testReference);
return UNITY_END(); return UNITY_END();
} }
*/ */

View file

@ -38,6 +38,6 @@ Transport::~Transport() {
} }
/*static*/ bool Transport::outbound(const Packet &packet) { /*static*/ bool Transport::outbound(const Packet &packet) {
// mock // MOCK
return true; return true;
} }

View file

@ -39,12 +39,12 @@ void setup() {
Serial.print("Hello from T-Beam on PlatformIO!\n"); Serial.print("Hello from T-Beam on PlatformIO!\n");
#endif #endif
try {
#ifndef NDEBUG #ifndef NDEBUG
//RNS::loglevel(RNS::LOG_WARNING); RNS::loglevel(RNS::LOG_WARNING);
RNS::loglevel(RNS::LOG_EXTREME); //RNS::loglevel(RNS::LOG_EXTREME);
//test(); test();
testCrypto();
return;
#endif #endif
//std::stringstream test; //std::stringstream test;
@ -79,6 +79,11 @@ void setup() {
//zRNS::Transport.register_announce_handler(announce_handler); //zRNS::Transport.register_announce_handler(announce_handler);
}
catch (std::exception& e) {
RNS::error(std::string("!!! Exception in main: ") + e.what() + " !!!");
}
#ifndef NATIVE #ifndef NATIVE
Serial.print("Goodbye from T-Beam on PlatformIO!\n"); Serial.print("Goodbye from T-Beam on PlatformIO!\n");
#endif #endif