// This file is part of the uutils coreutils package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore (ToDO) algo, algoname, regexes, nread, nonames
use clap::builder::ValueParser;
use clap::crate_version;
use clap::ArgAction;
use clap::{Arg, ArgMatches, Command};
use hex::encode;
use regex::Captures;
use regex::Regex;
use std::cmp::Ordering;
use std::error::Error;
use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::io::{self, stdin, BufRead, BufReader, Read};
use std::iter;
use std::num::ParseIntError;
use std::path::Path;
use uucore::error::USimpleError;
use uucore::error::{set_exit_code, FromIo, UError, UResult};
use uucore::sum::{
Blake2b, Blake3, Digest, DigestWriter, Md5, Sha1, Sha224, Sha256, Sha384, Sha3_224, Sha3_256,
Sha3_384, Sha3_512, Sha512, Shake128, Shake256,
};
use uucore::util_name;
use uucore::{display::Quotable, show_warning_caps};
use uucore::{format_usage, help_about, help_usage};
const NAME: &str = "hashsum";
const ABOUT: &str = help_about!("hashsum.md");
const USAGE: &str = help_usage!("hashsum.md");
struct Options {
algoname: &'static str,
digest: Box<dyn Digest + 'static>,
binary: bool,
check: bool,
tag: bool,
nonames: bool,
status: bool,
quiet: bool,
strict: bool,
warn: bool,
output_bits: usize,
zero: bool,
ignore_missing: bool,
}
/// Creates a Blake2b hasher instance based on the specified length argument.
///
/// # Returns
///
/// Returns a UResult of a tuple containing the algorithm name, the hasher instance, and
/// the output length in bits or an Err if the length is not a multiple of 8 or if it is
/// greater than 512.
fn create_blake2b(matches: &ArgMatches) -> UResult<(&'static str, Box<dyn Digest>, usize)> {
match matches.get_one::<usize>("length") {
Some(0) | None => Ok(("BLAKE2", Box::new(Blake2b::new()) as Box<dyn Digest>, 512)),
Some(length_in_bits) => {
if *length_in_bits > 512 {
return Err(USimpleError::new(
1,
"Invalid length (maximum digest length is 512 bits)",
));
}
if length_in_bits % 8 == 0 {
let length_in_bytes = length_in_bits / 8;
Ok((
"BLAKE2",
Box::new(Blake2b::with_output_bytes(length_in_bytes)),
*length_in_bits,
))
} else {
Err(USimpleError::new(
1,
"Invalid length (expected a multiple of 8)",
))
}
}
}
}
/// Creates a SHA3 hasher instance based on the specified bits argument.
///
/// # Returns
///
/// Returns a UResult of a tuple containing the algorithm name, the hasher instance, and
/// the output length in bits or an Err if an unsupported output size is provided, or if
/// the `--bits` flag is missing.
fn create_sha3(matches: &ArgMatches) -> UResult<(&'static str, Box<dyn Digest>, usize)> {
match matches.get_one::<usize>("bits") {
Some(224) => Ok((
"SHA3-224",
Box::new(Sha3_224::new()) as Box<dyn Digest>,
224,
)),
Some(256) => Ok((
"SHA3-256",
Box::new(Sha3_256::new()) as Box<dyn Digest>,
256,
)),
Some(384) => Ok((
"SHA3-384",
Box::new(Sha3_384::new()) as Box<dyn Digest>,
384,
)),
Some(512) => Ok((
"SHA3-512",
Box::new(Sha3_512::new()) as Box<dyn Digest>,
512,
)),
Some(_) => Err(USimpleError::new(
1,
"Invalid output size for SHA3 (expected 224, 256, 384, or 512)",
)),
None => Err(USimpleError::new(1, "--bits required for SHA3")),
}
}
/// Creates a SHAKE-128 hasher instance based on the specified bits argument.
///
/// # Returns
///
/// Returns a UResult of a tuple containing the algorithm name, the hasher instance, and
/// the output length in bits, or an Err if `--bits` flag is missing.
fn create_shake128(matches: &ArgMatches) -> UResult<(&'static str, Box<dyn Digest>, usize)> {
match matches.get_one::<usize>("bits") {
Some(bits) => Ok((
"SHAKE128",
Box::new(Shake128::new()) as Box<dyn Digest>,
*bits,
)),
None => Err(USimpleError::new