@@ -58,7 +58,7 @@ impl<'a, T: Writeable> Writeable for ChaChaPolyWriteAdapter<'a, T> {
5858}
5959
6060/// Encrypts the provided plaintext with the given key using ChaCha20Poly1305 in the modified
61- /// with-AAD form used in [`ChaChaDualPolyReadAdapter `].
61+ /// with-AAD form used in [`ChaChaTriPolyReadAdapter `].
6262pub ( crate ) fn chachapoly_encrypt_with_swapped_aad (
6363 mut plaintext : Vec < u8 > , key : [ u8 ; 32 ] , aad : [ u8 ; 32 ] ,
6464) -> Vec < u8 > {
@@ -84,34 +84,48 @@ pub(crate) fn chachapoly_encrypt_with_swapped_aad(
8484 plaintext
8585}
8686
87+ #[ derive( PartialEq , Eq ) ]
88+ pub ( crate ) enum TriPolyAADUsed {
89+ /// No AAD was used.
90+ ///
91+ /// The HMAC validated with standard ChaCha20Poly1305.
92+ None ,
93+ /// The HMAC vlidated using the first AAD provided.
94+ First ,
95+ /// The HMAC vlidated using the second AAD provided.
96+ Second ,
97+ }
98+
8799/// Enables the use of the serialization macros for objects that need to be simultaneously decrypted
88100/// and deserialized. This allows us to avoid an intermediate Vec allocation.
89101///
90- /// This variant of [`ChaChaPolyReadAdapter`] calculates Poly1305 tags twice , once using the given
91- /// key and once with the given 32-byte AAD appended after the encrypted stream, accepting either
92- /// being correct as sufficient.
102+ /// This variant of [`ChaChaPolyReadAdapter`] calculates Poly1305 tags thrice , once using the given
103+ /// key and once each for the two given 32-byte AADs appended after the encrypted stream, accepting
104+ /// any being correct as sufficient.
93105///
94- /// Note that we do *not* use the provided AAD as the standard ChaCha20Poly1305 AAD as that would
106+ /// Note that we do *not* use the provided AADs as the standard ChaCha20Poly1305 AAD as that would
95107/// require placing it first and prevent us from avoiding redundant Poly1305 rounds. Instead, the
96108/// ChaCha20Poly1305 MAC check is tweaked to move the AAD to *after* the the contents being
97109/// checked, effectively treating the contents as the AAD for the AAD-containing MAC but behaving
98110/// like classic ChaCha20Poly1305 for the non-AAD-containing MAC.
99- pub ( crate ) struct ChaChaDualPolyReadAdapter < R : Readable > {
111+ pub ( crate ) struct ChaChaTriPolyReadAdapter < R : Readable > {
100112 pub readable : R ,
101- pub used_aad : bool ,
113+ pub used_aad : TriPolyAADUsed ,
102114}
103115
104- impl < T : Readable > LengthReadableArgs < ( [ u8 ; 32 ] , [ u8 ; 32 ] ) > for ChaChaDualPolyReadAdapter < T > {
116+ impl < T : Readable > LengthReadableArgs < ( [ u8 ; 32 ] , [ u8 ; 32 ] , [ u8 ; 32 ] ) >
117+ for ChaChaTriPolyReadAdapter < T >
118+ {
105119 // Simultaneously read and decrypt an object from a LengthLimitedRead storing it in
106120 // Self::readable. LengthLimitedRead must be used instead of std::io::Read because we need the
107121 // total length to separate out the tag at the end.
108122 fn read < R : LengthLimitedRead > (
109- r : & mut R , params : ( [ u8 ; 32 ] , [ u8 ; 32 ] ) ,
123+ r : & mut R , params : ( [ u8 ; 32 ] , [ u8 ; 32 ] , [ u8 ; 32 ] ) ,
110124 ) -> Result < Self , DecodeError > {
111125 if r. remaining_bytes ( ) < 16 {
112126 return Err ( DecodeError :: InvalidValue ) ;
113127 }
114- let ( key, aad ) = params;
128+ let ( key, aad_a , aad_b ) = params;
115129
116130 let mut chacha = ChaCha20 :: new ( & key[ ..] , & [ 0 ; 12 ] ) ;
117131 let mut mac_key = [ 0u8 ; 64 ] ;
@@ -125,7 +139,7 @@ impl<T: Readable> LengthReadableArgs<([u8; 32], [u8; 32])> for ChaChaDualPolyRea
125139 let decrypted_len = r. remaining_bytes ( ) - 16 ;
126140 let s = FixedLengthReader :: new ( r, decrypted_len) ;
127141 let mut chacha_stream =
128- ChaChaDualPolyReader { chacha : & mut chacha, poly : & mut mac, read_len : 0 , read : s } ;
142+ ChaChaTriPolyReader { chacha : & mut chacha, poly : & mut mac, read_len : 0 , read : s } ;
129143
130144 let readable: T = Readable :: read ( & mut chacha_stream) ?;
131145 while chacha_stream. read . bytes_remain ( ) {
@@ -142,14 +156,18 @@ impl<T: Readable> LengthReadableArgs<([u8; 32], [u8; 32])> for ChaChaDualPolyRea
142156 mac. input ( & [ 0 ; 16 ] [ 0 ..16 - ( read_len % 16 ) ] ) ;
143157 }
144158
145- let mut mac_aad = mac;
159+ let mut mac_aad_a = mac;
160+ let mut mac_aad_b = mac;
146161
147- mac_aad. input ( & aad[ ..] ) ;
162+ mac_aad_a. input ( & aad_a[ ..] ) ;
163+ mac_aad_b. input ( & aad_b[ ..] ) ;
148164 // Note that we don't need to pad the AAD since its a multiple of 16 bytes
149165
150166 // For the AAD-containing MAC, swap the AAD and the read data, effectively.
151- mac_aad. input ( & ( read_len as u64 ) . to_le_bytes ( ) ) ;
152- mac_aad. input ( & 32u64 . to_le_bytes ( ) ) ;
167+ mac_aad_a. input ( & ( read_len as u64 ) . to_le_bytes ( ) ) ;
168+ mac_aad_b. input ( & ( read_len as u64 ) . to_le_bytes ( ) ) ;
169+ mac_aad_a. input ( & 32u64 . to_le_bytes ( ) ) ;
170+ mac_aad_b. input ( & 32u64 . to_le_bytes ( ) ) ;
153171
154172 // For the non-AAD-containing MAC, leave the data and AAD where they belong.
155173 mac. input ( & 0u64 . to_le_bytes ( ) ) ;
@@ -158,23 +176,25 @@ impl<T: Readable> LengthReadableArgs<([u8; 32], [u8; 32])> for ChaChaDualPolyRea
158176 let mut tag = [ 0 as u8 ; 16 ] ;
159177 r. read_exact ( & mut tag) ?;
160178 if fixed_time_eq ( & mac. result ( ) , & tag) {
161- Ok ( Self { readable, used_aad : false } )
162- } else if fixed_time_eq ( & mac_aad. result ( ) , & tag) {
163- Ok ( Self { readable, used_aad : true } )
179+ Ok ( Self { readable, used_aad : TriPolyAADUsed :: None } )
180+ } else if fixed_time_eq ( & mac_aad_a. result ( ) , & tag) {
181+ Ok ( Self { readable, used_aad : TriPolyAADUsed :: First } )
182+ } else if fixed_time_eq ( & mac_aad_b. result ( ) , & tag) {
183+ Ok ( Self { readable, used_aad : TriPolyAADUsed :: Second } )
164184 } else {
165185 return Err ( DecodeError :: InvalidValue ) ;
166186 }
167187 }
168188}
169189
170- struct ChaChaDualPolyReader < ' a , R : Read > {
190+ struct ChaChaTriPolyReader < ' a , R : Read > {
171191 chacha : & ' a mut ChaCha20 ,
172192 poly : & ' a mut Poly1305 ,
173193 read_len : usize ,
174194 pub read : R ,
175195}
176196
177- impl < ' a , R : Read > Read for ChaChaDualPolyReader < ' a , R > {
197+ impl < ' a , R : Read > Read for ChaChaTriPolyReader < ' a , R > {
178198 // Decrypts bytes from Self::read into `dest`.
179199 // After all reads complete, the caller must compare the expected tag with
180200 // the result of `Poly1305::result()`.
@@ -349,15 +369,15 @@ mod tests {
349369 }
350370
351371 #[ test]
352- fn short_read_chacha_dual_read_adapter ( ) {
353- // Previously, if we attempted to read from a ChaChaDualPolyReadAdapter but the object
372+ fn short_read_chacha_tri_read_adapter ( ) {
373+ // Previously, if we attempted to read from a ChaChaTriPolyReadAdapter but the object
354374 // being read is shorter than the available buffer while the buffer passed to
355- // ChaChaDualPolyReadAdapter itself always thinks it has room, we'd end up
375+ // ChaChaTriPolyReadAdapter itself always thinks it has room, we'd end up
356376 // infinite-looping as we didn't handle `Read::read`'s 0 return values at EOF.
357377 let mut stream = & [ 0 ; 1024 ] [ ..] ;
358378 let mut too_long_stream = FixedLengthReader :: new ( & mut stream, 2048 ) ;
359- let keys = ( [ 42 ; 32 ] , [ 99 ; 32 ] ) ;
360- let res = super :: ChaChaDualPolyReadAdapter :: < u8 > :: read ( & mut too_long_stream, keys) ;
379+ let keys = ( [ 42 ; 32 ] , [ 98 ; 32 ] , [ 99 ; 32 ] ) ;
380+ let res = super :: ChaChaTriPolyReadAdapter :: < u8 > :: read ( & mut too_long_stream, keys) ;
361381 match res {
362382 Ok ( _) => panic ! ( ) ,
363383 Err ( e) => assert_eq ! ( e, DecodeError :: ShortRead ) ,
0 commit comments