URI: 
       Add support for storing/retrieving an encrypted seed - dedup - deduplicating backup program
  HTML git clone git://bitreich.org/dedup/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/dedup/
   DIR Log
   DIR Files
   DIR Refs
   DIR Tags
   DIR README
   DIR LICENSE
       ---
   DIR commit eba08d1ff6618f1b3277dea6990a0afde7a0bc11
   DIR parent 042e687f46e7c334def143a387c332e6884cd078
  HTML Author: sin <sin@2f30.org>
       Date:   Sun, 19 May 2019 19:26:12 +0300
       
       Add support for storing/retrieving an encrypted seed
       
       The seed is XOR-ed with the initial state of the chunker to mitigate
       against fingerprinting attacks.
       
       Diffstat:
         M dup-gc.c                            |       1 +
         M dup-init.c                          |      34 ++++++++++++++++++++-----------
         M dup-keygen.c                        |       1 +
         M dup-pack.c                          |       3 ++-
         M dup-rm.c                            |       1 +
         M dup-unpack.c                        |       1 +
         M state.c                             |      63 +++++++++++++++++++++++++++++--
         M state.h                             |       9 +++++----
       
       8 files changed, 93 insertions(+), 20 deletions(-)
       ---
   DIR diff --git a/dup-gc.c b/dup-gc.c
       @@ -4,6 +4,7 @@
        #include <err.h>
        #include <fcntl.h>
        #include <limits.h>
       +#include <stdint.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
   DIR diff --git a/dup-init.c b/dup-init.c
       @@ -4,11 +4,14 @@
        #include <err.h>
        #include <fcntl.h>
        #include <limits.h>
       +#include <stdint.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <strings.h>
        #include <unistd.h>
        
       +#include <sodium.h>
       +
        #include "arg.h"
        #include "block.h"
        #include "config.h"
       @@ -40,21 +43,21 @@ savestate(char *repo)
        }
        
        static void
       -loadkey(char *keyfile)
       +loadkey(char *keyf)
        {
                int fd;
        
       -        if (keyfile == NULL)
       +        if (keyf == NULL)
                        return;
        
       -        fd = open(keyfile, O_RDONLY);
       +        fd = open(keyf, O_RDONLY);
                if (fd < 0)
       -                err(1, "open: %s", keyfile);
       +                err(1, "open: %s", keyf);
                if (readkey(fd, param.key, sizeof(param.key)) < 0)
       -                printerr("readkey: %s", keyfile);
       +                printerr("readkey: %s", keyf);
                param.keyloaded = 1;
                if (close(fd) < 0)
       -                err(1, "close: %s", keyfile);
       +                err(1, "close: %s", keyf);
        }
        
        static void
       @@ -70,7 +73,7 @@ main(int argc, char *argv[])
                char spath[PATH_MAX];
                char bpath[PATH_MAX];
                struct bctx *bctx;
       -        char *keyfile = NULL;
       +        char *keyf = NULL;
                char *repo;
                int lfd;
        
       @@ -79,7 +82,7 @@ main(int argc, char *argv[])
        
                ARGBEGIN {
                case 'k':
       -                keyfile = EARGF(usage());
       +                keyf = EARGF(usage());
                        break;
                case 'E':
                        param.ealgo = EARGF(usage());
       @@ -105,9 +108,16 @@ main(int argc, char *argv[])
                        usage();
                };
        
       -        if (strcasecmp(param.ealgo, "XChaCha20-Poly1305") == 0 &&
       -            keyfile == NULL)
       -                errx(1, "expected encryption key");
       +        if (strcasecmp(param.ealgo, "none") == 0) {
       +                param.seed = 0;
       +        } else if (strcasecmp(param.ealgo, "XChaCha20-Poly1305") == 0) {
       +                if (keyf == NULL)
       +                        errx(1, "expected encryption key");
       +                param.seed = randombytes_uniform(0xffffffff);
       +        }
       +
       +        if (sodium_init() < 0)
       +                errx(1, "sodium_init: failed");
        
                if (snprintf(spath, sizeof(spath), "%s/%s",
                             repo, ARCHIVEPATH) >= sizeof(spath))
       @@ -125,7 +135,7 @@ main(int argc, char *argv[])
                if (mkdir(spath, 0700) < 0)
                        err(1, "mkdir: %s", spath);
        
       -        loadkey(keyfile);
       +        loadkey(keyf);
                savestate(repo);
        
                if (bcreat(bpath, 0600, &bctx) < 0)
   DIR diff --git a/dup-keygen.c b/dup-keygen.c
       @@ -3,6 +3,7 @@
        
        #include <err.h>
        #include <fcntl.h>
       +#include <stdint.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
   DIR diff --git a/dup-pack.c b/dup-pack.c
       @@ -63,7 +63,8 @@ pack(struct sctx *sctx, struct bctx *bctx)
        {
                struct chunker *c;
        
       -        if ((c = copen(0, BSIZEMIN, BSIZEMAX, HMASKBITS, WINSIZE, 0)) == NULL)
       +        if ((c = copen(0, BSIZEMIN, BSIZEMAX, HMASKBITS, WINSIZE,
       +                       param.seed)) == NULL)
                        printerr("copen");
        
                while (cfill(c) > 0) {
   DIR diff --git a/dup-rm.c b/dup-rm.c
       @@ -4,6 +4,7 @@
        #include <err.h>
        #include <fcntl.h>
        #include <limits.h>
       +#include <stdint.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
   DIR diff --git a/dup-unpack.c b/dup-unpack.c
       @@ -4,6 +4,7 @@
        #include <err.h>
        #include <fcntl.h>
        #include <limits.h>
       +#include <stdint.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
   DIR diff --git a/state.c b/state.c
       @@ -6,6 +6,8 @@
        #include <string.h>
        #include <strings.h>
        
       +#include <sodium.h>
       +
        #include "config.h"
        #include "misc.h"
        #include "state.h"
       @@ -27,7 +29,9 @@
        #define ENONETYPE       0
        #define ECHACHATYPE     1
        
       -#define SHDRSIZE        8
       +#define MSEEDSIZE        4
       +#define CSEEDSIZE        (MSEEDSIZE + 16)
       +#define SHDRSIZE        (8 + 24 + CSEEDSIZE)
        
        /* misc helpers */
        extern int pack(unsigned char *, char *, ...);
       @@ -35,6 +39,8 @@ extern int unpack(unsigned char *, char *, ...);
        
        struct shdr {
                uint64_t flags;
       +        unsigned char nonce[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES];
       +        unsigned char seed[CSEEDSIZE];
        };
        
        /* Unpack state header */
       @@ -43,7 +49,10 @@ unpackshdr(unsigned char *buf, struct shdr *shdr)
        {
                int n;
        
       -        n = unpack(buf, "q", &shdr->flags);
       +        n = unpack(buf, "q'24'20",
       +                   &shdr->flags,
       +                   shdr->nonce,
       +                   shdr->seed);
                assert(n == SHDRSIZE);
                return n;
        }
       @@ -54,7 +63,10 @@ packshdr(unsigned char *buf, struct shdr *shdr)
        {
                int n;
        
       -        n = pack(buf, "q", shdr->flags);
       +        n = pack(buf, "q'24'20",
       +                 shdr->flags,
       +                 shdr->nonce,
       +                 shdr->seed);
                assert(n == SHDRSIZE);
                return n;
        }
       @@ -65,6 +77,11 @@ writestate(int fd, struct param *par)
                unsigned char buf[SHDRSIZE];
                struct shdr shdr;
        
       +        if (sodium_init() < 0) {
       +                seterr("sodium_init: failed");
       +                return -1;
       +        }
       +
                /* Set version */
                shdr.flags = (VMAJ << VMAJSHIFT) | VMIN;
        
       @@ -80,11 +97,29 @@ writestate(int fd, struct param *par)
                        return -1;
                }
        
       +        /* Clear seed + authentication tag */
       +        memset(shdr.seed, 0, sizeof(shdr.seed));
       +
       +        /* Pack seed */
       +        shdr.seed[0] = par->seed;
       +        shdr.seed[1] = par->seed >> 8;
       +        shdr.seed[2] = par->seed >> 16;
       +        shdr.seed[3] = par->seed >> 24;
       +
                /* Set encryption type */
                if (strcasecmp(par->ealgo, "none") == 0) {
                        shdr.flags |= ENONETYPE << EALGOSHIFT;
       +                memset(shdr.nonce, 0, sizeof(shdr.nonce));
                } else if (strcasecmp(par->ealgo, "XChaCha20-Poly1305") == 0) {
       +                unsigned long long elen;
       +
                        shdr.flags |= ECHACHATYPE << EALGOSHIFT;
       +                randombytes_buf(shdr.nonce, sizeof(shdr.nonce));
       +                crypto_aead_xchacha20poly1305_ietf_encrypt(shdr.seed, &elen,
       +                                                           shdr.seed, MSEEDSIZE,
       +                                                           NULL, 0, NULL,
       +                                                           shdr.nonce, par->key);
       +                assert(elen == CSEEDSIZE);
                } else {
                        seterr("invalid encryption type: %s", par->ealgo);
                        return -1;
       @@ -103,8 +138,14 @@ readstate(int fd, struct param *par)
        {
                unsigned char buf[SHDRSIZE];
                struct shdr shdr;
       +        unsigned long long dlen;
                int algo;
        
       +        if (sodium_init() < 0) {
       +                seterr("sodium_init: failed");
       +                return -1;
       +        }
       +
                if (xread(fd, buf, SHDRSIZE) != SHDRSIZE) {
                        seterr("failed to read state header: %s", strerror(errno));
                        return -1;
       @@ -142,10 +183,26 @@ readstate(int fd, struct param *par)
                        break;
                case ECHACHATYPE:
                        par->ealgo = "XChaCha20-Poly1305";
       +                if (crypto_aead_xchacha20poly1305_ietf_decrypt(shdr.seed, &dlen,
       +                                                               NULL,
       +                                                               shdr.seed, CSEEDSIZE,
       +                                                               NULL, 0,
       +                                                               shdr.nonce, par->key) < 0) {
       +                        seterr("authentication failed");
       +                        return -1;
       +                }
       +                assert(dlen == MSEEDSIZE);
                        break;
                default:
                        seterr("invalid encryption type: %d", algo);
                        return -1;
                }
       +
       +        /* Unpack seed */
       +        par->seed = (uint32_t)shdr.seed[0];
       +        par->seed |= (uint32_t)shdr.seed[1] << 8;
       +        par->seed |= (uint32_t)shdr.seed[2] << 16;
       +        par->seed |= (uint32_t)shdr.seed[3] << 24;
       +
                return 0;
        }
   DIR diff --git a/state.h b/state.h
       @@ -1,8 +1,9 @@
        struct param {
       -        char *calgo;
       -        char *ealgo;
       -        unsigned char key[KEYSIZE];
       -        int keyloaded;
       +        char *calgo;                        /* compression algorithm */
       +        char *ealgo;                        /* encryption algorithm */
       +        unsigned char key[KEYSIZE];        /* secret key */
       +        int keyloaded;                        /* 1 if key is loaded, 0 otherwise */
       +        uint32_t seed;                        /* XOR-ed with initial state of chunker */
        };
        
        extern int writestate(int, struct param *);