finished the protocol
This commit is contained in:
parent
84d9bd0ef0
commit
661c217a73
4 changed files with 121 additions and 20 deletions
|
@ -3,7 +3,7 @@
|
|||
[ ] Do print stuff for EVERYTHING (with colors preferably)
|
||||
[x] Client
|
||||
[x] Server
|
||||
[ ] rewrite the protocol.md
|
||||
[x] rewrite the protocol.md
|
||||
[ ] Make a video that shows how everything works yada yada
|
||||
[ ] export everything and upload it
|
||||
[ ] get a nice drink to celebrate
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
|
@ -54,16 +52,17 @@ public class Message
|
|||
|
||||
public byte[] Bytes()
|
||||
{
|
||||
// initialize a list
|
||||
List<byte> msg = [];
|
||||
// 0..4
|
||||
// 0..4 - message id
|
||||
msg.AddRange(BitConverter.GetBytes(Id));
|
||||
// 4..12
|
||||
// 4..12 - sender's phone number
|
||||
msg.AddRange(Utils.NumberToBytes(Sender));
|
||||
// 12
|
||||
// 12 - is this message an acknowledgement or a normal message
|
||||
msg.Add((byte)(IsAck ? 1 : 0));
|
||||
// 13..(len - 32)
|
||||
// 13.. the message itself (should be empty for an acknowledgement)
|
||||
msg.AddRange(Encoding.UTF8.GetBytes(Content));
|
||||
|
||||
// Turn into array, prepending the version byte
|
||||
return [0, .. msg];
|
||||
}
|
||||
}
|
124
protocol.md
124
protocol.md
|
@ -1,15 +1,67 @@
|
|||
# The Protocol
|
||||
|
||||
1. Encryptions used:
|
||||
- RSA-1024 (can be of somewhat arbitrary length):
|
||||
used for initial server communication,
|
||||
client to client communication and for client authentication.
|
||||
- SHA3-256 hash:
|
||||
verification of information by signing with the RSA keys (messages and authentication).
|
||||
- AES-CFB-256:
|
||||
Used for encryption of communication between the client and the server.
|
||||
- both PKCS7 and padding-less messages are being sent as
|
||||
most requests are made to be exactly 1 block (128 bits),
|
||||
which technically results in a cookbook style encrytion.
|
||||
2. Registration is done by getting a public key from the user, and in a
|
||||
second packet getting the 6 digit code, the code is then signed to make
|
||||
sure the key given in the first packet is indeed the expected key.
|
||||
For more details see Registration below
|
||||
3. Public keys are generated by the client when it wants to register, it is
|
||||
then the clien't job to save private key in a secure fashion
|
||||
(currently it is saved as an unencrypted file in pem format for ease of debug).
|
||||
|
||||
The AES session keys are also generated by the client, but they are not
|
||||
saved anywhere as they are only for the current session (if a disconnect
|
||||
happend, a new key needs to be generated). The session key is sent to the
|
||||
server as the first packet, signed with the server's public key, so only
|
||||
the server could obtain them.
|
||||
|
||||
### Key Derivation Function
|
||||
The server saves each user public key (and each client can cache other
|
||||
users public keys to reduce network usage), while the keys should be saved
|
||||
in a secure fashion, it is more important for them to not be changed rather
|
||||
then not having general access, as getting someone's public key is as easy
|
||||
as registering and making a simple request.
|
||||
|
||||
doesnt seem to be any reason to use a key derivation function.
|
||||
Passing keys between users is not of a great security risk, as all keys
|
||||
passed are public keys.
|
||||
4. Messages are first encrypted using the recipient's public key, then signed
|
||||
using the sender's private key (the signature is appended). This allows the recipient to verify the message's claimed origin. Message
|
||||
Acknowledgements are special messages, being sent as normal messages with
|
||||
the same id as the acknowledged message but with the IsAck flag set to true.
|
||||
5. See Passing messages below
|
||||
6. See Requests below
|
||||
7. The server uses 2 Dictionaries as the data structure (see `server/Data.cs`)
|
||||
(not saved to disk due to the non-trivial nature of it),
|
||||
1 dictionary is used to save the public keys, and the other acts as a
|
||||
mailbox for each client.
|
||||
|
||||
### About Key Derivation Function
|
||||
|
||||
KDF isnt necessary here, as the client already has the server's public key and no key exchange needs to happen,
|
||||
the client can send an encrypted symmetric key to the server, and a secure connection can be established using only 1 request.
|
||||
|
||||
NOTE: the server in this case trusts the client to create a good symmetric key. This is not a big issue in my opinion,
|
||||
as the client (if malicious) can send a third party the transfered data regardless.
|
||||
|
||||
## Initializing a connection
|
||||
|
||||
First packet of each connection needs to be an encrypted packet
|
||||
(using the server's public key) of an AES-256 session key appended by
|
||||
some random IV.
|
||||
|
||||
## Registration:
|
||||
|
||||
- User sends a `Register` requset giving them a public key and encrypting using the server's public key
|
||||
- Server sends the user a `VerificationRequired` (not in current code, as the 6 digit code does that for now) message & a 6-digit code (Secure channel)
|
||||
- User sends a `Register` requset giving them a public key and a phone number.
|
||||
- Server sends the user a `VerificationRequired` message (not in current code, as the 6 digit code does that for now) & a 6-digit code (Secure channel)
|
||||
- User sends the server a `ConfirmRegister` with the 6-digit code, signed using the key provided at previous stage
|
||||
- Server verifies the signature and code, and if both are valid it sends a last `Confirm` and the registration process is done
|
||||
|
||||
|
@ -24,26 +76,49 @@ In order to send a message from A to B, A will ask the server for B's key,
|
|||
A will then encrypt the message using B's key, append a signature, and send a `SendMessage`
|
||||
request with the payload having the structure of `Enc_b(Message object) + Signature_A(Message object)`.
|
||||
|
||||
The server will hold on to the message until B will send a `GetMessages` request
|
||||
to the server.
|
||||
The server will hold on to the message until B will send a `GetMessages`
|
||||
request to the server.
|
||||
|
||||
NOTE: The server actually doesnt know (and care) how the message is
|
||||
constructed, allowing the change of the message structure without updating
|
||||
the server itself.
|
||||
|
||||
## Requests
|
||||
|
||||
- Register:
|
||||
data: Phone - 8 bytes, RSA key size (payload length) - 2 bytes
|
||||
|
||||
Response: a simple `ValidationRequired`, not implemented as the 6 digit
|
||||
code covers that.
|
||||
- ConfirmRegister (signed & encrypted 6 digit code)
|
||||
data: 6 bytes for the 6 digit code, 4 bytes for signature length
|
||||
|
||||
Response: UTF-8 string of either `OK` or `SIG INVALID`, with PKCS7 padding
|
||||
- Login:
|
||||
data: 8 bytes of user's phone
|
||||
|
||||
Response: 16 bytes to be signed, no padding (1 block)
|
||||
- ConfirmLogin (signed hash):
|
||||
data: hash length
|
||||
|
||||
Response UTF-8 string of either `OK` or `INVALID SIG`, PKCS7 padding
|
||||
- GetMessages:
|
||||
data: EMPTY
|
||||
|
||||
Response: 8 shorts, appended with the messages themselves.
|
||||
The last short marks if there are more messages to be read, the rest
|
||||
are the lengths of each corresponding message (by order).
|
||||
No padding as only the 8 shorts are encrypted using the session key.
|
||||
- GetUserKey:
|
||||
extra data: 8 bytes (4 bits per digit) of whoever we want to get the key of
|
||||
|
||||
Response: The key, PKCS7 padded
|
||||
- SendMessage:
|
||||
extra data: 8 bytes (4 bits per digit) of who to send the data, 4 bytes (32bit) for length in bytes
|
||||
I think it all can go into a:
|
||||
|
||||
Response: NONE
|
||||
|
||||
Request format (see `lib/Request.cs:3` - `#RequestType` for request type numbers):
|
||||
```
|
||||
{
|
||||
Version byte (0) - 1 byte,
|
||||
|
@ -53,7 +128,34 @@ I think it all can go into a:
|
|||
} = 16 bytes = 128 bits
|
||||
```
|
||||
|
||||
Encryption and Hashes used:
|
||||
public keys: RSA-1024 (can be of somewhat arbitrary length)
|
||||
Hashes: SHA3-256
|
||||
symmetric keys: AES-CFB-256 with PCKS7 padding (when needed as most stuff are made to fit in 1 block)
|
||||
The SendMessage payload structure can be seen in `client/Message.cs:55` in
|
||||
the `Bytes()` function.
|
||||
The binary format contains:
|
||||
- 1 version byte
|
||||
- 4 bytes for a message ID
|
||||
- 8 bytes for the sender's phone number
|
||||
- 1 byte for flags (IsAck)
|
||||
- The rest is filled with the message itself
|
||||
|
||||
## Notes and assumptions
|
||||
|
||||
- Print statements are color coded: RED - unencrypted, GREEN - encrypted, ORANGE - General server stuff, WHITE - Messages.
|
||||
- The given code does not handle errors nicely (connection will simply shutdown and client will crash).
|
||||
- Stream handling is also not ideal, as both server and client reads all
|
||||
that was sent and not actually read only the amount needed.
|
||||
- Client does not get messages automatically,
|
||||
instead a `/get` command (among others such as `/pull` and `/fetch`) are
|
||||
present in order to get new messages from the server
|
||||
- The client does not handle getting message properly, as not extra reading
|
||||
and no proper buffering is being done (if the incoming messages are
|
||||
too long for the buffer, it will crash).
|
||||
- The server does not save its current data and does not load from disk.
|
||||
Saving the data and is not as trivial as in python since the RSA class
|
||||
does not contain a constructor.
|
||||
|
||||
# Part 3
|
||||
|
||||
Availability cannot be guaranteed, as the server can always get hit by a rocket,
|
||||
a malicious actor can attempt to scramble or change the packets in transit (which only
|
||||
a reconnect attempt can really solve this, assuming the connection will not be tempered with
|
||||
this time), the client's or server's area might have an extended power/internet outage and a meteor might hit earth and society might collapse.
|
|
@ -31,7 +31,7 @@ public class Data
|
|||
}
|
||||
else
|
||||
{
|
||||
// generate a new queue because one doesnt already exists
|
||||
// generate a new queue because one doesnt already exists
|
||||
Messages[Phone] = new Queue<byte[]>();
|
||||
return []; // no messages were in the list so no reason to attempt to send any message
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue