Jeff Vander Stoep | 39e02b1 | 2020-12-04 13:57:34 +0100 | [diff] [blame] | 1 | // Copyright 2015-2019 Brian Smith. |
| 2 | // |
| 3 | // Permission to use, copy, modify, and/or distribute this software for any |
| 4 | // purpose with or without fee is hereby granted, provided that the above |
| 5 | // copyright notice and this permission notice appear in all copies. |
| 6 | // |
| 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES |
| 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
| 10 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| 12 | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| 13 | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 14 | |
| 15 | //! SHA-2 and the legacy SHA-1 digest algorithm. |
| 16 | //! |
| 17 | //! If all the data is available in a single contiguous slice then the `digest` |
| 18 | //! function should be used. Otherwise, the digest can be calculated in |
| 19 | //! multiple steps using `Context`. |
| 20 | |
| 21 | // Note on why are we doing things the hard way: It would be easy to implement |
| 22 | // this using the C `EVP_MD`/`EVP_MD_CTX` interface. However, if we were to do |
| 23 | // things that way, we'd have a hard dependency on `malloc` and other overhead. |
| 24 | // The goal for this implementation is to drive the overhead as close to zero |
| 25 | // as possible. |
| 26 | |
| 27 | use crate::{ |
| 28 | c, cpu, debug, |
| 29 | endian::{self, BigEndian}, |
| 30 | polyfill, |
| 31 | }; |
| 32 | use core::num::Wrapping; |
| 33 | |
| 34 | mod sha1; |
| 35 | mod sha2; |
| 36 | |
| 37 | #[derive(Clone)] |
| 38 | pub(crate) struct BlockContext { |
| 39 | state: State, |
| 40 | |
| 41 | // Note that SHA-512 has a 128-bit input bit counter, but this |
| 42 | // implementation only supports up to 2^64-1 input bits for all algorithms, |
| 43 | // so a 64-bit counter is more than sufficient. |
| 44 | completed_data_blocks: u64, |
| 45 | |
| 46 | /// The context's algorithm. |
| 47 | pub algorithm: &'static Algorithm, |
| 48 | |
| 49 | cpu_features: cpu::Features, |
| 50 | } |
| 51 | |
| 52 | impl BlockContext { |
| 53 | pub(crate) fn new(algorithm: &'static Algorithm) -> Self { |
| 54 | Self { |
| 55 | state: algorithm.initial_state, |
| 56 | completed_data_blocks: 0, |
| 57 | algorithm, |
| 58 | cpu_features: cpu::features(), |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | #[inline] |
| 63 | pub(crate) fn update(&mut self, input: &[u8]) { |
| 64 | let num_blocks = input.len() / self.algorithm.block_len; |
| 65 | assert_eq!(num_blocks * self.algorithm.block_len, input.len()); |
| 66 | if num_blocks > 0 { |
| 67 | unsafe { |
| 68 | (self.algorithm.block_data_order)(&mut self.state, input.as_ptr(), num_blocks); |
| 69 | } |
| 70 | self.completed_data_blocks = self |
| 71 | .completed_data_blocks |
| 72 | .checked_add(polyfill::u64_from_usize(num_blocks)) |
| 73 | .unwrap(); |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | pub(crate) fn finish(mut self, pending: &mut [u8], num_pending: usize) -> Digest { |
| 78 | let block_len = self.algorithm.block_len; |
| 79 | assert_eq!(pending.len(), block_len); |
| 80 | assert!(num_pending <= pending.len()); |
| 81 | |
| 82 | let mut padding_pos = num_pending; |
| 83 | pending[padding_pos] = 0x80; |
| 84 | padding_pos += 1; |
| 85 | |
| 86 | if padding_pos > block_len - self.algorithm.len_len { |
| 87 | polyfill::slice::fill(&mut pending[padding_pos..block_len], 0); |
| 88 | unsafe { |
| 89 | (self.algorithm.block_data_order)(&mut self.state, pending.as_ptr(), 1); |
| 90 | } |
| 91 | // We don't increase |self.completed_data_blocks| because the |
| 92 | // padding isn't data, and so it isn't included in the data length. |
| 93 | padding_pos = 0; |
| 94 | } |
| 95 | |
| 96 | polyfill::slice::fill(&mut pending[padding_pos..(block_len - 8)], 0); |
| 97 | |
| 98 | // Output the length, in bits, in big endian order. |
| 99 | let completed_data_bits = self |
| 100 | .completed_data_blocks |
| 101 | .checked_mul(polyfill::u64_from_usize(block_len)) |
| 102 | .unwrap() |
| 103 | .checked_add(polyfill::u64_from_usize(num_pending)) |
| 104 | .unwrap() |
| 105 | .checked_mul(8) |
| 106 | .unwrap(); |
| 107 | pending[(block_len - 8)..block_len].copy_from_slice(&u64::to_be_bytes(completed_data_bits)); |
| 108 | |
| 109 | unsafe { |
| 110 | (self.algorithm.block_data_order)(&mut self.state, pending.as_ptr(), 1); |
| 111 | } |
| 112 | |
| 113 | Digest { |
| 114 | algorithm: self.algorithm, |
| 115 | value: (self.algorithm.format_output)(self.state), |
| 116 | } |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | /// A context for multi-step (Init-Update-Finish) digest calculations. |
| 121 | /// |
| 122 | /// # Examples |
| 123 | /// |
| 124 | /// ``` |
| 125 | /// use ring::digest; |
| 126 | /// |
| 127 | /// let one_shot = digest::digest(&digest::SHA384, b"hello, world"); |
| 128 | /// |
| 129 | /// let mut ctx = digest::Context::new(&digest::SHA384); |
| 130 | /// ctx.update(b"hello"); |
| 131 | /// ctx.update(b", "); |
| 132 | /// ctx.update(b"world"); |
| 133 | /// let multi_part = ctx.finish(); |
| 134 | /// |
| 135 | /// assert_eq!(&one_shot.as_ref(), &multi_part.as_ref()); |
| 136 | /// ``` |
| 137 | #[derive(Clone)] |
| 138 | pub struct Context { |
| 139 | block: BlockContext, |
| 140 | // TODO: More explicitly force 64-bit alignment for |pending|. |
| 141 | pending: [u8; MAX_BLOCK_LEN], |
| 142 | num_pending: usize, |
| 143 | } |
| 144 | |
| 145 | impl Context { |
| 146 | /// Constructs a new context. |
| 147 | pub fn new(algorithm: &'static Algorithm) -> Self { |
| 148 | Self { |
| 149 | block: BlockContext::new(algorithm), |
| 150 | pending: [0u8; MAX_BLOCK_LEN], |
| 151 | num_pending: 0, |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | pub(crate) fn clone_from(block: &BlockContext) -> Self { |
| 156 | Self { |
| 157 | block: block.clone(), |
| 158 | pending: [0u8; MAX_BLOCK_LEN], |
| 159 | num_pending: 0, |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | /// Updates the digest with all the data in `data`. `update` may be called |
| 164 | /// zero or more times until `finish` is called. It must not be called |
| 165 | /// after `finish` has been called. |
| 166 | pub fn update(&mut self, data: &[u8]) { |
| 167 | let block_len = self.block.algorithm.block_len; |
| 168 | if data.len() < block_len - self.num_pending { |
| 169 | self.pending[self.num_pending..(self.num_pending + data.len())].copy_from_slice(data); |
| 170 | self.num_pending += data.len(); |
| 171 | return; |
| 172 | } |
| 173 | |
| 174 | let mut remaining = data; |
| 175 | if self.num_pending > 0 { |
| 176 | let to_copy = block_len - self.num_pending; |
| 177 | self.pending[self.num_pending..block_len].copy_from_slice(&data[..to_copy]); |
| 178 | self.block.update(&self.pending[..block_len]); |
| 179 | remaining = &remaining[to_copy..]; |
| 180 | self.num_pending = 0; |
| 181 | } |
| 182 | |
| 183 | let num_blocks = remaining.len() / block_len; |
| 184 | let num_to_save_for_later = remaining.len() % block_len; |
| 185 | self.block.update(&remaining[..(num_blocks * block_len)]); |
| 186 | if num_to_save_for_later > 0 { |
| 187 | self.pending[..num_to_save_for_later] |
| 188 | .copy_from_slice(&remaining[(remaining.len() - num_to_save_for_later)..]); |
| 189 | self.num_pending = num_to_save_for_later; |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | /// Finalizes the digest calculation and returns the digest value. `finish` |
| 194 | /// consumes the context so it cannot be (mis-)used after `finish` has been |
| 195 | /// called. |
| 196 | pub fn finish(mut self) -> Digest { |
| 197 | let block_len = self.block.algorithm.block_len; |
| 198 | self.block |
| 199 | .finish(&mut self.pending[..block_len], self.num_pending) |
| 200 | } |
| 201 | |
| 202 | /// The algorithm that this context is using. |
| 203 | #[inline(always)] |
| 204 | pub fn algorithm(&self) -> &'static Algorithm { |
| 205 | self.block.algorithm |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | /// Returns the digest of `data` using the given digest algorithm. |
| 210 | /// |
| 211 | /// # Examples: |
| 212 | /// |
| 213 | /// ``` |
| 214 | /// # #[cfg(feature = "alloc")] |
| 215 | /// # { |
| 216 | /// use ring::{digest, test}; |
| 217 | /// let expected_hex = "09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b"; |
| 218 | /// let expected: Vec<u8> = test::from_hex(expected_hex).unwrap(); |
| 219 | /// let actual = digest::digest(&digest::SHA256, b"hello, world"); |
| 220 | /// |
| 221 | /// assert_eq!(&expected, &actual.as_ref()); |
| 222 | /// # } |
| 223 | /// ``` |
| 224 | pub fn digest(algorithm: &'static Algorithm, data: &[u8]) -> Digest { |
| 225 | let mut ctx = Context::new(algorithm); |
| 226 | ctx.update(data); |
| 227 | ctx.finish() |
| 228 | } |
| 229 | |
| 230 | /// A calculated digest value. |
| 231 | /// |
| 232 | /// Use `as_ref` to get the value as a `&[u8]`. |
| 233 | #[derive(Clone, Copy)] |
| 234 | pub struct Digest { |
| 235 | value: Output, |
| 236 | algorithm: &'static Algorithm, |
| 237 | } |
| 238 | |
| 239 | impl Digest { |
| 240 | /// The algorithm that was used to calculate the digest value. |
| 241 | #[inline(always)] |
| 242 | pub fn algorithm(&self) -> &'static Algorithm { |
| 243 | self.algorithm |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | impl AsRef<[u8]> for Digest { |
| 248 | #[inline(always)] |
| 249 | fn as_ref(&self) -> &[u8] { |
| 250 | let as64 = unsafe { &self.value.as64 }; |
| 251 | &endian::as_byte_slice(as64)[..self.algorithm.output_len] |
| 252 | } |
| 253 | } |
| 254 | |
| 255 | impl core::fmt::Debug for Digest { |
| 256 | fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { |
| 257 | write!(fmt, "{:?}:", self.algorithm)?; |
| 258 | debug::write_hex_bytes(fmt, self.as_ref()) |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | /// A digest algorithm. |
| 263 | pub struct Algorithm { |
| 264 | /// The length of a finalized digest. |
| 265 | pub output_len: usize, |
| 266 | |
| 267 | /// The size of the chaining value of the digest function, in bytes. For |
| 268 | /// non-truncated algorithms (SHA-1, SHA-256, SHA-512), this is equal to |
| 269 | /// `output_len`. For truncated algorithms (e.g. SHA-384, SHA-512/256), |
| 270 | /// this is equal to the length before truncation. This is mostly helpful |
| 271 | /// for determining the size of an HMAC key that is appropriate for the |
| 272 | /// digest algorithm. |
| 273 | pub chaining_len: usize, |
| 274 | |
| 275 | /// The internal block length. |
| 276 | pub block_len: usize, |
| 277 | |
| 278 | /// The length of the length in the padding. |
| 279 | len_len: usize, |
| 280 | |
| 281 | block_data_order: unsafe extern "C" fn(state: &mut State, data: *const u8, num: c::size_t), |
| 282 | format_output: fn(input: State) -> Output, |
| 283 | |
| 284 | initial_state: State, |
| 285 | |
| 286 | id: AlgorithmID, |
| 287 | } |
| 288 | |
| 289 | #[derive(Debug, Eq, PartialEq)] |
| 290 | enum AlgorithmID { |
| 291 | SHA1, |
| 292 | SHA256, |
| 293 | SHA384, |
| 294 | SHA512, |
| 295 | SHA512_256, |
| 296 | } |
| 297 | |
| 298 | impl PartialEq for Algorithm { |
| 299 | fn eq(&self, other: &Self) -> bool { |
| 300 | self.id == other.id |
| 301 | } |
| 302 | } |
| 303 | |
| 304 | impl Eq for Algorithm {} |
| 305 | |
| 306 | derive_debug_via_id!(Algorithm); |
| 307 | |
| 308 | /// SHA-1 as specified in [FIPS 180-4]. Deprecated. |
| 309 | /// |
| 310 | /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
| 311 | pub static SHA1_FOR_LEGACY_USE_ONLY: Algorithm = Algorithm { |
| 312 | output_len: sha1::OUTPUT_LEN, |
| 313 | chaining_len: sha1::CHAINING_LEN, |
| 314 | block_len: sha1::BLOCK_LEN, |
| 315 | len_len: 64 / 8, |
| 316 | block_data_order: sha1::block_data_order, |
| 317 | format_output: sha256_format_output, |
| 318 | initial_state: State { |
| 319 | as32: [ |
| 320 | Wrapping(0x67452301u32), |
| 321 | Wrapping(0xefcdab89u32), |
| 322 | Wrapping(0x98badcfeu32), |
| 323 | Wrapping(0x10325476u32), |
| 324 | Wrapping(0xc3d2e1f0u32), |
| 325 | Wrapping(0), |
| 326 | Wrapping(0), |
| 327 | Wrapping(0), |
| 328 | ], |
| 329 | }, |
| 330 | id: AlgorithmID::SHA1, |
| 331 | }; |
| 332 | |
| 333 | /// SHA-256 as specified in [FIPS 180-4]. |
| 334 | /// |
| 335 | /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
| 336 | pub static SHA256: Algorithm = Algorithm { |
| 337 | output_len: SHA256_OUTPUT_LEN, |
| 338 | chaining_len: SHA256_OUTPUT_LEN, |
| 339 | block_len: 512 / 8, |
| 340 | len_len: 64 / 8, |
| 341 | block_data_order: sha2::GFp_sha256_block_data_order, |
| 342 | format_output: sha256_format_output, |
| 343 | initial_state: State { |
| 344 | as32: [ |
| 345 | Wrapping(0x6a09e667u32), |
| 346 | Wrapping(0xbb67ae85u32), |
| 347 | Wrapping(0x3c6ef372u32), |
| 348 | Wrapping(0xa54ff53au32), |
| 349 | Wrapping(0x510e527fu32), |
| 350 | Wrapping(0x9b05688cu32), |
| 351 | Wrapping(0x1f83d9abu32), |
| 352 | Wrapping(0x5be0cd19u32), |
| 353 | ], |
| 354 | }, |
| 355 | id: AlgorithmID::SHA256, |
| 356 | }; |
| 357 | |
| 358 | /// SHA-384 as specified in [FIPS 180-4]. |
| 359 | /// |
| 360 | /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
| 361 | pub static SHA384: Algorithm = Algorithm { |
| 362 | output_len: SHA384_OUTPUT_LEN, |
| 363 | chaining_len: SHA512_OUTPUT_LEN, |
| 364 | block_len: SHA512_BLOCK_LEN, |
| 365 | len_len: SHA512_LEN_LEN, |
| 366 | block_data_order: sha2::GFp_sha512_block_data_order, |
| 367 | format_output: sha512_format_output, |
| 368 | initial_state: State { |
| 369 | as64: [ |
| 370 | Wrapping(0xcbbb9d5dc1059ed8), |
| 371 | Wrapping(0x629a292a367cd507), |
| 372 | Wrapping(0x9159015a3070dd17), |
| 373 | Wrapping(0x152fecd8f70e5939), |
| 374 | Wrapping(0x67332667ffc00b31), |
| 375 | Wrapping(0x8eb44a8768581511), |
| 376 | Wrapping(0xdb0c2e0d64f98fa7), |
| 377 | Wrapping(0x47b5481dbefa4fa4), |
| 378 | ], |
| 379 | }, |
| 380 | id: AlgorithmID::SHA384, |
| 381 | }; |
| 382 | |
| 383 | /// SHA-512 as specified in [FIPS 180-4]. |
| 384 | /// |
| 385 | /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
| 386 | pub static SHA512: Algorithm = Algorithm { |
| 387 | output_len: SHA512_OUTPUT_LEN, |
| 388 | chaining_len: SHA512_OUTPUT_LEN, |
| 389 | block_len: SHA512_BLOCK_LEN, |
| 390 | len_len: SHA512_LEN_LEN, |
| 391 | block_data_order: sha2::GFp_sha512_block_data_order, |
| 392 | format_output: sha512_format_output, |
| 393 | initial_state: State { |
| 394 | as64: [ |
| 395 | Wrapping(0x6a09e667f3bcc908), |
| 396 | Wrapping(0xbb67ae8584caa73b), |
| 397 | Wrapping(0x3c6ef372fe94f82b), |
| 398 | Wrapping(0xa54ff53a5f1d36f1), |
| 399 | Wrapping(0x510e527fade682d1), |
| 400 | Wrapping(0x9b05688c2b3e6c1f), |
| 401 | Wrapping(0x1f83d9abfb41bd6b), |
| 402 | Wrapping(0x5be0cd19137e2179), |
| 403 | ], |
| 404 | }, |
| 405 | id: AlgorithmID::SHA512, |
| 406 | }; |
| 407 | |
| 408 | /// SHA-512/256 as specified in [FIPS 180-4]. |
| 409 | /// |
| 410 | /// This is *not* the same as just truncating the output of SHA-512, as |
| 411 | /// SHA-512/256 has its own initial state distinct from SHA-512's initial |
| 412 | /// state. |
| 413 | /// |
| 414 | /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
| 415 | pub static SHA512_256: Algorithm = Algorithm { |
| 416 | output_len: SHA512_256_OUTPUT_LEN, |
| 417 | chaining_len: SHA512_OUTPUT_LEN, |
| 418 | block_len: SHA512_BLOCK_LEN, |
| 419 | len_len: SHA512_LEN_LEN, |
| 420 | block_data_order: sha2::GFp_sha512_block_data_order, |
| 421 | format_output: sha512_format_output, |
| 422 | initial_state: State { |
| 423 | as64: [ |
| 424 | Wrapping(0x22312194fc2bf72c), |
| 425 | Wrapping(0x9f555fa3c84c64c2), |
| 426 | Wrapping(0x2393b86b6f53b151), |
| 427 | Wrapping(0x963877195940eabd), |
| 428 | Wrapping(0x96283ee2a88effe3), |
| 429 | Wrapping(0xbe5e1e2553863992), |
| 430 | Wrapping(0x2b0199fc2c85b8aa), |
| 431 | Wrapping(0x0eb72ddc81c52ca2), |
| 432 | ], |
| 433 | }, |
| 434 | id: AlgorithmID::SHA512_256, |
| 435 | }; |
| 436 | |
| 437 | #[derive(Clone, Copy)] // XXX: Why do we need to be `Copy`? |
| 438 | #[repr(C)] |
| 439 | union State { |
| 440 | as64: [Wrapping<u64>; sha2::CHAINING_WORDS], |
| 441 | as32: [Wrapping<u32>; sha2::CHAINING_WORDS], |
| 442 | } |
| 443 | |
| 444 | #[derive(Clone, Copy)] |
| 445 | #[repr(C)] |
| 446 | union Output { |
| 447 | as64: [BigEndian<u64>; 512 / 8 / core::mem::size_of::<BigEndian<u64>>()], |
| 448 | as32: [BigEndian<u32>; 256 / 8 / core::mem::size_of::<BigEndian<u32>>()], |
| 449 | } |
| 450 | |
| 451 | /// The maximum block length (`Algorithm::block_len`) of all the algorithms in |
| 452 | /// this module. |
| 453 | pub const MAX_BLOCK_LEN: usize = 1024 / 8; |
| 454 | |
| 455 | /// The maximum output length (`Algorithm::output_len`) of all the algorithms |
| 456 | /// in this module. |
| 457 | pub const MAX_OUTPUT_LEN: usize = 512 / 8; |
| 458 | |
| 459 | /// The maximum chaining length (`Algorithm::chaining_len`) of all the |
| 460 | /// algorithms in this module. |
| 461 | pub const MAX_CHAINING_LEN: usize = MAX_OUTPUT_LEN; |
| 462 | |
| 463 | fn sha256_format_output(input: State) -> Output { |
| 464 | let input = unsafe { &input.as32 }; |
| 465 | Output { |
| 466 | as32: [ |
| 467 | BigEndian::from(input[0]), |
| 468 | BigEndian::from(input[1]), |
| 469 | BigEndian::from(input[2]), |
| 470 | BigEndian::from(input[3]), |
| 471 | BigEndian::from(input[4]), |
| 472 | BigEndian::from(input[5]), |
| 473 | BigEndian::from(input[6]), |
| 474 | BigEndian::from(input[7]), |
| 475 | ], |
| 476 | } |
| 477 | } |
| 478 | |
| 479 | fn sha512_format_output(input: State) -> Output { |
| 480 | let input = unsafe { &input.as64 }; |
| 481 | Output { |
| 482 | as64: [ |
| 483 | BigEndian::from(input[0]), |
| 484 | BigEndian::from(input[1]), |
| 485 | BigEndian::from(input[2]), |
| 486 | BigEndian::from(input[3]), |
| 487 | BigEndian::from(input[4]), |
| 488 | BigEndian::from(input[5]), |
| 489 | BigEndian::from(input[6]), |
| 490 | BigEndian::from(input[7]), |
| 491 | ], |
| 492 | } |
| 493 | } |
| 494 | |
| 495 | /// The length of the output of SHA-1, in bytes. |
| 496 | pub const SHA1_OUTPUT_LEN: usize = sha1::OUTPUT_LEN; |
| 497 | |
| 498 | /// The length of the output of SHA-256, in bytes. |
| 499 | pub const SHA256_OUTPUT_LEN: usize = 256 / 8; |
| 500 | |
| 501 | /// The length of the output of SHA-384, in bytes. |
| 502 | pub const SHA384_OUTPUT_LEN: usize = 384 / 8; |
| 503 | |
| 504 | /// The length of the output of SHA-512, in bytes. |
| 505 | pub const SHA512_OUTPUT_LEN: usize = 512 / 8; |
| 506 | |
| 507 | /// The length of the output of SHA-512/256, in bytes. |
| 508 | pub const SHA512_256_OUTPUT_LEN: usize = 256 / 8; |
| 509 | |
| 510 | /// The length of a block for SHA-512-based algorithms, in bytes. |
| 511 | const SHA512_BLOCK_LEN: usize = 1024 / 8; |
| 512 | |
| 513 | /// The length of the length field for SHA-512-based algorithms, in bytes. |
| 514 | const SHA512_LEN_LEN: usize = 128 / 8; |
| 515 | |
| 516 | #[cfg(test)] |
| 517 | mod tests { |
| 518 | |
| 519 | mod max_input { |
| 520 | use super::super::super::digest; |
| 521 | use crate::polyfill; |
| 522 | use alloc::vec; |
| 523 | |
| 524 | macro_rules! max_input_tests { |
| 525 | ( $algorithm_name:ident ) => { |
| 526 | mod $algorithm_name { |
| 527 | use super::super::super::super::digest; |
| 528 | |
| 529 | #[test] |
| 530 | fn max_input_test() { |
| 531 | super::max_input_test(&digest::$algorithm_name); |
| 532 | } |
| 533 | |
| 534 | #[test] |
| 535 | #[should_panic] |
| 536 | fn too_long_input_test_block() { |
| 537 | super::too_long_input_test_block(&digest::$algorithm_name); |
| 538 | } |
| 539 | |
| 540 | #[test] |
| 541 | #[should_panic] |
| 542 | fn too_long_input_test_byte() { |
| 543 | super::too_long_input_test_byte(&digest::$algorithm_name); |
| 544 | } |
| 545 | } |
| 546 | }; |
| 547 | } |
| 548 | |
| 549 | fn max_input_test(alg: &'static digest::Algorithm) { |
| 550 | let mut context = nearly_full_context(alg); |
| 551 | let next_input = vec![0u8; alg.block_len - 1]; |
| 552 | context.update(&next_input); |
| 553 | let _ = context.finish(); // no panic |
| 554 | } |
| 555 | |
| 556 | fn too_long_input_test_block(alg: &'static digest::Algorithm) { |
| 557 | let mut context = nearly_full_context(alg); |
| 558 | let next_input = vec![0u8; alg.block_len]; |
| 559 | context.update(&next_input); |
| 560 | let _ = context.finish(); // should panic |
| 561 | } |
| 562 | |
| 563 | fn too_long_input_test_byte(alg: &'static digest::Algorithm) { |
| 564 | let mut context = nearly_full_context(alg); |
| 565 | let next_input = vec![0u8; alg.block_len - 1]; |
| 566 | context.update(&next_input); // no panic |
| 567 | context.update(&[0]); |
| 568 | let _ = context.finish(); // should panic |
| 569 | } |
| 570 | |
| 571 | fn nearly_full_context(alg: &'static digest::Algorithm) -> digest::Context { |
| 572 | // All implementations currently support up to 2^64-1 bits |
| 573 | // of input; according to the spec, SHA-384 and SHA-512 |
| 574 | // support up to 2^128-1, but that's not implemented yet. |
| 575 | let max_bytes = 1u64 << (64 - 3); |
| 576 | let max_blocks = max_bytes / polyfill::u64_from_usize(alg.block_len); |
| 577 | digest::Context { |
| 578 | block: digest::BlockContext { |
| 579 | state: alg.initial_state, |
| 580 | completed_data_blocks: max_blocks - 1, |
| 581 | algorithm: alg, |
| 582 | cpu_features: crate::cpu::features(), |
| 583 | }, |
| 584 | pending: [0u8; digest::MAX_BLOCK_LEN], |
| 585 | num_pending: 0, |
| 586 | } |
| 587 | } |
| 588 | |
| 589 | max_input_tests!(SHA1_FOR_LEGACY_USE_ONLY); |
| 590 | max_input_tests!(SHA256); |
| 591 | max_input_tests!(SHA384); |
| 592 | max_input_tests!(SHA512); |
| 593 | } |
| 594 | } |