Skip to main content

bouncycastle_core_interface/
traits.rs

1//! Provides simplified abstracted APIs over classes of cryptigraphic primitives, such as Hash, KDF, etc.
2
3use crate::errors::{HashError, KDFError, MACError, RNGError};
4pub use crate::key_material::KeyMaterial;
5
6// Imports needed for docs
7#[allow(unused_imports)]
8use crate::key_material::KeyMaterialInternal;
9#[allow(unused_imports)]
10use crate::key_material::KeyType;
11// end of imports needed for docs
12
13pub trait Algorithm {
14    const ALG_NAME: &'static str;
15    const MAX_SECURITY_STRENGTH: SecurityStrength;
16}
17
18pub trait Hash : Default {
19    /// The size of the internal block in bits -- needed by functions such as HMAC to compute security parameters.
20    fn block_bitlen(&self) -> usize;
21
22    /// The size of the output in bytes.
23    fn output_len(&self) -> usize;
24
25    /// A static one-shot API that hashes the provided data.
26    /// `data` can be of any length, including zero bytes.
27    fn hash(self, data: &[u8]) -> Vec<u8>;
28
29    /// A static one-shot API that hashes the provided data into the provided output slice.
30    /// `data` can be of any length, including zero bytes.
31    /// The return value is the number of bytes written.
32    fn hash_out(self, data: &[u8], output: &mut [u8]) -> usize;
33
34    /// Provide a chunk of data to be absorbed into the hashes.
35    /// `data` can be of any length, including zero bytes.
36    /// do_update() is intended to be used as part of a streaming interface, and so may by called multiple times.
37    // fn do_update(&mut self, data: &[u8]) -> Result<(), HashError>;
38    fn do_update(&mut self, data: &[u8]);
39
40    /// Finish absorbing input and produce the hashes output.
41    /// Consumes self, so this must be the final call to this object.
42    // fn do_final(self) -> Result<Vec<u8>, HashError>;
43    fn do_final(self) -> Vec<u8>;
44
45    /// Finish absorbing input and produce the hashes output.
46    /// Consumes self, so this must be the final call to this object.
47    ///
48    /// If the provided buffer is smaller than the hash's output length, the output will be truncated.
49    /// If the provided buffor is larger than the hash's output length, the output  will be placed in
50    /// the first [Hash::output_len] bytes.
51    ///
52    /// The return value is the number of bytes written.
53    fn do_final_out(self, output: &mut [u8]) -> usize;
54
55    /// The same as [Hash::do_final], but allows for supplying a partial byte as the last input.
56    /// Assumes that the input is in the least significant bits (big endian).
57    fn do_final_partial_bits(
58        self,
59        partial_byte: u8,
60        num_partial_bits: usize,
61    ) -> Result<Vec<u8>, HashError>;
62
63    /// The same as [Hash::do_final_out], but allows for supplying a partial byte as the last input.
64    /// Assumes that the input is in the least significant bits (big endian).
65    /// will be placed in the first [Hash::output_len] bytes.
66    /// The return value is the number of bytes written.
67    fn do_final_partial_bits_out(
68        self,
69        partial_byte: u8,
70        num_partial_bits: usize,
71        output: &mut [u8],
72    ) -> Result<usize, HashError>;
73
74    /// Returns the maximum security strength that this KDF is capable of supporting, based on the underlying primitives.
75    fn max_security_strength(&self) -> SecurityStrength;
76}
77
78pub trait HashAlgParams: Algorithm {
79    const OUTPUT_LEN: usize;
80    const BLOCK_LEN: usize;
81}
82
83/// A Key Derivation Function (KDF) is a function that takes in one or more input key and some unstructured
84/// additional input, and uses them to produces a derived key.
85pub trait KDF : Default {
86    /// Implementations of this function are capable of deriving an output key from an input key,
87    /// assuming that they have been properly initialized.
88    ///
89    /// # Entropy Conversion rules
90    /// Implementations SHOULD act on a KeyMaterial of any [KeyType] and will generally
91    /// return a KeyMaterial of the same type
92    ///
93    /// ex.:
94    ///
95    ///   * [KeyType::BytesLowEntropy] -> [KeyType::BytesLowEntropy])
96    ///   * [KeyType::BytesFullEntropy] -> [KeyType::BytesFullEntropy])
97    ///   * [KeyType::SymmetricCipherKey] -> [KeyType::SymmetricCipherKey])
98    ///
99    /// If provided with an input key, even if it is [KeyType::BytesFullEntropy], but that
100    /// contains less key material than the internal block size of the KDF, then the KDF
101    /// will not be considered properly seeded, and the output [KeyMaterialInternal] will be set to
102    /// [KeyType::BytesLowEntropy] -- for example, seeding SHA3-256 with a [KeyMaterialInternal] containing
103    /// only 128 bits of key material.
104    ///
105    /// An implement can, and in most cases SHOULD, return a [HashError] if provided
106    /// with a [KeyMaterialInternal] of type [KeyType::Zeroized].
107    ///
108    /// # Additional Input
109    /// The `additional_input` parameter is used in deriving the key, but is not credited with any entropy,
110    /// and therefore does not affect the type of the output [KeyMaterialInternal].
111    /// This corresponds directly to `FixedInfo` as defined in NIST SP 800-56C.
112    /// The `additional_input` parameter can be empty by passing in `&[0u8; 0]`.
113    ///
114    /// Output length: this function will create a KeyMaterial populated with the default output length
115    /// of the underlying hash primitive.
116    fn derive_key(
117        self,
118        key: &impl KeyMaterial,
119        additional_input: &[u8],
120    ) -> Result<Box<dyn KeyMaterial>, KDFError>;
121
122    /// Same as [KDF::derive_key], but fills the provided output [KeyMaterialInternal].
123    ///
124    /// Output length: this function will behave differently depending on the underlying hash primitive;
125    /// some, such as SHA2 or SHA3 will produce a fixed-length output, while others, such as SHAKE or HKDF,
126    /// will fill the provided KeyMaterial to capacity and require you to truncate it afterwards
127    /// using [KeyMaterial::truncate].
128    fn derive_key_out(
129        self,
130        key: &impl KeyMaterial,
131        additional_input: &[u8],
132        output_key: &mut impl KeyMaterial,
133    ) -> Result<usize, KDFError>;
134
135    /// Meant to be used for hybrid key establishment schemes or other spit-key scenarios where multiple
136    /// keys need to be combined into a single key of the same length.
137    ///
138    /// This function can also be used to mix a KeyMaterial of low entropy with one of full entropy to
139    /// produce a new full entropy key. For the purposes of determining whether enough input key material
140    /// was provided, the lengths of all full-entropy input keys are added together.
141    ///
142    /// Implementations that are not safe to be used as a split-key PRF MAY still implement this function
143    /// and return a result, but SHOULD set the entropy level of the returned key appropriately; for example
144    /// a KDF that is only full-entropy when keyed in the first input SHOULD return a full entropy key
145    /// only if the first input is full entropy.
146    ///
147    /// Implementations can, and in most cases SHOULD, return a [KeyMaterialInternal] of the same type as the
148    /// strongest key, and SHOULD throw a [HashError] if all input keys are zeroized.
149    /// For example output a [KeyType::BytesFullEntropy] key whenever any one of
150    /// the input keys is a [KeyType::BytesFullEntropy] key.
151    /// As another example, combining a [KeyType::BytesLowEntropy] key with a [KeyType::MACKey] key
152    /// should return a [KeyType::MACKey].
153    ///
154    /// Output length: this function will create a KeyMaterial populated with the default output length
155    /// of the underlying hash primitive.
156    fn derive_key_from_multiple(
157        self,
158        keys: &[&impl KeyMaterial],
159        additional_input: &[u8],
160    ) -> Result<Box<dyn KeyMaterial>, KDFError>;
161
162    /// Same as [KDF::derive_key], but fills the provided output [KeyMaterialInternal].
163    ///
164    /// Output length: this function will behave differently depending on the underlying hash primitive;
165    /// some, such as SHA2 or SHA3 will produce a fixed-length output, while others, such as SHAKE or HKDF,
166    /// will fill the provided KeyMaterial to capacity and require you to truncate it afterwards
167    /// by using [KeyMaterial::truncate].
168    fn derive_key_from_multiple_out(
169        self,
170        keys: &[&impl KeyMaterial],
171        additional_input: &[u8],
172        output_key: &mut impl KeyMaterial,
173    ) -> Result<usize, KDFError>;
174
175    /// Returns the maximum security strength that this KDF is capable of supporting, based on the underlying primitives.
176    fn max_security_strength(&self) -> SecurityStrength;
177}
178
179/// A Message Authentication Code algorithm is a keyed hash function that behaves somewhat like a symmetric signature function.
180/// A MAC algorithm takes in a key and some data, and produces a MAC (message authentication code) that
181/// can be used to verify the integrity of data.
182///
183/// This trait provides one-shot functions [MAC::mac], [MAC::mac_out], and [MAC::verify].
184/// It also provides streaming functions [MAC::do_update], [MAC::do_final], [MAC::do_final_out],
185/// and [MAC::do_verify_final].
186/// The workflow is that a MAC object is initialized with a key with [MAC::new] -- or [MAC::new_allow_weak_key] if you
187/// need to disable the library's safety mechanism to prevent the use of weak keys -- then data is
188/// processed into one or more calls to [MAC::do_update],
189/// after that the object can either create a MAC with [MAC::do_final] or [MAC::do_final_out] (which are final functions, and so consume the object),
190/// or the object can be used to verify a MAC.
191///
192/// For varifying an existing MAC, it is functionally equivalent to use the provided [MAC::verify] and [MAC::do_verify_final]
193/// function or to compute a new MAC and compare it to the existing MAC, however the provided verification functions
194/// use constant-time comparison to avoid cryptographic timing attacks whereby an attacker could learn
195/// the bytes of the MAC value under some conditions. Therefore, it is highly recommended to use the provided verification functions.
196///
197/// Note that the MAC key is not represented in this trait because it is provided to the MAC algorithm
198/// as part of its new functions.
199///
200/// MACs do not implement Default because they do not have a sensible no-args constructor.
201pub trait MAC: Sized {
202
203    /// Create a new MAC instance with the given key.
204    ///
205    /// This is a common constructor whether creating or verifying a MAC value.
206    ///
207    /// Key / Salt is optional, which is indicated by providing an uninitialized KeyMaterial object of length zero,
208    /// the capacity is irrelevant, so KeyMateriol256::new() or KeyMaterial_internal::<0>::new() would both count as an absent salt.
209    ///
210    /// # Note about the security strength of the provided key:
211    /// If you initialize the MAC with a key that is tagged at a lower [SecurityStrength] than the
212    /// underlying hash function then [MAC::new] will fail with the following error:
213    /// ```text
214    /// MACError::KeyMaterialError(KeyMaterialError::SecurityStrength("HMAC::init(): provided key has a lower security strength than the instantiated HMAC")
215    /// ```
216    /// There are situations in which it is completely reasonable and secure to provide low-entropy
217    /// (and sometimes all-zero) keys / salts; for these cases we have provided [MAC::new_allow_weak_key].
218    fn new(key: &impl KeyMaterial) -> Result<Self, MACError>;
219
220    /// Create a new HMAC instance with the given key.
221    ///
222    /// This constructor completely ignores the [SecurityStrength] tag on the input key and will "just work".
223    /// This should be used if you really do need to use a weak key, such as an all-zero salt,
224    /// but use of this constructor is discouraged and you should really be asking yourself why you need it;
225    /// in most cases it indicates that your key is not long enough to support the security level of this
226    /// HMAC instance, or the key was derived using algorithms at a lower security level, etc.
227    fn new_allow_weak_key(key: &impl KeyMaterial) -> Result<Self, MACError>;
228
229    /// The size of the output in bytes.
230    fn output_len(&self) -> usize;
231
232    /// One-shot API that computes a MAC for the provided data.
233    /// `data` can be of any length, including zero bytes.
234    ///
235    /// Note about the security strength of the provided key:
236    /// If the provided key is tagged at a lower [SecurityStrength] than the instantiated MAC algorithm,
237    /// this will fail with an error:
238    /// ```text
239    /// MACError::KeyMaterialError(KeyMaterialError::SecurityStrength("HMAC::init(): provided key has a lower security strength than the instantiated HMAC")
240    /// ```
241    fn mac(self, data: &[u8]) -> Vec<u8>;
242
243    /// One-shot API that computes a MAC for the provided data and writes it into the provided output slice.
244    /// `data` can be of any length, including zero bytes.
245    ///
246    /// Depending on the underlying MAC implementation, NIST may require that the library enforce
247    /// a minimum length on the mac output value. See documentation for the underlying implementation
248    /// to see conditions under which it throws [MACError::InvalidLength].
249    fn mac_out(self, data: &[u8],out: &mut [u8]) -> Result<usize, MACError>;
250
251    /// One-shot API that verifies a MAC for the provided data.
252    /// `data` can be of any length, including zero bytes.
253    ///
254    /// Internally, this will re-compute the MAC value and then compare it to the provided mac value
255    /// using constant-time comparison. It is highly encouraged to use this utility function instead of
256    /// comparing mac values for equality yourself.
257    ///
258    /// Returns a bool to indicate successful verification of the provided mac value.
259    /// The provided mac value must be an exact match, including length; for example a mac value
260    /// which has been truncated, or which contains extra bytes at the end is considered to not be a match
261    /// and will return false.
262    fn verify(self, data: &[u8], mac: &[u8]) -> bool;
263
264    /// Provide a chunk of data to be absorbed into the MAC.
265    /// `data` can be of any length, including zero bytes.
266    /// do_update() is intended to be used as part of a streaming interface, and so may by called multiple times.
267    fn do_update(&mut self, data: &[u8]);
268
269    fn do_final(self) -> Vec<u8>;
270
271    /// Depending on the underlying MAC implementation, NIST may require that the library enforce
272    /// a minimum length on the mac output value. See documentation for the underlying implementation
273    /// to see conditions under which it throws [MACError::InvalidLength].
274    fn do_final_out(self, out: &mut [u8]) -> Result<usize, MACError>;
275
276    /// Internally, this will re-compute the MAC value and then compare it to the provided mac value
277    /// using constant-time comparison. It is highly encouraged to use this utility function instead of
278    /// comparing mac values for equality yourself.
279    ///
280    /// Returns a bool to indicate successful verification of the provided mac value.
281    /// The provided mac value must be an exact match, including length; for example a mac value
282    /// which has been truncated, or which contains extra bytes at the end is considered to not be a match
283    /// and will return false.
284    fn do_verify_final(self, mac: &[u8]) -> bool;
285
286    /// Returns the maximum security strength that this KDF is capable of supporting, based on the underlying primitives.
287    fn max_security_strength(&self) -> SecurityStrength;
288}
289
290#[derive(Eq, PartialEq, PartialOrd, Clone, Debug)]
291pub enum SecurityStrength {
292    None,
293    _112bit,
294    _128bit,
295    _192bit,
296    _256bit,
297}
298
299impl SecurityStrength {
300    /// Rounds down to the closest supported security strength.
301    /// For example, 120-bits is rounded down to 112-bit.
302    pub fn from_bits(bits: usize) -> Self {
303        if bits < 112 {
304            Self::None
305        } else if bits < 128 {
306            Self::_112bit
307        } else if bits < 192 {
308            Self::_128bit
309        } else if bits < 256 {
310            Self::_192bit
311        } else {
312            Self::_256bit
313        }
314    }
315
316    pub fn from_bytes(bytes: usize) -> Self {
317        Self::from_bits(bytes * 8)
318    }
319
320    pub fn as_int(&self) -> u32 {
321        match self {
322            Self::None => 0,
323            Self::_112bit => 112,
324            Self::_128bit => 128,
325            Self::_192bit => 192,
326            Self::_256bit => 256,
327        }
328    }
329}
330
331/// An interface for random number generation.
332/// This interface is meant to be simpler and more ergonomic than the interfaces provided by the
333/// `rng` crate, but that one should
334/// be used by applications that intend to submit to FIPS certification as it more closely aligns with the
335/// requirements of SP 800-90A.
336/// Note: this interface produces bytes. If you want a [KeyMaterial], then use [KeyMaterialInternal::from_rng].
337pub trait RNG : Default {
338    // TODO: add back once we figure out streaming interaction with entropy sources.
339    // fn add_seed_bytes(&mut self, additional_seed: &[u8]) -> Result<(), RNGError>;
340
341    fn add_seed_keymaterial(&mut self, additional_seed: impl KeyMaterial) -> Result<(), RNGError>;
342    fn next_int(&mut self) -> Result<u32, RNGError>;
343
344    /// Returns the number of requested bytes.
345    fn next_bytes(&mut self, len: usize) -> Result<Vec<u8>, RNGError>;
346
347    /// Returns the number of bytes written.
348    fn next_bytes_out(&mut self, out: &mut [u8]) -> Result<usize, RNGError>;
349
350    fn fill_keymaterial_out(&mut self, out: &mut impl KeyMaterial) -> Result<usize, RNGError>;
351
352    /// Returns the Security Strength of this RNG.
353    fn security_strength(&self) -> SecurityStrength;
354}
355
356/// Extensible Output Functions (XOFs) are similar to hash functions, except that they can produce output of arbitrary length.
357/// The naming used for the functions of this trait are borrowed from the SHA3-style sponge constructions that split XOF operation
358/// into two phases: an absorb phase in which an arbitrary amount of input is provided to the XOF,
359/// and then a squeeze phase in which an arbitrary amount of output is extracted.
360/// Once squeezing begins, no more input can be absorbed.
361///
362/// XOFs are _similar to_ hash functions, but are not hash functions for one technical but important reason:
363/// since the amount of output to produce is not provided to the XOF in advance, it cannot be used to
364/// diversify the XOF output streams.
365/// In other words, the overlapping parts of their outputs will be the same!
366/// For example, consider two XOFs that absorb the same input data, one that is squeezed to produce 32 bytes,
367/// and the other to produce 1 kb; both outputs will be identical in their first 32 bytes.
368/// This could lead to loss of security in a number of ways, for example distinguishing attacks where
369/// it is sufficient for the attacker to know that two values came from the same input, even if the
370/// attacker cannot learn what that input was. This is attack is often sufficient, for example,
371/// to break anonymity-preserving technology.
372/// Applications that require the arbitrary-length output of an XOF, but also care about these
373/// distinguishing attacks should consider adding a cryptographic salt to diversify the inputs.
374pub trait XOF : Default {
375    /// A static one-shot API that digests the input data and produces `result_len` bytes of output.
376    fn hash_xof(self, data: &[u8], result_len: usize) -> Vec<u8>;
377
378    /// A static one-shot API that digests the input data and produces `result_len` bytes of output.
379    /// Fills the provided output slice.
380    fn hash_xof_out(self, data: &[u8], output: &mut [u8]) -> usize;
381
382    fn absorb(&mut self, data: &[u8]) -> Result<(), HashError>;
383
384    /// Switches to squeezing.
385    fn absorb_last_partial_byte(
386        &mut self,
387        partial_byte: u8,
388        num_partial_bits: usize,
389    ) -> Result<(), HashError>;
390
391    /// Can be called multiple times.
392    fn squeeze(&mut self, num_bytes: usize) -> Result<Vec<u8>, HashError>;
393
394    /// Can be called multiple times.
395    /// Fills the provided output slice.
396    fn squeeze_out(&mut self, output: &mut [u8]) -> Result<usize, HashError>;
397
398    /// Squeezes a partial byte from the XOF.
399    /// Output will be in the top `num_bits` bits of the returned u8 (ie Big Endian).
400    /// This is a final call and consumes self.
401    fn squeeze_partial_byte_final(self, num_bits: usize) -> Result<u8, HashError>;
402
403    fn squeeze_partial_byte_final_out(
404        self,
405        num_bits: usize,
406        output: &mut u8,
407    ) -> Result<(), HashError>;
408
409    /// Returns the maximum security strength that this KDF is capable of supporting, based on the underlying primitives.
410    fn max_security_strength(&self) -> SecurityStrength;
411}