cl_noise_protocol/
traits.rs

1/// A trait for fixed size u8 array.
2
3// Inspired by ArrayVec and SmallVec, but no unsafe.
4
5// Use this trait so that we don't have to use [`Vec`] for some semi-fixed length buffers and
6// input/output types.
7pub trait U8Array: Sized {
8    /// Create a new array filled with all zeros.
9    fn new() -> Self;
10    /// Create a new array filled with a same value.
11    fn new_with(_: u8) -> Self;
12    /// Create a new array from a slice.
13    ///
14    /// # Panics
15    ///
16    /// The slice must be of the same length.
17    fn from_slice(_: &[u8]) -> Self;
18    /// Length of the array.
19    fn len() -> usize;
20    /// As slice.
21    fn as_slice(&self) -> &[u8];
22    /// As mutable slice.
23    fn as_mut(&mut self) -> &mut [u8];
24    // Cannot just impl [`Clone`], that will conflict with [u8; 32].
25    /// Clone.
26    fn clone(&self) -> Self {
27        Self::from_slice(self.as_slice())
28    }
29}
30
31macro_rules! impl_array {
32    ($len:expr) => {
33        impl U8Array for [u8; $len] {
34            fn new() -> Self {
35                [0u8; $len]
36            }
37            fn new_with(x: u8) -> Self {
38                [x; $len]
39            }
40            fn from_slice(data: &[u8]) -> Self {
41                let mut a = [0u8; $len];
42                a.copy_from_slice(data);
43                a
44            }
45            fn len() -> usize {
46                $len
47            }
48            fn as_slice(&self) -> &[u8] {
49                self
50            }
51            fn as_mut(&mut self) -> &mut [u8] {
52                self
53            }
54        }
55    };
56}
57
58impl_array!(32);
59impl_array!(64);
60impl_array!(128);
61
62/// An unspecified cryptographic error occured
63#[derive(PartialEq, Copy, Clone, Debug)]
64pub struct Unspecified;
65
66// This is required for the implementation of `std::error::Error`.
67impl core::fmt::Display for Unspecified {
68    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
69        f.write_str("ring::error::Unspecified")
70    }
71}
72
73#[cfg(feature = "std")]
74impl std::error::Error for Unspecified {}
75
76/// A DH.
77pub trait DH {
78    /// Type of private key.
79    type Key;
80    /// Type of pubkey key.
81    type Pubkey: U8Array;
82    /// Type of output.
83    type Output: U8Array;
84
85    /// Name of this DH function, e.g., “25519”.
86    fn name() -> &'static str;
87
88    /// Randomly generate a new private key.
89    fn genkey() -> Self::Key;
90
91    /// Calculate public key from a private key.
92    fn pubkey(_: &Self::Key) -> Self::Pubkey;
93
94    /// Perform DH key exchange.
95    fn dh(_: &Self::Key, _: &Self::Pubkey) -> Result<Self::Output, Unspecified>;
96}
97
98/// An AEAD.
99pub trait Cipher {
100    /// Name of this cipher function.
101    fn name() -> &'static str;
102    /// Type of key.
103    type Key;
104
105    /// Length of key.
106    fn key_len() -> usize;
107
108    /// Create a new key from a slice.
109    ///
110    /// # Panics
111    ///
112    /// The slice len must be equal to key_len.
113    fn key_from_slice(b: &[u8]) -> Self::Key;
114
115    /// Length of auth tag.
116    ///
117    /// All ciphers specified in the spec has tag length 16.
118    fn tag_len() -> usize {
119        16
120    }
121
122    /// AEAD encryption.
123    ///
124    /// # Panics
125    ///
126    /// If `out.len() != plaintext.len() + Self::tag_len()`
127    fn encrypt(k: &Self::Key, nonce: u64, ad: &[u8], plaintext: &[u8], out: &mut [u8]);
128
129    /// AEAD encryption, but encrypt on one buffer.
130    /// return the length of ciphertext.
131    ///
132    /// # Panics
133    ///
134    /// If `in_out.len() < plaintext_len + Self::tag_len()`
135    fn encrypt_in_place(
136        k: &Self::Key,
137        nonce: u64,
138        ad: &[u8],
139        in_out: &mut [u8],
140        plaintext_len: usize,
141    ) -> usize;
142
143    /// AEAD decryption.
144    ///
145    /// # Panics
146    ///
147    /// If `out.len() != ciphertext.len() - Self::tag_len()`
148    fn decrypt(
149        k: &Self::Key,
150        nonce: u64,
151        ad: &[u8],
152        ciphertext: &[u8],
153        out: &mut [u8],
154    ) -> Result<(), Unspecified>;
155
156    /// AEAD decryption, but decrypt on one buffer.
157    /// return the length of plaintext.
158    ///
159    /// # Panics
160    ///
161    /// If `in_out.len() < ciphertext_len` or `ciphertext_len < Self::tag_len()`
162    fn decrypt_in_place(
163        k: &Self::Key,
164        nonce: u64,
165        ad: &[u8],
166        in_out: &mut [u8],
167        ciphertext_len: usize,
168    ) -> Result<usize, Unspecified>;
169
170    /// Rekey. Returns a new cipher key as a pseudorandom function of `k`.
171    fn rekey(k: &Self::Key) -> Self::Key {
172        // XXX: `k1` is not zeroed.
173        let mut k1 = [0u8; 48];
174        Self::encrypt(k, 0u64.wrapping_sub(1), &[], &[0; 32], &mut k1);
175        Self::key_from_slice(&k1[..32])
176    }
177}
178
179/// A hash function.
180pub trait Hash: Default {
181    /// Name of the hash function.
182    fn name() -> &'static str;
183
184    /// Type of a block.
185    type Block: U8Array;
186    /// Type of output.
187    type Output: U8Array;
188
189    /// Length of block.
190    fn block_len() -> usize {
191        Self::Block::len()
192    }
193
194    /// Length of hash output, in number of bytes.
195    fn hash_len() -> usize {
196        Self::Output::len()
197    }
198
199    /// Update hash context with some input.
200    fn input(&mut self, data: &[u8]);
201
202    /// Get hash result.
203    fn result(self) -> Self::Output;
204
205    /// Calculate hash of some data.
206    fn hash(data: &[u8]) -> Self::Output {
207        let mut h: Self = Default::default();
208        h.input(data);
209        h.result()
210    }
211
212    /// Calculate HMAC-THIS-HASH, with some `key` and several messages.
213    fn hmac_many(key: &[u8], data: &[&[u8]]) -> Self::Output {
214        assert!(key.len() <= Self::block_len());
215
216        let mut ipad = Self::Block::new_with(0x36u8);
217        let mut opad = Self::Block::new_with(0x5cu8);
218
219        let ipad = ipad.as_mut();
220        let opad = opad.as_mut();
221
222        for (i, b) in key.iter().enumerate() {
223            ipad[i] ^= b;
224            opad[i] ^= b;
225        }
226
227        let mut hasher: Self = Default::default();
228        hasher.input(ipad);
229        for d in data {
230            hasher.input(d);
231        }
232        let inner_output = hasher.result();
233
234        hasher = Default::default();
235        hasher.input(opad);
236        hasher.input(inner_output.as_slice());
237        hasher.result()
238    }
239
240    /// Calculate HMAC-THIS-HASH, with some `key` and a message.
241    fn hmac(key: &[u8], data: &[u8]) -> Self::Output {
242        Self::hmac_many(key, &[data])
243    }
244
245    /// Calculate HKDF, as specified in the noise spec.
246    fn hkdf(chaining_key: &[u8], input_key_material: &[u8]) -> (Self::Output, Self::Output) {
247        let temp_key = Self::hmac(chaining_key, input_key_material);
248        let out1 = Self::hmac(temp_key.as_slice(), &[1u8]);
249        let out2 = Self::hmac_many(temp_key.as_slice(), &[out1.as_slice(), &[2u8]]);
250        (out1, out2)
251    }
252
253    /// Triple output HKDF.
254    fn hkdf3(
255        chaining_key: &[u8],
256        input_key_material: &[u8],
257    ) -> (Self::Output, Self::Output, Self::Output) {
258        let temp_key = Self::hmac(chaining_key, input_key_material);
259        let out1 = Self::hmac(temp_key.as_slice(), &[1u8]);
260        let out2 = Self::hmac_many(temp_key.as_slice(), &[out1.as_slice(), &[2u8]]);
261        let out3 = Self::hmac_many(temp_key.as_slice(), &[out2.as_slice(), &[3u8]]);
262        (out1, out2, out3)
263    }
264}