11use std:: str;
2+ use ct_codecs:: { Base64 , Decoder } ;
23
34use sha2:: Digest ;
45
@@ -42,8 +43,12 @@ pub trait Hasher {
4243 fn finalize ( self ) -> Self :: Output ;
4344
4445 /// Construct a hash of the output format of the associated hashing
45- /// algorithm using a provided string.
46+ /// algorithm using a provided hex string.
4647 fn try_from_hex_string ( s : & str ) -> Result < Self :: Output > ;
48+
49+ /// Construct a hash of the output format of the associated hashing
50+ /// algorithm using a provided base64 string.
51+ fn try_from_base64_string ( s : & str ) -> Result < Self :: Output > ;
4752}
4853
4954impl Hasher for Sha1 {
@@ -67,15 +72,19 @@ impl Hasher for Sha1 {
6772 fn try_from_hex_string ( s : & str ) -> Result < Self :: Output > {
6873 try_from_hex_string :: < Self > ( s)
6974 }
75+
76+ fn try_from_base64_string ( s : & str ) -> Result < Self :: Output > {
77+ try_from_base64_string :: < Self > ( s)
78+ }
7079}
7180
72- pub ( crate ) mod sha1_from_str {
81+ pub ( crate ) mod sha1_from_base64_str {
7382 use crate :: { Hasher , Sha1 , Sha1Digest } ;
7483 use crate :: Result ;
7584
7685 #[ inline]
7786 pub ( crate ) fn from_str ( s : & str ) -> Result < Sha1Digest > {
78- <Sha1 as Hasher >:: try_from_hex_string ( s)
87+ <Sha1 as Hasher >:: try_from_base64_string ( s)
7988 }
8089}
8190
@@ -96,12 +105,17 @@ impl Hasher for Sha256 {
96105 fn finalize ( self ) -> Self :: Output {
97106 self . 0 . finalize ( ) . into ( )
98107 }
108+
99109 fn try_from_hex_string ( s : & str ) -> Result < Self :: Output > {
100110 try_from_hex_string :: < Self > ( s)
101111 }
112+
113+ fn try_from_base64_string ( s : & str ) -> Result < Self :: Output > {
114+ try_from_base64_string :: < Self > ( s)
115+ }
102116}
103117
104- pub ( crate ) mod sha256_from_str {
118+ pub ( crate ) mod sha256_from_hex_str {
105119 use crate :: { Hasher , Sha256 , Sha256Digest } ;
106120 use crate :: Result ;
107121
@@ -111,6 +125,16 @@ pub(crate) mod sha256_from_str {
111125 }
112126}
113127
128+ pub ( crate ) mod sha256_from_base64_str {
129+ use crate :: { Hasher , Sha256 , Sha256Digest } ;
130+ use crate :: Result ;
131+
132+ #[ inline]
133+ pub ( crate ) fn from_str ( s : & str ) -> Result < Sha256Digest > {
134+ <Sha256 as Hasher >:: try_from_base64_string ( s)
135+ }
136+ }
137+
114138/// Parse a hexadecimal string into the output of the generically typed hashing
115139/// algorithm.
116140fn try_from_hex_string < T : Hasher > ( s : & str ) -> Result < T :: Output > {
@@ -136,10 +160,29 @@ fn try_from_hex_string<T: Hasher>(s: &str) -> Result<T::Output> {
136160 }
137161}
138162
163+ /// Parse a base64 string into the output of the generically typed hashing
164+ /// algorithm.
165+ fn try_from_base64_string < T : Hasher > ( s : & str ) -> Result < T :: Output > {
166+ let mut bytes = vec ! [ 0 ; s. len( ) ] ;
167+
168+ let bytes = Base64 :: decode ( bytes. as_mut ( ) , s, None ) . map_err ( Error :: TryFromBase64 ) ?;
169+
170+ if bytes. len ( ) == T :: FINGERPRINT_SIZE {
171+ let mut digest = T :: Output :: default ( ) ;
172+ digest. as_mut ( ) . copy_from_slice ( bytes) ;
173+ Ok ( digest)
174+ } else {
175+ Err ( Error :: InvalidDigestLength {
176+ expected : T :: FINGERPRINT_SIZE ,
177+ actual : bytes. len ( ) ,
178+ } )
179+ }
180+ }
181+
139182#[ cfg( test) ]
140183mod tests {
141184 use crate :: Hasher ;
142- use super :: { Sha256 , Sha1 , try_from_hex_string} ;
185+ use super :: { Sha256 , Sha1 , try_from_hex_string, try_from_base64_string } ;
143186 use sha1:: Digest ;
144187
145188 const TEST_DATA : & [ u8 ] = b"test string" ;
@@ -197,4 +240,25 @@ mod tests {
197240 assert ! ( sha256_digest. is_ok( ) ) ;
198241 assert_eq ! ( sha256_digest. unwrap( ) , exp_bytes) ;
199242 }
243+
244+ #[ test]
245+ fn try_from_base64_string_sha1 ( ) {
246+ let base64_string = "FF+ci4cThKAdESIk5GbSgrN0Q7A=" ;
247+ let exp_bytes = [ 20 , 95 , 156 , 139 , 135 , 19 , 132 , 160 , 29 , 17 , 34 , 36 , 228 , 102 , 210 , 130 , 179 , 116 , 67 , 176 ] ;
248+ let sha1_digest = try_from_base64_string :: < Sha1 > ( base64_string) ;
249+
250+ assert ! ( sha1_digest. is_ok( ) ) ;
251+ assert_eq ! ( sha1_digest. unwrap( ) , exp_bytes) ;
252+ }
253+
254+ #[ test]
255+ fn try_from_base64_string_sha256 ( ) {
256+ let base64_string = "LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=" ;
257+
258+ let exp_bytes = [ 44 , 242 , 77 , 186 , 95 , 176 , 163 , 14 , 38 , 232 , 59 , 42 , 197 , 185 , 226 , 158 , 27 , 22 , 30 , 92 , 31 , 167 , 66 , 94 , 115 , 4 , 51 , 98 , 147 , 139 , 152 , 36 ] ;
259+ let sha256_digest = try_from_base64_string :: < Sha256 > ( base64_string) ;
260+
261+ assert ! ( sha256_digest. is_ok( ) ) ;
262+ assert_eq ! ( sha256_digest. unwrap( ) , & exp_bytes[ ..] ) ;
263+ }
200264}
0 commit comments