mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
cksum: make sure --check raises "improperly formatted" for length-guessing related issues
cksum: Fix --check failing when digest length is wrong on untagged line
This commit is contained in:
committed by
Daniel Hofstetter
parent
812eb64c50
commit
e104fc8cf4
@@ -200,6 +200,22 @@ impl AlgoKind {
|
||||
use AlgoKind::*;
|
||||
matches!(self, Sysv | Bsd | Crc | Crc32b)
|
||||
}
|
||||
|
||||
/// When checking untagged format lines, non-XOF non-legacy algorithms
|
||||
/// should report "improperly formatted lines" if the digest length isn't
|
||||
/// equivalent to this.
|
||||
pub fn expected_digest_bit_len(self) -> Option<usize> {
|
||||
match self {
|
||||
Self::Md5 => Some(Md5::BIT_SIZE),
|
||||
Self::Sm3 => Some(Sm3::BIT_SIZE),
|
||||
Self::Sha1 => Some(Sha1::BIT_SIZE),
|
||||
Self::Sha224 => Some(Sha224::BIT_SIZE),
|
||||
Self::Sha256 => Some(Sha256::BIT_SIZE),
|
||||
Self::Sha384 => Some(Sha384::BIT_SIZE),
|
||||
Self::Sha512 => Some(Sha512::BIT_SIZE),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds a length for a SHA2 of SHA3 algorithm kind.
|
||||
|
||||
@@ -15,7 +15,7 @@ use std::io::{self, BufReader, Read, Write, stderr, stdin};
|
||||
use os_display::Quotable;
|
||||
|
||||
use crate::checksum::{
|
||||
AlgoKind, BlakeLength, ChecksumError, ReadingMode, SizedAlgoKind, digest_reader,
|
||||
AlgoKind, BlakeLength, ChecksumError, ReadingMode, ShaLength, SizedAlgoKind, digest_reader,
|
||||
parse_blake_length, unescape_filename,
|
||||
};
|
||||
use crate::error::{FromIo, UError, UIoError, UResult, USimpleError};
|
||||
@@ -490,7 +490,7 @@ impl LineInfo {
|
||||
}
|
||||
|
||||
/// Extract the expected digest from the checksum string and decode it
|
||||
fn get_raw_expected_digest(checksum: &str, byte_len_hint: Option<usize>) -> Option<Vec<u8>> {
|
||||
fn get_raw_expected_digest(checksum: &str, bit_len_hint: Option<usize>) -> Option<Vec<u8>> {
|
||||
// If the length of the digest is not a multiple of 2, then it must be
|
||||
// improperly formatted (1 byte is 2 hex digits, and base64 strings should
|
||||
// always be a multiple of 4).
|
||||
@@ -498,6 +498,8 @@ fn get_raw_expected_digest(checksum: &str, byte_len_hint: Option<usize>) -> Opti
|
||||
return None;
|
||||
}
|
||||
|
||||
let byte_len_hint = bit_len_hint.map(|n| n.div_ceil(8));
|
||||
|
||||
let checks_hint = |len| byte_len_hint.is_none_or(|hint| hint == len);
|
||||
|
||||
// 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(
|
||||
) -> Result<(), LineCheckError> {
|
||||
let filename_to_check = line_info.filename.as_slice();
|
||||
|
||||
let (algo_kind, algo_byte_len) =
|
||||
identify_algo_name_and_length(line_info, cli_algo_kind, last_algo)?;
|
||||
let (algo_kind, algo_len) = identify_algo_name_and_length(line_info, cli_algo_kind, last_algo)?;
|
||||
|
||||
// If the digest bitlen is known, we can check the format of the expected
|
||||
// checksum with it.
|
||||
let digest_char_length_hint = match (algo_kind, algo_byte_len) {
|
||||
(AlgoKind::Blake2b | AlgoKind::Blake3, Some(byte_len)) => Some(byte_len),
|
||||
(AlgoKind::Shake128 | AlgoKind::Shake256, Some(bit_len)) => Some(bit_len.div_ceil(8)),
|
||||
(AlgoKind::Shake128, None) => Some(sum::Shake128::DEFAULT_BIT_SIZE.div_ceil(8)),
|
||||
(AlgoKind::Shake256, None) => Some(sum::Shake256::DEFAULT_BIT_SIZE.div_ceil(8)),
|
||||
let digest_bit_length_hint = match (algo_kind, algo_len) {
|
||||
(AlgoKind::Blake2b | AlgoKind::Blake3, Some(byte_len)) => Some(byte_len * 8),
|
||||
(AlgoKind::Shake128 | AlgoKind::Shake256, Some(bit_len)) => Some(bit_len),
|
||||
(AlgoKind::Shake128, None) => Some(sum::Shake128::DEFAULT_BIT_SIZE),
|
||||
(AlgoKind::Shake256, None) => Some(sum::Shake256::DEFAULT_BIT_SIZE),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let expected_checksum = get_raw_expected_digest(&line_info.checksum, digest_char_length_hint)
|
||||
let expected_checksum = get_raw_expected_digest(&line_info.checksum, digest_bit_length_hint)
|
||||
.ok_or(LineCheckError::ImproperlyFormatted)?;
|
||||
|
||||
let algo = SizedAlgoKind::from_unsized(algo_kind, algo_byte_len)?;
|
||||
let algo = SizedAlgoKind::from_unsized(algo_kind, algo_len)
|
||||
.map_err(|_| LineCheckError::ImproperlyFormatted)?;
|
||||
|
||||
compute_and_check_digest_from_file(filename_to_check, &expected_checksum, algo, opts)
|
||||
}
|
||||
@@ -779,7 +781,9 @@ fn process_non_algo_based_line(
|
||||
// Remove the leading asterisk if present - only for the first line
|
||||
filename_to_check = &filename_to_check[1..];
|
||||
}
|
||||
let expected_checksum = get_raw_expected_digest(&line_info.checksum, None)
|
||||
|
||||
let expected_digest_sum = cli_algo_kind.expected_digest_bit_len();
|
||||
let expected_checksum = get_raw_expected_digest(&line_info.checksum, expected_digest_sum)
|
||||
.ok_or(LineCheckError::ImproperlyFormatted)?;
|
||||
|
||||
// When a specific algorithm name is input, use it and use the provided
|
||||
@@ -789,7 +793,11 @@ fn process_non_algo_based_line(
|
||||
ak::Blake2b | ak::Blake3 => Some(expected_checksum.len()),
|
||||
ak::Sha2 | ak::Sha3 => {
|
||||
// multiplication by 8 to get the number of bits
|
||||
Some(expected_checksum.len() * 8)
|
||||
Some(
|
||||
ShaLength::try_from(expected_checksum.len() * 8)
|
||||
.map_err(|_| LineCheckError::ImproperlyFormatted)?
|
||||
.as_usize(),
|
||||
)
|
||||
}
|
||||
_ => cli_algo_length,
|
||||
};
|
||||
|
||||
@@ -176,6 +176,10 @@ impl Digest for Blake3 {
|
||||
#[derive(Default)]
|
||||
pub struct Sm3(sm3::Sm3);
|
||||
|
||||
impl Sm3 {
|
||||
pub const BIT_SIZE: usize = 256;
|
||||
}
|
||||
|
||||
impl Digest for Sm3 {
|
||||
fn hash_update(&mut self, input: &[u8]) {
|
||||
<sm3::Sm3 as sm3::Digest>::update(&mut self.0, input);
|
||||
@@ -190,7 +194,7 @@ impl Digest for Sm3 {
|
||||
}
|
||||
|
||||
fn output_bits(&self) -> usize {
|
||||
256
|
||||
Self::BIT_SIZE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,6 +371,9 @@ impl Digest for SysV {
|
||||
// Implements the Digest trait for sha2 / sha3 algorithms with fixed output
|
||||
macro_rules! impl_digest_common {
|
||||
($algo_type: ty, $size: literal) => {
|
||||
impl $algo_type {
|
||||
pub const BIT_SIZE: usize = $size;
|
||||
}
|
||||
impl Default for $algo_type {
|
||||
fn default() -> Self {
|
||||
Self(Default::default())
|
||||
@@ -386,7 +393,7 @@ macro_rules! impl_digest_common {
|
||||
}
|
||||
|
||||
fn output_bits(&self) -> usize {
|
||||
$size
|
||||
Self::BIT_SIZE
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user