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/encfile.h>
27 #include <krypto/encfile-priv.h>
28 #include "encfile-priv.h"
29 #include <krypto/cipher.h>
30 #include <krypto/ciphermgr.h>
31 #include <krypto/key.h>
32
33 /* #include "aes-priv.h" */
34
35 #include <klib/rc.h>
36 #include <klib/checksum.h>
37 #include <klib/log.h>
38 #include <klib/out.h>
39 #include <klib/debug.h>
40 #include <klib/status.h>
41 /* #include <klib/vector.h> */
42 /* #include <klib/status.h> */
43 #include <kfs/file.h>
44 #include <kfs/sra.h>
45 #include <sysalloc.h>
46
47 #include <byteswap.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <assert.h>
51 /* #include <klib/out.h> */
52
53
54 /* ----------------------------------------------------------------------
55 * KEncFile
56 * Base object class for the encryption, decryption and validation of
57 * the file format defined above
58 */
59
60 #define KFILE_IMPL struct KEncFile
61 #include <kfs/impl.h>
62
63
64 #include "encfile-priv.h"
65
66 typedef struct KEncFileCiphers KEncFileCiphers;
67 struct KEncFileCiphers
68 {
69 KCipher * master;
70 KCipher * block;
71 };
72
73
74 typedef struct KEncFileIVec { uint8_t ivec [16]; } KEncFileIVec;
75
76 /* -----
77 */
78 struct KEncFile
79 {
80 KFile dad; /* base class */
81 KFile * encrypted; /* encrypted file as a KFile */
82 KEncFileCiphers ciphers; /* file and block ciphers */
83 KEncFileBlock block; /* current data block */
84 KEncFileFooter foot; /* contains crc checksum and block count */
85 uint64_t dec_size; /* size of decrypted file */
86 uint64_t enc_size; /* size of encrypted file */
87 bool dirty; /* data written but not flushed set in Write cleared in Flush*/
88 bool seekable; /* we can seek within the encrypted file */
89 bool size_known; /* can we know the size? Only streaming read can not know */
90 bool bswap; /* file created on system of opposite endianess */
91 bool changed; /* some write has happened cleared in Make, set in BufferWrite */
92 bool sought; /* did a seek on a read or write invalidating crc checksum */
93 bool has_header; /* have we read or written a header? */
94 bool eof;
95 bool sra; /* we know we are encrypting an SRA/KAR archive file */
96 bool swarm; /* block mode for swarm mode using KReencFile or KEncryptFile */
97 KEncFileVersion version; /* version from the header if read; or the one being written */
98 };
99
100
101 /* ----------
102 * BufferCalcMD5
103 * Generate the MD5 digest for a buffer
104 */
105 static __inline__
BufferCalcMD5(const void * buffer,size_t size,uint8_t digest[16])106 void BufferCalcMD5 (const void * buffer, size_t size, uint8_t digest [16])
107 {
108 MD5State state;
109
110 assert (buffer);
111 assert (size);
112 assert (digest);
113
114 MD5StateInit (&state);
115 MD5StateAppend (&state, buffer, size);
116 MD5StateFinish (&state, digest);
117 }
118
119
120 /* -----
121 * return true or false as to whether the the buffer described is all 0 bits
122 */
123 static __inline__
BufferAllZero(const void * buffer_,size_t size)124 bool BufferAllZero (const void * buffer_, size_t size)
125 {
126 const uint8_t * buffer;
127 size_t count;
128 bool ret;
129
130 assert (buffer_);
131
132 buffer = buffer_;
133 ret = true;
134
135 for (count = 0; count < size; ++count)
136 {
137 if (buffer[count] != '\0')
138 {
139 ret = false;
140 break;
141 }
142 }
143 return ret;
144 }
145
146 /* Compensate that KFileReadAll became non-blocking.
147 Keep calling KFileReadAll until buffer fills up
148 to satisfy caller's expectations */
KFile_ReadAllBlocking(const KFile * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)149 static rc_t KFile_ReadAllBlocking(const KFile *self, uint64_t pos,
150 void *buffer, size_t bsize, size_t *num_read)
151 {
152 size_t count = 0;
153 rc_t rc = KFileReadAll(self, pos, buffer, bsize, &count);
154 size_t total = count;
155
156 if (rc == 0 && count != 0 && count < bsize) {
157 uint8_t *b = buffer;
158 for (b = buffer; total < bsize; total += count) {
159 count = 0;
160 rc = KFileReadAll(self, pos + total, b + total, bsize - total,
161 &count);
162 if (rc != 0 || count == 0)
163 break;
164 }
165 }
166
167 if (total != 0) {
168 *num_read = total;
169 return 0;
170 }
171
172 return rc;
173 }
174
175 /* ----------
176 * BufferRead
177 * Read from an encrypted file and update size if warranted
178 *
179 * Read's aren't guaranteed to get full amount
180 */
181 static
KEncFileBufferRead(KEncFile * self,uint64_t offset,void * buffer,size_t bsize,size_t * num_read)182 rc_t KEncFileBufferRead (KEncFile * self, uint64_t offset, void * buffer,
183 size_t bsize, size_t * num_read)
184 {
185 rc_t rc;
186
187 assert (self);
188 assert (self->encrypted);
189 assert (buffer);
190 assert (bsize > 0);
191 assert (num_read);
192
193 rc = KFile_ReadAllBlocking (self->encrypted, offset, buffer, bsize,
194 num_read);
195 if (rc == 0)
196 {
197 if (self->enc_size < offset + *num_read)
198 {
199 self->enc_size = offset + *num_read;
200 }
201 }
202 /* leave logging to callers? */
203 else
204 PLOGERR (klogErr, (klogErr, rc, "Error reading from encrypted file "
205 "at '$(P)", "P=%lu", offset));
206
207 return rc;
208 }
209
210
211 /* ----------
212 * BufferWrite
213 * write to an encrypted file, mark it as changed and update size if warranted
214 */
215 static
KEncFileBufferWrite(KEncFile * self,uint64_t offset,const void * buffer,size_t bsize,size_t * num_writ)216 rc_t KEncFileBufferWrite (KEncFile * self, uint64_t offset, const void * buffer,
217 size_t bsize, size_t * num_writ)
218 {
219 rc_t rc = 0;
220
221 assert (self);
222 assert (self->encrypted);
223 assert (buffer);
224 assert (bsize > 0);
225 assert (num_writ);
226
227 rc = KFileWriteAll (self->encrypted, offset, buffer, bsize, num_writ);
228 if (rc != 0)
229 {
230 /* leave logging to callers? */
231 PLOGERR (klogErr, (klogErr, rc, "Error writing to encrypted file "
232 "at '$(P)", "P=%lu", offset));
233 // make sure we don't crash later in destructor
234 if (self->enc_size > offset + *num_writ)
235 {
236 self->enc_size = offset + *num_writ;
237 }
238 return rc;
239 }
240
241 if (bsize != *num_writ)
242 {
243 /* KOutMsg ("%s: bsize %zu *num_writ %zu\n",__func__, bsize, *num_writ); */
244 rc = RC (rcKrypto, rcFile, rcWriting, rcTransfer, rcIncomplete);
245 /* leave logging to callers? */
246 PLOGERR (klogErr, (klogErr, rc, "Error writing full buffer to"
247 " encrypted file at '$(P) wrote '$(W)'",
248 "P=%lu,W=%zu", offset, *num_writ));
249 }
250 else if (*num_writ > 0)
251 {
252 self->changed = true;
253 if (self->enc_size < offset + *num_writ)
254 {
255 self->enc_size = offset + *num_writ;
256 }
257 }
258 return rc;
259 }
260
261
262 /* ----------------------------------------------------------------------
263 * operations on KEncFileHeader
264 *
265 * The header only needs to be read and validated or written we need not
266 * reatian within the KEncFile object any information about the header in
267 * the initial version of this file format.
268 */
269
270 /* -----
271 * the first eight bytes of the file are two four byte strings
272 * The first is a common "NCBI"
273 * The second is the format specific "nenc"
274 */
275 #if 0
276 static const KEncFileSig KEncFileSignature = "NCBInenc";
277 #endif
278
279 /* -----
280 * the common constant used throughout the project to check the byte order
281 * as written by the system which created the file
282 */
283 /* enum fails to handle these due to integer overflow */
284
285 #define eEncFileByteOrderTag (0x05031988)
286 #define eEncFileByteOrderReverse (0x88190305)
287
288 /* ----
289 */
290 #define eCurrentVersion (0x00000002)
291 #define eCurrentVersionReverse (0x02000000)
292
293
294 static
295 const KEncFileHeader const_header
296 = { "NCBInenc", eEncFileByteOrderTag, eCurrentVersion };
297
298
299 static
300 const KEncFileHeader const_bswap_header
301 = { "NCBInenc", eEncFileByteOrderReverse, eCurrentVersionReverse };
302
303 /* skipping v1 for NCBIkenc */
304 static
305 const KEncFileHeader const_header_sra
306 = { "NCBIsenc", eEncFileByteOrderTag, eCurrentVersion };
307
308
309 #if 0
310 static
311 const KEncFileHeader const_bswap_header_sra
312 = { "NCBIsenc", eEncFileByteOrderReverse, eCurrentVersionReverse };
313 #endif
314
315 /* ----------
316 * HeaderRead
317 * Read the header of an encrypted file and validate it.
318 *
319 * We only allow a missing header for an empty file opened for update
320 */
321 static
KEncFileHeaderRead(KEncFile * self)322 rc_t KEncFileHeaderRead (KEncFile * self)
323 {
324 KEncFileHeader header;
325 size_t num_read;
326 rc_t rc;
327
328 assert (self);
329
330 rc = KEncFileBufferRead (self, 0, &header, sizeof (header), &num_read);
331 if (rc)
332 LOGERR (klogErr, rc, "error reading encrypted file header");
333
334 else if ((num_read == 0) && (self->dad.write_enabled))
335 {
336 /* only allow read to fail with zero length if opened with write */
337 self->version = eCurrentVersion;
338 self->bswap = false;
339 self->enc_size = 0; /* redundant? */
340 self->dec_size = 0; /* redundant? */
341 }
342 else if (num_read != sizeof (header))
343 {
344 rc = RC (rcFS, rcFile, rcConstructing, rcHeader, rcTooShort);
345 PLOGERR (klogErr,
346 (klogErr, rc, "error reading full header of encrypted "
347 "file wanted '$(S)' got '$(N); bytes read", "S=%u,N=%u",
348 sizeof (header), num_read));
349 }
350 else
351 {
352 rc_t orc;
353
354 if (memcmp (header.file_sig, const_header.file_sig,
355 sizeof (header.file_sig)) == 0)
356 self->sra = false;
357 else if (memcmp (header.file_sig, const_header_sra.file_sig,
358 sizeof (header.file_sig)) == 0)
359 self->sra = true;
360 else
361 {
362 rc = RC (rcFS, rcFile, rcConstructing, rcHeader, rcInvalid);
363 LOGERR (klogErr, rc, "file signature not correct for encrypted file");
364 }
365
366 switch (header.byte_order)
367 {
368 case eEncFileByteOrderTag:
369 self->bswap = false;
370 self->version = header.version;
371 break;
372
373 case eEncFileByteOrderReverse:
374 self->bswap = true;
375
376 /* assert for the right bswap call */
377 assert (sizeof (self->version) == 4);
378
379 self->version = bswap_32 (header.version);
380 break;
381
382 default:
383 orc = RC (rcFS, rcFile, rcConstructing, rcByteOrder, rcInvalid);
384 PLOGERR (klogErr, (klogErr, rc, "invalid byte order flag '$(F); in "
385 "encrypted file header", "F=%X",
386 header.byte_order));
387 if (rc == 0)
388 rc = orc;
389 break;
390 }
391
392 if ((self->version > eCurrentVersion) || (self->version == 0))
393 {
394 orc = RC (rcFS, rcFile, rcConstructing, rcHeader, rcBadVersion);
395 PLOGERR (klogErr, (klogErr, orc, "can not decrypt version '$(V)'",
396 "V=%u", header.version));
397 if (rc == 0)
398 rc = orc;
399 }
400 if (rc == 0)
401 self->has_header = true;
402 }
403 return rc;
404 }
405
406
407 /* -----
408 * HeaderWrite
409 */
410 #ifndef SENC_IS_NENC_FOR_WRITER
411 #define SENC_IS_NENC_FOR_WRITER 1
412 #endif
413
414 static
KEncFileHeaderWrite(KEncFile * self)415 rc_t KEncFileHeaderWrite (KEncFile * self)
416 {
417 rc_t rc;
418 size_t num_writ;
419 const KEncFileHeader * head;
420
421 #if SENC_IS_NENC_FOR_WRITER
422 head = self->sra
423 ? (self->bswap ? &const_bswap_header_sra : &const_header_sra)
424 : (self->bswap ? &const_bswap_header : &const_header);
425 #else
426 head = self->bswap ? &const_bswap_header : &const_header;
427 #endif
428
429 rc = KEncFileBufferWrite (self, 0, head, sizeof * head, &num_writ);
430 if (rc)
431 LOGERR (klogErr, rc, "Failed to write encrypted file header");
432
433 else
434 /* forced upgrade by writing the header */
435 self->version = eCurrentVersion;
436
437 if (rc == 0)
438 self->has_header = true;
439
440 return rc;
441 }
442
KEncFileWriteHeader_v2(KFile * self)443 LIB_EXPORT rc_t CC KEncFileWriteHeader_v2 (KFile * self)
444 {
445 if (self == NULL)
446 return RC (rcKrypto, rcFile, rcWriting, rcSelf, rcNull);
447
448 return KEncFileHeaderWrite ((KEncFile*)self);
449 }
450
451
452
453 /* ----------------------------------------------------------------------
454 * operations on KEncFileFooter
455 */
456
457 /* ----------
458 * Validate
459 * we expect to read a Footer when we expect a Block so we validate in RAM
460 * without a Read
461 *
462 * we're just comparing the values in the footer against expected values
463 */
464 static
KEncFileFooterValidate(const KEncFile * self,const uint64_t block_count,const uint64_t crc_checksum)465 rc_t KEncFileFooterValidate (const KEncFile * self,
466 const uint64_t block_count,
467 const uint64_t crc_checksum)
468 {
469 rc_t rc1 = 0, rc2 = 0;
470
471 assert (self);
472
473 if (self->foot.block_count != block_count)
474 {
475 rc1 = RC (rcKrypto, rcFile, rcValidating, rcFile, rcCorrupt);
476 LOGERR (klogErr, rc1, "bad block count in encrypted file footer");
477 }
478 /*
479 * crcs should match or the crc should be 0 and the version is 1
480 */
481 if ((self->foot.crc_checksum != crc_checksum) &&
482 ((self->version == 1) || (crc_checksum != 0)))
483 {
484 rc2 = RC (rcKrypto, rcFile, rcValidating, rcChecksum, rcCorrupt);
485 LOGERR (klogErr, rc2, "bad crc checksum in encrypted file footer");
486 }
487 return (rc1 ? rc1 : rc2);
488 }
489
490
491 static __inline__
KEncFileFooterSwap(const KEncFile * self,KEncFileFooter * foot)492 void KEncFileFooterSwap (const KEncFile * self, KEncFileFooter * foot)
493 {
494 assert (self);
495 assert (foot);
496
497 if (self->bswap)
498 {
499 assert (sizeof (foot->block_count) == 8);
500 foot->block_count = bswap_64 (foot->block_count);
501
502 assert (sizeof (foot->crc_checksum) == 8);
503 foot->crc_checksum = bswap_64 (foot->crc_checksum);
504 }
505 }
506
507
508 /* ----------
509 * Read
510 * If we know where the footer is we can read it specifically
511 */
512 #if 0
513 static
514 rc_t KEncFileFooterRead (KEncFile * self, const uint64_t pos,
515 const bool validate)
516 {
517 union foot_plus
518 {
519 KEncFileFooter foot;
520 uint8_t bytes [sizeof (KEncFileFooter) + 1];
521 } u;
522 size_t num_read;
523 rc_t rc;
524
525 assert ((self->size_known == true) || (self->size_known == false));
526 assert (((self->size_known == true) &&
527 ((pos + sizeof (u.foot)) == self->enc_size)) ||
528 (pos == self->enc_size));
529
530 /* try to read too much just to validate nothing after the footer */
531 rc = KEncFileBufferRead (self, pos, u.bytes, sizeof u.bytes, &num_read);
532 if (rc)
533 PLOGERR (klogErr, (klogErr, rc, "failed to read encrypted file footer "
534 "at '$(P)'", "P=%lu", pos));
535
536 else if (num_read == sizeof u.foot)
537 {
538 KEncFileFooterSwap (self, &u.foot);
539
540 if (validate)
541 rc = KEncFileFooterValidate (self, u.foot.block_count,
542 u.foot.crc_checksum);
543
544 if (rc == 0)
545 {
546 self->foot.block_count = u.foot.block_count;
547 self->foot.crc_checksum = u.foot.crc_checksum;
548 }
549 }
550 else if (num_read < sizeof u.foot)
551 rc = RC (rcKrypto, rcFile, rcReading, rcSize, rcInsufficient);
552
553 else
554 {
555 assert (num_read > sizeof u.foot);
556 rc = RC (rcKrypto, rcFile, rcReading, rcSize, rcExcessive);
557 }
558
559 return rc;
560 }
561 #endif
562
563 /* ----------
564 * Write
565 * when we write a footer we write from the values in the object. They
566 * are stored in the same object format as the footer so its very simple
567 */
568 static
KEncFileFooterWrite(KEncFile * self)569 rc_t KEncFileFooterWrite (KEncFile * self)
570 {
571 KEncFileFooter foot;
572 uint64_t pos;
573 size_t num_writ;
574 rc_t rc;
575
576 if (self->sought)
577 {
578 self -> foot . block_count = foot . block_count =
579 PlaintextSize_to_BlockCount ( self -> dec_size, NULL );
580 foot . crc_checksum = 0;
581 }
582 else
583 {
584 memmove ( & foot, & self -> foot, sizeof foot );
585 }
586
587 KEncFileFooterSwap (self, &foot);
588
589 if (self->sought)
590 foot.crc_checksum = 0;
591
592 pos = BlockId_to_CiphertextOffset ( self -> foot . block_count );
593
594 assert ((self->size_known == true) || (self->size_known == false));
595
596 rc = KEncFileBufferWrite (self, pos, &foot, sizeof (foot),
597 &num_writ);
598 if (rc == 0)
599 {
600 if (num_writ != sizeof (foot))
601 {
602 rc = RC (rcFS, rcFile, rcWriting, rcFile, rcInsufficient);
603 LOGERR (klogErr, rc, "faled to write correctly sized fotter "
604 "for encrypted file");
605 }
606 else
607 assert ((pos + sizeof (foot)) == self->enc_size);
608 }
609 return rc;
610 }
611
612
613 /* ----------
614 * IvecInit
615 * create the ivec for a given block
616 * done in a function to ensure decrypt and encrypt use the same code to
617 * generate this. Anything used to create this has to be available to
618 * code that doesn't know the content of the data or the state of the file
619 * beyond the location of the block with in the file.
620 *
621 * This is definitely over-kill using the MD5.
622 */
623 static __inline__
KEncFileIVecInit(const uint64_t block_id,KEncFileIVec * ivec)624 void KEncFileIVecInit (const uint64_t block_id, KEncFileIVec * ivec)
625 {
626 BufferCalcMD5 (&block_id, sizeof block_id, ivec->ivec);
627 }
628
629
630 /* ----------
631 * BlockEncrypt
632 *
633 * Not thread safe - use of cipher schedules ivec and block key in the ciphers
634 *
635 * If this function were a protected region where only one thread could be in
636 * the body of this function at a time it could be made thread safe.
637 */
638 static
KEncFileBlockEncrypt(KEncFile * self,KEncFileBlock * d,KEncFileBlock * e)639 rc_t KEncFileBlockEncrypt (KEncFile * self, KEncFileBlock * d,
640 KEncFileBlock * e)
641 {
642 SHA256State state;
643 uint64_t id;
644 uint16_t valid;
645 uint16_t saved_valid;
646 KEncFileCRC crc;
647 KEncFileIVec ivec;
648 rc_t rc;
649
650 assert (self);
651 assert (d);
652 assert (e);
653
654 /*
655 * First we finish preparing the two ciphers by creating the block
656 * user key out of the first part of the data and the shared Initialization
657 * vector for Chained Block Cipher mode encryption out of the block id
658 *
659 * create the initialization vector for this block
660 */
661 KEncFileIVecInit (d->id, &ivec);
662
663 /*
664 * set the ivec for both the master and data block ciphers
665 */
666 rc = KCipherSetEncryptIVec (self->ciphers.master, &ivec);
667 if (rc)
668 return rc;
669
670 rc = KCipherSetEncryptIVec (self->ciphers.block, &ivec);
671 if (rc)
672 return rc;
673
674 /*
675 * create the block user key out of the first 4kb of data and the block id
676 */
677 saved_valid = valid = d->u.valid;
678 id = d->id;
679
680 SHA256StateInit (&state);
681 SHA256StateAppend (&state, d->data,
682 valid > 4096 ? 4096 : valid);
683 SHA256StateAppend (&state, &id, sizeof (id));
684 SHA256StateFinish (&state, d->key);
685
686 /*
687 * create the block key schedule out of the block user key
688 */
689 rc = KCipherSetEncryptKey (self->ciphers.block, d->key, sizeof d->key);
690 if (rc)
691 return rc;
692
693 /*
694 * Salt the block using the randomish user key to randomly select
695 * data from the valid data.
696 *
697 * This will cover the data portion of the block past the last valid
698 * byte.
699 *
700 * NOTE we are accessing a byte array as a word array. COuld be trouble
701 * on some archaic processors such as the MC68000 family.
702 *
703 * NOTE we are using the array named data to access data beyond it's end
704 * based on knowledge of the structure of the KEncFileBlock.
705 */
706 {
707 uint16_t * pw;
708 unsigned int windex;
709 unsigned int rindex;
710 size_t bindex;
711
712 pw = (uint16_t*)d->key;
713 windex = 0;
714
715 for (bindex = valid;
716 bindex < sizeof d->data + sizeof d->u;
717 ++ bindex)
718 {
719 /* this goes beyond the end of the data array by design */
720 rindex = (size_t)pw[windex];
721 rindex %= bindex;
722
723 d->data[bindex] = d->data[rindex];
724
725 ++rindex;
726 if (rindex >= sizeof self->block.key / sizeof *pw)
727 rindex = 0;
728 }
729 }
730
731 /*
732 * If we are modifying a block created on a system with a different default
733 * Endian choice we'll need to byte swap the block id and the block valid
734 * count
735 */
736 if (self->bswap)
737 {
738 assert (sizeof id == 8);
739 id = bswap_64 (id);
740
741 assert (sizeof (valid = 2));
742 valid = bswap_16 (valid);
743 }
744
745 /* is this a bswap problem? */
746 if (saved_valid == sizeof d->data)
747 d->u.valid |= valid;
748 else
749 d->u.valid = valid;
750
751 e->id = id;
752
753 /*
754 * encrypt the block user key into the buffer
755 */
756 #if 0
757 {
758 unsigned iii;
759 KOutMsg ("v2 decrypted key %lu\n", d->id);
760 for (iii = 0; iii < sizeof (d->key); +++ iii)
761 KOutMsg ("%2.2x ", d->key[iii]);
762 KOutMsg ("\n");
763 }
764 #endif
765 rc = KCipherEncryptCBC (self->ciphers.master, d->key, e->key,
766 sizeof (d->key) / sizeof (ivec));
767 if (rc)
768 return rc;
769 #if 0
770 {
771 unsigned iii;
772 KOutMsg ("v2 encrypted key\n");
773 for (iii = 0; iii < sizeof (e->key); +++ iii)
774 KOutMsg ("%2.2x ", e->key[iii]);
775 KOutMsg ("\n");
776 }
777 #endif
778 /*
779 * encrypt the data, offset and valid values
780 */
781 rc = KCipherEncryptCBC (self->ciphers.block,
782 d->data, e->data,
783 (sizeof d->data + sizeof d->u) / sizeof (ivec));
784 if (rc)
785 return rc;
786
787 d->u.valid = saved_valid;
788
789 crc = CRC32 (0, e, (char*)(&e->crc)-(char*)e);
790
791 self->block.crc = crc;
792
793 if (self->bswap)
794 {
795 assert (sizeof crc == 4);
796 crc = bswap_32 (crc);
797 }
798 e->crc_copy = e->crc = crc;
799
800 /* KOutMsg ("%s: %lu %lu %lu ", __func__, self->foot.block_count, self->foot.crc_checksum,self->block.id); */
801 if (self->foot.block_count <= self->block.id)
802 self->foot.block_count = self->block.id + 1;
803
804 if (!self->sought)
805 self->foot.crc_checksum += crc;
806
807 /* KOutMsg ("%lu %lu\n", __func__, self->foot.block_count, self->foot.crc_checksum); */
808
809 return 0;
810 }
811
812
813 /* ----------
814 * BlockDecrypt
815 * decrypt decrypts the data from a KEncFileBlock into the KEncFileBlock
816 * in the KEncFile object
817 *
818 * Not thread safe - use of cipher schedules ivec and block key in the ciphers
819 *
820 * If this function were a protected region where only one thread could be in
821 * the body of this function at a time it could be made thread safe.
822 */
823 static
KEncFileBlockDecrypt(KEncFile * self,KEncFileBlockId bid,const KEncFileBlock * e,KEncFileBlock * d)824 rc_t KEncFileBlockDecrypt (KEncFile * self, KEncFileBlockId bid,
825 const KEncFileBlock * e, KEncFileBlock * d)
826 {
827 KEncFileIVec ivec;
828 rc_t rc;
829
830 d->id = e->id;
831
832 /* create the initialization vector for this block */
833 KEncFileIVecInit (bid, &ivec);
834
835 /*
836 * set the ivec for both the master and data block ciphers
837 */
838 rc = KCipherSetDecryptIVec (self->ciphers.master, &ivec);
839 if (rc)
840 return rc;
841
842 rc = KCipherSetDecryptIVec (self->ciphers.block, &ivec);
843 if (rc)
844 return rc;
845
846 /*
847 * decrypt the block key and initial vector using the user key and
848 * the computer ivec
849 */
850 rc = KCipherDecryptCBC (self->ciphers.master, e->key, d->key,
851 (sizeof e->key) / sizeof ivec);
852 if (rc)
853 return rc;
854
855 /*
856 * now create the AES key for the block from the newly decrypted
857 * block key
858 */
859 rc = KCipherSetDecryptKey (self->ciphers.block, d->key,
860 sizeof d->key);
861 if (rc)
862 return rc;
863
864 rc = KCipherDecryptCBC (self->ciphers.block, e->data, d->data,
865 (sizeof e->data + sizeof e->u) / sizeof ivec);
866 if (rc)
867 return rc;
868
869 if (self->bswap)
870 {
871 assert (sizeof d->u.valid == 2);
872 d->u.valid = bswap_16 (d->u.valid);
873 }
874
875 if (d->u.valid >= sizeof d->data)
876 d->u.valid = sizeof d->data;
877 else
878 memset (d->data + d->u.valid, 0, sizeof d->data - d->u.valid);
879
880 return rc;
881 }
882
883
884 /*
885 * if not decrypting block can be NULL
886 */
887
888 /*
889 TBD: figure out rational way to handle bad password making blocks look really weird
890 If we have one that looks like a partial but isn't the last block -what do we do?
891 */
892
893 static
KEncFileBlockRead(KEncFile * self,KEncFileBlock * block,KEncFileBlockId block_id,bool validate)894 rc_t KEncFileBlockRead (KEncFile * self, KEncFileBlock * block,
895 KEncFileBlockId block_id, bool validate)
896 {
897 union
898 {
899 KEncFileBlock b;
900 KEncFileFooter f;
901 } u;
902 size_t num_read;
903 uint64_t epos, dpos;
904 rc_t vrc, rc = 0;
905 bool missing;
906
907 assert (self);
908 assert ((validate == false) || (validate == true));
909 /* we should be decrypting or validating - maybe both */
910 assert ((block != NULL) || (validate == true));
911
912 /* translate block id into both encrypted and decrypted addresses */
913 epos = BlockId_to_CiphertextOffset ( block_id );
914 dpos = BlockId_to_PlaintextOffset ( block_id );
915
916 missing = false;
917
918 /* clear out target block */
919 if (block != NULL)
920 memset (block, 0, sizeof * block);
921
922 rc = KEncFileBufferRead (self, epos, &u.b, sizeof u.b, &num_read);
923 if (rc)
924 {
925 PLOGERR (klogErr, (klogErr, rc, "Failure to read block '$(B)' at '$(E)'"
926 " in encrypted file decrypted at '$(D)",
927 "B=%lu,E=%lu,D=%lu", block_id, epos, dpos));
928 }
929 else
930 {
931 switch (num_read)
932 {
933 case 0:
934 self->eof = true;
935 /* ain't got no block here */
936 break;
937
938 default:
939 /* Invalid size */
940 rc = RC (rcKrypto, rcFile, rcReading, rcBuffer, rcInsufficient);
941 PLOGERR (klogErr, (klogErr, rc, "Failure to read full block '$(B)' "
942 "at '$(E)' in encrypted file decrypted at '$(D)",
943 "B=%lu,E=%lu,D=%lu", block_id, epos, dpos));
944 break;
945
946 case sizeof (u.f):
947 /* footer */
948 if (validate) /* validate before checking as missing */
949 {
950 KEncFileFooterSwap (self, &u.f);
951
952 if (u.f.block_count != block_id)
953 {
954 vrc = RC (rcKrypto, rcFile, rcValidating, rcSize,
955 rcIncorrect);
956 PLOGERR (klogErr, (klogErr, vrc, "read footer block count "
957 "'$(B)' does not match actual block "
958 "count '$(A)'", "B=%lu,A=%lu",
959 u.f.block_count, block_id));
960 if ( rc == 0 )
961 rc = vrc;
962 }
963 vrc = KEncFileFooterValidate (self, u.f.block_count,
964 u.f.crc_checksum);
965
966 #if 1
967 if ( rc == 0 )
968 rc = vrc;
969 #else
970 /* what is the significance of a NULL block? */
971 if (block == NULL)
972 rc = vrc;
973 #endif
974 }
975
976 /* is it a "missing" footer? */
977 /* or if the footer appears invalid - make it "valid" */
978 if (((missing = BufferAllZero(&u.f, sizeof u.f)) == true) ||
979 (self->foot.block_count != block_id))
980 {
981 /* self->foot.block_count = block_id; */
982 self->foot.crc_checksum = 0;
983 }
984
985 /* force some values though they might already be known */
986 self->enc_size = epos + sizeof u.f;
987 self->size_known = true;
988 self->dec_size = dpos;
989 self->eof = true;
990 break;
991
992 case sizeof (u.b):
993 /* block */
994 self->eof = false;
995 /* is it a "missing" block? */
996 if ((missing = BufferAllZero(&u.b, sizeof u.b)) == true)
997 {
998 if (validate)
999 {
1000 vrc = RC (rcKrypto, rcFile, rcValidating,
1001 rcData, rcNull);
1002
1003 PLOGERR (klogErr, (klogErr, vrc, "read missing block at "
1004 "block number '$(I)' encrypted position "
1005 "$(E) decrypted postion $(D)",
1006 "I=%lu,E=%lu,D=%lu", block_id, epos,
1007 dpos));
1008 if ( rc == 0 )
1009 rc = vrc;
1010 }
1011 u.b.id = block_id;
1012 u.b.u.valid = sizeof u.b.data;
1013
1014 /* if we can only learn of the size by reading and are thus scanning
1015 * through the current decrypt position must be the current known
1016 * decrypted side size
1017 */
1018 if (!self->size_known)
1019 {
1020 assert (dpos == self->dec_size);
1021 self->dec_size = dpos + sizeof u.b.data;
1022 }
1023 /*
1024 * if we know the decrypted size and it is less than what we
1025 * read, adjust the valid. BUT this must not be for the block read
1026 * for the last block to know the decrypted size. A chicken and egg
1027 * problem.
1028 */
1029 else if ((self->dec_size >= dpos) &&
1030 (self->dec_size < dpos + sizeof u.b.data))
1031 u.b.u.valid = (uint16_t)(self->dec_size - dpos);
1032 }
1033
1034 /* we read a full block that wasn't all zeroes */
1035 else
1036 {
1037 /* since we've chosen not to standardize the file format byte ordering */
1038 if (self->bswap)
1039 {
1040 assert (sizeof u.b.crc == 4);
1041 u.b.crc = bswap_32 (u.b.crc);
1042 u.b.crc_copy = bswap_32 (u.b.crc_copy);
1043
1044 assert (sizeof u.b.id == 8);
1045 u.b.id = bswap_64 (u.b.id);
1046 }
1047
1048 if (validate)
1049 {
1050 uint32_t crc;
1051
1052 if (block_id != u.b.id)
1053 {
1054 vrc = RC (rcKrypto, rcFile, rcValidating, rcIndex,
1055 rcIncorrect);
1056 PLOGERR (klogErr, (klogErr, vrc, "error validating id "
1057 "for block '$(BID)' is not $(C2)",
1058 "BID=%lu,C2=%lu", block_id, u.b.id));
1059 if ( rc == 0 )
1060 rc = vrc;
1061 }
1062
1063 crc = CRC32 (0, &u.b, (char*)&u.b.crc - (char*)&u.b);
1064
1065 if (crc != u.b.crc)
1066 {
1067 vrc = RC (rcKrypto, rcFile, rcValidating, rcChecksum, rcCorrupt);
1068 PLOGERR (klogErr,
1069 (klogErr,
1070 vrc,
1071 "error validating crc for block '$(BID)' $(C1) is not $(C2)",
1072 "BID=%lu,C1=0x%X,C2=0x%X", block_id,
1073 crc, u.b.crc));
1074 if ( rc == 0 )
1075 rc = vrc;
1076 }
1077 if (crc != u.b.crc_copy)
1078 {
1079 vrc = RC (rcKrypto, rcFile, rcValidating, rcChecksum, rcCorrupt);
1080 PLOGERR (klogErr,
1081 (klogErr,
1082 vrc,
1083 "error validating crc_copy for block '$(BID)' $(C1) is not $(C2)",
1084 "BID=%lu,C1=0x%X,C2=0x%X", block_id,
1085 crc, u.b.crc_copy));
1086 if ( rc == 0 )
1087 rc = vrc;
1088 }
1089 }
1090 }
1091 if (self->sought == false)
1092 {
1093 if (block_id == 0)
1094 {
1095 self->foot.block_count = 1;
1096 self->foot.crc_checksum = u.b.crc;
1097 }
1098 else
1099 {
1100 ++self->foot.block_count;
1101 self->foot.crc_checksum += u.b.crc;
1102 }
1103 }
1104
1105 if (block != NULL)
1106 {
1107 if (missing)
1108 {
1109 if (self->dad.write_enabled == false)
1110 rc = RC (rcKrypto, rcFile, rcReading, rcData, rcIncomplete);
1111 else
1112 {
1113 memmove (block, &u.b, sizeof u.b);
1114 rc = 0;
1115 }
1116 }
1117 else
1118 {
1119 rc = KEncFileBlockDecrypt (self, block_id, &u.b, block);
1120 if (rc == 0)
1121 {
1122 if (block_id == 0)
1123 {
1124 rc_t sra = KFileIsSRA ((const char *)block->data, block->u.valid);
1125 self->sra = (sra == 0);
1126 }
1127
1128 if (!self->size_known)
1129 {
1130 assert (dpos == self->dec_size);
1131 self->dec_size = dpos + sizeof u.b.u.valid;
1132 if (u.b.u.valid != sizeof u.b.data)
1133 {
1134 self->size_known = true;
1135 self->enc_size = epos + sizeof u.b + sizeof self->foot;
1136 }
1137 }
1138 }
1139 }
1140 }
1141 break;
1142 }
1143 }
1144 return rc;
1145 }
1146
1147
1148 /*
1149 * Take a dirty block, encrypt it and write it to the backing file
1150 */
1151 static
KEncFileBlockFlush(KEncFile * self,KEncFileBlock * dec_block)1152 rc_t KEncFileBlockFlush (KEncFile * self, KEncFileBlock * dec_block)
1153 {
1154 rc_t rc = 0;
1155
1156 assert (self);
1157 assert (dec_block);
1158
1159
1160 if (dec_block->id == 0)
1161 {
1162 rc = KFileIsSRA ((const char *)(dec_block->data), sizeof (KSraHeader));
1163
1164 /* we wait ALL the way until we try to flush the first block before we set
1165 * the sra flag for write only files.
1166 * we get it when we read the first block otherwise.
1167 */
1168 if (self->sra != (rc == 0))
1169 {
1170 self->sra = (rc == 0);
1171 self->has_header = false;
1172 }
1173 }
1174 if ((dec_block->id == 0) || (self->seekable))
1175 {
1176 if (!self->has_header)
1177 {
1178 if (!self->swarm)
1179 {
1180 rc = KEncFileHeaderWrite (self);
1181 if (rc)
1182 return rc;
1183 }
1184 else if (dec_block->id == 0)
1185 self->enc_size = sizeof (KEncFileHeader);
1186 }
1187 }
1188
1189 /* if (self->dirty) */
1190 {
1191 KEncFileBlock enc_block;
1192
1193 rc = KEncFileBlockEncrypt (self, dec_block, &enc_block);
1194 if (rc == 0)
1195 {
1196 KEncFileBlockId block_id;
1197 uint64_t pos;
1198 size_t num_writ;
1199
1200 block_id = dec_block->id;
1201
1202 pos = BlockId_to_CiphertextOffset ( block_id );
1203
1204 rc = KEncFileBufferWrite (self, pos, &enc_block, sizeof enc_block,
1205 &num_writ);
1206
1207 if (rc)
1208 PLOGERR (klogErr, (klogErr, rc,
1209 "error writing encrypted block '$(B)'",
1210 "B=%lu", block_id));
1211
1212 else if (num_writ != sizeof enc_block)
1213 {
1214 rc = RC (rcKrypto, rcFile, rcWriting, rcBuffer, rcInsufficient);
1215 PLOGERR (klogErr, (klogErr, rc, "error writing encrypted block "
1216 "'$(B)' wrote '$(Z)' not '$(Y)'",
1217 "B=%lu, Z=%zu", block_id, num_writ,
1218 sizeof enc_block));
1219 }
1220 else
1221 self->dirty = false;
1222 }
1223 }
1224
1225 return rc;
1226 }
1227
1228
1229 /* ----------------------------------------------------------------------
1230 * Interface Functions
1231 *
1232 * Destroy
1233 *
1234 */
1235 static
KEncFileDestroy(KEncFile * self)1236 rc_t CC KEncFileDestroy (KEncFile *self)
1237 {
1238 rc_t rc1 = 0;
1239 rc_t rc2 = 0;
1240 rc_t rc3 = 0;
1241 rc_t rc4 = 0;
1242 rc_t rc5 = 0;
1243 rc_t rc6 = 0;
1244
1245 assert (self);
1246
1247 if (self->dad.write_enabled)
1248 {
1249 /*
1250 * write the header if we've written nothing to an empty file
1251 * or if we've written something which will mean a change to v2
1252 * of the encrypted file format
1253 */
1254 if ((self->dec_size == 0) || (self->seekable && self->changed) ||
1255 ((self->dec_size == 0) && (!self->dad.read_enabled) && self->changed && (self->has_header == false)))
1256 /* SMURF IX
1257 (self->has_header == false))
1258 */
1259 rc1 = KEncFileHeaderWrite (self);
1260
1261 /* write any dirty block */
1262 if (self->dirty)
1263 rc2 = KEncFileBlockFlush (self, &self->block);
1264
1265 /* [re]write footer */
1266 if (self->changed)
1267 rc3 = KEncFileFooterWrite (self);
1268 }
1269 rc4 = KFileRelease (self->encrypted);
1270 rc5 = KCipherRelease (self->ciphers.master);
1271 rc6 = KCipherRelease (self->ciphers.block);
1272
1273 free (self);
1274
1275 if (rc1)
1276 return rc1;
1277 if (rc2)
1278 return rc2;
1279 if (rc3)
1280 return rc3;
1281 if (rc4)
1282 return rc4;
1283 if (rc5)
1284 return rc5;
1285 return rc6;
1286 }
1287
1288
1289 /* ----------------------------------------------------------------------
1290 * GetSysFile
1291 * returns an underlying system file object
1292 * and starting offset to contiguous region
1293 * suitable for memory mapping, or NULL if
1294 * no such file is available.
1295 *
1296 * We do not allow this for read, write or update as you can not memory map the
1297 * unencrypted file in a meaningful way.
1298 */
1299 static
KEncFileGetSysFile(const KEncFile * self,uint64_t * offset)1300 struct KSysFile *CC KEncFileGetSysFile (const KEncFile *self, uint64_t *offset)
1301 {
1302 assert (self);
1303 assert (offset);
1304
1305 return NULL;
1306 }
1307
1308
1309 /* ----------------------------------------------------------------------
1310 * RandomAccess
1311 *
1312 * returns 0 if random access, error code otherwise
1313 */
1314 static
KEncFileRandomAccess(const KEncFile * self)1315 rc_t CC KEncFileRandomAccess (const KEncFile *self)
1316 {
1317 assert (self != NULL);
1318 assert ((self->seekable == true) || (self->seekable == false));
1319
1320 /* we checked for random access in the contructor */
1321 if (self->seekable)
1322 return 0;
1323
1324 return RC (rcFS, rcFile, rcUpdating, rcFunction, rcUnsupported);
1325 }
1326
1327
1328 /* ----------------------------------------------------------------------
1329 * Size
1330 * returns size in bytes of file
1331 *
1332 * "size" [ OUT ] - return parameter for file size
1333 */
1334 static
KEncFileSize(const KEncFile * self,uint64_t * size)1335 rc_t CC KEncFileSize (const KEncFile *self, uint64_t *size)
1336 {
1337 if (!self->size_known)
1338 return RC (rcKrypto, rcFile, rcAccessing, rcSize, rcUnsupported);
1339
1340 *size = self->dec_size;
1341 return 0;
1342 }
1343
1344
1345 /* ----------------------------------------------------------------------
1346 * SetSize
1347 * sets size in bytes of file
1348 *
1349 * "size" [ IN ] - new file size
1350 *
1351 * This is the size of the decrypted payload not of the encrypted file
1352 */
1353 static
KEncFileSetSizeBlockFull(KEncFile * self,uint64_t block_id)1354 rc_t KEncFileSetSizeBlockFull (KEncFile *self, uint64_t block_id)
1355 {
1356 if ((self->block.id == block_id) && (self->block.u.valid != 0))
1357 {
1358 if (self->block.u.valid < sizeof self->block.data)
1359 {
1360 self->block.u.valid = sizeof self->block.data;
1361 self->dirty = true;
1362 }
1363 else
1364 assert (self->block.u.valid == sizeof self->block.data);
1365 }
1366 else
1367 {
1368 KEncFileBlock block;
1369 rc_t rc;
1370
1371 rc = KEncFileBlockRead (self, &block, block_id, false);
1372 if (rc)
1373 return rc;
1374
1375 /* if (self->block.u.valid != sizeof self->block.data) */
1376 /* { */
1377 /* OUTMSG (("%s: %u %u\n", __func__,self->block.u.valid,sizeof self->block.data)); */
1378 /* OUTMSG (("%s: %lu %lu\n", __func__,self->block.id,block_id)); */
1379 /* } */
1380
1381 /* only change block if not "missing" */
1382 if (BufferAllZero (&block, sizeof block) == false)
1383 {
1384 assert (block.id == block_id);
1385
1386 /* only change if not already full - shouldnt get here if not? */
1387 if (block.u.valid < sizeof block.data)
1388 {
1389 self->changed = self->sought = true;
1390 block.u.valid = sizeof block.data;
1391
1392 rc = KEncFileBlockFlush (self, &block);
1393 if (rc)
1394 return rc;
1395 }
1396 else
1397 assert (self->block.u.valid == sizeof self->block.data);
1398 }
1399 }
1400 return 0;
1401 }
1402
1403
1404 static
KEncFileSetSizeBlockPartial(KEncFile * self,uint64_t block_id,uint32_t valid)1405 rc_t KEncFileSetSizeBlockPartial (KEncFile *self, uint64_t block_id, uint32_t valid)
1406 {
1407 if ((self->block.id == block_id) && (self->block.u.valid != 0))
1408 {
1409 if (self->block.u.valid != valid)
1410 {
1411 self->block.u.valid = valid;
1412 self->dirty = true;
1413 }
1414 }
1415 else
1416 {
1417 KEncFileBlock block;
1418 rc_t rc;
1419
1420 rc = KEncFileBlockRead (self, &block, block_id, false);
1421 if (rc)
1422 return rc;
1423
1424 /* only change block if not "missing" */
1425 if (BufferAllZero (&block, sizeof block) == false)
1426 {
1427 assert (block.id == block_id);
1428
1429 if (block.u.valid != valid)
1430 {
1431 self->changed = self->sought = true;
1432 block.u.valid = valid;
1433
1434 rc = KEncFileBlockFlush (self, &block);
1435 if (rc)
1436 return rc;
1437 }
1438 }
1439 }
1440 return 0;
1441 }
1442
1443
1444 static
KEncFileSetSizeInt(KEncFile * self,uint64_t dec_size)1445 rc_t KEncFileSetSizeInt (KEncFile *self, uint64_t dec_size)
1446 {
1447 uint64_t trim_size = 0;
1448 uint64_t enc_size;
1449 bool do_size = true;
1450
1451 rc_t rc = 0;
1452
1453 /* should we not have been called? */
1454 if ((dec_size == self->dec_size) && (self->enc_size != 0))
1455 return 0;
1456
1457 /* if wiping out the whole file */
1458 if (dec_size == 0)
1459 {
1460 trim_size = sizeof (KEncFileHeader);
1461 enc_size = (sizeof (KEncFileHeader) + sizeof (KEncFileFooter));
1462
1463 /* if we did clear out the RAM structures to match */
1464 memset (&self->block, 0, sizeof self->block);
1465 memset (&self->foot, 0, sizeof self->foot);
1466 self->dirty = false;
1467 self->size_known = true;
1468 self->bswap = false;
1469 self->changed = true;
1470 self->sought = false;
1471 self->has_header = false;
1472 self->version = eCurrentVersion;
1473 }
1474 else
1475 {
1476 KEncFileBlockId new_bid; /* block id of new last block */
1477 KEncFileBlockId new_fid; /* block id of new footer / block count */
1478 uint32_t new_doff; /* bytes into last partial block */
1479
1480 /*
1481 * determine sizes of decrypted virtual file
1482 * and encrypted 'real' file
1483 */
1484
1485 /*
1486 NB - the following code utilizes a function for converting
1487 an OFFSET to a zero-based block-id. However, it passes in a size.
1488 By examining new_doff, it detects the case where "dec_size" is an
1489 exact multiple of plaintext block size, and takes the return to
1490 be a "block-id" of the footer, and new_bid to be the last block.
1491
1492 in the case where "new_doff" is zero, "new_bid" will be the effective
1493 id of the footer, and "new_bid" will need to be adjusted to the previous
1494 full block.
1495
1496 in the case where "new_doff" is not zero, "new_bid" will be the
1497 last data block id, and the footer will be one beyond.
1498
1499 although the code utilizes incorrect and misleading primitives,
1500 it works.
1501 */
1502
1503 new_fid = new_bid = PlaintextOffset_to_BlockId (dec_size, &new_doff);
1504 if (new_doff == 0)
1505 --new_bid; /* exactly fills a block */
1506 else
1507 ++new_fid; /* leaves a partial block */
1508
1509 enc_size = BlockId_to_CiphertextOffset ( new_fid ) + sizeof self->foot;
1510
1511 /* are we starting with an empty file? It's easy if we are */
1512 if (self->dec_size == 0)
1513 {
1514 /* TBD - this looks incorrect... what about KEncFileHeader?
1515 the code below would use BlockId_to_CiphertextOffset()
1516 */
1517 trim_size = sizeof (KEncFileHeader);
1518
1519 /* if we did clear out the RAM structures to match */
1520 memset (&self->block, 0, sizeof self->block);
1521 self->bswap = false;
1522 self->changed = true;
1523 self->version = eCurrentVersion;
1524 }
1525 else
1526 {
1527 KEncFileBlockId old_bid; /* block id of old last block */
1528 KEncFileBlockId old_fid; /* block id of old footer / block count */
1529 uint32_t old_doff; /* bytes into last partial block */
1530
1531 old_fid = old_bid = PlaintextOffset_to_BlockId (self->dec_size, &old_doff);
1532 if (old_doff == 0)
1533 --old_bid; /* exactly fills a block */
1534 else
1535 ++old_fid; /* leaves a partial block */
1536
1537 /* are we only changing the last block? */
1538 if (old_bid == new_bid)
1539 {
1540 assert ((self->dad.read_enabled == false) || (self->enc_size == enc_size));
1541
1542 if (new_doff == 0)
1543 {
1544 /* change from partial to full last block */
1545 rc = KEncFileSetSizeBlockFull (self, new_bid);
1546 }
1547 else
1548 {
1549 /* resize last block */
1550 rc = KEncFileSetSizeBlockPartial (self, new_bid, new_doff);
1551 }
1552
1553 /* no need to resize underlying file */
1554 do_size = false;
1555 }
1556 else
1557 {
1558
1559 /* truncating the file? */
1560 if (dec_size < self->dec_size)
1561 {
1562 trim_size = BlockId_to_CiphertextOffset ( new_fid );
1563
1564 /* do we throw away the block in the object? */
1565 if (self->block.id > new_bid)
1566 {
1567 self->dirty = false;
1568 memset (&self->block, 0, sizeof self->block);
1569 }
1570
1571 /* we only change the new last block if its now partial */
1572 if ( new_doff != 0 )
1573 rc = KEncFileSetSizeBlockPartial (self, new_bid, new_doff);
1574
1575 }
1576 /* expanding the file */
1577 else
1578 {
1579 assert (dec_size > self->dec_size);
1580
1581 trim_size = BlockId_to_CiphertextOffset ( old_fid );
1582
1583 /* make old last block a full block if it wasn't already */
1584 if ( old_doff != 0 )
1585 rc = KEncFileSetSizeBlockFull (self, old_bid);
1586 }
1587 }
1588 }
1589 }
1590 if (rc == 0)
1591 {
1592 if (do_size)
1593 {
1594 /* first trim for some reason... sparse files? */
1595 rc = KFileSetSize (self->encrypted, trim_size);
1596 if (rc)
1597 LOGERR (klogErr, rc, "failure to trim size of encrypted file");
1598 else
1599 {
1600 /* now extend to encrypted size */
1601 rc = KFileSetSize (self->encrypted, enc_size);
1602 if (rc)
1603 LOGERR (klogErr, rc, "failure to file size of encrypted file");
1604 }
1605 }
1606 if (rc == 0)
1607 {
1608 self->enc_size = enc_size;
1609 self->dec_size = dec_size;
1610 }
1611 }
1612 return rc;
1613 }
1614
1615
1616 static
KEncFileSetSize(KEncFile * self,uint64_t dec_size)1617 rc_t CC KEncFileSetSize (KEncFile *self, uint64_t dec_size)
1618 {
1619 assert (self);
1620 assert (self->encrypted);
1621
1622 if (self->dad.write_enabled == false)
1623 return RC (rcKrypto, rcFile, rcResizing, rcFile, rcNoPerm);
1624
1625 if ((self->seekable == false) || (self->size_known == false))
1626 return RC(rcKrypto, rcFile, rcAccessing, rcFunction, rcUnsupported);
1627
1628 /* silently ignore changes in size that don't change the size */
1629 if (dec_size == self->dec_size)
1630 return 0;
1631
1632 else
1633 return KEncFileSetSizeInt (self, dec_size);
1634 }
1635
1636
1637 /* ----------------------------------------------------------------------
1638 * Read
1639 * read file from known position
1640 *
1641 * "pos" [ IN ] - starting position within file
1642 *
1643 * "buffer" [ OUT ] and "bsize" [ IN ] - return buffer for read
1644 *
1645 * "num_read" [ OUT, NULL OKAY ] - optional return parameter
1646 * giving number of bytes actually read
1647 */
1648 static
KEncFileRead(const KEncFile * cself,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)1649 rc_t CC KEncFileRead (const KEncFile *cself,
1650 uint64_t pos,
1651 void *buffer,
1652 size_t bsize,
1653 size_t *num_read)
1654 {
1655 KEncFile * self = (KEncFile *)cself; /* mutable values */
1656 uint64_t max_bid;
1657 uint64_t block_id;
1658 uint32_t offset;
1659 rc_t rc = 0;
1660
1661 assert (self); /* checked in file.c KFileRead() */
1662 /* pos can be 'anything' */
1663 assert (buffer); /* checked in file.c KFileRead() */
1664 assert (bsize); /* checked in file.c KFileRead() */
1665 assert (num_read); /* checked in file.c KFileRead() */
1666
1667 assert (self->dad.read_enabled);
1668 assert (self->encrypted);
1669
1670 /* do we have a decrypted_size? */
1671
1672 block_id = PlaintextOffset_to_BlockId (pos, &offset);
1673
1674 switch ( ( uint32_t ) self->size_known)
1675 {
1676 case 0:
1677
1678 max_bid = EncryptedPos_to_BlockId (self->enc_size, NULL, NULL);
1679
1680 /* if past end of file as we know it so far quick out */
1681 if (max_bid <= block_id)
1682 return 0;
1683 break;
1684
1685 case 1:
1686 /* if past end of file quick out */
1687 if (pos > self->dec_size)
1688 return 0;
1689 break;
1690
1691 default:
1692 assert (0 && self->size_known);
1693 break;
1694 }
1695
1696 /*
1697 * are we on the wrong block?
1698 * Or are do we need to read the first block?
1699 */
1700 if ((block_id != self->block.id) || (self->block.u.valid == 0))
1701 {
1702 if ((!self->seekable) && (self->block.id + 1 != block_id))
1703 {
1704 rc = RC (rcFS, rcFile, rcReading, rcOffset, rcIncorrect);
1705 PLOGERR (klogErr, (klogErr, rc, "attempt to seek in encryption write at"
1706 " '$(O)' seek to '$(P)'", "O=%lu,P=%lu",
1707 BlockId_to_CiphertextOffset(self->block.id), pos));
1708 }
1709 else
1710 {
1711 /* flush any dirty block */
1712 if (self->dirty)
1713 {
1714 assert (self->dad.write_enabled);
1715 rc = KEncFileBlockFlush (self, &self->block);
1716 }
1717
1718 /* now try to read in a new block */
1719 if (rc == 0)
1720 rc = KEncFileBlockRead (self, &self->block, block_id, false);
1721
1722 if (rc == 0)
1723 {
1724 uint64_t read_max;
1725
1726 read_max = BlockId_to_PlaintextOffset ( block_id ) + self -> block . u . valid;
1727 if (self->dec_size < read_max)
1728 self->dec_size = read_max;
1729 }
1730 }
1731 }
1732
1733 /*
1734 * if we are trying to read past the end of the file
1735 * return 0 with nothing read
1736 */
1737 if ((rc == 0) &&
1738 (block_id == self->block.id) &&
1739 (offset < self->block.u.valid))
1740 {
1741 size_t to_copy;
1742
1743 to_copy = self->block.u.valid - offset;
1744 if (to_copy > bsize)
1745 to_copy = bsize;
1746
1747 memmove (buffer, self->block.data + offset, to_copy);
1748 *num_read = to_copy;
1749 }
1750 return rc;
1751 }
1752
1753
1754 /* ----------------------------------------------------------------------
1755 * Write
1756 * write file at known position
1757 *
1758 * "pos" [ IN ] - starting position within file
1759 *
1760 * "buffer" [ IN ] and "size" [ IN ] - data to be written
1761 *
1762 * "num_writ" [ OUT, NULL OKAY ] - optional return parameter
1763 * giving number of bytes actually written
1764 */
1765 static
KEncFileWrite(KEncFile * self,uint64_t pos,const void * buffer,size_t bsize,size_t * pnum_writ)1766 rc_t CC KEncFileWrite (KEncFile *self, uint64_t pos,
1767 const void *buffer, size_t bsize,
1768 size_t *pnum_writ)
1769 {
1770 rc_t rc = 0;
1771
1772 assert (self);
1773 assert (buffer);
1774 assert (bsize > 0);
1775 assert (pnum_writ);
1776
1777 assert (self->dad.write_enabled);
1778 assert (self->encrypted);
1779
1780 /* KOutMsg ("+++++\n%s: pos %lu\n",__func__,pos); */
1781
1782 if (self->dec_size != pos)
1783 {
1784 /* write only does not allow seeks */
1785 if ((!self->dad.read_enabled) && (!self->swarm))
1786 {
1787 rc = RC (rcFS, rcFile, rcWriting, rcOffset, rcIncorrect);
1788 PLOGERR (klogErr, (klogErr, rc, "attempt to seek in encryption write at"
1789 " '$(O)' seek to '$(P)'", "O=%lu,P=%lu",
1790 BlockId_to_CiphertextOffset(self->block.id), pos));
1791 }
1792 else
1793 self->sought = true;
1794 }
1795 if (rc == 0)
1796 {
1797 uint64_t block_id;
1798 uint32_t offset;
1799 uint64_t block_max;
1800 uint64_t new_size;
1801
1802 rc = 0;
1803 /* Block Id for this write */
1804 block_id = PlaintextOffset_to_BlockId (pos, &offset);
1805
1806 block_max = BlockId_to_PlaintextOffset ( block_id + 1 );
1807
1808 new_size = pos + bsize;
1809 if (new_size > block_max)
1810 bsize = block_max - new_size;
1811
1812
1813 /* is the new position beyond the current file length? */
1814 if ((new_size > self->dec_size) && (self->dad.read_enabled) && (!self->swarm))
1815 {
1816 rc = KEncFileSetSizeInt (self, new_size);
1817 if (rc)
1818 return rc;
1819 }
1820
1821 /* are we going to a new block? */
1822 if ((block_id != self->block.id) || (self->block.u.valid == 0))
1823 {
1824 /* do we have sometihng to flush first? */
1825 if (self->dirty)
1826 {
1827 assert (self->dad.write_enabled);
1828 rc = KEncFileBlockFlush (self, &self->block);
1829 }
1830
1831 if (rc == 0)
1832 {
1833 /* if we are going to over write the whole block */
1834 if ((!self->dad.read_enabled) ||
1835 ((offset == 0) && (bsize >= sizeof (self->block.data))))
1836 {
1837 memset (&self->block, 0, sizeof self->block);
1838 self->block.id = block_id;
1839 }
1840 /* else try to fetch an existing block */
1841 else
1842 rc = KEncFileBlockRead (self, &self->block, block_id, false);
1843 }
1844 }
1845
1846 if (rc == 0)
1847 {
1848 /* we are at the right block and ready to write */
1849 uint32_t new_valid;
1850 size_t to_copy;
1851
1852 /*
1853 * force block id to be right even if fetch was beyond end of
1854 * existing file
1855 */
1856 self->block.id = block_id;
1857
1858 /* to_copy = sizeof self->block.data - self->block.u.valid; */
1859 to_copy = sizeof self->block.data - offset;
1860
1861 if (to_copy > bsize)
1862 to_copy = bsize;
1863
1864 memmove (self->block.data + offset, buffer, to_copy);
1865 self->dirty = true;
1866 *pnum_writ = to_copy;
1867
1868 new_valid = (uint32_t) ( offset + to_copy );
1869 if (new_valid > self->block.u.valid)
1870 {
1871 uint64_t new_size;
1872
1873 self->block.u.valid = new_valid;
1874
1875 new_size = pos + to_copy;
1876 if (new_size > self->dec_size)
1877 self->dec_size = new_size;
1878 }
1879
1880 if (self->swarm)
1881 rc = KEncFileBlockFlush (self, &self->block);
1882
1883
1884 }
1885 }
1886 return rc;
1887 }
1888
1889
1890 /* ----------------------------------------------------------------------
1891 * Type
1892 * returns a KFileDesc
1893 * not intended to be a content type,
1894 * but rather an implementation class
1895 *
1896 * Just return what the backing file says...
1897 */
1898 static
KEncFileType(const KEncFile * self)1899 uint32_t CC KEncFileType (const KEncFile *self)
1900 {
1901 assert (self != NULL);
1902 assert (self->encrypted != NULL);
1903
1904 return KFileType (self->encrypted);
1905 }
1906
1907
1908 /* ----------------------------------------------------------------------
1909 * KEncFileMake
1910 * create a new file object
1911 */
1912
1913 /* ----------
1914 * KeysInit
1915 */
1916 static
KEncFileCiphersInit(KEncFile * self,const KKey * key,bool read,bool write)1917 rc_t KEncFileCiphersInit (KEncFile * self, const KKey * key, bool read, bool write)
1918 {
1919 KCipherManager * mgr;
1920 size_t z;
1921 rc_t rc;
1922
1923 switch ( key->type)
1924 {
1925 default:
1926 return RC (rcKrypto, rcEncryptionKey, rcConstructing, rcParam, rcInvalid);
1927
1928 case kkeyNone:
1929 return RC (rcKrypto, rcEncryptionKey, rcConstructing, rcParam, rcIncorrect);
1930
1931 case kkeyAES128:
1932 z = 128/8; break;
1933
1934 case kkeyAES192:
1935 z = 192/8; break;
1936
1937 case kkeyAES256:
1938 z = 256/8; break;
1939 }
1940 rc = KCipherManagerMake (&mgr);
1941 if (rc == 0)
1942 {
1943 rc = KCipherManagerMakeCipher (mgr, &self->ciphers.master, kcipher_AES);
1944 if (rc == 0)
1945 {
1946 rc = KCipherManagerMakeCipher (mgr, &self->ciphers.block, kcipher_AES);
1947 if (rc == 0)
1948 {
1949 rc = KCipherSetDecryptKey (self->ciphers.master, key->text, z);
1950 if (rc == 0)
1951 {
1952 rc = KCipherSetEncryptKey (self->ciphers.master, key->text, z);
1953 if (rc == 0)
1954 goto keep_ciphers;
1955 }
1956 KCipherRelease (self->ciphers.block);
1957 self->ciphers.block = NULL;
1958 }
1959 KCipherRelease (self->ciphers.master);
1960 self->ciphers.master = NULL;
1961 }
1962 keep_ciphers:
1963 KCipherManagerRelease (mgr);
1964 }
1965 return rc;
1966 }
1967
1968
1969
1970 static const KFile_vt_v1 vtKEncFile =
1971 {
1972 /* version */
1973 1, 1,
1974
1975 /* 1.0 */
1976 KEncFileDestroy,
1977 KEncFileGetSysFile,
1978 KEncFileRandomAccess,
1979 KEncFileSize,
1980 KEncFileSetSize,
1981 KEncFileRead,
1982 KEncFileWrite,
1983
1984 /* 1.1 */
1985 KEncFileType
1986 };
1987
1988
1989 static
KEncFileMakeIntValidSize(uint64_t enc_size,bool w)1990 rc_t KEncFileMakeIntValidSize (uint64_t enc_size, bool w)
1991 {
1992
1993 if (enc_size == 0)
1994 {
1995 if (w)
1996 return 0;
1997 }
1998 else
1999 {
2000 uint64_t min_size = sizeof (KEncFileHeader) + sizeof (KEncFileFooter);
2001 uint64_t block_count;
2002
2003 if (enc_size >= min_size)
2004 {
2005 block_count = EncryptedPos_to_BlockId (enc_size, NULL, NULL);
2006
2007 if (enc_size - BlockId_to_CiphertextOffset (block_count) == sizeof (KEncFileFooter))
2008 return 0;
2009 }
2010 }
2011 return RC (rcKrypto, rcFile, rcConstructing, rcSize, rcIncorrect);
2012 }
2013
2014
2015 /* ----------
2016 * MakeInt
2017 * common make for all encryptor/decryptors
2018 */
2019 static
KEncFileMakeInt(KEncFile ** pself,KFile * encrypted,bool r,bool w,bool v,bool s)2020 rc_t KEncFileMakeInt (KEncFile ** pself, KFile * encrypted,
2021 bool r, bool w, bool v, bool s)
2022 {
2023 uint64_t enc_size;
2024 rc_t rc = 0, orc;
2025 bool seekable;
2026 bool size_known;
2027
2028 assert (pself);
2029 assert (encrypted);
2030 assert (((r == true) || (r == false)) &&
2031 ((w == true) || (w == false)) &&
2032 ((v == true) || (v == false)));
2033
2034 /* must be able to do at elast one of read and write */
2035 assert (r || w);
2036
2037 /* expecting to validate read only right now */
2038 /* assert ((v && r && !w) || (!v)); */
2039
2040 if (w && ! encrypted->write_enabled)
2041 {
2042 rc = RC (rcKrypto, rcFile, rcConstructing, rcFile, rcReadonly);
2043 LOGERR (klogErr, rc, "Can not make a encryptor for a unwritable file");
2044 }
2045 if (r && ! encrypted->read_enabled)
2046 {
2047 orc = RC (rcKrypto, rcFile, rcConstructing, rcFile, rcWriteonly);
2048 LOGERR (klogErr, orc, "Can not make a decryptor for an unreadable file");
2049 if (rc == 0)
2050 rc = orc;
2051 }
2052 if (rc)
2053 return rc;
2054
2055 /* determine whether the original file can tell us the size */
2056 rc = KFileSize (encrypted, &enc_size);
2057 if (rc == 0)
2058 size_known = true;
2059
2060 else if (GetRCState(rc) == rcUnsupported)
2061 size_known = false;
2062
2063 else
2064 return rc;
2065
2066 if (!v && size_known)
2067 {
2068 rc = KEncFileMakeIntValidSize (enc_size, w);
2069 if (rc)
2070 return rc;
2071 }
2072
2073 /* determine whether the original file allows seeks */
2074 rc = KFileRandomAccess (encrypted);
2075 if (rc == 0)
2076 seekable = true;
2077
2078 else if (GetRCState(rc) == rcUnsupported)
2079 seekable = false;
2080
2081 else
2082 {
2083 LOGERR (klogErr, rc, "error checking random access building "
2084 "encrypted file");
2085 return rc;
2086 }
2087
2088 /* We are currently only supporting update on seekable and size_known original files */
2089 if (r && w && ((!seekable) || (!size_known)))
2090 {
2091 rc = RC (rcKrypto, rcFile, rcConstructing, rcFile, rcIncorrect);
2092 LOGERR (klogErr, rc, "encryptor/decryptor requires seek and size ability");
2093 return rc;
2094 }
2095
2096 rc = KFileAddRef (encrypted);
2097 if (rc)
2098 {
2099 LOGERR (klogErr, rc, "Could not add reference to encrypted file");
2100 return rc;
2101 }
2102 else
2103 {
2104 KEncFile * self;
2105
2106 /* allocate and zero out an object since we want much of it to be zeroed */
2107 self = calloc (1, sizeof *self);
2108 if (self == NULL)
2109 {
2110 rc = RC (rcFS, rcFile, rcConstructing, rcMemory, rcExhausted);
2111 LOGERR (klogSys, rc,
2112 "out of memory creating encryptor and/or decryptor");
2113 }
2114 else
2115 {
2116 /* all KFiles get this initialization */
2117 rc = KFileInit (&self->dad, (const KFile_vt*)&vtKEncFile, "KEncFile", "no-name", r, w);
2118 if (rc)
2119 LOGERR (klogInt, rc, "error with init for encrypted file");
2120
2121 else
2122 {
2123 self->encrypted = encrypted;
2124 self->swarm = s;
2125
2126 /* write only or empty updatable */
2127 if ((!r) || (w && size_known && (enc_size == 0)))
2128 {
2129 /* dummy size to make the SetSizeInt work */
2130 self->enc_size = enc_size;
2131 rc = KEncFileSetSizeInt (self, 0);
2132 self->seekable = r && seekable;
2133 }
2134 else
2135 {
2136 self->enc_size = enc_size;
2137 self->seekable = seekable;
2138 self->size_known = size_known;
2139 rc = KEncFileHeaderRead (self);
2140 }
2141 if (rc == 0)
2142 {
2143 *pself = self;
2144 return 0;
2145 }
2146 }
2147 free (self);
2148 }
2149 KFileRelease (encrypted);
2150 }
2151 return rc;
2152 }
2153
2154
2155 static
KEncFileMakeSize(KEncFile * self)2156 rc_t KEncFileMakeSize (KEncFile *self)
2157 {
2158 KEncFileBlockId fid;
2159 rc_t rc;
2160
2161 assert (self->seekable);
2162
2163 /*
2164 * turn the encrypted size into a block/offset
2165 * the offset should be 0 for a missing footer
2166 * or the size of a footer
2167 */
2168 fid = EncryptedPos_to_BlockId (self->enc_size, NULL, NULL);
2169
2170 assert (BlockId_to_CiphertextOffset(fid) + sizeof (self->foot) == self->enc_size);
2171
2172 if (fid == 0)
2173 self->dec_size = 0;
2174
2175 else
2176 {
2177 KEncFileBlockId bid = fid - 1;
2178 KEncFileBlock b;
2179
2180 /*
2181 * not calling this a seek as its not reading a data block
2182 * out of order that will be modified
2183 */
2184 rc = KEncFileBlockRead (self, &b, bid, false);
2185 if (rc)
2186 return rc;
2187 else
2188 {
2189 if (BufferAllZero(&b, sizeof b) == true)
2190 self->dec_size = BlockId_to_PlaintextOffset (bid) +
2191 sizeof self->block.data;
2192
2193 else
2194 self->dec_size = BlockId_to_PlaintextOffset (bid) + b.u.valid;
2195 }
2196 }
2197 self->size_known = true;
2198 return 0;
2199 }
2200
2201
2202 /* ----------
2203 * MakeCmn
2204 * common parameter validation for all encryptor/decryptors
2205 */
2206 static
KEncFileMakeCmn(KEncFile ** pself,KFile * encrypted,const KKey * key,bool r,bool w,bool s)2207 rc_t KEncFileMakeCmn (KEncFile ** pself, KFile * encrypted, const KKey * key,
2208 bool r, bool w, bool s)
2209 {
2210 rc_t rc = 0, orc;
2211
2212 assert (((r == true)||(r == false))&&((w == true)||(w == false)));
2213 assert (w || r);
2214
2215 if (pself == NULL)
2216 {
2217 rc = RC (rcKrypto, rcFile, rcConstructing, rcSelf, rcNull);
2218 LOGERR (klogErr, rc,
2219 "pointer to self NULL when creating "
2220 "an encryptor/decryptor");
2221 }
2222 else
2223 *pself = NULL;
2224
2225 if (encrypted == NULL)
2226 {
2227 orc = RC (rcFS, rcFile, rcConstructing, rcParam, rcNull);
2228 LOGERR (klogErr, orc,
2229 "encrypted file not readable when creating "
2230 "an encryptor/decryptor");
2231 if (rc == 0)
2232 rc = orc;
2233 }
2234
2235 if (key == NULL)
2236 {
2237 orc = RC (rcFS, rcFile, rcConstructing, rcParam, rcNull);
2238 LOGERR (klogErr, orc,
2239 "key not supplied when creating an encryptor/decryptor");
2240 if (rc == 0)
2241 rc = orc;
2242 }
2243
2244 CRC32Init(); /* likely to be called way too often */
2245
2246 switch (key->type)
2247 {
2248 default:
2249 orc = RC (rcFS, rcFile, rcConstructing, rcParam, rcInvalid);
2250 PLOGERR (klogErr,
2251 (klogErr, orc, "invalid key type '$(T)' should be "
2252 "kkeyAES128(1), kkeyAES192(2) or kkeyAES256(3)",
2253 "T=%u", key->type));
2254 if (rc == 0)
2255 rc = orc;
2256 break;
2257
2258 case kkeyAES128:
2259 case kkeyAES192:
2260 case kkeyAES256:
2261 break;
2262 }
2263 if (rc == 0)
2264 {
2265 KEncFile * self;
2266
2267 assert ((r == true) || (r == false));
2268 assert ((w == true) || (w == false));
2269
2270 rc = KEncFileMakeInt (&self, encrypted, r, w, false, s);
2271 if (rc == 0)
2272 {
2273 rc = KEncFileCiphersInit (self, key, r, w);
2274 if (rc == 0)
2275 {
2276
2277 if (self->seekable && self->size_known)
2278 rc = KEncFileMakeSize (self);
2279
2280 if (rc == 0)
2281 {
2282 *pself = self;
2283 return 0;
2284 }
2285 }
2286 KFileRelease (&self->dad);
2287 }
2288 }
2289 return rc;
2290 }
2291
2292
2293 /* ----------
2294 * Read mode is fully seekable if the underlying KFile is seekable some
2295 * integrity checking will not be performed in allowing this seeking.
2296 */
KEncFileMakeRead_v2(const KFile ** pself,const KFile * encrypted,const KKey * key)2297 LIB_EXPORT rc_t CC KEncFileMakeRead_v2 (const KFile ** pself,
2298 const KFile * encrypted,
2299 const KKey * key)
2300 {
2301 KEncFile * self;
2302 rc_t rc;
2303
2304 /*
2305 * casting encrypted dowsn't actually make it writable
2306 * it just lets us use a common constructor
2307 */
2308 rc = KEncFileMakeCmn (&self, (KFile *)encrypted, key, true, false, false);
2309 if (rc)
2310 LOGERR (klogErr, rc, "error constructing decryptor");
2311
2312 else
2313 *pself = &self->dad;
2314
2315 return rc;
2316 }
2317
2318
2319 /* ----------
2320 * Write mode encrypted file can only be written straight through form the
2321 * first byte to the last.
2322 *
2323 * Existing content is lost.
2324 */
KEncFileMakeWrite_v2(KFile ** pself,KFile * encrypted,const KKey * key)2325 LIB_EXPORT rc_t CC KEncFileMakeWrite_v2 (KFile ** pself,
2326 KFile * encrypted,
2327 const KKey * key)
2328 {
2329 KEncFile * self;
2330 rc_t rc;
2331
2332 rc = KEncFileMakeCmn (&self, encrypted, key, false, true, false);
2333 if (rc)
2334 LOGERR (klogErr, rc, "error constructing encryptor");
2335
2336 else
2337 *pself = &self->dad;
2338
2339 return rc;
2340 }
2341
2342
KEncFileMakeUpdate_v2(KFile ** pself,KFile * encrypted,const KKey * key)2343 LIB_EXPORT rc_t CC KEncFileMakeUpdate_v2 (KFile ** pself,
2344 KFile * encrypted,
2345 const KKey * key)
2346 {
2347 KEncFile * self;
2348 rc_t rc;
2349
2350 /* static int count = 0; */
2351
2352 /* KOutMsg ("%s: %d\n",__func__,++count); */
2353
2354 rc = KEncFileMakeCmn (&self, (KFile *)encrypted, key, true, true, false);
2355 if (rc)
2356 LOGERR (klogErr, rc, "error constructing encryptor/decryptor");
2357
2358 else
2359 *pself = &self->dad;
2360
2361 return rc;
2362 }
2363
2364
2365 /* ----------
2366 * Swarm mode encrypted file can be writtenout of order but the footer is not
2367 * handled automatically
2368 */
KEncFileMakeBlock_v2(KFile ** pself,KFile * encrypted,const KKey * key)2369 LIB_EXPORT rc_t CC KEncFileMakeBlock_v2 (KFile ** pself,
2370 KFile * encrypted,
2371 const KKey * key)
2372 {
2373 KEncFile * self;
2374 rc_t rc;
2375
2376 /* static int count = 0; */
2377
2378 /* KOutMsg ("%s: %d\n",__func__,++count); */
2379
2380 rc = KEncFileMakeCmn (&self, (KFile *)encrypted, key, false, true, true);
2381 if (rc)
2382 LOGERR (klogErr, rc, "error constructing encryptor/decryptor");
2383
2384 else
2385 *pself = &self->dad;
2386
2387 return rc;
2388 }
2389
2390
2391 /* ----------
2392 * Validate mode is useful only for the KFileEncValidate function
2393 */
2394 static
KEncFileMakeValidate(KEncFile ** pself,const KFile * encrypted)2395 rc_t KEncFileMakeValidate (KEncFile ** pself, const KFile * encrypted)
2396 {
2397 KEncFile * self;
2398 rc_t rc;
2399
2400 assert (pself);
2401 assert (encrypted);
2402
2403 rc = KEncFileMakeInt (&self, (KFile*)encrypted, true, false, true, false);
2404 if (rc)
2405 LOGERR (klogErr, rc, "error making KEncFile");
2406 else
2407 {
2408 rc = KEncFileHeaderRead (self);
2409 if (rc)
2410 LOGERR (klogErr, rc, "error reading encrypted file header");
2411 else
2412 {
2413 *pself = self;
2414 return 0;
2415 }
2416 }
2417 *pself = NULL;
2418 return rc;
2419 }
2420
2421
2422 /* ======================================================================
2423 * Interface extensions
2424 */
2425
2426
2427 /* ----------
2428 * Validate mode can not be read or written.
2429 * Upon open the whole file is read from begining to end and all CRC
2430 * and other integrity checks are performed immedaitely
2431 *
2432 * This will fail if the file being tested is not "at position 0" and can not
2433 * be sought back to 0.
2434 */
2435
2436
2437
KEncFileValidate_v2(const KFile * encrypted)2438 LIB_EXPORT rc_t CC KEncFileValidate_v2 (const KFile * encrypted)
2439 {
2440 KEncFile * file;
2441 rc_t rc = 0;
2442
2443 /* fail if a NULL parameter: can't validate all addresses */
2444 if (encrypted == NULL)
2445 {
2446 rc = RC (rcKrypto, rcFile, rcValidating, rcParam, rcNull);
2447 LOGERR (klogErr, rc, "encrypted file was null when trying to validate");
2448 return rc;
2449 }
2450
2451 /* file header is validated within the call to Make Validate */
2452 rc = KEncFileMakeValidate (&file, encrypted);
2453 if (rc)
2454 LOGERR (klogErr, rc,
2455 "unable to validate encrypted file due to "
2456 "inability to open as encrypted file");
2457 else
2458 {
2459 uint64_t pos; /* position within the encrypted file */
2460 uint64_t block_count = 0; /* how many blocks have we read */
2461
2462 /* loop through all data blocks */
2463 pos = sizeof (KEncFileHeader);
2464 for (block_count = 0; ; ++block_count)
2465 {
2466 rc_t vrc;
2467 STSMSG (2, ("reading block '%u' at '%lu'", block_count,
2468 BlockId_to_CiphertextOffset(block_count)));
2469
2470 vrc = KEncFileBlockRead (file, NULL, block_count, true);
2471 if (vrc != 0)
2472 {
2473 if ( rc == 0 )
2474 rc = vrc;
2475 if ( GetRCContext( vrc ) != rcValidating )
2476 {
2477 STSMSG (2, ("read error at block '%u'", block_count));
2478 break;
2479 }
2480 }
2481 if (file->eof)
2482 {
2483 STSMSG (2, ("block '%u' was end", block_count));
2484 break;
2485 }
2486 pos += sizeof (KEncFileData);
2487 }
2488 KFileRelease (&file->dad);
2489 }
2490 return (rc);
2491 }
2492
2493
KEncFileHeaderWrite_v2(KFile * dad)2494 LIB_EXPORT rc_t CC KEncFileHeaderWrite_v2 (KFile * dad)
2495 {
2496 rc_t rc;
2497
2498 if (dad->vt != (const KFile_vt*)&vtKEncFile)
2499 {
2500 rc = RC (rcKrypto, rcFile, rcWriting, rcType, rcIncorrect);
2501 LOGERR (klogErr, rc, "file not an encryptor requested writing header");
2502 }
2503 else
2504 {
2505 KEncFile * self;
2506 self = (KEncFile*)dad;
2507
2508 rc = KEncFileHeaderWrite (self);
2509 }
2510 return rc;
2511 }
2512
KEncFileFooterWrite_v2(KFile * dad)2513 LIB_EXPORT rc_t CC KEncFileFooterWrite_v2 (KFile * dad)
2514 {
2515 rc_t rc;
2516
2517 if (dad->vt != (const KFile_vt*)&vtKEncFile)
2518 {
2519 rc = RC (rcKrypto, rcFile, rcWriting, rcType, rcIncorrect);
2520 LOGERR (klogErr, rc, "file not an encryptor requested writing footer");
2521 }
2522 else
2523 {
2524 KEncFile * self;
2525 self = (KEncFile*)dad;
2526
2527 rc = KEncFileFooterWrite (self);
2528 }
2529 return rc;
2530 }
2531
2532 /* ----------
2533 * Identify whether a file is a KEncFile type encrypted file by the header.
2534 * read the header into a buffer and pass it into this function.
2535 * The buffer_size needs to be at least 8 but more bytes lead to a better
2536 * check up to the size of the header of a KEncFile type encrypted file.
2537 * As the header may change in the future (in a backwards compatible way)
2538 * that size might change from the current 16.
2539 *
2540 * Possible returns:
2541 * 0:
2542 * the file is an identified KEncFile type file. False positives are
2543 * possible if a file happens to match at 8 or more bytes
2544 *
2545 * RC (rcFS, rcFile, rcIdentifying, rcFile, rcWrongType)
2546 * the file is definitely not a KEncFile type encrypted file.
2547 *
2548 * RC (rcFS, rcFile, rcIdentifying, rcParam, rcNull)
2549 * bad parameters in the call
2550 *
2551 * RC (rcFS, rcFile, rcIdentifying, rcBuffer, rcInsufficient)
2552 * not a large enough buffer to make an identification
2553 */
KFileIsEnc_v2(const char * buffer,size_t buffer_size)2554 LIB_EXPORT rc_t CC KFileIsEnc_v2 (const char * buffer, size_t buffer_size)
2555 {
2556 KEncFileHeader header;
2557 size_t count;
2558 bool byte_swapped;
2559
2560 if ((buffer == NULL) || (buffer_size == 0))
2561 return RC (rcFS, rcFile, rcIdentifying, rcParam, rcNull);
2562
2563 /* must have the signature to consider it an Encrypted file */
2564 if (buffer_size < sizeof (header.file_sig))
2565 return RC (rcFS, rcFile, rcIdentifying, rcBuffer, rcInsufficient);
2566
2567 if ((memcmp (buffer, &const_header.file_sig, sizeof const_header.file_sig ) != 0) &&
2568 (memcmp (buffer, &const_header_sra.file_sig, sizeof const_header_sra.file_sig ) != 0))
2569 return SILENT_RC (rcFS, rcFile, rcIdentifying, rcFile, rcWrongType);
2570
2571 /* can we also check the byte order? It's okay if we can't */
2572 if (buffer_size < sizeof header.file_sig + sizeof header.byte_order)
2573 return 0;
2574
2575 count = buffer_size > sizeof header ? sizeof header : buffer_size;
2576
2577 memmove (&header, buffer, count);
2578
2579 if (header.byte_order == const_header.byte_order)
2580 byte_swapped = false;
2581
2582 else if (header.byte_order == const_bswap_header.byte_order)
2583 byte_swapped = true;
2584
2585 /* but if it's not we fail with a different error */
2586 else
2587 return RC (rcFS, rcFile, rcIdentifying, rcFile, rcOutoforder);
2588
2589 /* can we check the version as well? It's okay if we can't */
2590 if (buffer_size < sizeof (header))
2591 return 0;
2592
2593 assert (sizeof (header.version) == 4);
2594 if (byte_swapped)
2595 header.version = bswap_32(header.version);
2596
2597 /* and it's a different error if the version is not within our range */
2598 if ((header.version <= 0) || (header.version > eCurrentVersion))
2599 return RC (rcKrypto, rcFile, rcClassifying, rcFile, rcBadVersion);
2600
2601 return 0;
2602 }
2603
2604
KFileIsSraEnc(const char * buffer,size_t buffer_size)2605 LIB_EXPORT rc_t CC KFileIsSraEnc (const char * buffer, size_t buffer_size)
2606 {
2607 KEncFileHeader header;
2608 size_t count;
2609 bool byte_swapped;
2610
2611 if ((buffer == NULL) || (buffer_size == 0))
2612 return RC (rcFS, rcFile, rcIdentifying, rcParam, rcNull);
2613
2614
2615 if (buffer_size < sizeof (header.file_sig))
2616 return RC (rcFS, rcFile, rcIdentifying, rcBuffer, rcInsufficient);
2617
2618 if (memcmp (buffer, &const_header_sra.file_sig, sizeof const_header.file_sig ) != 0)
2619 return RC (rcFS, rcFile, rcIdentifying, rcFile, rcWrongType);
2620
2621 if (buffer_size < sizeof header.file_sig + sizeof header.byte_order)
2622 return 0;
2623
2624 count = buffer_size > sizeof header ? sizeof header : buffer_size;
2625
2626 memmove (&header, buffer, count);
2627
2628 if (header.byte_order == const_header.byte_order)
2629 byte_swapped = false;
2630
2631 else if (header.byte_order == const_bswap_header.byte_order)
2632 byte_swapped = true;
2633
2634 else
2635 return RC (rcFS, rcFile, rcIdentifying, rcFile, rcOutoforder);
2636
2637 if (buffer_size < sizeof (header))
2638 return 0;
2639
2640 assert (sizeof (header.version) == 4);
2641 if (byte_swapped)
2642 header.version = bswap_32(header.version);
2643
2644 if ((header.version <= 0) || (header.version > eCurrentVersion))
2645 return RC (rcKrypto, rcFile, rcClassifying, rcFile, rcBadVersion);
2646
2647 return 0;
2648 }
2649
2650 /* end of file encfile.c */
2651
2652
2653
2654