2022-01-03 21:29:04 +00:00
#![ allow(dead_code) ]
2021-11-26 16:50:49 +00:00
#![ allow(clippy::absurd_extreme_comparisons) ]
2022-10-30 23:29:31 +00:00
use super ::* ;
2022-07-10 21:36:50 +00:00
use crate ::* ;
2021-11-22 16:28:30 +00:00
use core ::convert ::TryInto ;
2023-02-08 02:44:50 +00:00
/// Envelopes are versioned
2023-01-29 18:13:50 +00:00
///
/// These are the formats for the on-the-wire serialization performed by this module
///
/// #[repr(C, packed)]
/// struct EnvelopeHeader {
2023-02-08 02:44:50 +00:00
/// // Size is at least 4 bytes. Depending on the version specified, the size may vary and should be case to the appropriate struct
/// magic: [u8; 3], // 0x00: 0x56 0x4C 0x44 ("VLD")
/// version: u8, // 0x03: 0 = EnvelopeV0
2023-01-29 18:13:50 +00:00
/// }
///
/// #[repr(C, packed)]
/// struct EnvelopeV0 {
2023-02-08 02:44:50 +00:00
/// // Size is 106 bytes without signature and 170 with signature
/// magic: [u8; 3], // 0x00: 0x56 0x4C 0x44 ("VLD")
/// version: u8, // 0x03: 0 = EnvelopeV0
/// crypto_kind: [u8; 4], // 0x04: CryptoSystemVersion FOURCC code (CryptoKind)
2023-01-29 18:13:50 +00:00
/// size: u16, // 0x08: Total size of the envelope including the encrypted operations message. Maximum size is 65,507 bytes, which is the data size limit for a single UDP message on IPv4.
/// timestamp: u64, // 0x0A: Duration since UNIX_EPOCH in microseconds when this message is sent. Messages older than 10 seconds are dropped.
2023-02-08 02:44:50 +00:00
/// nonce: [u8; 24], // 0x12: Random nonce for replay protection and for dh
/// sender_id: [u8; 32], // 0x2A: Node ID of the message source, which is the public key of the sender (must be verified with find_node if this is a new node_id/address combination)
/// recipient_id: [u8; 32], // 0x4A: Node ID of the intended recipient, which is the public key of the recipient (must be the receiving node, or a relay lease holder)
2023-01-29 18:13:50 +00:00
/// // 0x6A: message is appended (operations)
2023-02-08 02:44:50 +00:00
/// signature: [u8; 64], // 0x?? (end-0x40): Signature of the entire envelope including header is appended to the packet
2023-01-29 18:13:50 +00:00
/// // entire header needs to be included in message digest, relays are not allowed to modify the envelope without invalidating the signature.
/// }
2021-11-22 16:28:30 +00:00
pub const MAX_ENVELOPE_SIZE : usize = 65507 ;
2022-04-04 01:35:14 +00:00
pub const MIN_ENVELOPE_SIZE : usize = 0x6A + 0x40 ; // Header + Signature
2023-02-08 02:44:50 +00:00
pub const ENVELOPE_MAGIC : & [ u8 ; 3 ] = b " VLD " ;
2021-11-22 16:28:30 +00:00
#[ derive(Debug, Clone, PartialEq, Eq, Default) ]
pub struct Envelope {
version : u8 ,
2023-02-08 02:44:50 +00:00
crypto_kind : CryptoKind ,
2022-12-17 01:07:28 +00:00
timestamp : Timestamp ,
2023-02-08 02:44:50 +00:00
nonce : Nonce ,
sender_id : PublicKey ,
recipient_id : PublicKey ,
2021-11-22 16:28:30 +00:00
}
impl Envelope {
pub fn new (
version : u8 ,
2023-02-08 02:44:50 +00:00
crypto_kind : CryptoKind ,
2022-12-17 01:07:28 +00:00
timestamp : Timestamp ,
2023-02-08 02:44:50 +00:00
nonce : Nonce ,
sender_id : PublicKey ,
recipient_id : PublicKey ,
2021-11-22 16:28:30 +00:00
) -> Self {
2023-02-08 02:44:50 +00:00
assert! ( version > = MIN_ENVELOPE_VERSION ) ;
assert! ( version < = MAX_ENVELOPE_VERSION ) ;
assert! ( VALID_CRYPTO_KINDS . contains ( & crypto_kind ) ) ;
2021-11-22 16:28:30 +00:00
Self {
2021-11-26 16:50:49 +00:00
version ,
2023-02-08 02:44:50 +00:00
crypto_kind ,
2021-11-26 16:50:49 +00:00
timestamp ,
nonce ,
sender_id ,
recipient_id ,
2021-11-22 16:28:30 +00:00
}
}
2023-02-08 02:44:50 +00:00
pub fn from_signed_data ( crypto : Crypto , data : & [ u8 ] ) -> Result < Envelope , VeilidAPIError > {
2021-11-22 16:28:30 +00:00
// Ensure we are at least the length of the envelope
2022-05-28 14:07:57 +00:00
// Silent drop here, as we use zero length packets as part of the protocol for hole punching
2021-11-22 16:28:30 +00:00
if data . len ( ) < MIN_ENVELOPE_SIZE {
2022-11-26 19:16:02 +00:00
apibail_generic! ( " envelope data too small " ) ;
2021-11-22 16:28:30 +00:00
}
// Verify magic number
2023-02-08 02:44:50 +00:00
let magic : [ u8 ; 3 ] = data [ 0x00 .. 0x03 ]
2022-07-10 21:36:50 +00:00
. try_into ( )
. map_err ( VeilidAPIError ::internal ) ? ;
2021-11-22 16:28:30 +00:00
if magic ! = * ENVELOPE_MAGIC {
2022-11-26 19:16:02 +00:00
apibail_generic! ( " bad magic number " ) ;
2021-11-22 16:28:30 +00:00
}
2023-02-08 02:44:50 +00:00
// Check envelope version
let version = data [ 0x03 ] ;
if version > MAX_ENVELOPE_VERSION | | version < MIN_ENVELOPE_VERSION {
apibail_parse_error! ( " unsupported envelope version " , version ) ;
2021-11-22 16:28:30 +00:00
}
2023-02-08 02:44:50 +00:00
// Check crypto kind
2023-02-08 21:50:07 +00:00
let crypto_kind = FourCC (
2023-02-08 02:44:50 +00:00
data [ 0x04 .. 0x08 ]
. try_into ( )
. map_err ( VeilidAPIError ::internal ) ? ,
) ;
let Some ( vcrypto ) = crypto . get ( crypto_kind ) else {
apibail_parse_error! ( " unsupported crypto kind " , crypto_kind ) ;
} ;
2021-11-22 16:28:30 +00:00
// Get size and ensure it matches the size of the envelope and is less than the maximum message size
2022-07-10 21:36:50 +00:00
let size : u16 = u16 ::from_le_bytes (
data [ 0x08 .. 0x0A ]
. try_into ( )
. map_err ( VeilidAPIError ::internal ) ? ,
) ;
2021-11-22 16:28:30 +00:00
if ( size as usize ) > MAX_ENVELOPE_SIZE {
2022-11-26 19:16:02 +00:00
apibail_parse_error! ( " envelope too large " , size ) ;
2021-11-22 16:28:30 +00:00
}
if ( size as usize ) ! = data . len ( ) {
2022-11-26 19:16:02 +00:00
apibail_parse_error! (
2022-07-10 21:36:50 +00:00
" size doesn't match envelope size " ,
format! (
" size doesn't match envelope size: size={} data.len()={} " ,
size ,
data . len ( )
2022-11-26 19:16:02 +00:00
)
) ;
2021-11-22 16:28:30 +00:00
}
// Get the timestamp
2022-12-17 01:07:28 +00:00
let timestamp : Timestamp = u64 ::from_le_bytes (
2022-07-10 21:36:50 +00:00
data [ 0x0A .. 0x12 ]
. try_into ( )
. map_err ( VeilidAPIError ::internal ) ? ,
2022-12-17 01:07:28 +00:00
)
. into ( ) ;
2021-11-22 16:28:30 +00:00
// Get nonce and sender node id
2023-02-08 02:44:50 +00:00
let nonce_slice : [ u8 ; NONCE_LENGTH ] = data [ 0x12 .. 0x2A ]
2022-07-10 21:36:50 +00:00
. try_into ( )
. map_err ( VeilidAPIError ::internal ) ? ;
2023-02-08 02:44:50 +00:00
let sender_id_slice : [ u8 ; PUBLIC_KEY_LENGTH ] = data [ 0x2A .. 0x4A ]
2022-07-10 21:36:50 +00:00
. try_into ( )
. map_err ( VeilidAPIError ::internal ) ? ;
2023-02-08 02:44:50 +00:00
let recipient_id_slice : [ u8 ; PUBLIC_KEY_LENGTH ] = data [ 0x4A .. 0x6A ]
2022-07-10 21:36:50 +00:00
. try_into ( )
. map_err ( VeilidAPIError ::internal ) ? ;
2023-02-08 02:44:50 +00:00
let nonce : Nonce = Nonce ::new ( nonce_slice ) ;
let sender_id = PublicKey ::new ( sender_id_slice ) ;
let recipient_id = PublicKey ::new ( recipient_id_slice ) ;
2021-11-22 16:28:30 +00:00
// Ensure sender_id and recipient_id are not the same
2021-11-26 16:50:49 +00:00
if sender_id = = recipient_id {
2022-11-26 19:16:02 +00:00
apibail_parse_error! (
2022-07-10 21:36:50 +00:00
" sender_id should not be same as recipient_id " ,
2022-11-26 19:16:02 +00:00
recipient_id . encode ( )
) ;
2021-11-22 16:28:30 +00:00
}
2022-04-04 01:35:14 +00:00
// Get signature
2023-02-08 02:44:50 +00:00
let signature = Signature ::new (
2022-07-10 21:36:50 +00:00
data [ ( data . len ( ) - 64 ) .. ]
. try_into ( )
. map_err ( VeilidAPIError ::internal ) ? ,
) ;
2022-04-04 01:35:14 +00:00
// Validate signature
2023-02-08 02:44:50 +00:00
vcrypto
. verify ( & sender_id , & data [ 0 .. ( data . len ( ) - 64 ) ] , & signature )
2022-07-10 21:36:50 +00:00
. map_err ( VeilidAPIError ::internal ) ? ;
2022-04-04 01:35:14 +00:00
2021-11-22 16:28:30 +00:00
// Return envelope
Ok ( Self {
2021-11-26 16:50:49 +00:00
version ,
2023-02-08 02:44:50 +00:00
crypto_kind ,
2021-11-26 16:50:49 +00:00
timestamp ,
nonce ,
sender_id ,
recipient_id ,
2021-11-22 16:28:30 +00:00
} )
}
pub fn decrypt_body (
& self ,
crypto : Crypto ,
data : & [ u8 ] ,
2023-02-08 02:44:50 +00:00
node_id_secret : & SecretKey ,
2022-07-10 21:36:50 +00:00
) -> Result < Vec < u8 > , VeilidAPIError > {
2021-11-22 16:28:30 +00:00
// Get DH secret
2023-02-08 02:44:50 +00:00
let vcrypto = crypto
. get ( self . crypto_kind )
. expect ( " need to ensure only valid crypto kinds here " ) ;
2023-01-29 18:13:50 +00:00
let dh_secret = vcrypto . cached_dh ( & self . sender_id , node_id_secret ) ? ;
2021-11-22 16:28:30 +00:00
2022-04-04 01:35:14 +00:00
// Decrypt message without authentication
2023-01-29 18:13:50 +00:00
let body =
vcrypto . crypt_no_auth_aligned_8 ( & data [ 0x6A .. data . len ( ) - 64 ] , & self . nonce , & dh_secret ) ;
2021-11-22 16:28:30 +00:00
Ok ( body )
}
pub fn to_encrypted_data (
& self ,
crypto : Crypto ,
body : & [ u8 ] ,
2023-02-08 02:44:50 +00:00
node_id_secret : & SecretKey ,
2022-07-10 21:36:50 +00:00
) -> Result < Vec < u8 > , VeilidAPIError > {
2021-11-22 16:28:30 +00:00
// Ensure body isn't too long
2022-04-04 01:35:14 +00:00
let envelope_size : usize = body . len ( ) + MIN_ENVELOPE_SIZE ;
2021-11-22 16:28:30 +00:00
if envelope_size > MAX_ENVELOPE_SIZE {
2022-11-26 19:16:02 +00:00
apibail_parse_error! ( " envelope size is too large " , envelope_size ) ;
2021-11-22 16:28:30 +00:00
}
2023-02-08 02:44:50 +00:00
// Generate dh secret
let vcrypto = crypto
. get ( self . crypto_kind )
. expect ( " need to ensure only valid crypto kinds here " ) ;
let dh_secret = vcrypto . cached_dh ( & self . recipient_id , node_id_secret ) ? ;
// Write envelope body
2021-11-26 16:50:49 +00:00
let mut data = vec! [ 0 u8 ; envelope_size ] ;
2021-11-22 16:28:30 +00:00
// Write magic
2023-02-08 02:44:50 +00:00
data [ 0x00 .. 0x03 ] . copy_from_slice ( ENVELOPE_MAGIC ) ;
2021-11-22 16:28:30 +00:00
// Write version
2023-02-08 02:44:50 +00:00
data [ 0x03 ] = self . version ;
// Write crypto kind
data [ 0x04 .. 0x08 ] . copy_from_slice ( & self . crypto_kind . 0 ) ;
2021-11-22 16:28:30 +00:00
// Write size
data [ 0x08 .. 0x0A ] . copy_from_slice ( & ( envelope_size as u16 ) . to_le_bytes ( ) ) ;
// Write timestamp
2022-12-17 01:07:28 +00:00
data [ 0x0A .. 0x12 ] . copy_from_slice ( & self . timestamp . as_u64 ( ) . to_le_bytes ( ) ) ;
2021-11-22 16:28:30 +00:00
// Write nonce
2023-02-08 02:44:50 +00:00
data [ 0x12 .. 0x2A ] . copy_from_slice ( & self . nonce . bytes ) ;
2021-11-22 16:28:30 +00:00
// Write sender node id
data [ 0x2A .. 0x4A ] . copy_from_slice ( & self . sender_id . bytes ) ;
// Write recipient node id
data [ 0x4A .. 0x6A ] . copy_from_slice ( & self . recipient_id . bytes ) ;
// Encrypt and authenticate message
2023-02-08 02:44:50 +00:00
let encrypted_body = vcrypto . crypt_no_auth_unaligned ( body , & self . nonce , & dh_secret ) ;
2021-11-22 16:28:30 +00:00
// Write body
2022-04-04 01:35:14 +00:00
if ! encrypted_body . is_empty ( ) {
data [ 0x6A .. envelope_size - 64 ] . copy_from_slice ( encrypted_body . as_slice ( ) ) ;
}
// Sign the envelope
2023-02-08 02:44:50 +00:00
let signature = vcrypto . sign (
2022-04-04 01:35:14 +00:00
& self . sender_id ,
node_id_secret ,
& data [ 0 .. ( envelope_size - 64 ) ] ,
2022-07-10 21:36:50 +00:00
) ? ;
2022-04-04 01:35:14 +00:00
// Append the signature
data [ ( envelope_size - 64 ) .. ] . copy_from_slice ( & signature . bytes ) ;
2021-11-22 16:28:30 +00:00
Ok ( data )
}
pub fn get_version ( & self ) -> u8 {
self . version
}
2023-02-08 02:44:50 +00:00
pub fn get_crypto_kind ( & self ) -> CryptoKind {
self . crypto_kind
2021-11-22 16:28:30 +00:00
}
2022-12-17 01:07:28 +00:00
pub fn get_timestamp ( & self ) -> Timestamp {
2021-11-22 16:28:30 +00:00
self . timestamp
}
2023-02-08 02:44:50 +00:00
pub fn get_nonce ( & self ) -> Nonce {
2021-11-22 16:28:30 +00:00
self . nonce
}
2023-02-08 02:44:50 +00:00
pub fn get_sender_id ( & self ) -> PublicKey {
2021-11-22 16:28:30 +00:00
self . sender_id
}
2023-02-08 02:44:50 +00:00
pub fn get_recipient_id ( & self ) -> PublicKey {
2021-11-22 16:28:30 +00:00
self . recipient_id
}
}