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