@@ -12,6 +12,7 @@ use std::{
1212 fmt:: Display ,
1313 fs:: File ,
1414 io:: { self , BufReader , Read , Write , stdin} ,
15+ num:: IntErrorKind ,
1516 path:: Path ,
1617 str,
1718} ;
@@ -220,12 +221,12 @@ pub enum ChecksumError {
220221 QuietNotCheck ,
221222 #[ error( "--length required for {}" , . 0 . quote( ) ) ]
222223 LengthRequired ( String ) ,
223- #[ error( "unknown algorithm: {0}: clap should have prevented this case" ) ]
224- UnknownAlgorithm ( String ) ,
225- #[ error( "length is not a multiple of 8" ) ]
226- InvalidLength ,
224+ #[ error( "invalid length: {}" , . 0 . quote( ) ) ]
225+ InvalidLength ( String ) ,
227226 #[ error( "digest length for {} must be 224, 256, 384, or 512" , . 0 . quote( ) ) ]
228- InvalidLengthFor ( String ) ,
227+ InvalidLengthForSha ( String ) ,
228+ #[ error( "--algorithm={0} requires specifying --length 224, 256, 384, or 512" ) ]
229+ LengthRequiredForSha ( String ) ,
229230 #[ error( "--length is only supported with --algorithm blake2b, sha2, or sha3" ) ]
230231 LengthOnlyForBlake2bSha2Sha3 ,
231232 #[ error( "the --binary and --text options are meaningless when verifying checksums" ) ]
@@ -238,6 +239,8 @@ pub enum ChecksumError {
238239 CombineMultipleAlgorithms ,
239240 #[ error( "Needs an algorithm to hash with.\n Use --help for more information." ) ]
240241 NeedAlgorithmToHash ,
242+ #[ error( "unknown algorithm: {0}: clap should have prevented this case" ) ]
243+ UnknownAlgorithm ( String ) ,
241244 #[ error( "" ) ]
242245 Io ( #[ from] io:: Error ) ,
243246}
@@ -277,7 +280,7 @@ pub fn create_sha3(bits: usize) -> UResult<HashAlgorithm> {
277280 bits : 512 ,
278281 } ) ,
279282
280- _ => Err ( ChecksumError :: InvalidLengthFor ( "SHA3" . into ( ) ) . into ( ) ) ,
283+ _ => Err ( ChecksumError :: InvalidLengthForSha ( "SHA3" . into ( ) ) . into ( ) ) ,
281284 }
282285}
283286
@@ -304,7 +307,7 @@ pub fn create_sha2(bits: usize) -> UResult<HashAlgorithm> {
304307 bits : 512 ,
305308 } ) ,
306309
307- _ => Err ( ChecksumError :: InvalidLengthFor ( "SHA2" . into ( ) ) . into ( ) ) ,
310+ _ => Err ( ChecksumError :: InvalidLengthForSha ( "SHA2" . into ( ) ) . into ( ) ) ,
308311 }
309312}
310313
@@ -837,25 +840,41 @@ fn identify_algo_name_and_length(
837840 last_algo : & mut Option < String > ,
838841) -> Result < ( String , Option < usize > ) , LineCheckError > {
839842 let algo_from_line = line_info. algo_name . clone ( ) . unwrap_or_default ( ) ;
840- let algorithm = algo_from_line. to_lowercase ( ) ;
843+ let line_algo = algo_from_line. to_lowercase ( ) ;
841844 * last_algo = Some ( algo_from_line) ;
842845
843- // check if we are called with XXXsum (example: md5sum) but we detected a different algo parsing the file
844- // (for example SHA1 (f) = d...)
846+ // check if we are called with XXXsum (example: md5sum) but we detected a
847+ // different algo parsing the file (for example SHA1 (f) = d...)
848+ //
845849 // Also handle the case cksum -s sm3 but the file contains other formats
846- if algo_name_input. is_some ( ) && algo_name_input != Some ( & algorithm) {
847- return Err ( LineCheckError :: ImproperlyFormatted ) ;
850+ if let Some ( algo_name_input) = algo_name_input {
851+ match ( algo_name_input, line_algo. as_str ( ) ) {
852+ ( l, r) if l == r => ( ) ,
853+ // Edge case for SHA2, which matches SHA(224|256|384|512)
854+ (
855+ ALGORITHM_OPTIONS_SHA2 ,
856+ ALGORITHM_OPTIONS_SHA224
857+ | ALGORITHM_OPTIONS_SHA256
858+ | ALGORITHM_OPTIONS_SHA384
859+ | ALGORITHM_OPTIONS_SHA512 ,
860+ ) => ( ) ,
861+ _ => return Err ( LineCheckError :: ImproperlyFormatted ) ,
862+ }
848863 }
849864
850- if !SUPPORTED_ALGORITHMS . contains ( & algorithm . as_str ( ) ) {
865+ if !SUPPORTED_ALGORITHMS . contains ( & line_algo . as_str ( ) ) {
851866 // Not supported algo, leave early
852867 return Err ( LineCheckError :: ImproperlyFormatted ) ;
853868 }
854869
855870 let bytes = if let Some ( bitlen) = line_info. algo_bit_len {
856- match algorithm . as_str ( ) {
871+ match line_algo . as_str ( ) {
857872 ALGORITHM_OPTIONS_BLAKE2B if bitlen % 8 == 0 => Some ( bitlen / 8 ) ,
858- ALGORITHM_OPTIONS_SHA3 if [ 224 , 256 , 384 , 512 ] . contains ( & bitlen) => Some ( bitlen) ,
873+ ALGORITHM_OPTIONS_SHA2 | ALGORITHM_OPTIONS_SHA3
874+ if [ 224 , 256 , 384 , 512 ] . contains ( & bitlen) =>
875+ {
876+ Some ( bitlen)
877+ }
859878 // Either
860879 // the algo based line is provided with a bit length
861880 // with an algorithm that does not support it (only Blake2B does).
@@ -866,14 +885,14 @@ fn identify_algo_name_and_length(
866885 // the given length is wrong because it's not a multiple of 8.
867886 _ => return Err ( LineCheckError :: ImproperlyFormatted ) ,
868887 }
869- } else if algorithm == ALGORITHM_OPTIONS_BLAKE2B {
888+ } else if line_algo == ALGORITHM_OPTIONS_BLAKE2B {
870889 // Default length with BLAKE2b,
871890 Some ( 64 )
872891 } else {
873892 None
874893 } ;
875894
876- Ok ( ( algorithm , bytes) )
895+ Ok ( ( line_algo , bytes) )
877896}
878897
879898/// Given a filename and an algorithm, compute the digest and compare it with
@@ -1219,21 +1238,29 @@ pub fn digest_reader<T: Read>(
12191238
12201239/// Calculates the length of the digest.
12211240pub fn calculate_blake2b_length ( length : usize ) -> UResult < Option < usize > > {
1222- match length {
1223- 0 => Ok ( None ) ,
1224- n if n % 8 != 0 => {
1225- show_error ! ( "invalid length: \u{2018} {length}\u{2019} " ) ;
1241+ calculate_blake2b_length_str ( length. to_string ( ) . as_str ( ) )
1242+ }
1243+
1244+ /// Calculates the length of the digest.
1245+ pub fn calculate_blake2b_length_str ( length : & str ) -> UResult < Option < usize > > {
1246+ match length. parse ( ) {
1247+ Ok ( 0 ) => Ok ( None ) ,
1248+ Ok ( n) if n % 8 != 0 => {
1249+ show_error ! ( "{}" , ChecksumError :: InvalidLength ( length. into( ) ) ) ;
12261250 Err ( io:: Error :: new ( io:: ErrorKind :: InvalidInput , "length is not a multiple of 8" ) . into ( ) )
12271251 }
1228- n if n > 512 => {
1229- show_error ! ( "invalid length: \u{2018} {length} \u{2019} " ) ;
1252+ Ok ( n ) if n > 512 => {
1253+ show_error ! ( "{}" , ChecksumError :: InvalidLength ( length . into ( ) ) ) ;
12301254 Err ( io:: Error :: new (
12311255 io:: ErrorKind :: InvalidInput ,
1232- "maximum digest length for \u{2018} BLAKE2b\u{2019} is 512 bits" ,
1256+ format ! (
1257+ "maximum digest length for {} is 512 bits" ,
1258+ "BLAKE2b" . quote( )
1259+ ) ,
12331260 )
12341261 . into ( ) )
12351262 }
1236- n => {
1263+ Ok ( n ) => {
12371264 // Divide by 8, as our blake2b implementation expects bytes instead of bits.
12381265 if n == 512 {
12391266 // When length is 512, it is blake2b's default.
@@ -1243,17 +1270,43 @@ pub fn calculate_blake2b_length(length: usize) -> UResult<Option<usize>> {
12431270 Ok ( Some ( n / 8 ) )
12441271 }
12451272 }
1273+ Err ( _) => Err ( ChecksumError :: InvalidLength ( length. into ( ) ) . into ( ) ) ,
12461274 }
12471275}
12481276
12491277pub fn validate_sha2_sha3_length ( algo_name : & str , length : Option < usize > ) -> UResult < usize > {
12501278 match length {
12511279 Some ( len @ ( 224 | 256 | 384 | 512 ) ) => Ok ( len) ,
12521280 Some ( len) => {
1253- show_error ! ( "invalid length: '{len}'" ) ;
1254- Err ( ChecksumError :: InvalidLengthFor ( algo_name. to_ascii_uppercase ( ) ) . into ( ) )
1281+ show_error ! ( "{}" , ChecksumError :: InvalidLength ( len . to_string ( ) ) ) ;
1282+ Err ( ChecksumError :: InvalidLengthForSha ( algo_name. to_ascii_uppercase ( ) ) . into ( ) )
12551283 }
1256- None => Err ( ChecksumError :: LengthRequired ( algo_name. to_ascii_uppercase ( ) ) . into ( ) ) ,
1284+ None => Err ( ChecksumError :: LengthRequiredForSha ( algo_name. into ( ) ) . into ( ) ) ,
1285+ }
1286+ }
1287+
1288+ pub fn sanitize_sha2_sha3_length_str ( algo_name : & str , length : & str ) -> UResult < usize > {
1289+ // There is a difference in the errors sent when the length is not a number
1290+ // vs. its an invalid number.
1291+ //
1292+ // When inputting an invalid number, an extra error message it printed to
1293+ // remind of the accepted inputs.
1294+ let len = match length. parse :: < usize > ( ) {
1295+ Ok ( l) => l,
1296+ // Note: Positive overflow while parsing counts as an invalid number,
1297+ // but a number still.
1298+ Err ( e) if * e. kind ( ) == IntErrorKind :: PosOverflow => {
1299+ show_error ! ( "{}" , ChecksumError :: InvalidLength ( length. into( ) ) ) ;
1300+ return Err ( ChecksumError :: InvalidLengthForSha ( algo_name. to_ascii_uppercase ( ) ) . into ( ) ) ;
1301+ }
1302+ Err ( _) => return Err ( ChecksumError :: InvalidLength ( length. into ( ) ) . into ( ) ) ,
1303+ } ;
1304+
1305+ if [ 224 , 256 , 384 , 512 ] . contains ( & len) {
1306+ Ok ( len)
1307+ } else {
1308+ show_error ! ( "{}" , ChecksumError :: InvalidLength ( length. into( ) ) ) ;
1309+ Err ( ChecksumError :: InvalidLengthForSha ( algo_name. to_ascii_uppercase ( ) ) . into ( ) )
12571310 }
12581311}
12591312
0 commit comments