| 1 | //! This crate provides traits which describe functionality of cryptographic hash |
| 2 | //! functions and Message Authentication algorithms. |
| 3 | //! |
| 4 | //! Traits in this repository are organized into the following levels: |
| 5 | //! |
| 6 | //! - **High-level convenience traits**: [`Digest`], [`DynDigest`], [`Mac`]. |
| 7 | //! Wrappers around lower-level traits for most common use-cases. Users should |
| 8 | //! usually prefer using these traits. |
| 9 | //! - **Mid-level traits**: [`Update`], [`FixedOutput`], [`FixedOutputReset`], |
| 10 | //! [`ExtendableOutput`], [`ExtendableOutputReset`], [`XofReader`], |
| 11 | //! [`VariableOutput`], [`Reset`], [`KeyInit`], and [`InnerInit`]. These |
| 12 | //! traits atomically describe available functionality of an algorithm. |
| 13 | //! - **Marker traits**: [`HashMarker`], [`MacMarker`]. Used to distinguish |
| 14 | //! different algorithm classes. |
| 15 | //! - **Low-level traits** defined in the [`core_api`] module. These traits |
| 16 | //! operate at a block-level and do not contain any built-in buffering. |
| 17 | //! They are intended to be implemented by low-level algorithm providers only. |
| 18 | //! Usually they should not be used in application-level code. |
| 19 | //! |
| 20 | //! Additionally hash functions implement traits from the standard library: |
| 21 | //! [`Default`], [`Clone`], [`Write`][std::io::Write]. The latter is |
| 22 | //! feature-gated behind `std` feature, which is usually enabled by default |
| 23 | //! by hash implementation crates. |
| 24 | |
| 25 | #![no_std ] |
| 26 | #![cfg_attr (docsrs, feature(doc_cfg))] |
| 27 | #![forbid (unsafe_code)] |
| 28 | #![doc ( |
| 29 | html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" , |
| 30 | html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" |
| 31 | )] |
| 32 | #![warn (missing_docs, rust_2018_idioms)] |
| 33 | |
| 34 | #[cfg (feature = "alloc" )] |
| 35 | #[macro_use ] |
| 36 | extern crate alloc; |
| 37 | |
| 38 | #[cfg (feature = "std" )] |
| 39 | extern crate std; |
| 40 | |
| 41 | #[cfg (feature = "rand_core" )] |
| 42 | #[cfg_attr (docsrs, doc(cfg(feature = "rand_core" )))] |
| 43 | pub use crypto_common::rand_core; |
| 44 | |
| 45 | #[cfg (feature = "alloc" )] |
| 46 | use alloc::boxed::Box; |
| 47 | |
| 48 | #[cfg (feature = "dev" )] |
| 49 | #[cfg_attr (docsrs, doc(cfg(feature = "dev" )))] |
| 50 | pub mod dev; |
| 51 | |
| 52 | #[cfg (feature = "core-api" )] |
| 53 | #[cfg_attr (docsrs, doc(cfg(feature = "core-api" )))] |
| 54 | pub mod core_api; |
| 55 | mod digest; |
| 56 | #[cfg (feature = "mac" )] |
| 57 | mod mac; |
| 58 | |
| 59 | #[cfg (feature = "core-api" )] |
| 60 | #[cfg_attr (docsrs, doc(cfg(feature = "core-api" )))] |
| 61 | pub use block_buffer; |
| 62 | #[cfg (feature = "oid" )] |
| 63 | #[cfg_attr (docsrs, doc(cfg(feature = "oid" )))] |
| 64 | pub use const_oid; |
| 65 | pub use crypto_common; |
| 66 | |
| 67 | pub use crate::digest::{Digest, DynDigest, HashMarker}; |
| 68 | pub use crypto_common::{generic_array, typenum, typenum::consts, Output, OutputSizeUser, Reset}; |
| 69 | #[cfg (feature = "mac" )] |
| 70 | pub use crypto_common::{InnerInit, InvalidLength, Key, KeyInit}; |
| 71 | #[cfg (feature = "mac" )] |
| 72 | pub use mac::{CtOutput, Mac, MacError, MacMarker}; |
| 73 | |
| 74 | use core::fmt; |
| 75 | |
| 76 | /// Types which consume data with byte granularity. |
| 77 | pub trait Update { |
| 78 | /// Update state using the provided data. |
| 79 | fn update(&mut self, data: &[u8]); |
| 80 | |
| 81 | /// Digest input data in a chained manner. |
| 82 | #[must_use ] |
| 83 | fn chain(mut self, data: impl AsRef<[u8]>) -> Self |
| 84 | where |
| 85 | Self: Sized, |
| 86 | { |
| 87 | self.update(data.as_ref()); |
| 88 | self |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | /// Trait for hash functions with fixed-size output. |
| 93 | pub trait FixedOutput: Update + OutputSizeUser + Sized { |
| 94 | /// Consume value and write result into provided array. |
| 95 | fn finalize_into(self, out: &mut Output<Self>); |
| 96 | |
| 97 | /// Retrieve result and consume the hasher instance. |
| 98 | #[inline ] |
| 99 | fn finalize_fixed(self) -> Output<Self> { |
| 100 | let mut out: GenericArray::OutputSize> = Default::default(); |
| 101 | self.finalize_into(&mut out); |
| 102 | out |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | /// Trait for hash functions with fixed-size output able to reset themselves. |
| 107 | pub trait FixedOutputReset: FixedOutput + Reset { |
| 108 | /// Write result into provided array and reset the hasher state. |
| 109 | fn finalize_into_reset(&mut self, out: &mut Output<Self>); |
| 110 | |
| 111 | /// Retrieve result and reset the hasher state. |
| 112 | #[inline ] |
| 113 | fn finalize_fixed_reset(&mut self) -> Output<Self> { |
| 114 | let mut out: GenericArray::OutputSize> = Default::default(); |
| 115 | self.finalize_into_reset(&mut out); |
| 116 | out |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | /// Trait for reader types which are used to extract extendable output |
| 121 | /// from a XOF (extendable-output function) result. |
| 122 | pub trait XofReader { |
| 123 | /// Read output into the `buffer`. Can be called an unlimited number of times. |
| 124 | fn read(&mut self, buffer: &mut [u8]); |
| 125 | |
| 126 | /// Read output into a boxed slice of the specified size. |
| 127 | /// |
| 128 | /// Can be called an unlimited number of times in combination with `read`. |
| 129 | /// |
| 130 | /// `Box<[u8]>` is used instead of `Vec<u8>` to save stack space, since |
| 131 | /// they have size of 2 and 3 words respectively. |
| 132 | #[cfg (feature = "alloc" )] |
| 133 | #[cfg_attr (docsrs, doc(cfg(feature = "alloc" )))] |
| 134 | fn read_boxed(&mut self, n: usize) -> Box<[u8]> { |
| 135 | let mut buf: Box<[u8]> = vec![0u8; n].into_boxed_slice(); |
| 136 | self.read(&mut buf); |
| 137 | buf |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | /// Trait for hash functions with extendable-output (XOF). |
| 142 | pub trait ExtendableOutput: Sized + Update { |
| 143 | /// Reader |
| 144 | type Reader: XofReader; |
| 145 | |
| 146 | /// Retrieve XOF reader and consume hasher instance. |
| 147 | fn finalize_xof(self) -> Self::Reader; |
| 148 | |
| 149 | /// Finalize XOF and write result into `out`. |
| 150 | fn finalize_xof_into(self, out: &mut [u8]) { |
| 151 | self.finalize_xof().read(out); |
| 152 | } |
| 153 | |
| 154 | /// Compute hash of `data` and write it into `output`. |
| 155 | fn digest_xof(input: impl AsRef<[u8]>, output: &mut [u8]) |
| 156 | where |
| 157 | Self: Default, |
| 158 | { |
| 159 | let mut hasher = Self::default(); |
| 160 | hasher.update(input.as_ref()); |
| 161 | hasher.finalize_xof().read(output); |
| 162 | } |
| 163 | |
| 164 | /// Retrieve result into a boxed slice of the specified size and consume |
| 165 | /// the hasher. |
| 166 | /// |
| 167 | /// `Box<[u8]>` is used instead of `Vec<u8>` to save stack space, since |
| 168 | /// they have size of 2 and 3 words respectively. |
| 169 | #[cfg (feature = "alloc" )] |
| 170 | #[cfg_attr (docsrs, doc(cfg(feature = "alloc" )))] |
| 171 | fn finalize_boxed(self, output_size: usize) -> Box<[u8]> { |
| 172 | let mut buf = vec![0u8; output_size].into_boxed_slice(); |
| 173 | self.finalize_xof().read(&mut buf); |
| 174 | buf |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | /// Trait for hash functions with extendable-output (XOF) able to reset themselves. |
| 179 | pub trait ExtendableOutputReset: ExtendableOutput + Reset { |
| 180 | /// Retrieve XOF reader and reset hasher instance state. |
| 181 | fn finalize_xof_reset(&mut self) -> Self::Reader; |
| 182 | |
| 183 | /// Finalize XOF, write result into `out`, and reset the hasher state. |
| 184 | fn finalize_xof_reset_into(&mut self, out: &mut [u8]) { |
| 185 | self.finalize_xof_reset().read(buffer:out); |
| 186 | } |
| 187 | |
| 188 | /// Retrieve result into a boxed slice of the specified size and reset |
| 189 | /// the hasher state. |
| 190 | /// |
| 191 | /// `Box<[u8]>` is used instead of `Vec<u8>` to save stack space, since |
| 192 | /// they have size of 2 and 3 words respectively. |
| 193 | #[cfg (feature = "alloc" )] |
| 194 | #[cfg_attr (docsrs, doc(cfg(feature = "alloc" )))] |
| 195 | fn finalize_boxed_reset(&mut self, output_size: usize) -> Box<[u8]> { |
| 196 | let mut buf: Box<[u8]> = vec![0u8; output_size].into_boxed_slice(); |
| 197 | self.finalize_xof_reset().read(&mut buf); |
| 198 | buf |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | /// Trait for hash functions with variable-size output. |
| 203 | pub trait VariableOutput: Sized + Update { |
| 204 | /// Maximum size of output hash. |
| 205 | const MAX_OUTPUT_SIZE: usize; |
| 206 | |
| 207 | /// Create new hasher instance with the given output size. |
| 208 | /// |
| 209 | /// It will return `Err(InvalidOutputSize)` in case if hasher can not return |
| 210 | /// hash of the specified output size. |
| 211 | fn new(output_size: usize) -> Result<Self, InvalidOutputSize>; |
| 212 | |
| 213 | /// Get output size of the hasher instance provided to the `new` method |
| 214 | fn output_size(&self) -> usize; |
| 215 | |
| 216 | /// Write result into the output buffer. |
| 217 | /// |
| 218 | /// Returns `Err(InvalidOutputSize)` if `out` size is not equal to |
| 219 | /// `self.output_size()`. |
| 220 | fn finalize_variable(self, out: &mut [u8]) -> Result<(), InvalidBufferSize>; |
| 221 | |
| 222 | /// Compute hash of `data` and write it to `output`. |
| 223 | /// |
| 224 | /// Length of the output hash is determined by `output`. If `output` is |
| 225 | /// bigger than `Self::MAX_OUTPUT_SIZE`, this method returns |
| 226 | /// `InvalidOutputSize`. |
| 227 | fn digest_variable( |
| 228 | input: impl AsRef<[u8]>, |
| 229 | output: &mut [u8], |
| 230 | ) -> Result<(), InvalidOutputSize> { |
| 231 | let mut hasher = Self::new(output.len())?; |
| 232 | hasher.update(input.as_ref()); |
| 233 | hasher |
| 234 | .finalize_variable(output) |
| 235 | .map_err(|_| InvalidOutputSize) |
| 236 | } |
| 237 | |
| 238 | /// Retrieve result into a boxed slice and consume hasher. |
| 239 | /// |
| 240 | /// `Box<[u8]>` is used instead of `Vec<u8>` to save stack space, since |
| 241 | /// they have size of 2 and 3 words respectively. |
| 242 | #[cfg (feature = "alloc" )] |
| 243 | #[cfg_attr (docsrs, doc(cfg(feature = "alloc" )))] |
| 244 | fn finalize_boxed(self) -> Box<[u8]> { |
| 245 | let n = self.output_size(); |
| 246 | let mut buf = vec![0u8; n].into_boxed_slice(); |
| 247 | self.finalize_variable(&mut buf) |
| 248 | .expect("buf length is equal to output_size" ); |
| 249 | buf |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | /// Trait for hash functions with variable-size output able to reset themselves. |
| 254 | pub trait VariableOutputReset: VariableOutput + Reset { |
| 255 | /// Write result into the output buffer and reset the hasher state. |
| 256 | /// |
| 257 | /// Returns `Err(InvalidOutputSize)` if `out` size is not equal to |
| 258 | /// `self.output_size()`. |
| 259 | fn finalize_variable_reset(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize>; |
| 260 | |
| 261 | /// Retrieve result into a boxed slice and reset the hasher state. |
| 262 | /// |
| 263 | /// `Box<[u8]>` is used instead of `Vec<u8>` to save stack space, since |
| 264 | /// they have size of 2 and 3 words respectively. |
| 265 | #[cfg (feature = "alloc" )] |
| 266 | #[cfg_attr (docsrs, doc(cfg(feature = "alloc" )))] |
| 267 | fn finalize_boxed_reset(&mut self) -> Box<[u8]> { |
| 268 | let n: usize = self.output_size(); |
| 269 | let mut buf: Box<[u8]> = vec![0u8; n].into_boxed_slice(); |
| 270 | self.finalize_variable_reset(&mut buf) |
| 271 | .expect(msg:"buf length is equal to output_size" ); |
| 272 | buf |
| 273 | } |
| 274 | } |
| 275 | |
| 276 | /// The error type used in variable hash traits. |
| 277 | #[derive (Clone, Copy, Debug, Default)] |
| 278 | pub struct InvalidOutputSize; |
| 279 | |
| 280 | impl fmt::Display for InvalidOutputSize { |
| 281 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 282 | f.write_str(data:"invalid output size" ) |
| 283 | } |
| 284 | } |
| 285 | |
| 286 | #[cfg (feature = "std" )] |
| 287 | #[cfg_attr (docsrs, doc(cfg(feature = "std" )))] |
| 288 | impl std::error::Error for InvalidOutputSize {} |
| 289 | |
| 290 | /// Buffer length is not equal to hash output size. |
| 291 | #[derive (Default, Debug, Copy, Clone, Eq, PartialEq)] |
| 292 | pub struct InvalidBufferSize; |
| 293 | |
| 294 | impl fmt::Display for InvalidBufferSize { |
| 295 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 296 | f.write_str(data:"invalid buffer length" ) |
| 297 | } |
| 298 | } |
| 299 | |
| 300 | #[cfg (feature = "std" )] |
| 301 | impl std::error::Error for InvalidBufferSize {} |
| 302 | |