]> git.proxmox.com Git - rustc.git/blame - vendor/orion/src/hazardous/hash/sha2/sha256.rs
New upstream version 1.76.0+dfsg1
[rustc.git] / vendor / orion / src / hazardous / hash / sha2 / sha256.rs
CommitLineData
0a29b90c
FG
1// MIT License
2
49aad941 3// Copyright (c) 2020-2023 The orion Developers
0a29b90c
FG
4
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23//! # Parameters:
24//! - `data`: The data to be hashed.
25//!
26//! # Errors:
27//! An error will be returned if:
28//! - [`finalize()`] is called twice without a [`reset()`] in between.
29//! - [`update()`] is called after [`finalize()`] without a [`reset()`] in
30//! between.
31//!
32//! # Panics:
33//! A panic will occur if:
34//! - More than 2*(2^32-1) __bits__ of data are hashed.
35//!
36//! # Security:
37//! - SHA256 is vulnerable to length extension attacks.
38//!
39//! # Recommendation:
40//! - It is recommended to use [BLAKE2b] when possible.
41//!
42//! # Example:
43//! ```rust
44//! use orion::hazardous::hash::sha2::sha256::Sha256;
45//!
46//! // Using the streaming interface
47//! let mut state = Sha256::new();
48//! state.update(b"Hello world")?;
49//! let hash = state.finalize()?;
50//!
51//! // Using the one-shot function
52//! let hash_one_shot = Sha256::digest(b"Hello world")?;
53//!
54//! assert_eq!(hash, hash_one_shot);
55//! # Ok::<(), orion::errors::UnknownCryptoError>(())
56//! ```
57//! [`update()`]: sha256::Sha256::update
58//! [`reset()`]: sha256::Sha256::reset
59//! [`finalize()`]: sha256::Sha256::finalize
60//! [BLAKE2b]: super::blake2::blake2b
61
62use crate::errors::UnknownCryptoError;
63
64#[cfg(feature = "safe_api")]
65use std::io;
66
67/// The blocksize for the hash function SHA256.
68pub const SHA256_BLOCKSIZE: usize = 64;
69/// The output size for the hash function SHA256.
70pub const SHA256_OUTSIZE: usize = 32;
71/// The number of constants for the hash function SHA256.
72const N_CONSTS: usize = 64;
73
74construct_public! {
75 /// A type to represent the `Digest` that SHA256 returns.
76 ///
77 /// # Errors:
78 /// An error will be returned if:
79 /// - `slice` is not 32 bytes.
80 (Digest, test_digest, SHA256_OUTSIZE, SHA256_OUTSIZE)
81}
82
83impl_from_trait!(Digest, SHA256_OUTSIZE);
84
85use super::sha2_core::{State, Variant, Word};
86use super::w32::WordU32;
87
88#[derive(Clone)]
89/// SHA256 streaming state.
90pub(crate) struct V256;
91
4b012472 92impl Variant<WordU32, N_CONSTS> for V256 {
0a29b90c
FG
93 #[rustfmt::skip]
94 #[allow(clippy::unreadable_literal)]
95 /// The SHA256 constants as defined in FIPS 180-4.
96 const K: [WordU32; N_CONSTS] = [
97 WordU32(0x428a2f98), WordU32(0x71374491), WordU32(0xb5c0fbcf), WordU32(0xe9b5dba5),
98 WordU32(0x3956c25b), WordU32(0x59f111f1), WordU32(0x923f82a4), WordU32(0xab1c5ed5),
99 WordU32(0xd807aa98), WordU32(0x12835b01), WordU32(0x243185be), WordU32(0x550c7dc3),
100 WordU32(0x72be5d74), WordU32(0x80deb1fe), WordU32(0x9bdc06a7), WordU32(0xc19bf174),
101 WordU32(0xe49b69c1), WordU32(0xefbe4786), WordU32(0x0fc19dc6), WordU32(0x240ca1cc),
102 WordU32(0x2de92c6f), WordU32(0x4a7484aa), WordU32(0x5cb0a9dc), WordU32(0x76f988da),
103 WordU32(0x983e5152), WordU32(0xa831c66d), WordU32(0xb00327c8), WordU32(0xbf597fc7),
104 WordU32(0xc6e00bf3), WordU32(0xd5a79147), WordU32(0x06ca6351), WordU32(0x14292967),
105 WordU32(0x27b70a85), WordU32(0x2e1b2138), WordU32(0x4d2c6dfc), WordU32(0x53380d13),
106 WordU32(0x650a7354), WordU32(0x766a0abb), WordU32(0x81c2c92e), WordU32(0x92722c85),
107 WordU32(0xa2bfe8a1), WordU32(0xa81a664b), WordU32(0xc24b8b70), WordU32(0xc76c51a3),
108 WordU32(0xd192e819), WordU32(0xd6990624), WordU32(0xf40e3585), WordU32(0x106aa070),
109 WordU32(0x19a4c116), WordU32(0x1e376c08), WordU32(0x2748774c), WordU32(0x34b0bcb5),
110 WordU32(0x391c0cb3), WordU32(0x4ed8aa4a), WordU32(0x5b9cca4f), WordU32(0x682e6ff3),
111 WordU32(0x748f82ee), WordU32(0x78a5636f), WordU32(0x84c87814), WordU32(0x8cc70208),
112 WordU32(0x90befffa), WordU32(0xa4506ceb), WordU32(0xbef9a3f7), WordU32(0xc67178f2),
113 ];
114
115 #[rustfmt::skip]
116 #[allow(clippy::unreadable_literal)]
117 /// The SHA256 initial hash value H(0) as defined in FIPS 180-4.
118 const H0: [WordU32; 8] = [
119 WordU32(0x6a09e667), WordU32(0xbb67ae85), WordU32(0x3c6ef372), WordU32(0xa54ff53a),
120 WordU32(0x510e527f), WordU32(0x9b05688c), WordU32(0x1f83d9ab), WordU32(0x5be0cd19),
121 ];
122
123 /// The Big Sigma 0 function as specified in FIPS 180-4 section 4.1.2.
124 fn big_sigma_0(x: WordU32) -> WordU32 {
125 (x.rotate_right(2)) ^ x.rotate_right(13) ^ x.rotate_right(22)
126 }
127
128 /// The Big Sigma 1 function as specified in FIPS 180-4 section 4.1.2.
129 fn big_sigma_1(x: WordU32) -> WordU32 {
130 (x.rotate_right(6)) ^ x.rotate_right(11) ^ x.rotate_right(25)
131 }
132
133 /// The Small Sigma 0 function as specified in FIPS 180-4 section 4.1.2.
134 fn small_sigma_0(x: WordU32) -> WordU32 {
135 (x.rotate_right(7)) ^ x.rotate_right(18) ^ (x >> WordU32(3))
136 }
137
138 /// The Small Sigma 1 function as specified in FIPS 180-4 section 4.1.2.
139 fn small_sigma_1(x: WordU32) -> WordU32 {
140 (x.rotate_right(17)) ^ x.rotate_right(19) ^ (x >> WordU32(10))
141 }
142}
143
144#[derive(Clone, Debug)]
145/// SHA256 streaming state.
146pub struct Sha256 {
4b012472 147 pub(crate) _state: State<WordU32, V256, SHA256_BLOCKSIZE, SHA256_OUTSIZE, N_CONSTS>,
0a29b90c
FG
148}
149
150impl Default for Sha256 {
151 fn default() -> Self {
152 Self::new()
153 }
154}
155
156impl Sha256 {
157 /// Initialize a `Sha256` struct.
158 pub fn new() -> Self {
159 Self {
4b012472 160 _state: State::<WordU32, V256, SHA256_BLOCKSIZE, SHA256_OUTSIZE, N_CONSTS>::_new(),
0a29b90c
FG
161 }
162 }
163
164 /// Reset to `new()` state.
165 pub fn reset(&mut self) {
166 self._state._reset();
167 }
168
169 #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
170 /// Update state with `data`. This can be called multiple times.
171 pub fn update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
172 self._state._update(data)
173 }
174
175 /// Finalize the hash and put the final digest into `dest`.
176 pub(crate) fn _finalize_internal(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
177 self._state._finalize(dest)
178 }
179
180 #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
181 /// Return a SHA256 digest.
182 pub fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
183 let mut digest = [0u8; SHA256_OUTSIZE];
184 self._finalize_internal(&mut digest)?;
185
186 Ok(Digest::from(digest))
187 }
188
189 #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
190 /// Calculate a SHA256 digest of some `data`.
191 pub fn digest(data: &[u8]) -> Result<Digest, UnknownCryptoError> {
192 let mut ctx = Self::new();
193 ctx.update(data)?;
194 ctx.finalize()
195 }
196}
197
198impl crate::hazardous::mac::hmac::HmacHashFunction for Sha256 {
199 /// The blocksize of the hash function.
200 const _BLOCKSIZE: usize = SHA256_BLOCKSIZE;
201
202 /// The output size of the hash function.
203 const _OUTSIZE: usize = SHA256_OUTSIZE;
204
205 /// Create a new instance of the hash function.
206 fn _new() -> Self {
207 Self::new()
208 }
209
210 /// Update the internal state with `data`.
211 fn _update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
212 self.update(data)
213 }
214
215 /// Finalize the hash and put the final digest into `dest`.
216 fn _finalize(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
217 self._finalize_internal(dest)
218 }
219
220 /// Compute a digest of `data` and copy it into `dest`.
221 fn _digest(data: &[u8], dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
222 let mut ctx = Self::new();
223 ctx.update(data)?;
224 ctx._finalize_internal(dest)
225 }
226
227 #[cfg(test)]
228 fn compare_state_to_other(&self, other: &Self) {
229 self._state.compare_state_to_other(&other._state);
230 }
231}
232
233#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
234/// Example: hashing from a [`Read`](std::io::Read)er with SHA256.
235/// ```rust
236/// use orion::{
237/// hazardous::hash::sha2::sha256::{Sha256, Digest},
238/// errors::UnknownCryptoError,
239/// };
240/// use std::io::{self, Read, Write};
241///
242/// // `reader` could also be a `File::open(...)?`.
243/// let mut reader = io::Cursor::new(b"some data");
244/// let mut hasher = Sha256::new();
245/// std::io::copy(&mut reader, &mut hasher)?;
246///
247/// let digest: Digest = hasher.finalize()?;
248///
249/// # Ok::<(), Box<dyn std::error::Error>>(())
250/// ```
251#[cfg(feature = "safe_api")]
252impl io::Write for Sha256 {
253 /// Update the hasher's internal state with *all* of the bytes given.
254 /// If this function returns the `Ok` variant, it's guaranteed that it
255 /// will contain the length of the buffer passed to [`Write`](std::io::Write).
256 /// Note that this function is just a small wrapper over
257 /// [`Sha256::update`](crate::hazardous::hash::sha2::sha256::Sha256::update).
258 ///
259 /// ## Errors:
260 /// This function will only ever return the [`std::io::ErrorKind::Other`]()
261 /// variant when it returns an error. Additionally, this will always contain Orion's
262 /// [`UnknownCryptoError`](crate::errors::UnknownCryptoError) type.
263 fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
264 self.update(bytes)
265 .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
266 Ok(bytes.len())
267 }
268
269 /// This type doesn't buffer writes, so flushing is a no-op.
270 fn flush(&mut self) -> Result<(), std::io::Error> {
271 Ok(())
272 }
273}
274
275// Testing public functions in the module.
276#[cfg(test)]
277mod public {
278 use super::*;
279
280 #[test]
281 fn test_default_equals_new() {
282 let new = Sha256::new();
283 let default = Sha256::default();
284 new._state.compare_state_to_other(&default._state);
285 }
286
287 #[test]
288 #[cfg(feature = "safe_api")]
289 fn test_debug_impl() {
290 let initial_state = Sha256::new();
291 let debug = format!("{:?}", initial_state);
292 let expected = "Sha256 { _state: State { working_state: [***OMITTED***], buffer: [***OMITTED***], leftover: 0, message_len: [WordU32(0), WordU32(0)], is_finalized: false } }";
293 assert_eq!(debug, expected);
294 }
295
296 mod test_streaming_interface {
297 use super::*;
298 use crate::test_framework::incremental_interface::*;
299
300 impl TestableStreamingContext<Digest> for Sha256 {
301 fn reset(&mut self) -> Result<(), UnknownCryptoError> {
302 self.reset();
303 Ok(())
304 }
305
306 fn update(&mut self, input: &[u8]) -> Result<(), UnknownCryptoError> {
307 self.update(input)
308 }
309
310 fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
311 self.finalize()
312 }
313
314 fn one_shot(input: &[u8]) -> Result<Digest, UnknownCryptoError> {
315 Sha256::digest(input)
316 }
317
318 fn verify_result(expected: &Digest, input: &[u8]) -> Result<(), UnknownCryptoError> {
319 let actual: Digest = Self::one_shot(input)?;
320
321 if &actual == expected {
322 Ok(())
323 } else {
324 Err(UnknownCryptoError)
325 }
326 }
327
328 fn compare_states(state_1: &Sha256, state_2: &Sha256) {
329 state_1._state.compare_state_to_other(&state_2._state);
330 }
331 }
332
333 #[test]
334 fn default_consistency_tests() {
335 let initial_state: Sha256 = Sha256::new();
336
337 let test_runner = StreamingContextConsistencyTester::<Digest, Sha256>::new(
338 initial_state,
339 SHA256_BLOCKSIZE,
340 );
341 test_runner.run_all_tests();
342 }
343
344 #[quickcheck]
345 #[cfg(feature = "safe_api")]
346 /// Related bug: https://github.com/orion-rs/orion/issues/46
347 /// Test different streaming state usage patterns.
348 fn prop_input_to_consistency(data: Vec<u8>) -> bool {
349 let initial_state: Sha256 = Sha256::new();
350
351 let test_runner = StreamingContextConsistencyTester::<Digest, Sha256>::new(
352 initial_state,
353 SHA256_BLOCKSIZE,
354 );
355 test_runner.run_all_tests_property(&data);
356 true
357 }
358 }
359
360 #[cfg(feature = "safe_api")]
361 mod test_io_impls {
362 use crate::hazardous::hash::sha2::sha256::Sha256;
363 use std::io::Write;
364
365 #[quickcheck]
366 fn prop_hasher_write_same_as_update(data: Vec<u8>) -> bool {
367 let mut hasher_a = Sha256::new();
368 let mut hasher_b = hasher_a.clone();
369
370 hasher_a.update(&data).unwrap();
371 hasher_b.write_all(&data).unwrap();
372
373 let hash_a = hasher_a.finalize().unwrap();
374 let hash_b = hasher_b.finalize().unwrap();
375
376 hash_a == hash_b
377 }
378 }
379}
380
381// Testing private functions in the module.
382#[cfg(test)]
383mod private {
384 use super::*;
385
386 mod test_increment_mlen {
387 use super::*;
388
389 #[test]
390 fn test_mlen_increase_values() {
391 let mut context = Sha256::default();
392
393 context._state.increment_mlen(&WordU32::from(1u32));
394 assert_eq!(context._state.message_len[0], WordU32::from(0u32));
395 assert_eq!(context._state.message_len[1], WordU32::from(8u32));
396
397 context._state.increment_mlen(&WordU32::from(17u32));
398 assert_eq!(context._state.message_len[0], WordU32::from(0u32));
399 assert_eq!(context._state.message_len[1], WordU32::from(144u32));
400
401 context._state.increment_mlen(&WordU32::from(12u32));
402 assert_eq!(context._state.message_len[0], WordU32::from(0u32));
403 assert_eq!(context._state.message_len[1], WordU32::from(240u32));
404
405 // Overflow
406 context._state.increment_mlen(&WordU32::from(u32::MAX / 8));
407 assert_eq!(context._state.message_len[0], WordU32::from(1u32));
408 assert_eq!(context._state.message_len[1], WordU32::from(232u32));
409 }
410
411 #[test]
412 #[should_panic]
413 fn test_panic_on_second_overflow() {
414 let mut context = Sha256::default();
415 context._state.message_len = [WordU32::MAX, WordU32::from(u32::MAX - 7)];
416 // u32::MAX - 7, to leave so that the length represented
417 // in bites should overflow by exactly one.
418 context._state.increment_mlen(&WordU32::from(1u32));
419 }
420 }
421}