Compare commits

...

14 Commits

Author SHA1 Message Date
Tristan B. Velloza Kildaire 27eeaf3716
Merge 1419e99f29 into 9aacb97156 2024-04-20 21:54:56 +00:00
Tristan B. Velloza Kildaire 9aacb97156 Message
- Documented `decode(byte[] dataIn, ref Message decoded)`
2024-01-29 21:59:12 +02:00
Tristan B. Velloza Kildaire d0de2c1842 Router (unittests)
- Removed redundant imports
2024-01-29 19:53:36 +02:00
Tristan B. Velloza Kildaire d3dc83766a Router (unittests)
- Removed redundant imports
2024-01-29 19:52:03 +02:00
Tristan B. Velloza Kildaire 1cfe8e0166 Arp (unittests)
- Removed redundant imports
2024-01-29 19:51:41 +02:00
Tristan B. Velloza Kildaire 1419e99f29 Router
- Don't encrypt payloads destined to ourselvges
- This reworks the `sendData(byte[] payload, string to)` method
2024-01-24 16:08:32 +02:00
Tristan B. Velloza Kildaire a9575e5149 Router
- `sendData(byte[] payload, string to)` now encrypts data to the destination address
- Added `getPrivateKey()`
- `handle_DATA(Link link, string srcAddr, Message recvMesg)` now will decrypt data destined to it before passing it up the the user message handler

Router (unittests)

- Fixed to use new `Router` API which makes use of `Identity`
- We now generate the identities before instantiating the routers
2024-01-24 15:58:52 +02:00
Tristan B. Velloza Kildaire 645dc31ff2 Keys
- Added encryption and decryption methods
2024-01-24 15:47:09 +02:00
Tristan B. Velloza Kildaire c3e8098604 Router
- No need for `const` there
2024-01-24 15:27:05 +02:00
Tristan B. Velloza Kildaire 13317a6f96 Router
- Now takes in an `Identity`

App

- Generate an `Identity`
2024-01-24 15:26:24 +02:00
Tristan B. Velloza Kildaire 1a086f3d51 Identity
- Marked as `const` (nothing should ever change herein)
2024-01-24 15:26:19 +02:00
Tristan B. Velloza Kildaire fb61fcf4cd Merge branch 'master' into feature/crypto 2024-01-24 15:21:47 +02:00
Tristan B. Velloza Kildaire cebf44562a Keys
- Added new module
2024-01-17 16:01:19 +02:00
Tristan B. Velloza Kildaire c9677ed60e Dub
- Added `crypto` dependency
2024-01-16 21:59:01 +02:00
6 changed files with 139 additions and 45 deletions

View File

@ -4,6 +4,7 @@
],
"copyright": "Copyright © 2024, Tristan B. Velloza Kildaire",
"dependencies": {
"crypto": "~>0.2.18",
"gogga": "~>2.2.1",
"msgpack-d": "~>1.0.5",
"niknaks": "~>0.8.1"

View File

@ -20,7 +20,9 @@ void main(string[] args)
string identity = args[1];
string[] interfaces = args[2..$];
Router r = new Router([identity, "privKey1"]);
import twine.core.keys;
Identity ident = Identity.newIdentity();
Router r = new Router(ident);
import niknaks.debugging;

View File

@ -464,8 +464,6 @@ version(unittest)
import twine.links.link;
import std.stdio;
import core.thread : Thread;
import core.sync.mutex : Mutex;
import core.sync.condition : Condition;
import std.conv : to;
}

61
source/twine/core/keys.d Normal file
View File

@ -0,0 +1,61 @@
module twine.core.keys;
import crypto.rsa : RSA, RSAKeyPair;
public const struct Identity
{
private string publicKey;
private string privateKey;
@disable
this();
this(string publicKey, string privateKey)
{
this.publicKey = publicKey;
this.privateKey = privateKey;
}
public string getPublicKey()
{
return this.publicKey;
}
public string getPrivateKey()
{
return this.privateKey;
}
public ubyte[] identity_b()
{
import std.digest.sha : sha512Of;
return sha512Of(getPublicKey()).dup;
}
public string identity()
{
// hex of hash of public key
import std.digest : toHexString;
return toHexString(identity_b());
}
public static Identity newIdentity()
{
RSAKeyPair kp = RSA.generateKeyPair();
return Identity(kp.publicKey, kp.privateKey);
}
}
private alias rsa_encrypt = RSA.encrypt;
public byte[] encrypt(byte[] raw, string publicKey)
{
return cast(byte[])rsa_encrypt(publicKey, cast(ubyte[])raw);
}
private alias rsa_decrypt = RSA.decrypt;
public byte[] decrypt(byte[] encrypted, string privateKey)
{
return cast(byte[])rsa_decrypt(privateKey, cast(ubyte[])encrypted);
}

