@@ -16,7 +16,7 @@ pub const BUF_SIZE: usize = 1 << 14;
1616
1717/// Wraps a writer and encrypts and authenticates everything written to it.
1818///
19- /// `EncrWriter ` splits data into fixed-size fragments and encrypts and
19+ /// `EncWriter ` splits data into fixed-size fragments and encrypts and
2020/// authenticates each fragment separately. It appends any remaining data
2121/// to its in-memory buffer until it has gathered a complete fragment.
2222/// Therefore, using an `std::io::BufWriter` in addition usually does not
@@ -27,8 +27,9 @@ pub const BUF_SIZE: usize = 1 << 14;
2727/// When the `EncWriter` is dropped, any buffered content will be encrypted
2828/// as well as authenticated and written out. However, any errors that happen
2929/// in the process of flushing the buffer when the `EncWriter` is dropped will
30- /// be ignored. Therefore, code should call `flush ` explicitly to ensure that
30+ /// be ignored. Therefore, code should call `close ` explicitly to ensure that
3131/// all encrypted data has been written out successfully.
32+ ///
3233/// # Examples
3334///
3435/// Let's encrypt a string and store the ciphertext in memory:
@@ -59,7 +60,7 @@ pub const BUF_SIZE: usize = 1 << 14;
5960/// let mut writer = EncWriter::new(ciphertext, &key, nonce, aad);
6061///
6162/// writer.write_all(plaintext).unwrap();
62- /// writer.flush ().unwrap(); // Complete the encryption process explicitly.
63+ /// writer.close ().unwrap(); // Complete the encryption process explicitly.
6364/// ```
6465pub struct EncWriter < A : Algorithm , W : Write > {
6566 inner : W ,
@@ -68,14 +69,108 @@ pub struct EncWriter<A: Algorithm, W: Write> {
6869 buf_size : usize ,
6970 nonce : Counter < A > ,
7071 aad : [ u8 ; 16 + 1 ] , // TODO: replace with [u8; A::TAG_LEN + 1]
71- flushed : bool ,
72+
73+ // If an error occurs, we must fail any subsequent write of flush operation.
74+ // If set to true, this flag tells the write and flush implementation to fail
75+ // immediately.
76+ errored : bool ,
77+
78+ // If `close` has been called explicitly, we must not try to close the
79+ // EncWriter again. This flag tells the Drop impl if it should skip the
80+ // close.
81+ closed : bool ,
82+
83+ // If the inner writer panics in a call to write, we don't want to
84+ // write the buffered data a second time in BufWriter's destructor. This
85+ // flag tells the Drop impl if it should skip the close.
86+ panicked : bool ,
7287}
7388
7489impl < A : Algorithm , W : Write > EncWriter < A , W > {
90+ /// Creates a new `EncWriter` with a default buffer size of 16 KiB.
91+ ///
92+ /// Anything written to the `EncWriter` gets encrypted and authenticated
93+ /// using the provided `key` and `nonce`. The `aad` is only authenticated
94+ /// and neither encrypted nor written to the `inner` writer.
95+ ///
96+ /// # Examples
97+ ///
98+ /// ```
99+ /// use std::io::{Write, Read};
100+ /// use sio::{Key, Nonce, Aad, EncWriter};
101+ /// use sio::ring::AES_256_GCM;
102+ ///
103+ /// // Load your secret keys from a secure location or derive
104+ /// // them using a secure (password-based) key-derivation-function, like Argon2id.
105+ /// // Obviously, don't use this all-zeros key for anything real.
106+ /// let key: Key<AES_256_GCM> = Key::new([0; Key::<AES_256_GCM>::SIZE]);
107+ ///
108+ /// // Make sure you use an unique key-nonce combination!
109+ /// // Reusing a nonce value for the same secret key breaks
110+ /// // the security of the encryption algorithm.
111+ /// let nonce = Nonce::new([0; Nonce::<AES_256_GCM>::SIZE]);
112+ ///
113+ /// // You must be able to re-generate this aad to decrypt
114+ /// // the ciphertext again. Usually, it's stored together with
115+ /// // the encrypted data.
116+ /// let aad = Aad::from("Some authenticated but not encrypted data".as_bytes());
117+ //////
118+ /// let mut ciphertext: Vec<u8> = Vec::default(); // Store the ciphertext in memory.
119+ /// let mut writer = EncWriter::new(ciphertext, &key, nonce, aad);
120+ ///
121+ /// // Perform some write and flush operations
122+ /// // ...
123+ ///
124+ /// writer.close().unwrap(); // Complete the encryption process explicitly.
125+ /// ```
75126 pub fn new ( inner : W , key : & Key < A > , nonce : Nonce < A > , aad : Aad ) -> Self {
76127 Self :: with_buffer_size ( inner, key, nonce, aad, BUF_SIZE ) . unwrap ( )
77128 }
78129
130+ /// Creates a new `EncWriter` with the specified buffer size as fragment
131+ /// size. The `buf_size` must not be `0` nor greater than `MAX_BUF_SIZE`.
132+ ///
133+ /// Anything written to the `EncWriter` gets encrypted and authenticated
134+ /// using the provided `key` and `nonce`. The `aad` is only authenticated
135+ /// and neither encrypted nor written to the `inner` writer.
136+ ///
137+ /// It's important to always use the same buffer/fragment size for
138+ /// encrypting and decrypting. Trying to decrypt data that has been
139+ /// encrypted with a different fragment size will fail. Therefore,
140+ /// the buffer size is usually fixed for one (kind of) application.
141+ ///
142+ /// # Examples
143+ ///
144+ /// Creating an `EncWriter` with a fragment size of 64 KiB.
145+ ///
146+ /// ```
147+ /// use std::io::{Write, Read};
148+ /// use sio::{Key, Nonce, Aad, EncWriter};
149+ /// use sio::ring::AES_256_GCM;
150+ ///
151+ /// // Load your secret keys from a secure location or derive
152+ /// // them using a secure (password-based) key-derivation-function, like Argon2id.
153+ /// // Obviously, don't use this all-zeros key for anything real.
154+ /// let key: Key<AES_256_GCM> = Key::new([0; Key::<AES_256_GCM>::SIZE]);
155+ ///
156+ /// // Make sure you use an unique key-nonce combination!
157+ /// // Reusing a nonce value for the same secret key breaks
158+ /// // the security of the encryption algorithm.
159+ /// let nonce = Nonce::new([0; Nonce::<AES_256_GCM>::SIZE]);
160+ ///
161+ /// // You must be able to re-generate this aad to decrypt
162+ /// // the ciphertext again. Usually, it's stored together with
163+ /// // the encrypted data.
164+ /// let aad = Aad::from("Some authenticated but not encrypted data".as_bytes());
165+ //////
166+ /// let mut ciphertext: Vec<u8> = Vec::default(); // Store the ciphertext in memory.
167+ /// let mut writer = EncWriter::with_buffer_size(ciphertext, &key, nonce, aad, 64 * 1024).unwrap();
168+ ///
169+ /// // Perform some write and flush operations
170+ /// // ...
171+ ///
172+ /// writer.close().unwrap(); // Complete the encryption process explicitly.
173+ /// ```
79174 pub fn with_buffer_size (
80175 inner : W ,
81176 key : & Key < A > ,
@@ -104,49 +199,84 @@ impl<A: Algorithm, W: Write> EncWriter<A, W> {
104199 buf_size : buf_size,
105200 nonce : nonce,
106201 aad : associated_data,
107- flushed : false ,
202+ errored : false ,
203+ closed : false ,
204+ panicked : false ,
108205 } )
109206 }
110207
208+ /// Completes the encryption process, writes the last ciphertext
209+ /// fragment to the inner writer and ensures that all buffered
210+ /// contents reach their destination.
211+ pub fn close ( mut self ) -> io:: Result < ( ) > {
212+ self . close_internal ( )
213+ }
214+
215+ fn close_internal ( & mut self ) -> io:: Result < ( ) > {
216+ if self . errored {
217+ return Err ( io:: Error :: from ( io:: ErrorKind :: Other ) ) ;
218+ }
219+ self . closed = true ;
220+ self . aad [ 0 ] = 0x80 ; // For the last fragment change the AAD
221+
222+ self . panicked = true ;
223+ let r = self . write_buffer ( ) . and_then ( |( ) | self . inner . flush ( ) ) ;
224+ self . panicked = false ;
225+
226+ self . errored = r. is_err ( ) ;
227+ r
228+ }
229+
230+ // Encrypt and authenticate the buffer and write the ciphertext
231+ // to the inner writer.
111232 fn write_buffer ( & mut self ) -> io:: Result < ( ) > {
112233 self . buffer . resize ( self . buffer . len ( ) + A :: TAG_LEN , 0 ) ;
113234 let ciphertext = self . algorithm . seal_in_place (
114235 & self . nonce . next ( ) ?,
115236 & self . aad ,
116237 self . buffer . as_mut_slice ( ) ,
117238 ) ?;
118- self . inner . write_all ( ciphertext) ?;
239+
240+ self . panicked = true ;
241+ let r = self . inner . write_all ( ciphertext) ;
242+ self . panicked = false ;
243+
119244 self . buffer . clear ( ) ;
120- Ok ( ( ) )
245+ r
121246 }
122247}
123248
124249impl < A : Algorithm , W : Write > Write for EncWriter < A , W > {
125250 fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
126- if self . flushed {
251+ if self . errored {
127252 return Err ( io:: Error :: from ( io:: ErrorKind :: Other ) ) ;
128253 }
129- let n = buf. len ( ) ;
130254
131- let remaining = self . buf_size - self . buffer . len ( ) ;
132- if buf. len ( ) <= remaining {
133- return self . buffer . write_all ( buf) . and ( Ok ( n) ) ;
134- }
255+ let r: io:: Result < usize > = {
256+ let n = buf. len ( ) ;
135257
136- self . buffer . extend_from_slice ( & buf[ ..remaining] ) ;
137- self . write_buffer ( ) ?;
258+ let remaining = self . buf_size - self . buffer . len ( ) ;
259+ if buf. len ( ) <= remaining {
260+ return self . buffer . write_all ( buf) . and ( Ok ( n) ) ;
261+ }
138262
139- let buf = & buf[ remaining..] ;
140- let chunks = buf. chunks ( self . buf_size ) ;
141- chunks
142- . clone ( )
143- . take ( chunks. len ( ) - 1 ) // Since we take only n-1 elements...
144- . try_for_each ( |chunk| {
145- self . buffer . extend_from_slice ( chunk) ;
146- self . write_buffer ( )
147- } ) ?;
148- self . buffer . extend_from_slice ( chunks. last ( ) . unwrap ( ) ) ; // ... there is always a last one.
149- Ok ( n)
263+ self . buffer . extend_from_slice ( & buf[ ..remaining] ) ;
264+ self . write_buffer ( ) ?;
265+
266+ let buf = & buf[ remaining..] ;
267+ let chunks = buf. chunks ( self . buf_size ) ;
268+ chunks
269+ . clone ( )
270+ . take ( chunks. len ( ) - 1 ) // Since we take only n-1 elements...
271+ . try_for_each ( |chunk| {
272+ self . buffer . extend_from_slice ( chunk) ;
273+ self . write_buffer ( )
274+ } ) ?;
275+ self . buffer . extend_from_slice ( chunks. last ( ) . unwrap ( ) ) ; // ... there is always a last one.
276+ Ok ( n)
277+ } ;
278+ self . errored = r. is_err ( ) ;
279+ r
150280 }
151281
152282 #[ inline]
@@ -155,12 +285,24 @@ impl<A: Algorithm, W: Write> Write for EncWriter<A, W> {
155285 }
156286
157287 fn flush ( & mut self ) -> io:: Result < ( ) > {
158- if self . flushed {
288+ if self . errored {
159289 return Err ( io:: Error :: from ( io:: ErrorKind :: Other ) ) ;
160290 }
161- self . flushed = true ;
162- self . aad [ 0 ] = 0x80 ;
163- self . write_buffer ( ) . and_then ( |( ) | self . inner . flush ( ) )
291+ self . panicked = true ;
292+ let r = self . inner . flush ( ) ;
293+ self . panicked = false ;
294+
295+ self . errored = r. is_err ( ) ;
296+ r
297+ }
298+ }
299+
300+ impl < A : Algorithm , W : Write > Drop for EncWriter < A , W > {
301+ fn drop ( & mut self ) {
302+ if !self . panicked && !self . closed {
303+ // dtors should not panic, so we ignore a failed close
304+ let _r = self . close_internal ( ) ;
305+ }
164306 }
165307}
166308
@@ -266,7 +408,7 @@ mod tests {
266408
267409 use super :: ring:: AES_256_GCM ;
268410 use super :: * ;
269- use std:: io:: { Read , Write } ;
411+ use std:: io:: Read ;
270412
271413 #[ test]
272414 fn test_it ( ) {
@@ -280,6 +422,6 @@ mod tests {
280422 let mut ew = EncWriter :: with_buffer_size ( dw, & key, dec_nonce, Aad :: empty ( ) , 100 ) . unwrap ( ) ;
281423
282424 std:: io:: copy ( & mut std:: io:: repeat ( 'a' as u8 ) . take ( 2000 ) , & mut ew) . unwrap ( ) ;
283- ew. flush ( ) . unwrap ( ) ;
425+ ew. close ( ) . unwrap ( ) ;
284426 }
285427}
0 commit comments