@@ -10,26 +10,25 @@ pub struct Crc32Reader<R> {
1010 inner : R ,
1111 hasher : Hasher ,
1212 check : u32 ,
13+ /// Signals if `inner` stores aes encrypted data.
14+ /// AE-2 encrypted data doesn't use crc and sets the value to 0.
15+ enabled : bool ,
1316}
1417
1518impl < R > Crc32Reader < R > {
1619 /// Get a new Crc32Reader which checks the inner reader against checksum.
17- pub ( crate ) fn new ( inner : R , checksum : u32 ) -> Self {
20+ /// The check is disabled if `ae2_encrypted == true`.
21+ pub ( crate ) fn new ( inner : R , checksum : u32 , ae2_encrypted : bool ) -> Crc32Reader < R > {
1822 Crc32Reader {
1923 inner,
2024 hasher : Hasher :: new ( ) ,
2125 check : checksum,
26+ enabled : !ae2_encrypted,
2227 }
2328 }
2429
25- fn check_matches ( & self ) -> Result < ( ) , & ' static str > {
26- let res = self . hasher . clone ( ) . finalize ( ) ;
27- if self . check == res {
28- Ok ( ( ) )
29- } else {
30- /* TODO: make this into our own Crc32Error error type! */
31- Err ( "Invalid checksum" )
32- }
30+ fn check_matches ( & self ) -> bool {
31+ self . check == self . hasher . clone ( ) . finalize ( )
3332 }
3433
3534 #[ allow( dead_code) ]
@@ -38,27 +37,159 @@ impl<R> Crc32Reader<R> {
3837 }
3938}
4039
40+ #[ cold]
41+ fn invalid_checksum ( ) -> io:: Error {
42+ io:: Error :: new ( io:: ErrorKind :: InvalidData , "Invalid checksum" )
43+ }
44+
4145impl < R : Read > Read for Crc32Reader < R > {
4246 fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
43- /* We want to make sure we only check the hash when the input stream is exhausted. */
44- if buf. is_empty ( ) {
45- /* If the input buf is empty (this shouldn't happen, but isn't guaranteed), we
46- * still want to "pull" from the source in case it surfaces an i/o error. This will
47- * always return a count of Ok(0) if successful. */
48- return self . inner . read ( buf) ;
49- }
50-
5147 let count = self . inner . read ( buf) ?;
52- if count == 0 {
53- return self
54- . check_matches ( )
55- . map ( | ( ) | 0 )
56- /* TODO: use io::Error::other for MSRV >=1.74 */
57- . map_err ( |e| io :: Error :: new ( io :: ErrorKind :: Other , e ) ) ;
48+
49+ if self . enabled {
50+ if count == 0 && !buf . is_empty ( ) && ! self . check_matches ( ) {
51+ return Err ( invalid_checksum ( ) ) ;
52+ }
53+ self . hasher . update ( & buf [ ..count ] ) ;
5854 }
59- self . hasher . update ( & buf[ ..count] ) ;
6055 Ok ( count)
6156 }
57+
58+ fn read_to_end ( & mut self , buf : & mut Vec < u8 > ) -> io:: Result < usize > {
59+ let start = buf. len ( ) ;
60+ let n = self . inner . read_to_end ( buf) ?;
61+
62+ if self . enabled {
63+ self . hasher . update ( & buf[ start..] ) ;
64+ if !self . check_matches ( ) {
65+ return Err ( invalid_checksum ( ) ) ;
66+ }
67+ }
68+
69+ Ok ( n)
70+ }
71+
72+ fn read_to_string ( & mut self , buf : & mut String ) -> io:: Result < usize > {
73+ let start = buf. len ( ) ;
74+ let n = self . inner . read_to_string ( buf) ?;
75+
76+ if self . enabled {
77+ self . hasher . update ( & buf. as_bytes ( ) [ start..] ) ;
78+ if !self . check_matches ( ) {
79+ return Err ( invalid_checksum ( ) ) ;
80+ }
81+ }
82+
83+ Ok ( n)
84+ }
85+ }
86+
87+ pub ( crate ) mod non_crypto {
88+ use std:: io;
89+ use std:: io:: prelude:: * ;
90+
91+ use crc32fast:: Hasher ;
92+
93+ /// Reader that validates the CRC32 when it reaches the EOF.
94+ pub struct Crc32Reader < R > {
95+ inner : R ,
96+ hasher : Hasher ,
97+ check : u32 ,
98+ }
99+
100+ impl < R > Crc32Reader < R > {
101+ /// Get a new Crc32Reader which checks the inner reader against checksum.
102+ pub ( crate ) fn new ( inner : R , checksum : u32 ) -> Self {
103+ Crc32Reader {
104+ inner,
105+ hasher : Hasher :: new ( ) ,
106+ check : checksum,
107+ }
108+ }
109+
110+ fn check_matches ( & self ) -> Result < ( ) , & ' static str > {
111+ let res = self . hasher . clone ( ) . finalize ( ) ;
112+ if self . check == res {
113+ Ok ( ( ) )
114+ } else {
115+ /* TODO: make this into our own Crc32Error error type! */
116+ Err ( "Invalid checksum" )
117+ }
118+ }
119+
120+ pub fn into_inner ( self ) -> R {
121+ self . inner
122+ }
123+ }
124+
125+ impl < R : Read > Read for Crc32Reader < R > {
126+ fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
127+ /* We want to make sure we only check the hash when the input stream is exhausted. */
128+ if buf. is_empty ( ) {
129+ /* If the input buf is empty (this shouldn't happen, but isn't guaranteed), we
130+ * still want to "pull" from the source in case it surfaces an i/o error. This will
131+ * always return a count of Ok(0) if successful. */
132+ return self . inner . read ( buf) ;
133+ }
134+
135+ let count = self . inner . read ( buf) ?;
136+ if count == 0 {
137+ return self
138+ . check_matches ( )
139+ . map ( |( ) | 0 )
140+ /* TODO: use io::Error::other for MSRV >=1.74 */
141+ . map_err ( |e| io:: Error :: new ( io:: ErrorKind :: Other , e) ) ;
142+ }
143+ self . hasher . update ( & buf[ ..count] ) ;
144+ Ok ( count)
145+ }
146+ }
147+
148+ #[ cfg( test) ]
149+ mod test {
150+ use super :: * ;
151+
152+ #[ test]
153+ fn test_empty_reader ( ) {
154+ let data: & [ u8 ] = b"" ;
155+ let mut buf = [ 0 ; 1 ] ;
156+
157+ let mut reader = Crc32Reader :: new ( data, 0 ) ;
158+ assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 0 ) ;
159+
160+ let mut reader = Crc32Reader :: new ( data, 1 ) ;
161+ assert ! ( reader
162+ . read( & mut buf)
163+ . unwrap_err( )
164+ . to_string( )
165+ . contains( "Invalid checksum" ) ) ;
166+ }
167+
168+ #[ test]
169+ fn test_byte_by_byte ( ) {
170+ let data: & [ u8 ] = b"1234" ;
171+ let mut buf = [ 0 ; 1 ] ;
172+
173+ let mut reader = Crc32Reader :: new ( data, 0x9be3e0a3 ) ;
174+ assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 1 ) ;
175+ assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 1 ) ;
176+ assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 1 ) ;
177+ assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 1 ) ;
178+ assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 0 ) ;
179+ // Can keep reading 0 bytes after the end
180+ assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 0 ) ;
181+ }
182+
183+ #[ test]
184+ fn test_zero_read ( ) {
185+ let data: & [ u8 ] = b"1234" ;
186+ let mut buf = [ 0 ; 5 ] ;
187+
188+ let mut reader = Crc32Reader :: new ( data, 0x9be3e0a3 ) ;
189+ assert_eq ! ( reader. read( & mut buf[ ..0 ] ) . unwrap( ) , 0 ) ;
190+ assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 4 ) ;
191+ }
192+ }
62193}
63194
64195#[ cfg( test) ]
@@ -70,10 +201,10 @@ mod test {
70201 let data: & [ u8 ] = b"" ;
71202 let mut buf = [ 0 ; 1 ] ;
72203
73- let mut reader = Crc32Reader :: new ( data, 0 ) ;
204+ let mut reader = Crc32Reader :: new ( data, 0 , false ) ;
74205 assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 0 ) ;
75206
76- let mut reader = Crc32Reader :: new ( data, 1 ) ;
207+ let mut reader = Crc32Reader :: new ( data, 1 , false ) ;
77208 assert ! ( reader
78209 . read( & mut buf)
79210 . unwrap_err( )
@@ -86,7 +217,7 @@ mod test {
86217 let data: & [ u8 ] = b"1234" ;
87218 let mut buf = [ 0 ; 1 ] ;
88219
89- let mut reader = Crc32Reader :: new ( data, 0x9be3e0a3 ) ;
220+ let mut reader = Crc32Reader :: new ( data, 0x9be3e0a3 , false ) ;
90221 assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 1 ) ;
91222 assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 1 ) ;
92223 assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 1 ) ;
@@ -101,7 +232,7 @@ mod test {
101232 let data: & [ u8 ] = b"1234" ;
102233 let mut buf = [ 0 ; 5 ] ;
103234
104- let mut reader = Crc32Reader :: new ( data, 0x9be3e0a3 ) ;
235+ let mut reader = Crc32Reader :: new ( data, 0x9be3e0a3 , false ) ;
105236 assert_eq ! ( reader. read( & mut buf[ ..0 ] ) . unwrap( ) , 0 ) ;
106237 assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 4 ) ;
107238 }
0 commit comments