author | Olivier Brunel
<jjk@jjacky.com> 2023-04-28 19:59:05 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2023-05-20 18:06:38 UTC |
parent | f66014223dffbcdd65fd704c4b468de5c8b3a8a1 |
src/doc/ccpl.h.0.md | +44 | -0 |
src/doc/ccpl.h/ccpl_init.3.md | +89 | -0 |
src/doc/chacha20.h/chacha20_init.3.md | +4 | -0 |
src/doc/poly1305.h/poly1305_init.3.md | +1 | -1 |
src/liblimb/ccpl.h/ccpl_aad.c | +18 | -0 |
src/liblimb/ccpl.h/ccpl_crypt.c | +30 | -0 |
src/liblimb/ccpl.h/ccpl_final.c | +28 | -0 |
src/liblimb/ccpl.h/ccpl_init.c | +23 | -0 |
src/liblimb/include/limb/ccpl.h | +28 | -0 |
diff --git a/src/doc/ccpl.h.0.md b/src/doc/ccpl.h.0.md new file mode 100644 index 0000000..c79565b --- /dev/null +++ b/src/doc/ccpl.h.0.md @@ -0,0 +1,44 @@ +% limb manual +% ccpl.h(0) + +# NAME + +ccpl.h - ChaCha20-Poly1305 AEAD encryption + +# SYNOPSIS + + #include <limb/ccpl.h> + +# DESCRIPTION + +This header defines the required function to encrypt/decrypt messages using the +ChaCha20-Poly1305 AEAD algorithm. + +## Types + +The following types are defined : + +: *ccpl_ctx* +:: An opaque structure to be given to the functions below. + +## Functions + +The following functions/macros are defined : + +: [ccpl_init](3) +:: To initialize a ccpl context. + +: [ccpl_aad](3) +:: To feed additional data into a ccpl context. + +: [ccpl_crypt](3) +:: To crypt data using a ccpl context. + +: [ccpl_encrypt](3) +:: To encrypt data using a ccpl context; + +: [ccpl_decrupt](3) +:: To decrypt data using a ccpl context. + +: [ccpl_final](3) +:: To obtain the MAC from a ccpl context. diff --git a/src/doc/ccpl.h/ccpl_init.3.md b/src/doc/ccpl.h/ccpl_init.3.md new file mode 100644 index 0000000..a004d13 --- /dev/null +++ b/src/doc/ccpl.h/ccpl_init.3.md @@ -0,0 +1,89 @@ +% limb manual +% ccpl_init(3) + +# NAME + +ccpl\_init, ccpl\_aad, ccpl\_crypt, ccpl\_encrypt, ccpl\_decrypt, ccpl\_final - +encrypt/decrypt data using the ChaCha20-Poly1305 algorithm + +# SYNOPSIS + + #include <limb/ccpl.h> + +```pre hl +void ccpl_init(void *<em>key</em>, void *<em>nonce</em>, void *<em>ctx</em>) +int ccpl_aad(const void *<em>data</em>, size_t <em>dlen</em>, void *<em>ctx</em>) +void ccpl_crypt(void *<em>dst</em>, const void *<em>data</em>, size_t <em>dlen</em>, int <em>encrypt</em>, void *<em>ctx</em>) +void ccpl_encrypt(void *<em>dst</em>, const void *<em>data</em>, size_t <em>dlen</em>, void *<em>ctx</em>) +void ccpl_decrypt(void *<em>dst</em>, const void *<em>data</em>, size_t <em>dlen</em>, void *<em>ctx</em>) +void ccpl_final(void *<em>dst</em>, void *<em>ctx</em>) +``` + +# DESCRIPTION + +The `ccpl_init`() function initializes the given ccpl context pointed by `ctx` +to encrypt/decrypt data using the ChaCha20-Poly1305 authenticated encryption +with additional data (AEAD) algorithm. + +This implementation is conform to [RFC 8439][rfc8439], as such the key pointed +to by `key` must be 256bit/32 bytes long, and the nonce pointed.by `nonce` must +be 96bit/12 bytes long. + +In order to be secure, the given `nonce` must be different for each invocation +with the same `key`. + +Limitations of message length are the same as described in [chacha20_init](3), +however an additional limitation, specific to this combined algorithm, also +applies, and brings the maximum size of both the additional data and the +encrypted data to 2^64 bytes each. + +[rfc8439] (https://datatracker.ietf.org/doc/html/rfc8439) + +First, the `ccpl_aad`() function must be used to feed additional data pointed by +`data` of length `dlen` into the ccpl context pointed by `ctx`. Such data will +not be encrypted, but will be covered by the authentication code generated using +the Poly1305 algorithm. +You can call this function as many times as needed. + +Then, the `ccpl_crypt`() function can be used to either encrypt or decrypt data +pointed by `data` of length `dlen` into the memory pointed by `dst` (which must +be able to store `dlen` bytes). + +As with [chacha20_crypt](3) it is possible to use the same memory area for both +`data` and `dst`, and have it processed in-place. + +Though the data processing is the same for encrypting and decrypting using the +ChaCha20 cipher, a difference is made regarding the Poly1305 MAC, as it is +always the /encrypted/ data that must be fed into it. +This is why the argument `encrypt` is needed, and must be a set to 1 when +encrypting data (thus feeding it to Poly1305 /after/ processing through +the ChaCha20 cipher), and set to 0 when decrypting data (thus feeding it to +Poly1305 /before/ processing through the ChaCha20 cipher). + +All calls must be either of encrypting or decrypting, mixing both is invalid. +However, you can call the function (with the same value for `encrypt`) as many +times as needed. + +As a convenience, the `ccpl_encrypt`() and `ccpl_decrypt`() macros are provided. + +! Additional Data First +! It is required that all additional data - fed through the `ccpl_aad`() +! function - be fed into the ccpl `ctx` /before/ any call is made to +! `ccpl_crypt`(). + +The `ccpl_final`() function stores the computed Poly1305-based MAC from `ctx` +in binary form into `dst`, which must be able to store 16 bytes. + +When decrypting data, the stored MAC should be compared to the one accompanying +the data. If bitwise identical, both the decrypted data and the additional data +fed into the ccpl `ctx` have been authenticated. + +# RETURN VALUE + +The `ccpl_aad`() function returns 1 on success, and 0 on failure. The only +possible failure case is if a call to `ccpl_crypt`() has already been made for +the same context. + +# SEE ALSO + +[chacha20_init](3), [poly1305_init](3) diff --git a/src/doc/chacha20.h/chacha20_init.3.md b/src/doc/chacha20.h/chacha20_init.3.md index 64f9e6f..a00a1b8 100644 --- a/src/doc/chacha20.h/chacha20_init.3.md +++ b/src/doc/chacha20.h/chacha20_init.3.md @@ -53,3 +53,7 @@ first. The `chacha20`() function can be used as convenience if the entire message can be stored in a continuous memory area, to encrypt/decrypt it in a single call. + +# SEE ALSO + +[ccpl_init](3) diff --git a/src/doc/poly1305.h/poly1305_init.3.md b/src/doc/poly1305.h/poly1305_init.3.md index 2808036..0f5108a 100644 --- a/src/doc/poly1305.h/poly1305_init.3.md +++ b/src/doc/poly1305.h/poly1305_init.3.md @@ -36,4 +36,4 @@ form into `dst`, which must be able to store 16 bytes. # SEE ALSO -[hmac](3) +[hmac](3), [ccpl_init](3) diff --git a/src/liblimb/ccpl.h/ccpl_aad.c b/src/liblimb/ccpl.h/ccpl_aad.c new file mode 100644 index 0000000..4b0f48f --- /dev/null +++ b/src/liblimb/ccpl.h/ccpl_aad.c @@ -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 */ +#include <limb/ccpl.h> + +int +ccpl_aad(const void *data, size_t dlen, void *ctx_) +{ + ccpl_ctx *ctx = ctx_; + + /* can't be called after calls to ccpl_crypt() */ + if (ctx->w) return 0; + + poly1305_update(data, dlen, &ctx->pl); + ctx->alen += dlen; + + return 1; +} diff --git a/src/liblimb/ccpl.h/ccpl_crypt.c b/src/liblimb/ccpl.h/ccpl_crypt.c new file mode 100644 index 0000000..5190378 --- /dev/null +++ b/src/liblimb/ccpl.h/ccpl_crypt.c @@ -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 */ +#include <string.h> +#include <limb/ccpl.h> + +void +ccpl_crypt(void *dst, const void *data, size_t dlen, int encrypt, void *ctx_) +{ + ccpl_ctx *ctx = ctx_; + + if (!ctx->w) { + size_t l = 16 - (ctx->alen % 16); + if (l) { + char pad[l]; + memset(pad, 0, l); + poly1305_update(pad, l, &ctx->pl); + } + } + ctx->w = 1; + + if (!encrypt) + poly1305_update(data, dlen, &ctx->pl); + + chacha20_crypt(dst, data, dlen, &ctx->cc); + ctx->dlen += dlen; + + if (encrypt) + poly1305_update(dst, dlen, &ctx->pl); +} diff --git a/src/liblimb/ccpl.h/ccpl_final.c b/src/liblimb/ccpl.h/ccpl_final.c new file mode 100644 index 0000000..2e8beda --- /dev/null +++ b/src/liblimb/ccpl.h/ccpl_final.c @@ -0,0 +1,28 @@ +/* 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 <string.h> +#include <limb/ccpl.h> +#include <limb/u64.h> + +void +ccpl_final(void *dst, void *ctx_) +{ + ccpl_ctx *ctx = ctx_; + + size_t l = 16 - (((ctx->w) ? ctx->dlen : ctx->alen) % 16); + if (l) { + char pad[l]; + memset(pad, 0, l); + poly1305_update(pad, l, &ctx->pl); + } + + u64p_le(&ctx->alen); + poly1305_update(&ctx->alen, sizeof(u64), &ctx->pl); + + u64p_le(&ctx->dlen); + poly1305_update(&ctx->dlen, sizeof(u64), &ctx->pl); + + poly1305_final(dst, &ctx->pl); + chacha20_clear(&ctx->cc); +} diff --git a/src/liblimb/ccpl.h/ccpl_init.c b/src/liblimb/ccpl.h/ccpl_init.c new file mode 100644 index 0000000..d09634c --- /dev/null +++ b/src/liblimb/ccpl.h/ccpl_init.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 <limb/ccpl.h> +#include <limb/u32.h> + +void +ccpl_init(void *key, void *nonce, void *ctx_) +{ + ccpl_ctx *ctx = ctx_; + + char k[32] = { 0 }; + chacha20_init(key, nonce, &ctx->cc); + chacha20_crypt(k, k, sizeof(k), &ctx->cc); + poly1305_init(k, &ctx->pl); + + chacha20_init(key, nonce, &ctx->cc); + ctx->cc.in[12] = 1; + u32p_le(&ctx->cc.in[12]); + + ctx->alen = ctx->dlen = 0; + ctx->w = 0; +} diff --git a/src/liblimb/include/limb/ccpl.h b/src/liblimb/include/limb/ccpl.h new file mode 100644 index 0000000..fb7ec6b --- /dev/null +++ b/src/liblimb/include/limb/ccpl.h @@ -0,0 +1,28 @@ +/* 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_CCPL_H +#define LIMB_CCPL_H + +#include <limb/chacha20.h> +#include <limb/int.h> +#include <limb/poly1305.h> + +struct ccpl_ctx { + struct chacha20_ctx cc; + struct poly1305_ctx pl; + u64 alen; + u64 dlen; + u8 w; +}; + +typedef struct ccpl_ctx ccpl_ctx; + +extern void ccpl_init(void *key, void *nonce, void *ctx); +extern int ccpl_aad(const void *data, size_t dlen, void *ctx); +extern void ccpl_crypt(void *dst, const void *data, size_t dlen, int encrypt, void *ctx); +#define ccpl_encrypt(dst,data,dlen,ctx) ccpl_crypt(dst, data, dlen, 1, ctx) +#define ccpl_decrypt(dst,data,dlen,ctx) ccpl_crypt(dst, data, dlen, 0, ctx) +extern void ccpl_final(void *dst, void *ctx); + +#endif /* LIMB_CCPL_H */