165 lines
5.2 KiB
Rust
165 lines
5.2 KiB
Rust
use std::io::Read;
|
|
|
|
use crate::messages_structure::HandshakeMessage;
|
|
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<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
|
|
///
|
|
pub fn sign_message(crypto_pair: &CryptographicSignature, message: &Vec<u8>) -> Vec<u8> {
|
|
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 = 12 + msg_length as usize + 32;
|
|
let mut signed_message = Vec::with_capacity(message_length);
|
|
println!("{}", message_length);
|
|
signed_message.extend_from_slice(&message[..8 + msg_length as usize]);
|
|
signed_message.pop();
|
|
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:{:?}", signed_message);
|
|
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);
|
|
}
|
|
|
|
///
|
|
/// signs a message
|
|
///
|
|
#[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);
|
|
}
|
|
}
|