state.c - dedup - deduplicating backup program
 (HTM) git clone git://bitreich.org/dedup/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/dedup/
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
       state.c (5150B)
       ---
            1 /* Routines to read and write repository parameters */
            2 #include <assert.h>
            3 #include <errno.h>
            4 #include <stdint.h>
            5 #include <stdio.h>
            6 #include <string.h>
            7 #include <strings.h>
            8 
            9 #include <sodium.h>
           10 
           11 #include "config.h"
           12 #include "misc.h"
           13 #include "state.h"
           14 
           15 #define VMIN            0
           16 #define VMAJ            1
           17 #define VMINMASK        0xff
           18 #define VMAJSHIFT       8
           19 #define VMAJMASK        0xff
           20 
           21 #define CALGOSHIFT      16
           22 #define CALGOMASK       0x7
           23 #define CNONETYPE       0
           24 #define CSNAPPYTYPE     1
           25 #define CLZ4TYPE        2
           26 
           27 #define EALGOSHIFT      19
           28 #define EALGOMASK       0x7
           29 #define ENONETYPE       0
           30 #define ECHACHATYPE     1
           31 
           32 #define NONCESIZE        crypto_aead_xchacha20poly1305_ietf_NPUBBYTES
           33 #define MSEEDSIZE        4
           34 #define CSEEDSIZE        (MSEEDSIZE + crypto_aead_xchacha20poly1305_ietf_ABYTES)
           35 #define SHDRSIZE        (8 + NONCESIZE + CSEEDSIZE)
           36 
           37 /* misc helpers */
           38 extern int pack(unsigned char *, char *, ...);
           39 extern int unpack(unsigned char *, char *, ...);
           40 
           41 struct shdr {
           42         uint64_t flags;
           43         unsigned char nonce[NONCESIZE];
           44         unsigned char seed[CSEEDSIZE];
           45 };
           46 
           47 /* Unpack state header */
           48 static int
           49 unpackshdr(unsigned char *buf, struct shdr *shdr)
           50 {
           51         char fmt[BUFSIZ];
           52         int n;
           53 
           54         snprintf(fmt, sizeof(fmt), "q'%d'%d", NONCESIZE, CSEEDSIZE);
           55         n = unpack(buf, fmt,
           56                    &shdr->flags,
           57                    shdr->nonce,
           58                    shdr->seed);
           59         assert(n == SHDRSIZE);
           60         return n;
           61 }
           62 
           63 /* Pack state header */
           64 static int
           65 packshdr(unsigned char *buf, struct shdr *shdr)
           66 {
           67         char fmt[BUFSIZ];
           68         int n;
           69 
           70         snprintf(fmt, sizeof(fmt), "q'%d'%d", NONCESIZE, CSEEDSIZE);
           71         n = pack(buf, fmt,
           72                  shdr->flags,
           73                  shdr->nonce,
           74                  shdr->seed);
           75         assert(n == SHDRSIZE);
           76         return n;
           77 }
           78 
           79 int
           80 writestate(int fd, struct param *par)
           81 {
           82         unsigned char buf[SHDRSIZE];
           83         struct shdr shdr;
           84 
           85         if (sodium_init() < 0) {
           86                 seterr("sodium_init: failed");
           87                 return -1;
           88         }
           89 
           90         /* Set version */
           91         shdr.flags = (VMAJ << VMAJSHIFT) | VMIN;
           92 
           93         /* Set compression type */
           94         if (strcasecmp(par->calgo, "none") == 0) {
           95                 shdr.flags |= CNONETYPE << CALGOSHIFT;
           96         } else if (strcasecmp(par->calgo, "snappy") == 0) {
           97                 shdr.flags |= CSNAPPYTYPE << CALGOSHIFT;
           98         } else if (strcasecmp(par->calgo, "lz4") == 0) {
           99                 shdr.flags |= CLZ4TYPE << CALGOSHIFT;
          100         } else {
          101                 seterr("invalid compression type: %s", par->calgo);
          102                 return -1;
          103         }
          104 
          105         /* Clear seed + authentication tag */
          106         memset(shdr.seed, 0, sizeof(shdr.seed));
          107 
          108         /* Pack seed */
          109         shdr.seed[0] = par->seed;
          110         shdr.seed[1] = par->seed >> 8;
          111         shdr.seed[2] = par->seed >> 16;
          112         shdr.seed[3] = par->seed >> 24;
          113 
          114         /* Set encryption type */
          115         if (strcasecmp(par->ealgo, "none") == 0) {
          116                 shdr.flags |= ENONETYPE << EALGOSHIFT;
          117                 memset(shdr.nonce, 0, sizeof(shdr.nonce));
          118         } else if (strcasecmp(par->ealgo, "XChaCha20-Poly1305") == 0) {
          119                 unsigned long long elen;
          120 
          121                 shdr.flags |= ECHACHATYPE << EALGOSHIFT;
          122                 randombytes_buf(shdr.nonce, sizeof(shdr.nonce));
          123                 crypto_aead_xchacha20poly1305_ietf_encrypt(shdr.seed, &elen,
          124                                                            shdr.seed, MSEEDSIZE,
          125                                                            NULL, 0, NULL,
          126                                                            shdr.nonce, par->key);
          127                 assert(elen == CSEEDSIZE);
          128         } else {
          129                 seterr("invalid encryption type: %s", par->ealgo);
          130                 return -1;
          131         }
          132 
          133         packshdr(buf, &shdr);
          134         if (xwrite(fd, buf, SHDRSIZE) != SHDRSIZE) {
          135                 seterr("failed to write state header: %s", strerror(errno));
          136                 return -1;
          137         }
          138         return 0;
          139 }
          140 
          141 int
          142 readstate(int fd, struct param *par)
          143 {
          144         unsigned char buf[SHDRSIZE];
          145         struct shdr shdr;
          146         unsigned long long dlen;
          147         int algo;
          148 
          149         if (sodium_init() < 0) {
          150                 seterr("sodium_init: failed");
          151                 return -1;
          152         }
          153 
          154         if (xread(fd, buf, SHDRSIZE) != SHDRSIZE) {
          155                 seterr("failed to read state header: %s", strerror(errno));
          156                 return -1;
          157         }
          158         unpackshdr(buf, &shdr);
          159 
          160         /* If the major version is different, the format is incompatible */
          161         if (((shdr.flags >> VMAJSHIFT) & VMAJMASK) != VMAJ) {
          162                 seterr("state header version mismatch");
          163                 return -1;
          164         }
          165 
          166         /* Populate param compression algo */
          167         algo = (shdr.flags >> CALGOSHIFT) & CALGOMASK;
          168         switch (algo) {
          169         case CNONETYPE:
          170                 par->calgo = "none";
          171                 break;
          172         case CSNAPPYTYPE:
          173                 par->calgo = "snappy";
          174                 break;
          175         case CLZ4TYPE:
          176                 par->calgo = "lz4";
          177                 break;
          178         default:
          179                 seterr("invalid compression type: %d", algo);
          180                 return -1;
          181         }
          182 
          183         /* Populate param encryption algo */
          184         algo = (shdr.flags >> EALGOSHIFT) & EALGOMASK;
          185         switch (algo) {
          186         case ENONETYPE:
          187                 par->ealgo = "none";
          188                 break;
          189         case ECHACHATYPE:
          190                 par->ealgo = "XChaCha20-Poly1305";
          191                 if (crypto_aead_xchacha20poly1305_ietf_decrypt(shdr.seed, &dlen,
          192                                                                NULL,
          193                                                                shdr.seed, CSEEDSIZE,
          194                                                                NULL, 0,
          195                                                                shdr.nonce, par->key) < 0) {
          196                         seterr("authentication failed");
          197                         return -1;
          198                 }
          199                 assert(dlen == MSEEDSIZE);
          200                 break;
          201         default:
          202                 seterr("invalid encryption type: %d", algo);
          203                 return -1;
          204         }
          205 
          206         /* Unpack seed */
          207         par->seed = (uint32_t)shdr.seed[0];
          208         par->seed |= (uint32_t)shdr.seed[1] << 8;
          209         par->seed |= (uint32_t)shdr.seed[2] << 16;
          210         par->seed |= (uint32_t)shdr.seed[3] << 24;
          211 
          212         return 0;
          213 }