1 /*
2 * rsyncrypto - an rsync friendly encryption
3 * Copyright (C) 2005-2008 Shachar Shemesh for Lingnu Open Source Consulting ltd.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * In addition, as a special exception, the rsyncrypto authors give permission
20 * to link the code of this program with the OpenSSL library (or with modified
21 * versions of OpenSSL that use the same license as OpenSSL), and distribute
22 * linked combinations including the two. You must obey the GNU General Public
23 * License in all respects for all of the code used other than OpenSSL. If you
24 * modify this file, you may extend this exception to your version of the file,
25 * but you are not obligated to do so. If you do not wish to do so, delete this
26 * exception statement from your version.
27 *
28 * The project's homepage is at http://rsyncrypto.lingnu.com/
29 */
30
31 #include <precomp.h>
32 #include "rsyncrypto.h"
33 #include "crypto.h"
34 #include "process.h"
35 #include "autopipe.h"
36 #include "redir.h"
37
38 /* Cyclic add and subtract */
39 #define MOD_ADD(a,b,mod) (((a)+(b))%(mod))
40 #define MOD_SUB(a,b,mod) MOD_ADD((a), (mod)-(b), (mod))
41
42 #define VERSION_MAGIC_1 0xD657EA1Cul
43
44 /* Public/Private key handling */
extract_public_key(const char * pem_filename)45 RSA *extract_public_key( const char *pem_filename )
46 {
47 BIO *in;
48 X509 *x509;
49 EVP_PKEY *pkey;
50 RSA *rsa=NULL;
51
52 /* We pull the public key out of the certificate. It's much like pulling teeth */
53 /* First, get the certificate loaded into a stream */
54 in=BIO_new(BIO_s_file()); /* NULL is error */
55 if( in==NULL )
56 throw rscerror( "Error allocating public key", ENOMEM );
57
58 if( BIO_read_filename(in, pem_filename)<=0 ) /* <=0 is error */
59 throw rscerror( "Error reading public key file", errno, pem_filename );
60
61 /* Next, extract the X509 certificate from it */
62 x509=PEM_read_bio_X509(in, NULL, NULL, NULL );
63 if( x509==NULL )
64 throw rscerror( "Error parsing certificate" );
65
66 /* And the public key in generic format */
67 pkey=X509_get_pubkey(x509);
68 /* And finally, we get the actual RSA key */
69 rsa=EVP_PKEY_get1_RSA(pkey);
70 /* Lastly, release all the resources we've allocated */
71 X509_free(x509);
72 EVP_PKEY_free(pkey);
73 BIO_free_all(in);
74
75 return rsa;
76 }
77
extract_private_key(const char * key_filename)78 RSA *extract_private_key( const char *key_filename )
79 {
80 BIO *in;
81 RSA *rsa=NULL;
82
83 /* We pull the public key out of the certificate. It's much like pulling teeth */
84 /* First, get the certificate loaded into a stream */
85 in=BIO_new(BIO_s_file()); /* NULL is error */
86 if( in==NULL )
87 throw rscerror( "Error allocating private key" );
88 if( BIO_read_filename(in, key_filename)<=0 ) /* <=0 is error */
89 throw rscerror( "Error reading private key file", errno, key_filename );
90
91 /* And finally, we get the actual RSA key */
92 rsa=PEM_read_bio_RSAPrivateKey(in,NULL,NULL,NULL);
93 /* Lastly, release all the resources we've allocated */
94 BIO_free_all(in);
95
96 return rsa;
97 }
98
read_header(const autofd & headfd)99 std::unique_ptr<key> read_header( const autofd &headfd )
100 {
101 autommap headmap( headfd, PROT_READ );
102 return key::read_key( headmap.get_uc() );
103 }
104
write_header(const char * filename,const key * head)105 void write_header( const char *filename, const key *head )
106 {
107 autofd::mkpath( std::string(filename, autofd::dirpart(filename)).c_str(), 0700 );
108 autofd newhead(filename, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
109 off_t headsize=head->exported_length();
110
111 if( newhead.lseek( headsize-1, SEEK_SET )!=headsize-1 ||
112 newhead.write( filename, 1 )!=1 )
113 throw rscerror("write failed", errno, filename );
114
115 autommap headfilemap( NULL, static_cast<size_t>(headsize), PROT_WRITE|PROT_READ, MAP_SHARED,
116 newhead, 0 );
117 head->export_key( headfilemap.get() );
118 }
119
120 const uint32_t HEADER_ENCRYPTION_VERSION=0;
121
header_size(const RSA * rsa)122 size_t header_size( const RSA *rsa )
123 {
124 return RSA_size(rsa)+sizeof(HEADER_ENCRYPTION_VERSION);
125 }
126
127 /* Encrypt the file's header */
encrypt_header(const key * header,RSA * rsa,unsigned char * to)128 void encrypt_header( const key *header, RSA *rsa, unsigned char *to )
129 {
130 size_t export_size=header->exported_length();
131
132 *reinterpret_cast<uint32_t *>(to)=htonl(HEADER_ENCRYPTION_VERSION);
133
134 to+=sizeof(HEADER_ENCRYPTION_VERSION);
135
136 header->export_key( to );
137
138 /* Encrypt the whole thing in place */
139 if( RSA_public_encrypt(export_size, to, to, rsa, RSA_PKCS1_OAEP_PADDING)==-1 ) {
140 unsigned long rsaerr=ERR_get_error();
141 throw rscerror(ERR_error_string(rsaerr, NULL));
142 }
143 }
144
145 /* Decrypt the file's header */
decrypt_header(file_t fromfd,RSA * prv)146 std::unique_ptr<key> decrypt_header( file_t fromfd, RSA *prv )
147 {
148 const size_t key_size=RSA_size(prv);
149 size_t headsize=header_size(prv);
150 autommap filemap(NULL, headsize, PROT_READ, MAP_PRIVATE, fromfd, 0);
151
152 if( *static_cast<uint32_t *>(filemap.get())!=htonl(HEADER_ENCRYPTION_VERSION) )
153 throw rscerror("Wrong file or header encrypted with wrong encryption");
154
155 unsigned char *buff=filemap.get_uc()+sizeof(HEADER_ENCRYPTION_VERSION);
156 auto_array<unsigned char> decrypted(new unsigned char[headsize]);
157
158 #if OPENSSL_VERSION_NUMBER < 0x10100000L
159 if( (prv->p==nullptr || prv->q==nullptr) ) {
160 #else
161 const BIGNUM *p, *q;
162 RSA_get0_factors(prv, &p, &q);
163 if( (p==nullptr || q==nullptr) ) {
164 #endif
165 // This is not a private key!
166 throw rscerror("Neither AES session key nor RSA private key present - cannot decrypt using only public key");
167 }
168
169 if( RSA_private_decrypt(key_size, buff, decrypted.get(), prv, RSA_PKCS1_OAEP_PADDING)==-1 ) {
170 unsigned long rsaerr=ERR_get_error();
171 throw rscerror(ERR_error_string(rsaerr, NULL));
172 }
173
174 std::unique_ptr<key> ret(key::read_key( decrypted.get() ));
175
176 // Let's verify that we have read the correct data from the file, by reencoding the key we got and comparing
177 // the cyphertexts.
178 // On second thought - let's not. You never know if we don't change encoding at some future point.
179
180 return ret;
181 }
182
183 // "encrypt_file" will also close the from and to file handles.
184 void encrypt_file( key *header, RSA *rsa, read_bufferfd &fromfd, write_bufferfd &tofd )
185 {
186 const size_t key_size=RSA_size(rsa);
187
188 /* Skip the header. We'll only write it out once the file itself is written */
189 autofd::lseek(tofd, header_size(rsa), SEEK_SET);
190
191 redir_pipe ipipe(8000);
192 redir_fd redir_from(fromfd);
193 process_ctl gzip_process( const_cast<char *>(FILENAME(gzip)), &redir_from, &ipipe, NULL, "--rsyncable", NULL );
194
195 // Run through gzip's output, and encrypt it
196 const size_t block_size=header->block_size(); // Let's cache the block size
197 auto_array<unsigned char> buffer(new unsigned char [block_size]);
198 unsigned int i=0;
199 int numread=1;
200 bool new_block=true;
201
202 read_bufferfd *readfd=new read_bufferfd(ipipe.get_read());
203 while( (numread=readfd->read(buffer.get()+i, 1))!=0 ) {
204 if( new_block ) {
205 header->init_encrypt();
206 new_block=false;
207 }
208
209 new_block=header->calc_boundry( buffer[i] );
210 i+=numread;
211 if( i>=block_size || new_block ) {
212 header->encrypt_block( buffer.get(), i );
213 tofd.write( buffer.get(), block_size );
214
215 i=0;
216 }
217 }
218
219 delete readfd;
220
221 if( i>0 ) {
222 // Still some leftover bytes to encrypt
223 header->encrypt_block( buffer.get(), i );
224 tofd.write( buffer.get(), block_size );
225 }
226
227 // Report how many bytes of last block are relevant.
228 bzero( buffer.get(), block_size );
229 buffer[0]=i;
230 header->init_encrypt();
231 header->encrypt_block( buffer.get(), 1 );
232 tofd.write( buffer.get(), block_size );
233
234 tofd.flush();
235
236 // Wait for gzip to return, and check whether it succeeded
237 int childstatus=gzip_process.wait();
238
239 if( childstatus==0 ) {
240 /* gzip was successful - write out the header, encrypted */
241 autommap buffer( NULL, key_size, PROT_READ|PROT_WRITE, MAP_SHARED, tofd, 0 );
242 encrypt_header( header, rsa, buffer.get_uc() );
243 } else {
244 throw rscerror("Error in running gzip");
245 }
246
247 tofd.clear();
248 }
249
250 // "decrypt_file" will also close the from and to file handles.
251 std::unique_ptr<key> decrypt_file( std::unique_ptr<key> header, RSA *prv, read_bufferfd &fromfd, write_bufferfd &tofd )
252 {
253 if( header==NULL ) {
254 /* Need to reconstruct the header from the encrypted file */
255 header=decrypt_header( fromfd, prv );
256 }
257
258 /* If file does not contain a valid header - abort */
259 if( header==NULL )
260 throw rscerror("Couldn't extract encryption header");
261
262 struct stat filestat;
263 off_t currpos;
264
265 filestat=fromfd.fstat();
266
267 /* Skip the header */
268 currpos=fromfd.lseek(header_size(prv), SEEK_SET);
269
270 redir_pipe opipe;
271 redir_fd redir_to(tofd);
272 process_ctl gzip_process( const_cast<char *>(FILENAME(gzip)), &opipe, &redir_to, NULL, "-d", NULL );
273
274 size_t numread;
275 const size_t block_size=header->block_size();
276 auto_array<unsigned char> buffer(new unsigned char [block_size]);
277 bool done=false;
278 bool new_block=true;
279 write_bufferfd *writefd=new write_bufferfd(opipe.get_write());
280
281 /* Read the file one AES_BLOCK_SIZE at a time, decrypt and write to the pipe */
282 while( !done && (numread=fromfd.read( buffer.get(), block_size))!=0 ) {
283 currpos+=numread;
284 if( numread>0 && numread<block_size )
285 throw rscerror("Unexpected file end");
286
287 if( new_block ) {
288 header->init_encrypt();
289 new_block=false;
290 }
291
292 header->decrypt_block( buffer.get(), block_size );
293
294 unsigned int i;
295 for( i=0; i<block_size && !new_block; ++i ) {
296 new_block=header->calc_boundry(buffer[i]);
297 }
298
299 if( currpos>=filestat.st_size-static_cast<off_t>(block_size) ) {
300 done=true;
301
302 // Oops - file is not a whole multiple of block size
303 if( currpos>filestat.st_size-static_cast<off_t>(block_size) )
304 throw rscerror("Uneven file end");
305 } else {
306 writefd->write( buffer.get(), i );
307 }
308
309 // If this was not a full block, the remaining bytes should be zero
310 for( ; i<block_size; ++i )
311 if( buffer[i]!=0 )
312 throw rscerror("Error in encrypted stream");
313 }
314
315 // The next block will tell us how many bytes of the last block should be written.
316 auto_array<unsigned char> buffer2(new unsigned char [block_size]);
317 if( fromfd.read( buffer2.get(), block_size)!=static_cast<ssize_t>(block_size) )
318 throw rscerror("Unexcpeted end of file past sanity checks");
319
320 header->init_encrypt();
321 header->decrypt_block( buffer2.get(), block_size );
322 for( unsigned int i=1; i<block_size; ++i )
323 if( buffer2[i]!=0 )
324 throw rscerror("Error in encrypted stream (trailer)");
325 if( buffer2[0]>=block_size )
326 throw rscerror("Error in encrypted stream (trailer 2)");
327
328 if( buffer2[0]==0 )
329 buffer2[0]=block_size;
330
331 writefd->write( buffer.get(), buffer2[0] );
332 writefd->flush();
333 delete writefd;
334 opipe.clear();
335
336 int child_status=gzip_process.wait();
337
338 if( child_status!=0 )
339 throw rscerror("gunzip failed to run");
340
341 fromfd.clear();
342
343 return header;
344 }
345