Welcome to little lamb

Code » limb » commit 7e759f6

Add shldata-rw.h & related functions

author Olivier Brunel
2023-05-03 19:40:02 UTC
committer Olivier Brunel
2023-05-20 18:06:40 UTC
parent 7423739ef546330949dbe8cc01feca199712f2e4

Add shldata-rw.h & related functions

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;
+}