1 // Copyright (c) 2012-2014 Konstantin Isakov <ikm@zbackup.org> and ZBackup contributors, see CONTRIBUTORS
2 // Part of ZBackup. Licensed under GNU GPLv2 or later + OpenSSL, see LICENSE
3
4 #include <string.h>
5 #include <algorithm>
6
7 #include "check.hh"
8 #include "encrypted_file.hh"
9 #include "endian.hh"
10 #include "page_size.hh"
11 #include "random.hh"
12
13 namespace EncryptedFile {
14
15 using Encryption::BlockSize;
16
InputStream(char const * fileName,EncryptionKey const & key,void const * iv_)17 InputStream::InputStream( char const * fileName, EncryptionKey const & key,
18 void const * iv_ ):
19 file( fileName, UnbufferedFile::ReadOnly ), filePos( 0 ), key( key ),
20 // Our buffer must be larger than BlockSize, as otherwise we won't be able
21 // to handle PKCS#7 padding properly
22 buffer( std::max( getPageSize(), ( unsigned ) BlockSize * 2 ) ),
23 fill( 0 ), remainder( 0 ), backedUp( false )
24 {
25 if ( key.hasKey() )
26 {
27 memcpy( iv, iv_, sizeof( iv ) );
28 // Since we use padding, file size should be evenly dividable by the cipher
29 // block size, and we should have at least one block
30 UnbufferedFile::Offset size = file.size();
31 if ( !size || size % BlockSize )
32 throw exIncorrectFileSize();
33 }
34 }
35
Next(void const ** data,int * size)36 bool InputStream::Next( void const ** data, int * size )
37 {
38 // If we backed up, return the unconsumed data
39 if ( backedUp )
40 backedUp = false;
41 else
42 {
43 try
44 {
45 // Update adler32 for the previous block
46 adler32.add( start, fill );
47
48 // Read more data
49 if ( filePos && !remainder )
50 {
51 // Once we're read a full block, we always have a remainder. If not,
52 // this means we've hit the end of file already
53 fill = 0;
54 return false;
55 }
56
57 // If we have a remainder, move it to the beginning of buffer and make
58 // it start the next block
59 memmove( buffer.data(), start + fill, remainder );
60 start = buffer.data();
61 fill = file.read( start + remainder, buffer.size() - remainder ) +
62 remainder;
63 // remainder should techically be 0 now, but decrypt() will update it
64 // anyway
65 // remainder = 0;
66 decrypt();
67 }
68 catch( UnbufferedFile::exReadError & )
69 {
70 fill = 0; // To make sure state is remaining consistent
71 return false;
72 }
73 }
74 *data = start;
75 *size = fill;
76 filePos += fill;
77 return *size;
78 }
79
BackUp(int count)80 void InputStream::BackUp( int count )
81 {
82 ZBACKUP_CHECK( count >= 0, "count is negative" );
83 if ( !backedUp )
84 {
85 ZBACKUP_CHECK( (size_t) count <= fill, "Backing up too much" );
86 size_t consumed = fill - count;
87 adler32.add( start, consumed );
88 start += consumed;
89 fill = count;
90 filePos -= count;
91 backedUp = fill; // Don't make the next Next() return 0 bytes
92 }
93 else
94 {
95 ZBACKUP_CHECK( count == 0, "backing up after being backed up already" );
96 }
97 }
98
Skip(int count)99 bool InputStream::Skip( int count )
100 {
101 ZBACKUP_CHECK( count >= 0, "count is negative" );
102
103 // We always need to read and decrypt data, as otherwise both the state of
104 // CBC and adler32 would be incorrect
105 void const * data;
106 int size;
107 while( count )
108 {
109 if ( !Next( &data, &size ) )
110 return false;
111 else
112 if ( size > count )
113 {
114 BackUp( size - count );
115 break;
116 }
117 else
118 count -= size;
119 }
120 return true;
121 }
122
ByteCount() const123 int64_t InputStream::ByteCount() const
124 {
125 return filePos;
126 }
127
getAdler32()128 Adler32::Value InputStream::getAdler32()
129 {
130 // This makes all data consumed, if not already
131 BackUp( 0 );
132 return adler32.result();
133 }
134
read(void * buf,size_t size)135 void InputStream::read( void * buf, size_t size )
136 {
137 void const * data;
138 int avail;
139 char * n = ( char * ) buf;
140 while( size )
141 {
142 if ( !Next( &data, &avail ) )
143 throw exReadFailed();
144 else
145 if ( avail > ( ssize_t ) size )
146 {
147 memcpy( n, data, size );
148 BackUp( avail - size );
149 break;
150 }
151 else
152 {
153 memcpy( n, data, avail );
154 n += avail;
155 size -= avail;
156 }
157 }
158 }
159
checkAdler32()160 void InputStream::checkAdler32()
161 {
162 Adler32::Value ours = getAdler32();
163 Adler32::Value r;
164 read( &r, sizeof( r ) );
165 if ( ours != fromLittleEndian( r ) )
166 throw exAdlerMismatch();
167 }
168
consumeRandomIv()169 void InputStream::consumeRandomIv()
170 {
171 if ( key.hasKey() )
172 {
173 char iv[ Encryption::IvSize ];
174 read( iv, sizeof( iv ) ); // read() can throw exceptions, Skip() can't
175 }
176 }
177
decrypt()178 void InputStream::decrypt()
179 {
180 if ( fill == buffer.size() )
181 {
182 // When we have the full buffer, we set the last block of it aside and
183 // treat the rest as the normal CBC sequence. The last block in the buffer
184 // may be the last block of file, in which case we would need to handle
185 // padding. That may happen the next time the function is called
186 remainder = BlockSize;
187 fill -= BlockSize;
188 doDecrypt();
189 }
190 else
191 {
192 // This is an end of file. Decrypt data treating the last block being
193 // padded
194
195 // Since we always have padding in the file and the last block is always
196 // set apart when reading full buffers, we must have at least one block
197 // to decrypt here
198 doDecrypt();
199
200 // Unpad the last block
201 if ( key.hasKey() )
202 fill -= BlockSize - Encryption::unpad( start + fill - BlockSize );
203
204 // We have not left any remainder this time
205 remainder = 0;
206 }
207 }
208
doDecrypt()209 void InputStream::doDecrypt()
210 {
211 if ( !key.hasKey() )
212 return;
213
214 // Since we use padding, file size should be evenly dividable by the cipher's
215 // block size, and we should always have at least one block. When we get here,
216 // we would always get the proper fill value unless those characteristics are
217 // not met. We check for the same condition on construction, but the file
218 // size can change while we are reading it
219
220 // We don't throw an exception here as the interface we implement doesn't
221 // support them
222 ZBACKUP_CHECK( fill > 0 && !( fill % BlockSize ), "incorrect size of the encrypted "
223 "file - must be non-zero and in multiples of %u",
224 ( unsigned ) BlockSize );
225
226 // Copy the next iv prior to decrypting the data in place, as it will
227 // not be available afterwards
228 char newIv[ Encryption::IvSize ];
229 memcpy( newIv, Encryption::getNextDecryptionIv( start, fill ),
230 sizeof( newIv ) );
231 // Decrypt the data
232 Encryption::decrypt( iv, key.getKey(), start, start, fill );
233 // Copy the new iv
234 memcpy( iv, newIv, sizeof( iv ) );
235 }
236
OutputStream(char const * fileName,EncryptionKey const & key,void const * iv_)237 OutputStream::OutputStream( char const * fileName, EncryptionKey const & key,
238 void const * iv_ ):
239 file( fileName, UnbufferedFile::WriteOnly ), filePos( 0 ), key( key ),
240 buffer( getPageSize() ), start( buffer.data() ), avail( 0 ), backedUp( false )
241 {
242 if ( key.hasKey() )
243 memcpy( iv, iv_, sizeof( iv ) );
244 }
245
Next(void ** data,int * size)246 bool OutputStream::Next( void ** data, int * size )
247 {
248 // If we backed up, return the unconsumed data
249 if ( backedUp )
250 backedUp = false;
251 else
252 {
253 try
254 {
255 // Update adler32 for the previous block
256 adler32.add( start, avail );
257
258 // Encrypt and write the buffer if it had data
259 if ( filePos )
260 encryptAndWrite( buffer.size() );
261
262 start = buffer.data();
263 avail = buffer.size();
264 }
265 catch( UnbufferedFile::exWriteError & )
266 {
267 avail = 0; // To make sure state is remaining consistent
268 return false;
269 }
270 }
271 *data = start;
272 *size = avail;
273 filePos += avail;
274 return *size;
275 }
276
BackUp(int count)277 void OutputStream::BackUp( int count )
278 {
279 ZBACKUP_CHECK( count >= 0, "count is negative" );
280 if ( !backedUp )
281 {
282 ZBACKUP_CHECK( (size_t) count <= avail, "Backing up too much" );
283 size_t consumed = avail - count;
284 adler32.add( start, consumed );
285 start += consumed;
286 avail = count;
287 filePos -= count;
288 backedUp = avail; // Don't make the next Next() return 0 bytes
289 }
290 else
291 {
292 ZBACKUP_CHECK( count == 0, "backing up after being backed up already" );
293 }
294 }
295
ByteCount() const296 int64_t OutputStream::ByteCount() const
297 {
298 return filePos;
299 }
300
getAdler32()301 Adler32::Value OutputStream::getAdler32()
302 {
303 // This makes all data consumed, if not already
304 BackUp( 0 );
305 return adler32.result();
306 }
307
write(void const * buf,size_t size)308 void OutputStream::write( void const * buf, size_t size )
309 {
310 void * data;
311 int avail;
312 char const * n = ( char const * ) buf;
313 while( size )
314 {
315 if ( !Next( &data, &avail ) )
316 throw exReadFailed();
317 else
318 if ( avail > ( ssize_t ) size )
319 {
320 memcpy( data, n, size );
321 BackUp( avail - size );
322 break;
323 }
324 else
325 {
326 memcpy( data, n, avail );
327 n += avail;
328 size -= avail;
329 }
330 }
331 }
332
writeAdler32()333 void OutputStream::writeAdler32()
334 {
335 Adler32::Value v = toLittleEndian( getAdler32() );
336 write( &v, sizeof( v ) );
337 }
338
writeRandomIv()339 void OutputStream::writeRandomIv()
340 {
341 if ( key.hasKey() )
342 {
343 char iv[ Encryption::IvSize ];
344 Random::genaratePseudo( iv, sizeof( iv ) );
345 write( iv, sizeof( iv ) );
346 }
347 }
348
encryptAndWrite(size_t bytes)349 void OutputStream::encryptAndWrite( size_t bytes )
350 {
351 if ( key.hasKey() )
352 {
353 ZBACKUP_CHECK( bytes > 0 && !( bytes % BlockSize ), "incorrect number of bytes to "
354 "encrypt and write - must be non-zero and in multiples of %u",
355 ( unsigned ) BlockSize );
356
357 void const * nextIv = Encryption::encrypt( iv, key.getKey(), buffer.data(),
358 buffer.data(), bytes );
359 memcpy( iv, nextIv, sizeof( iv ) );
360 }
361
362 file.write( buffer.data(), bytes );
363 }
364
~OutputStream()365 OutputStream::~OutputStream()
366 {
367 // This makes all data consumed, if not already
368 BackUp( 0 );
369
370 // If we have the full buffer, write it first
371 if ( start == buffer.data() + buffer.size() )
372 {
373 encryptAndWrite( buffer.size() );
374 start = buffer.data();
375 }
376
377 size_t bytesToWrite = start - buffer.data();
378
379 if ( key.hasKey() )
380 {
381 // Perform padding
382 size_t remainderSize = bytesToWrite % BlockSize;
383
384 Encryption::pad( start - remainderSize, remainderSize );
385 bytesToWrite += BlockSize - remainderSize;
386 }
387
388 encryptAndWrite( bytesToWrite );
389 }
390
391 }
392