@@ -16,7 +16,7 @@ pub const BUF_SIZE: usize = 1 << 14;
16
16
17
17
/// Wraps a writer and encrypts and authenticates everything written to it.
18
18
///
19
- /// `EncrWriter ` splits data into fixed-size fragments and encrypts and
19
+ /// `EncWriter ` splits data into fixed-size fragments and encrypts and
20
20
/// authenticates each fragment separately. It appends any remaining data
21
21
/// to its in-memory buffer until it has gathered a complete fragment.
22
22
/// Therefore, using an `std::io::BufWriter` in addition usually does not
@@ -27,8 +27,9 @@ pub const BUF_SIZE: usize = 1 << 14;
27
27
/// When the `EncWriter` is dropped, any buffered content will be encrypted
28
28
/// as well as authenticated and written out. However, any errors that happen
29
29
/// 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
31
31
/// all encrypted data has been written out successfully.
32
+ ///
32
33
/// # Examples
33
34
///
34
35
/// Let's encrypt a string and store the ciphertext in memory:
@@ -59,7 +60,7 @@ pub const BUF_SIZE: usize = 1 << 14;
59
60
/// let mut writer = EncWriter::new(ciphertext, &key, nonce, aad);
60
61
///
61
62
/// writer.write_all(plaintext).unwrap();
62
- /// writer.flush ().unwrap(); // Complete the encryption process explicitly.
63
+ /// writer.close ().unwrap(); // Complete the encryption process explicitly.
63
64
/// ```
64
65
pub struct EncWriter < A : Algorithm , W : Write > {
65
66
inner : W ,
@@ -68,14 +69,108 @@ pub struct EncWriter<A: Algorithm, W: Write> {
68
69
buf_size : usize ,
69
70
nonce : Counter < A > ,
70
71
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 ,
72
87
}
73
88
74
89
impl < 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
+ /// ```
75
126
pub fn new ( inner : W , key : & Key < A > , nonce : Nonce < A > , aad : Aad ) -> Self {
76
127
Self :: with_buffer_size ( inner, key, nonce, aad, BUF_SIZE ) . unwrap ( )
77
128
}
78
129
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
+ /// ```
79
174
pub fn with_buffer_size (
80
175
inner : W ,
81
176
key : & Key < A > ,
@@ -104,49 +199,84 @@ impl<A: Algorithm, W: Write> EncWriter<A, W> {
104
199
buf_size : buf_size,
105
200
nonce : nonce,
106
201
aad : associated_data,
107
- flushed : false ,
202
+ errored : false ,
203
+ closed : false ,
204
+ panicked : false ,
108
205
} )
109
206
}
110
207
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.
111
232
fn write_buffer ( & mut self ) -> io:: Result < ( ) > {
112
233
self . buffer . resize ( self . buffer . len ( ) + A :: TAG_LEN , 0 ) ;
113
234
let ciphertext = self . algorithm . seal_in_place (
114
235
& self . nonce . next ( ) ?,
115
236
& self . aad ,
116
237
self . buffer . as_mut_slice ( ) ,
117
238
) ?;
118
- self . inner . write_all ( ciphertext) ?;
239
+
240
+ self . panicked = true ;
241
+ let r = self . inner . write_all ( ciphertext) ;
242
+ self . panicked = false ;
243
+
119
244
self . buffer . clear ( ) ;
120
- Ok ( ( ) )
245
+ r
121
246
}
122
247
}
123
248
124
249
impl < A : Algorithm , W : Write > Write for EncWriter < A , W > {
125
250
fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
126
- if self . flushed {
251
+ if self . errored {
127
252
return Err ( io:: Error :: from ( io:: ErrorKind :: Other ) ) ;
128
253
}
129
- let n = buf. len ( ) ;
130
254
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 ( ) ;
135
257
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
+ }
138
262
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
150
280
}
151
281
152
282
#[ inline]
@@ -155,12 +285,24 @@ impl<A: Algorithm, W: Write> Write for EncWriter<A, W> {
155
285
}
156
286
157
287
fn flush ( & mut self ) -> io:: Result < ( ) > {
158
- if self . flushed {
288
+ if self . errored {
159
289
return Err ( io:: Error :: from ( io:: ErrorKind :: Other ) ) ;
160
290
}
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
+ }
164
306
}
165
307
}
166
308
@@ -266,7 +408,7 @@ mod tests {
266
408
267
409
use super :: ring:: AES_256_GCM ;
268
410
use super :: * ;
269
- use std:: io:: { Read , Write } ;
411
+ use std:: io:: Read ;
270
412
271
413
#[ test]
272
414
fn test_it ( ) {
@@ -280,6 +422,6 @@ mod tests {
280
422
let mut ew = EncWriter :: with_buffer_size ( dw, & key, dec_nonce, Aad :: empty ( ) , 100 ) . unwrap ( ) ;
281
423
282
424
std:: io:: copy ( & mut std:: io:: repeat ( 'a' as u8 ) . take ( 2000 ) , & mut ew) . unwrap ( ) ;
283
- ew. flush ( ) . unwrap ( ) ;
425
+ ew. close ( ) . unwrap ( ) ;
284
426
}
285
427
}
0 commit comments