-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
cksum: rework blake length validation , add tests #11437
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c8a8354
aa2e186
5f1799c
c2613a5
693711e
a6f6cf7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -250,8 +250,8 @@ pub enum SizedAlgoKind { | |
| Sha2(ShaLength), | ||
| Sha3(ShaLength), | ||
| // Note: we store Blake*'s length as BYTES. | ||
| Blake2b(Option<usize>), | ||
| Blake3(Option<usize>), | ||
| Blake2b(usize), | ||
| Blake3(usize), | ||
| // Shake* length are stored in bits. | ||
| Shake128(Option<usize>), | ||
| Shake256(Option<usize>), | ||
|
|
@@ -284,22 +284,15 @@ impl SizedAlgoKind { | |
| (ak::Sm3, _) => Ok(Self::Sm3), | ||
| (ak::Sha1, _) => Ok(Self::Sha1), | ||
|
|
||
| (ak::Blake3, l) => Ok(Self::Blake3(l)), | ||
| (ak::Blake2b, l) => Ok(Self::Blake2b(l.unwrap_or(Blake2b::DEFAULT_BYTE_SIZE))), | ||
| (ak::Blake3, l) => Ok(Self::Blake3(l.unwrap_or(Blake3::DEFAULT_BYTE_SIZE))), | ||
| (ak::Shake128, l) => Ok(Self::Shake128(l)), | ||
| (ak::Shake256, l) => Ok(Self::Shake256(l)), | ||
| (ak::Sha2, Some(l)) => Ok(Self::Sha2(ShaLength::try_from(l)?)), | ||
| (ak::Sha3, Some(l)) => Ok(Self::Sha3(ShaLength::try_from(l)?)), | ||
| (algo @ (ak::Sha2 | ak::Sha3), None) => { | ||
| Err(ChecksumError::LengthRequiredForSha(algo.to_lowercase().into()).into()) | ||
| } | ||
| // [`calculate_blake2b_length`] expects a length in bits but we | ||
| // have a length in bytes. | ||
| (algo @ ak::Blake2b, Some(l)) => Ok(Self::Blake2b(calculate_blake_length_str( | ||
| algo, | ||
| &(8 * l).to_string(), | ||
| )?)), | ||
| (ak::Blake2b, None) => Ok(Self::Blake2b(None)), | ||
|
|
||
| (ak::Sha224, None) => Ok(Self::Sha2(ShaLength::Len224)), | ||
| (ak::Sha256, None) => Ok(Self::Sha2(ShaLength::Len256)), | ||
| (ak::Sha384, None) => Ok(Self::Sha2(ShaLength::Len384)), | ||
|
|
@@ -314,14 +307,9 @@ impl SizedAlgoKind { | |
| Self::Sha1 => "SHA1".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::Blake3(byte_len) => { | ||
| format!( | ||
| "BLAKE3-{}", | ||
| byte_len.unwrap_or(Blake3::DEFAULT_BYTE_SIZE) * 8 | ||
| ) | ||
| } | ||
| Self::Blake2b(Blake2b::DEFAULT_BYTE_SIZE) => "BLAKE2b".into(), | ||
| Self::Blake2b(byte_len) => format!("BLAKE2b-{}", byte_len * 8), | ||
| Self::Blake3(byte_len) => format!("BLAKE3-{}", byte_len * 8), | ||
| Self::Shake128(opt_bit_len) => format!( | ||
| "SHAKE128-{}", | ||
| opt_bit_len.unwrap_or(Shake128::DEFAULT_BIT_SIZE) | ||
|
|
@@ -354,12 +342,8 @@ impl SizedAlgoKind { | |
| Self::Sha3(Len256) => Box::new(Sha3_256::default()), | ||
| Self::Sha3(Len384) => Box::new(Sha3_384::default()), | ||
| Self::Sha3(Len512) => Box::new(Sha3_512::default()), | ||
| Self::Blake2b(len_opt) => { | ||
| Box::new(len_opt.map(Blake2b::with_output_bytes).unwrap_or_default()) | ||
| } | ||
| Self::Blake3(len_opt) => { | ||
| Box::new(len_opt.map(Blake3::with_output_bytes).unwrap_or_default()) | ||
| } | ||
| Self::Blake2b(len) => Box::new(Blake2b::with_output_bytes(*len)), | ||
| Self::Blake3(len) => Box::new(Blake3::with_output_bytes(*len)), | ||
| Self::Shake128(len_opt) => { | ||
| Box::new(len_opt.map(Shake128::with_output_bits).unwrap_or_default()) | ||
| } | ||
|
|
@@ -378,10 +362,10 @@ impl SizedAlgoKind { | |
| Self::Md5 => 128, | ||
| Self::Sm3 => 512, | ||
| Self::Sha1 => 160, | ||
| Self::Blake3(len) => len.unwrap_or(Blake3::DEFAULT_BYTE_SIZE) * 8, | ||
| Self::Sha2(len) => len.as_usize(), | ||
| Self::Sha3(len) => len.as_usize(), | ||
| Self::Blake2b(len) => len.unwrap_or(Blake2b::DEFAULT_BYTE_SIZE * 8), | ||
| Self::Blake2b(len) => len * 8, | ||
| Self::Blake3(len) => len * 8, | ||
| Self::Shake128(len) => len.unwrap_or(Shake128::DEFAULT_BIT_SIZE), | ||
| Self::Shake256(len) => len.unwrap_or(Shake256::DEFAULT_BIT_SIZE), | ||
| } | ||
|
|
@@ -495,36 +479,65 @@ pub fn digest_reader<T: Read>( | |
| Ok((digest.result(), output_size)) | ||
| } | ||
|
|
||
| /// Calculates the BYTE length of the digest. | ||
| pub fn calculate_blake_length_str(algo: AlgoKind, bit_length: &str) -> UResult<Option<usize>> { | ||
| pub enum BlakeLength<'s> { | ||
| Int(usize), | ||
| String(&'s str), | ||
| } | ||
|
|
||
| /// Expects a size in BITS, either as a string or int, and returns it as a BYTE | ||
| /// length. | ||
| /// | ||
| /// Note: when the input is a string, validation may print error messages. | ||
| /// Note: when the algo is Blake2b, values that are above 512 | ||
| /// (Blake2b::DEFAULT_BIT_SIZE) are errors. | ||
| pub fn validate_calculate_blake_length( | ||
| algo: AlgoKind, | ||
| bit_length: BlakeLength<'_>, | ||
| ) -> UResult<usize> { | ||
| debug_assert!(matches!(algo, AlgoKind::Blake2b | AlgoKind::Blake3)); | ||
|
|
||
| // TODO MSRV>=1.89 : Replace format! with format_args! to make string | ||
| // evaluation lazy. | ||
| #[allow(clippy::useless_format)] | ||
| let (disp, parsed, may_print_error) = match &bit_length { | ||
| BlakeLength::Int(i) => (format!("{}", *i), Ok(*i), false), | ||
| BlakeLength::String(s) => (format!("{}", *s), s.parse::<usize>(), true), | ||
| }; | ||
|
|
||
| let print_error = || { | ||
| if may_print_error { | ||
| show_error!("{}", ChecksumError::InvalidLength(disp.clone())); | ||
| } | ||
| }; | ||
|
|
||
| // Blake2b's length is parsed in an u64. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess this comment is outdated?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes thanks |
||
| match bit_length.parse::<usize>() { | ||
| Ok(0) => Ok(None), | ||
| match parsed { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the following block you are mixing the handling of parsing errors and the validation logic. I would move the handling of the parsing errors up to where you parse the string and do an early return in the error cases.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since GNU treats parsing errors and validation errors very similarly, I can't think of a way to make an early return that's not adding a lot of verbosity. The reason for the current ordering of the match arms is that when the parsing fails because of an overflow error, the returned error should be the same as when the value exceeds 512 for Blake2b. So I put both arms side by side, and then I put the general case for parsing errors after. |
||
| Ok(0) => Ok(if algo == AlgoKind::Blake2b { | ||
| Blake2b::DEFAULT_BYTE_SIZE | ||
| } else { | ||
| Blake3::DEFAULT_BYTE_SIZE | ||
| }), | ||
|
|
||
| // Error cases | ||
| Ok(n) if n > 512 && algo == AlgoKind::Blake2b => { | ||
| show_error!("{}", ChecksumError::InvalidLength(bit_length.into())); | ||
| Ok(n) if n > Blake2b::DEFAULT_BIT_SIZE && algo == AlgoKind::Blake2b => { | ||
| print_error(); | ||
| Err(ChecksumError::LengthTooBigForBlake(algo.to_uppercase().into()).into()) | ||
| } | ||
| Err(e) if *e.kind() == IntErrorKind::PosOverflow => { | ||
| show_error!("{}", ChecksumError::InvalidLength(bit_length.into())); | ||
| print_error(); | ||
| Err(ChecksumError::LengthTooBigForBlake(algo.to_uppercase().into()).into()) | ||
| } | ||
| Err(_) => Err(ChecksumError::InvalidLength(bit_length.into()).into()), | ||
| Err(_) => Err(ChecksumError::InvalidLength(disp).into()), | ||
|
|
||
| Ok(n) if n % 8 != 0 => { | ||
| show_error!("{}", ChecksumError::InvalidLength(bit_length.into())); | ||
| print_error(); | ||
| Err(ChecksumError::LengthNotMultipleOf8.into()) | ||
| } | ||
|
|
||
| // Valid cases | ||
|
|
||
| // When length is 512, it is blake2b's default. So, don't show it | ||
| Ok(512) => Ok(None), | ||
| // Divide by 8, as our blake2b implementation expects bytes instead of bits. | ||
| Ok(n) => Ok(Some(n / 8)), | ||
| Ok(n) => Ok(n / 8), | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -644,18 +657,22 @@ mod tests { | |
| #[test] | ||
| fn test_calculate_blake2b_length() { | ||
| assert_eq!( | ||
| calculate_blake_length_str(AlgoKind::Blake2b, "0").unwrap(), | ||
| None | ||
| validate_calculate_blake_length(AlgoKind::Blake2b, BlakeLength::String("0")).unwrap(), | ||
| Blake2b::DEFAULT_BYTE_SIZE | ||
| ); | ||
| assert!( | ||
| validate_calculate_blake_length(AlgoKind::Blake2b, BlakeLength::String("10")).is_err() | ||
| ); | ||
| assert!( | ||
| validate_calculate_blake_length(AlgoKind::Blake2b, BlakeLength::String("520")).is_err() | ||
| ); | ||
| assert!(calculate_blake_length_str(AlgoKind::Blake2b, "10").is_err()); | ||
| assert!(calculate_blake_length_str(AlgoKind::Blake2b, "520").is_err()); | ||
| assert_eq!( | ||
| calculate_blake_length_str(AlgoKind::Blake2b, "512").unwrap(), | ||
| None | ||
| validate_calculate_blake_length(AlgoKind::Blake2b, BlakeLength::String("512")).unwrap(), | ||
| Blake2b::DEFAULT_BYTE_SIZE | ||
| ); | ||
| assert_eq!( | ||
| calculate_blake_length_str(AlgoKind::Blake2b, "256").unwrap(), | ||
| Some(32) | ||
| validate_calculate_blake_length(AlgoKind::Blake2b, BlakeLength::String("256")).unwrap(), | ||
| 32 | ||
| ); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a fan of this function name ;-) Maybe something like
parse_blake_lengthwould be better?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok with that 👍