diff --git a/src/uucore/src/lib/features/checksum/mod.rs b/src/uucore/src/lib/features/checksum/mod.rs index 6dd18ee9a32..1f77b7e635f 100644 --- a/src/uucore/src/lib/features/checksum/mod.rs +++ b/src/uucore/src/lib/features/checksum/mod.rs @@ -250,14 +250,15 @@ pub enum SizedAlgoKind { Sha3(ShaLength), // Note: we store Blake2b's length as BYTES. Blake2b(Option), + // Shake* length are stored in bits. Shake128(Option), Shake256(Option), } impl SizedAlgoKind { - pub fn from_unsized(kind: AlgoKind, byte_length: Option) -> UResult { + pub fn from_unsized(kind: AlgoKind, output_length: Option) -> UResult { use AlgoKind as ak; - match (kind, byte_length) { + match (kind, output_length) { ( ak::Sysv | ak::Bsd @@ -305,19 +306,26 @@ impl SizedAlgoKind { } pub fn to_tag(self) -> String { - use SizedAlgoKind::*; match self { - Md5 => "MD5".into(), - Sm3 => "SM3".into(), - Sha1 => "SHA1".into(), - Blake3 => "BLAKE3".into(), - Sha2(len) => format!("SHA{}", len.as_usize()), - Sha3(len) => format!("SHA3-{}", len.as_usize()), - Blake2b(Some(byte_len)) => format!("BLAKE2b-{}", byte_len * 8), - Blake2b(None) => "BLAKE2b".into(), - Shake128(_) => "SHAKE128".into(), - Shake256(_) => "SHAKE256".into(), - Sysv | Bsd | Crc | Crc32b => panic!("Should not be used for tagging"), + Self::Md5 => "MD5".into(), + Self::Sm3 => "SM3".into(), + Self::Sha1 => "SHA1".into(), + Self::Blake3 => "BLAKE3".into(), + Self::Sha2(len) => format!("SHA{}", len.as_usize()), + Self::Sha3(len) => format!("SHA3-{}", len.as_usize()), + Self::Blake2b(Some(byte_len)) => format!("BLAKE2b-{}", byte_len * 8), + Self::Blake2b(None) => "BLAKE2b".into(), + Self::Shake128(opt_bit_len) => format!( + "SHAKE128-{}", + opt_bit_len.unwrap_or(Shake128::DEFAULT_BIT_SIZE) + ), + Self::Shake256(opt_bit_len) => format!( + "SHAKE256-{}", + opt_bit_len.unwrap_or(Shake256::DEFAULT_BIT_SIZE) + ), + Self::Sysv | Self::Bsd | Self::Crc | Self::Crc32b => { + panic!("Should not be used for tagging") + } } } diff --git a/src/uucore/src/lib/features/checksum/validate.rs b/src/uucore/src/lib/features/checksum/validate.rs index b3fca0b75b6..17b1c7bf522 100644 --- a/src/uucore/src/lib/features/checksum/validate.rs +++ b/src/uucore/src/lib/features/checksum/validate.rs @@ -19,7 +19,7 @@ use crate::checksum::{ }; use crate::error::{FromIo, UError, UIoError, UResult, USimpleError}; use crate::quoting_style::{QuotingStyle, locale_aware_escape_name}; -use crate::sum::DigestOutput; +use crate::sum::{self, DigestOutput}; use crate::{ os_str_as_bytes, os_str_from_bytes, read_os_string_lines, show, show_warning_caps, translate, }; @@ -643,6 +643,7 @@ fn identify_algo_name_and_length( AlgoKind::Sha2 | AlgoKind::Sha3 if [224, 256, 384, 512].contains(&bitlen) => { Some(bitlen) } + AlgoKind::Shake128 | AlgoKind::Shake256 => Some(bitlen), // Either // the algo based line is provided with a bit length // with an algorithm that does not support it (only Blake2B does). @@ -741,6 +742,9 @@ fn process_algo_based_line( // checksum with it. let digest_char_length_hint = match (algo_kind, algo_byte_len) { (AlgoKind::Blake2b, 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)), _ => None, }; diff --git a/tests/by-util/test_cksum.rs b/tests/by-util/test_cksum.rs index f375bcb98b0..67f96e90762 100644 --- a/tests/by-util/test_cksum.rs +++ b/tests/by-util/test_cksum.rs @@ -3150,13 +3150,19 @@ fn test_check_checkfile_with_io_error() { "ac" )] fn test_shake128(#[case] args: &[&str], #[case] expected: &str) { + let bit_len = if args.is_empty() || args[1] == "0" { + "256" + } else { + args[1] + }; + new_ucmd!() .arg("-a") .arg("shake128") .args(args) .pipe_in("xxx") .succeeds() - .stdout_only(format!("SHAKE128 (-) = {expected}\n")); + .stdout_only(format!("SHAKE128-{bit_len} (-) = {expected}\n")); } #[rstest] @@ -3213,11 +3219,71 @@ fn test_shake128(#[case] args: &[&str], #[case] expected: &str) { "2f" )] fn test_shake256(#[case] args: &[&str], #[case] expected: &str) { + let bit_len = if args.is_empty() || args[1] == "0" { + "512" + } else { + args[1] + }; + new_ucmd!() .arg("-a") .arg("shake256") .args(args) .pipe_in("xxx") .succeeds() - .stdout_only(format!("SHAKE256 (-) = {expected}\n")); + .stdout_only(format!("SHAKE256-{bit_len} (-) = {expected}\n")); +} + +#[test] +fn test_check_shake128_no_length() { + const INPUT_SHAKE128_CORRECT_LEN: &str = + "SHAKE128 (bar) = ac8549b2861a151896ab721bd29d7a20c1a3d1f75b31266f786f20d963fb0fdf"; + const INPUT_SHAKE128_WRONG_LEN: &str = "SHAKE128 (bar) = ac8549b2861a151896ab721bd29d7a20"; + + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + at.write("bar", "xxx"); + + scene + .ucmd() + .arg("-a") + .arg("shake128") + .arg("-c") + .pipe_in(INPUT_SHAKE128_CORRECT_LEN) + .succeeds(); + + scene + .ucmd() + .arg("-a") + .arg("shake128") + .arg("-c") + .pipe_in(INPUT_SHAKE128_WRONG_LEN) + .fails() + .stderr_only("cksum: 'standard input': no properly formatted checksum lines found\n"); +} + +#[test] +fn test_check_shake256_no_length() { + const INPUT_SHAKE256_CORRECT_LEN: &str = "SHAKE256 (bar) = 2fa631503c3ea5fe85131dbfa24805185474740e6dcb5f2a64f69d932bcb55f7b24958f3e3c4cc0e71f1fe6f054cd3fb28b9efb62b4f8f3fbe6d50d90f5c6eba"; + const INPUT_SHAKE256_WRONG_LEN: &str = + "SHAKE256 (bar) = 2fa631503c3ea5fe85131dbfa24805185474740e6dcb5f2a64f69d932bcb55f7"; + + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + at.write("bar", "xxx"); + + scene + .ucmd() + .arg("-c") + .pipe_in(INPUT_SHAKE256_CORRECT_LEN) + .succeeds(); + + scene + .ucmd() + .arg("-c") + .pipe_in(INPUT_SHAKE256_WRONG_LEN) + .fails() + .stderr_only("cksum: 'standard input': no properly formatted checksum lines found\n"); }