@ -56,12 +56,44 @@ struct ESockInfo {
them : Option < RsaPublicKey > ,
them : Option < RsaPublicKey > ,
}
}
#[ derive(Debug) ]
impl ESockInfo
{
/// Generate a new private key
pub fn new ( us : impl Into < RsaPrivateKey > ) -> Self
{
Self {
us : us . into ( ) ,
them : None ,
}
}
/// Generate a new private key for the local endpoint
pub fn generate ( ) -> Result < Self , rsa ::Error >
{
Ok ( Self ::new ( RsaPrivateKey ::generate ( ) ? ) )
}
}
/// The encryption state of the Tx and Rx instances.
#[ derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone) ]
struct ESockState {
struct ESockState {
encr : bool ,
encr : bool ,
encw : bool ,
encw : bool ,
}
}
impl Default for ESockState
{
#[ inline ]
fn default ( ) -> Self
{
Self {
encr : false ,
encw : false ,
}
}
}
/// Contains a cc20 Key and IV that can be serialized and then encrypted
/// Contains a cc20 Key and IV that can be serialized and then encrypted
#[ derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize) ]
#[ derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize) ]
struct ESockSessionKey
struct ESockSessionKey
@ -188,16 +220,42 @@ impl<W: AsyncWrite, R: AsyncRead> ESock<W, R>
impl < W : AsyncWrite + Unpin , R : AsyncRead + Unpin > ESock < W , R >
impl < W : AsyncWrite + Unpin , R : AsyncRead + Unpin > ESock < W , R >
{
{
/// Get the Tx and Rx of the stream.
///
/// # Returns
/// Returns encrypted stream halfs if the stream is encrypted, unencrypted if not.
pub fn stream ( & mut self ) -> ( & mut ( dyn AsyncWrite + Unpin + ' _ ) , & mut ( dyn AsyncRead + Unpin + ' _ ) )
{
( if self . state . encw {
& mut self . tx
} else {
self . tx . inner_mut ( )
} , if self . state . encr {
& mut self . rx
} else {
self . rx . inner_mut ( )
} )
}
/// Enable write encryption
/// Enable write encryption
pub async fn set_encrypted_write ( & mut self , set : bool ) -> eyre ::Result < ( ) >
pub async fn set_encrypted_write ( & mut self , set : bool ) -> eyre ::Result < ( ) >
{
{
use tokio ::prelude ::* ;
use tokio ::prelude ::* ;
if set {
if set {
let session_key = ESockSessionKey ::generate ( ) ;
let session_key = ESockSessionKey ::generate ( ) ;
let data = session_key . to_ciphertext ( self . info . them . as_ref ( ) . expect ( "Cannot set encrypted write when keys have not been exchanged" ) ) ? ;
let data = {
let crypter = session_key . to_encrypter ( ) ? ;
let them = self . info . them . as_ref ( ) . expect ( "Cannot set encrypted write when keys have not been exchanged" ) ;
session_key . to_ciphertext ( them )
. wrap_err ( eyre ! ( "Failed to encrypt session key with foreign endpoint's key" ) )
. with_section ( | | session_key . to_string ( ) . header ( "Session key was" ) )
. with_section ( | | them . to_string ( ) . header ( "Foreign pubkey was" ) ) ?
} ;
let crypter = session_key . to_encrypter ( )
. wrap_err ( eyre ! ( "Failed to create encryption device from session key for Tx" ) )
. with_section ( | | session_key . to_string ( ) . header ( "Session key was" ) ) ? ;
// Send rsa `data` over unencrypted endpoint
// Send rsa `data` over unencrypted endpoint
self . unencrypted ( ) . 0. write_all ( & data [ .. ] ) . await ? ;
self . unencrypted ( ) . 0. write_all ( & data [ .. ] ) . await
. wrap_err ( eyre ! ( "Failed to write ciphertext to endpoint" ) )
. with_section ( | | data . to_base64_string ( ) . header ( "Ciphertext of session key was" ) ) ? ;
// Set crypter of `tx` to `session_key`.
// Set crypter of `tx` to `session_key`.
* self . tx . crypter_mut ( ) = crypter ;
* self . tx . crypter_mut ( ) = crypter ;
// Set `encw` to true
// Set `encw` to true
@ -218,11 +276,17 @@ impl<W: AsyncWrite+ Unpin, R: AsyncRead + Unpin> ESock<W, R>
if set {
if set {
let mut data = [ 0 u8 ; RSA_CIPHERTEXT_SIZE ] ;
let mut data = [ 0 u8 ; RSA_CIPHERTEXT_SIZE ] ;
// Read `data` from unencrypted endpoint
// Read `data` from unencrypted endpoint
self . unencrypted ( ) . 1. read_exact ( & mut data [ .. ] ) . await ? ;
self . unencrypted ( ) . 1. read_exact ( & mut data [ .. ] ) . await
. wrap_err ( eyre ! ( "Failed to read ciphertext from endpoint" ) ) ? ;
// Decrypt `data`
// Decrypt `data`
let session_key = ESockSessionKey ::from_ciphertext ( & data , & self . info . us ) ? ;
let session_key = ESockSessionKey ::from_ciphertext ( & data , & self . info . us )
. wrap_err ( eyre ! ( "Failed to decrypt session key from ciphertext" ) )
. with_section ( | | data . to_base64_string ( ) . header ( "Ciphertext was" ) )
. with_section ( | | self . info . us . to_string ( ) . header ( "Our RSA key is" ) ) ? ;
// Set crypter of `rx` to `session_key`.
// Set crypter of `rx` to `session_key`.
* self . rx . crypter_mut ( ) = session_key . to_decrypter ( ) ? ;
* self . rx . crypter_mut ( ) = session_key . to_decrypter ( )
. wrap_err ( eyre ! ( "Failed to create decryption device from session key for Rx" ) )
. with_section ( | | session_key . to_string ( ) . header ( "Decrypted session key was" ) ) ? ;
// Set `encr` to true
// Set `encr` to true
self . state . encr = true ;
self . state . encr = true ;
Ok ( ( ) )
Ok ( ( ) )
@ -255,17 +319,29 @@ impl<W: AsyncWrite+ Unpin, R: AsyncRead + Unpin> ESock<W, R>
// Read the public key from `rx`.
// Read the public key from `rx`.
//TODO: Find pubkey max size.
//TODO: Find pubkey max size.
let mut sz_buf = [ 0 u8 ; std ::mem ::size_of ::< u64 > ( ) ] ;
let mut sz_buf = [ 0 u8 ; std ::mem ::size_of ::< u64 > ( ) ] ;
rx . read_exact ( & mut sz_buf [ .. ] ) . await ? ;
rx . read_exact ( & mut sz_buf [ .. ] ) . await
let sz = match usize ::try_from ( u64 ::from_be_bytes ( sz_buf ) ) ? {
. wrap_err ( eyre ! ( "Failed to read size of pubkey form endpoint" ) ) ? ;
x if x > TRANS_KEY_MAX_SIZE = > return Err ( eyre ! ( "Recv'd key size exceeded max" ) ) ,
let sz64 = u64 ::from_be_bytes ( sz_buf ) ;
x = > x
let sz = match usize ::try_from ( sz64 )
} ;
. wrap_err ( eyre ! ( "Read size could not fit into u64" ) )
. with_section ( | | format! ( "{:?}" , sz_buf ) . header ( "Read buffer was" ) )
. with_section ( | | u64 ::from_be_bytes ( sz_buf ) . header ( "64=bit size value was" ) )
. with_warning ( | | "This should not happen, it is only possible when you are running a machine with a pointer size lower than 64 bits." )
. with_suggestion ( | | "The message is likely malformed. If it is not, then you are communicating with an endpoint of 64 bits whereas your pointer size is far less." ) ? {
x if x > TRANS_KEY_MAX_SIZE = > return Err ( eyre ! ( "Recv'd key size exceeded max acceptable key buffer size" ) ) ,
x = > x
} ;
let mut key_bytes = Vec ::with_capacity ( sz ) ;
let mut key_bytes = Vec ::with_capacity ( sz ) ;
tokio ::io ::copy ( & mut rx . take ( sz as u64 ) , & mut key_bytes ) . await ? ;
tokio ::io ::copy ( & mut rx . take ( sz64 ) , & mut key_bytes ) . await
. wrap_err ( "Failed to read key bytes into buffer" )
. with_section ( move | | sz64 . header ( "Pubkey size to read was" ) ) ? ;
if key_bytes . len ( ) ! = sz {
if key_bytes . len ( ) ! = sz {
return Err ( eyre ! ( "Could not read required bytes" ) ) ;
return Err ( eyre ! ( "Could not read required bytes" ) ) ;
}
}
let k = RsaPublicKey ::from_bytes ( key_bytes ) ? ;
let k = RsaPublicKey ::from_bytes ( & key_bytes )
. wrap_err ( "Failed to construct RSA public key from read bytes" )
. with_section ( | | sz . header ( "Pubkey size was" ) )
. with_section ( move | | key_bytes . to_base64_string ( ) . header ( "Pubkey bytes were" ) ) ? ;
Result ::< RsaPublicKey , eyre ::Report > ::Ok ( k )
Result ::< RsaPublicKey , eyre ::Report > ::Ok ( k )
}
}
@ -273,16 +349,27 @@ impl<W: AsyncWrite+ Unpin, R: AsyncRead + Unpin> ESock<W, R>
let write_fut = {
let write_fut = {
let key_bytes = our_key . to_bytes ( ) ;
let key_bytes = our_key . to_bytes ( ) ;
assert! ( key_bytes . len ( ) < = TRANS_KEY_MAX_SIZE ) ;
assert! ( key_bytes . len ( ) < = TRANS_KEY_MAX_SIZE ) ;
let sz_buf = u64 ::try_from ( key_bytes . len ( ) ) ? . to_be_bytes ( ) ;
let sz64 = u64 ::try_from ( key_bytes . len ( ) )
. wrap_err ( eyre ! ( "Size of our pubkey could not fit into u64" ) )
. with_section ( | | key_bytes . len ( ) . header ( "Size was" ) )
. with_warning ( | | "This should not happen, it is only possible when you are running a machine with a pointer size larger than 64 bits." )
. with_warning ( | | "There was likely internal memory corruption." ) ? ;
let sz_buf = sz64 . to_be_bytes ( ) ;
async move {
async move {
tx . write_all ( & sz_buf [ .. ] ) . await ? ;
tx . write_all ( & sz_buf [ .. ] ) . await
tx . write_all ( & key_bytes [ .. ] ) . await ? ;
. wrap_err ( eyre ! ( "Failed to write key size" ) )
. with_section ( | | sz64 . header ( "Key size bytes were" ) )
. with_section ( | | format! ( "{:?}" , sz_buf ) . header ( "Key size bytes (BE) were" ) ) ? ;
tx . write_all ( & key_bytes [ .. ] ) . await
. wrap_err ( eyre ! ( "Failed to write key bytes" ) )
. with_section ( | | sz64 . header ( "Size of key was" ) )
. with_section ( | | key_bytes . to_base64_string ( ) . header ( "Key bytes are" ) ) ? ;
Result ::< ( ) , eyre ::Report > ::Ok ( ( ) )
Result ::< ( ) , eyre ::Report > ::Ok ( ( ) )
}
}
} ;
} ;
let ( send , recv ) = tokio ::join ! [ write_fut , read_fut ] ;
let ( send , recv ) = tokio ::join ! [ write_fut , read_fut ] ;
send ? ;
send . wrap_err ( "Failed to send our pubkey" ) ? ;
let recv = recv ? ;
let recv = recv . wrap_err ( "Failed to receive foreign pubkey" ) ? ;
self . info . them = Some ( recv ) ;
self . info . them = Some ( recv ) ;
Ok ( ( ) )
Ok ( ( ) )
}
}