online_security_project/protocol.md
2024-12-14 19:10:09 +02:00

3.8 KiB

The Protocol

All encryptions are made using RSA (key size to be determined), no symmetric encryptions are used due to messages being short.

a. Encryption will be a-symmetric because we can assume messages are short b. See "Registration" below c. Server keeps public keys for everyone, and gives them to a user when they want to send a message to someone (only the relevant key) d. Every e2e message is both signed and encrypted aka, message M from A to B EM = E_Bpub(E_Apriv(N)) e. message is sent to the server in a E_server(E_Apriv(metadata + EM from d)), message ack is sent to the server as a MessageAck(msg_id), which will be retrieved by the user when it pulls for messages. f. TODO: properly explain the different api structs g. TODO: properly explain how the server handles data

Key Derivation Function

as there is no use of symmetric keys (at least for this scope), I dont believe there is a need to use KDF, it will reduce the keyspace and we already have the public key of the server in the clients

Registration:

  • User sends a register request to server (phone number, RSA public key), giving them a public key and encrypting using the server's public key
  • Server sends the user a VerificationRequired message & a 6-digit code (Secure channel)
  • User sends the server the 6-digit code, signed using the key provided at stage 1 (this message is very short and funny, because its a 6-digit code, signed using the user's private key, and encrypted using the server's public key)
  • Server sends a last Confirm and the registration process is done

"Login"

The users dont need to login, as they dont really need to hold a conenction to the server, only thing that matters is that every message to the server should be signed with the user's private key, thus the key acts as a form of credentials

Passing messages

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, signed with A, wrapped in a SendMessage request and ultimately signed by A and encrypted using the server's key.

The server will hold on to the message until B will send a GetMessages request to the server.

"Control" requests

  • Register (phone, pub RSA key) extra data: RSA key size (payload length)
  • ConfirmRegister (signed & encrypted 6 digit code) extra data: 6 bytes for the 6 digit code (can use less but it will be padding otherwise)
  • GetMessages (signed & encrypted to not allow someone to "flush" someone else's msgs) extra data: EMPTY
  • GetUserKey (dont think it needs any signing or encryption technically, as it is very simple registering and "stealing" a key outside the system, keys are assumed to be unbreakable) extra data: 8 bytes (4 bits per digit) of whoever we want to get the key of
  • SendMessage (to_user, msg_id, EM from d above) extra data: 8 bytes (4 bits per digit) of who to send the data, 4 bytes (32bit) for length
  • SendAck (to_user, msg_id - signed and encrypted)
    • server doesnt know if the msg itself is indeed valid and not tempered with extra data: 8 bytes (4 bits per digit) of who to send the data, 4 bytes (32bit) for length

I think it all can go into a:

{
	Version byte (0) - 1 byte
	RequestType - 1 byte,
	Phone number - 8 bytes (every 4 bits is a number, so we have 16 numbers), 
	UTC timestamp - 8 bytes (long),
	extra data (based on the request given) - up to 18 bytes
} = 32 bytes = 256 bits

and we can just append encrypted payloads to it (in SendMessage and SendAck)

To each message we also append a sha3-256 signed hash, this shit really feels like overkill and im not sure about it, on the other i do want to have a bigger key size and 512 seems like an okay-ish thing to have, as 256 is short and 1024 is amusingly long for the amount of data the server needs to encrypt

enc_server( request - 256 bits, signed sha3-256 )

which means: Keys: RSA-512 Hashes: SHA3-256