symm: Implement Bernstein's ChaCha stream cipher.
[catacomb] / symm / chacha.h
diff --git a/symm/chacha.h b/symm/chacha.h
new file mode 100644 (file)
index 0000000..f46eab9
--- /dev/null
@@ -0,0 +1,357 @@
+/* -*-c-*-
+ *
+ * ChaCha stream cipher
+ *
+ * (c) 2015 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_CHACHA_H
+#define CATACOMB_CHACHA_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+#ifndef CATACOMB_GCIPHER_H
+#  include "gcipher.h"
+#endif
+
+#ifndef CATACOMB_GRAND_H
+#  include "grand.h"
+#endif
+
+/*----- Constants ---------------------------------------------------------*/
+
+#define CHACHA_NONCESZ 8u
+#define CHACHA_KEYSZ 32u
+#define CHACHA_OUTSZ 64u
+
+#define HCHACHA_INSZ 16u
+#define HCHACHA_OUTSZ 32u
+
+#define XCHACHA_NONCESZ 24u
+#define XCHACHA_KEYSZ CHACHA_KEYSZ
+#define XCHACHA_OUTSZ CHACHA_OUTSZ
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef uint32 chacha_matrix[16];
+
+typedef struct chacha_ctx {
+  chacha_matrix a;
+  octet buf[CHACHA_OUTSZ];
+  size_t bufi;
+} chacha_ctx;
+
+#define XCHACHA_DEFCTX(name)                                           \
+  typedef struct name { chacha_ctx s; chacha_matrix k; } name
+XCHACHA_DEFCTX(xchacha20_ctx);
+XCHACHA_DEFCTX(xchacha12_ctx);
+XCHACHA_DEFCTX(xchacha8_ctx);
+
+/*----- The ChaCha stream cipher ------------------------------------------*/
+
+/* --- @chacha_init@ --- *
+ *
+ * Arguments:  @chacha_ctx *ctx@ = context to fill in
+ *             @const void *key@ = pointer to key material
+ *             @size_t ksz@ = size of key (either 32 or 16)
+ *             @const void *nonce@ = initial nonce, or null
+ *
+ * Returns:    ---
+ *
+ * Use:                Initializes a ChaCha context ready for use.
+ */
+
+extern void chacha_init(chacha_ctx */*ctx*/,
+                        const void */*key*/, size_t /*ksz*/,
+                        const void */*nonce*/);
+
+/* --- @chacha_setnonce@ --- *
+ *
+ * Arguments:  @chacha_ctx *ctx@ = pointer to context
+ *             @const void *nonce@ = the nonce (@CHACHA_NONCESZ@ bytes)
+ *
+ * Returns:    ---
+ *
+ * Use:                Set a new nonce in the context @ctx@, e.g., for processing a
+ *             different message.  The stream position is reset to zero (see
+ *             @chacha_seek@ etc.).
+ */
+
+extern void chacha_setnonce(chacha_ctx */*ctx*/, const void */*nonce*/);
+
+/* --- @chacha_seek@, @chacha_seeku64@ --- *
+ *
+ * Arguments:  @chacha_ctx *ctx@ = pointer to context
+ *             @unsigned long i@, @kludge64 i@ = new position to set
+ *
+ * Returns:    ---
+ *
+ * Use:                Sets a new stream position, in units of ChaCha output
+ *             blocks, which are @CHACHA_OUTSZ@ bytes each.  Byte
+ *             granularity can be achieved by calling @chacha_encrypt@
+ *             appropriately.
+ */
+
+extern void chacha_seek(chacha_ctx */*ctx*/, unsigned long /*i*/);
+extern void chacha_seeku64(chacha_ctx */*ctx*/, kludge64 /*i*/);
+
+/* --- @chacha_tell@, @chacha_tellu64@ --- *
+ *
+ * Arguments:  @chacha_ctx *ctx@ = pointer to context
+ *
+ * Returns:    The current position in the output stream, in blocks,
+ *             rounding upwards.
+ */
+
+extern unsigned long chacha_tell(chacha_ctx */*ctx*/);
+extern kludge64 chacha_tellu64(chacha_ctx */*ctx*/);
+
+/* --- @chacha{20,12,8}_encrypt@ --- *
+ *
+ * Arguments:  @chacha_ctx *ctx@ = pointer to context
+ *             @const void *src@ = source buffer (or null)
+ *             @void *dest@ = destination buffer (or null)
+ *             @size_t sz@ = size of the buffers
+ *
+ * Returns:    ---
+ *
+ * Use:                Encrypts or decrypts @sz@ bytes of data from @src@ to @dest@.
+ *             ChaCha works by XORing plaintext with a keystream, so
+ *             encryption and decryption are the same operation.  If @dest@
+ *             is null then ignore @src@ and skip @sz@ bytes of the
+ *             keystream.  If @src@ is null, then just write the keystream
+ *             to @dest@.
+ */
+
+extern void chacha20_encrypt(chacha_ctx */*ctx*/,
+                            const void */*src*/, void */*dest*/,
+                            size_t /*sz*/);
+extern void chacha12_encrypt(chacha_ctx */*ctx*/,
+                             const void */*src*/, void */*dest*/,
+                             size_t /*sz*/);
+extern void chacha8_encrypt(chacha_ctx */*ctx*/,
+                             const void */*src*/, void */*dest*/,
+                             size_t /*sz*/);
+
+/*----- The HChaCha pseudorandom function ---------------------------------*/
+
+/* --- @hchacha{20,12,8}_prf@ --- *
+ *
+ * Arguments:  @chacha_ctx *ctx@ = pointer to context
+ *             @const void *src@ = the input (@HCHACHA_INSZ@ bytes)
+ *             @void *dest@ = the output (@HCHACHA_OUTSZ@ bytes)
+ *
+ * Returns:    ---
+ *
+ * Use:                Apply the HChaCha/r pseudorandom function to @src@, writing
+ *             the result to @out@.
+ */
+
+extern void hchacha20_prf(chacha_ctx */*ctx*/,
+                         const void */*src*/, void */*dest*/);
+extern void hchacha12_prf(chacha_ctx */*ctx*/,
+                         const void */*src*/, void */*dest*/);
+extern void hchacha8_prf(chacha_ctx */*ctx*/,
+                        const void */*src*/, void */*dest*/);
+
+/*----- The XChaCha stream cipher ----------------------------------------*/
+
+/* --- @xchacha{20,12,8}_init@ --- *
+ *
+ * Arguments:  @xchachaR_ctx *ctx@ = the context to fill in
+ *             @const void *key@ = pointer to key material
+ *             @size_t ksz@ = size of key (either 32 or 16)
+ *             @const void *nonce@ = initial nonce, or null
+ *
+ * Returns:    ---
+ *
+ * Use:                Initializes an XChaCha/r context ready for use.
+ *
+ *             There is a different function for each number of rounds,
+ *             unlike for plain ChaCha.
+ */
+
+extern void xchacha20_init(xchacha20_ctx */*ctx*/,
+                          const void */*key*/, size_t /*ksz*/,
+                          const void */*nonce*/);
+extern void xchacha12_init(xchacha12_ctx */*ctx*/,
+                           const void */*key*/, size_t /*ksz*/,
+                           const void */*nonce*/);
+extern void xchacha8_init(xchacha8_ctx */*ctx*/,
+                          const void */*key*/, size_t /*ksz*/,
+                          const void */*nonce*/);
+
+/* --- @xchacha{20,12,8}_setnonce@ --- *
+ *
+ * Arguments:  @xchachaR_ctx *ctx@ = pointer to context
+ *             @const void *nonce@ = the nonce (@XCHACHA_NONCESZ@ bytes)
+ *
+ * Returns:    ---
+ *
+ * Use:                Set a new nonce in the context @ctx@, e.g., for processing a
+ *             different message.  The stream position is reset to zero (see
+ *             @chacha_seek@ etc.).
+ *
+ *             There is a different function for each number of rounds,
+ *             unlike for plain ChaCha.
+ */
+
+extern void xchacha20_setnonce(xchacha20_ctx */*ctx*/,
+                              const void */*nonce*/);
+extern void xchacha12_setnonce(xchacha12_ctx */*ctx*/,
+                               const void */*nonce*/);
+extern void xchacha8_setnonce(xchacha8_ctx */*ctx*/,
+                              const void */*nonce*/);
+
+/* --- @xchacha{20,12,8}_seek@, @xchacha{20,12,8}_seeku64@ --- *
+ *
+ * Arguments:  @xchachaR_ctx *ctx@ = pointer to context
+ *             @unsigned long i@, @kludge64 i@ = new position to set
+ *
+ * Returns:    ---
+ *
+ * Use:                Sets a new stream position, in units of ChaCha output
+ *             blocks, which are @XCHACHA_OUTSZ@ bytes each.  Byte
+ *             granularity can be achieved by calling @xchachaR_encrypt@
+ *             appropriately.
+ *
+ *             There is a different function for each number of rounds,
+ *             unlike for plain ChaCha, because the context structures are
+ *             different.
+ */
+
+extern void xchacha20_seek(xchacha20_ctx */*ctx*/, unsigned long /*i*/);
+extern void xchacha12_seek(xchacha12_ctx */*ctx*/, unsigned long /*i*/);
+extern void xchacha8_seek(xchacha8_ctx */*ctx*/, unsigned long /*i*/);
+extern void xchacha20_seeku64(xchacha20_ctx */*ctx*/, kludge64 /*i*/);
+extern void xchacha12_seeku64(xchacha12_ctx */*ctx*/, kludge64 /*i*/);
+extern void xchacha8_seeku64(xchacha8_ctx */*ctx*/, kludge64 /*i*/);
+
+/* --- @xchacha{20,12,8}_tell@, @xchacha{20,12,8}_tellu64@ --- *
+ *
+ * Arguments:  @chacha_ctx *ctx@ = pointer to context
+ *
+ * Returns:    The current position in the output stream, in blocks,
+ *             rounding upwards.
+ *
+ *             There is a different function for each number of rounds,
+ *             unlike for plain ChaCha, because the context structures are
+ *             different.
+ */
+
+extern unsigned long xchacha20_tell(xchacha20_ctx */*ctx*/);
+extern unsigned long xchacha12_tell(xchacha12_ctx */*ctx*/);
+extern unsigned long xchacha8_tell(xchacha8_ctx */*ctx*/);
+extern kludge64 xchacha20_tellu64(xchacha20_ctx */*ctx*/);
+extern kludge64 xchacha12_tellu64(xchacha12_ctx */*ctx*/);
+extern kludge64 xchacha8_tellu64(xchacha8_ctx */*ctx*/);
+
+/* --- @xchacha{20,12,8}_encrypt@ --- *
+ *
+ * Arguments:  @xchachaR_ctx *ctx@ = pointer to context
+ *             @const void *src@ = source buffer (or null)
+ *             @void *dest@ = destination buffer (or null)
+ *             @size_t sz@ = size of the buffers
+ *
+ * Returns:    ---
+ *
+ * Use:                Encrypts or decrypts @sz@ bytes of data from @src@ to @dest@.
+ *             XChaCha works by XORing plaintext with a keystream, so
+ *             encryption and decryption are the same operation.  If @dest@
+ *             is null then ignore @src@ and skip @sz@ bytes of the
+ *             keystream.  If @src@ is null, then just write the keystream
+ *             to @dest@.
+ */
+
+extern void xchacha20_encrypt(xchacha20_ctx */*ctx*/,
+                           const void */*src*/, void */*dest*/,
+                           size_t /*sz*/);
+extern void xchacha12_encrypt(xchacha12_ctx */*ctx*/,
+                             const void */*src*/, void */*dest*/,
+                             size_t /*sz*/);
+extern void xchacha8_encrypt(xchacha8_ctx */*ctx*/,
+                             const void */*src*/, void */*dest*/,
+                             size_t /*sz*/);
+
+/*----- Generic cipher interface ------------------------------------------*/
+
+extern const octet chacha_keysz[];
+#define chacha20_keysz chacha_keysz
+#define chacha12_keysz chacha_keysz
+#define chacha8_keysz chacha_keysz
+#define xchacha_keysz chacha_keysz
+#define xchacha20_keysz chacha_keysz
+#define xchacha12_keysz chacha_keysz
+#define xchacha8_keysz chacha_keysz
+
+const gccipher chacha20, chacha12, chacha8;
+const gccipher xchacha20, xchacha12, xchacha8;
+
+/*----- Generic random number generator interface -------------------------*/
+
+/* --- @chacha{,12,8}_rand@, @xchacha{,12,8}_rand@ --- *
+ *
+ * Arguments:          @const void *k@ = pointer to key material
+ *                     @size_t ksz@ = size of key material
+ *                     @const void *n@ = pointer to nonce or null
+ *                             (@CHACHA_NONCESZ@ or @XCHACHA_NONCESZ@)
+ *
+ * Returns:            Pointer to generic random number generator instance.
+ *
+ * Use:                        Creates a random number interface wrapper around
+ *                     the ChaCha or XChaCha stream ciphers.
+ */
+
+extern grand *chacha20_rand(const void */*k*/, size_t /*ksz*/,
+                           const void */*n*/);
+extern grand *chacha12_rand(const void */*k*/, size_t /*ksz*/,
+                           const void */*n*/);
+extern grand *chacha8_rand(const void */*k*/, size_t /*ksz*/,
+                          const void */*n*/);
+extern grand *xchacha20_rand(const void */*k*/, size_t /*ksz*/,
+                            const void */*n*/);
+extern grand *xchacha12_rand(const void */*k*/, size_t /*ksz*/,
+                            const void */*n*/);
+extern grand *xchacha8_rand(const void */*k*/, size_t /*ksz*/,
+                           const void */*n*/);
+
+enum {
+  CHACHA_SEEK = GRAND_SPECIFIC('S'),   /* @unsigned long pos@ */
+  CHACHA_SEEKU64,                      /* @kludge64 pos@ */
+  CHACHA_TELL,                         /* @unsigned long *pos@ */
+  CHACHA_TELLU64                       /* @kludge64 *pos@ */
+};
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif