symm: Implement Bernstein's Salsa20 stream cipher and its variants.
[catacomb] / symm / salsa20.h
diff --git a/symm/salsa20.h b/symm/salsa20.h
new file mode 100644 (file)
index 0000000..4a0d1eb
--- /dev/null
@@ -0,0 +1,335 @@
+/* -*-c-*-
+ *
+ * Salsa20 stream cipher
+ *
+ * (c) 2015 Straylight/Edgeware
+ */
+
+#ifndef CATACOMB_SALSA20_H
+#define CATACOMB_SALSA20_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 SALSA20_NONCESZ 8u
+#define SALSA20_KEYSZ 32u
+#define SALSA20_OUTSZ 64u
+
+#define HSALSA20_INSZ 16u
+#define HSALSA20_OUTSZ 32u
+
+#define XSALSA20_NONCESZ 24u
+#define XSALSA20_KEYSZ SALSA20_KEYSZ
+#define XSALSA20_OUTSZ SALSA20_OUTSZ
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef uint32 salsa20_matrix[16];
+
+typedef struct salsa20_ctx {
+  salsa20_matrix a;
+  octet buf[SALSA20_OUTSZ];
+  size_t bufi;
+} salsa20_ctx;
+
+#define XSALSA20_DEFCTX(name)                                          \
+  typedef struct name { salsa20_ctx s; salsa20_matrix k; } name
+XSALSA20_DEFCTX(xsalsa20_ctx);
+XSALSA20_DEFCTX(xsalsa2012_ctx);
+XSALSA20_DEFCTX(xsalsa208_ctx);
+
+/*----- The Salsa20 stream cipher -----------------------------------------*/
+
+/* --- @salsa20_init@ --- *
+ *
+ * Arguments:  @salsa20_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 Salsa20 context ready for use.
+ */
+
+extern void salsa20_init(salsa20_ctx */*ctx*/,
+                        const void */*key*/, size_t /*ksz*/,
+                        const void */*nonce*/);
+
+/* --- @salsa20_setnonce@ --- *
+ *
+ * Arguments:  @salsa20_ctx *ctx@ = pointer to context
+ *             @const void *nonce@ = the nonce (@SALSA20_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
+ *             @salsa20_seek@ etc.).
+ */
+
+extern void salsa20_setnonce(salsa20_ctx */*ctx*/, const void */*nonce*/);
+
+/* --- @salsa20_seek@, @salsa20_seeku64@ --- *
+ *
+ * Arguments:  @salsa20_ctx *ctx@ = pointer to context
+ *             @unsigned long i@, @kludge64 i@ = new position to set
+ *
+ * Returns:    ---
+ *
+ * Use:                Sets a new stream position, in units of Salsa20 output
+ *             blocks, which are @SALSA20_OUTSZ@ bytes each.  Byte
+ *             granularity can be achieved by calling @salsa20_encrypt@
+ *             appropriately.
+ */
+
+extern void salsa20_seek(salsa20_ctx */*ctx*/, unsigned long /*i*/);
+extern void salsa20_seeku64(salsa20_ctx */*ctx*/, kludge64 /*i*/);
+
+/* --- @salsa20_tell@, @salsa20_tellu64@ --- *
+ *
+ * Arguments:  @salsa20_ctx *ctx@ = pointer to context
+ *
+ * Returns:    The current position in the output stream, in blocks,
+ *             rounding upwards.
+ */
+
+extern unsigned long salsa20_tell(salsa20_ctx */*ctx*/);
+extern kludge64 salsa20_tellu64(salsa20_ctx */*ctx*/);
+
+/* --- @salsa20{,12,8}_encrypt@ --- *
+ *
+ * Arguments:  @salsa20_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@.
+ *             Salsa20 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 salsa20_encrypt(salsa20_ctx */*ctx*/,
+                           const void */*src*/, void */*dest*/,
+                           size_t /*sz*/);
+extern void salsa2012_encrypt(salsa20_ctx */*ctx*/,
+                             const void */*src*/, void */*dest*/,
+                             size_t /*sz*/);
+extern void salsa208_encrypt(salsa20_ctx */*ctx*/,
+                             const void */*src*/, void */*dest*/,
+                             size_t /*sz*/);
+
+/*----- The HSalsa20 pseudorandom function --------------------------------*/
+
+/* --- @hsalsa20{,12,8}_prf@ --- *
+ *
+ * Arguments:  @salsa20_ctx *ctx@ = pointer to context
+ *             @const void *src@ = the input (@HSALSA20_INSZ@ bytes)
+ *             @void *dest@ = the output (@HSALSA20_OUTSZ@ bytes)
+ *
+ * Returns:    ---
+ *
+ * Use:                Apply the HSalsa20/r pseudorandom function to @src@, writing
+ *             the result to @out@.
+ */
+
+extern void hsalsa20_prf(salsa20_ctx */*ctx*/,
+                        const void */*src*/, void */*dest*/);
+extern void hsalsa2012_prf(salsa20_ctx */*ctx*/,
+                          const void */*src*/, void */*dest*/);
+extern void hsalsa208_prf(salsa20_ctx */*ctx*/,
+                         const void */*src*/, void */*dest*/);
+
+/*----- The XSalsa20 stream cipher ----------------------------------------*/
+
+/* --- @xsalsa20{,12,8}_init@ --- *
+ *
+ * Arguments:  @xsalsa20R_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 XSalsa20/r context ready for use.
+ *
+ *             There is a different function for each number of rounds,
+ *             unlike for plain Salsa20.
+ */
+
+extern void xsalsa20_init(xsalsa20_ctx */*ctx*/,
+                         const void */*key*/, size_t /*ksz*/,
+                         const void */*nonce*/);
+extern void xsalsa2012_init(xsalsa2012_ctx */*ctx*/,
+                           const void */*key*/, size_t /*ksz*/,
+                           const void */*nonce*/);
+extern void xsalsa208_init(xsalsa208_ctx */*ctx*/,
+                          const void */*key*/, size_t /*ksz*/,
+                          const void */*nonce*/);
+
+/* --- @xsalsa20{,12,8}_setnonce@ --- *
+ *
+ * Arguments:  @xsalsa20R_ctx *ctx@ = pointer to context
+ *             @const void *nonce@ = the nonce (@XSALSA20_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
+ *             @salsa20_seek@ etc.).
+ *
+ *             There is a different function for each number of rounds,
+ *             unlike for plain Salsa20.
+ */
+
+extern void xsalsa20_setnonce(xsalsa20_ctx */*ctx*/,
+                             const void */*nonce*/);
+extern void xsalsa2012_setnonce(xsalsa2012_ctx */*ctx*/,
+                               const void */*nonce*/);
+extern void xsalsa208_setnonce(xsalsa208_ctx */*ctx*/,
+                              const void */*nonce*/);
+
+/* --- @xsalsa20{,12,8}_seek@, @xsalsa20{,12,8}_seeku64@ --- *
+ *
+ * Arguments:  @xsalsa20R_ctx *ctx@ = pointer to context
+ *             @unsigned long i@, @kludge64 i@ = new position to set
+ *
+ * Returns:    ---
+ *
+ * Use:                Sets a new stream position, in units of Salsa20 output
+ *             blocks, which are @XSALSA20_OUTSZ@ bytes each.  Byte
+ *             granularity can be achieved by calling @xsalsa20R_encrypt@
+ *             appropriately.
+ *
+ *             There is a different function for each number of rounds,
+ *             unlike for plain Salsa20, because the context structures are
+ *             different.
+ */
+
+extern void xsalsa20_seek(xsalsa20_ctx */*ctx*/, unsigned long /*i*/);
+extern void xsalsa2012_seek(xsalsa2012_ctx */*ctx*/, unsigned long /*i*/);
+extern void xsalsa208_seek(xsalsa208_ctx */*ctx*/, unsigned long /*i*/);
+extern void xsalsa20_seeku64(xsalsa20_ctx */*ctx*/, kludge64 /*i*/);
+extern void xsalsa2012_seeku64(xsalsa2012_ctx */*ctx*/, kludge64 /*i*/);
+extern void xsalsa208_seeku64(xsalsa208_ctx */*ctx*/, kludge64 /*i*/);
+
+/* --- @xsalsa20{,12,8}_tell@, @xsalsa20{,12,8}_tellu64@ --- *
+ *
+ * Arguments:  @salsa20_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 Salsa20, because the context structures are
+ *             different.
+ */
+
+extern unsigned long xsalsa20_tell(xsalsa20_ctx */*ctx*/);
+extern unsigned long xsalsa2012_tell(xsalsa2012_ctx */*ctx*/);
+extern unsigned long xsalsa208_tell(xsalsa208_ctx */*ctx*/);
+extern kludge64 xsalsa20_tellu64(xsalsa20_ctx */*ctx*/);
+extern kludge64 xsalsa2012_tellu64(xsalsa2012_ctx */*ctx*/);
+extern kludge64 xsalsa208_tellu64(xsalsa208_ctx */*ctx*/);
+
+/* --- @xsalsa20{,12,8}_encrypt@ --- *
+ *
+ * Arguments:  @xsalsa20R_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@.
+ *             XSalsa20 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 xsalsa20_encrypt(xsalsa20_ctx */*ctx*/,
+                           const void */*src*/, void */*dest*/,
+                           size_t /*sz*/);
+extern void xsalsa2012_encrypt(xsalsa2012_ctx */*ctx*/,
+                             const void */*src*/, void */*dest*/,
+                             size_t /*sz*/);
+extern void xsalsa208_encrypt(xsalsa208_ctx */*ctx*/,
+                             const void */*src*/, void */*dest*/,
+                             size_t /*sz*/);
+
+/*----- Generic cipher interface ------------------------------------------*/
+
+extern const octet salsa20_keysz[];
+#define salsa2012_keysz salsa20_keysz
+#define salsa208_keysz salsa20_keysz
+#define xsalsa20_keysz salsa20_keysz
+#define xsalsa2012_keysz salsa20_keysz
+#define xsalsa208_keysz salsa20_keysz
+
+const gccipher salsa20, salsa2012, salsa208;
+const gccipher xsalsa20, xsalsa2012, xsalsa208;
+
+/*----- Generic random number generator interface -------------------------*/
+
+/* --- @salsa20{,12,8}_rand@, @xsalsa20{,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
+ *                             (@SALSA20_NONCESZ@ or @XSALSA20_NONCESZ@)
+ *
+ * Returns:            Pointer to generic random number generator instance.
+ *
+ * Use:                        Creates a random number interface wrapper around
+ *                     the Salsa20/r or XSalsa20/r stream ciphers.
+ */
+
+extern grand *salsa20_rand(const void */*k*/, size_t /*ksz*/,
+                          const void */*n*/);
+extern grand *salsa2012_rand(const void */*k*/, size_t /*ksz*/,
+                            const void */*n*/);
+extern grand *salsa208_rand(const void */*k*/, size_t /*ksz*/,
+                           const void */*n*/);
+extern grand *xsalsa20_rand(const void */*k*/, size_t /*ksz*/,
+                           const void */*n*/);
+extern grand *xsalsa2012_rand(const void */*k*/, size_t /*ksz*/,
+                             const void */*n*/);
+extern grand *xsalsa208_rand(const void */*k*/, size_t /*ksz*/,
+                            const void */*n*/);
+
+enum {
+  SALSA20_SEEK = GRAND_SPECIFIC('S'),  /* @unsigned long pos@ */
+  SALSA20_SEEKU64,                     /* @kludge64 pos@ */
+  SALSA20_TELL,                                /* @unsigned long *pos@ */
+  SALSA20_TELLU64                      /* @kludge64 *pos@ */
+};
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif