crypto handshake and encryption

This commit is contained in:
2026-08-28 13:39:26 +02:00
parent 7a21c71817
commit 9d59da3a4e
6 changed files with 383 additions and 42 deletions
Generated
+209 -12
View File
@@ -2,6 +2,16 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "aead"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1973cfbc1a2daf9cf550e74e1f088c28e7f7d8c1e1418fb6c9dc5184b7e84c99"
dependencies = [
"crypto-common 0.2.2",
"inout",
]
[[package]] [[package]]
name = "ahash" name = "ahash"
version = "0.8.12" version = "0.8.12"
@@ -108,6 +118,15 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "block-buffer"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa"
dependencies = [
"hybrid-array",
]
[[package]] [[package]]
name = "bs58" name = "bs58"
version = "0.5.1" version = "0.5.1"
@@ -145,12 +164,58 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "chacha20"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures 0.3.1",
]
[[package]]
name = "chacha20poly1305"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b89e1c441e926b9c82a8d023f6e1b7ae0adcfaa7d621814e4d60789bac751cb"
dependencies = [
"aead",
"chacha20",
"cipher",
"poly1305",
]
[[package]]
name = "cipher"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c"
dependencies = [
"block-buffer 0.12.1",
"crypto-common 0.2.2",
"inout",
]
[[package]]
name = "cmov"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a"
[[package]] [[package]]
name = "const-oid" name = "const-oid"
version = "0.9.6" version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "const-oid"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c"
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.17" version = "0.2.17"
@@ -160,6 +225,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "cpufeatures"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "crypto-common" name = "crypto-common"
version = "0.1.7" version = "0.1.7"
@@ -170,6 +244,26 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "crypto-common"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
dependencies = [
"getrandom 0.4.3",
"hybrid-array",
"rand_core 0.10.1",
]
[[package]]
name = "ctutils"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e"
dependencies = [
"cmov",
]
[[package]] [[package]]
name = "curve25519-dalek" name = "curve25519-dalek"
version = "4.1.3" version = "4.1.3"
@@ -177,10 +271,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"cpufeatures", "cpufeatures 0.2.17",
"curve25519-dalek-derive", "curve25519-dalek-derive",
"digest", "digest 0.10.7",
"fiat-crypto", "fiat-crypto 0.2.9",
"rustc_version",
"subtle",
"zeroize",
]
[[package]]
name = "curve25519-dalek"
version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5eed333089e2e1c1ac8c6c0398e5e2497b4c9926ca6d0365ed1e099afa5bc23"
dependencies = [
"cfg-if",
"cpufeatures 0.3.1",
"curve25519-dalek-derive",
"fiat-crypto 0.3.0",
"rustc_version", "rustc_version",
"subtle", "subtle",
"zeroize", "zeroize",
@@ -209,7 +318,7 @@ version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
dependencies = [ dependencies = [
"const-oid", "const-oid 0.9.6",
"zeroize", "zeroize",
] ]
@@ -219,8 +328,19 @@ version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [ dependencies = [
"block-buffer", "block-buffer 0.10.4",
"crypto-common", "crypto-common 0.1.7",
]
[[package]]
name = "digest"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2"
dependencies = [
"block-buffer 0.12.1",
"const-oid 0.10.2",
"crypto-common 0.2.2",
] ]
[[package]] [[package]]
@@ -239,11 +359,11 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
dependencies = [ dependencies = [
"curve25519-dalek", "curve25519-dalek 4.1.3",
"ed25519", "ed25519",
"rand_core 0.6.4", "rand_core 0.6.4",
"serde", "serde",
"sha2", "sha2 0.10.9",
"subtle", "subtle",
"zeroize", "zeroize",
] ]
@@ -255,15 +375,19 @@ dependencies = [
"anyhow", "anyhow",
"axum", "axum",
"bs58", "bs58",
"chacha20poly1305",
"curve25519-dalek 5.0.0",
"ed25519-dalek", "ed25519-dalek",
"futures-util", "futures-util",
"rand 0.8.7", "rand 0.8.7",
"rusqlite", "rusqlite",
"serde", "serde",
"serde_json", "serde_json",
"sha2 0.11.0",
"tokio", "tokio",
"tower-http", "tower-http",
"uuid", "uuid",
"x25519-dalek",
] ]
[[package]] [[package]]
@@ -284,6 +408,12 @@ version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
[[package]]
name = "fiat-crypto"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24"
[[package]] [[package]]
name = "find-msvc-tools" name = "find-msvc-tools"
version = "0.1.11" version = "0.1.11"
@@ -393,6 +523,7 @@ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"r-efi 6.0.0", "r-efi 6.0.0",
"rand_core 0.10.1",
] ]
[[package]] [[package]]
@@ -464,6 +595,15 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hybrid-array"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b"
dependencies = [
"typenum",
]
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "1.11.0" version = "1.11.0"
@@ -499,6 +639,15 @@ dependencies = [
"tower-service", "tower-service",
] ]
[[package]]
name = "inout"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7"
dependencies = [
"hybrid-array",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.18" version = "1.0.18"
@@ -612,6 +761,16 @@ version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548"
[[package]]
name = "poly1305"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e2d0073b297041425c7c3df6eb4792d598a15323fe63346852b092eca02904c"
dependencies = [
"cpufeatures 0.3.1",
"universal-hash",
]
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.21" version = "0.2.21"
@@ -710,6 +869,12 @@ dependencies = [
"getrandom 0.3.4", "getrandom 0.3.4",
] ]
[[package]]
name = "rand_core"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
[[package]] [[package]]
name = "rusqlite" name = "rusqlite"
version = "0.31.0" version = "0.31.0"
@@ -824,8 +989,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"cpufeatures", "cpufeatures 0.2.17",
"digest", "digest 0.10.7",
] ]
[[package]] [[package]]
@@ -835,8 +1000,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"cpufeatures", "cpufeatures 0.2.17",
"digest", "digest 0.10.7",
]
[[package]]
name = "sha2"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4"
dependencies = [
"cfg-if",
"cpufeatures 0.3.1",
"digest 0.11.3",
] ]
[[package]] [[package]]
@@ -1113,6 +1289,16 @@ version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "universal-hash"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96"
dependencies = [
"crypto-common 0.2.2",
"ctutils",
]
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.24.1" version = "1.24.1"
@@ -1217,6 +1403,17 @@ version = "0.57.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
[[package]]
name = "x25519-dalek"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7e8131a03190127fb2263afc72b322ecadae46b6ff8c6f399ff5d02f5559af6"
dependencies = [
"curve25519-dalek 5.0.0",
"rand_core 0.10.1",
"zeroize",
]
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.8.56" version = "0.8.56"
+4
View File
@@ -16,3 +16,7 @@ tower-http = { version = "0.7.0", features = ["fs", "cors"] }
rusqlite = { version = "0.31", features = ["bundled"] } rusqlite = { version = "0.31", features = ["bundled"] }
uuid = { version = "1.24.1", features = ["v4"] } uuid = { version = "1.24.1", features = ["v4"] }
futures-util = "0.3.34" futures-util = "0.3.34"
x25519-dalek = { version = "3.0.0", features = ["static_secrets"] }
curve25519-dalek = "5.0.0"
sha2 = "0.11.0"
chacha20poly1305 = "0.11.0"
+120 -1
View File
@@ -1,7 +1,17 @@
use std::path::PathBuf; use std::{path::PathBuf, sync::Arc};
use axum::extract::ws::WebSocket;
use chacha20poly1305::{
ChaCha20Poly1305, Key, Nonce,
aead::{Aead, KeyInit},
};
use curve25519_dalek::edwards::CompressedEdwardsY;
use ed25519_dalek::{Signature, SigningKey, VerifyingKey}; use ed25519_dalek::{Signature, SigningKey, VerifyingKey};
use rand::rngs::OsRng; use rand::rngs::OsRng;
use sha2::{Digest, Sha512};
use x25519_dalek::{PublicKey as X25519Public, SharedSecret, StaticSecret as X25519Secret};
use crate::{server::Server, ws::EnclaveWebSocket};
pub async fn get() -> anyhow::Result<SigningKey> { pub async fn get() -> anyhow::Result<SigningKey> {
let private_key_path = PathBuf::from("private.key"); let private_key_path = PathBuf::from("private.key");
@@ -45,3 +55,112 @@ pub fn from_string_sig(signature: &str) -> anyhow::Result<Signature> {
.map_err(|_| anyhow::anyhow!("Invalid signature"))?, .map_err(|_| anyhow::anyhow!("Invalid signature"))?,
)) ))
} }
pub fn ed25519_signing_key_to_x25519(signing_key: &SigningKey) -> X25519Secret {
let hash = Sha512::digest(signing_key.as_bytes());
let mut scalar_bytes = [0u8; 32];
scalar_bytes.copy_from_slice(&hash[..32]);
X25519Secret::from(scalar_bytes) // clamping happens internally
}
pub fn ed25519_verifying_key_to_x25519(verifying_key: &VerifyingKey) -> Option<X25519Public> {
let compressed = CompressedEdwardsY(verifying_key.to_bytes());
let edwards_point = compressed.decompress()?;
Some(X25519Public::from(edwards_point.to_montgomery().to_bytes()))
}
pub struct SessionCipher {
cipher: ChaCha20Poly1305,
send_counter: u64,
recv_counter: u64,
}
impl SessionCipher {
pub fn new(shared_secret: &SharedSecret) -> anyhow::Result<Self> {
// SharedSecret's raw bytes ARE suitable for direct use as a ChaCha20Poly1305 key
// (both are 32 bytes), though in a hardened design you'd typically run this
// through a KDF (e.g. HKDF) rather than using the raw ECDH output directly.
let key = Key::try_from(shared_secret.as_bytes().as_slice())?;
Ok(Self {
cipher: ChaCha20Poly1305::new(&key),
send_counter: 0,
recv_counter: 0,
})
}
pub fn next_send_nonce(&mut self) -> [u8; 12] {
let mut nonce = [0u8; 12];
nonce[..8].copy_from_slice(&self.send_counter.to_be_bytes());
// top bit distinguishes "send" direction from "recv" direction,
// so client-send and server-send counters never collide even if
// both happened to reach the same numeric value
nonce[11] |= 0b1000_0000;
self.send_counter += 1;
nonce
}
pub fn next_recv_nonce(&mut self) -> [u8; 12] {
let mut nonce = [0u8; 12];
nonce[..8].copy_from_slice(&self.recv_counter.to_be_bytes());
self.recv_counter += 1;
nonce
}
pub fn encrypt(&mut self, plaintext: &[u8]) -> anyhow::Result<Vec<u8>> {
let nonce_bytes = self.next_send_nonce();
let nonce = Nonce::try_from(nonce_bytes)?;
let ciphertext = self
.cipher
.encrypt(&nonce, plaintext)
.map_err(|_| anyhow::anyhow!("encryption failed"))?;
// prepend the nonce so the other side can reconstruct it on decrypt
let mut out = nonce_bytes.to_vec();
out.extend(ciphertext);
Ok(out)
}
pub fn decrypt(&mut self, data: &[u8]) -> anyhow::Result<Vec<u8>> {
if data.len() < 12 {
anyhow::bail!("message too short to contain a nonce");
}
let (nonce_bytes, ciphertext) = data.split_at(12);
let nonce = Nonce::try_from(nonce_bytes)?;
self.cipher
.decrypt(&nonce, ciphertext)
.map_err(|_| anyhow::anyhow!("decryption failed"))
}
}
pub async fn crypto_handshake(
server: &Arc<Server>,
mut socket: WebSocket,
) -> anyhow::Result<Arc<EnclaveWebSocket>> {
socket
.send(axum::extract::ws::Message::Binary(
server.x_keypair.0.to_bytes().to_vec().into(),
))
.await?;
let axum::extract::ws::Message::Binary(raw_pubkey) = socket
.recv()
.await
.transpose()?
.ok_or(anyhow::anyhow!("Failed to get client x key"))?
else {
return Err(anyhow::anyhow!(""));
};
let client_pubkey = X25519Public::from(*raw_pubkey.as_array().ok_or(anyhow::anyhow!(
"Failed to get proper length of client x key"
))?);
let shared_secret = server.x_keypair.1.diffie_hellman(&client_pubkey);
let cipher = SessionCipher::new(&shared_secret)?;
Ok(Arc::new(EnclaveWebSocket::new(socket, cipher)))
}
+3 -14
View File
@@ -4,7 +4,6 @@ use std::{
}; };
use ed25519_dalek::{Signer, VerifyingKey}; use ed25519_dalek::{Signer, VerifyingKey};
use futures_util::SinkExt;
use crate::{server::Server, ws::EnclaveWebSocket}; use crate::{server::Server, ws::EnclaveWebSocket};
@@ -14,18 +13,8 @@ use crate::server::UserConnections;
impl UserConnections { impl UserConnections {
pub async fn initialize( pub async fn initialize(
server: &Arc<Server>, server: &Arc<Server>,
socket: Arc<EnclaveWebSocket>, socket: &Arc<EnclaveWebSocket>,
) -> anyhow::Result<(Arc<EnclaveWebSocket>, VerifyingKey, ClientMeta)> { ) -> anyhow::Result<(VerifyingKey, ClientMeta)> {
{
socket
.tx()
.await
.send(axum::extract::ws::Message::Binary(
server.key.verifying_key().to_bytes().to_vec().into(),
))
.await?;
}
let Some(ServerMethod::Initialize { let Some(ServerMethod::Initialize {
public_key: public_key_string, public_key: public_key_string,
signature, signature,
@@ -122,6 +111,6 @@ impl UserConnections {
)); ));
}; };
Ok((socket, public_key, meta)) Ok((public_key, meta))
} }
} }
+16 -4
View File
@@ -21,8 +21,8 @@ use crate::{
data::{config::Config, messages::MessageStore, users::UserMetaStore}, data::{config::Config, messages::MessageStore, users::UserMetaStore},
protocol::{ClientMethod, read_loop}, protocol::{ClientMethod, read_loop},
types::ClientMeta, types::ClientMeta,
ws::EnclaveWebSocket,
}; };
use x25519_dalek::{PublicKey as X25519Public, StaticSecret as X25519Secret};
pub struct VoiceConnection { pub struct VoiceConnection {
pub addr: SocketAddr, pub addr: SocketAddr,
@@ -40,6 +40,7 @@ pub struct UserConnections {
pub struct Server { pub struct Server {
pub key: SigningKey, pub key: SigningKey,
pub x_keypair: (X25519Public, X25519Secret),
pub config: Config, pub config: Config,
pub clients: Mutex<HashMap<VerifyingKey, Arc<UserConnections>>>, pub clients: Mutex<HashMap<VerifyingKey, Arc<UserConnections>>>,
pub voice_pins: Mutex<HashMap<u64, (VerifyingKey, String)>>, pub voice_pins: Mutex<HashMap<u64, (VerifyingKey, String)>>,
@@ -50,8 +51,14 @@ pub struct Server {
impl Server { impl Server {
pub async fn new() -> anyhow::Result<Arc<Self>> { pub async fn new() -> anyhow::Result<Arc<Self>> {
let key = crate::crypto::get().await?;
Ok(Arc::new(Self { Ok(Arc::new(Self {
key: crate::crypto::get().await?, x_keypair: (
crate::crypto::ed25519_verifying_key_to_x25519(&key.verifying_key())
.ok_or(anyhow::anyhow!("Failed to convert ed pubkey to x"))?,
crate::crypto::ed25519_signing_key_to_x25519(&key),
),
key,
config: Config::get().await?, config: Config::get().await?,
clients: Mutex::new(HashMap::new()), clients: Mutex::new(HashMap::new()),
voice_pins: Mutex::new(HashMap::new()), voice_pins: Mutex::new(HashMap::new()),
@@ -67,8 +74,13 @@ impl Server {
let s = self.clone(); let s = self.clone();
ws.on_upgrade(move |socket: WebSocket| async move { ws.on_upgrade(move |socket: WebSocket| async move {
match UserConnections::initialize(&s, Arc::new(EnclaveWebSocket::new(socket))).await { let Ok(client) = crate::crypto::crypto_handshake(&s, socket).await else {
Ok((client, public_key, meta)) => { eprintln!("Filed to initialize crypto");
return;
};
match UserConnections::initialize(&s, &client).await {
Ok((public_key, meta)) => {
if let Err(e) = s if let Err(e) = s
.user_store .user_store
.upsert_user(&crate::crypto::to_string(&public_key), &meta) .upsert_user(&crate::crypto::to_string(&public_key), &meta)
+31 -11
View File
@@ -1,26 +1,31 @@
use std::borrow::Cow; use std::borrow::Cow;
use axum::extract::ws::{Message, Utf8Bytes, WebSocket}; use axum::extract::ws::{Message, WebSocket};
use futures_util::{ use futures_util::{
SinkExt, StreamExt, SinkExt, StreamExt,
stream::{SplitSink, SplitStream}, stream::{SplitSink, SplitStream},
}; };
use tokio::sync::{Mutex, MutexGuard}; use tokio::sync::Mutex;
use crate::protocol::{ClientMethod, ServerMethod}; use crate::{
crypto::SessionCipher,
protocol::{ClientMethod, ServerMethod},
};
pub struct EnclaveWebSocket { pub struct EnclaveWebSocket {
tx: Mutex<SplitSink<WebSocket, Message>>, tx: Mutex<SplitSink<WebSocket, Message>>,
rx: Mutex<SplitStream<WebSocket>>, rx: Mutex<SplitStream<WebSocket>>,
cihper: Mutex<SessionCipher>,
} }
impl EnclaveWebSocket { impl EnclaveWebSocket {
pub fn new(ws: WebSocket) -> Self { pub fn new(ws: WebSocket, cipher: SessionCipher) -> Self {
let (tx, rx) = ws.split(); let (tx, rx) = ws.split();
Self { Self {
tx: Mutex::new(tx), tx: Mutex::new(tx),
rx: Mutex::new(rx), rx: Mutex::new(rx),
cihper: Mutex::new(cipher),
} }
} }
@@ -39,6 +44,23 @@ impl EnclaveWebSocket {
} }
}, },
Some(Message::Binary(encrypted)) => {
let text = String::from_utf8(self.cihper.lock().await.decrypt(&encrypted)?)?;
match serde_json::from_str(&text.to_string()) {
Ok(msg) => Ok(Some(msg)),
Err(e) => {
self.send(&ClientMethod::Error {
error: Cow::Owned(format!("Unable to parse message: {e}")),
})
.await?;
Ok(None)
}
}
}
Some(Message::Ping(v)) => { Some(Message::Ping(v)) => {
self.tx.lock().await.send(Message::Pong(v)).await?; self.tx.lock().await.send(Message::Pong(v)).await?;
@@ -52,18 +74,16 @@ impl EnclaveWebSocket {
} }
pub async fn send(&self, message: &ClientMethod) -> anyhow::Result<()> { pub async fn send(&self, message: &ClientMethod) -> anyhow::Result<()> {
let text = serde_json::to_string(message)?;
let encrypted = self.cihper.lock().await.encrypt(text.as_bytes())?;
self.tx self.tx
.lock() .lock()
.await .await
.send(Message::Text(Utf8Bytes::from(serde_json::to_string( .send(Message::Binary(encrypted.into()))
message,
)?)))
.await?; .await?;
Ok(()) Ok(())
} }
pub async fn tx(&self) -> MutexGuard<'_, SplitSink<WebSocket, Message>> {
self.tx.lock().await
}
} }