2 Commits

Author SHA1 Message Date
c804695725 signature verification 2025-12-31 19:40:25 +01:00
cc09fab16d message handling and serv registration 2025-12-30 20:18:18 +01:00
8 changed files with 254 additions and 46 deletions

View File

@@ -25,6 +25,7 @@ pub struct P2PClientApp {
status_message: String,
known_peers: Vec<String>,
connect_address_input: String,
connect_server_name_input: String,
// Key: Parent Directory Hash (String), Value: List of children FileNode
loaded_fs: HashMap<String, MerkleTree>,
@@ -48,7 +49,8 @@ impl P2PClientApp {
network_event_rx: event_rx,
status_message: "Client Initialized. Awaiting network status...".to_string(),
known_peers: vec!["bob".to_string()],
connect_address_input: "127.0.0.1:8080".to_string(),
connect_address_input: "https://jch.irif.fr:8443".to_string(),
connect_server_name_input: "jch.irif.fr".to_string(),
loaded_fs,
active_peer: None,
server_status: ServerStatus::Loading,
@@ -125,11 +127,13 @@ impl eframe::App for P2PClientApp {
ui.horizontal(|ui| {
ui.label("Server IP:");
ui.text_edit_singleline(&mut self.connect_address_input);
ui.text_edit_singleline(&mut self.connect_server_name_input);
if ui.button("Connect").clicked() {
let addr = self.connect_address_input.clone();
let serv_name = self.connect_server_name_input.clone();
let _ = self
.network_cmd_tx
.send(NetworkCommand::ConnectToServer(addr));
.send(NetworkCommand::ConnectToServer(addr, serv_name));
self.server_status = ServerStatus::Loading;
ui.close();
}

View File

@@ -1,4 +1,8 @@
use std::io::Read;
use crate::messages_structure::HandshakeMessage;
use bytes::Bytes;
use p256::EncodedPoint;
use p256::ecdsa::{
Signature, SigningKey, VerifyingKey,
signature::{Signer, Verifier},
@@ -9,6 +13,7 @@ use sha2::{Digest, Sha256};
///
/// contains the ecdsa private key, the ecdsa public key and the username
///
///
pub struct CryptographicSignature {
priv_key: SigningKey,
pub pub_key: VerifyingKey,
@@ -42,6 +47,53 @@ pub fn formatPubKey(crypto_pair: CryptographicSignature) -> String {
hex::encode(pubkey_bytes)
}
pub async fn get_peer_key(username: &String) -> Result<VerifyingKey, reqwest::Error> {
let client = reqwest::Client::new();
let uri = format!("https://jch.irif.fr:8443/peers/{}/key", username);
let res = client.get(uri).send().await?;
if res.status().is_success() {
println!("Successfully retreived the peers key.");
} else {
eprintln!(
"Failed to get the peers key from the server. Status: {}",
res.status()
);
}
let body: Bytes = res.bytes().await?;
let slice: &[u8] = body.as_ref();
let body_bytes: &[u8; 64] = slice.try_into().expect("size error");
let received_key = convert_verifyingkey(body_bytes);
Ok(received_key)
}
fn convert_verifyingkey(raw_xy: &[u8; 64]) -> VerifyingKey {
let mut sec1 = [0u8; 65];
sec1[0] = 0x04;
sec1[1..].copy_from_slice(raw_xy);
let ep = EncodedPoint::from_bytes(&sec1).expect("invalid point bytes");
let pk = VerifyingKey::from_encoded_point(&ep).expect("invalid encoded point");
VerifyingKey::from(pk)
}
pub fn verify_signature(pubkey: VerifyingKey, message: &Vec<u8>) -> bool {
let length_bytes: [u8; 2] = message[5..7].try_into().expect("Taille incorrecte");
let length = u16::from_be_bytes(length_bytes);
println!("message length: {}", length);
let msg_to_hash = &message[..length as usize + 7];
let signature_bytes = &message[length as usize + 7..length as usize + 7 + 64];
println!("conversion start");
let sig = match Signature::from_bytes(signature_bytes.try_into().expect("conversion error")) {
Ok(s) => s,
Err(_) => return false,
};
println!("conversion done");
match pubkey.verify(&msg_to_hash, &sig) {
Ok(()) => true,
Err(_) => false,
}
}
///
/// takes a serialized message and adds the signature using the private key
///

View File

@@ -9,7 +9,9 @@ use crate::{
cryptographic_signature::CryptographicSignature,
message_handling::EventType,
messages_channels::{MultipleSenders, start_receving_thread},
registration::{register_ip_addresses, register_with_the_server},
registration::{
get_socket_address, parse_addresses, register_ip_addresses, register_with_the_server,
},
};
use std::sync::{Arc, Mutex};
use std::{
@@ -19,8 +21,8 @@ use std::{
/// Messages sent to the Network thread by the GUI.
pub enum NetworkCommand {
ConnectToServer(String), // ServerIP
FetchPeerList(String), // ServerIP
ConnectToServer(String, String), // ServerIP
FetchPeerList(String), // ServerIP
RegisterAsPeer(String),
Ping(),
ConnectPeer(String), // IP:PORT
@@ -95,14 +97,14 @@ pub fn start_p2p_executor(
NetworkCommand::RequestChunk(_, _) => {
println!("[Network] RequestChunk() called");
}
NetworkCommand::ConnectToServer(ip) => {
NetworkCommand::ConnectToServer(ip, server_name) => {
println!("[Network] ConnectToServer() called");
// Actual server connection
let messages_list = HashMap::<i32, EventType>::new();
let username = String::from("Gamixtreize");
let username = String::from("az");
let crypto_pair = CryptographicSignature::new(username);
@@ -119,25 +121,41 @@ pub fn start_p2p_executor(
eprintln!("request failed: {}", e);
}
match SocketAddr::from_str(&ip) {
Ok(sockaddr) => {
start_receving_thread(
&shared_socket,
&shared_messageslist,
&shared_cryptopair,
sockaddr,
&shared_senders,
);
register_ip_addresses(
&shared_cryptopair,
ip,
&shared_senders,
&shared_messageslist,
);
}
Err(e) => {
eprintln!("failed to parse socket address: {}", e);
println!("ip: {}", ip);
let server_addr_query = get_socket_address(server_name);
match server_addr_query.await {
Ok(sockaddr_bytes) => {
match String::from_utf8(sockaddr_bytes.to_vec()) {
Ok(s) => {
let addresses = parse_addresses(&s);
if let Some(first) = addresses.first() {
// first: &SocketAddr
start_receving_thread(
&shared_socket,
&shared_messageslist,
&shared_cryptopair,
*first, // copie le SocketAddr (implémente Copy pour SocketAddr)
&shared_senders,
);
register_ip_addresses(
&shared_cryptopair,
first.to_string(),
&shared_senders,
&shared_messageslist,
545,
);
} else {
eprintln!("no valid socket addresses found in: {}", s);
}
}
Err(e) => {
eprintln!("invalid UTF-8 in socket address bytes: {}", e);
}
}
}
Err(e) => eprintln!("failed to retrieve socket address: {}", e),
}
tokio::time::sleep(std::time::Duration::from_millis(5000)).await;

View File

@@ -0,0 +1,112 @@
use crate::{
cryptographic_signature::{
CryptographicSignature, get_peer_key, sign_message, verify_signature,
},
messages_channels::MultipleSenders,
messages_structure::HandshakeMessage,
registration,
};
use std::sync::{Arc, Mutex};
use std::{collections::HashMap, net::SocketAddr};
pub enum EventType {
ServerHelloReply,
PeerHelloReply,
PeerHello,
}
/*pub fn handle_recevied_message(
messages_list: &mut HashMap<i32, EventType>,
recevied_message: &Vec<u8>,
crypto_pair: &CryptographicSignature,
socket_addr: &SocketAddr,
senders: &MultipleSenders,
) {
let message_id: [u8; 4] = recevied_message[0..4].try_into().expect("size error");
let id = i32::from_be_bytes(message_id);
let eventtype = messages_list.get(&id);
match eventtype {
Some(EventType::ServerHelloReply) => {
registration::register_ip_addresses(
&crypto_pair,
socket_addr.ip().to_string(),
&senders,
messages_list,
);
}
Some(_) => print!("Not implemented"),
None => print!("Message not found"),
}
}*/
pub fn handle_recevied_message(
messages_list: &Arc<Mutex<HashMap<i32, EventType>>>,
recevied_message: &Vec<u8>,
crypto_pair: &CryptographicSignature,
socket_addr: &SocketAddr,
senders: &MultipleSenders,
) {
if recevied_message.len() < 4 {
return;
} // Basic safety check
let message_id: [u8; 4] = recevied_message[0..4].try_into().expect("size error");
let id = i32::from_be_bytes(message_id);
// Lock the mutex to access the HashMap
let list = messages_list.lock().unwrap();
let eventtype = list.get(&id); // Clone the enum so we can release the lock if needed
match eventtype {
Some(EventType::ServerHelloReply) => {
/*registration::register_ip_addresses(
crypto_pair,
socket_addr.to_string(),
senders,
&messages_list, // Pass the mutable reference inside the lock
546,
);*/
}
Some(_) => print!("Not implemented"),
None => {
let message_type = recevied_message[4];
if message_type == 1 {
println!("verify the signature");
let parsed_received_message = HandshakeMessage::parse(recevied_message.to_vec());
let received_name = String::from_utf8(parsed_received_message.name).expect("error");
let peer_pubkey = tokio::runtime::Runtime::new()
.unwrap()
.block_on(get_peer_key(&received_name))
.expect("failed to retrieve public key");
if !verify_signature(peer_pubkey, recevied_message) {
println!(
"incorrect signature from given peer: {}, ignoring message {}",
&received_name, id
);
} else {
let username_size = crypto_pair.username.len();
let hello_handshake = HandshakeMessage::helloReply(
id as u32,
username_size as u16 + 4,
crypto_pair.username.clone(),
);
//HandshakeMessage::display(&hello_handshake);
let hello_handshake_serialized = hello_handshake.serialize();
let message_signed = sign_message(crypto_pair, &hello_handshake_serialized);
senders.send_via(0, message_signed, socket_addr.to_string());
let mut list = messages_list.lock().expect("Failed to lock messages_list");
match list.get(&id) {
Some(_) => {
list.remove(&id);
}
None => {
list.insert(id, EventType::ServerHelloReply);
}
}
}
}
print!("Message not found for ID: {}", id)
}
}
}

View File

@@ -47,7 +47,10 @@ impl MultipleSenders {
for msg in rx {
// Use the cloned Arc inside the thread
if let Err(e) = sock_clone.send_to(&msg.payload, &msg.address) {
eprintln!("Erreur d'envoi sur canal {}: {}", i, e);
eprintln!(
"Erreur d'envoi sur canal {}: {}, address: {}",
i, e, &msg.address
);
} else {
let message_id: [u8; 4] = msg.payload[0..4].try_into().expect("size error");
let id = i32::from_be_bytes(message_id);
@@ -85,6 +88,7 @@ impl MultipleSenders {
let sock_clone = Arc::clone(socket);
let cryptopair_clone = Arc::clone(crypto_pair);
let senders_clone = Arc::clone(senders);
let messages_clone = Arc::clone(messages_list);
thread::spawn(move || {
let mut buf = [0u8; 1024];
@@ -123,9 +127,9 @@ pub fn start_receving_thread(
loop {
match sock_clone.recv_from(&mut buf) {
Ok((amt, src)) => {
// Only send the part of the buffer that contains data
let received_data = buf[..amt].to_vec();
println!("Reçu {} octets de {}: {:?}", amt, src, received_data);
handle_recevied_message(
&messages_clone,
&received_data,
@@ -133,7 +137,6 @@ pub fn start_receving_thread(
&socket_addr,
&senders_clone,
);
println!("Reçu {} octets de {}: {:?}", amt, src, received_data);
}
Err(e) => eprintln!("Erreur de réception: {}", e),
}

View File

@@ -7,12 +7,12 @@ pub struct UDPMessage {
}
pub struct HandshakeMessage {
id: u32,
pub id: u32,
msg_type: u8,
length: u16,
extensions: u32,
name: Vec<u8>,
signature: Vec<u8>,
pub name: Vec<u8>,
pub signature: Vec<u8>,
}
impl UDPMessage {
@@ -130,9 +130,9 @@ impl HandshakeMessage {
let extensions_bytes: [u8; 4] = received_message[7..11]
.try_into()
.expect("Taille incorrecte");
let name_bytes = &received_message[11..12 + msg_length as usize];
let name_bytes = &received_message[11..(11 + msg_length - 4) as usize];
let signature_bytes =
&received_message[12 + msg_length as usize..(13 + msg_length + 32) as usize];
&received_message[(11 + msg_length - 4) as usize..(11 + msg_length - 4 + 64) as usize];
HandshakeMessage {
id: u32::from_be_bytes(id_bytes),
msg_type: received_message[4],

View File

@@ -7,6 +7,7 @@ use crate::messages_structure::{HandshakeMessage, UDPMessage};
use std::collections::HashMap;
use std::net::SocketAddr;
use std::net::UdpSocket;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
///
@@ -39,7 +40,7 @@ pub async fn register_with_the_server(
/// sends a get request to the server to get the socket address of the given peer
///
async fn get_socket_address(username: String) -> Result<Bytes, reqwest::Error> {
pub async fn get_socket_address(username: String) -> Result<Bytes, reqwest::Error> {
let client = reqwest::Client::new();
let uri = format!("https://jch.irif.fr:8443/peers/{}/addresses", username);
let res = client.get(uri).send().await?;
@@ -47,7 +48,7 @@ async fn get_socket_address(username: String) -> Result<Bytes, reqwest::Error> {
println!("Successfully retreived the addresses.");
} else {
eprintln!(
"Failed to register with the server. Status: {}",
"Failed to get the peers addresses from the server. Status: {}",
res.status()
);
}
@@ -55,6 +56,20 @@ async fn get_socket_address(username: String) -> Result<Bytes, reqwest::Error> {
Ok(body)
}
pub fn parse_addresses(input: &String) -> Vec<SocketAddr> {
let mut addrs = Vec::new();
for line in input.lines() {
let s = line.trim();
if s.is_empty() {
continue;
}
if let Ok(sock) = SocketAddr::from_str(s) {
addrs.push(sock);
}
}
addrs
}
///
/// registers the IP addresses by sending a Hello request to the server.
///
@@ -63,21 +78,25 @@ pub fn register_ip_addresses(
server_uri: String,
senders: &MultipleSenders,
messages_list: &Arc<Mutex<HashMap<i32, EventType>>>,
id: i32,
) {
let username_size = crypto_pair.username.len();
let hello_handshake =
HandshakeMessage::hello(545, username_size as u16 + 4, crypto_pair.username.clone());
let hello_handshake = HandshakeMessage::hello(
id as u32,
username_size as u16 + 4,
crypto_pair.username.clone(),
);
//HandshakeMessage::display(&hello_handshake);
let hello_handshake_serialized = hello_handshake.serialize();
let message_signed = sign_message(crypto_pair, &hello_handshake_serialized);
senders.send_via(0, message_signed, server_uri);
let mut list = messages_list.lock().expect("Failed to lock messages_list");
match list.get(&545) {
match list.get(&id) {
Some(_) => {
list.remove(&545);
list.remove(&id);
}
None => {
list.insert(545, EventType::ServerHelloReply);
list.insert(id, EventType::ServerHelloReply);
}
}
// 3. Perform the insertion

10
todo.md
View File

@@ -5,12 +5,12 @@
## registration with the server
- generation of the cryptographic key OK
- put request to the uri (check if the peer is already connected) OK
- udp handshakes
- get request to the uri /peers/key to get the public key of a peer
- get request to the uri /peers/key/addresses
- udp handshakes OK
- get request to the uri /peers/key to get the public key of a peer OK
- get request to the uri /peers/key/addresses OK
## handshake
- handshake structure
- handshake structure OK
- 5min timeout after handshake
- matain connection every 4 min
@@ -32,4 +32,4 @@ telechargement des fichiers
choisir un dossier à partager
se deconnecter du réseau
2 channels -> un pour envoyer et un pour recevoir
2 channels -> un pour envoyer et un pour recevoir OK