author | Olivier Brunel
<jjk@jjacky.com> 2023-05-03 19:40:02 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2023-05-20 18:06:40 UTC |
parent | 7423739ef546330949dbe8cc01feca199712f2e4 |
src/doc/shldata-rw.h.0.md | +28 | -0 |
src/doc/shldata-rw.h/shldata_write.3.md | +100 | -0 |
src/liblimb/include/limb/shldata-rw.h | +17 | -0 |
src/liblimb/shldata-rw.h/shldata_read.c | +39 | -0 |
src/liblimb/shldata-rw.h/shldata_write.c | +54 | -0 |
diff --git a/src/doc/shldata-rw.h.0.md b/src/doc/shldata-rw.h.0.md new file mode 100644 index 0000000..325263a --- /dev/null +++ b/src/doc/shldata-rw.h.0.md @@ -0,0 +1,28 @@ +% limb manual +% shldata-rw.h(0) + +# NAME + +shldata-rw.h - helpers functions to read/write shielded data files + +# SYNOPSIS + + #include <limb/shldata-rw.h> + +# DESCRIPTION + +The header defines helpers functions used to read/write shielded data files, as +per [shldata](5). + +## Functions + +The following functions are defined : + +: [shldata_chkmagic](3) +:: To ensure a magic number is valid for a shielded data file. + +: [shldata_read](3) +:: To read a shielded data file and decrypt its data. + +: [shldata_write](3) +:: To encrypt data and write them to a shielded data file. diff --git a/src/doc/shldata-rw.h/shldata_write.3.md b/src/doc/shldata-rw.h/shldata_write.3.md new file mode 100644 index 0000000..c7ce352 --- /dev/null +++ b/src/doc/shldata-rw.h/shldata_write.3.md @@ -0,0 +1,100 @@ +% limb manual +% shldata_write(3) + +# NAME + +shldata\_write, shldata\_read, shldata\_chkmagic - write/read shielded data +files + +# SYNOPSIS + + #include <limb/shldata-rw.h> + +```pre hl +int shldata_chkmagic(u32 <em>magic</em>) + +int shldata_write(int <em>bfd</em>, const char *<em>file</em>, u32 <em>magic</em>, u64 <em>ver</em>, + const char *<em>pwd</em>, size_t <em>plen</em>, unsigned <em>algo</em>, unsigned <em>iter</em>, + int <em>inplace</em>, const struct iovec <em>v</em>[], unsigned <em>n</em>) +int shldata_read(u32 *<em>magic</em>, u64 *<em>ver</em>, stralloc *<em>sa</em>, int <em>bfd</em>, const char *<em>file</em>, + const char *<em>pwd</em>, size_t <em>plen</em>) +``` + +# DESCRIPTION + +The `shldata_chkmagic`() function returns whether or not `magic` is a valid +magic constant for a shielded data file, as per [shldata](5). + +The `shldata_write`() function will write to `file` the shielded data consisting +of the data pointed by the array `v` of `n` *struct iovec*, encrypted using a +key derived via PBKDF2 from the password pointed by `pwd` of length `plen` and +algorithm `algo` and `iter` iterations. + +When `file` specifies a relative path, file written is then determined relative +to the directory associated with the file descriptor `bfd`. +If passed the special value *AT_FDCWD* in the `bfd` parameter, the current +working directory is used. + +The file will first have the magic `magic` and version number `ver` written out +as header, then all derivation parameters, encrypted data and authentication +code as needed, in [patrim](5) format. + +If `inplace` is non-zero, data will first be encrypted in-place before being +written out, otherwise memory will be allocated as needed. + + +The `shldata_read`() function will read the `file` - which must be a shielded +data file. Its magic number will be put as value pointed by `magic` and its +version number put as value pointed by `ver`. + +When `file` specifies a relative path, file written is then determined relative +to the directory associated with the file descriptor `bfd`. +If passed the special value *AT_FDCWD* in the `bfd` parameter, the current +working directory is used. + +If the magic is valid, parameters will read and the encrypted data will then be +decrypted using the password pointed by `pwd` of length `plen` and placed into +the *stralloc* pointed by `sa`. + +# RETURN VALUE + +The `shldata_chkmagic`() function returns 1 is `magic` is a valid shielded data +magic number, otherwise it returns zero and sets `errno` to *EINVAL*. + +The `shldata_write`() and `shldata_read`() functions return 1 on success. +Otherwise they return 0 and set `errno` to indicate the error. + +# ERRORS + +The `shldata_write`() and `shldta_read`() functions may fail if : + +: *EINVAL* +:: The magic number (given in `magic` or read from `file`, respectively) isn't +:: a valid magic for a shielded data file. + +: *ENOMEM* +:: Out of memory. + +The `shldata_write`() function may also fail if : + +: *EINVAL* +:: The value of `algo` or `iter` is invalid. + +The `shldata_write`() function may also fail for the errors described for +[open_exclat](3) save for *EEXIST*, [buffer_putv](3), [buffer_put](3), +[buffer_flush](3) and [renameat](3). + +The `shldata_read`() function may also fail if : + +: *EPIPE* +:: Not enough data could be read from `file` (e.g: file truncated) + +: *EINVAL* +:: Invalid data read from `file`. + +: *EBADMSG* +:: Authentication of the message (derivation parameters and encrypted data) +:: failed. (This could be caused by a wrong password being used.) + +The `shldata_read`() function may also fail for the errors described for +[open_readat](3), [buffer_get](3) and [buffer_fill](3). diff --git a/src/liblimb/include/limb/shldata-rw.h b/src/liblimb/include/limb/shldata-rw.h new file mode 100644 index 0000000..7c81454 --- /dev/null +++ b/src/liblimb/include/limb/shldata-rw.h @@ -0,0 +1,17 @@ +/* This file is part of limb https://lila.oss/limb + * Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef LIMB_SHLDATA_RW_H +#define LIMB_SHLDATA_RW_H + +#include <skalibs/stralloc.h> +#include <limb/int.h> +#include <limb/siovec.h> + +extern int shldata_write(int bfd, const char *file, u32 magic, u64 ver, + const char *pwd, size_t plen, unsigned algo, unsigned iter, + int inplace, const struct iovec v[], unsigned n); +extern int shldata_read(u32 *magic, u64 *ver, stralloc *sa, int bfd, const char *file, + const char *pwd, size_t plen); + +#endif /* LIMB_SHLDATA_RW_H */ diff --git a/src/liblimb/shldata-rw.h/shldata_read.c b/src/liblimb/shldata-rw.h/shldata_read.c new file mode 100644 index 0000000..26982c0 --- /dev/null +++ b/src/liblimb/shldata-rw.h/shldata_read.c @@ -0,0 +1,39 @@ +/* This file is part of limb https://lila.oss/limb + * Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <limb/buffer.h> +#include <limb/buffer-shldata.h> +#include <limb/djbunix.h> +#include <limb/shldata-rw.h> +#include <limb/unix-transactional.h> + +int +shldata_read(u32 *magic, u64 *ver, stralloc *sa, int bfd, const char *file, + const char *pwd, size_t plen) +{ + int ret = 0; + char buf[4096]; + buffer b = BUFFER_INIT(&buffer_read, -1, buf, sizeof(buf)); + + b.fd = open_readat(bfd, file); + if (b.fd < 0) return 0; + + buffer_shldata_ctx bsd = BUFFER_SHLDATA_ZERO; + + size_t salen = sa->len; + if (!buffer_gethdr(&b, magic, ver) + || !buffer_shldata_getinit_sa(&b, pwd, plen, sa, &bsd) + || !stralloc_readyplus(sa, buffer_shldata_datasize(&bsd)) + || !buffer_shldata_get(&b, sa->s + sa->len, buffer_shldata_datasize(&bsd), &bsd) + || (sa->len += buffer_shldata_datasize(&bsd), 0) + || !buffer_shldata_getfinal_sa(&b, sa, &bsd)) + goto err; + + salen = sa->len; + ret = 1; +err: + sa->len = salen; + fd_close(b.fd); + buffer_shldata_free(&bsd); + return ret; +} diff --git a/src/liblimb/shldata-rw.h/shldata_write.c b/src/liblimb/shldata-rw.h/shldata_write.c new file mode 100644 index 0000000..b53f4ba --- /dev/null +++ b/src/liblimb/shldata-rw.h/shldata_write.c @@ -0,0 +1,54 @@ +/* This file is part of limb https://lila.oss/limb + * Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <skalibs/random.h> +#include <limb/buffer.h> +#include <limb/buffer-shldata.h> +#include <limb/djbunix.h> +#include <limb/unix-transactional.h> +#include <limb/shldata-rw.h> +#include <limb/siovec.h> + +int +shldata_write(int bfd, const char *file, u32 magic, u64 ver, + const char *pwd, size_t plen, unsigned algo, unsigned iter, + int inplace, const struct iovec v[], unsigned n) +{ + int ret = 0; + char buf[4096]; + buffer b = BUFFER_INIT(&buffer_write, -1, buf, sizeof(buf)); + char tmp[8]; + + *tmp = '.'; + do { + random_name(tmp + 1, sizeof(tmp) - 1); + b.fd = open_exclat(bfd, tmp); + } while (b.fd < 0 && errno == EEXIST); + if (b.fd < 0) return 0; + + if (buffer_puthdr(&b, magic, ver) < 0) + goto err; + + buffer_shldata_ctx bsd = BUFFER_SHLDATA_ZERO; + + if (buffer_shldata_putinit(&b, pwd, plen, algo, iter, siov_len(v, n), &bsd) < 0) + goto err; + + for (unsigned i = 0; i < n; ++i) + if (buffer_shldata_put(&b, v[i].iov_base, v[i].iov_len, inplace, &bsd) < 0) + goto err; + + if (buffer_shldata_putfinal(&b, &bsd) < 0 || !buffer_flush(&b) + || renameat(bfd, tmp, bfd, file) < 0) + goto err; + + *tmp = 0; + ret = 1; +err: + fd_close(b.fd); + if (*tmp) unlinkat(bfd, tmp, 0); + return ret; +}