URI: 
       tImplement cream format for secrets - safe - password protected secret keeper
  HTML git clone git://git.z3bra.org/safe.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit a25d4e0e8990e3c9baeb922bcd5d2acb73055a7e
   DIR parent efb4beb219890a5796415c790604a282d6b37399
  HTML Author: Willy Goiffon <contact@z3bra.org>
       Date:   Wed, 19 Oct 2022 09:52:18 +0200
       
       Implement cream format for secrets
       
       Diffstat:
         M safe.c                              |      86 ++++++++++++++++++++++++++-----
       
       1 file changed, 74 insertions(+), 12 deletions(-)
       ---
   DIR diff --git a/safe.c b/safe.c
       t@@ -1,3 +1,4 @@
       +#include <netinet/in.h>
        #include <sys/resource.h>
        #include <sys/socket.h>
        #include <sys/stat.h>
       t@@ -22,9 +23,28 @@
        #include "readpassphrase.h"
        #include "config.h"
        
       +struct crypto {
       +        uint8_t  magic[6];
       +        uint16_t version;
       +        uint32_t xchacha20poly1305_bufsiz;
       +        uint32_t argon2id_memory;
       +        uint32_t argon2id_time;
       +        uint32_t argon2id_threads;
       +        uint8_t  salt[crypto_pwhash_SALTBYTES];
       +};
       +
       +struct crypto crypto_defaults = {
       +        .magic = {'C','R','E','A','M','\1'},
       +        .version = 0x10,
       +        .xchacha20poly1305_bufsiz = BUFSIZ, /* must match size in readsecret() and writesecret() */
       +        .argon2id_memory          = 64*1024,
       +        .argon2id_time            = 3,
       +        .argon2id_threads         = 1, /* hardcoded in libsodium */
       +};
       +
        struct safe {
                uint8_t key[crypto_secretstream_xchacha20poly1305_KEYBYTES];
       -        uint8_t salt[crypto_pwhash_SALTBYTES];
       +        struct crypto crypto;
        };
        
        enum {
       t@@ -191,9 +211,9 @@ void
        deriv(char *pw, struct safe *s)
        {
                if (crypto_pwhash(s->key, sizeof(s->key), pw, strlen(pw),
       -                        s->salt, crypto_pwhash_OPSLIMIT_INTERACTIVE,
       -                        crypto_pwhash_MEMLIMIT_INTERACTIVE,
       -                        crypto_pwhash_ALG_DEFAULT))
       +                        s->crypto.salt, s->crypto.argon2id_time,
       +                        s->crypto.argon2id_memory * 1024,
       +                        crypto_pwhash_ALG_ARGON2ID13))
                        err(1, "crypto_pwhash:");
        }
        
       t@@ -212,7 +232,7 @@ pushkey(struct safe *s, char *path)
                if (connect(sfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
                        return -1;
        
       -        if (xwrite(sfd, s->salt, sizeof(s->salt)) < 0)
       +        if (xwrite(sfd, s->crypto.salt, sizeof(s->crypto.salt)) < 0)
                        return -1;
        
                if (write(sfd, s->key, sizeof(s->key)) < 0)
       t@@ -239,7 +259,7 @@ readkey(struct safe *s, char *path)
                if (connect(sfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
                        goto err;
        
       -        if ((n = xread(sfd, s->salt, sizeof(s->salt), NULL)) <= 0)
       +        if ((n = xread(sfd, &s->crypto.salt, sizeof(s->crypto.salt), NULL)) <= 0)
                        goto err;
        
                if (xread(sfd, s->key, sizeof(s->key), NULL) < 0)
       t@@ -280,6 +300,44 @@ trydecrypt(struct safe *s, int fd)
        }
        
        int
       +readheader(int fd, struct crypto *hdr)
       +{
       +        uint8_t buf[40];
       +        uint16_t s;
       +        uint32_t l;
       +
       +        xread(fd, buf, sizeof(buf), NULL);
       +
       +        memcpy(hdr->magic, buf +  0, 6);
       +        memcpy(&s, buf +  6, 2); hdr->version = ntohs(s);
       +        memcpy(&l, buf +  8, 4); hdr->xchacha20poly1305_bufsiz = ntohl(l);
       +        memcpy(&l, buf + 12, 4); hdr->argon2id_memory = ntohl(l);
       +        memcpy(&l, buf + 16, 4); hdr->argon2id_time = ntohl(l);
       +        memcpy(&l, buf + 20, 4); hdr->argon2id_threads = ntohl(l);
       +        memcpy(hdr->salt, buf + 24, 16);
       +
       +        return 0;
       +}
       +
       +int
       +writeheader(int fd, struct crypto hdr)
       +{
       +        uint8_t buf[40];
       +        uint16_t s;
       +        uint32_t l;
       +
       +        memcpy(buf +  0, hdr.magic, 6);
       +        s = htons(hdr.version);                  memcpy(buf +  6, (uint8_t *) &s, 2);
       +        l = htonl(hdr.xchacha20poly1305_bufsiz); memcpy(buf +  8, (uint8_t *) &l, 4);
       +        l = htonl(hdr.argon2id_memory);          memcpy(buf + 12, (uint8_t *) &l, 4);
       +        l = htonl(hdr.argon2id_time);            memcpy(buf + 16, (uint8_t *) &l, 4);
       +        l = htonl(hdr.argon2id_threads);         memcpy(buf + 20, (uint8_t *) &l, 4);
       +        memcpy(buf + 24, hdr.salt, 16);
       +
       +        return xwrite(fd, buf, sizeof(buf));
       +}
       +
       +int
        writepass(struct safe *s, char *m, size_t mlen, int fd)
        {
                uint8_t *c, h[crypto_secretstream_xchacha20poly1305_HEADERBYTES];
       t@@ -373,6 +431,9 @@ main(int argc, char *argv[])
                sockp  = getenv("SAFE_SOCK");
                prompt = "password:";
        
       +        /* set default cream parameters */
       +        memcpy(&s.crypto, &crypto_defaults, sizeof(s.crypto));
       +
                ARGBEGIN {
                case 'f':
                        fflag = 1;
       t@@ -478,10 +539,10 @@ main(int argc, char *argv[])
                        if (fd < 0)
                                err(1, "%s", master_entry);
        
       -                randombytes_buf(s.salt, sizeof(s.salt));
       +                randombytes_buf(s.crypto.salt, sizeof(s.crypto.salt));
                        deriv((char *)passphrase, &s);
        
       -                xwrite(fd, s.salt, sizeof(s.salt));
       +                writeheader(fd, s.crypto);
                        writepass(&s, passphrase, pplen, fd);
                        haskey = 1;
                }
       t@@ -491,13 +552,14 @@ main(int argc, char *argv[])
                        if (pplen < 0)
                                return -1;
        
       -                xread(fd, s.salt, sizeof(s.salt), NULL);
       +                //xread(fd, &s.crypto, sizeof(s.crypto), NULL);
       +                readheader(fd, &s.crypto);
                        deriv(passphrase, &s);
                        haskey = 1;
                }
        
                /* try to decrypt master password first, to ensure passphrase match */
       -        lseek(fd, sizeof(s.salt), SEEK_SET);
       +        lseek(fd, sizeof(s.crypto), SEEK_SET);
                if (trydecrypt(&s, fd) < 0) {
                        fprintf(stderr, "incorrect master password\n");
                        close(fd);
       t@@ -527,7 +589,7 @@ main(int argc, char *argv[])
                        if (fd < 0)
                                err(1, "%s", secret);
        
       -                xwrite(fd, s.salt, sizeof(s.salt));
       +                writeheader(fd, s.crypto);
                        writesecret(&s, STDIN_FILENO, fd);
                        close(fd);
                } else {
       t@@ -536,7 +598,7 @@ main(int argc, char *argv[])
                                err(1, "%s", secret);
        
                        /* Read salt from the beginning of the file */
       -                lseek(fd, sizeof(s.salt), SEEK_SET);
       +                lseek(fd, sizeof(s.crypto), SEEK_SET);
                        readsecret(&s, fd, STDOUT_FILENO);
                        close(fd);
                }