1- use crate :: crypto:: chacha20:: ChaCha20 ;
2- use crate :: crypto:: chacha20poly1305rfc:: ChaCha20Poly1305RFC ;
31use crate :: crypto:: fixed_time_eq;
4- use crate :: crypto:: poly1305:: Poly1305 ;
52
63use crate :: io:: { self , Read , Write } ;
74use crate :: ln:: msgs:: DecodeError ;
@@ -10,6 +7,10 @@ use crate::util::ser::{
107} ;
118
129use alloc:: vec:: Vec ;
10+ use chacha20_poly1305:: {
11+ chacha20:: { ChaCha20 , Key , Nonce } ,
12+ poly1305:: Poly1305 ,
13+ } ;
1314
1415pub ( crate ) struct ChaChaReader < ' a , R : io:: Read > {
1516 pub chacha : & ' a mut ChaCha20 ,
@@ -19,7 +20,7 @@ impl<'a, R: io::Read> io::Read for ChaChaReader<'a, R> {
1920 fn read ( & mut self , dest : & mut [ u8 ] ) -> Result < usize , io:: Error > {
2021 let res = self . read . read ( dest) ?;
2122 if res > 0 {
22- self . chacha . process_in_place ( & mut dest[ 0 ..res] ) ;
23+ self . chacha . apply_keystream ( & mut dest[ ..res] ) ;
2324 }
2425 Ok ( res)
2526 }
@@ -42,11 +43,20 @@ impl<'a, W: Writeable> ChaChaPolyWriteAdapter<'a, W> {
4243impl < ' a , T : Writeable > Writeable for ChaChaPolyWriteAdapter < ' a , T > {
4344 // Simultaneously write and encrypt Self::writeable.
4445 fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , io:: Error > {
45- let mut chacha = ChaCha20Poly1305RFC :: new ( & self . rho , & [ 0 ; 12 ] , & [ ] ) ;
46- let mut chacha_stream = ChaChaPolyWriter { chacha : & mut chacha, write : w } ;
46+ let mut chacha = ChaCha20 :: new ( Key :: new ( self . rho ) , Nonce :: new ( [ 0 ; 12 ] ) , 0 ) ;
47+ let mut mac_key = [ 0u8 ; 64 ] ;
48+ chacha. apply_keystream ( & mut mac_key) ;
49+
50+ #[ cfg( not( fuzzing) ) ]
51+ let mac = Poly1305 :: new ( mac_key[ ..32 ] . try_into ( ) . unwrap ( ) ) ;
52+ #[ cfg( fuzzing) ]
53+ let mac = Poly1305 :: new ( self . rho ) ;
54+
55+ let mut chacha_stream =
56+ ChaChaPolyWriter { chacha : & mut chacha, poly : mac, write_len : 0 , write : w } ;
4757 self . writeable . write ( & mut chacha_stream) ?;
48- let mut tag = [ 0 as u8 ; 16 ] ;
49- chacha . finish_and_get_tag ( & mut tag ) ;
58+
59+ let tag = chacha_stream . finish_and_get_tag ( ) ;
5060 tag. write ( w) ?;
5161
5262 Ok ( ( ) )
@@ -62,12 +72,15 @@ impl<'a, T: Writeable> Writeable for ChaChaPolyWriteAdapter<'a, T> {
6272pub ( crate ) fn chachapoly_encrypt_with_swapped_aad (
6373 mut plaintext : Vec < u8 > , key : [ u8 ; 32 ] , aad : [ u8 ; 32 ] ,
6474) -> Vec < u8 > {
65- let mut chacha = ChaCha20 :: new ( & key[ .. ] , & [ 0 ; 12 ] ) ;
75+ let mut chacha = ChaCha20 :: new ( Key :: new ( key) , Nonce :: new ( [ 0 ; 12 ] ) , 0 ) ;
6676 let mut mac_key = [ 0u8 ; 64 ] ;
67- chacha. process_in_place ( & mut mac_key) ;
77+ chacha. apply_keystream ( & mut mac_key) ;
6878
69- let mut mac = Poly1305 :: new ( & mac_key[ ..32 ] ) ;
70- chacha. process_in_place ( & mut plaintext[ ..] ) ;
79+ #[ cfg( not( fuzzing) ) ]
80+ let mut mac = Poly1305 :: new ( mac_key[ ..32 ] . try_into ( ) . unwrap ( ) ) ;
81+ #[ cfg( fuzzing) ]
82+ let mut mac = Poly1305 :: new ( key) ;
83+ chacha. apply_keystream ( & mut plaintext[ ..] ) ;
7184 mac. input ( & plaintext[ ..] ) ;
7285
7386 if plaintext. len ( ) % 16 != 0 {
@@ -80,7 +93,7 @@ pub(crate) fn chachapoly_encrypt_with_swapped_aad(
8093 mac. input ( & ( plaintext. len ( ) as u64 ) . to_le_bytes ( ) ) ;
8194 mac. input ( & 32u64 . to_le_bytes ( ) ) ;
8295
83- plaintext. extend_from_slice ( & mac. result ( ) ) ;
96+ plaintext. extend_from_slice ( & mac. tag ( ) ) ;
8497 plaintext
8598}
8699
@@ -105,7 +118,7 @@ pub(crate) enum TriPolyAADUsed {
105118///
106119/// Note that we do *not* use the provided AADs as the standard ChaCha20Poly1305 AAD as that would
107120/// require placing it first and prevent us from avoiding redundant Poly1305 rounds. Instead, the
108- /// ChaCha20Poly1305 MAC check is tweaked to move the AAD to *after* the the contents being
121+ /// ChaCha20Poly1305 MAC check is tweaked to move the AAD to *after* the contents being
109122/// checked, effectively treating the contents as the AAD for the AAD-containing MAC but behaving
110123/// like classic ChaCha20Poly1305 for the non-AAD-containing MAC.
111124pub ( crate ) struct ChaChaTriPolyReadAdapter < R : Readable > {
@@ -127,14 +140,14 @@ impl<T: Readable> LengthReadableArgs<([u8; 32], [u8; 32], [u8; 32])>
127140 }
128141 let ( key, aad_a, aad_b) = params;
129142
130- let mut chacha = ChaCha20 :: new ( & key[ .. ] , & [ 0 ; 12 ] ) ;
143+ let mut chacha = ChaCha20 :: new ( Key :: new ( key) , Nonce :: new ( [ 0 ; 12 ] ) , 0 ) ;
131144 let mut mac_key = [ 0u8 ; 64 ] ;
132- chacha. process_in_place ( & mut mac_key) ;
145+ chacha. apply_keystream ( & mut mac_key) ;
133146
134147 #[ cfg( not( fuzzing) ) ]
135- let mut mac = Poly1305 :: new ( & mac_key[ ..32 ] ) ;
148+ let mut mac = Poly1305 :: new ( mac_key[ ..32 ] . try_into ( ) . unwrap ( ) ) ;
136149 #[ cfg( fuzzing) ]
137- let mut mac = Poly1305 :: new ( & key) ;
150+ let mut mac = Poly1305 :: new ( key) ;
138151
139152 let decrypted_len = r. remaining_bytes ( ) - 16 ;
140153 let s = FixedLengthReader :: new ( r, decrypted_len) ;
@@ -145,7 +158,6 @@ impl<T: Readable> LengthReadableArgs<([u8; 32], [u8; 32], [u8; 32])>
145158 while chacha_stream. read . bytes_remain ( ) {
146159 let mut buf = [ 0 ; 256 ] ;
147160 if chacha_stream. read ( & mut buf) ? == 0 {
148- // Reached EOF
149161 return Err ( DecodeError :: ShortRead ) ;
150162 }
151163 }
@@ -173,13 +185,13 @@ impl<T: Readable> LengthReadableArgs<([u8; 32], [u8; 32], [u8; 32])>
173185 mac. input ( & 0u64 . to_le_bytes ( ) ) ;
174186 mac. input ( & ( read_len as u64 ) . to_le_bytes ( ) ) ;
175187
176- let mut tag = [ 0 as u8 ; 16 ] ;
188+ let mut tag = [ 0u8 ; 16 ] ;
177189 r. read_exact ( & mut tag) ?;
178- if fixed_time_eq ( & mac. result ( ) , & tag) {
190+ if fixed_time_eq ( & mac. tag ( ) , & tag) {
179191 Ok ( Self { readable, used_aad : TriPolyAADUsed :: None } )
180- } else if fixed_time_eq ( & mac_aad_a. result ( ) , & tag) {
192+ } else if fixed_time_eq ( & mac_aad_a. tag ( ) , & tag) {
181193 Ok ( Self { readable, used_aad : TriPolyAADUsed :: First } )
182- } else if fixed_time_eq ( & mac_aad_b. result ( ) , & tag) {
194+ } else if fixed_time_eq ( & mac_aad_b. tag ( ) , & tag) {
183195 Ok ( Self { readable, used_aad : TriPolyAADUsed :: Second } )
184196 } else {
185197 return Err ( DecodeError :: InvalidValue ) ;
@@ -197,12 +209,12 @@ struct ChaChaTriPolyReader<'a, R: Read> {
197209impl < ' a , R : Read > Read for ChaChaTriPolyReader < ' a , R > {
198210 // Decrypts bytes from Self::read into `dest`.
199211 // After all reads complete, the caller must compare the expected tag with
200- // the result of `Poly1305::result ()`.
212+ // the result of `Poly1305::tag ()`
201213 fn read ( & mut self , dest : & mut [ u8 ] ) -> Result < usize , io:: Error > {
202214 let res = self . read . read ( dest) ?;
203215 if res > 0 {
204- self . poly . input ( & dest[ 0 ..res] ) ;
205- self . chacha . process_in_place ( & mut dest[ 0 ..res] ) ;
216+ self . poly . input ( & dest[ ..res] ) ;
217+ self . chacha . apply_keystream ( & mut dest[ ..res] ) ;
206218 self . read_len += res;
207219 }
208220 Ok ( res)
@@ -224,64 +236,109 @@ impl<T: Readable> LengthReadableArgs<[u8; 32]> for ChaChaPolyReadAdapter<T> {
224236 return Err ( DecodeError :: InvalidValue ) ;
225237 }
226238
227- let mut chacha = ChaCha20Poly1305RFC :: new ( & secret, & [ 0 ; 12 ] , & [ ] ) ;
239+ let mut chacha = ChaCha20 :: new ( Key :: new ( secret) , Nonce :: new ( [ 0 ; 12 ] ) , 0 ) ;
240+ let mut mac_key = [ 0u8 ; 64 ] ;
241+ chacha. apply_keystream ( & mut mac_key) ;
242+
243+ #[ cfg( not( fuzzing) ) ]
244+ let mut mac = Poly1305 :: new ( mac_key[ ..32 ] . try_into ( ) . unwrap ( ) ) ;
245+ #[ cfg( fuzzing) ]
246+ let mut mac = Poly1305 :: new ( secret) ;
247+
228248 let decrypted_len = r. remaining_bytes ( ) - 16 ;
229249 let s = FixedLengthReader :: new ( r, decrypted_len) ;
230- let mut chacha_stream = ChaChaPolyReader { chacha : & mut chacha, read : s } ;
250+ let mut chacha_stream = ChaChaPolyReader :: new ( & mut chacha, & mut mac , s ) ;
231251 let readable: T = Readable :: read ( & mut chacha_stream) ?;
232252 while chacha_stream. read . bytes_remain ( ) {
233253 let mut buf = [ 0 ; 256 ] ;
234- chacha_stream. read ( & mut buf) ?;
254+ if chacha_stream. read ( & mut buf) ? == 0 {
255+ return Err ( DecodeError :: ShortRead ) ;
256+ }
235257 }
236258
237- let mut tag = [ 0 as u8 ; 16 ] ;
259+ let read_len = chacha_stream. read_len ( ) ;
260+ drop ( chacha_stream) ;
261+
262+ if read_len % 16 != 0 {
263+ mac. input ( & [ 0 ; 16 ] [ 0 ..16 - ( read_len % 16 ) ] ) ;
264+ }
265+ mac. input ( & 0u64 . to_le_bytes ( ) ) ;
266+ mac. input ( & ( read_len as u64 ) . to_le_bytes ( ) ) ;
267+
268+ let mut tag = [ 0u8 ; 16 ] ;
238269 r. read_exact ( & mut tag) ?;
239- if !chacha . finish_and_check_tag ( & tag) {
270+ if !fixed_time_eq ( & mac . tag ( ) , & tag) {
240271 return Err ( DecodeError :: InvalidValue ) ;
241272 }
242273
243274 Ok ( Self { readable } )
244275 }
245276}
246277
247- /// Enables simultaneously reading and decrypting a ChaCha20Poly1305RFC stream from a std::io::Read.
278+ /// Enables simultaneously reading and decrypting a ChaCha20Poly1305 stream from a std::io::Read.
248279struct ChaChaPolyReader < ' a , R : Read > {
249- pub chacha : & ' a mut ChaCha20Poly1305RFC ,
280+ chacha : & ' a mut ChaCha20 ,
281+ poly : & ' a mut Poly1305 ,
282+ read_len : usize ,
250283 pub read : R ,
251284}
252285
286+ impl < ' a , R : Read > ChaChaPolyReader < ' a , R > {
287+ fn new ( chacha : & ' a mut ChaCha20 , poly : & ' a mut Poly1305 , read : R ) -> Self {
288+ Self { chacha, poly, read_len : 0 , read }
289+ }
290+
291+ fn read_len ( & self ) -> usize {
292+ self . read_len
293+ }
294+ }
295+
253296impl < ' a , R : Read > Read for ChaChaPolyReader < ' a , R > {
254297 // Decrypt bytes from Self::read into `dest`.
255- // `ChaCha20Poly1305RFC::finish_and_check_tag` must be called to check the tag after all reads
256- // complete.
257298 fn read ( & mut self , dest : & mut [ u8 ] ) -> Result < usize , io:: Error > {
258299 let res = self . read . read ( dest) ?;
259300 if res > 0 {
260- self . chacha . decrypt_in_place ( & mut dest[ 0 ..res] ) ;
301+ self . poly . input ( & dest[ ..res] ) ;
302+ self . chacha . apply_keystream ( & mut dest[ ..res] ) ;
303+ self . read_len += res;
261304 }
262305 Ok ( res)
263306 }
264307}
265308
266309/// Enables simultaneously writing and encrypting a byte stream into a Writer.
267310struct ChaChaPolyWriter < ' a , W : Writer > {
268- pub chacha : & ' a mut ChaCha20Poly1305RFC ,
311+ chacha : & ' a mut ChaCha20 ,
312+ poly : Poly1305 ,
313+ write_len : usize ,
269314 pub write : & ' a mut W ,
270315}
271316
317+ impl < ' a , W : Writer > ChaChaPolyWriter < ' a , W > {
318+ /// Finish encrypting and return the 16-byte authentication tag.
319+ fn finish_and_get_tag ( mut self ) -> [ u8 ; 16 ] {
320+ if self . write_len % 16 != 0 {
321+ self . poly . input ( & [ 0 ; 16 ] [ 0 ..16 - ( self . write_len % 16 ) ] ) ;
322+ }
323+ self . poly . input ( & 0u64 . to_le_bytes ( ) ) ;
324+ self . poly . input ( & ( self . write_len as u64 ) . to_le_bytes ( ) ) ;
325+ self . poly . tag ( )
326+ }
327+ }
328+
272329impl < ' a , W : Writer > Writer for ChaChaPolyWriter < ' a , W > {
273330 // Encrypt then write bytes from `src` into Self::write.
274- // `ChaCha20Poly1305RFC::finish_and_get_tag` can be called to retrieve the tag after all writes
275- // complete.
276331 fn write_all ( & mut self , src : & [ u8 ] ) -> Result < ( ) , io:: Error > {
277332 let mut src_idx = 0 ;
278333 while src_idx < src. len ( ) {
279334 let mut write_buffer = [ 0 ; 8192 ] ;
280335 let bytes_written = ( & mut write_buffer[ ..] )
281336 . write ( & src[ src_idx..] )
282337 . expect ( "In-memory writes can't fail" ) ;
283- self . chacha . encrypt_in_place ( & mut write_buffer[ ..bytes_written] ) ;
338+ self . chacha . apply_keystream ( & mut write_buffer[ ..bytes_written] ) ;
339+ self . poly . input ( & write_buffer[ ..bytes_written] ) ;
284340 self . write . write_all ( & write_buffer[ ..bytes_written] ) ?;
341+ self . write_len += bytes_written;
285342 src_idx += bytes_written;
286343 }
287344 Ok ( ( ) )
0 commit comments