started working o nstuff yay

This commit is contained in:
Rusty Striker 2024-12-14 17:17:58 +02:00
parent 2df8de0a3e
commit 65f5a95dac
Signed by: RustyStriker
GPG key ID: 87E4D691632DFF15
11 changed files with 295 additions and 13 deletions

26
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,26 @@
{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md
"name": ".NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/client/bin/Debug/net8.0/client.dll",
"args": [],
"cwd": "${workspaceFolder}/client",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}

41
.vscode/tasks.json vendored Normal file
View file

@ -0,0 +1,41 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/online_security_project.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/online_security_project.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/online_security_project.sln"
],
"problemMatcher": "$msCompile"
}
]
}

View file

@ -1,2 +1,50 @@
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace Client;
public class Program
{
static void Main(string[] args)
{
using TcpClient client = new("127.0.0.1", 12345);
byte[] toSend = Encoding.ASCII.GetBytes("hello server");
var stream = client.GetStream();
var inputTask = Task.Run(async () => await HandleUserInput(client, stream));
var serverInput = Task.Run(async () => await HandleServerInput(client, stream));
_ = Task.WaitAny(inputTask, serverInput);
}
static async Task HandleUserInput(TcpClient client, NetworkStream stream) {
while(client.Connected) {
string? input = Console.ReadLine();
if(input == null) {
await Task.Delay(100);
continue;
}
else {
stream.Write(Encoding.ASCII.GetBytes(input));
Console.WriteLine($"[{DateTime.Now}]Sent to server: {input}");
}
}
}
static async Task HandleServerInput(TcpClient client, NetworkStream stream) {
byte[] buffer = new byte[1024];
while(client.Connected) {
int readLen = await stream.ReadAsync(buffer);
if(readLen != 0) {
string fromServer = Encoding.ASCII.GetString(buffer[..readLen]);
Console.WriteLine($"[{DateTime.Now}]\t\tFrom server: {fromServer}");
}
}
}
}

View file

@ -7,7 +7,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

View file

@ -1,6 +0,0 @@
namespace lib;
public class Class1
{
}

10
lib/Request.cs Normal file
View file

@ -0,0 +1,10 @@
namespace lib;
public enum RequestType {
Register = 1,
ConfirmRegister = 2,
GetMessages = 3,
GetUserKey = 4,
SendMessage = 5,
SendAck = 6
}

53
lib/Utils.cs Normal file
View file

@ -0,0 +1,53 @@
using System.Text;
using System.Linq;
namespace lib;
public static class Utils {
public static byte[] NumberToBytes(string Number) {
if(Number.Any(c => !char.IsDigit(c)) || Number.Length > 16) {
throw new Exception("Invalid arguments!");
}
byte[] res = Enumerable.Repeat((byte)0b1111_1111, 8).ToArray();
// Pad Number if needed to be of even length (because each 2 digits are turned into 1 byte)
Number = Number.Length % 2 == 0 ? Number : Number + '-';
for(int i = 0; i < Number.Length - 1; i += 2) {
char c1 = Number[i];
char c2 = Number[i + 1];
res[i / 2] = (byte)((DigitToByte(c1) << 4) | DigitToByte(c2));
}
return res;
}
public static string BytesToNumber(byte[] Bytes) {
string s = "";
foreach(byte b in Bytes) {
byte b1 = (byte)((b >> 4) & 0b1111);
byte b2 = (byte)(b & 0b1111);
s = s + ByteToDigit(b1) + ByteToDigit(b2);
}
return new string(s.Where(c => char.IsDigit(c)).ToArray());
}
public static byte DigitToByte(char c) {
if (int.TryParse(c.ToString(), out int d)) {
return (byte)d;
}
else {
return 0b1111; // empty, turned into '-' later to be discarded
}
}
public static char ByteToDigit(byte b) {
byte offset = Encoding.ASCII.GetBytes("0")[0];
if(b == 0b1111) {
return '-';
}
else {
return Encoding.ASCII.GetChars([(byte)(b + offset)])[0];
}
}
}

View file

@ -5,6 +5,10 @@ VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "client\client.csproj", "{F38E98E8-4FE8-4F34-B5A7-004444ED1F50}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "server", "server\server.csproj", "{36C3F9FE-FA02-4AC0-89A2-65B377767C8F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "lib", "lib\lib.csproj", "{8E625330-2219-4E74-8524-A947D783B3BB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -18,5 +22,13 @@ Global
{F38E98E8-4FE8-4F34-B5A7-004444ED1F50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F38E98E8-4FE8-4F34-B5A7-004444ED1F50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F38E98E8-4FE8-4F34-B5A7-004444ED1F50}.Release|Any CPU.Build.0 = Release|Any CPU
{36C3F9FE-FA02-4AC0-89A2-65B377767C8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{36C3F9FE-FA02-4AC0-89A2-65B377767C8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{36C3F9FE-FA02-4AC0-89A2-65B377767C8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{36C3F9FE-FA02-4AC0-89A2-65B377767C8F}.Release|Any CPU.Build.0 = Release|Any CPU
{8E625330-2219-4E74-8524-A947D783B3BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8E625330-2219-4E74-8524-A947D783B3BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E625330-2219-4E74-8524-A947D783B3BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E625330-2219-4E74-8524-A947D783B3BB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View file

@ -3,11 +3,29 @@
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 `Confirm` message & a 6-digit code
- 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)
@ -27,3 +45,41 @@ 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
enc_server( request - 256 bits, signed sha3-256 )
which means:
Keys: RSA-512
Hashes: SHA3-256

View file

@ -1,2 +1,44 @@
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
using System;
using System.Net;
using System.Net.Sockets;
namespace Server;
public class Program
{
static void Main(string[] args)
{
int port = 12345;
TcpListener server = new(IPAddress.Parse("0.0.0.0"), port);
try {
server.Start();
byte[] buffer = new byte[256];
while(true) {
// Currently, every time it gets a block, it will simply send it back but ToUpper
using TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Got a client!");
var stream = client.GetStream();
int readLen;
while((readLen = stream.Read(buffer, 0, buffer.Length)) != 0) {
// for now, lets just read it as an ascii string
string input = System.Text.Encoding.ASCII.GetString(buffer, 0, readLen);
Console.WriteLine($"Got block: {input}");
byte[] ret = System.Text.Encoding.ASCII.GetBytes(input.ToUpper());
stream.Write(ret, 0, ret.Length);
}
}
}
catch(Exception ex) {
Console.WriteLine($"Server error: {ex.Message}");
Console.WriteLine("Trace: " + ex.StackTrace);
}
finally {
server.Stop();
}
}
}

View file

@ -7,7 +7,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>