author | Olivier Brunel
<jjk@jjacky.com> 2023-04-30 20:21:14 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2023-05-20 18:06:39 UTC |
parent | a7fa2570a72d7591e2e0cc5ebe48ede7611d8329 |
src/doc/hasher.h.0.md | +23 | -0 |
src/doc/hasher.h/hasher_hash.3.md | +23 | -8 |
src/doc/patrim.5.md | +5 | -0 |
src/doc/patrim.h.0.md | +3 | -0 |
src/doc/patrim.h/patrim_put.3.md | +9 | -0 |
src/doc/shldata.5.md | +49 | -0 |
src/doc/shldata.h.0.md | +52 | -0 |
src/doc/shldata.h/shldata_initr.3.md | +88 | -0 |
src/doc/shldata.h/shldata_initw.3.md | +107 | -0 |
src/include/shldata.h | +18 | -0 |
src/liblimb/hasher.h/hashers.c | +19 | -0 |
src/liblimb/include/limb/hasher.h | +18 | -0 |
src/liblimb/include/limb/patrim.h | +1 | -0 |
src/liblimb/include/limb/shldata.h | +30 | -0 |
src/liblimb/shldata.h/shldata_decrypt.c | +16 | -0 |
src/liblimb/shldata.h/shldata_encrypt.c | +17 | -0 |
src/liblimb/shldata.h/shldata_finalr.c | +31 | -0 |
src/liblimb/shldata.h/shldata_finalw.c | +26 | -0 |
src/liblimb/shldata.h/shldata_initr.c | +75 | -0 |
src/liblimb/shldata.h/shldata_initw.c | +61 | -0 |
src/liblimb/shldata.h/shldata_predata.c | +23 | -0 |
diff --git a/src/doc/hasher.h.0.md b/src/doc/hasher.h.0.md index f5482c0..ebc1159 100644 --- a/src/doc/hasher.h.0.md +++ b/src/doc/hasher.h.0.md @@ -27,6 +27,18 @@ The following types are defined : : *hasher_final* :: Generic pointer function for computing/obtaining the message digest +## Constants + +The following constants are defined : + +: *ALGO_SHA1*, *ALGO_SHA256*, *ALGO_SHA512*, *ALGO_SHA3_224*, *ALGO_SHA3_256*, +: *ALGO_SHA3_384*, *ALGO_SHA3_512*, *ALGO_BLAKE3* +:: Indices to identify each of the algorithms for which a hasher is available +:: in the arrays *algos* and *hashers*. + +: *NB_AGLOS* +:: Number of elements/algorithms. + ## Structures The following structures are defined : @@ -35,6 +47,17 @@ The following structures are defined : :: A structure representing a hasher, allowing to compute a message digest :: through the algorithm of said hasher. +## Pointers + +The following pointers are defined : + +: *algos* +:: Pointer to an NULL-terminated array of *NB_ALGOS* strings naming the +:: algorithms. + +: *hashers* +:: Pointer to an array of *NB_ALGOS* pointers to the available *hasher*s. + ## Functions The following functions/macros are defined : diff --git a/src/doc/hasher.h/hasher_hash.3.md b/src/doc/hasher.h/hasher_hash.3.md index 598c7e6..d2fcd24 100644 --- a/src/doc/hasher.h/hasher_hash.3.md +++ b/src/doc/hasher.h/hasher_hash.3.md @@ -10,6 +10,10 @@ hasher\_hash, hinit, hupdate, hfinal - compute a message digest using a given ha #include <limb/hasher.h> ```pre hl +const char * const algos[NB_ALGOS + 1] +hasher * const hashers[NB_ALGOS] + + void hinit (hasher *<em>hasher</em>) void hupdate (const void *<em>msg</em>, size_t <em>mlen</em>, hasher *<em>hasher</em>) void hfinal (void *<em>digest</em>, hasher *<em>hasher</em>) @@ -80,31 +84,42 @@ A few hashers are available, each define in their own header. In order to use a hasher, all you need is to include its header, which includes [hasher.h](0), and you can any of the functions described above. +A constant *NB_ALGOS* is defined with the number of available hashers. Two +pointers are defined : + +- `algos` which points to a NULL-terminated array of strings, naming each of the + available hashers/algorithms. +- `hashers` which points to an array of pointers to the available hashers. + +Obviously, indices in each array are referring to the same hasher/algorithm. In +addition, constants are defined for each of the indices. + + The following hashers are available : : *blake3* -:: Requires [hasher_blake3.h](0). +:: Index *ALGO_BLAKE3*. Requires [hasher_blake3.h](0). : *sha1* -:: Requires [hasher_sha1.h](0). +:: Index *ALGO_SHA1*. Requires [hasher_sha1.h](0). : *sha256* -:: Requires [hasher_sha256.h](0). +:: Index *ALGO_SHA256*. Requires [hasher_sha256.h](0). : *sha512* -:: Requires [hasher_sha512.h](0). +:: Index *ALGO_SHA512*. Requires [hasher_sha512.h](0). : *sha3_224* -:: Requires [hasher_sha3_224.h](0). +:: Index *ALGO_SHA3_224*. Requires [hasher_sha3_224.h](0). : *sha3_256* -:: Requires [hasher_sha3_256.h](0). +:: Index *ALGO_SHA3_256*. Requires [hasher_sha3_256.h](0). : *sha3_384* -:: Requires [hasher_sha3_384.h](0). +:: Index *ALGO_SHA3_384*. Requires [hasher_sha3_384.h](0). : *sha3_512* -:: Requires [hasher_sha3_512.h](0). +:: Index *ALGO_SHA3_512*. Requires [hasher_sha3_512.h](0). ! NOTE: ! The hashers for SHA1, SHA256 and SHA512 are wrappers around functions from diff --git a/src/doc/patrim.5.md b/src/doc/patrim.5.md index 066c33c..e730398 100644 --- a/src/doc/patrim.5.md +++ b/src/doc/patrim.5.md @@ -42,6 +42,11 @@ header as such : - A big-endian encoded 32bit magic number, to identify the specific file format. The magic number should have certain bits set to indicate it is PATRIM encoded, specifically : `(magic & 0xf0f0f000) = 0xa0e0f000` +- Additionally, bit 8 is used as a flag to indicate whether or not the file + contains shielded data, as described in [shldata](5). + When set, and shielded data are present, for every ID in the file its bit 7 is + a flag which, when set, indicates the data are part of the shielded data + protocol itself. - A version number, pack-trimmed. Helpers functions [buffer_puthdr](3) and [buffer_gethdr](3) are available to diff --git a/src/doc/patrim.h.0.md b/src/doc/patrim.h.0.md index 0e7bce8..fe9c272 100644 --- a/src/doc/patrim.h.0.md +++ b/src/doc/patrim.h.0.md @@ -23,6 +23,9 @@ The following functions/macros are defined : : [patrim_isint](3) :: Returns whether the given ID is that of an integer or not. +: [patrim_isshldata](3) +:: Returns whether the given ID belongs to the shielded data protocol or not. + : [patrim_put](3) :: To encode data in [patrim](5) format. diff --git a/src/doc/patrim.h/patrim_put.3.md b/src/doc/patrim.h/patrim_put.3.md index 964a262..1c897a4 100644 --- a/src/doc/patrim.h/patrim_put.3.md +++ b/src/doc/patrim.h/patrim_put.3.md @@ -16,6 +16,7 @@ int patrim_get(u64 *<em>id</em>, u64 *<em>u</em>, const char *<em>data</em>, siz int patrim_isblob(u64 <em>id</em>) int patrim_isint(u64 <em>id</em>) +int patrim_isshldata(u64 <em>id</em>) ``` # DESCRIPTION @@ -40,6 +41,10 @@ otherwise. The `patrim_isint`() macro returns 1 if the `id` if that of an integer, zero otherwise. +The `patrim_isshldata`() macro returns 1 if the `id` is one that belongs to the +"shielded data" protocol - as described in [shldata](5). Note that this /only +applies/ when e.g. reading a shielded data file. + # RETURN VALUE On success the `patrim_put`() and `patrim_get`() functions return the number of @@ -48,3 +53,7 @@ not enough bytes could be written or read - they return -1. The `patrim_isblob`() and `patrim_isint`() macros return 1 id `id` represents a blob or an integer, respectively, otherwise they return 0. + +The `patrim_isshldata`() macro returns 1 if `id` belongs to the shielded data +protocol, 0 otherwise. Note that this is only applicable when e.g. reading a +shielded data file. diff --git a/src/doc/shldata.5.md b/src/doc/shldata.5.md new file mode 100644 index 0000000..c7fb35f --- /dev/null +++ b/src/doc/shldata.5.md @@ -0,0 +1,49 @@ +% limb manual +% shldata(5) + +# NAME + +shielded data - encryption/decryption protocol + +# DESCRIPTION + +The "shielded data" protocol is a way to protect data using a user-provided +password. Using specified parameters (cryptographic hash algorithm, iteration +numbers, etc) a secret key is derived from the password and used to encrypt data +via the ChaCha20-Poly1305 algorithm. + +Similarly, provided with the original password, the same key derivation function +is applied - using parameters taken from the input data - to obtain the secret +key, used via ChaCha20-Poly1305 to both decrypt & authenticate the data, adding +the derivation parameters to the authentication process. + +The actual encryption/decryption is performed using the ChaCha20-Poly1305 +algorithm, as described in [RFC 8439][rfc8439]. + +[rfc8439] (https://datatracker.ietf.org/doc/html/rfc8439) + +The derivation parameters as well as the encrypted data and the message +authentication code are encoded in [patrim](5) format : + +- The file header should use a PATRIM compatible magic constant, with bit 8 of + said number being set to 1 to indicate it contains shielded data. + +- For every ID in the file, bit 7 is a flag with special meaning : If set, it + indicates that the associated data are part of the shielded data protocol. + Else, the ID is a custom ID defined/used per the application itself. + +- When shielded data are added into a file, first all the IDs referring to key + derivation must be included, then the `ID_DATA` containing the encrypted data + followed by the `ID_MAC` containing the authentication code. + +- It is possible to have more than one such shielded data in a single file, + though each will have its own settings & require its own password. + +- Application-custom IDs can be used before, after, or in-between such shielded + data sections, but must not be mixed within groups of shielded data IDs. + +Refer to [shldata.h](0) for an interface to the encryption/decryption of +shielded data. + +Helpers functions for general purpose PATRIM encoding are also available via +[patrim.h](0). diff --git a/src/doc/shldata.h.0.md b/src/doc/shldata.h.0.md new file mode 100644 index 0000000..f23575c --- /dev/null +++ b/src/doc/shldata.h.0.md @@ -0,0 +1,52 @@ +% limb manual +% shldata.h(0) + +# NAME + +shldata.h - encrypt/decrypt data using the shielded data protocol + +# SYNOPSIS + + #include <limb/shldata.h> + +# DESCRIPTION + +The header defines functions used to encrypt/decrypt data using the "shielded +data" protocol. Refer to [shldata](5) for more. + +## Types + +The following types are defined : + +: *shldata_ctx* +:: An opaque structure used to perform encryption or decryption through the +:: shield data protocol. + +## Functions + +The following functions/macros are defined : + +: [shldata_initw](3) +:: To initialize encryption of data through the shielded data protocol. + +: [shldata_encrypt](3) +:: To encrypt data through the shielded data protocol. + +: [shldata_predata](3) +:: Part of the shielded data encryption protocol. + +: [shldata_finalw](3) +:: To finalize the encryption of data through the shielded data protocol. + +: [shldata_initr](3) +:: To initialize decryption through the shielded data protocol. + +: [shldata_datasize](3) +:: Returns the length of encrypted data to be decrypted through the shielded data +:: protocol. + +: [shldata_decrypt](3) +:: To decrypt data through the shielded data protocol. + +: [shldata_finalr](3) +:: To finalize the decryption of data through the shielded data protocol. diff --git a/src/doc/shldata.h/shldata_initr.3.md b/src/doc/shldata.h/shldata_initr.3.md new file mode 100644 index 0000000..98a03cb --- /dev/null +++ b/src/doc/shldata.h/shldata_initr.3.md @@ -0,0 +1,88 @@ +% limb manual +% shldata_initr(3) + +# NAME + +shldata\_initr, shldata\_datasize, shldata\_decrypt, shldata\_finalr - decrypt +data using the shielded data protocol + +# SYNOPSIS + + #include <limb/shldata.h> + +```pre hl +ssize_t shldata_initr(const char *<em>sce</em>, size_t <em>slen</em>, const char *<em>pwd</em>, size_t <em>plen</em>, shldata_ctx *<em>ctx</em>) +size_t shldata_datasize(shldata_ctx *<em>ctx</em>) +int shldata_decrypt(char *<em>dst</em>, const char *<em>sce</em>, size_t <em>len</em>, shldata_ctx *<em>ctx</em>) +ssize_t shldata_finalr(const char *<em>sce</em>, size_t <em>slen</em>, shldata_ctx *<em>ctx</em>) +``` + +# DESCRIPTION + +All those functions are used to read & decrypt data protected with a +user-supplied password using the shielded data protocol, as described in +[shldata](5). + +First, the `shldata_initr`() function will read the memory pointed by `sce` (up +to a maximum of `slen` bytes) for derivation parameters, then it will derive a +secret key from the password pointed by `pwd` of length `plen` and initialize +the opaque structure pointed by `ctx`. + +The `shldata_datasize`() macro returns the length of the encrypted data, and +therefore decrypted data. + +The `shldata_decrypt`() function can then be used to decrypt data pointed by +`sce` of length `slen` into the memory pointed by `dst` (which must be able to +store at least `slen` bytes), using the specified `ctx`. + +As with [ccpl_decrupt](3) it is possible to use the same memory area for both +`sce` and `dst`, and have it processed in-place. + +It is possible to call this function as many times as needed. + +Lastly, the `shldata_finalr`() function will read the memory pointed by `sce` +(up to a maximum of `sleb` bytes) to authenticate both the derivation parameters +used during `shldata_initr`() and the encrypted data. + +Once done, it is possible to re-use an opaque structure for a new processing of +data. It is also allowed to to so more than once per shielded data file, as per +[shldata](5). + +# RETURN VALUE + +The `shldata_initr`(), and `shldata_finalr`() functions return the number of +bytes read and processed from `sce` on success. Otherwise they return -1 and set +`errno` to indicate the error. + +For `shldata_initr`() this obviously means the offset at which encrypted data +begins in `sce`. + +The `shldata_datasize`() macro returns the length of the data to be decrypted. + +The `shldata_decrypt`() function returns 1 on success, 0 otherwise. It should +never fail, as the only possible reason for failure is that the amount of data +given to be decrypted is larger than the amount of encrypted data, which should +never happen. + +# ERRORS + +The `shldata_initr`() and `shldata_finalr`() functions may fail if : + +: *EINVAL* +:: The memory pointed by `sce` contains invalid data. + +: *ENODATA* +:: There is not enough data available in `sce`. + +The `shldata_finalr`() function may fail if : + +: *EINVAL* +:: The amount of data decrypted is different from the amount of encrypted data. + +: *EBADMSG* +:: Authentication of the message (derivation parameters and encrypted data) +:: failed. (This could be caused by a wrong password being used.) + +# SEE ALSO + +[shldata_initw](3) diff --git a/src/doc/shldata.h/shldata_initw.3.md b/src/doc/shldata.h/shldata_initw.3.md new file mode 100644 index 0000000..8e9fbfb --- /dev/null +++ b/src/doc/shldata.h/shldata_initw.3.md @@ -0,0 +1,107 @@ +% limb manual +% shldata_initw(3) + +# NAME + +shldata\_initw, shldata\_encrypt, shldata\_predata, shldata\_finalw - encrypt +data using the shielded data protocol + +# SYNOPSIS + + #include <limb/shldata.h> + +```pre hl +ssize_t shldata_initw(char *<em>dst</em>, size_t <em>dlen</em>, const char *<em>pwd</em>, size_t <em>plen</em>, + unsigned <em>algo</em>, unsigned <em>iter</em>, size_t <em>len</em>, shldata_ctx *<em>ctx</em>) +int shldata_encrypt(char *<em>dst</em>, const char *<em>data</em>, size_t <em>dlen</em>, shldata_ctx *<em>ctx</em>) +ssize_t shldata_predata(char *<em>dst</em>, size_t <em>dlen</em>, shldata_ctx *<em>ctx</em>) +ssize_t shldata_finalw(char *<em>dst</em>, size_t <em>dlen</em>, shldata_ctx *<em>ctx</em>) +``` + +# DESCRIPTION + +All those functions are used to protect data with a user-supplied password using +the shielded data protocol, as described in [shldata](5). + +First, the `shldata_initw`() function must be called to both write into the +memory pointed by `dst` of length `dlen` bytes the necessary parameters that +will be needed for decryption, and to initialize the opaque structure pointed by +`ctx` in order to perform data encryption. + +Key derivation will be performed using PBKDF2 from the password pointed by `pwd` +of length `plen`, with the HMAC based on the algorithm indicated in `algo` - +which must be a valid index/constant as defined in [hasher.h](0) - and the +number of iterations indicated in `iter`. + +It is recommended, if possible, to indicate the exact length of data to be +encrypted in `len`. It is however possible to use zero if not yet known. + +The `shldata_encrypt`() function can then be used to encrypt data pointed by +`data` of length `dlen` into the memory pointed by `dst` (which must be able to +store at least `dlen` bytes), using the specified `ctx`. + +As with [ccpl_encrupt](3) it is possible to use the same memory area for both +`data` and `dst`, and have it processed in-place. + +It is possible to call this function as many times as needed. + +! If the length of data to be encrypted was known and given to `shldata_initw`() +! it is correct to write encrypted data right after the parameters written by +! said function, and no call to `shldata_predata`() is required. +! +! If, however, the length was /not/ given (i.e. `len` was zero), one should +! *not* write encrypted data yet, but hold them in memory somewhere. All data +! to be encrypted must be encrypted through `shldata_encrypt`() (in as many +! calls as needed), and /only then/ a call to `shldata_predata`() must be done. + +The `shldata_predata`() function will write into the memory pointed by `dst` of +length `dlen` additional data that must be written out after the output written +by `shldata_initw`() but /before/ the encrypted data written by +`shldata_encrypt`(). +This is because the length of encrypted data must be specified /before/ the +actual data. This is also why specifying said length to `shldata_initw`() means +it will already have been written out then, and no call to `shldata_predata`() +is then required (though it is valid to call it anyways, but it will never write +anything). + +Lastly, the `shldata_finalw`() function must be called, and will write into the +memory pointed by `dst` of length `dlen` the final additional data (i.e. the +message authentication code). + +Once done, it is possible to re-use an opaque structure for a new processing of +data. It is also allowed to to so more than once per shielded data file, as per +[shldata](5). + +# RETURN VALUE + +The `shldata_initw`(), `shldata_predata`() and `shldata_finalw`() functions +return the number of bytes written into `dst` on success. Otherwise they return +-1 and set `errno` to indicate the error. + +The `shldata_encrypt`() function returns 1 on success, 0 otherwise. It should +never fail, as the only possible reason for failure is that the amount of data +given to be encrypted is larger than that specified to `shldata_initw`(), which +should never happen. + +# ERRORS + +The `shldata_initw`(), `shldata_predata`() and `shldata_finalw`() functions may +fail if : + +: *ENOBUFS* +:: There is not enough space in `dst`. + +The `shldata_initw`() may fail if : + +: *EINVAL* +:: The value of `algo` or `iter` is invalid. + +The `shldata_predata`() and `shldata_finalw`() function may fail if : + +: *EINVAL* +:: The length specified to `shldata_initw`() and the length of encrypted data +:: are different (which should never happen). + +# SEE ALSO + +[shldata_initr](3) diff --git a/src/include/shldata.h b/src/include/shldata.h new file mode 100644 index 0000000..8f394fc --- /dev/null +++ b/src/include/shldata.h @@ -0,0 +1,18 @@ +/* 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_LIMB_SHLDATA_H +#define LIMB_LIMB_SHLDATA_H + +#define KEY_LEN 32 +#define SALT_LEN 32 +#define NONCE_LEN 12 + +#define ID_ALGO 64 +#define ID_ITER 66 + +#define ID_SALT 65 +#define ID_DATA 67 +#define ID_MAC 69 + +#endif /* LIMB_LIMB_SHLDATA_H */ diff --git a/src/liblimb/hasher.h/hashers.c b/src/liblimb/hasher.h/hashers.c new file mode 100644 index 0000000..a81b87c --- /dev/null +++ b/src/liblimb/hasher.h/hashers.c @@ -0,0 +1,19 @@ +/* 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/hasher.h> +#include <limb/hasher_sha1.h> +#include <limb/hasher_sha256.h> +#include <limb/hasher_sha512.h> +#include <limb/hasher_sha3_224.h> +#include <limb/hasher_sha3_256.h> +#include <limb/hasher_sha3_384.h> +#include <limb/hasher_sha3_512.h> +#include <limb/hasher_blake3.h> + +/* XXX make sure to preserve order as ALGO_* in hasher.h */ +const char * const algos[NB_ALGOS + 1] = { "sha1", "sha256", "sha512", "sha3-224", + "sha3-256", "sha3-384", "sha3-512", "blake3", 0 }; + +hasher * const hashers[NB_ALGOS] = { sha1, sha256, sha512, sha3_224, + sha3_256, sha3_384, sha3_512, blake3 }; diff --git a/src/liblimb/include/limb/hasher.h b/src/liblimb/include/limb/hasher.h index a21f906..f39cea9 100644 --- a/src/liblimb/include/limb/hasher.h +++ b/src/liblimb/include/limb/hasher.h @@ -28,4 +28,22 @@ struct hasher { extern void hasher_hash(void *digest, const void *msg, size_t mlen, hasher *hasher); +/* supported algorithms/hashers */ +/* XXX make sure to preserve order in *algos[] in hashers.c */ +enum { + ALGO_SHA1 = 0, + ALGO_SHA256, + ALGO_SHA512, + ALGO_SHA3_224, + ALGO_SHA3_256, + ALGO_SHA3_384, + ALGO_SHA3_512, + ALGO_BLAKE3, + NB_ALGOS +}; + +/* names of said algos, in the same order */ +extern const char * const algos[NB_ALGOS + 1]; +extern hasher * const hashers[NB_ALGOS]; + #endif /* LIMB_HASHER_H */ diff --git a/src/liblimb/include/limb/patrim.h b/src/liblimb/include/limb/patrim.h index c13cc2a..8646b2f 100644 --- a/src/liblimb/include/limb/patrim.h +++ b/src/liblimb/include/limb/patrim.h @@ -9,6 +9,7 @@ #define patrim_isblob(id) (id & 1) #define patrim_isint(id) !patrim_isblob(id) +#define patrim_isshldata(id) (id & (1 << 6)) extern int patrim_put(char *dst, size_t dlen, size_t offset, u64 id, u64 u); extern int patrim_get(u64 *id, u64 *u, const char *data, size_t dlen, size_t offset); diff --git a/src/liblimb/include/limb/shldata.h b/src/liblimb/include/limb/shldata.h new file mode 100644 index 0000000..9081fce --- /dev/null +++ b/src/liblimb/include/limb/shldata.h @@ -0,0 +1,30 @@ +/* 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_H +#define LIMB_SHLDATA_H + +#include <sys/types.h> +#include <limb/ccpl.h> + +struct shldata_ctx { + ccpl_ctx ccpl; + size_t len; + size_t done; +}; + +typedef struct shldata_ctx shldata_ctx; + +extern ssize_t shldata_initw(char *dst, size_t dlen, const char *pwd, size_t plen, + unsigned algo, unsigned iter, size_t len, shldata_ctx *ctx); +extern int shldata_encrypt(char *dst, const char *data, size_t dlen, shldata_ctx *ctx); +extern ssize_t shldata_predata(char *dst, size_t dlen, shldata_ctx *ctx); +extern ssize_t shldata_finalw(char *dst, size_t dlen, shldata_ctx *ctx); + + +extern ssize_t shldata_initr(const char *sce, size_t slen, const char *pwd, size_t plen, shldata_ctx *ctx); +#define shldata_datasize(ctx) (ctx)->len +extern int shldata_decrypt(char *dst, const char *sce, size_t len, shldata_ctx *ctx); +extern ssize_t shldata_finalr(const char *sce, size_t slen, shldata_ctx *ctx); + +#endif /* LIMB_SHLDATA_H */ diff --git a/src/liblimb/shldata.h/shldata_decrypt.c b/src/liblimb/shldata.h/shldata_decrypt.c new file mode 100644 index 0000000..9ca4e35 --- /dev/null +++ b/src/liblimb/shldata.h/shldata_decrypt.c @@ -0,0 +1,16 @@ +/* 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/ccpl.h> +#include <limb/shldata.h> + +int +shldata_decrypt(char *dst, const char *sce, size_t len, shldata_ctx *ctx) +{ + if (ctx->done + len > ctx->len) + return 0; + + ccpl_decrypt(dst, sce, len, &ctx->ccpl); + ctx->done += len; + return 1; +} diff --git a/src/liblimb/shldata.h/shldata_encrypt.c b/src/liblimb/shldata.h/shldata_encrypt.c new file mode 100644 index 0000000..045e97b --- /dev/null +++ b/src/liblimb/shldata.h/shldata_encrypt.c @@ -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 */ +#include <limb/ccpl.h> +#include <limb/shldata.h> +#include "shldata.h" + +int +shldata_encrypt(char *dst, const char *data, size_t dlen, shldata_ctx *ctx) +{ + if (ctx->len && ctx->done + dlen > ctx->len) + return 0; + + ccpl_encrypt(dst, data, dlen, &ctx->ccpl); + ctx->done += dlen; + return 1; +} diff --git a/src/liblimb/shldata.h/shldata_finalr.c b/src/liblimb/shldata.h/shldata_finalr.c new file mode 100644 index 0000000..b74721a --- /dev/null +++ b/src/liblimb/shldata.h/shldata_finalr.c @@ -0,0 +1,31 @@ +/* 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 <string.h> +#include <limb/patrim.h> +#include <limb/shldata.h> +#include "shldata.h" + +ssize_t +shldata_finalr(const char *sce, size_t slen, shldata_ctx *ctx) +{ + char mac[16]; + + if (ctx->done != ctx->len) + return (errno = EINVAL, -1); + + u64 id, u; + int r; + r = patrim_get(&id, &u, sce, slen, 0); + if (r < 0) return (errno = ENODATA, -1); + + if (id != ID_MAC || u != sizeof(mac)) + return (errno = EINVAL, -1); + + ccpl_final(mac, &ctx->ccpl); + if (memcmp(sce + r, mac, sizeof(mac))) + return (errno = EBADMSG, -1); + + return r + sizeof(mac); +} diff --git a/src/liblimb/shldata.h/shldata_finalw.c b/src/liblimb/shldata.h/shldata_finalw.c new file mode 100644 index 0000000..432a4ff --- /dev/null +++ b/src/liblimb/shldata.h/shldata_finalw.c @@ -0,0 +1,26 @@ +/* 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 <string.h> +#include <limb/patrim.h> +#include <limb/shldata.h> +#include "shldata.h" + +ssize_t +shldata_finalw(char *dst, size_t dlen, shldata_ctx *ctx) +{ + if (!ctx->len || ctx->len != ctx->done) + return (errno = EINVAL, -1); + + char mac[16]; + ccpl_final(mac, &ctx->ccpl); + + int r; + r = patrim_put(dst, dlen, 0, ID_MAC, sizeof(mac)); + if (r < 0 || dlen - r < sizeof(mac)) + return (errno = ENOBUFS, -1); + memcpy(dst + r, mac, sizeof(mac)); + + return r + sizeof(mac); +} diff --git a/src/liblimb/shldata.h/shldata_initr.c b/src/liblimb/shldata.h/shldata_initr.c new file mode 100644 index 0000000..1e3e922 --- /dev/null +++ b/src/liblimb/shldata.h/shldata_initr.c @@ -0,0 +1,75 @@ +/* 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 <limb/hasher.h> +#include <limb/patrim.h> +#include <limb/pbkdf2.h> +#include <limb/shldata.h> +#include "shldata.h" + +ssize_t +shldata_initr(const char *sce, size_t slen, const char *pwd, size_t plen, shldata_ctx *ctx) +{ + unsigned algo, iter, o; + const char *salt; + size_t sltlen; + ssize_t aadoff; + int r; + + /* silence warnings */ + salt = NULL; + sltlen = 0; + + aadoff = -1; + o = algo = iter = 0; + for (;;) { + u64 id, u; + + r = patrim_get(&id, &u, sce, slen, o); + if (r < 0) return (errno = ENODATA, -1); + if (!patrim_isshldata(id)) { + /* skip any ID that isn't ours */ + o += r; + if (patrim_isblob(id)) + o += u; + continue; + } + if (aadoff < 0) + aadoff = o; + switch (id) { + case ID_ALGO: + algo = u + 1; + break; + case ID_ITER: + iter = u; + break; + case ID_SALT: + salt = sce + o + r; + sltlen = u; + o += sltlen; + break; + case ID_DATA: + ctx->len = u; + ctx->done = 0; + break; + default: + return (errno = EINVAL, -1); + } + if (id == ID_DATA) + break; + o += r; + } + if (!algo || !iter || !sltlen) + return (errno = EINVAL, -1); + --algo; + + char key[KEY_LEN]; + char nonce[NONCE_LEN] = { 0 }; + pbkdf2(key, sizeof(key), hashers[algo], pwd, plen, salt, sltlen, iter); + ccpl_init(key, nonce, &ctx->ccpl); + ccpl_aad(sce + aadoff, o - aadoff, &ctx->ccpl); + + /* return offset of begining of encrypted data */ + return o + r; +} diff --git a/src/liblimb/shldata.h/shldata_initw.c b/src/liblimb/shldata.h/shldata_initw.c new file mode 100644 index 0000000..163e4e1 --- /dev/null +++ b/src/liblimb/shldata.h/shldata_initw.c @@ -0,0 +1,61 @@ +/* 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 <string.h> +#include <skalibs/random.h> +#include <limb/bytestr.h> +#include <limb/hasher.h> +#include <limb/patrim.h> +#include <limb/pbkdf2.h> +#include <limb/shldata.h> +#include "shldata.h" + +ssize_t +shldata_initw(char *dst, size_t dlen, const char *pwd, size_t plen, + unsigned algo, unsigned iter, size_t len, shldata_ctx *ctx) +{ + if (algo >= NB_ALGOS || !iter) + return (errno = EINVAL, -1); + + char salt[SALT_LEN]; + random_buf(salt, sizeof(salt)); + + size_t l = 0; + int r; + + r = patrim_put(dst, dlen, l, ID_ALGO, algo); + if (r < 0) return (errno = ENOBUFS, -1); + l += r; + r = patrim_put(dst, dlen, l, ID_ITER, iter); + if (r < 0) return (errno = ENOBUFS, -1); + l += r; + r = patrim_put(dst, dlen, l, ID_SALT, sizeof(salt)); + if (r < 0) return (errno = ENOBUFS, -1); + l += r; + if (dlen - l < sizeof(salt)) + return (errno = ENOBUFS, -1); + memcpy(dst + l, salt, sizeof(salt)); + l += sizeof(salt); + + ctx->len = len; + ctx->done = 0; + + if (len) { + r = patrim_put(dst, dlen, l, ID_DATA, len); + if (r < 0) return (errno = ENOBUFS, -1); + l += r; + } else { + r = 0; + } + + char key[KEY_LEN]; + char nonce[NONCE_LEN] = { 0 }; + + pbkdf2(key, sizeof(key), hashers[algo], pwd, plen, salt, sizeof(salt), iter); + ccpl_init(key, nonce, &ctx->ccpl); + ccpl_aad(dst, l - r, &ctx->ccpl); + byte_zero(key, sizeof(key)); + + return l; +} diff --git a/src/liblimb/shldata.h/shldata_predata.c b/src/liblimb/shldata.h/shldata_predata.c new file mode 100644 index 0000000..a4c1afb --- /dev/null +++ b/src/liblimb/shldata.h/shldata_predata.c @@ -0,0 +1,23 @@ +/* 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 <limb/patrim.h> +#include <limb/shldata.h> +#include "shldata.h" + +ssize_t +shldata_predata(char *dst, size_t dlen, shldata_ctx *ctx) +{ + if (ctx->len) { + if (ctx->len != ctx->done) + return (errno = EINVAL, -1); + return 0; + } + + int r = patrim_put(dst, dlen, 0, ID_DATA, ctx->done); + if (r < 0) return (errno = ENOBUFS, -1); + + ctx->len = ctx->done; + return r; +}