hyphae_handshake/
crypto.rs

1//! Traits for Noise handshakes and encryption primitives needed by Hyphae.
2//! 
3
4use rand_core::{CryptoRng, RngCore};
5use zeroize::{Zeroize, ZeroizeOnDrop};
6
7use crate::handshake::HandshakeVersion;
8
9pub mod backends;
10#[cfg(any(test, feature = "keylog"))]
11pub mod keylog;
12pub mod noise;
13pub mod transport;
14
15#[derive(Debug)]
16pub enum CryptoError {
17    DecryptionFailed,
18    InvalidProtocol,
19    UnsupportedProtocol,
20    UnsupportedSecretKey,
21    InvalidInitialization,
22    InvalidKeySize,
23    InvalidState,
24    InsufficientBuffer,
25    StateExhausted,
26    Internal,
27}
28
29impl core::fmt::Display for CryptoError {
30    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        core::fmt::Debug::fmt(&self, f)
32    }
33}
34
35impl core::error::Error for CryptoError {}
36
37pub const HYPHAE_AEAD_KEY_LEN: usize = 32;
38pub const HYPHAE_AEAD_TAG_LEN: usize = 16;
39pub const HYPHAE_AEAD_NONCE_LEN: usize = 12;
40pub const HYPHAE_HEADER_SAMPLE_LEN: usize = 16;
41pub const HYPHAE_HEADER_MASK_MAX_LEN: usize = 16;
42
43#[derive(Clone, Zeroize, ZeroizeOnDrop, Default)]
44pub struct SymmetricKey ([u8; Self::SIZE]);
45
46impl SymmetricKey {
47    pub const SIZE: usize = HYPHAE_AEAD_KEY_LEN;
48}
49
50impl AsRef<[u8; Self::SIZE]> for SymmetricKey {
51    fn as_ref(&self) -> &[u8; Self::SIZE] {
52        &self.0
53    }
54}
55
56impl AsMut<[u8; Self::SIZE]> for SymmetricKey {
57    fn as_mut(&mut self) -> &mut [u8; Self::SIZE] {
58        &mut self.0
59    }
60}
61
62#[non_exhaustive]
63pub enum SecretKeySetup<'a> {
64    /// Use a local, long-term secret key `s` that will be copied into
65    /// the handshake state.
66    Local (&'a [u8]),
67
68    /// Use the backend's configured `RemoteKey` as the long-term
69    /// secret key `s`.
70    BackendRemote,
71}
72
73impl SecretKeySetup<'_> {
74    pub fn remote() -> SecretKeySetup<'static> {
75        SecretKeySetup::BackendRemote
76    }
77}
78
79impl <'a> From<&'a [u8]> for SecretKeySetup<'a> {
80    fn from(value: &'a [u8]) -> Self {
81        SecretKeySetup::Local(value)
82    }
83}
84
85pub trait CryptoBackend {
86    /// Backend's `InitialCrypto` implementation.
87    type InitialCrypto: InitialCrypto;
88
89    /// Backend's `NoiseHandshake` implementation.
90    type NoiseHandshake: NoiseHandshake;
91
92    /// Backend's `TransportCrypto` implementation.
93    type TransportCrypto: TransportCrypto;
94
95    /// Backend's `TransportRekey` implementation.
96    type TransportRekey: TransportRekey;
97
98    /// Returns `true` if the backend's `NoiseHandshake` supports
99    /// `noise_protocol`.
100    fn protocol_supported(&self, noise_protocol: &str) -> bool;
101
102    /// Returns `InitialCrypto`.
103    /// 
104    /// `InitialCrypto` is used to obfuscate data in the initial
105    /// packet space and calculate retry packet integrity tags.
106    /// 
107    /// Hyphae initial crypto always uses `ChaChaPoly` and `BLAKE2s`.
108    fn initial_crypto(&self) -> Self::InitialCrypto;
109
110    /// Returns a new, uninitialized `NoiseHandshake` or an error if the
111    /// backend is not properly configured.
112    fn new_handshake(&self) -> Result<Self::NoiseHandshake, CryptoError>;
113
114    /// Returns `TransportCrypto` for the handshake's selected AEAD
115    /// and hash algorithm.
116    /// 
117    /// `TransportCrypto` is used to protect data in the handshake,
118    /// 0-RTT, and 1-RTT packet spaces.
119    fn transport_crypto(&self, handshake: &Self::NoiseHandshake) -> Result<Self::TransportCrypto, CryptoError>;
120    
121    /// Extract the 1-RTT rekey chain from a finished handshake.
122    fn export_1rtt_rekey(&self, handshake: &mut Self::NoiseHandshake, rekey: &mut Self::TransportRekey) -> Result<(), CryptoError>;
123
124}
125
126pub trait NoiseHandshake {
127    fn initialize<'a> (
128        &mut self,
129        rng: &mut (impl CryptoRng + RngCore),
130        protocol_name: &str,
131        initiator: bool,
132        prologue: impl Iterator<Item = &'a[u8]>,
133        s: Option<SecretKeySetup>,
134        rs: Option<&[u8]>
135    ) -> Result<(), CryptoError>;
136
137    fn write_message_in_place(&mut self, buffer: &mut [u8]) -> Result<(), CryptoError>;
138
139    fn read_message_in_place<'a> (&mut self, buffer: &'a mut [u8]) -> Result<&'a [u8], CryptoError>;
140
141    fn next_message_layout(&self) -> Result<(usize, usize), CryptoError>;
142
143    fn is_reset(&self) -> bool;
144
145    fn is_initiator(&self) -> bool;
146
147    fn is_my_turn(&self) -> bool;
148
149    fn is_finished(&self) -> bool;
150
151    fn remote_public(&self) -> Option<&[u8]>;
152
153    fn handshake_hash(&self) -> &[u8];
154
155    fn get_ask(&mut self, label: &[u8], key: &mut SymmetricKey) -> Result<(), CryptoError>;
156}
157
158pub trait InitialCrypto: TransportCrypto {
159    fn initial_level_secret(&self, handshake_version: HandshakeVersion, transport_label: &[u8], client_dcid: &[u8], level_secret: &mut SymmetricKey) -> Result<(), CryptoError>;
160
161    fn retry_tag_secret(&self, handshake_version: HandshakeVersion, transport_label: &[u8], client_dcid: &[u8], level_secret: &mut SymmetricKey) -> Result<(), CryptoError>;
162}
163
164pub trait TransportCrypto: Clone {
165    type Hash: Send + Sync + 'static;
166
167    fn zeros_hash(&self) -> Self::Hash;
168
169    // todo remove
170    fn hash_into(&self, message: &[u8], output: &mut Self::Hash);
171
172    fn hkdf(&self, key: &Self::Hash, ikm: &[u8], info: &[u8], output: &mut Self::Hash);
173
174    fn hash_as_slice<'a> (&self, hash: &'a Self::Hash) -> &'a [u8];
175
176    fn hash_as_mut_slice<'a> (&self, hash: &'a mut Self::Hash) -> &'a  mut[u8];
177
178    fn derive_subkey(&self, level_secret: &SymmetricKey, label: &[u8], output_key: &mut SymmetricKey);
179
180    fn aead_confidentiality_limit(&self) -> u64;
181
182    fn aead_integrity_limit(&self) -> u64;
183
184    fn encrypt_in_place(&self, packet_key: &SymmetricKey, packet_id: u64, ad: &[u8], buffer: &mut [u8]) -> Result<(), CryptoError>;
185
186    fn decrypt_in_place<'a> (&self, packet_key: &SymmetricKey, packet_id: u64, ad: &[u8], buffer: &'a mut [u8]) -> Result<&'a [u8], CryptoError>;
187
188    fn header_protection_mask(&self, header_key: &SymmetricKey, sample: &[u8], mask: &mut [u8]) -> Result<(), CryptoError>;
189}
190
191pub trait TransportRekey: Default {
192    fn next_1rtt_secret(&mut self, level_secret: &mut SymmetricKey);
193}
194
195/// Trait for `CryptoBackend`s that can be shared between threads.
196/// 
197/// This has a blanket implementation for any `CryptoBackend` with
198/// associated types that are also `Send + Sync + 'static`.
199pub trait SyncCryptoBackend:
200    CryptoBackend<
201        InitialCrypto: Send + Sync + 'static,
202        NoiseHandshake:  Send + Sync + 'static,
203        TransportCrypto: Send + Sync + 'static,
204        TransportRekey: Send + Sync + 'static,
205    > + Sync + Send + 'static
206{}
207
208impl <B> SyncCryptoBackend for B
209where
210    B: CryptoBackend + Send + Sync + 'static,
211    B::InitialCrypto: Send + Sync + 'static,
212    B::NoiseHandshake: Send + Sync + 'static,
213    B::TransportCrypto: Send + Sync + 'static,
214    B::TransportRekey: Send + Sync + 'static,
215{}