URI: 
       Encrypt/authenticate snapshot metadata - 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 72ba1a8a75b1990156ec209538cc00498efcb43d
   DIR parent 9c6cdcc42dc9b0def23ed2839cb528f3867f9cfb
  HTML Author: sin <sin@2f30.org>
       Date:   Sun, 12 May 2019 15:24:55 +0100
       
       Encrypt/authenticate snapshot metadata
       
       Diffstat:
         M bencrypt.c                          |       2 +-
         M snap.c                              |     197 +++++++++++++++++++++++++------
       
       2 files changed, 160 insertions(+), 39 deletions(-)
       ---
   DIR diff --git a/bencrypt.c b/bencrypt.c
       @@ -112,7 +112,7 @@ becreat(struct bctx *bctx, char *path, int mode)
                        return -1;
                }
        
       -        /* Ensure that if caller requested encryption, a key was provided */
       +        /* Ensure a key has been provided if caller requested encryption */
                if (type != EDNONETYPE && !param.keyloaded) {
                        seterr("expected encryption key");
                        return -1;
   DIR diff --git a/snap.c b/snap.c
       @@ -10,6 +10,7 @@
        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
       +#include <strings.h>
        #include <unistd.h>
        
        #include <sodium.h>
       @@ -18,6 +19,7 @@
        #include "misc.h"
        #include "queue.h"
        #include "snap.h"
       +#include "state.h"
        
        /* snapshot header constants */
        #define SHDRMAGIC        "SNAPSNAPPYSNOOP"
       @@ -29,7 +31,9 @@
        #define VMAJSHIFT        8
        #define VMAJMASK        0xff
        
       -#define SHDRSIZE        (NSHDRMAGIC + 24 + 24 + 8 + 8)
       +#define SHDRSIZE        (NSHDRMAGIC + 24 + 8 + 8)
       +
       +extern struct param param;
        
        /* misc helpers */
        extern int pack(unsigned char *, char *, ...);
       @@ -38,7 +42,6 @@ extern int unpack(unsigned char *, char *, ...);
        /* Snapshot header structure */
        struct shdr {
                char magic[NSHDRMAGIC];                /* magic number for file(1) */
       -        unsigned char nonce[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES];
                unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES];
                uint64_t flags;                        /* version number */
                uint64_t nbd;                        /* number of block hashes */
       @@ -52,6 +55,7 @@ struct mdnode {
        struct sctx {
                TAILQ_HEAD(mdhead, mdnode) mdhead;        /* list of hashes contained in snapshot */
                struct mdnode *mdnext;                        /* next hash to be returned via sget() */
       +        int crypto;                                /* when set, snapshots are encrypted */
                int fd;                                        /* underlying snapshot file descriptor */
                int rdonly;                                /* when set, ssync() is a no-op */
                struct shdr shdr;                        /* snapshot header */
       @@ -69,9 +73,8 @@ unpackshdr(int fd, struct shdr *shdr)
                        return -1;
                }
        
       -        n = unpack(buf, "'16'24'24qq",
       +        n = unpack(buf, "'16'24qq",
                           shdr->magic,
       -                   shdr->nonce,
                           shdr->header,
                           &shdr->flags,
                           &shdr->nbd);
       @@ -87,9 +90,8 @@ packshdr(int fd, struct shdr *shdr)
                unsigned char buf[SHDRSIZE];
                int n;
        
       -        n = pack(buf, "'16'24'24qq",
       +        n = pack(buf, "'16'24qq",
                         shdr->magic,
       -                 shdr->nonce,
                         shdr->header,
                         shdr->flags,
                         shdr->nbd);
       @@ -103,52 +105,99 @@ packshdr(int fd, struct shdr *shdr)
        }
        
        static int
       -loadmd(struct sctx *sctx)
       +initmdhead(struct sctx *sctx)
        {
       -        struct mdnode *mdnode;
       +        unsigned char ad[SHDRSIZE];
       +        struct shdr *shdr;
       +        uint64_t i;
        
       -        mdnode = calloc(1, sizeof(*mdnode));
       -        if (mdnode == NULL) {
       -                seterr("calloc: %s", strerror(errno));
       +        if (lseek(sctx->fd, 0, SEEK_SET) < 0) {
       +                seterr("lseek: %s", strerror(errno));
                        return -1;
                }
       -        if (xread(sctx->fd, mdnode->md, MDSIZE) != MDSIZE) {
       -                free(mdnode);
       -                seterr("failed to read block hash: %s", strerror(errno));
       +
       +        if (xread(sctx->fd, ad, sizeof(ad)) != sizeof(ad)) {
       +                seterr("failed to read snapshot header: %s\n", strerror(errno));
                        return -1;
                }
       -        TAILQ_INSERT_TAIL(&sctx->mdhead, mdnode, e);
       -        return 0;
       -}
       -
       -static int
       -initmdhead(struct sctx *sctx)
       -{
       -        struct shdr *shdr;
       -        uint64_t i;
        
                shdr = &sctx->shdr;
       -        for (i = 0; i < shdr->nbd; i++) {
       -                if (loadmd(sctx) == 0)
       -                        continue;
       +        if (sctx->crypto) {
       +                crypto_secretstream_xchacha20poly1305_state state;
       +                struct shdr *shdr;
       +
       +                shdr = &sctx->shdr;
       +                if (crypto_secretstream_xchacha20poly1305_init_pull(&state,
       +                                                                    shdr->header,
       +                                                                    param.key) != 0) {
       +                        seterr("invalid crypto header");
       +                        return -1;
       +                }
        
       -                /* Cleanup */
       -                while (!TAILQ_EMPTY(&sctx->mdhead)) {
       +                for (i = 0; i < shdr->nbd; i++) {
       +                        unsigned char buf[MDSIZE + crypto_secretstream_xchacha20poly1305_ABYTES];
       +                        unsigned char md[MDSIZE];
       +                        struct mdnode *mdnode;
       +                        unsigned char tag;
       +
       +                        if (xread(sctx->fd, buf, sizeof(buf)) != sizeof(buf)) {
       +                                seterr("failed to read block hash: %s", strerror(errno));
       +                                goto err0;
       +                        }
       +
       +                        if (crypto_secretstream_xchacha20poly1305_pull(&state, md, NULL, &tag,
       +                                                                       buf, sizeof(buf),
       +                                                                       ad, sizeof(ad)) != 0) {
       +                                seterr("authentication failed");
       +                                goto err0;
       +                        }
       +
       +                        mdnode = calloc(1, sizeof(*mdnode));
       +                        if (mdnode == NULL) {
       +                                seterr("calloc: %s", strerror(errno));
       +                                goto err0;
       +                        }
       +                        memcpy(mdnode->md, md, MDSIZE);
       +                        TAILQ_INSERT_TAIL(&sctx->mdhead, mdnode, e);
       +                }
       +        } else {
       +                for (i = 0; i < shdr->nbd; i++) {
       +                        unsigned char md[MDSIZE];
                                struct mdnode *mdnode;
        
       -                        mdnode = TAILQ_FIRST(&sctx->mdhead);
       -                        TAILQ_REMOVE(&sctx->mdhead, mdnode, e);
       -                        free(mdnode);
       +                        if (xread(sctx->fd, md, MDSIZE) != MDSIZE) {
       +                                seterr("failed to read block hash: %s", strerror(errno));
       +                                goto err0;
       +                        }
       +
       +                        mdnode = calloc(1, sizeof(*mdnode));
       +                        if (mdnode == NULL) {
       +                                seterr("calloc: %s", strerror(errno));
       +                                goto err0;
       +                        }
       +                        memcpy(mdnode->md, md, MDSIZE);
       +                        TAILQ_INSERT_TAIL(&sctx->mdhead, mdnode, e);
                        }
       -                return -1;
                }
                return 0;
       +
       +err0:
       +        /* Cleanup */
       +        while (!TAILQ_EMPTY(&sctx->mdhead)) {
       +                struct mdnode *mdnode;
       +
       +                mdnode = TAILQ_FIRST(&sctx->mdhead);
       +                TAILQ_REMOVE(&sctx->mdhead, mdnode, e);
       +                free(mdnode);
       +        }
       +        return -1;
        }
        
        int
        screat(char *path, int mode, struct sctx **sctx)
        {
                struct shdr *shdr;
       +        int crypto;
                int fd;
        
                if (path == NULL || sctx == NULL) {
       @@ -156,6 +205,22 @@ screat(char *path, int mode, struct sctx **sctx)
                        return -1;
                }
        
       +        /* Determine algorithm type */
       +        if (strcasecmp(param.ealgo, "none") == 0) {
       +                crypto = 0;
       +        } else if (strcasecmp(param.ealgo, "XChaCha20-Poly1305") == 0) {
       +                crypto = 1;
       +        } else {
       +                seterr("invalid encryption type: %s", param.ealgo);
       +                return -1;
       +        }
       +
       +        /* Ensure a key has been provided if caller requested encryption */
       +        if (crypto && !param.keyloaded) {
       +                seterr("expected encryption key");
       +                return -1;
       +        }
       +
                if (sodium_init() < 0) {
                        seterr("sodium_init: failed");
                        return -1;
       @@ -176,6 +241,7 @@ screat(char *path, int mode, struct sctx **sctx)
        
                TAILQ_INIT(&(*sctx)->mdhead);
                (*sctx)->mdnext = NULL;
       +        (*sctx)->crypto = crypto;
                (*sctx)->fd = fd;
        
                shdr = &(*sctx)->shdr;
       @@ -196,6 +262,7 @@ int
        sopen(char *path, int flags, int mode, struct sctx **sctx)
        {
                struct shdr *shdr;
       +        int crypto;
                int fd;
        
                if (path == NULL || sctx == NULL) {
       @@ -209,6 +276,16 @@ sopen(char *path, int flags, int mode, struct sctx **sctx)
                        return -1;
                }
        
       +        /* Determine algorithm type */
       +        if (strcasecmp(param.ealgo, "none") == 0) {
       +                crypto = 0;
       +        } else if (strcasecmp(param.ealgo, "XChaCha20-Poly1305") == 0) {
       +                crypto = 1;
       +        } else {
       +                seterr("invalid encryption type: %s", param.ealgo);
       +                return -1;
       +        }
       +
                if (sodium_init() < 0) {
                        seterr("sodium_init: failed");
                        return -1;
       @@ -229,6 +306,7 @@ sopen(char *path, int flags, int mode, struct sctx **sctx)
        
                TAILQ_INIT(&(*sctx)->mdhead);
                (*sctx)->mdnext = NULL;
       +        (*sctx)->crypto = crypto;
                (*sctx)->fd = fd;
                (*sctx)->rdonly = 1;
        
       @@ -340,16 +418,59 @@ ssync(struct sctx *sctx)
                }
        
                shdr = &sctx->shdr;
       -        if (packshdr(sctx->fd, shdr) < 0)
       -                return -1;
       -        TAILQ_FOREACH(mdnode, &sctx->mdhead, e) {
       -                if (xwrite(sctx->fd, mdnode->md, MDSIZE) != MDSIZE) {
       -                        seterr("failed to write block hash: %s",
       -                                strerror(errno));
       +        if (sctx->crypto) {
       +                unsigned char ad[SHDRSIZE];
       +                crypto_secretstream_xchacha20poly1305_state state;
       +
       +                crypto_secretstream_xchacha20poly1305_init_push(&state,
       +                                                                shdr->header,
       +                                                                param.key);
       +
       +                if (packshdr(sctx->fd, shdr) < 0)
       +                        return -1;
       +
       +                if (lseek(sctx->fd, 0, SEEK_SET) < 0) {
       +                        seterr("lseek: %s", strerror(errno));
       +                        return -1;
       +                }
       +
       +                if (xread(sctx->fd, ad, sizeof(ad)) != sizeof(ad)) {
       +                        seterr("failed to read snapshot header: %s\n", strerror(errno));
                                return -1;
                        }
       +
       +                TAILQ_FOREACH(mdnode, &sctx->mdhead, e) {
       +                        unsigned char buf[MDSIZE + crypto_secretstream_xchacha20poly1305_ABYTES];
       +                        unsigned char tag;
       +
       +                        if (TAILQ_LAST(&sctx->mdhead, mdhead) == mdnode)
       +                                tag = crypto_secretstream_xchacha20poly1305_TAG_FINAL;
       +                        else
       +                                tag = 0;
       +
       +                        crypto_secretstream_xchacha20poly1305_push(&state,
       +                                                                   buf, NULL,
       +                                                                   mdnode->md, MDSIZE,
       +                                                                   ad, sizeof(ad), tag);
       +                        if (xwrite(sctx->fd, buf, sizeof(buf)) != sizeof(buf)) {
       +                                seterr("failed to write block hash: %s",
       +                                        strerror(errno));
       +                                return -1;
       +                        }
       +                }
       +        } else {
       +                if (packshdr(sctx->fd, shdr) < 0)
       +                        return -1;
       +                TAILQ_FOREACH(mdnode, &sctx->mdhead, e) {
       +                        if (xwrite(sctx->fd, mdnode->md, MDSIZE) != MDSIZE) {
       +                                seterr("failed to write block hash: %s",
       +                                        strerror(errno));
       +                                return -1;
       +                        }
       +                }
                }
                fsync(sctx->fd);
       +
                return 0;
        }