@@ -17,6 +17,7 @@ use std::{
1717} ;
1818
1919use crate :: {
20+ display:: Quotable as DisplayQuotable ,
2021 error:: { FromIo , UError , UResult , USimpleError } ,
2122 os_str_as_bytes, os_str_from_bytes,
2223 quoting_style:: { QuotingStyle , locale_aware_escape_name} ,
@@ -25,7 +26,7 @@ use crate::{
2526 Blake2b , Blake3 , Bsd , CRC32B , Crc , Digest , DigestWriter , Md5 , Sha1 , Sha3_224 , Sha3_256 ,
2627 Sha3_384 , Sha3_512 , Sha224 , Sha256 , Sha384 , Sha512 , Shake128 , Shake256 , Sm3 , SysV ,
2728 } ,
28- util_name,
29+ translate , util_name,
2930} ;
3031use thiserror:: Error ;
3132
@@ -1185,22 +1186,47 @@ pub fn digest_reader<T: Read>(
11851186 }
11861187}
11871188
1189+ /// Validates and calculates the length of the digest from a string input.
1190+ /// This function handles very large numbers that might not fit in usize.
1191+ pub fn validate_blake2b_length_str ( length_str : & str ) -> UResult < Option < usize > > {
1192+ // First try to parse as u128 to handle very large numbers
1193+ match length_str. parse :: < u128 > ( ) {
1194+ Ok ( length_u128) => {
1195+ if length_u128 > usize:: MAX as u128 {
1196+ // For very large numbers, always show the max length error
1197+ show_error ! ( "invalid length: '{length_str}'" ) ;
1198+ return Err ( io:: Error :: new (
1199+ io:: ErrorKind :: InvalidInput ,
1200+ "maximum digest length for 'BLAKE2b' is 512 bits" ,
1201+ )
1202+ . into ( ) ) ;
1203+ }
1204+ let length = length_u128 as usize ;
1205+ calculate_blake2b_length ( length)
1206+ }
1207+ Err ( _) => {
1208+ show_error ! ( "invalid length: '{length_str}'" ) ;
1209+ Err ( io:: Error :: new ( io:: ErrorKind :: InvalidInput , "invalid length" ) . into ( ) )
1210+ }
1211+ }
1212+ }
1213+
11881214/// Calculates the length of the digest.
11891215pub fn calculate_blake2b_length ( length : usize ) -> UResult < Option < usize > > {
11901216 match length {
11911217 0 => Ok ( None ) ,
1192- n if n % 8 != 0 => {
1193- show_error ! ( "invalid length: \u{2018} {length}\u{2019} " ) ;
1194- Err ( io:: Error :: new ( io:: ErrorKind :: InvalidInput , "length is not a multiple of 8" ) . into ( ) )
1195- }
11961218 n if n > 512 => {
1197- show_error ! ( "invalid length: \u{2018} { length}\u{2019} " ) ;
1219+ show_error ! ( "invalid length: '{ length}' " ) ;
11981220 Err ( io:: Error :: new (
11991221 io:: ErrorKind :: InvalidInput ,
1200- "maximum digest length for \u{2018} BLAKE2b\u{2019} is 512 bits" ,
1222+ "maximum digest length for ' BLAKE2b' is 512 bits" ,
12011223 )
12021224 . into ( ) )
12031225 }
1226+ n if n % 8 != 0 => {
1227+ show_error ! ( "invalid length: '{length}'" ) ;
1228+ Err ( io:: Error :: new ( io:: ErrorKind :: InvalidInput , "length is not a multiple of 8" ) . into ( ) )
1229+ }
12041230 n => {
12051231 // Divide by 8, as our blake2b implementation expects bytes instead of bits.
12061232 if n == 512 {
@@ -1214,6 +1240,78 @@ pub fn calculate_blake2b_length(length: usize) -> UResult<Option<usize>> {
12141240 }
12151241}
12161242
1243+ /// Validate BLAKE2b length with Fluent error messages
1244+ /// This function is used by utilities that need localized error messages
1245+ pub fn validate_blake2b_length (
1246+ length_str : & str ,
1247+ utility_name : & str ,
1248+ ) -> UResult < Option < usize > > {
1249+ // First try to parse as u128 to handle very large numbers
1250+ match length_str. parse :: < u128 > ( ) {
1251+ Ok ( length_u128) => {
1252+ if length_u128 > usize:: MAX as u128 {
1253+ // For very large numbers, always show the max length error
1254+ // Use the original string to avoid precision issues
1255+ let error_key = format ! ( "{}-error-invalid-length" , utility_name) ;
1256+ let max_key = format ! ( "{}-error-max-digest-length" , utility_name) ;
1257+ show_error ! (
1258+ "{}" ,
1259+ translate!( & error_key, "length" => DisplayQuotable :: quote( length_str) )
1260+ ) ;
1261+ return Err ( io:: Error :: new (
1262+ io:: ErrorKind :: InvalidInput ,
1263+ translate ! ( & max_key, "algorithm" => "BLAKE2b" , "max_bits" => 512 ) ,
1264+ )
1265+ . into ( ) ) ;
1266+ }
1267+ let length = length_u128 as usize ;
1268+ match length {
1269+ 0 => Ok ( None ) ,
1270+ n if n > 512 => {
1271+ let error_key = format ! ( "{}-error-invalid-length" , utility_name) ;
1272+ let max_key = format ! ( "{}-error-max-digest-length" , utility_name) ;
1273+ show_error ! (
1274+ "{}" ,
1275+ translate!( & error_key, "length" => DisplayQuotable :: quote( length_str) )
1276+ ) ;
1277+ Err ( io:: Error :: new (
1278+ io:: ErrorKind :: InvalidInput ,
1279+ translate ! ( & max_key, "algorithm" => "BLAKE2b" , "max_bits" => 512 ) ,
1280+ )
1281+ . into ( ) )
1282+ }
1283+ n if n % 8 != 0 => {
1284+ let error_key = format ! ( "{}-error-invalid-length" , utility_name) ;
1285+ show_error ! (
1286+ "{}" ,
1287+ translate!( & error_key, "length" => DisplayQuotable :: quote( length_str) )
1288+ ) ;
1289+ Err ( io:: Error :: new (
1290+ io:: ErrorKind :: InvalidInput ,
1291+ "length is not a multiple of 8" ,
1292+ )
1293+ . into ( ) )
1294+ }
1295+ n => {
1296+ // Divide by 8, as our blake2b implementation expects bytes instead of bits.
1297+ if n == 512 {
1298+ // When length is 512, it is blake2b's default.
1299+ // So, don't show it
1300+ Ok ( None )
1301+ } else {
1302+ Ok ( Some ( n / 8 ) )
1303+ }
1304+ }
1305+ }
1306+ }
1307+ Err ( _) => {
1308+ let error_key = format ! ( "{}-error-invalid-length" , utility_name) ;
1309+ show_error ! ( "{}" , translate!( & error_key, "length" => length_str. quote( ) ) ) ;
1310+ Err ( io:: Error :: new ( io:: ErrorKind :: InvalidInput , "invalid length" ) . into ( ) )
1311+ }
1312+ }
1313+ }
1314+
12171315pub fn unescape_filename ( filename : & [ u8 ] ) -> ( Vec < u8 > , & ' static str ) {
12181316 let mut unescaped = Vec :: with_capacity ( filename. len ( ) ) ;
12191317 let mut byte_iter = filename. iter ( ) . peekable ( ) ;
0 commit comments