--- /dev/null
+/* -*-c-*-
+ *
+ * Generic authenticated encryption interface
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "gaead.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @gaead_encrypt@ --- *
+ *
+ * Arguments: @const gaead_key *k@ = the AEAD key, already prepared
+ * @const void *n@, @size_t nsz@ = nonce
+ * @const void *h@, @size_t hsz@ = additional `header' data
+ * @const void *m@, @size_t msz@ = message input
+ * @void *c@, @size_t *csz_input@ = ciphertext output
+ * @void *t@, @size_t tsz@ = tag output
+ *
+ * Returns: Zero on success, @-1@ if the output buffer is too small.
+ *
+ * Use: Encrypts and authenticates a message in a single operation.
+ * This just saves a bunch of messing about with the various
+ * @gaead_...@ objects.
+ *
+ * On entry, @*csz_inout@ should be the capacity of the
+ * ciphertext buffer; on exit, it will be updated with the
+ * actual size of ciphertext produced. The function will not
+ * fail if @*csz_inout >= msz + k->c->ohd@.
+ */
+
+int gaead_encrypt(const gaead_key *k, const void *n, size_t nsz,
+ const void *h, size_t hsz,
+ const void *m, size_t msz,
+ void *c, size_t *csz_inout,
+ void *t, size_t tsz)
+{
+ gaead_enc *e = 0;
+ gaead_aad *a = 0;
+ buf b;
+ int rc;
+
+ buf_init(&b, c, *csz_inout);
+ e = GAEAD_ENC(k, n, nsz, hsz, msz, tsz); if (!e) { rc = -1; goto end; }
+ if (hsz) { a = GAEAD_AAD(e); GAEAD_HASH(a, h, hsz); }
+ rc = GAEAD_ENCRYPT(e, m, msz, &b); if (rc) goto end;
+ rc = GAEAD_DONE(e, a, &b, t, tsz);
+end:
+ if (rc >= 0) *csz_inout = BLEN(&b);
+ if (e) GAEAD_DESTROY(e);
+ if (a) GAEAD_DESTROY(a);
+ return (rc);
+}
+
+/* --- @gaead_decrypt@ --- *
+ *
+ * Arguments: @const gaead_key *k@ = the AEAD key, already prepared
+ * @const void *n@, @size_t nsz@ = nonce
+ * @const void *h@, @size_t hsz@ = additional `header' data
+ * @const void *c@, @size_t csz@ = ciphertext input
+ * @void *m@, @size_t *msz_inout@ = message output
+ * @const void *t@, @size_t tsz@ = tag input
+ *
+ * Returns: @+1@ if everything is good; zero for authentication failure,
+ * @-1@ for other problems.
+ *
+ * Use: Decrypts and verifies a message in a single operation.
+ * This just saves a bunch of messing about with the various
+ * @gaead_...@ objects.
+ *
+ * On entry, @*msz_inout@ should be the capacity of the
+ * message buffer; on exit, it will be updated with the
+ * actual size of message produced. The function will not
+ * fail if @*msz_inout >= csz@.
+ */
+
+int gaead_decrypt(const gaead_key *k, const void *n, size_t nsz,
+ const void *h, size_t hsz,
+ const void *c, size_t csz,
+ void *m, size_t *msz_inout,
+ const void *t, size_t tsz)
+{
+ gaead_dec *d = 0;
+ gaead_aad *a = 0;
+ buf b;
+ int rc;
+
+ buf_init(&b, m, *msz_inout);
+ d = GAEAD_DEC(k, n, nsz, hsz, csz, tsz); if (!d) { rc = -1; goto end; }
+ if (hsz) { a = GAEAD_AAD(d); GAEAD_HASH(a, h, hsz); }
+ rc = GAEAD_DECRYPT(d, c, csz, &b); if (rc) goto end;
+ rc = GAEAD_DONE(d, a, &b, t, tsz);
+end:
+ if (rc >= 0) *msz_inout = BLEN(&b);
+ if (d) GAEAD_DESTROY(d);
+ if (a) GAEAD_DESTROY(a);
+ return (rc);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * Generic authenticated encryption interface
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef CATACOMB_GAEAD_H
+#define CATACOMB_GAEAD_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+
+#ifndef CATACOMB_BUF_H
+# include "buf.h"
+#endif
+
+#ifndef CATACOMB_KEYSZ_H
+# include "keysz.h"
+#endif
+
+/*----- Generic AEAD interface --------------------------------------------*/
+
+typedef struct gaead_key {
+ const struct gaead_keyops *ops;
+} gaead_key;
+
+typedef struct gaead_enc {
+ const struct gaead_encops *ops;
+} gaead_enc;
+
+typedef struct gaead_dec {
+ const struct gaead_decops *ops;
+} gaead_dec;
+
+typedef struct gaead_aad {
+ const struct gaead_aadops *ops;
+} gaead_aad;
+
+typedef struct gaead_keyops {
+ const struct gcaead *c; /* Pointer to AEAD class */
+
+ gaead_aad *(*aad)(const gaead_key */*k*/);
+ /* Return an AAD-hashing object for this key. Only available if
+ * the @AEADF_AADNDEP@ class flag is clear.
+ */
+
+ gaead_enc *(*enc)(const gaead_key */*k*/,
+ const void */*n*/, size_t /*nsz*/,
+ size_t /*hsz*/, size_t /*msz*/, size_t /*tsz*/);
+ /* Return a message encryption object for this key, with the given
+ * nonce. If the @AEADF_PCHSZ@, @AEADF_PCMSZ@ and/or @AEADF_PCTSZ@
+ * class flags are set then the caller must provide the AAD length
+ * @hsz@, message length @msz@ and/or tag length @tsz@ respectively;
+ * otherwise these arguments will be ignored.
+ *
+ * The caller is expected to have ensured that the nonce and tag
+ * lengths are acceptable, e.g., by checking against the tables
+ * provided in the class object. Some unfortunate AEAD schemes have
+ * more complicated requirements: if the sizes are unacceptable in
+ * combination, this function returns null.
+ */
+
+ gaead_dec *(*dec)(const gaead_key */*k*/,
+ const void */*n*/, size_t /*nsz*/,
+ size_t /*hsz*/, size_t /*csz*/, size_t /*tsz*/);
+ /* Return a message encryption object for this key, with the given
+ * nonce. If the @AEADF_PCHSZ@, @AEADF_PCMSZ@ and/or @AEADF_PCTSZ@
+ * class flags are set then the caller must provide the AAD length
+ * @hsz@, ciphertext length @csz@ and/or tag length @tsz@
+ * respectively; otherwise these arguments will be ignored.
+ *
+ * The caller is expected to have ensured that the nonce and tag
+ * lengths are acceptable, e.g., by checking against the tables
+ * provided in the class object. Some unfortunate AEAD schemes have
+ * more complicated requirements: if the sizes are unacceptable in
+ * combination, this function returns null.
+ */
+
+ void (*destroy)(gaead_key */*k*/);
+ /* Destroy the key object. This will not invalidate AAD-hashing,
+ * encryption or decryption objects.
+ */
+
+} gaead_keyops;
+
+typedef struct gaead_aadops {
+ const struct gcaead *c; /* Pointer to AEAD class */
+
+ gaead_aad *(*dup)(const gaead_aad */*a*/);
+ /* Return a new AAD-hashing object with a copy of this object's
+ * state. This is useful if the AAD for multiple messages shares a
+ * common prefix: the prefix can be processed once, and a copy
+ * created for each different suffix. Only available if the
+ * @AEADF_AADNDEP@ class flag is clear.
+ */
+
+ void (*hash)(gaead_aad */*a*/, const void */*h*/, size_t /*hsz*/);
+ /* Feed header (additional authenticated) data into the AAD-hashing
+ * object.
+ */
+
+ void (*destroy)(gaead_aad */*a*/);
+ /* Destroy the AAD-hashing object. */
+
+} gaead_aadops;
+
+typedef struct gaead_encops {
+ const struct gcaead *c; /* Pointer to AEAD class */
+
+ gaead_aad *(*aad)(gaead_enc */*e*/);
+ /* Return a new AAD-hashing object for the current key and nonce. If
+ * the @AEADF_AADNDEP@ class flag is clear then this works just as if
+ * the @aad@ method on the key had been called instead: the new
+ * object is in fact independent of the nonce and can be used with
+ * any encryption or decryption operation. If @AEADF_AADNDEP@ is
+ * set, then the returned AAD-hashing object is specific to this
+ * encryption operation. If @AEADF_AADFIRST@ is also set, then all
+ * additional data must be hashed before any message data is
+ * presented for encryption.
+ */
+
+ int (*reinit)(gaead_enc */*e*/, const void */*n*/, size_t /*nsz*/,
+ size_t /*hsz*/, size_t /*msz*/, size_t /*tsz*/);
+ /* Reinitialize this object for a new encryption operation with a
+ * different nonce. The data lengths @hsz@, @msz@, and @tsz@ are as
+ * for the key @enc@ method. Returns zero on success.
+ *
+ * The caller is expected to have ensured that the nonce and tag
+ * lengths are acceptable, e.g., by checking against the tables
+ * provided in the class object. Some unfortunate AEAD schemes have
+ * more complicated requirements: if the sizes are unacceptable in
+ * combination, this function returns @-1@.
+ */
+
+ int (*encrypt)(gaead_enc */*e*/, const void */*m*/, size_t /*msz*/,
+ buf */*b*/);
+ /* Encrypt a chunk of data, writing the result to the output buffer
+ * @b@. This will succeed if @BLEFT(b) >= msz + e->c->bufsz@;
+ * otherwise it might fail. Failure doesn't affect the encryption
+ * operation's state. Returns zero on success, or @-1@ on failure.
+ */
+
+ int (*done)(gaead_enc */*e*/, const gaead_aad */*a*/, buf */*b*/,
+ void */*t*/, size_t /*tsz*/);
+ /* Completes encryption, returning the authentication tag for the
+ * message and any additional authenticated data accumulated in @a@.
+ * The pointer @a@ may be null if there is no AAD. If the
+ * @AEADF_AADNDEP@ class flag is set, and any header data has been
+ * provided to the operation's AAD-hashing object, then a pointer to
+ * this object must be provided as @a@. If @AEADF_AADNDEP@ is clear,
+ * then any AAD-hashing object for this key may be provided.
+ * Internally buffered ciphertext may be written to @b@. This will
+ * succeed if @BLEFT(b) >= e->c->bufsz@; otherwise it might fail.
+ * Failure doesn't affect the encryption operation's state. Returns
+ * zero on success, or @-1@ on failure.
+ */
+
+ void (*destroy)(gaead_enc */*e*/);
+ /* Destroy the encryption object. */
+
+} gaead_encops;
+
+typedef struct gaead_decops {
+ const struct gcaead *c; /* Pointer to AEAD class */
+
+ gaead_aad *(*aad)(gaead_dec */*d*/);
+ /* Return a new AAD-hashing object for the current key and nonce. If
+ * the @AEADF_AADNDEP@ class flag is clear then this works just as if
+ * the @aad@ method on the key had been called instead: the new
+ * object is in fact independent of the nonce and can be used with
+ * any encryption or decryption operation. If @AEADF_AADNDEP@ is
+ * set, then the returned AAD-hashing object is specific to this
+ * decryption operation. If @AEADF_AADFIRST@ is also set, then all
+ * additional data must be hashed before any ciphertext is presented
+ * for decryption.
+ */
+
+ int (*reinit)(gaead_dec */*d*/, const void */*n*/, size_t /*nsz*/,
+ size_t /*hsz*/, size_t /*csz*/, size_t /*tsz*/);
+ /* Reinitialize this object for a new decryption operation with a
+ * different nonce. The data lengths @hsz@, @csz@, and @tsz@ are as
+ * for the key @dec@ method.
+ *
+ * The caller is expected to have ensured that the nonce and tag
+ * lengths are acceptable, e.g., by checking against the tables
+ * provided in the class object. Some unfortunate AEAD schemes have
+ * more complicated requirements: if the sizes are unacceptable in
+ * combination, this function returns @-1@.
+ */
+
+ int (*decrypt)(gaead_dec */*d*/, const void */*c*/, size_t /*csz*/,
+ buf */*b*/);
+ /* Decrypt a chunk of data, writing the result to the output buffer
+ * @b@. This will succeed if @BLEFT(b) >= msz + e->c->bufsz@;
+ * otherwise it might fail. Failure doesn't affect the decryption
+ * operation's state. Returns zero on success, or @-1@ on failure.
+ *
+ * CAUTION: the decrypted data may be inauthentic. Don't do anything
+ * risky with it until its tag has been verified.
+ */
+
+ int (*done)(gaead_dec */*d*/, const gaead_aad */*a*/, buf */*b*/,
+ const void */*t*/, size_t /*tsz*/);
+ /* Completes decryption, verifying the authentication tag for the
+ * message and any additional authenticated data accumulated in @a@.
+ * The pointer @a@ may be null if there is no AAD. If the
+ * @AEADF_AADNDEP@ class flag is set, and any header data has been
+ * provided to the operation's AAD-hashing object, then a pointer to
+ * this object must be provided as @a@. If @AEADF_AADNDEP@ is clear,
+ * then any AAD-hashing object for this key may be provided.
+ * Internally buffered plaintext may be written to @b@. This will
+ * succeed if @BLEFT(b) >= e->c->bufsz@; otherwise it might fail.
+ * Failure doesn't affect the decryption operation's state. Returns
+ * @+1@ on success, @0@ on verification failure, or @-1@ on other
+ * kinds of failures.
+ */
+
+ void (*destroy)(gaead_dec */*d*/);
+ /* Destroy the decryption object. */
+
+} gaead_decops;
+
+typedef struct gcaead {
+ const char *name; /* AEAD scheme name */
+ const octet *keysz; /* Acceptable keys-size table */
+ const octet *noncesz; /* Acceptable nonce-size table */
+ const octet *tagsz; /* Acceptable tag-size table */
+ size_t blksz; /* Block size, or zero if none */
+ unsigned bufsz; /* Maximum extra msg/ct output */
+ unsigned ohd; /* Maximum encryption overhead */
+ unsigned f; /* Various other flags */
+#define AEADF_PCHSZ 1u /* Precommit to AAD size */
+#define AEADF_PCMSZ 2u /* Precommit to message size */
+#define AEADF_PCTSZ 4u /* Precommit to tag size */
+#define AEADF_AADNDEP 8u /* AAD hash is nonce-dependent */
+#define AEADF_AADFIRST 16u /* AAD must precede msg/ct */
+
+ gaead_key *(*key)(const void */*k*/, size_t /*ksz*/);
+ /* Return a key object (above) with the given key material. */
+
+ int (*szok)(size_t /*nsz*/, size_t /*hsz*/,
+ size_t /*msz*/, size_t /*tsz*/);
+ /* Return true (nonzero) if the given collection of sizes for nonce,
+ * header, message, and tag are acceptable in combination. Mostly
+ * this will be true if the nonce length and tag size are are
+ * acceptable independently (and the header and message lengths are
+ * irrelevant), but some schemes are more awkward.
+ */
+} gcaead;
+
+#define GAEAD_KEY(cc, k, ksz) (cc)->key((k), (ksz))
+#define GAEAD_CLASS(obj) (obj)->ops->c
+#define GAEAD_AAD(ked) (ked)->ops->aad((ked))
+#define GAEAD_REINIT(ed, n, nsz, hsz, msz, tsz) \
+ (ed)->ops->reinit((ed), (n), (nsz), (hsz), (msz), (tsz))
+#define GAEAD_ENC(k, n, nsz, hsz, msz, tsz) \
+ (k)->ops->enc((k), (n), (nsz), (hsz), (msz), (tsz))
+#define GAEAD_DEC(k, n, nsz, hsz, msz, tsz) \
+ (k)->ops->dec((k), (n), (nsz), (hsz), (msz), (tsz))
+#define GAEAD_DUP(a) (a)->ops->dup((a))
+#define GAEAD_HASH(a, h, hsz) (a)->ops->hash((a), (h), (hsz))
+#define GAEAD_ENCRYPT(e, m, msz, b) \
+ (e)->ops->encrypt((e), (m), (msz), (b))
+#define GAEAD_DECRYPT(d, c, csz, b) \
+ (d)->ops->decrypt((d), (c), (csz), (b))
+#define GAEAD_DONE(ed, aad, b, t, tsz) \
+ (ed)->ops->done((ed), (aad), (b), (t), (tsz))
+#define GAEAD_DESTROY(obj) (obj)->ops->destroy((obj))
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @gaead_szokcommon@ --- *
+ *
+ * Arguments: @const gcaead *aec@ = pointer to AEAD class
+ * @size_t nsz@, @size_t hsz@, @size_t msz@, @size_t tsz@ =
+ * nonce, header, message, and tag sizes
+ *
+ * Returns: Nonzero if the sizes are acceptable to the AEAD scheme in
+ * combination.
+ *
+ * Use: Generic implementation for sensible AEAD schemes.
+ */
+
+extern int gaead_szokcommon(const gcaead */*aec*/,
+ size_t /*nsz*/, size_t /*hsz*/,
+ size_t /*msz*/, size_t /*tsz*/);
+
+/* --- @gaead_encrypt@ --- *
+ *
+ * Arguments: @const gaead_key *k@ = the AEAD key, already prepared
+ * @const void *n@, @size_t nsz@ = nonce
+ * @const void *h@, @size_t hsz@ = additional `header' data
+ * @const void *m@, @size_t msz@ = message input
+ * @void *c@, @size_t *csz_input@ = ciphertext output
+ * @void *t@, @size_t tsz@ = tag output
+ *
+ * Returns: Zero on success, @-1@ if the output buffer is too small.
+ *
+ * Use: Encrypts and authenticates a message in a single operation.
+ * This just saves a bunch of messing about with the various
+ * @gaead_...@ objects.
+ *
+ * On entry, @*csz_inout@ should be the capacity of the
+ * ciphertext buffer; on exit, it will be updated with the
+ * actual size of ciphertext produced. The function will not
+ * fail if @*csz_inout >= msz + k->c->ohd@.
+ */
+
+extern int gaead_encrypt(const gaead_key */*k*/,
+ const void */*n*/, size_t /*nsz*/,
+ const void */*h*/, size_t /*hsz*/,
+ const void */*m*/, size_t /*msz*/,
+ void */*c*/, size_t */*csz_inout*/,
+ void */*t*/, size_t /*tsz*/);
+
+/* --- @gaead_decrypt@ --- *
+ *
+ * Arguments: @const gaead_key *k@ = the AEAD key, already prepared
+ * @const void *n@, @size_t nsz@ = nonce
+ * @const void *h@, @size_t hsz@ = additional `header' data
+ * @const void *c@, @size_t csz@ = ciphertext input
+ * @void *m@, @size_t *msz_inout@ = message output
+ * @const void *t@, @size_t tsz@ = tag input
+ *
+ * Returns: @+1@ if everything is good; zero for authentication failure,
+ * @-1@ for other problems.
+ *
+ * Use: Decrypts and verifies a message in a single operation.
+ * This just saves a bunch of messing about with the various
+ * @gaead_...@ objects.
+ *
+ * On entry, @*msz_inout@ should be the capacity of the
+ * message buffer; on exit, it will be updated with the
+ * actual size of message produced. The function will not
+ * fail if @*msz_inout >= csz@.
+ */
+
+extern int gaead_decrypt(const gaead_key */*k*/,
+ const void */*n*/, size_t /*nsz*/,
+ const void */*h*/, size_t /*hsz*/,
+ const void */*c*/, size_t /*csz*/,
+ void */*m*/, size_t */*msz_inout*/,
+ const void */*t*/, size_t /*tsz*/);
+
+/*----- Tables ------------------------------------------------------------*/
+
+extern const gcaead *const gaeadtab[];
+
+/* --- @gaead_byname@ --- *
+ *
+ * Arguments: @const char *p@ = pointer to name string
+ *
+ * Returns: The named AEAD class, or null.
+ */
+
+extern const gcaead *gaead_byname(const char */*p*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif