Skip to content

Commit e104fc8

Browse files
RenjiSanncakebaker
authored andcommitted
cksum: make sure --check raises "improperly formatted" for length-guessing related issues
cksum: Fix --check failing when digest length is wrong on untagged line
1 parent 812eb64 commit e104fc8

3 files changed

Lines changed: 46 additions & 15 deletions

File tree

src/uucore/src/lib/features/checksum/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,22 @@ impl AlgoKind {
200200
use AlgoKind::*;
201201
matches!(self, Sysv | Bsd | Crc | Crc32b)
202202
}
203+
204+
/// When checking untagged format lines, non-XOF non-legacy algorithms
205+
/// should report "improperly formatted lines" if the digest length isn't
206+
/// equivalent to this.
207+
pub fn expected_digest_bit_len(self) -> Option<usize> {
208+
match self {
209+
Self::Md5 => Some(Md5::BIT_SIZE),
210+
Self::Sm3 => Some(Sm3::BIT_SIZE),
211+
Self::Sha1 => Some(Sha1::BIT_SIZE),
212+
Self::Sha224 => Some(Sha224::BIT_SIZE),
213+
Self::Sha256 => Some(Sha256::BIT_SIZE),
214+
Self::Sha384 => Some(Sha384::BIT_SIZE),
215+
Self::Sha512 => Some(Sha512::BIT_SIZE),
216+
_ => None,
217+
}
218+
}
203219
}
204220

205221
/// Holds a length for a SHA2 of SHA3 algorithm kind.

src/uucore/src/lib/features/checksum/validate.rs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use std::io::{self, BufReader, Read, Write, stderr, stdin};
1515
use os_display::Quotable;
1616

1717
use crate::checksum::{
18-
AlgoKind, BlakeLength, ChecksumError, ReadingMode, SizedAlgoKind, digest_reader,
18+
AlgoKind, BlakeLength, ChecksumError, ReadingMode, ShaLength, SizedAlgoKind, digest_reader,
1919
parse_blake_length, unescape_filename,
2020
};
2121
use crate::error::{FromIo, UError, UIoError, UResult, USimpleError};
@@ -490,14 +490,16 @@ impl LineInfo {
490490
}
491491

492492
/// Extract the expected digest from the checksum string and decode it
493-
fn get_raw_expected_digest(checksum: &str, byte_len_hint: Option<usize>) -> Option<Vec<u8>> {
493+
fn get_raw_expected_digest(checksum: &str, bit_len_hint: Option<usize>) -> Option<Vec<u8>> {
494494
// If the length of the digest is not a multiple of 2, then it must be
495495
// improperly formatted (1 byte is 2 hex digits, and base64 strings should
496496
// always be a multiple of 4).
497497
if !checksum.len().is_multiple_of(2) {
498498
return None;
499499
}
500500

501+
let byte_len_hint = bit_len_hint.map(|n| n.div_ceil(8));
502+
501503
let checks_hint = |len| byte_len_hint.is_none_or(|hint| hint == len);
502504

503505
// If the length of the string matches the one to be expected (in case it's
@@ -741,23 +743,23 @@ fn process_algo_based_line(
741743
) -> Result<(), LineCheckError> {
742744
let filename_to_check = line_info.filename.as_slice();
743745

744-
let (algo_kind, algo_byte_len) =
745-
identify_algo_name_and_length(line_info, cli_algo_kind, last_algo)?;
746+
let (algo_kind, algo_len) = identify_algo_name_and_length(line_info, cli_algo_kind, last_algo)?;
746747

747748
// If the digest bitlen is known, we can check the format of the expected
748749
// checksum with it.
749-
let digest_char_length_hint = match (algo_kind, algo_byte_len) {
750-
(AlgoKind::Blake2b | AlgoKind::Blake3, Some(byte_len)) => Some(byte_len),
751-
(AlgoKind::Shake128 | AlgoKind::Shake256, Some(bit_len)) => Some(bit_len.div_ceil(8)),
752-
(AlgoKind::Shake128, None) => Some(sum::Shake128::DEFAULT_BIT_SIZE.div_ceil(8)),
753-
(AlgoKind::Shake256, None) => Some(sum::Shake256::DEFAULT_BIT_SIZE.div_ceil(8)),
750+
let digest_bit_length_hint = match (algo_kind, algo_len) {
751+
(AlgoKind::Blake2b | AlgoKind::Blake3, Some(byte_len)) => Some(byte_len * 8),
752+
(AlgoKind::Shake128 | AlgoKind::Shake256, Some(bit_len)) => Some(bit_len),
753+
(AlgoKind::Shake128, None) => Some(sum::Shake128::DEFAULT_BIT_SIZE),
754+
(AlgoKind::Shake256, None) => Some(sum::Shake256::DEFAULT_BIT_SIZE),
754755
_ => None,
755756
};
756757

757-
let expected_checksum = get_raw_expected_digest(&line_info.checksum, digest_char_length_hint)
758+
let expected_checksum = get_raw_expected_digest(&line_info.checksum, digest_bit_length_hint)
758759
.ok_or(LineCheckError::ImproperlyFormatted)?;
759760

760-
let algo = SizedAlgoKind::from_unsized(algo_kind, algo_byte_len)?;
761+
let algo = SizedAlgoKind::from_unsized(algo_kind, algo_len)
762+
.map_err(|_| LineCheckError::ImproperlyFormatted)?;
761763

762764
compute_and_check_digest_from_file(filename_to_check, &expected_checksum, algo, opts)
763765
}
@@ -779,7 +781,9 @@ fn process_non_algo_based_line(
779781
// Remove the leading asterisk if present - only for the first line
780782
filename_to_check = &filename_to_check[1..];
781783
}
782-
let expected_checksum = get_raw_expected_digest(&line_info.checksum, None)
784+
785+
let expected_digest_sum = cli_algo_kind.expected_digest_bit_len();
786+
let expected_checksum = get_raw_expected_digest(&line_info.checksum, expected_digest_sum)
783787
.ok_or(LineCheckError::ImproperlyFormatted)?;
784788

785789
// When a specific algorithm name is input, use it and use the provided
@@ -789,7 +793,11 @@ fn process_non_algo_based_line(
789793
ak::Blake2b | ak::Blake3 => Some(expected_checksum.len()),
790794
ak::Sha2 | ak::Sha3 => {
791795
// multiplication by 8 to get the number of bits
792-
Some(expected_checksum.len() * 8)
796+
Some(
797+
ShaLength::try_from(expected_checksum.len() * 8)
798+
.map_err(|_| LineCheckError::ImproperlyFormatted)?
799+
.as_usize(),
800+
)
793801
}
794802
_ => cli_algo_length,
795803
};

src/uucore/src/lib/features/sum.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,10 @@ impl Digest for Blake3 {
176176
#[derive(Default)]
177177
pub struct Sm3(sm3::Sm3);
178178

179+
impl Sm3 {
180+
pub const BIT_SIZE: usize = 256;
181+
}
182+
179183
impl Digest for Sm3 {
180184
fn hash_update(&mut self, input: &[u8]) {
181185
<sm3::Sm3 as sm3::Digest>::update(&mut self.0, input);
@@ -190,7 +194,7 @@ impl Digest for Sm3 {
190194
}
191195

192196
fn output_bits(&self) -> usize {
193-
256
197+
Self::BIT_SIZE
194198
}
195199
}
196200

@@ -367,6 +371,9 @@ impl Digest for SysV {
367371
// Implements the Digest trait for sha2 / sha3 algorithms with fixed output
368372
macro_rules! impl_digest_common {
369373
($algo_type: ty, $size: literal) => {
374+
impl $algo_type {
375+
pub const BIT_SIZE: usize = $size;
376+
}
370377
impl Default for $algo_type {
371378
fn default() -> Self {
372379
Self(Default::default())
@@ -386,7 +393,7 @@ macro_rules! impl_digest_common {
386393
}
387394

388395
fn output_bits(&self) -> usize {
389-
$size
396+
Self::BIT_SIZE
390397
}
391398
}
392399
};

0 commit comments

Comments
 (0)