Remove handshake buffers from Session attributes
This commit is contained in:
parent
ece419f063
commit
ff4c78a951
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "async-psec"
|
name = "async-psec"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
authors = ["Hardcore Sushi <hardcore.sushi@disroot.org>"]
|
authors = ["Hardcore Sushi <hardcore.sushi@disroot.org>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "Asynchronous PSEC implementation"
|
description = "Asynchronous PSEC implementation"
|
||||||
|
48
src/lib.rs
48
src/lib.rs
@ -1,6 +1,6 @@
|
|||||||
/*! Asynchronous PSEC implementation.
|
/*! Asynchronous PSEC implementation.
|
||||||
|
|
||||||
PSEC (Peer-to-peer Secure Ephemeral Communications) is a simplification/adaptation of TLS 1.3 for P2P networks which provides an encrypted and authenticated secure transport layer for ephemeral communications. PSEC ensures deniability, forward secrecy, future secrecy, and optional plaintext length obfuscation. This crate is an implementation of this protocol built with the [tokio] framework.
|
[PSEC](https://github.com/hardcore-sushi/PSEC) (Peer-to-peer Secure Ephemeral Communications) is a simplification/adaptation of TLS 1.3 for P2P networks which provides an encrypted and authenticated secure transport layer for ephemeral communications. PSEC ensures deniability, forward secrecy, future secrecy, and optional plaintext length obfuscation. This crate is an implementation of this protocol built with the [tokio] framework.
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
Add this in your `Cargo.toml`:
|
Add this in your `Cargo.toml`:
|
||||||
@ -390,8 +390,6 @@ impl Debug for SessionWriteHalf {
|
|||||||
/// A PSEC connection.
|
/// A PSEC connection.
|
||||||
pub struct Session {
|
pub struct Session {
|
||||||
stream: TcpStream,
|
stream: TcpStream,
|
||||||
handshake_sent_buff: Vec<u8>,
|
|
||||||
handshake_recv_buff: Vec<u8>,
|
|
||||||
local_cipher: Option<Aes128Gcm>,
|
local_cipher: Option<Aes128Gcm>,
|
||||||
local_iv: Option<[u8; crypto::IV_LEN]>,
|
local_iv: Option<[u8; crypto::IV_LEN]>,
|
||||||
local_counter: usize,
|
local_counter: usize,
|
||||||
@ -495,23 +493,23 @@ impl Session {
|
|||||||
send(&mut self.stream, buff).await
|
send(&mut self.stream, buff).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handshake_read(&mut self, buff: &mut [u8]) -> Result<(), PsecError> {
|
async fn handshake_read(&mut self, buff: &mut [u8], handshake_recv_buff: &mut Vec<u8>) -> Result<(), PsecError> {
|
||||||
self.receive(buff).await?;
|
self.receive(buff).await?;
|
||||||
self.handshake_recv_buff.extend(buff.as_ref());
|
handshake_recv_buff.extend(buff.as_ref());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handshake_write(&mut self, buff: &[u8]) -> Result<(), PsecError> {
|
async fn handshake_write(&mut self, buff: &[u8], handshake_sent_buff: &mut Vec<u8>) -> Result<(), PsecError> {
|
||||||
self.send(buff).await?;
|
self.send(buff).await?;
|
||||||
self.handshake_sent_buff.extend(buff);
|
handshake_sent_buff.extend(buff);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_handshake(&self, i_am_bob: bool) -> [u8; 48] {
|
fn hash_handshake(i_am_bob: bool, handshake_sent_buff: &[u8], handshake_recv_buff: &[u8]) -> [u8; 48] {
|
||||||
let handshake_bytes = if i_am_bob {
|
let handshake_bytes = if i_am_bob {
|
||||||
[self.handshake_sent_buff.as_slice(), self.handshake_recv_buff.as_slice()].concat()
|
[handshake_sent_buff, handshake_recv_buff].concat()
|
||||||
} else {
|
} else {
|
||||||
[self.handshake_recv_buff.as_slice(), self.handshake_sent_buff.as_slice()].concat()
|
[handshake_recv_buff, handshake_sent_buff].concat()
|
||||||
};
|
};
|
||||||
let mut hasher = Sha384::new();
|
let mut hasher = Sha384::new();
|
||||||
hasher.update(handshake_bytes);
|
hasher.update(handshake_bytes);
|
||||||
@ -519,21 +517,19 @@ impl Session {
|
|||||||
handshake_hash.as_slice().try_into().unwrap()
|
handshake_hash.as_slice().try_into().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_handshake_successful(&mut self, application_keys: ApplicationKeys){
|
fn init_ciphers(&mut self, application_keys: ApplicationKeys){
|
||||||
self.local_cipher = Some(Aes128Gcm::new_from_slice(&application_keys.local_key).unwrap());
|
self.local_cipher = Some(Aes128Gcm::new_from_slice(&application_keys.local_key).unwrap());
|
||||||
self.local_iv = Some(application_keys.local_iv);
|
self.local_iv = Some(application_keys.local_iv);
|
||||||
self.peer_cipher = Some(Aes128Gcm::new_from_slice(&application_keys.peer_key).unwrap());
|
self.peer_cipher = Some(Aes128Gcm::new_from_slice(&application_keys.peer_key).unwrap());
|
||||||
self.peer_iv = Some(application_keys.peer_iv);
|
self.peer_iv = Some(application_keys.peer_iv);
|
||||||
self.handshake_sent_buff.clear();
|
|
||||||
self.handshake_sent_buff.shrink_to_fit();
|
|
||||||
self.handshake_recv_buff.clear();
|
|
||||||
self.handshake_recv_buff.shrink_to_fit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Performing a PSEC handshake.
|
/** Performing a PSEC handshake.
|
||||||
|
|
||||||
If successful, the `Session` is ready to send and receive data and you can retrieve the peer public key with the [`peer_public_key`](Session::peer_public_key) attribute. Otherwise, trying to encrypt or decrypt data with this session will panic.*/
|
If successful, the `Session` is ready to send and receive data and you can retrieve the peer public key with the [`peer_public_key`](Session::peer_public_key) attribute. Otherwise, trying to encrypt or decrypt data with this session will panic.*/
|
||||||
pub async fn do_handshake(&mut self, identity: &Identity) -> Result<(), PsecError> {
|
pub async fn do_handshake(&mut self, identity: &Identity) -> Result<(), PsecError> {
|
||||||
|
let mut handshake_sent_buff = Vec::new();
|
||||||
|
let mut handshake_recv_buff = Vec::new();
|
||||||
//ECDHE initial exchange
|
//ECDHE initial exchange
|
||||||
//generate random bytes
|
//generate random bytes
|
||||||
let mut handshake_buffer = [0; RANDOM_LEN+PUBLIC_KEY_LENGTH];
|
let mut handshake_buffer = [0; RANDOM_LEN+PUBLIC_KEY_LENGTH];
|
||||||
@ -542,12 +538,12 @@ impl Session {
|
|||||||
let ephemeral_secret = x25519_dalek::EphemeralSecret::new(OsRng);
|
let ephemeral_secret = x25519_dalek::EphemeralSecret::new(OsRng);
|
||||||
let ephemeral_public_key = x25519_dalek::PublicKey::from(&ephemeral_secret);
|
let ephemeral_public_key = x25519_dalek::PublicKey::from(&ephemeral_secret);
|
||||||
handshake_buffer[RANDOM_LEN..].copy_from_slice(&ephemeral_public_key.to_bytes());
|
handshake_buffer[RANDOM_LEN..].copy_from_slice(&ephemeral_public_key.to_bytes());
|
||||||
self.handshake_write(&handshake_buffer).await?;
|
self.handshake_write(&handshake_buffer, &mut handshake_sent_buff).await?;
|
||||||
self.handshake_read(&mut handshake_buffer).await?;
|
self.handshake_read(&mut handshake_buffer, &mut handshake_recv_buff).await?;
|
||||||
let peer_ephemeral_public_key = slice_to_public_key(&handshake_buffer[RANDOM_LEN..]);
|
let peer_ephemeral_public_key = slice_to_public_key(&handshake_buffer[RANDOM_LEN..]);
|
||||||
//computing handshake keys
|
//computing handshake keys
|
||||||
let i_am_bob = self.handshake_sent_buff < self.handshake_recv_buff; //mutual consensus for keys attribution
|
let i_am_bob = handshake_sent_buff < handshake_recv_buff; //mutual consensus for keys attribution
|
||||||
let handshake_hash = self.hash_handshake(i_am_bob);
|
let handshake_hash = Session::hash_handshake(i_am_bob, &handshake_sent_buff, &handshake_recv_buff);
|
||||||
let shared_secret = ephemeral_secret.diffie_hellman(&peer_ephemeral_public_key);
|
let shared_secret = ephemeral_secret.diffie_hellman(&peer_ephemeral_public_key);
|
||||||
let handshake_keys = HandshakeKeys::derive_keys(shared_secret.to_bytes(), handshake_hash, i_am_bob);
|
let handshake_keys = HandshakeKeys::derive_keys(shared_secret.to_bytes(), handshake_hash, i_am_bob);
|
||||||
|
|
||||||
@ -556,11 +552,11 @@ impl Session {
|
|||||||
//generate random bytes
|
//generate random bytes
|
||||||
let mut random_bytes = [0; RANDOM_LEN];
|
let mut random_bytes = [0; RANDOM_LEN];
|
||||||
OsRng.fill_bytes(&mut random_bytes);
|
OsRng.fill_bytes(&mut random_bytes);
|
||||||
self.handshake_write(&random_bytes).await?;
|
self.handshake_write(&random_bytes, &mut handshake_sent_buff).await?;
|
||||||
drop(random_bytes);
|
drop(random_bytes);
|
||||||
//receive peer random bytes
|
//receive peer random bytes
|
||||||
let mut peer_random = [0; RANDOM_LEN];
|
let mut peer_random = [0; RANDOM_LEN];
|
||||||
self.handshake_read(&mut peer_random).await?;
|
self.handshake_read(&mut peer_random, &mut handshake_recv_buff).await?;
|
||||||
drop(peer_random);
|
drop(peer_random);
|
||||||
//get public key & sign our ephemeral public key
|
//get public key & sign our ephemeral public key
|
||||||
let mut auth_msg = [0; PUBLIC_KEY_LENGTH+SIGNATURE_LENGTH];
|
let mut auth_msg = [0; PUBLIC_KEY_LENGTH+SIGNATURE_LENGTH];
|
||||||
@ -571,10 +567,10 @@ impl Session {
|
|||||||
let mut local_handshake_counter = 0;
|
let mut local_handshake_counter = 0;
|
||||||
let nonce = crypto::iv_to_nonce(&handshake_keys.local_iv, &mut local_handshake_counter);
|
let nonce = crypto::iv_to_nonce(&handshake_keys.local_iv, &mut local_handshake_counter);
|
||||||
let encrypted_auth_msg = local_cipher.encrypt(Nonce::from_slice(&nonce), auth_msg.as_ref()).unwrap();
|
let encrypted_auth_msg = local_cipher.encrypt(Nonce::from_slice(&nonce), auth_msg.as_ref()).unwrap();
|
||||||
self.handshake_write(&encrypted_auth_msg).await?;
|
self.handshake_write(&encrypted_auth_msg, &mut handshake_sent_buff).await?;
|
||||||
|
|
||||||
let mut encrypted_peer_auth_msg = [0; PUBLIC_KEY_LENGTH+SIGNATURE_LENGTH+crypto::AES_TAG_LEN];
|
let mut encrypted_peer_auth_msg = [0; PUBLIC_KEY_LENGTH+SIGNATURE_LENGTH+crypto::AES_TAG_LEN];
|
||||||
self.handshake_read(&mut encrypted_peer_auth_msg).await?;
|
self.handshake_read(&mut encrypted_peer_auth_msg, &mut handshake_recv_buff).await?;
|
||||||
//decrypt peer_auth_msg
|
//decrypt peer_auth_msg
|
||||||
let peer_cipher = Aes128Gcm::new_from_slice(&handshake_keys.peer_key).unwrap();
|
let peer_cipher = Aes128Gcm::new_from_slice(&handshake_keys.peer_key).unwrap();
|
||||||
let mut peer_handshake_counter = 0;
|
let mut peer_handshake_counter = 0;
|
||||||
@ -586,7 +582,7 @@ impl Session {
|
|||||||
let peer_public_key = ed25519_dalek::PublicKey::from_bytes(&self.peer_public_key.unwrap()).unwrap();
|
let peer_public_key = ed25519_dalek::PublicKey::from_bytes(&self.peer_public_key.unwrap()).unwrap();
|
||||||
let peer_signature = Signature::from_bytes(&peer_auth_msg[PUBLIC_KEY_LENGTH..]).unwrap();
|
let peer_signature = Signature::from_bytes(&peer_auth_msg[PUBLIC_KEY_LENGTH..]).unwrap();
|
||||||
if peer_public_key.verify(peer_ephemeral_public_key.as_bytes(), &peer_signature).is_ok() {
|
if peer_public_key.verify(peer_ephemeral_public_key.as_bytes(), &peer_signature).is_ok() {
|
||||||
let handshake_hash = self.hash_handshake(i_am_bob);
|
let handshake_hash = Session::hash_handshake(i_am_bob, &handshake_sent_buff, &handshake_recv_buff);
|
||||||
//sending handshake finished
|
//sending handshake finished
|
||||||
let handshake_finished = crypto::compute_handshake_finished(handshake_keys.local_handshake_traffic_secret, handshake_hash);
|
let handshake_finished = crypto::compute_handshake_finished(handshake_keys.local_handshake_traffic_secret, handshake_hash);
|
||||||
self.send(&handshake_finished).await?;
|
self.send(&handshake_finished).await?;
|
||||||
@ -595,7 +591,7 @@ impl Session {
|
|||||||
if crypto::verify_handshake_finished(peer_handshake_finished, handshake_keys.peer_handshake_traffic_secret, handshake_hash) {
|
if crypto::verify_handshake_finished(peer_handshake_finished, handshake_keys.peer_handshake_traffic_secret, handshake_hash) {
|
||||||
//computing application keys
|
//computing application keys
|
||||||
let application_keys = ApplicationKeys::derive_keys(handshake_keys.handshake_secret, handshake_hash, i_am_bob);
|
let application_keys = ApplicationKeys::derive_keys(handshake_keys.handshake_secret, handshake_hash, i_am_bob);
|
||||||
self.on_handshake_successful(application_keys);
|
self.init_ciphers(application_keys);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -638,8 +634,6 @@ impl From<TcpStream> for Session {
|
|||||||
fn from(stream: TcpStream) -> Self {
|
fn from(stream: TcpStream) -> Self {
|
||||||
Session {
|
Session {
|
||||||
stream: stream,
|
stream: stream,
|
||||||
handshake_sent_buff: Vec::new(),
|
|
||||||
handshake_recv_buff: Vec::new(),
|
|
||||||
local_cipher: None,
|
local_cipher: None,
|
||||||
local_iv: None,
|
local_iv: None,
|
||||||
local_counter: 0,
|
local_counter: 0,
|
||||||
|
Loading…
Reference in New Issue
Block a user