View File

@ -12,6 +12,7 @@ import core.sync.mutex : Mutex;
import core.sync.condition : Condition;
import niknaks.functional : Optional;
import twine.core.arp;
import twine.core.keys;
/**
* This represents data passed
@ -91,7 +92,9 @@ public class Router : Receiver
private const LinkManager linkMan; // const, never should be changed besides during construction
private Thread advThread;
private Duration advFreq;
private string[] keyPairs;
// crypto
private const Identity identity;
// routing tables
private Route[string] routes;
@ -104,7 +107,7 @@ public class Router : Receiver
private const DataCallbackDelegate messageHandler;
// todo, set advFreq back to 5 seconds
this(string[] keyPairs, DataCallbackDelegate messageHandler = toDelegate(&nopHandler), Duration advFreq = dur!("seconds")(100))
this(const Identity identity, DataCallbackDelegate messageHandler = toDelegate(&nopHandler), Duration advFreq = dur!("seconds")(100))
{
this.linkMan = new LinkManager(this);
this.arp = new ArpManager();
@ -112,7 +115,7 @@ public class Router : Receiver
this.advThread = new Thread(&advertiseLoop);
this.advFreq = advFreq;
this.keyPairs = keyPairs;
this.identity = identity;
this.messageHandler = messageHandler;
this.routesLock = new Mutex();
@ -122,9 +125,9 @@ public class Router : Receiver
}
// todo, set advFreq back to 5 seconds
this(string[] keyPairs, DataCallbackFunction messageHandler, Duration advFreq = dur!("seconds")(100))
this(Identity identity, DataCallbackFunction messageHandler, Duration advFreq = dur!("seconds")(100))
{
this(keyPairs, toDelegate(messageHandler), advFreq);
this(identity, toDelegate(messageHandler), advFreq);
}
/**
@ -167,7 +170,12 @@ public class Router : Receiver
*/
private string getPublicKey()
{
return this.keyPairs[0];
return this.identity.getPublicKey();
}
private string getPrivateKey()
{
return this.identity.getPrivateKey();
}
/**
@ -299,6 +307,9 @@ public class Router : Receiver
{
logger.dbg("packet '", dataPkt, "' is destined to me");
// decode the data
payload = decrypt(payload, getPrivateKey());
// run handler
messageHandler(UserDataPkt(uSrc, payload));
}
@ -407,6 +418,9 @@ public class Router : Receiver
process(link, data, srcAddr);
}
// todo, add session-based send over here
import twine.core.keys;
/**
* Sends a piece of data to the given
* network-layer address
@ -426,6 +440,21 @@ public class Router : Receiver
// found route
if(route.isPresent())
{
Route r = route.get();
// is data to self
if(r.isSelfRoute())
{
// our link is null, we don't send to ourselves - rather
// we call the user handler right now
messageHandler(UserDataPkt(to, payload));
return true;
}
// encrypt the payload here to destination key
payload = encrypt(payload, to);
// construct data packet to send
Data dataPkt; // todo, if any crypto it would be with `to` NOT `via` (which is imply the next hop)
if(!Data.makeDataPacket(getPublicKey(), to, payload, dataPkt))
@ -442,35 +471,21 @@ public class Router : Receiver
return false;
}
Route r = route.get();
// resolve link-layer address of next hop
Optional!(ArpEntry) ae = this.arp.resolve(r.gateway(), r.link());
// is data to self
if(r.isSelfRoute())
if(ae.isPresent())
{
// our link is null, we don't send to ourselves - rather
// we call the user handler right now
messageHandler(UserDataPkt(to, payload));
// transmit over link to the destination ll-addr (as indiacted by arp)
r.link().transmit(mesgOut.encode(), ae.get().llAddr());
return true;
}
// to someone else
else
{
// resolve link-layer address of next hop
Optional!(ArpEntry) ae = this.arp.resolve(r.gateway(), r.link());
if(ae.isPresent())
{
// transmit over link to the destination ll-addr (as indiacted by arp)
r.link().transmit(mesgOut.encode(), ae.get().llAddr());
return true;
}
else
{
logger.error("ARP failed for next hop '", r.gateway(), "' when sending to dst '"~r.destination()~"'");
return false;
}
logger.error("ARP failed for next hop '", r.gateway(), "' when sending to dst '"~r.destination()~"'");
return false;
}
}
// route not found
else
@ -768,9 +783,7 @@ public class Router : Receiver
version(unittest)
{
import std.stdio;
import core.thread : Thread;
import core.sync.mutex : Mutex;
import core.sync.condition : Condition;
import std.conv : to;
import twine.core.wire;
@ -884,11 +897,14 @@ unittest
p2.connect(p1, p1.getAddress());
Router r1 = new Router(["p1Pub", "p1Priv"], toDelegate(&nopHandler), dur!("seconds")(5));
Identity r1_ident = Identity.newIdentity();
Identity r2_ident = Identity.newIdentity();
Router r1 = new Router(r1_ident, toDelegate(&nopHandler), dur!("seconds")(5));
r1.getLinkMan().addLink(p1);
r1.start();
Router r2 = new Router(["p2Pub", "p2Priv"], toDelegate(&nopHandler), dur!("seconds")(5));
Router r2 = new Router(r2_ident, toDelegate(&nopHandler), dur!("seconds")(5));
r2.getLinkMan().addLink(p2);
r2.start();
@ -986,6 +1002,12 @@ unittest
p1_to_p3.connect(p3_to_p1, p3_to_p1.getAddress());
p3_to_p1.connect(p1_to_p3, p1_to_p3.getAddress());
Identity r1_ident = Identity.newIdentity();
Identity r2_ident = Identity.newIdentity();
Identity r3_ident = Identity.newIdentity();
UserDataPkt r1_to_r1_reception;
void r1_msg_handler(UserDataPkt m)
{
@ -995,27 +1017,27 @@ unittest
UserDataPkt r1_to_r2_reception, r3_to_r2_reception;
void r2_msg_handler(UserDataPkt m)
{
if(m.getSrc() == "p1Pub")
if(m.getSrc() == r1_ident.getPublicKey())
{
r1_to_r2_reception = m;
}
else if(m.getSrc() == "p3Pub")
else if(m.getSrc() == r3_ident.getPublicKey())
{
r3_to_r2_reception = m;
}
}
Router r1 = new Router(["p1Pub", "p1Priv"], &r1_msg_handler, dur!("seconds")(5));
Router r1 = new Router(r1_ident, &r1_msg_handler, dur!("seconds")(5));
r1.getLinkMan().addLink(p1_to_p2);
r1.getLinkMan().addLink(p1_to_p3);
r1.start();
Router r2 = new Router(["p2Pub", "p2Priv"], &r2_msg_handler, dur!("seconds")(5));
Router r2 = new Router(r2_ident, &r2_msg_handler, dur!("seconds")(5));
r2.getLinkMan().addLink(p2_to_p1);
r2.start();
Router r3 = new Router(["p3Pub", "p3Priv"], toDelegate(&nopHandler), dur!("seconds")(5));
Router r3 = new Router(r3_ident, toDelegate(&nopHandler), dur!("seconds")(5));
r3.getLinkMan().addLink(p3_to_p1);
r3.start();
@ -1055,21 +1077,21 @@ unittest
writeln(dumpArray!(r3_routes));
// r1 -> r2 (on-link forwarding decision)
assert(r1.sendData(cast(byte[])"ABBA poespoes", "p2Pub"));
assert(r1.sendData(cast(byte[])"ABBA poespoes", r2_ident.getPublicKey()));
// todo, use condvar to wait aaasuredly
Thread.sleep(dur!("seconds")(2));
// check reception of message
assert(r1_to_r2_reception.getPayload() == "ABBA poespoes");
// r3 -> r2 (forwarded via r1)
assert(r3.sendData(cast(byte[])"ABBA naainaai", "p2Pub"));
assert(r3.sendData(cast(byte[])"ABBA naainaai", r2_ident.getPublicKey()));
// todo, use condvar to wait aaasuredly
Thread.sleep(dur!("seconds")(2));
// check reception of message
assert(r3_to_r2_reception.getPayload() == "ABBA naainaai");
// r1 -> r1 (self-route)
assert(r1.sendData(cast(byte[])"ABBA kakkak", "p1Pub"));
assert(r1.sendData(cast(byte[])"ABBA kakkak", r1_ident.getPublicKey()));
// todo, use condvar to wait aaasuredly
Thread.sleep(dur!("seconds")(2));
// check reception of message

View File

@ -81,6 +81,16 @@ public struct Message
return encode(this);
}
/**
* Decoes the given data into the provided
* `Message` variable
*
* Params:
* dataIn = the data to decode
* decoded = the decoded `Message`
* Returns: `true` if the decode succeeded,
* otherwise `false`
*/
public static bool decode(byte[] dataIn, ref Message decoded)
{
try
@ -189,7 +199,7 @@ public struct Data
return this.src;
}
public string getDst()
public string getDst() const
{
return this.dst;
}