1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 */
25 #include <krypto/extern.h>
26 #include <krypto/reencfile.h>
27 #include <krypto/key.h>
28 #include <krypto/encfile.h>
29 #include <krypto/encfile-priv.h>
30 #include "encfile-priv.h"
31
32 #include <klib/rc.h>
33 #include <klib/checksum.h>
34 #include <klib/log.h>
35 #include <klib/out.h>
36 #include <klib/debug.h>
37 #include <klib/vector.h>
38 #include <klib/status.h>
39 #include <kfs/file.h>
40 #include <kfs/ramfile.h>
41
42 #include <sysalloc.h>
43
44 #include <byteswap.h>
45
46 #include <stdlib.h>
47 #include <string.h>
48 #include <assert.h>
49
50 #include <klib/out.h>
51
52 #define USE_MISSING_VECTOR false
53
54 /* ----------------------------------------------------------------------
55 * KReencFile
56 * Base object class for the encryption, decryption and validation of
57 * the file format defined above
58 */
59 #define KFILE_IMPL KReencFile
60 #include <kfs/impl.h>
61
62 /* -----
63 */
64 struct KReencFile
65 {
66 KFile dad; /* base class */
67 const KFile * encrypted; /* encrypted file we start from */
68 const KFile * dec; /* decryptor of the original */
69 KFile * enc; /* encryptor */
70 KFile * ram; /* a file that works from a sliding window buffer */
71
72 size_t num_read;
73 size_t num_writ;
74 /* block id's can not max out a 64 bit number as that is a file that is 32K times too big */
75 #define NO_CURRENT_BLOCK (~(uint64_t)0)
76 uint64_t block_id;
77 uint64_t footer_block; /* if zero, file does not have any content blocks */
78
79 uint64_t size; /* size as known from the original file [see known_size] */
80 bool known_size; /* is the size of the original file known? */
81
82 char plain_text [ENC_DATA_BLOCK_SIZE];
83 union
84 {
85 KEncFileBlock block;
86 char text [sizeof (KEncFileBlock)];
87 } block;
88 union
89 {
90 KEncFileFooter foot;
91 char text [sizeof (KEncFileFooter)];
92 } foot;
93
94 };
95
96 /* ----------------------------------------------------------------------
97 * Interface Functions
98 *
99 * Destroy
100 *
101 */
102 static
KReencFileDestroy(KReencFile * self)103 rc_t CC KReencFileDestroy (KReencFile *self)
104 {
105 if (self)
106 {
107 rc_t rc1, rc2, rc3, rc4;
108
109 rc1 = KFileRelease (self->encrypted);
110 if (rc1)
111 LOGERR (klogInt, rc1, "Re-enc failed to release encrypted file");
112
113 rc2 = KFileRelease (self->dec);
114 if (rc2)
115 LOGERR (klogInt, rc2, "Re-enc failed to release decryptor");
116
117 rc3 = KFileRelease (self->ram);
118 if (rc3)
119 LOGERR (klogInt, rc3, "Re-enc failed to release ram file");
120
121 rc4 = KFileRelease (self->enc);
122 if (rc4)
123 LOGERR (klogInt, rc4, "Re-enc failed to release encryptor");
124
125 free (self);
126
127 return (rc1 ? rc1 :
128 rc2 ? rc2 :
129 rc3 ? rc3 :
130 rc4);
131 }
132 return 0;
133 }
134
135
136 /* ----------------------------------------------------------------------
137 * GetSysFile
138 * returns an underlying system file object
139 * and starting offset to contiguous region
140 * suitable for memory mapping, or NULL if
141 * no such file is available.
142 *
143 * We do not allow this for read, write or update as you can not memory map the
144 * unencrypted file in a meaningful way.
145 */
146 static
KReencFileGetSysFileUnsupported(const KReencFile * self,uint64_t * offset)147 struct KSysFile *CC KReencFileGetSysFileUnsupported (const KReencFile *self, uint64_t *offset)
148 {
149 assert (self);
150 assert (offset);
151
152 return NULL;
153 }
154
155
156 /* ----------------------------------------------------------------------
157 * RandomAccess
158 *
159 * returns 0 if random access, error code otherwise
160 */
161 static
KReencFileRandomAccess(const KReencFile * self)162 rc_t CC KReencFileRandomAccess (const KReencFile *self)
163 {
164 assert (self != NULL);
165 assert (self->encrypted != NULL);
166
167 return KFileRandomAccess (self->encrypted);
168 }
169
170
171 /* ----------------------------------------------------------------------
172 * Size
173 * returns size in bytes of file
174 *
175 * "size" [ OUT ] - return parameter for file size
176 */
177 static
KReencFileSize(const KReencFile * self,uint64_t * size)178 rc_t CC KReencFileSize (const KReencFile *self, uint64_t *size)
179 {
180 assert (self != NULL);
181 assert (self->encrypted != NULL);
182
183 /* -----
184 * the re-encrypted file will be the same size as the
185 * previously encrypted file and we have the same understanding
186 * about knowing the size
187 */
188 return KFileSize (self->encrypted, size);
189 }
190
191
192 static
KEncryptFileSize(const KReencFile * self,uint64_t * size)193 rc_t CC KEncryptFileSize (const KReencFile *self, uint64_t *size)
194 {
195 uint64_t z;
196 rc_t rc;
197
198 assert (self != NULL);
199 assert (self->encrypted != NULL);
200
201 /* -----
202 * the re-encrypted file will be the same size as the
203 * previously encrypted file and we have the same understanding
204 * about knowing the size
205 */
206 rc = KFileSize (self->encrypted, &z);
207
208 if (rc == 0)
209 {
210 uint64_t bid = PlaintextSize_to_BlockCount ( z, NULL );
211 *size = BlockId_to_CiphertextOffset ( bid ) + sizeof ( KEncFileFooter );
212 }
213 else
214 {
215 *size = z;
216 }
217 return rc;
218 }
219
220
221 /* ----------------------------------------------------------------------
222 * SetSize
223 * sets size in bytes of file
224 *
225 * "size" [ IN ] - new file size
226 */
227 static
KReencFileSetSizeUnsupported(KReencFile * self,uint64_t size)228 rc_t CC KReencFileSetSizeUnsupported (KReencFile *self, uint64_t size)
229 {
230 assert (self);
231
232 return RC ( rcFS, rcFile, rcUpdating, rcFunction, rcUnsupported );
233 }
234
235
236 /*
237 * The next three functions do the actual Out from a KFileRead.
238 * We will only out from the header, or a footer or a single
239 * encrypted block rather than try to fully satisfy all of a
240 * KFileRead. USe KFileReadAll to get more than one part
241 *
242 * For all we have an offset within the part which is the
243 * position from the original read request for the header
244 */
245 static __inline__
KReencFileReadHeaderOut(KReencFile * self,size_t offset,void * buffer,size_t bsize,size_t * num_read)246 rc_t KReencFileReadHeaderOut (KReencFile * self, size_t offset, void * buffer,
247 size_t bsize, size_t *num_read)
248 {
249 assert (self);
250 assert (offset < sizeof (KEncFileHeader));
251 assert (buffer);
252 assert (bsize);
253 assert (num_read);
254
255 /* trim request if necessary */
256 if (offset + bsize > sizeof (KEncFileHeader))
257 bsize = sizeof (KEncFileHeader) - offset;
258
259 memmove (buffer, self->block.text + offset, bsize);
260 self->block_id = NO_CURRENT_BLOCK;
261 *num_read = bsize;
262
263 return 0;
264 }
265
266
267 static __inline__
KReencFileReadBlockOut(KReencFile * self,size_t offset,void * buffer,size_t bsize,size_t * num_read)268 rc_t KReencFileReadBlockOut (KReencFile * self, size_t offset, void * buffer,
269 size_t bsize, size_t * num_read)
270 {
271 assert (self);
272 assert (offset < sizeof self->block);
273 assert (buffer);
274 assert (bsize);
275 assert (num_read);
276
277 if (offset + bsize > sizeof self->block)
278 bsize = sizeof self->block - offset;
279
280 memmove (buffer, self->block.text + offset, bsize);
281 *num_read = bsize;
282
283 return 0;
284 }
285
286
287 static __inline__
KReencFileReadFooterOut(KReencFile * self,size_t offset,void * buffer,size_t bsize,size_t * num_read)288 rc_t KReencFileReadFooterOut (KReencFile * self, size_t offset,
289 void * buffer, size_t bsize, size_t * num_read)
290 {
291 /* for the footer we will copy out from the footer in self */
292
293 assert (self);
294 assert (offset < sizeof self->foot);
295 assert (buffer);
296 assert (bsize);
297 assert (num_read);
298
299 /* KOutMsg ("%s: offset '%zu' bsize '%zu'",__func__,offset,bsize); */
300 if (offset + bsize > sizeof self->foot)
301 bsize = sizeof self->foot - offset;
302
303 memmove (buffer, self->foot.text + offset, bsize);
304 self->block_id = NO_CURRENT_BLOCK;
305 *num_read = bsize;
306
307 /* KOutMsg (" *num_read '%zu'\n",bsize); */
308 /* { */
309 /* size_t ix; */
310 /* char * b = buffer; */
311 /* KOutMsg ("%s:",__func__); */
312 /* for (ix = 0; ix < bsize; ++ix) */
313 /* KOutMsg (" %2.2x",b[ix]); */
314 /* KOutMsg ("\n"); */
315
316 /* } */
317 return 0;
318 }
319
320
321 /*
322 * Handle Read within the Encrypted file header
323 *
324 * We use a private interface into the KEncFile then
325 * the Out function below to take what we write with
326 * the Encryptor and copy it to the callers read buffer.
327 */
328 static
329 rc_t KReencFileReadHandleBlock (KReencFile *self,
330 uint64_t pos,
331 void *buffer,
332 size_t bsize,
333 size_t *num_read);
334
335 static __inline__
KReencFileReadHandleHeader(KReencFile * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)336 rc_t KReencFileReadHandleHeader (KReencFile *self,
337 uint64_t pos,
338 void *buffer,
339 size_t bsize,
340 size_t *num_read)
341 {
342 rc_t rc;
343
344 assert (self);
345 assert (pos < sizeof (KEncFileHeader));
346 assert (buffer);
347 assert (bsize);
348 assert (num_read);
349
350 if ( !self->known_size || self->size != sizeof(KEncFileHeader) + sizeof(KEncFileFooter) )
351 {
352 /* added to support NCBInenc and NCBIsenc variants of KEncFile
353 * read the first block of the source file but don't write any of it
354 *
355 * If the source is stream mode only then the next block to be read is the
356 * first and this will not violate by seeking. It will just have already
357 * read the block it will want to read real soon. Likewith within a
358 * single call to KFileReadAll.
359 */
360 rc = KReencFileReadHandleBlock (self, 0, NULL, 0, NULL);
361 if (rc)
362 return rc;
363 }
364
365 /* use a private function from KEncFile to generate a header */
366 rc = KEncFileWriteHeader (self->enc);
367 if (rc)
368 LOGERR (klogErr, rc, "re-enc error generating encrypted header");
369 else
370 {
371 /*
372 * assume it worked and its the right size
373 * copy the requested portion of the header out to finish the read
374 */
375 rc = KReencFileReadHeaderOut (self, pos, buffer, bsize, num_read);
376 if (rc)
377 LOGERR (klogErr, rc, "re-enc error filling read request");
378 }
379 return rc;
380 }
381
382
383 /*
384 * Read the requested block form the source encrypted file
385 */
386 static
KReencFileReadABlock(KReencFile * self,uint64_t block_id)387 rc_t KReencFileReadABlock (KReencFile * self, uint64_t block_id)
388 {
389 rc_t rc;
390
391
392 /* OUTMSG (("%s: block_id %lu\n",__func__,block_id)); */
393
394 if (block_id + 1 == self->footer_block)
395 memset (self->plain_text, 0, sizeof self->plain_text);
396
397 /* -----
398 * simple call down to the decryptor to get the plain text data
399 * for this block. We will regenerate the framing when we re-encrypt
400 */
401 rc = KFileReadAll (self->dec, BlockId_to_PlaintextOffset ( block_id ),
402 &self->plain_text, sizeof (self->plain_text),
403 &self->num_read);
404 if (rc)
405 LOGERR (klogErr, rc, "re-enc error reading a block");
406
407 /*
408 * interpret bytes read for validity
409 *
410 * zero means we hit a premature end of file where we expected a block
411 */
412 else if (self->num_read == 0)
413 {
414 /*misleading RC? */
415 rc = RC (rcKrypto, rcFile, rcReading, rcSize, rcInsufficient);
416 LOGERR (klogErr, rc, "re-enc no block read");
417 }
418 /*
419 * less than a full block must be in the last block
420 */
421 else if (self->num_read < sizeof self->plain_text)
422 {
423 /* KOutMsg ("%s: block_id '%lu'num_read '%zu' of '%zu' last_block '%lu'\n", */
424 /* __func__, block_id, self->num_read, sizeof self->plain_text, */
425 /* self->footer_block); */
426
427 if (block_id + 1 != self->footer_block)
428 {
429 rc = RC (rcKrypto, rcFile, rcReading, rcSize, rcInsufficient);
430 LOGERR (klogErr, rc, "re-enc incomplete block read");
431 }
432 }
433 /*
434 * unlikely scenario, read too much
435 */
436 else if (self->num_read > sizeof self->plain_text)
437 {
438 rc = RC (rcKrypto, rcFile, rcReading, rcBuffer, rcIncorrect);
439 LOGERR (klogErr, rc, "re-enc no block read");
440 }
441 if (rc == 0)
442 self->block_id = block_id;
443 return rc;
444 }
445
446
447 static
KReencFileWriteABlock(KReencFile * self,uint64_t block_id)448 rc_t KReencFileWriteABlock (KReencFile * self, uint64_t block_id)
449 {
450 rc_t rc;
451
452 /* -----
453 * simple call to encrypt an entire data section for the relevant block
454 * We send in up to 32KB of plain text which through two element KFiles will
455 * we written into a buffer back in this KFile. More data will be written
456 * to that buffer than requested here - that is the framing and also the
457 * header if the block is the first one.
458 */
459 rc = KFileWriteAll (self->enc, BlockId_to_PlaintextOffset ( block_id ),
460 self->plain_text, self->num_read, &self->num_writ);
461
462 if (rc)
463 LOGERR (klogInt, rc, "re-enc error encrypting a block");
464
465 else if (self->num_writ != self->num_read)
466 {
467 rc = RC (rcKrypto, rcFile, rcWriting, rcFile, rcIncomplete);
468 LOGERR (klogErr, rc, "re-enc failure encrypting all of block");
469 }
470
471 /* trigger a flush */
472 /* if (rc == 0) */
473 /* rc = KFileWriteAll (self->enc, BlockId_to_DecryptedPos (block_id^1), */
474 /* self->plain_text, self->num_read, &self->num_writ); */
475
476 return rc;
477 }
478
479
480 /*
481 * Add the current encrypted block to the footer statistics
482 */
483 static __inline__
KReencFileAddToFooter(KReencFile * self)484 rc_t KReencFileAddToFooter (KReencFile * self)
485 {
486 assert (self);
487 /* KOutMsg ("%s: ",__func__); */
488
489 if (self->block.block.crc != self->block.block.crc_copy)
490 {
491 rc_t rc = RC (rcKrypto, rcFile, rcReading, rcChecksum, rcInvalid);
492 LOGERR (klogInt, rc, "rc-enc block CRCs disagree");
493 return rc;
494 }
495
496 ++ self->foot.foot.block_count;
497 self->foot.foot.crc_checksum += self->block.block.crc;
498
499 /* KOutMsg ("%lu %lu %lu\n",self->foot.foot.block_count,self->block.block.crc,self->foot.foot.crc_checksum); */
500 return 0;
501 }
502
503
504 /*
505 * Read a block from the source encrypted block and Write it which reencrypts it
506 *
507 * The new_block parameter says whether this is the first time we've seen this
508 * block. If it is we need to add data to the footer
509 */
510 static
KReencFileReencBlock(KReencFile * self,uint64_t block_id,bool new_block)511 rc_t KReencFileReencBlock (KReencFile * self, uint64_t block_id, bool new_block)
512 {
513 rc_t rc;
514
515 assert (self);
516
517 /* KOutMsg ("%s: %lu %lu\n", __func__, block_id, self->footer_block); */
518 assert (block_id <= self->footer_block);
519 assert ((new_block == true) || (new_block == false));
520
521 rc = KReencFileReadABlock (self, block_id);
522 if (rc)
523 LOGERR (klogErr, rc, "re-enc failure to read a block");
524 else
525 {
526 if ((self->num_read == 0) || (self->num_read > sizeof (self->plain_text)))
527 {
528 rc = RC (rcFS, rcFile, rcReading, rcSize, rcIncorrect);
529 LOGERR (klogErr, rc, "Bad length on block read of encrypted file");
530 }
531 else
532 {
533 rc = KReencFileWriteABlock (self, block_id);
534 if (rc)
535 LOGERR (klogErr, rc, "re-enc failure to write a block");
536
537 else if (new_block)
538 {
539 rc = KReencFileAddToFooter (self);
540 if (rc)
541 LOGERR (klogErr, rc,
542 "re-enc failure to do block accounting");
543 }
544 }
545 }
546 return rc;
547 }
548
549
550 /*
551 * Handle Read within the Encrypted file footer
552 */
553 static __inline__
KReencFileReadHandleFooter(KReencFile * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)554 rc_t KReencFileReadHandleFooter (KReencFile *self,
555 uint64_t pos,
556 void *buffer,
557 size_t bsize,
558 size_t *num_read)
559 {
560 uint64_t block_id; /* block id for the footer gets us the start of footer */
561 size_t offset;
562 rc_t rc;
563
564 /* KOutMsg ("\n\n\n%s: pos '%lu' bsize '%zu'\n",__func__,pos,bsize); */
565
566 assert (self);
567 assert (pos >= sizeof (KEncFileHeader));
568 assert (buffer);
569 assert (bsize);
570 assert (num_read);
571
572 rc = 0;
573 block_id = EncryptedPos_to_BlockId (pos, NULL, NULL);
574
575 assert (block_id == self->footer_block);
576
577 offset = pos - BlockId_to_CiphertextOffset ( block_id );
578
579 assert (offset < sizeof self->foot);
580
581 /* if we are tying to treat this as a footer but it wasn't the next
582 * expected block mark all inbetween as missing to handle in the
583 * function just below this
584 */
585
586 /* KOutMsg ("%s: self->next_block %lu\n",__func__, self->next_block); */
587
588 self->foot.foot.block_count = block_id;
589 self->foot.foot.crc_checksum = 0;
590
591 if (rc == 0)
592 {
593 uint64_t header_pos;
594
595 header_pos = BlockId_to_CiphertextOffset ( block_id );
596
597 assert (header_pos <= pos);
598 assert (pos - header_pos <= sizeof self->foot);
599
600 rc = KReencFileReadFooterOut (self, (size_t)(pos - header_pos),
601 buffer, bsize, num_read);
602
603 /* KOutMsg ("%s: footer '%lu' '%lx'\n",__func__, */
604 /* self->foot.foot.block_count, */
605 /* self->foot.foot.crc_checksum); */
606
607 if (rc)
608 LOGERR (klogInt, rc, "re-enc failed to output footer");
609 }
610 return rc;
611 }
612
613
614 /*
615 *
616 */
617 static
KReencFileReadHandleBlock(KReencFile * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)618 rc_t KReencFileReadHandleBlock (KReencFile *self,
619 uint64_t pos,
620 void *buffer,
621 size_t bsize,
622 size_t *num_read)
623 {
624 rc_t rc = 0; /* we have a path where we need to check this without set */
625 uint64_t block_id; /* block id for the requeted position */
626 uint32_t offset; /* how far into the encrypted block */
627 bool new_block; /* is this the first time for this block */
628
629 /* -----
630 * figure out what block this corresponds to.
631 * the header is for this purpose part of the first block
632 * when we decide what to give the reader. We only care
633 * about which block and not whether it is in the payload
634 * or framing.
635 * This block id is not to a known to exist block. It could be
636 * to the header, the footer or past the end of the file.
637 *
638 * NOTE: This could be a pre-fetch of the first block when
639 * processing the header - it will have some funny values
640 * with just a self and all other parameters 0s.
641 * pos of zero gives block_id of 0 and the bsize of zero
642 * means we never look at the others. Thi sis to allow the
643 * (at the time this was written) new feature of two
644 * different file-signatures for encrypted files.
645 */
646 block_id = EncryptedPos_to_BlockId (pos, NULL, NULL);
647
648 if (block_id != self->block_id)
649 {
650 new_block = true;
651
652 if (rc == 0)
653 {
654 /* read requested block */
655 rc = KReencFileReencBlock (self, block_id, new_block);
656 if (rc)
657 {
658 LOGERR (klogErr, rc,
659 "re-enc failure re-encryptinng a requested block");
660 }
661 }
662 }
663 if ((rc == 0) && (bsize > 0))
664 {
665 /* satisfy read request
666 *
667 * if we are here we decrypted and re-encrypted the
668 * expected block
669 */
670 offset = ( uint32_t ) ( pos - BlockId_to_CiphertextOffset ( block_id ) );
671 rc = KReencFileReadBlockOut (self, offset, buffer, bsize, num_read);
672 if (rc)
673 LOGERR (klogErr, rc, "re-enc error copying out from block");
674 }
675 return rc;
676 }
677
678
679 /* ----------------------------------------------------------------------
680 * Read
681 * read file from known position
682 *
683 * "pos" [ IN ] - starting position within file
684 *
685 * "buffer" [ OUT ] and "bsize" [ IN ] - return buffer for read
686 *
687 * "num_read" [ OUT, NULL OKAY ] - optional return parameter
688 * giving number of bytes actually read
689 */
690 #if 0
691 static
692 rc_t CC KReencFileReadUnsupported (const KReencFile *self,
693 uint64_t pos,
694 void *buffer,
695 size_t bsize,
696 size_t *num_read)
697 {
698 assert (self);
699 assert (buffer);
700 assert (bsize);
701 assert (num_read);
702
703 return RC ( rcFS, rcFile, rcReading, rcFunction, rcUnsupported );
704 }
705 #endif
706
707 /*
708 * Read will often return only a partial read.
709 *
710 * We take the less complex route here and return only from the header, a
711 * single block or the footer, whatever is at the beginning of the requested
712 * region.
713 */
714 static
KReencFileRead(const KReencFile * self_,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)715 rc_t CC KReencFileRead (const KReencFile *self_,
716 uint64_t pos,
717 void *buffer,
718 size_t bsize,
719 size_t *num_read)
720 {
721 /* make it all mutable and stop using self_ */
722 KReencFile * self = (KReencFile *)self_;
723 rc_t rc = 0;
724
725 assert (self);
726 assert (buffer);
727 assert (bsize);
728 assert (num_read);
729
730 *num_read = 0;
731
732 /* -----
733 * the size of the re-encrypted file will be the same as the size of the
734 * previously encrypted file so we can bail early if we know we can.
735 *
736 * The initial use case is that the file will just be lying out on disk
737 * and a KSysfile so that we do know the size.
738 *
739 * There are three pieces to an encrypted file:
740 * 1 Header
741 * 2 One or More Blocks
742 * 3 Footer
743 *
744 * We will only know if we are in the footer if we already know the size of
745 * the file. Else we have to find the footer by not finding a block when we
746 * try to read it. We'll thus look for the header first, then the footer else
747 * we try to find a block,
748 */
749
750 /* Header */
751 if (pos < sizeof (KEncFileHeader))
752 rc = KReencFileReadHandleHeader (self, pos, buffer, bsize, num_read);
753
754 /* if past the whole encrypted file */
755 else if (pos >= self->size)
756 rc = 0;
757
758 /* Footer */
759 else if (pos >= self->size - sizeof self->foot)
760 rc = KReencFileReadHandleFooter (self, pos, buffer, bsize, num_read);
761
762 /* Blocks */
763 else
764 rc = KReencFileReadHandleBlock (self, pos, buffer, bsize, num_read);
765
766 return rc;
767 }
768
769
770 /* ----------------------------------------------------------------------
771 * Write
772 * write file at known position
773 *
774 * "pos" [ IN ] - starting position within file
775 * "buffer" [ IN ] and "size" [ IN ] - data to be written
776 *
777 * "num_writ" [ OUT, NULL OKAY ] - optional return parameter
778 * giving number of bytes actually written
779 *
780 * Unsupported as we now treat archives as READ ONLY
781 */
782 static
KReencFileWriteUnsupported(KReencFile * self,uint64_t pos,const void * buffer,size_t bsize,size_t * num_writ)783 rc_t CC KReencFileWriteUnsupported (KReencFile *self, uint64_t pos,
784 const void *buffer, size_t bsize,
785 size_t *num_writ)
786 {
787 rc_t rc = RC (rcFS, rcFile, rcReading, rcFunction, rcUnsupported);
788
789 assert (self);
790 assert (buffer);
791 assert (bsize);
792 assert (num_writ);
793
794 assert (false);
795
796 LOGERR (klogInt, rc, "KFileRead failed to filter call");
797
798 return rc;
799 }
800
801 #if 0
802 static
803 rc_t CC KReencFileWrite (KReencFile *self, uint64_t pos,
804 const void *buffer, size_t bsize,
805 size_t *num_writ)
806 {
807 assert (self);
808 assert (buffer);
809 assert (bsize);
810 assert (num_writ);
811
812 assert (REENCFILE_WRITE_SUPPORTED);
813
814 /* this needs to be finished before we can support Write open */
815
816 return KReencFileWriteUnsupported (self, pos, buffer, bsize, num_writ);
817 }
818 #endif
819
820
821 /* ----------------------------------------------------------------------
822 * Type
823 * returns a KFileDesc
824 * not intended to be a content type,
825 * but rather an implementation class
826 */
827 static
KReencFileType(const KReencFile * self)828 uint32_t CC KReencFileType (const KReencFile *self)
829 {
830 assert (self != NULL);
831 assert (self->encrypted != NULL);
832
833 return KFileType (self->encrypted);
834 }
835
836
837 /* ----------------------------------------------------------------------
838 * KReencFileMake
839 * create a new file object
840 */
841
842
843 /* ----------
844 * MakeParamValidate
845 * common parameter validation for both reencryptors
846 */
847 static
KReencFileMakeParamValidate(const KFile ** pself,const KFile * encrypted,const KKey * deckey,const KKey * enckey)848 rc_t KReencFileMakeParamValidate (const KFile ** pself, const KFile * encrypted,
849 const KKey * deckey, const KKey * enckey)
850 {
851 rc_t rc = 0;
852
853 do
854 {
855 if (pself == NULL)
856 {
857 rc = RC (rcFS, rcFile, rcConstructing, rcSelf, rcNull);
858 LOGERR (klogErr, rc,
859 "pointer to self NULL when creating "
860 "a re-encryptor");
861 break;
862 }
863
864 *pself = NULL;
865
866 if (encrypted == NULL)
867 {
868 rc = RC (rcFS, rcFile, rcConstructing, rcParam, rcNull);
869 LOGERR (klogErr, rc,
870 "encrypted file not supplied when creating "
871 "an encryptor/decryptor");
872 break;
873 }
874
875 if ((enckey == NULL) || (deckey == NULL))
876 {
877 rc = RC (rcFS, rcFile, rcConstructing, rcParam, rcNull);
878 LOGERR (klogErr, rc,
879 "key not supplied when creating a re-encryptor");
880 break;
881 }
882
883 switch (deckey->type)
884 {
885 default:
886 rc = RC (rcFS, rcFile, rcConstructing, rcParam, rcInvalid);
887 PLOGERR (klogErr,
888 (klogErr, rc, "invalid key type '$(T)' should be "
889 "kkeyAES128(1), kkeyAES192(2) or kkeyAES256(3)",
890 "T=%u", deckey->type));
891 break;
892
893 case kkeyAES128:
894 case kkeyAES192:
895 case kkeyAES256:
896 break;
897 }
898 switch (enckey->type)
899 {
900 default:
901 rc = RC (rcFS, rcFile, rcConstructing, rcParam, rcInvalid);
902 PLOGERR (klogErr,
903 (klogErr, rc, "invalid key type '$(T)' should be "
904 "kkeyAES128(1), kkeyAES192(2) or kkeyAES256(3)",
905 "T=%u", enckey->type));
906 break;
907
908 case kkeyAES128:
909 case kkeyAES192:
910 case kkeyAES256:
911 break;
912 }
913 } while (0);
914 return rc;
915 }
916
917
918 /* ----------
919 * Read mode is fully seekable if the underlying KFile is seekable some
920 * integrity checking will not be performed in allowing this seeking.
921 */
922 static const KFile_vt_v1 vtKReencFileRead =
923 {
924 /* version */
925 1, 1,
926
927 /* 1.0 */
928 KReencFileDestroy,
929 KReencFileGetSysFileUnsupported,
930 KReencFileRandomAccess,
931 KReencFileSize,
932 KReencFileSetSizeUnsupported,
933 KReencFileRead,
934 KReencFileWriteUnsupported,
935
936 /* 1.1 */
937 KReencFileType
938 };
939
940
KReencFileMakeRead(const KFile ** pself,const KFile * encrypted,const KKey * deckey,const KKey * enckey)941 LIB_EXPORT rc_t CC KReencFileMakeRead (const KFile ** pself,
942 const KFile * encrypted,
943 const KKey * deckey,
944 const KKey * enckey)
945 {
946 KReencFile * self;
947 uint64_t size;
948 uint64_t block_count;
949 rc_t rc;
950
951 rc = KReencFileMakeParamValidate (pself, encrypted, deckey, enckey);
952 if (rc)
953 {
954 LOGERR (klogErr, rc, "error constructing decryptor");
955 return rc;
956 }
957
958 rc = KFileSize (encrypted, &size);
959 if (GetRCState (rc) == rcUnsupported)
960 {
961 size = 0;
962 rc = RC (rcKrypto, rcFile, rcConstructing, rcSize, rcUnsupported);
963 LOGERR (klogErr, rc, "Can't re-encrypt files that don't support KFileSize");
964 return rc;
965 }
966
967 if (rc)
968 {
969 LOGERR (klogErr, rc, "Unable to attempt to size encrypted file for reencryption");
970 return rc;
971 }
972
973 rc = KFileAddRef (encrypted);
974 if (rc)
975 {
976 LOGERR (klogErr, rc, "Unable to add reference to encrypted file for re-encryptor");
977 return rc;
978 }
979
980 if (size == 0)
981 {
982 *pself = encrypted;
983 return rc;
984 }
985 if (size < sizeof (KEncFileHeader) + sizeof (KEncFileFooter))
986 {
987 rc = RC (rcKrypto, rcFile, rcConstructing, rcSize, rcInvalid);
988 LOGERR (klogErr, rc, "encrypted file too short to be valied for re-encryption");
989 KFileRelease (encrypted);
990 return rc;
991 }
992
993 {
994 uint64_t temp;
995
996 temp = size - (sizeof (KEncFileHeader) + sizeof (KEncFileFooter));
997 block_count = temp / sizeof (KEncFileBlock);
998 if ((block_count * sizeof (KEncFileBlock)) != temp)
999 {
1000 rc = RC (rcKrypto, rcFile, rcConstructing, rcSize, rcInvalid);
1001 LOGERR (klogErr, rc, "encrypted file invalid size for re-encryption");
1002 KFileRelease (encrypted);
1003 return rc;
1004 }
1005 }
1006
1007 self = calloc (1,sizeof (*self));
1008
1009 if (self == NULL)
1010 {
1011 rc = RC (rcFS, rcFile, rcConstructing, rcMemory, rcExhausted);
1012 LOGERR (klogSys, rc,
1013 "out of memory creating encrypter and/or decryptor");
1014 }
1015 else
1016 {
1017 rc = KFileInit (&self->dad, (const KFile_vt*)&vtKReencFileRead, "KReencFile", "no-name", true, false);
1018 if (rc)
1019 LOGERR (klogInt, rc, "failed in initialize reenc base class");
1020 else
1021 {
1022 self->encrypted = encrypted;
1023 /* dec, enc, ram need to be Make */
1024 /* num_read, num_write stay 0 */
1025 self->block_id = NO_CURRENT_BLOCK;
1026 /* missing needs to be Made */
1027 /* next_block stays 0 */
1028 /* seek_block stays 0 - obsolete */
1029 self->footer_block = EncryptedPos_to_BlockId (size, NULL, NULL);
1030 self->size = size;
1031 self->known_size = true; /* obsolete */
1032 /* plain_text and block stay 0 */
1033 self->foot.foot.block_count = self->footer_block;
1034
1035 rc = KEncFileMakeRead (&self->dec, encrypted, deckey);
1036 if (rc)
1037 LOGERR (klogErr, rc, "Failed to create re-enc decryptor");
1038
1039 else
1040 {
1041 rc = KRamFileMakeUpdate (&self->ram, self->block.text,
1042 sizeof self->block.text);
1043 if (rc)
1044 LOGERR (klogErr, rc,
1045 "Failed to create re-enc encryptor");
1046 else
1047 {
1048
1049 rc = KEncFileMakeWriteBlock (&self->enc, self->ram, enckey);
1050 if (rc)
1051 LOGERR (klogErr, rc,
1052 "Failed to create RAM file for reenc");
1053 else
1054 {
1055 *pself = &self->dad;
1056 return 0;
1057 }
1058 KFileRelease (self->ram);
1059 }
1060 KFileRelease (self->dec);
1061 }
1062 }
1063 free (self);
1064 }
1065 KFileRelease (encrypted);
1066 return rc;
1067 }
1068
1069
1070 static const KFile_vt_v1 vtKEncryptFileRead =
1071 {
1072 /* version */
1073 1, 1,
1074
1075 /* 1.0 */
1076 KReencFileDestroy,
1077 KReencFileGetSysFileUnsupported,
1078 KReencFileRandomAccess,
1079 KEncryptFileSize,
1080 KReencFileSetSizeUnsupported,
1081 KReencFileRead,
1082 KReencFileWriteUnsupported,
1083
1084 /* 1.1 */
1085 KReencFileType
1086 };
1087
1088
KEncryptFileMakeRead(const KFile ** pself,const KFile * encrypted,const KKey * enckey)1089 LIB_EXPORT rc_t CC KEncryptFileMakeRead (const KFile ** pself,
1090 const KFile * encrypted,
1091 const KKey * enckey)
1092 {
1093 KReencFile * self;
1094 uint64_t rawsize;
1095 uint64_t size;
1096 rc_t rc;
1097
1098 rc = KReencFileMakeParamValidate (pself, encrypted, enckey, enckey);
1099 if (rc)
1100 {
1101 LOGERR (klogErr, rc, "error constructing decryptor");
1102 return rc;
1103 }
1104
1105 rc = KFileSize (encrypted, &rawsize);
1106 if (GetRCState (rc) == rcUnsupported)
1107 {
1108 size = 0;
1109 rc = RC (rcKrypto, rcFile, rcConstructing, rcSize, rcUnsupported);
1110 LOGERR (klogErr, rc, "Can't encrypt files that don't support KFileSize");
1111 return rc;
1112 }
1113
1114 if (rc)
1115 {
1116 LOGERR (klogErr, rc, "Unable to attempt to size encrypted file for encryption");
1117 return rc;
1118 }
1119
1120 rc = KFileAddRef (encrypted);
1121 if (rc)
1122 {
1123 LOGERR (klogErr, rc, "Unable to add reference to unencrypted file for encryptor");
1124 return rc;
1125 }
1126
1127 self = calloc (1,sizeof (*self));
1128
1129 if (self == NULL)
1130 {
1131 rc = RC (rcFS, rcFile, rcConstructing, rcMemory, rcExhausted);
1132 LOGERR (klogSys, rc,
1133 "out of memory creating encrypter and/or decryptor");
1134 }
1135 else
1136 {
1137 rc = KFileInit (&self->dad, (const KFile_vt*)&vtKEncryptFileRead, "KEncryptFile", "no-path", true, false);
1138 if (rc)
1139 LOGERR (klogInt, rc, "failed in initialize reenc base class");
1140 else
1141 {
1142 self->encrypted = encrypted;
1143 /* dec, enc, ram need to be made below */
1144 /* num_read, num_write stay 0 */
1145 self->block_id = NO_CURRENT_BLOCK;
1146 /* missing needs to be Made */
1147 /* next_block stays 0 */
1148 /* seek_block stays 0 - obsolete */
1149
1150 self->footer_block = PlaintextSize_to_BlockCount ( rawsize, NULL );
1151 size = BlockId_to_CiphertextOffset ( self -> footer_block ) + sizeof ( KEncFileFooter );
1152 self->size = size;
1153 self->known_size = true; /* obsolete */
1154
1155 /* plain_text and block stay 0 */
1156 self->foot.foot.block_count = self->footer_block;
1157
1158 rc = KFileAddRef (self->dec = encrypted);
1159 if (rc)
1160 LOGERR (klogErr, rc, "Unable to add reference to unencrypted file for encryptor");
1161
1162 else
1163 {
1164 rc = KRamFileMakeUpdate (&self->ram, self->block.text,
1165 sizeof self->block.text);
1166 if (rc)
1167 LOGERR (klogErr, rc,
1168 "Failed to create ram file for encryptor");
1169 else
1170 {
1171
1172 rc = KEncFileMakeWriteBlock (&self->enc, self->ram, enckey);
1173 if (rc)
1174 LOGERR (klogErr, rc,
1175 "Failed to create RAM file for enc");
1176 else
1177 {
1178 *pself = &self->dad;
1179 return 0;
1180 }
1181 KFileRelease (self->ram);
1182 }
1183 KFileRelease (self->dec);
1184 }
1185 }
1186 free (self);
1187 }
1188 KFileRelease (encrypted);
1189 return rc;
1190 }
1191
1192
1193 /* ----------
1194 * Write mode re-encrypted file
1195 */
1196 #if 0
1197 static const KFile_vt_v1 vtKReencFileWrite =
1198 {
1199 /* version */
1200 1, 1,
1201
1202 /* 1.0 */
1203 KReencFileDestroy,
1204 KReencFileGetSysFileUnsupported,
1205 KReencFileRandomAccess,
1206 KReencFileSize,
1207 KReencFileSetSizeUnsupported,
1208 KReencFileReadUnsupported,
1209 KReencFileWrite,
1210
1211 /* 1.1 */
1212 KReencFileType
1213 };
1214 #endif
1215
KReencFileMakeWrite(KFile ** pself,KFile * encrypted,const KKey * deckey,const KKey * enckey)1216 LIB_EXPORT rc_t CC KReencFileMakeWrite (KFile ** pself,
1217 KFile * encrypted,
1218 const KKey * deckey,
1219 const KKey * enckey)
1220 {
1221 #if REENCFILE_WRITE_SUPPORTED
1222 KReencFile * self;
1223 rc_t rc;
1224
1225 rc = KFileSetSize (encrypted, 0);
1226 #if 0
1227 if (rc)
1228 LOGERR (klogWarn, rc, "error truncating output file - "
1229 "corrupted file might result");
1230 #endif
1231
1232 rc = KReencFileMakeParamValidate (&self, encrypted, deckey, enckey,
1233 &vtKEncFileWrite, true);
1234 if (rc)
1235 LOGERR (klogErr, rc, "error creating encryptor");
1236 else
1237 *pself = &self->dad;
1238 return rc;
1239 #else
1240 return RC ( rcFS, rcFile, rcCreating, rcFunction, rcUnsupported );
1241 #endif
1242 }
1243
1244
1245 /* end of file reencfile.c */
1246
1247
1248