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 <krypto/key.h>
29 #include <krypto/ciphermgr.h>
30 #include <krypto/cipher.h>
31 #include "aes-priv.h"
32 #include "encfile-priv.h"
33
34 #include <klib/rc.h>
35 #include <klib/checksum.h>
36 #include <klib/log.h>
37 #include <klib/out.h>
38 #include <klib/debug.h>
39 #include <klib/vector.h>
40 #include <klib/status.h>
41 #include <kfs/file.h>
42
43 #include <sysalloc.h>
44
45 #include <byteswap.h>
46
47 #include <stdlib.h>
48 #include <string.h>
49 #include <assert.h>
50
51
52 #include <klib/out.h>
53
54 #define USE_READ_V1 false
55 #define USE_WRITE_V1 false
56 #define USE_UPDATE_V1 false
57 #define USE_BLOCK_V1 false
58 /* KReencFile and KEncryptFile need to use update v1 as it is different */
59 #define USE_VALIDATE_V1 false
60 #define USE_ISENC_V1 false
61
62 #define ENABLE_V2 true
63
64
65 /* ----------------------------------------------------------------------
66 * KEncFileV1
67 * Base object class for the encryption, decryption and validation of
68 * the file format defined above
69 */
70 typedef struct KEncFileV1 KEncFileV1;
71 #define KFILE_IMPL struct KEncFileV1
72 #include <kfs/impl.h>
73
74
75 #include "encfile-priv.h"
76
77 /* ----------
78 * BufferCalcMD5
79 * Generate the MD5 digest for a buffer
80 */
81 static
BufferCalcMD5(const void * buffer,size_t size,uint8_t digest[16])82 void BufferCalcMD5 (const void * buffer, size_t size, uint8_t digest [16])
83 {
84 MD5State state;
85
86 assert (buffer);
87 assert (size);
88 assert (digest);
89
90 MD5StateInit (&state);
91 MD5StateAppend (&state, buffer, size);
92 MD5StateFinish (&state, digest);
93 }
94
95
96 typedef struct KEncFileCiphers KEncFileCiphers;
97 struct KEncFileCiphers
98 {
99 KCipher * master;
100 KCipher * block;
101 };
102
103 typedef uint8_t KEncFileIVec [16];
104 /* -----
105 */
106 struct KEncFileV1
107 {
108 KFile dad; /* base class */
109 KFile * encrypted; /* encrypted file as a KFile */
110 KEncFileCiphers ciphers;
111 KEncFileBlock block; /* */
112 uint64_t encrypted_max; /* highest read/written point in the encrypted file */
113 KEncFileFooter foot; /* contains rcrchecksum and blockcount */
114 #if ENABLE_V2
115 KEncFileVersion version;
116 #endif
117 bool dirty; /* data written but not flushed */
118 bool bswap;
119 bool eof;
120 bool seekable;
121 bool written;
122 bool swarm;
123 };
124
125
126 /* ----------------------------------------------------------------------
127 * Buffer - just some part of the encrypted file read or written
128 *
129 * these functions exist to hide the potential multiple calls needed
130 * if the KFileRead or KFileWrite called on the encrypted file break up
131 * the requested amount into partial reads or writes
132 */
133
134 /* ----------
135 * BufferRead
136 * Fill a buffer with a requested number of bytes from the encrypted file.
137 * Read either the requested number of bytes or up through EOF.
138 * The caller has to handle an EOF shorted buffer.
139 */
140 static
KEncFileV1BufferRead(const KEncFileV1 * cself,uint64_t pos,void * buffer,size_t bsize,size_t * pnum_read)141 rc_t KEncFileV1BufferRead (const KEncFileV1 * cself, uint64_t pos, void * buffer,
142 size_t bsize, size_t * pnum_read)
143 {
144 KEncFileV1 * self; /* for mutable fields */
145 rc_t rc;
146
147 assert (cself);
148 assert (buffer);
149 assert (pnum_read);
150
151 *pnum_read = 0;
152
153 self = (KEncFileV1*)cself; /* to hit mutable fields */
154
155 /* we want to read a full requested size if possible so keep trying if we
156 * haven't read enough yet.
157 * We can quit early only if EOF (i.e. read 0 bytes.
158 */
159 rc = KFileReadAll (self->encrypted, pos, buffer, bsize, pnum_read);
160 if (rc)
161 PLOGERR (klogErr,
162 (klogErr, rc,
163 "error reading position '$(P)' in encrypted file",
164 "P=%lu", pos));
165
166 else if (self->encrypted_max < pos)
167 self->encrypted_max = pos;
168
169 return rc;
170 }
171
172
173 /* ----------
174 * BufferWrite
175 * Write a buffer of requested size out to the encrypted file.
176 * return the number of bytes successfully written
177 */
178 static
KEncFileV1BufferWrite(KEncFileV1 * self,uint64_t pos,const void * buffer,size_t bsize,size_t * pnum_writ)179 rc_t KEncFileV1BufferWrite (KEncFileV1 * self, uint64_t pos, const void * buffer,
180 size_t bsize, size_t * pnum_writ)
181 {
182 rc_t rc;
183
184 rc = KFileWriteAll (self->encrypted, pos, buffer, bsize, pnum_writ);
185 if ((rc == 0) && (self->encrypted_max < pos))
186 self->encrypted_max = pos;
187
188 return rc;
189 }
190
191
192 /* ----------------------------------------------------------------------
193 * operations on KEncFileHeader
194 *
195 * The header only needs to be read and validated or written we need not
196 * reatian within the KEncFile object any information about the header in
197 * the initial version of this file format.
198 */
199
200 /* -----
201 * the first eight bytes of the file are two four byte strings
202 * The first is a common "NCBI"
203 * The second is the format specific "nenc"
204 */
205 #if 0
206 static const KEncFileSig KEncFileSignature = "NCBInenc";
207 #endif
208
209 /* -----
210 * the common constant used throughout the project to check the byte order
211 * as written by the system which created the file
212 */
213 /* enum fails to handle these due to integer overflow */
214
215 #define eByteOrderTag (0x05031988)
216 #define eByteOrderReverse (0x88190305)
217
218 /* ----
219 * Not unexpectedly the first version of this file will be "1"
220 */
221 #if ENABLE_V2
222
223 #define eCurrentVersion (0x00000002)
224 #define eCurrentVersionReverse (0x02000000)
225
226 static
227 const KEncFileHeader const_header_v1
228 = { "NCBInenc", eByteOrderTag, 0x00000001 };
229
230 static
231 const KEncFileHeader const_bswap_header_v1
232 = { "NCBInenc", eByteOrderReverse, 0x01000000 };
233
234 #else
235
236 #define eCurrentVersion (0x00000001)
237 #define eCurrentVersionReverse (0x01000000)
238
239 #endif
240
241 static
242 const KEncFileHeader const_header
243 = { "NCBInenc", eByteOrderTag, eCurrentVersion };
244
245 static
246 const KEncFileHeader const_bswap_header
247 = { "NCBInenc", eByteOrderReverse, eCurrentVersionReverse };
248
249
250 /* ----------
251 * HeaderRead
252 * Read the header of an encrypted file and validate it.
253 */
254 static
KEncFileV1HeaderRead(KEncFileV1 * self)255 rc_t KEncFileV1HeaderRead (KEncFileV1 * self)
256 {
257 KEncFileHeader header;
258 size_t num_read;
259 rc_t rc;
260
261 assert (self);
262
263 rc = KEncFileV1BufferRead (self, 0, &header, sizeof (header), &num_read);
264 if (rc)
265 return rc;
266
267 if (num_read != sizeof (header))
268 {
269 rc = RC (rcFS, rcFile, rcConstructing, rcHeader, rcTooShort);
270 PLOGERR (klogErr,
271 (klogErr, rc, "error reading full header of encrypted "
272 "file wanted '$(S)' got '$(N); bytes read", "S=%u,N=%u",
273 sizeof (header), num_read));
274 return rc;
275 }
276
277 /* expected is encrypted on a system of the same endianess */
278 if (memcmp (&header, &const_header, sizeof (header)) == 0)
279 {
280 self->bswap = false;
281 #if ENABLE_V2
282 self->version = eCurrentVersion;
283 #endif
284 return 0;
285 }
286
287 /* next most likely is encrypted on a machine of opposite endianess */
288 if (memcmp (&header, &const_bswap_header, sizeof (header)) == 0)
289 {
290 self->bswap = true;
291 #if ENABLE_V2
292 self->version = eCurrentVersion;
293 #endif
294 return 0;
295 }
296
297 #if ENABLE_V2
298 if (memcmp (&header, &const_header_v1, sizeof (header)) == 0)
299 {
300 self->bswap = false;
301 self->version = 1;
302 return 0;
303 }
304
305 /* next most likely is encrypted on a machine of opposite endianess */
306 if (memcmp (&header, &const_bswap_header_v1, sizeof (header)) == 0)
307 {
308 self->bswap = true;
309 self->version = 1;
310 return 0;
311 }
312 #endif
313
314 /* okay it's a "bad" header, so figure out why */
315 if (memcmp (&header, &const_header, sizeof (header.file_sig)) != 0)
316 {
317 rc = RC (rcKrypto, rcFile, rcReading, rcHeader, rcInvalid);
318 LOGERR (klogErr, rc, "file is not the NCBI encrypted file format");
319 /* if this fails the rest doesn't matter */
320 return rc;
321 }
322
323 switch (header.byte_order)
324 {
325 default:
326 rc = RC (rcFS, rcFile, rcConstructing, rcByteOrder, rcInvalid);
327 PLOGERR (klogErr,
328 (klogErr, rc, "invalid byte order flag '$(F); in "
329 "encrypted file", "F=%X", header.byte_order));
330 /* we don't return to possibly log other version errors */
331 break;
332 case eByteOrderReverse:
333 case eByteOrderTag:
334 break;
335 }
336
337 switch (header.version)
338 {
339 default:
340 rc = RC (rcFS, rcFile, rcConstructing, rcHeader, rcBadVersion);
341 PLOGERR (klogErr,
342 (klogErr, rc, "can not decrypt version '$(V)'",
343 "V=%u", header.version));
344 break;
345
346 case 1:
347 #if ENABLE_V2
348 case 2:
349 #endif
350 break;
351 }
352 return rc;
353 }
354
355
356 /* -----
357 * HeaderWrite
358 *
359 * build a ram copy of the header and write it to the file
360 */
361 static
KEncFileV1HeaderWrite(KEncFileV1 * self)362 rc_t KEncFileV1HeaderWrite (KEncFileV1 * self)
363 {
364 size_t num_writ;
365 rc_t rc;
366
367 rc = KEncFileV1BufferWrite (self, 0, &const_header, sizeof (const_header),
368 &num_writ);
369 if (rc == 0)
370 {
371 if (num_writ != sizeof (const_header))
372 rc = RC (rcFS, rcFile, rcWriting, rcHeader, rcInsufficient);
373 }
374 return rc;
375 }
376
KEncFileV1WriteHeader_v1(KFile * self)377 LIB_EXPORT rc_t CC KEncFileV1WriteHeader_v1 (KFile * self)
378 {
379 if (self == NULL)
380 return RC (rcKrypto, rcFile, rcWriting, rcSelf, rcNull);
381 return KEncFileV1HeaderWrite ((KEncFileV1*)self);
382 }
383
384
385 /* ----------------------------------------------------------------------
386 * operations on KEncFileFooter
387 */
388
389 /* ----------
390 * Validate
391 * we expect to read a Footer when we expect a Block so we validate in RAM
392 * without a Read
393 *
394 * we're just comparing the values in the footer against expected values
395 */
396 static
KEncFileV1FooterValidate(const KEncFileV1 * self,uint64_t block_count,uint64_t crc_checksum)397 rc_t KEncFileV1FooterValidate (const KEncFileV1 * self,
398 uint64_t block_count, uint64_t crc_checksum)
399 {
400 rc_t rc1 = 0, rc2 = 0;
401
402 if (self->foot.block_count != block_count)
403 {
404 rc2 = RC (rcKrypto, rcFile, rcValidating, rcFile, rcCorrupt);
405 LOGERR (klogErr, rc1, "bad block count in encrypted file footer");
406 }
407 if ((self->foot.crc_checksum != crc_checksum)
408 #if ENABLE_V2
409 &&((crc_checksum != 0) || (self->version == 1))
410 #endif
411 )
412 {
413 rc1 = RC (rcKrypto, rcFile, rcValidating, rcChecksum, rcCorrupt);
414 LOGERR (klogErr, rc2, "bad crc checksum in encrypted file footer");
415 }
416 return (rc1 ? rc1 : rc2);
417 }
418
419
420 /* ----------
421 * Write
422 * when we write a footer we write from the values in the object. They
423 * are stored in the same object format as the footer so its very simple
424 */
425 static
KEncFileV1FooterWrite(KEncFileV1 * self)426 rc_t KEncFileV1FooterWrite (KEncFileV1 * self)
427 {
428 KEncFileFooter foot;
429 uint64_t offset;
430 size_t num_writ;
431 rc_t rc;
432
433 memmove (&foot, &self->foot, sizeof (foot));
434 if (self->bswap)
435 {
436 foot.block_count = bswap_64 (foot.block_count);
437 foot.crc_checksum = bswap_64 (foot.crc_checksum);
438 }
439
440 offset = BlockId_to_CiphertextOffset ( self -> foot . block_count );
441
442 /* assert ((self->encrypted_max == offset) || */
443 /* (self->encrypted_max + sizeof(self->foot) == offset)); */
444
445 rc = KEncFileV1BufferWrite (self, offset, &foot, sizeof (foot),
446 &num_writ);
447 if (rc == 0)
448 {
449 if (num_writ != sizeof (foot))
450 rc = RC (rcFS, rcFile, rcWriting, rcFile, rcInsufficient);
451 }
452 return rc;
453 }
454
455
456 /* ----------
457 * IvecInit
458 * create the ivec for a given block
459 * done in a function to ensure decrypt and encrypt use the same code to
460 * generate this. Anything used to create this has to be available to
461 * code that doesn't know the content of the data or the state of the file
462 * beyond the location of the block with in the file.
463 *
464 * This is definitely over-kill using the MD5.
465 */
466 static
KEncFileV1IVecInit(const KEncFileV1 * self,KEncFileIVec ivec)467 void KEncFileV1IVecInit (const KEncFileV1 * self, KEncFileIVec ivec)
468 {
469 BufferCalcMD5 (&self->block.id, sizeof self->block.id, ivec);
470 }
471
472
473 /* ----------
474 * BlockEncrypt
475 */
476
477 static
KEncFileV1BlockEncrypt(KEncFileV1 * self,KEncFileBlock * e)478 rc_t KEncFileV1BlockEncrypt (KEncFileV1 * self, KEncFileBlock * e)
479 {
480 SHA256State state;
481 uint64_t id;
482 uint16_t valid;
483 uint16_t saved_valid;
484 KEncFileCRC crc;
485 uint8_t ivec [16];
486 rc_t rc;
487
488 assert (self);
489 assert (e);
490
491 /*
492 * First we finish preparing the two ciphers by creating the block
493 * user key out of the first part of the data and the shared Initialization
494 * vector for Chained Block Cipher mode encryption out of the block id
495 *
496 * create the initialization vector for this block
497 */
498 KEncFileV1IVecInit (self, ivec);
499
500 /*
501 * set the ivec for both the master and data block ciphers
502 */
503 rc = KCipherSetEncryptIVec (self->ciphers.master, ivec);
504 if (rc)
505 return rc;
506
507 rc = KCipherSetEncryptIVec (self->ciphers.block, ivec);
508 if (rc)
509 return rc;
510
511 /*
512 * create the block user key out of the first 4kb of data and the block id
513 */
514 saved_valid = valid = self->block.u.valid;
515 id = self->block.id;
516
517 SHA256StateInit (&state);
518 SHA256StateAppend (&state, self->block.data,
519 valid > 4096 ? 4096 : valid);
520 SHA256StateAppend (&state, &id, sizeof (id));
521 SHA256StateFinish (&state, self->block.key);
522
523 /*
524 * create the block key schedule out of the block user key
525 */
526 rc = KCipherSetEncryptKey (self->ciphers.block, self->block.key,
527 sizeof self->block.key);
528 if (rc)
529 return rc;
530
531 /*
532 * Salt the block using the randomish user key to randomly select
533 * data from the valid data.
534 *
535 * This will cover the data portion of the block past the last valid
536 * byte.
537 *
538 * NOTE we are accessing a byte array as a word array.
539 *
540 * NOTE we are using the array named data to access data beyond it's end.
541 */
542 {
543 uint16_t * pw;
544 unsigned int windex;
545 unsigned int rindex;
546 size_t bindex;
547
548 pw = (uint16_t*)self->block.key;
549 windex = 0;
550
551 for (bindex = valid;
552 bindex < sizeof self->block.data + sizeof self->block.u;
553 ++ bindex)
554 {
555 /* this goes beyond the end of the data array by design */
556 rindex = (size_t)pw[windex];
557 rindex %= bindex;
558
559 self->block.data[bindex] = self->block.data[rindex];
560
561 ++rindex;
562 if (rindex >= sizeof self->block.key / sizeof *pw)
563 rindex = 0;
564 }
565 }
566
567 /*
568 * If we are modifying a block created on a system with a different default
569 * Endian choice we'll need to byte swap the block id and the block valid
570 * count
571 */
572 if (self->bswap)
573 {
574 id = bswap_64 (id);
575 valid = bswap_16 (valid);
576 }
577
578
579 if (saved_valid == sizeof self->block.data)
580 self->block.u.valid |= valid;
581 else
582 self->block.u.valid = valid;
583
584 e->id = id;
585
586 /*
587 * encrypt the block user key into the buffer
588 */
589 rc = KCipherEncryptCBC (self->ciphers.master, self->block.key, e->key,
590 sizeof (self->block.key) / sizeof (ivec));
591 if (rc)
592 return rc;
593
594 /*
595 * encrypt the data, offset and valid values
596 */
597 rc = KCipherEncryptCBC (self->ciphers.block,
598 self->block.data, e->data,
599 (sizeof self->block.data + sizeof self->block.u) / sizeof (ivec));
600 if (rc)
601 return rc;
602
603 self->block.u.valid = saved_valid;
604
605 crc = CRC32 (0, e, (char*)(&e->crc)-(char*)e);
606
607 self->block.crc = crc;
608
609 if (self->bswap)
610 {
611 crc = bswap_32 (crc);
612 }
613 e->crc_copy = e->crc = crc;
614
615 return 0;
616 }
617
618
619 /* ----------
620 * BlockDecrypt
621 * decrypt decrypts the data from a KEncFileBlock into the KEncFileBlock
622 * in the KEncFile object
623 */
624
625 static
KEncFileV1BlockDecrypt(KEncFileV1 * self,KEncFileBlock * e)626 rc_t KEncFileV1BlockDecrypt (KEncFileV1 * self, KEncFileBlock * e)
627 {
628 uint8_t ivec [16];
629 rc_t rc;
630
631 assert (self);
632 assert (e);
633
634 /* create the initialization vector for this block */
635 KEncFileV1IVecInit (self, ivec);
636
637 /*
638 * set the ivec for both the master and data block ciphers
639 */
640 rc = KCipherSetDecryptIVec (self->ciphers.master, ivec);
641 if (rc)
642 return rc;
643
644 rc = KCipherSetDecryptIVec (self->ciphers.block, ivec);
645 if (rc)
646 return rc;
647
648 /*
649 * decrypt the block key and initial vector using the user key and
650 * the computer ivec
651 */
652 rc = KCipherDecryptCBC (self->ciphers.master, e->key, self->block.key,
653 (sizeof e->key) / sizeof ivec);
654 if (rc)
655 return rc;
656
657 /*
658 * now create the AES key for the block from the newly decrypted
659 * block key
660 */
661 rc = KCipherSetDecryptKey (self->ciphers.block, self->block.key,
662 sizeof self->block.key);
663 if (rc)
664 return rc;
665 rc = KCipherDecryptCBC (self->ciphers.block, e->data,
666 self->block.data,
667 (sizeof e->data + sizeof e->u) / sizeof ivec);
668 if (rc)
669 return rc;
670
671 if (self->bswap)
672 {
673 self->block.u.valid = bswap_16 (self->block.u.valid);
674 /* self->block.id = bswap_64 (self->block.id); */
675 }
676
677 /* we choose not to flag errors in decryption so don't validate these */
678 if (self->block.u.valid & 0x8000)
679 self->block.u.valid = 0x8000;
680
681 return rc;
682 }
683
684
685 /* ----------
686 * BlockRead
687 * read a requested block from the encrypted file;
688 * decryption is a separate step
689 */
690 static
KEncFileV1BlockRead(const KEncFileV1 * cself,uint64_t block_id,KEncFileBlock * block,bool validate)691 rc_t KEncFileV1BlockRead (const KEncFileV1 * cself, uint64_t block_id,
692 KEncFileBlock * block, bool validate)
693 {
694 KEncFileV1 * self; /* mutable fields */
695 uint64_t pos;
696 uint64_t max;
697 size_t num_read;
698 rc_t rc;
699 KEncFileBlock e;
700
701 assert (cself);
702 assert (block);
703
704 self = (KEncFileV1*)cself;
705 pos = BlockId_to_CiphertextOffset ( block_id );
706
707 /* set aside the current maximum position within the encrypted file */
708 max = self->encrypted_max;
709
710 memset (&self->block, 0, sizeof self->block);
711 self->block.id = block_id;
712 self->block.u.valid = 0;
713 self->dirty = false;
714
715 rc = KEncFileV1BufferRead (self, pos, &e, sizeof e, &num_read);
716 if (rc)
717 PLOGERR (klogErr,
718 (klogErr, rc,
719 "error in reading block '$(BID)' from encrypted file",
720 "BID=%lu", block_id));
721 else
722 {
723 uint32_t crc;
724
725 /* we'll judge the success of the read now on how many bytes read
726 * there are only three legitimate values:
727 * + size of a block
728 * + size of a footer
729 * + zero meaning no footer yet
730 *
731 * This might have to change to handled streamed files where the
732 * producer jsut hasn't finished yet
733 */
734 switch (num_read)
735 {
736 default: /* bad value means a truncated file most likely */
737 rc = RC (rcKrypto, rcFile, rcReading, rcFile, rcInsufficient);
738 PLOGERR (klogErr,
739 (klogErr, rc, "wrong size reading block '$(B)' at '$(P)' "
740 "from encrypted file - likely truncated", "B=%lu,P=%lu",
741 block_id, pos));
742 break;
743
744 case sizeof e:
745 if (max <= pos) /* if we hadn't read this far do accounting */
746 {
747 if (self->bswap)
748 {
749 e.crc = bswap_32 (e.crc);
750 e.id = bswap_64 (e.id);
751 }
752
753 if (block_id != e.id)
754 {
755 PLOGERR (klogErr,
756 (klogErr,
757 RC (rcKrypto, rcFile, rcValidating, rcIndex, rcIncorrect),
758 "error validating id for block '$(BID)' is not $(C2)",
759 "BID=%lu,C2=%lu", block_id, e.id));
760 }
761
762 if (validate)
763 {
764 crc = CRC32 (0, &e, (char*)(&e.crc)-(char*)&e);
765
766
767 if (crc != e.crc)
768 {
769 PLOGERR (klogErr,
770 (klogErr,
771 RC (rcKrypto, rcFile, rcValidating, rcCrc, rcCorrupt),
772 "error validating crc for block '$(BID)' $(C1) is not $(C2)",
773 "BID=%lu,C1=0x%X,C2=0x%X", block_id,
774 crc, e.crc));
775 }
776 }
777
778 ++self->foot.block_count;
779 /* Byte Endian problem! */
780 self->foot.crc_checksum += e.crc;
781 }
782 memmove (block, &e, sizeof e);
783 self->eof = false;
784 break;
785
786 case sizeof (self->foot):
787 {
788 KEncFileFooter foot;
789 memmove (&foot, &e, sizeof foot);
790 if (self->bswap)
791 {
792 foot.block_count = bswap_64 (foot.block_count);
793 foot.crc_checksum = bswap_64 (foot.crc_checksum);
794 }
795 if (validate && !self->written)
796 {
797 rc = KEncFileV1FooterValidate (self, foot.block_count,
798 foot.crc_checksum);
799 if (rc)
800 break;
801 }
802 }
803 /* fall through */
804 case 0:
805 self->block.u.valid = 0;
806 self->block.crc = 0;
807 self->eof = true;
808 return 0;
809
810 }
811 }
812 return rc;
813 }
814
815 static
KEncFileV1BlockWrite(KEncFileV1 * self)816 rc_t KEncFileV1BlockWrite (KEncFileV1 * self)
817 {
818 KEncFileBlock e;
819 uint64_t block_offset;
820 size_t num_writ;
821 rc_t rc;
822
823 assert (self);
824
825 if (self->block.u.valid > sizeof self->block.data)
826 return RC (rcFS, rcFile, rcWriting, rcBuffer, rcCorrupt);
827
828 /* where in the file is this block */
829 block_offset = BlockId_to_CiphertextOffset ( self -> block . id );
830
831 /* if this is an update to a block take out the old crc value */
832 if (block_offset < self->encrypted_max)
833 self->foot.crc_checksum -= self->block.crc;
834
835 /* if it's not we need to add it as a new block in the count */
836 else
837 ++self->foot.block_count;
838
839 rc = KEncFileV1BlockEncrypt (self, &e);
840 if (rc)
841 return rc;
842
843 /* Byte Endian problem */
844 self->foot.crc_checksum += self->block.crc;
845
846 /* now write the buffer to the encrypted file */
847 rc = KEncFileV1BufferWrite (self, block_offset, &e, sizeof e, &num_writ);
848
849 if ((rc == 0) && (num_writ != sizeof e))
850 {
851 rc = RC (rcFS, rcFile, rcWriting, rcFile, rcTooShort);
852 PLOGERR (klogErr,
853 (klogErr, rc, "incomplete block write '$(B)' wanted"
854 " '$(V)' got '$(N)'", "B=%lu,V=%u,N=%u",
855 self->foot.block_count+1, self->block.u.valid, num_writ));
856 }
857 return rc;
858 }
859
860
861 static
KEncFileV1BlockFlush(KEncFileV1 * self)862 rc_t KEncFileV1BlockFlush (KEncFileV1 *self)
863 {
864 rc_t rc = 0;
865
866 assert (self);
867 assert (self->block.u.valid);
868 assert (self->block.u.valid <= sizeof (self->block.data));
869
870 /* first do we need to deal with the file header?
871 * if the encrypted file has not been written to we do */
872 if ((self->encrypted_max == 0) && (self->swarm == false))
873 {
874 rc = KEncFileV1HeaderWrite (self);
875 if (rc)
876 return rc;
877 }
878
879 if (self->dirty)
880 {
881 rc = KEncFileV1BlockWrite (self);
882 if (rc == 0)
883 self->dirty = false;
884 }
885 return rc;
886 }
887
888
889 /*
890 * block_id - which block to read and decrypt
891 * fill - if not false, we fill in zero blocks up through this block
892 *
893 */
894 static
KEncFileV1BlockSeek(KEncFileV1 * self,uint64_t block_id,bool fill,bool validate)895 rc_t KEncFileV1BlockSeek (KEncFileV1 * self, uint64_t block_id, bool fill, bool validate)
896 {
897 KEncFileBlock b;
898 rc_t rc;
899
900 if (block_id != self->block.id)
901 {
902 if (self->dirty)
903 {
904 /* flush what we got */
905 rc = KEncFileV1BlockFlush (self);
906 if (rc)
907 return rc;
908 }
909
910 if (validate && (block_id > self->block.id))
911 {
912 uint64_t tid;
913
914 for (tid = self->block.id + 1; tid < block_id; ++tid)
915 {
916 if ( self -> encrypted_max > BlockId_to_CiphertextOffset ( block_id ) )
917 continue;
918
919 memset (&b, 0, sizeof b);
920
921 rc = KEncFileV1BlockRead (self, tid, &b, validate);
922 if (rc)
923 return rc;
924
925 if (self->eof)
926 {
927 if (fill)
928 {
929 self->eof = false;
930 memset (self->block.data, 0, sizeof (self->block.data));
931 self->block.u.valid = sizeof (self->block.data);
932 self->dirty = true;
933 rc = KEncFileV1BlockFlush (self);
934 if (rc)
935 return rc;
936 }
937 else
938 return 0;
939 }
940 /* in this loop a less than full block is end of file */
941 else if (fill)
942 {
943 rc = KEncFileV1BlockDecrypt (self, &b);
944 if (rc)
945 return rc;
946
947 if (self->block.u.valid < sizeof self->block.u.valid)
948 {
949 memset (self->block.data + self->block.u.valid, 0,
950 sizeof (self->block.data) - self->block.u.valid);
951 self->dirty = true;
952 rc = KEncFileV1BlockFlush (self);
953 if (rc)
954 return rc;
955 }
956 else
957 {
958 return 0;
959 }
960 }
961 }
962 }
963 }
964 /* done with intervening blocks */
965 memset (&b, 0, sizeof b);
966
967 rc = KEncFileV1BlockRead (self, block_id, &b, validate);
968 if (rc)
969 return rc;
970
971 if (! self->eof)
972 {
973 rc = KEncFileV1BlockDecrypt (self, &b);
974 }
975 if (fill)
976 {
977 self->block.id = block_id;
978 self->block.u.valid = 0;
979 }
980 return rc;
981 }
982
983
984 /* ----------------------------------------------------------------------
985 * Interface Functions
986 *
987 * Destroy
988 *
989 */
990 static
KEncFileV1DestroyRead(KEncFileV1 * self)991 rc_t CC KEncFileV1DestroyRead (KEncFileV1 *self)
992 {
993 rc_t rc1 = 0;
994 rc_t rc2 = 0;
995 rc_t rc3 = 0;
996
997 if (self)
998 {
999 rc1 = KFileRelease (self->encrypted);
1000 rc2 = KCipherRelease (self->ciphers.master);
1001 rc3 = KCipherRelease (self->ciphers.block);
1002 free (self);
1003 return rc1 ? rc1 : rc2 ? rc2 : rc3;
1004 }
1005 return 0;
1006 }
1007
1008
1009 static
KEncFileV1DestroyWrite(KEncFileV1 * self)1010 rc_t CC KEncFileV1DestroyWrite (KEncFileV1 *self)
1011 {
1012 rc_t rc1;
1013 rc_t rc2;
1014
1015 rc1 = (self->block.u.valid) ? KEncFileV1BlockFlush (self) : 0;
1016 if ((rc1 == 0)&&(self->encrypted_max != 0))
1017 rc1 = KEncFileV1FooterWrite (self);
1018 rc2 = KFileRelease (self->encrypted);
1019
1020 return (rc1 ? rc1 : rc2);
1021 }
1022
1023
1024 static
KEncFileV1DestroySwarm(KEncFileV1 * self)1025 rc_t CC KEncFileV1DestroySwarm (KEncFileV1 *self)
1026 {
1027 rc_t rc1 = 0;
1028 rc_t rc2 = 0;
1029 rc_t rc3 = 0;
1030
1031 if (self)
1032 {
1033 rc1 = KFileRelease (self->encrypted);
1034 rc2 = KCipherRelease (self->ciphers.master);
1035 rc3 = KCipherRelease (self->ciphers.block);
1036 free (self);
1037 return rc1 ? rc1 : rc2 ? rc2 : rc3;
1038 }
1039 return 0;
1040 }
1041
1042
1043 /* ----------------------------------------------------------------------
1044 * GetSysFile
1045 * returns an underlying system file object
1046 * and starting offset to contiguous region
1047 * suitable for memory mapping, or NULL if
1048 * no such file is available.
1049 *
1050 * We do not allow this for read, write or update as you can not memory map the
1051 * unencrypted file in a meaningful way.
1052 */
1053 static
KEncFileV1GetSysFileUnsupported(const KEncFileV1 * self,uint64_t * offset)1054 struct KSysFile *CC KEncFileV1GetSysFileUnsupported (const KEncFileV1 *self, uint64_t *offset)
1055 {
1056 assert (self);
1057 assert (offset);
1058 return NULL;
1059 }
1060
1061
1062 /* ----------------------------------------------------------------------
1063 * RandomAccess
1064 *
1065 * returns 0 if random access, error code otherwise
1066 */
1067 static
KEncFileV1RandomAccess(const KEncFileV1 * self)1068 rc_t CC KEncFileV1RandomAccess (const KEncFileV1 *self)
1069 {
1070 assert (self != NULL);
1071 assert (self->encrypted != NULL);
1072 return KFileRandomAccess (self->encrypted);
1073 }
1074
1075
1076 static
KEncFileV1RandomAccessUnsupported(const KEncFileV1 * self)1077 rc_t CC KEncFileV1RandomAccessUnsupported (const KEncFileV1 *self)
1078 {
1079 return RC ( rcFS, rcFile, rcUpdating, rcFunction, rcUnsupported );
1080 }
1081
1082
1083 /* ----------------------------------------------------------------------
1084 * Size
1085 * returns size in bytes of file
1086 *
1087 * "size" [ OUT ] - return parameter for file size
1088 */
1089 static
KEncFileV1SizeUnsupported(const KEncFileV1 * self,uint64_t * size)1090 rc_t CC KEncFileV1SizeUnsupported (const KEncFileV1 *self, uint64_t *size)
1091 {
1092 return RC ( rcFS, rcFile, rcAccessing, rcFunction, rcUnsupported );
1093 }
1094
1095
1096 /* ----------------------------------------------------------------------
1097 * SetSize
1098 * sets size in bytes of file
1099 *
1100 * "size" [ IN ] - new file size
1101 */
1102 static
KEncFileV1SetSizeUnsupported(KEncFileV1 * self,uint64_t size)1103 rc_t CC KEncFileV1SetSizeUnsupported (KEncFileV1 *self, uint64_t size)
1104 {
1105 assert (self);
1106 return RC ( rcFS, rcFile, rcUpdating, rcFunction, rcUnsupported );
1107 }
1108
1109
1110 /* ----------------------------------------------------------------------
1111 * Read
1112 * read file from known position
1113 *
1114 * "pos" [ IN ] - starting position within file
1115 *
1116 * "buffer" [ OUT ] and "bsize" [ IN ] - return buffer for read
1117 *
1118 * "num_read" [ OUT, NULL OKAY ] - optional return parameter
1119 * giving number of bytes actually read
1120 */
1121 static
KEncFileV1ReadUnsupported(const KEncFileV1 * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)1122 rc_t CC KEncFileV1ReadUnsupported (const KEncFileV1 *self,
1123 uint64_t pos,
1124 void *buffer,
1125 size_t bsize,
1126 size_t *num_read)
1127 {
1128 return RC ( rcFS, rcFile, rcReading, rcFunction, rcUnsupported );
1129 }
1130
1131
1132 static
KEncFileV1Read(const KEncFileV1 * cself,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)1133 rc_t CC KEncFileV1Read (const KEncFileV1 *cself,
1134 uint64_t pos,
1135 void *buffer,
1136 size_t bsize,
1137 size_t *num_read)
1138 {
1139 KEncFileV1 * self = (KEncFileV1 *)cself; /* mutable values */
1140 uint64_t block_id;
1141 uint32_t offset;
1142 size_t to_copy;
1143 rc_t rc = 0;
1144
1145 assert (self); /* checked in file.c KFileRead() */
1146 /* pos can be 'anything' */
1147 assert (buffer); /* checked in file.c KFileRead() */
1148 assert (bsize); /* checked in file.c KFileRead() */
1149 assert (num_read); /* checked in file.c KFileRead() */
1150
1151 *num_read = 0;
1152
1153 block_id = PlaintextOffset_to_BlockId (pos, &offset);
1154
1155 /*
1156 * are we on the wrong block?
1157 * Or are do we need to read the first block?
1158 */
1159 if ((block_id != self->block.id) || (self->block.u.valid == 0))
1160 {
1161 rc = KEncFileV1BlockSeek (self, block_id, false, false);
1162 if (rc)
1163 return rc;
1164 }
1165
1166 /*
1167 * if we are trying to read past the end of the file
1168 * return 0 with nothing read
1169 */
1170 if (self->eof || (block_id != self->block.id) ||
1171 (offset >= self->block.u.valid))
1172 return 0;
1173
1174 to_copy = self->block.u.valid - offset;
1175 if (to_copy > bsize)
1176 to_copy = bsize;
1177
1178 memmove (buffer, self->block.data + offset, to_copy);
1179 *num_read = to_copy;
1180
1181 return 0;
1182 }
1183
1184
1185 /* ----------------------------------------------------------------------
1186 * Write
1187 * write file at known position
1188 *
1189 * "pos" [ IN ] - starting position within file
1190 *
1191 * "buffer" [ IN ] and "size" [ IN ] - data to be written
1192 *
1193 * "num_writ" [ OUT, NULL OKAY ] - optional return parameter
1194 * giving number of bytes actually written
1195 *
1196 * Unsupported as we now treat archives as READ ONLY
1197 */
1198 static
KEncFileV1WriteUnsupported(KEncFileV1 * self,uint64_t pos,const void * buffer,size_t bsize,size_t * num_writ)1199 rc_t CC KEncFileV1WriteUnsupported (KEncFileV1 *self, uint64_t pos,
1200 const void *buffer, size_t bsize,
1201 size_t *num_writ)
1202 {
1203 rc_t rc = RC (rcFS, rcFile, rcReading, rcFunction, rcUnsupported);
1204 LOGERR (klogInt, rc, "KFileRead failed to filter call");
1205 return rc;
1206 }
1207
1208 static
KEncFileV1WriteInt(KEncFileV1 * self,uint64_t block_id,uint32_t block_offset,const void * buffer,size_t bsize,size_t * pnum_writ,bool seek)1209 rc_t KEncFileV1WriteInt (KEncFileV1 *self, uint64_t block_id, uint32_t block_offset,
1210 const void *buffer, size_t bsize,
1211 size_t *pnum_writ, bool seek)
1212 {
1213 const uint8_t * pb;
1214 size_t tot_writ;
1215 rc_t rc;
1216
1217 assert (self);
1218 assert (self->block.u.valid <= sizeof (self->block.data));
1219 assert (block_offset < sizeof (self->block.data));
1220 assert (buffer);
1221 assert (bsize);
1222 assert (pnum_writ);
1223
1224 if (seek)
1225 {
1226 /* if we need to change blocks */
1227 if (block_id != self->block.id)
1228 {
1229 rc = KEncFileV1BlockSeek (self, block_id, true, false);
1230 if (rc)
1231 return rc;
1232 }
1233 /* do we have to fill some of this block */
1234 if (self->block.u.valid < block_id)
1235 {
1236 memset (self->block.data + self->block.u.valid, 0,
1237 block_offset - self->block.u.valid);
1238 self->block.u.valid = block_offset;
1239 }
1240 }
1241
1242 /*
1243 * is the full write within this block?
1244 * doesn't matter whether we are skipping back or not
1245 */
1246 if ((block_offset + bsize) <= sizeof (self->block.data))
1247 {
1248 memmove (self->block.data + block_offset, buffer, bsize);
1249 self->dirty = true;
1250 if (block_offset + bsize > self->block.u.valid)
1251 self->block.u.valid = (KEncFileBlockValid) ( block_offset + bsize );
1252 *pnum_writ = bsize;
1253 return 0;
1254 }
1255
1256 /* we are either forcing ourselves backward or not */
1257 else
1258 self->block.u.valid = block_offset;
1259
1260 /* by this point we are 'at' the right place in the file */
1261 /* do we have an existing (possibly partial) block? */
1262
1263 /* change to a sized target pointer */
1264 pb = buffer;
1265 tot_writ = 0;
1266
1267 /* handle this first block with some data in it */
1268 if (self->block.u.valid != 0)
1269 {
1270 size_t remaining;
1271
1272 /* how many bytes left in this block */
1273 remaining = sizeof self->block.data - self->block.u.valid;
1274
1275 memmove (self->block.data + self->block.u.valid, buffer, remaining);
1276 self->block.u.valid = sizeof self->block.data;
1277
1278 self->dirty = true;
1279 rc = KEncFileV1BlockFlush (self);
1280 if (rc)
1281 {
1282 LOGERR (klogErr, rc, "error flushing block in encrypt");
1283 return rc;
1284 }
1285
1286 tot_writ = remaining;
1287 pb += remaining;
1288 bsize -= remaining;
1289 ++block_id;
1290 }
1291
1292 /* now loop through complete blocks to write */
1293 for (; bsize >= sizeof self->block.data; bsize -= sizeof self->block.data)
1294 {
1295 memmove (self->block.data, pb, sizeof self->block.data);
1296
1297 self->block.u.valid = sizeof self->block.data;
1298 self->block.id = block_id;
1299 self->dirty = true;
1300 rc = KEncFileV1BlockFlush (self);
1301 if (rc)
1302 {
1303 LOGERR (klogErr, rc, "error flushing block in encrypt");
1304 return rc;
1305 }
1306 pb += sizeof self->block.data;
1307 tot_writ += sizeof self->block.data;
1308 ++block_id;
1309 }
1310
1311 /* now any last partial block that starts at the beginning of a block */
1312 if (bsize != 0)
1313 {
1314 KEncFileBlock b;
1315
1316 if ( self -> encrypted_max > BlockId_to_CiphertextOffset ( block_id ) )
1317 {
1318 rc = KEncFileV1BlockRead (self, block_id, &b, false);
1319 if (rc)
1320 return rc;
1321 /* if valid is not 0 we actually read something */
1322 if (b.u.valid)
1323 rc = KEncFileV1BlockDecrypt (self, &b);
1324 }
1325 else
1326 {
1327 self->block.u.valid = 0;
1328 self->block.id = block_id;
1329 }
1330
1331 memmove (self->block.data, pb, bsize);
1332
1333 if (bsize > self->block.u.valid)
1334 self->block.u.valid = (KEncFileBlockValid) bsize;
1335
1336 self->dirty = true;
1337 tot_writ += bsize;
1338 }
1339 *pnum_writ = tot_writ;
1340 return 0;
1341 }
1342
1343
1344 static
KEncFileV1Write(KEncFileV1 * self,uint64_t pos,const void * buffer,size_t bsize,size_t * pnum_writ)1345 rc_t CC KEncFileV1Write (KEncFileV1 *self, uint64_t pos,
1346 const void *buffer, size_t bsize,
1347 size_t *pnum_writ)
1348 {
1349 uint64_t block_id;
1350 uint64_t curr_block_id;
1351 uint32_t block_offset;
1352 uint32_t curr_block_offset;
1353 rc_t rc = 0;
1354
1355 /* -----
1356 * check for incorrect call with a seek attempt
1357 * we only allow seeks on read or read/write files
1358 *
1359 * find our location in the encrypted file by block id
1360 * and offset
1361 */
1362 block_id = PlaintextOffset_to_BlockId (pos, &block_offset);
1363 curr_block_id = PlaintextOffset_to_BlockId
1364 ( BlockId_to_PlaintextOffset ( self -> block . id ) + self -> block . u . valid,
1365 &curr_block_offset);
1366
1367 /* are we writing to the wrong block/offset? */
1368 if ((block_id != curr_block_id) || (block_offset != curr_block_offset))
1369 {
1370 rc = RC (rcFS, rcFile, rcWriting, rcOffset, rcIncorrect);
1371 PLOGERR (klogErr, (klogErr, rc, "attempt to seek in encryption write at"
1372 " '$(O)' seek to '$(P)'", "O=%lu,P=%lu",
1373 BlockId_to_CiphertextOffset ( self -> block . id ), pos ) );
1374 }
1375 else
1376 {
1377 if ((block_id != 0) && (block_id != self->block.id))
1378 {
1379 rc = KEncFileV1BlockFlush (self);
1380 if (rc == 0)
1381 {
1382 ++self->block.id;
1383 self->block.u.valid = 0;
1384 }
1385 }
1386
1387 if (rc == 0)
1388 rc = KEncFileV1WriteInt (self, block_id, block_offset, buffer,
1389 bsize, pnum_writ, false);
1390 }
1391 return rc;
1392 }
1393
1394
1395 static
KEncFileV1WriteSwarm(KEncFileV1 * self,uint64_t pos,const void * buffer,size_t bsize,size_t * pnum_writ)1396 rc_t CC KEncFileV1WriteSwarm (KEncFileV1 *self, uint64_t pos,
1397 const void *buffer, size_t bsize,
1398 size_t *pnum_writ)
1399 {
1400 uint32_t block_offset;
1401 rc_t rc;
1402
1403 self->block.id = PlaintextOffset_to_BlockId (pos, &block_offset);
1404 self->block.u.valid = 0;
1405 if (bsize > sizeof self->block.data - block_offset)
1406 bsize = sizeof self->block.data - block_offset;
1407
1408 rc = KEncFileV1WriteInt (self, self->block.id, block_offset, buffer,
1409 bsize, pnum_writ, false);
1410 if (rc == 0)
1411 rc = KEncFileV1BlockFlush (self);
1412 return rc;
1413 }
1414
1415
1416 /* ----------------------------------------------------------------------
1417 * Type
1418 * returns a KFileDesc
1419 * not intended to be a content type,
1420 * but rather an implementation class
1421 */
1422 static
KEncFileV1Type(const KEncFileV1 * self)1423 uint32_t CC KEncFileV1Type (const KEncFileV1 *self)
1424 {
1425 assert (self != NULL);
1426 assert (self->encrypted != NULL);
1427
1428 return KFileType (self->encrypted);
1429 }
1430
1431
1432 /* ----------------------------------------------------------------------
1433 * KEncFileV1Make
1434 * create a new file object
1435 */
1436
1437 /* ----------
1438 * KeysInit
1439 */
1440 static
KEncFileV1CiphersInit(KEncFileV1 * self,const KKey * key,bool read,bool write)1441 rc_t KEncFileV1CiphersInit (KEncFileV1 * self, const KKey * key, bool read, bool write)
1442 {
1443 KCipherManager * mgr;
1444 size_t z;
1445 rc_t rc;
1446
1447 switch ( key->type)
1448 {
1449 default:
1450 return RC (rcKrypto, rcEncryptionKey, rcConstructing, rcParam, rcInvalid);
1451
1452 case kkeyNone:
1453 return RC (rcKrypto, rcEncryptionKey, rcConstructing, rcParam, rcIncorrect);
1454
1455 case kkeyAES128:
1456 z = 128/8; break;
1457
1458 case kkeyAES192:
1459 z = 192/8; break;
1460
1461 case kkeyAES256:
1462 z = 256/8; break;
1463 }
1464 rc = KCipherManagerMake (&mgr);
1465 if (rc == 0)
1466 {
1467 rc = KCipherManagerMakeCipher (mgr, &self->ciphers.master, kcipher_AES);
1468 if (rc == 0)
1469 {
1470 rc = KCipherManagerMakeCipher (mgr, &self->ciphers.block, kcipher_AES);
1471 if (rc == 0)
1472 {
1473 rc = KCipherSetDecryptKey (self->ciphers.master, key->text, z);
1474 if (rc == 0)
1475 {
1476 rc = KCipherSetEncryptKey (self->ciphers.master, key->text, z);
1477 if (rc == 0)
1478 goto keep_ciphers;
1479 }
1480 KCipherRelease (self->ciphers.block);
1481 self->ciphers.block = NULL;
1482 }
1483 KCipherRelease (self->ciphers.master);
1484 self->ciphers.master = NULL;
1485 }
1486 keep_ciphers:
1487 KCipherManagerRelease (mgr);
1488 }
1489 return rc;
1490 }
1491
1492
1493
1494 /* ----------
1495 * MakeInt
1496 * common make for all encryptor/decryptors
1497 */
1498 static
KEncFileV1MakeInt(KEncFileV1 ** pself,KFile * encrypted,const KFile_vt_v1 * vt,bool r,bool w,bool v)1499 rc_t KEncFileV1MakeInt (KEncFileV1 ** pself, KFile * encrypted,
1500 const KFile_vt_v1 * vt, bool r, bool w, bool v)
1501 {
1502 KEncFileV1 * self;
1503 rc_t rc;
1504
1505 assert (pself);
1506 assert (encrypted);
1507
1508 /* allocate and zero out an object since we want much of it to be zeroed */
1509 self = calloc (sizeof *self, 1);
1510 if (self == NULL)
1511 {
1512 rc = RC (rcFS, rcFile, rcConstructing, rcMemory, rcExhausted);
1513 LOGERR (klogSys, rc,
1514 "out of memory creating encrypter and/or decryptor");
1515 }
1516 else
1517 {
1518 /* all KFiles get this initialization */
1519 rc = KFileInit (&self->dad, (const KFile_vt*)vt, "KEncFileV1", "no-name", r, w);
1520 if (rc)
1521 LOGERR (klogInt, rc, "failure initialize encrypted file root class");
1522 else
1523 {
1524 rc = KFileAddRef (encrypted);
1525 if (rc == 0)
1526 {
1527 self->encrypted = encrypted;
1528 *pself = self;
1529 return 0;
1530 }
1531 }
1532 free (self);
1533 }
1534 return rc;
1535 }
1536
1537
1538 /* ----------
1539 * MakeCmn
1540 * common parameter validation for all encryptor/decryptors
1541 */
1542 static
KEncFileV1MakeCmn(KEncFileV1 ** pself,KFile * encrypted,const KKey * key,const KFile_vt_v1 * vt,bool r,bool w)1543 rc_t KEncFileV1MakeCmn (KEncFileV1 ** pself, KFile * encrypted, const KKey * key,
1544 const KFile_vt_v1 * vt, bool r, bool w)
1545 {
1546 rc_t rc = 0;
1547
1548 do
1549 {
1550 CRC32Init(); /* likely to be called way too often */
1551
1552 if (pself == NULL)
1553 {
1554 rc = RC (rcFS, rcFile, rcConstructing, rcSelf, rcNull);
1555 LOGERR (klogErr, rc,
1556 "pointer to self NULL when creating "
1557 "an encryptor/decryptor");
1558 break;
1559 }
1560 *pself = NULL;
1561
1562 if (encrypted == NULL)
1563 {
1564 rc = RC (rcFS, rcFile, rcConstructing, rcParam, rcNull);
1565 LOGERR (klogErr, rc,
1566 "encrypted file not supplied when creating "
1567 "an encryptor/decryptor");
1568 break;
1569 }
1570
1571 if (key == NULL)
1572 {
1573 rc = RC (rcFS, rcFile, rcConstructing, rcParam, rcNull);
1574 LOGERR (klogErr, rc,
1575 "key not supplied when creating an encryptor/decryptor");
1576 break;
1577 }
1578
1579 switch (key->type)
1580 {
1581 default:
1582 rc = RC (rcFS, rcFile, rcConstructing, rcParam, rcInvalid);
1583 PLOGERR (klogErr,
1584 (klogErr, rc, "invalid key type '$(T)' should be "
1585 "kkeyAES128(1), kkeyAES192(2) or kkeyAES256(3)",
1586 "T=%u", key->type));
1587 break;
1588
1589 case kkeyAES128:
1590 case kkeyAES192:
1591 case kkeyAES256:
1592 break;
1593 }
1594 if (rc == 0)
1595 {
1596 KEncFileV1 * self;
1597
1598 assert (vt);
1599 assert ((r == true) || (r == false));
1600 assert ((w == true) || (w == false));
1601
1602 rc = KEncFileV1MakeInt (&self, encrypted, vt, r, w, false);
1603 if (rc == 0)
1604 {
1605 rc = KEncFileV1CiphersInit (self, key, r, w);
1606 if (rc == 0)
1607 {
1608 *pself = self;
1609 return 0;
1610 }
1611 KFileRelease (&self->dad);
1612 }
1613 }
1614 } while (0);
1615 return rc;
1616 }
1617
1618
1619
1620 static const KFile_vt_v1 vtKEncFileV1Read =
1621 {
1622 /* version */
1623 1, 1,
1624
1625 /* 1.0 */
1626 KEncFileV1DestroyRead,
1627 KEncFileV1GetSysFileUnsupported,
1628 KEncFileV1RandomAccess,
1629 KEncFileV1SizeUnsupported,
1630 KEncFileV1SetSizeUnsupported,
1631 KEncFileV1Read,
1632 KEncFileV1WriteUnsupported,
1633
1634 /* 1.1 */
1635 KEncFileV1Type
1636 };
1637 static const KFile_vt_v1 vtKEncFileV1Write =
1638 {
1639 /* version */
1640 1, 1,
1641
1642 /* 1.0 */
1643 KEncFileV1DestroyWrite,
1644 KEncFileV1GetSysFileUnsupported,
1645 KEncFileV1RandomAccessUnsupported,
1646 KEncFileV1SizeUnsupported,
1647 KEncFileV1SetSizeUnsupported,
1648 KEncFileV1ReadUnsupported,
1649 KEncFileV1Write,
1650
1651 /* 1.1 */
1652 KEncFileV1Type
1653 };
1654 static const KFile_vt_v1 vtKEncFileV1Update =
1655 {
1656 /* version */
1657 1, 1,
1658
1659 /* 1.0 */
1660 KEncFileV1DestroySwarm,
1661 KEncFileV1GetSysFileUnsupported,
1662 KEncFileV1RandomAccess,
1663 KEncFileV1SizeUnsupported,
1664 KEncFileV1SetSizeUnsupported,
1665 KEncFileV1ReadUnsupported,
1666 KEncFileV1WriteSwarm,
1667
1668 /* 1.1 */
1669 KEncFileV1Type
1670 };
1671 static const KFile_vt_v1 vtKEncFileV1Validate =
1672 {
1673 /* version */
1674 1, 1,
1675
1676 /* 1.0 */
1677 KEncFileV1DestroyRead,
1678 KEncFileV1GetSysFileUnsupported,
1679 KEncFileV1RandomAccessUnsupported,
1680 KEncFileV1SizeUnsupported,
1681 KEncFileV1SetSizeUnsupported,
1682 KEncFileV1ReadUnsupported,
1683 KEncFileV1WriteUnsupported,
1684
1685 /* 1.1 */
1686 KEncFileV1Type
1687 };
1688
1689
1690 /* ----------
1691 * Read mode is fully seekable if the underlying KFile is seekable some
1692 * integrity checking will not be performed in allowing this seeking.
1693 */
KEncFileMakeRead_v1(const KFile ** pself,const KFile * encrypted,const KKey * key)1694 LIB_EXPORT rc_t CC KEncFileMakeRead_v1 (const KFile ** pself,
1695 const KFile * encrypted,
1696 const KKey * key)
1697 {
1698 KEncFileV1 * self;
1699 rc_t rc;
1700 rc = KEncFileV1MakeCmn (&self, (KFile *)encrypted, key, &vtKEncFileV1Read,
1701 true, false);
1702 if (rc)
1703 LOGERR (klogErr, rc, "error constructing decryptor");
1704 else
1705 {
1706 rc = KEncFileV1HeaderRead (self);
1707 if (rc)
1708 LOGERR (klogErr, rc, "error reading encrypted file header");
1709 else
1710 {
1711 *pself = &self->dad;
1712 return 0;
1713 }
1714 KFileRelease (&self->dad);
1715 }
1716 return rc;
1717 }
1718
1719
1720 /* ----------
1721 * Write mode encrypted file can only be written straight through form the
1722 * first byte to the last.
1723 */
KEncFileMakeWrite_v1(KFile ** pself,KFile * encrypted,const KKey * key)1724 LIB_EXPORT rc_t CC KEncFileMakeWrite_v1 (KFile ** pself,
1725 KFile * encrypted,
1726 const KKey * key)
1727 {
1728 KEncFileV1 * self;
1729 rc_t rc;
1730
1731 rc = KFileSetSize (encrypted, 0);
1732 #if 0
1733 if (rc)
1734 LOGERR (klogWarn, rc, "error truncating output file - "
1735 "corrupted file might result");
1736 #endif
1737
1738 rc = KEncFileV1MakeCmn (&self, encrypted, key, &vtKEncFileV1Write,
1739 false, true);
1740 if (rc)
1741 LOGERR (klogErr, rc, "error creating encryptor");
1742 else
1743 *pself = &self->dad;
1744 return rc;
1745 }
1746
1747
1748 /* ----------
1749 * Update mode is read/write mode where seeking within the file is allowed.
1750 */
1751
1752
KEncFileV1MakeUpdate_v1(KFile ** pself,KFile * encrypted,const KKey * key)1753 LIB_EXPORT rc_t CC KEncFileV1MakeUpdate_v1 (KFile ** pself,
1754 KFile * encrypted,
1755 const KKey * key)
1756 {
1757 KEncFileV1 * self;
1758 rc_t rc;
1759
1760 rc = KEncFileV1MakeCmn (&self, encrypted, key, &vtKEncFileV1Update,
1761 false, true);
1762 if (rc)
1763 LOGERR (klogErr, rc, "error creating encryptor");
1764 else
1765 {
1766 self->swarm = true;
1767 *pself = &self->dad;
1768 }
1769 return rc;
1770 }
1771
1772
1773 /* ----------
1774 * Validate mode is useful only for the KFileEncValidate function
1775 */
1776 static
KEncFileV1MakeValidate(const KEncFileV1 ** pself,const KFile * encrypted)1777 rc_t KEncFileV1MakeValidate (const KEncFileV1 ** pself, const KFile * encrypted)
1778 {
1779 KEncFileV1 * self;
1780 rc_t rc;
1781
1782 assert (pself);
1783 assert (encrypted);
1784
1785 rc = KEncFileV1MakeInt (&self, (KFile*)encrypted, &vtKEncFileV1Validate, true, false, true);
1786 if (rc)
1787 LOGERR (klogErr, rc, "error making KEncFileV1");
1788 else
1789 {
1790 rc = KEncFileV1HeaderRead (self);
1791 if (rc)
1792 LOGERR (klogErr, rc, "error reading encrypted file header");
1793 else
1794 {
1795 *pself = self;
1796 return 0;
1797 }
1798 }
1799 *pself = NULL;
1800 return rc;
1801 }
1802
1803
1804 /* ----------
1805 * Validate mode can not be read or written.
1806 * Upon open the whole file is read from begining to end and all CRC
1807 * and other integrity checks are performed immedaitely
1808 */
KEncFileV1Validate_v1(const KFile * encrypted)1809 LIB_EXPORT rc_t CC KEncFileV1Validate_v1 (const KFile * encrypted)
1810 {
1811 const KEncFileV1 * file;
1812 rc_t rc;
1813
1814 /* fail if a NULL parameter: can't validate all addresses */
1815 if (encrypted == NULL)
1816 {
1817 rc = RC (rcKrypto, rcFile, rcValidating, rcParam, rcNull);
1818 LOGERR (klogErr, rc, "encrypted file was null when trying to validate");
1819 return rc;
1820 }
1821
1822 /* if the parameter is already a KEncFileV1 work on the file behind it instead */
1823 /* we definitely can't work on a file being written that has not been closed */
1824 if (encrypted->vt == (const KFile_vt*)&vtKEncFileV1Read)
1825 encrypted = (const KFile *)(((const KEncFileV1*)encrypted)->encrypted);
1826
1827 /* file header is validated within the call to Make Validate */
1828 rc = KEncFileV1MakeValidate (&file, encrypted);
1829 if (rc)
1830 LOGERR (klogErr, rc,
1831 "unable to validate encrypted file due to "
1832 "inability to open as encrypted file");
1833 else
1834 {
1835 uint64_t pos; /* position within the encrypted file */
1836 uint64_t block_count = 0; /* how many blocks have we read */
1837
1838 /* loop through all data blocks */
1839 pos = sizeof (KEncFileHeader);
1840 for (block_count = 0; ; ++block_count)
1841 {
1842 KEncFileBlock block;
1843
1844 STSMSG (2, ("reading block '%u' at '%lu'", block_count,
1845 BlockId_to_CiphertextOffset ( block_count ) ) );
1846
1847 rc = KEncFileV1BlockRead (file, block_count, &block, true);
1848 if (rc)
1849 {
1850 STSMSG (2, ("read error at block '%u'", block_count));
1851 break;
1852 }
1853 if (file->eof)
1854 {
1855 STSMSG (2, ("block '%u' was end", block_count));
1856
1857 break;
1858 }
1859 pos += sizeof (KEncFileData);
1860 }
1861 KFileRelease (&file->dad);
1862 }
1863 return (rc);
1864 }
1865
1866
KFileIsEnc_v1(const char * buffer,size_t buffer_size)1867 LIB_EXPORT rc_t CC KFileIsEnc_v1 (const char * buffer, size_t buffer_size)
1868 {
1869 const KEncFileHeader * header;
1870
1871 if ((buffer == NULL) || (buffer_size == 0))
1872 return RC (rcFS, rcFile, rcIdentifying, rcParam, rcNull);
1873
1874 header = (const KEncFileHeader*)buffer;
1875
1876 if (buffer_size < sizeof header->file_sig)
1877 return RC (rcFS, rcFile, rcIdentifying, rcBuffer, rcInsufficient);
1878
1879 if (buffer_size > sizeof (*header))
1880 buffer_size = sizeof (*header);
1881
1882 if ((memcmp (header, &const_header, buffer_size) == 0) ||
1883 (memcmp (header, &const_bswap_header, buffer_size) == 0)
1884 #if ENABLE_V2
1885 ||
1886 (memcmp (header, &const_header_v1, buffer_size) == 0) ||
1887 (memcmp (header, &const_bswap_header_v1, buffer_size) == 0)
1888 #endif
1889 )
1890 return 0;
1891
1892 return RC (rcFS, rcFile, rcIdentifying, rcFile, rcWrongType);
1893 }
1894
1895
1896
1897 /* ----------
1898 * Read mode is fully seekable if the underlying KFile is seekable some
1899 * integrity checking will not be performed in allowing this seeking.
1900 */
KEncFileMakeRead(const struct KFile ** pself,const struct KFile * encrypted_input,const struct KKey * key)1901 LIB_EXPORT rc_t CC KEncFileMakeRead (const struct KFile ** pself,
1902 const struct KFile * encrypted_input,
1903 const struct KKey * key)
1904 {
1905 #if USE_READ_V1
1906 return KEncFileV1MakeRead_v1 (pself, encrypted_input, key);
1907 #else
1908 return KEncFileMakeRead_v2 (pself, encrypted_input, key);
1909 #endif
1910 }
1911
1912
1913 /* ----------
1914 * Write mode encrypted file can only be written straight through from the
1915 * first byte to the last.
1916 */
KEncFileMakeWrite(struct KFile ** pself,struct KFile * encrypted_output,const struct KKey * key)1917 LIB_EXPORT rc_t CC KEncFileMakeWrite (struct KFile ** pself,
1918 struct KFile * encrypted_output,
1919 const struct KKey * key)
1920 {
1921 #if USE_WRITE_V1
1922 return KEncFileV1MakeWrite_v1 (pself, encrypted_output, key);
1923 #else
1924 return KEncFileMakeWrite_v2 (pself, encrypted_output, key);
1925 #endif
1926 }
1927
1928 /* ----------
1929 * Update mode is read/write mode where seeking within the file is allowed.
1930 *
1931 * NOTE this is in the private interface because it is not actually working
1932 * yet.
1933 */
KEncFileMakeUpdate(struct KFile ** pself,struct KFile * encrypted,const struct KKey * key)1934 LIB_EXPORT rc_t CC KEncFileMakeUpdate (struct KFile ** pself,
1935 struct KFile * encrypted,
1936 const struct KKey * key)
1937 {
1938 #if USE_UPDATE_V1
1939 return KEncFileV1MakeUpdate_v1 (pself, encrypted, key);
1940 #else
1941 return KEncFileMakeUpdate_v2 (pself, encrypted, key);
1942 #endif
1943 }
KEncFileMakeWriteBlock(struct KFile ** pself,struct KFile * encrypted,const struct KKey * key)1944 LIB_EXPORT rc_t CC KEncFileMakeWriteBlock (struct KFile ** pself,
1945 struct KFile * encrypted,
1946 const struct KKey * key)
1947 {
1948 #if USE_BLOCK_V1
1949 return KEncFileV1MakeUpdate_v1 (pself, encrypted, key);
1950 #else
1951 return KEncFileMakeBlock_v2 (pself, encrypted, key);
1952 #endif
1953 }
1954
1955
KEncFileWriteHeader(KFile * self)1956 LIB_EXPORT rc_t CC KEncFileWriteHeader (KFile * self)
1957 {
1958 #if USE_BLOCK_V1
1959 return KEncFileV1WriteHeader_v1 (self);
1960 #else
1961 return KEncFileWriteHeader_v2 (self);
1962 #endif
1963 }
1964
1965
1966 /* ----------
1967 * Validate mode can not be read or written.
1968 * Upon open the whole file is read from begining to end and all CRC
1969 * and other integrity checks are performed immedaitely
1970 */
KEncFileValidate(const struct KFile * encrypted)1971 LIB_EXPORT rc_t CC KEncFileValidate (const struct KFile * encrypted)
1972 {
1973 #if USE_VALIDATE_V1
1974 return KEncFileV1Validate_v1 (encrypted);
1975 #else
1976 return KEncFileValidate_v2 (encrypted);
1977 #endif
1978 }
1979
1980
1981 /* ----------
1982 * Identify whether a file is a KEncFile type encrypted file by the header.
1983 * read the header into a buffer and pass it into this function.
1984 * The buffer_size needs to be at least 8 but more bytes lead to a better
1985 * check up to the size of the header of a KEncFile type encrypted file.
1986 * As the header may change in the future (in a backwards compatible way)
1987 * that size might change from the current 16.
1988 *
1989 * Possible returns:
1990 * 0:
1991 * the file is an identified KEncFile type file. False positives are
1992 * possible if a file happens to match at 8 or more bytes
1993 *
1994 * RC (rcFS, rcFile, rcIdentifying, rcFile, rcWrongType)
1995 * the file is definitely not a KEncFile type encrypted file.
1996 *
1997 * RC (rcFS, rcFile, rcIdentifying, rcParam, rcNull)
1998 * bad parameters in the call
1999 *
2000 * RC (rcFS, rcFile, rcIdentifying, rcBuffer, rcInsufficient)
2001 * not a large enough buffer to make an identification
2002 */
KFileIsEnc(const char * buffer,size_t buffer_size)2003 LIB_EXPORT rc_t CC KFileIsEnc (const char * buffer, size_t buffer_size)
2004 {
2005 #if USE_ISENC_V1
2006 return KFileIsEnc_v1 (buffer, buffer_size);
2007 #else
2008 return KFileIsEnc_v2 (buffer, buffer_size);
2009 #endif
2010 }
2011
2012
2013
2014 #ifdef __cplusplus
2015 }
2016 #endif
2017
2018
2019
2020 /* end of file encfile.c */
2021
2022