use std::io::Read; use bytes::Bytes; use p256::EncodedPoint; use p256::ecdsa::{ Signature, SigningKey, VerifyingKey, signature::{Signer, Verifier}, }; use rand_core::OsRng; 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, pub username: String, } impl CryptographicSignature { /// /// creates a CryptographicSignature /// pub fn new(username: String) -> CryptographicSignature { // generate a private key let priv_key = SigningKey::random(&mut OsRng); // extract the public key from the private key let pub_key = VerifyingKey::from(&priv_key); // return the new struct CryptographicSignature { priv_key: priv_key, pub_key: pub_key, username: username, } } } /// /// returns a string representing the pub_key as a String /// pub fn formatPubKey(crypto_pair: CryptographicSignature) -> String { let encoded_point = crypto_pair.pub_key.to_encoded_point(false); let pubkey_bytes = encoded_point.as_bytes(); hex::encode(pubkey_bytes) } pub async fn get_peer_key(username: &String) -> Result { 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) -> 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 /// pub fn sign_message(crypto_pair: &CryptographicSignature, message: &Vec) -> Vec { let length_bytes: [u8; 2] = message[5..7] .try_into() .expect("slice with incorrect length"); let msg_length = u16::from_be_bytes(length_bytes); println!( "message to serialize: {:?}", &message[..7 + msg_length as usize] ); let digest = Sha256::digest(&message[..7 + msg_length as usize]); let signature = crypto_pair.priv_key.sign_prehash_recoverable(&digest); let message_length = 7 + msg_length as usize + 64; let mut signed_message = Vec::with_capacity(message_length); println!("{}", message_length); signed_message.extend_from_slice(&message[..7 + msg_length as usize]); println!("signed_tmp:{:?}", signed_message); match signature { Ok(signature) => { let r = signature.0.r(); let s = signature.0.s(); let r_bytes = r.to_bytes(); // Returns a GenericArray/bytes object let s_bytes = s.to_bytes(); signed_message.extend_from_slice(&r_bytes[..32]); signed_message.extend_from_slice(&s_bytes[..32]); println!("signed:{:?}, len: {}", signed_message, signed_message.len()); signed_message } Err(e) => { panic!("error"); } } } #[cfg(test)] mod tests { use super::*; /// /// creates a cryptographic signature /// #[test] fn creating_cryptographic_signature() { let username = String::from("gamixtreize"); let crypto_pair = CryptographicSignature::new(username); let formatted_pubkey = formatPubKey(crypto_pair); println!("pubkey : {}", formatted_pubkey); } /*#[test] fn signing_message() { let username = String::from("gamixtreize"); let crypto_pair = CryptographicSignature::new(username.clone()); let handshake = HandshakeMessage::hello(0, 12, username); let ser = handshake.serialize(); let signed_message = sign_message(&crypto_pair, &ser); println!("unsigned_message: {:?}", ser); println!("signed_message: {:?}", signed_message); }*/ }