forked from zbackup/zbackup
-
Notifications
You must be signed in to change notification settings - Fork 0
/
encrypted_file.hh
137 lines (113 loc) · 5.11 KB
/
encrypted_file.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright (c) 2012-2014 Konstantin Isakov <[email protected]> and ZBackup contributors, see CONTRIBUTORS
// Part of ZBackup. Licensed under GNU GPLv2 or later + OpenSSL, see LICENSE
#ifndef ENCRYPTED_FILE_HH_INCLUDED
#define ENCRYPTED_FILE_HH_INCLUDED
#include <google/protobuf/io/zero_copy_stream.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
#include <exception>
#include <vector>
#include "adler32.hh"
#include "encryption.hh"
#include "encryption_key.hh"
#include "ex.hh"
#include "unbuffered_file.hh"
/// Google's ZeroCopyStream implementations which read and write files encrypted
/// with our encryption mechanism. They also calculate adler32 of all file
/// content and write/check it at the end.
/// Encryption-wise we implement AES-128 in CBC mode with PKCS#7 padding. We
/// don't use EVP for this currently - everyone is welcome to change this, and
/// to add support for arbitrary ciphers, key lengths and modes of operations as
/// well. When no encryption key is set, no encryption or padding is done, but
/// everything else works the same way otherwise
namespace EncryptedFile {
DEF_EX( Ex, "Encrypted file exception", std::exception )
DEF_EX( exFileCorrupted, "encrypted file data is currupted", Ex )
DEF_EX( exIncorrectFileSize, "size of the encrypted file is incorrect", exFileCorrupted )
DEF_EX( exReadFailed, "read failed", Ex ) // Only thrown by InputStream::read()
DEF_EX( exAdlerMismatch, "adler32 mismatch", Ex )
class InputStream: public google::protobuf::io::ZeroCopyInputStream
{
public:
/// Opens the input file. If EncryptionKey contains no key, the input won't be
/// decrypted and iv would be ignored
InputStream( char const * fileName, EncryptionKey const &, void const * iv );
virtual bool Next( void const ** data, int * size );
virtual void BackUp( int count );
virtual bool Skip( int count );
virtual int64_t ByteCount() const;
/// Returns adler32 of all data read so far. Calling this makes backing up
/// for the previous Next() call impossible - the data has to be consumed
Adler32::Value getAdler32();
/// Performs a traditional read, for convenience purposes
void read( void * buf, size_t size );
/// Reads an adler32 value from the stream and compares with checkAdler32().
/// Throws an exception on mismatch
void checkAdler32();
/// Reads and discards the number of bytes equivalent to an IV size. This is
/// used when no IV is initially provided.
/// If there's no encryption key set, does nothing
void consumeRandomIv();
/// Closes the file
~InputStream() {}
private:
UnbufferedFile file;
UnbufferedFile::Offset filePos;
EncryptionKey const & key;
char iv[ Encryption::IvSize ];
std::vector< char > buffer;
char * start; /// Points to the start of the data currently held in buffer
size_t fill; /// Number of bytes held in buffer
size_t remainder; /// Number of bytes held in buffer just after the main
/// 'fill'-bytes portion. We have to keep those to implement
/// PKCS#7 padding
bool backedUp; /// True if the BackUp operation was performed, and the buffer
/// contents are therefore unconsumed
Adler32 adler32;
/// Decrypts 'fill' bytes at 'start', adjusting 'fill' and setting 'remainder'
void decrypt();
/// Only used by decrypt()
void doDecrypt();
};
class OutputStream: public google::protobuf::io::ZeroCopyOutputStream
{
public:
/// Creates the output file. If EncryptionKey contains no key, the output
/// won't be encrypted and iv would be ignored
OutputStream( char const * fileName, EncryptionKey const &, void const * iv );
virtual bool Next( void ** data, int * size );
virtual void BackUp( int count );
virtual int64_t ByteCount() const;
/// Returns adler32 of all data written so far. Calling this makes backing up
/// for the previous Next() call impossible - the data has to be consumed
Adler32::Value getAdler32();
/// Performs a traditional write, for convenience purposes
void write( void const * buf, size_t size );
/// Writes the current adler32 value returned by getAdler32() to the stream
void writeAdler32();
/// Writes the number of random bytes equivalent to an IV size. This is used
/// when no IV is initially provided, and provides an equivalent of having
/// a random IV when used just after the stream has been opened.
/// If there's no encryption key set, does nothing
void writeRandomIv();
/// Finishes writing and closes the file
~OutputStream();
private:
UnbufferedFile file;
UnbufferedFile::Offset filePos;
EncryptionKey const & key;
char iv[ Encryption::IvSize ];
std::vector< char > buffer;
char * start; /// Points to the start of the area currently available for
/// writing to in buffer
size_t avail; /// Number of bytes available for writing to in buffer
bool backedUp; /// True if the BackUp operation was performed, and the buffer
/// contents are therefore unconsumed
Adler32 adler32;
/// Encrypts and writes 'bytes' bytes from the beginning of the buffer.
/// 'bytes' must be non-zero and in multiples of BlockSize
void encryptAndWrite( size_t bytes );
};
}
#endif