Safenet: Part One

Posted: March 2023

Introduction

Don't trust the NSA and their "secure" protocols, like TLS? Create your own! I'll be documenting my steps through the journey of the creation of safenet, an alternative to TLS. However, I am not creating safenet because of some distrust of the NSA, I'm just bored.

Flow

Body Format

To initialize connections, I will be using HTTP to set things up. I'll be utilizing my own HTTP server library, tinyhttp to make the API routes. These routes are not HTTP compliant, meaning if you use cURL or your average web browser and point them towards any of these endpoints, it will result in an error.

HTTP/1.1 API:

For client-side requests, I use minreq. As of right now, I have three API routes.

GET /keys/pub

This is the only endpoint that is HTTP compliant!

Returns server public ECDSA key.

POST /conn/init

Takes in a body of bytes formatted like:

struct Body { id: [u8; 3], // a string that consists of 3 bytes, e.g "aaa" uuid: [u8; 16], // a uuid ecdsa_public_key: [u8; 49], // client's public key to check against client's ECDH key ecdh_pub_key: [u8; 49], // client's ECDH public key, which is used to generate shared secret ecdh_pub_key_signature: &[u8] // takes the rest of the body, since this is the only variabile with a non-constant size/length }

And returns the same.

POST /conn/test

Takes a unique body formatted as so:

struct Body { id: [u8; 3], uuid: [u8; 16], msg: &[u8] // Encrypted string, represented as bytes }

Returns result of decryption, e.g "200 OK".

"Safenet API"

I'm still debating whether I should use my existing HTTP library, tinyhttp, or write my own protocol. As of now, I'm leaning towards the former, since I do not have to write a protocol from scrath and I know exactly how my HTTP server will behave. My only concern would be security, however, I only need the status line of the HTTP request to be HTTP compliant. I can have my headers + body encrypted.

Data Frame
struct DataFrame { id: u32, // use `from_be_bytes()` to get into array of 4 u8's uuid: [u8; 16], body: &[u8] // rest of the frame will be the body }

The id field will be a serialized string, which we can deserialize by getting an array of [u8: 3], which is an array of 3 u8's. Then, we can convert the array into a String using String::from_utf8().

I will use a uuid that is generated at startup, in order to avoid duplicate id's. Due to my current implementation of sorting through peer keys, we cannot use ip's like: 127.0.0.1/localhost or 0.0.0.0.

Usage

Safenet is framework-agnostic, as long as you stay strict to the spec. Specifically, the /conn/init must be defined to maintain compatibility.

made by ~~> Mateo