ed25519/sign.c \
ed25519/verify.c
+chacha_poly1305_SOURCES = \
+ chacha-poly1305/chacha.c chacha-poly1305/chacha.h \
+ chacha-poly1305/chacha-poly1305.c chacha-poly1305/chacha-poly1305.h \
+ chacha-poly1305/poly1305.c chacha-poly1305/poly1305.h
+
tincd_SOURCES = \
buffer.c buffer.h \
cipher.h \
tincd.c \
utils.c utils.h \
xalloc.h \
- $(ed25519_SOURCES)
+ $(ed25519_SOURCES) \
+ $(chacha_poly1305_SOURCES)
tinc_SOURCES = \
dropin.c dropin.h \
tincctl.c tincctl.h \
top.c top.h \
utils.c utils.h \
- $(ed25519_SOURCES)
+ $(ed25519_SOURCES) \
+ $(chacha_poly1305_SOURCES)
sptps_test_SOURCES = \
logger.c logger.h \
sptps.c sptps.h \
sptps_test.c \
utils.c utils.h \
- $(ed25519_SOURCES)
+ $(ed25519_SOURCES) \
+ $(chacha_poly1305_SOURCES)
sptps_keypair_SOURCES = \
sptps_keypair.c \
sptps.c sptps.h \
sptps_speed.c \
utils.c utils.h \
- $(ed25519_SOURCES)
+ $(ed25519_SOURCES) \
+ $(chacha_poly1305_SOURCES)
## Conditionally compile device drivers
openssl/rsa.c \
openssl/rsagen.c
sptps_test_SOURCES += \
- openssl/cipher.c \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
ed25519/ecdh.c \
openssl/crypto.c \
ed25519/ecdsagen.c
sptps_speed_SOURCES += \
- openssl/cipher.c \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
ed25519/ecdh.c \
--- /dev/null
+#include "../system.h"
+
+#include "../cipher.h"
+#include "../xalloc.h"
+
+#include "chacha.h"
+#include "chacha-poly1305.h"
+#include "poly1305.h"
+
+struct chacha_poly1305_ctx {
+ struct chacha_ctx main_ctx, header_ctx;
+};
+
+chacha_poly1305_ctx_t *chacha_poly1305_init(void)
+{
+ chacha_poly1305_ctx_t *ctx = xzalloc(sizeof *ctx);
+ return ctx;
+}
+
+void chacha_poly1305_exit(chacha_poly1305_ctx_t *ctx)
+{
+ free(ctx);
+}
+
+bool chacha_poly1305_set_key(chacha_poly1305_ctx_t *ctx, const void *key)
+{
+ chacha_keysetup(&ctx->main_ctx, key, 256);
+ chacha_keysetup(&ctx->header_ctx, key + 32, 256);
+ return true;
+}
+
+static void put_u64(void *vp, uint64_t v)
+{
+ uint8_t *p = (uint8_t *) vp;
+
+ p[0] = (uint8_t) (v >> 56) & 0xff;
+ p[1] = (uint8_t) (v >> 48) & 0xff;
+ p[2] = (uint8_t) (v >> 40) & 0xff;
+ p[3] = (uint8_t) (v >> 32) & 0xff;
+ p[4] = (uint8_t) (v >> 24) & 0xff;
+ p[5] = (uint8_t) (v >> 16) & 0xff;
+ p[6] = (uint8_t) (v >> 8) & 0xff;
+ p[7] = (uint8_t) v & 0xff;
+}
+
+bool chacha_poly1305_encrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen) {
+ uint8_t seqbuf[8];
+ const uint8_t one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */
+ uint8_t poly_key[POLY1305_KEYLEN];
+
+ /*
+ * Run ChaCha20 once to generate the Poly1305 key. The IV is the
+ * packet sequence number.
+ */
+ memset(poly_key, 0, sizeof(poly_key));
+ put_u64(seqbuf, seqnr);
+ chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL);
+ chacha_encrypt_bytes(&ctx->main_ctx, poly_key, poly_key, sizeof(poly_key));
+
+ /* Set Chacha's block counter to 1 */
+ chacha_ivsetup(&ctx->main_ctx, seqbuf, one);
+
+ chacha_encrypt_bytes(&ctx->main_ctx, indata, outdata, inlen);
+ poly1305_auth(outdata + inlen, outdata, inlen, poly_key);
+
+ if (outlen)
+ *outlen = inlen + POLY1305_TAGLEN;
+
+ return true;
+}
+
+bool chacha_poly1305_decrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen) {
+ uint8_t seqbuf[8];
+ const uint8_t one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */
+ uint8_t expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN];
+
+ /*
+ * Run ChaCha20 once to generate the Poly1305 key. The IV is the
+ * packet sequence number.
+ */
+ memset(poly_key, 0, sizeof(poly_key));
+ put_u64(seqbuf, seqnr);
+ chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL);
+ chacha_encrypt_bytes(&ctx->main_ctx, poly_key, poly_key, sizeof(poly_key));
+
+ /* Set Chacha's block counter to 1 */
+ chacha_ivsetup(&ctx->main_ctx, seqbuf, one);
+
+ /* Check tag before anything else */
+ inlen -= POLY1305_TAGLEN;
+ const uint8_t *tag = indata + inlen;
+
+ poly1305_auth(expected_tag, indata, inlen, poly_key);
+ if (memcmp(expected_tag, tag, POLY1305_TAGLEN))
+ return false;
+
+ chacha_encrypt_bytes(&ctx->main_ctx, indata, outdata, inlen);
+
+ if (outlen)
+ *outlen = inlen;
+
+ return true;
+}
--- /dev/null
+#ifndef CHACHA_POLY1305_H
+#define CHACHA_POLY1305_H
+
+#define CHACHA_POLY1305_KEYLEN 64
+
+typedef struct chacha_poly1305_ctx chacha_poly1305_ctx_t;
+
+extern chacha_poly1305_ctx_t *chacha_poly1305_init(void);
+extern void chacha_poly1305_exit(chacha_poly1305_ctx_t *);
+extern bool chacha_poly1305_set_key(chacha_poly1305_ctx_t *ctx, const void *key);
+
+extern bool chacha_poly1305_encrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen);
+extern bool chacha_poly1305_decrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen);
+
+#endif //CHACHA_POLY1305_H
--- /dev/null
+/*
+chacha-merged.c version 20080118
+D. J. Bernstein
+Public domain.
+*/
+
+#include "../system.h"
+
+#include "chacha.h"
+
+typedef struct chacha_ctx chacha_ctx;
+
+#define U8C(v) (v##U)
+#define U32C(v) (v##U)
+
+#define U8V(v) ((uint8_t)(v) & U8C(0xFF))
+#define U32V(v) ((uint32_t)(v) & U32C(0xFFFFFFFF))
+
+#define ROTL32(v, n) \
+ (U32V((v) << (n)) | ((v) >> (32 - (n))))
+
+#define U8TO32_LITTLE(p) \
+ (((uint32_t)((p)[0]) ) | \
+ ((uint32_t)((p)[1]) << 8) | \
+ ((uint32_t)((p)[2]) << 16) | \
+ ((uint32_t)((p)[3]) << 24))
+
+#define U32TO8_LITTLE(p, v) \
+ do { \
+ (p)[0] = U8V((v) ); \
+ (p)[1] = U8V((v) >> 8); \
+ (p)[2] = U8V((v) >> 16); \
+ (p)[3] = U8V((v) >> 24); \
+ } while (0)
+
+#define ROTATE(v,c) (ROTL32(v,c))
+#define XOR(v,w) ((v) ^ (w))
+#define PLUS(v,w) (U32V((v) + (w)))
+#define PLUSONE(v) (PLUS((v),1))
+
+#define QUARTERROUND(a,b,c,d) \
+ a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
+ c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
+ a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
+ c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
+
+static const char sigma[16] = "expand 32-byte k";
+static const char tau[16] = "expand 16-byte k";
+
+void chacha_keysetup(chacha_ctx *x, const uint8_t *k, uint32_t kbits)
+{
+ const char *constants;
+
+ x->input[4] = U8TO32_LITTLE(k + 0);
+ x->input[5] = U8TO32_LITTLE(k + 4);
+ x->input[6] = U8TO32_LITTLE(k + 8);
+ x->input[7] = U8TO32_LITTLE(k + 12);
+ if (kbits == 256) { /* recommended */
+ k += 16;
+ constants = sigma;
+ } else { /* kbits == 128 */
+ constants = tau;
+ }
+ x->input[8] = U8TO32_LITTLE(k + 0);
+ x->input[9] = U8TO32_LITTLE(k + 4);
+ x->input[10] = U8TO32_LITTLE(k + 8);
+ x->input[11] = U8TO32_LITTLE(k + 12);
+ x->input[0] = U8TO32_LITTLE(constants + 0);
+ x->input[1] = U8TO32_LITTLE(constants + 4);
+ x->input[2] = U8TO32_LITTLE(constants + 8);
+ x->input[3] = U8TO32_LITTLE(constants + 12);
+}
+
+void chacha_ivsetup(chacha_ctx *x, const uint8_t *iv, const uint8_t *counter)
+{
+ x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0);
+ x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4);
+ x->input[14] = U8TO32_LITTLE(iv + 0);
+ x->input[15] = U8TO32_LITTLE(iv + 4);
+}
+
+void
+chacha_encrypt_bytes(chacha_ctx *x, const uint8_t *m, uint8_t *c, uint32_t bytes)
+{
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
+ uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+ uint8_t *ctarget = NULL;
+ uint8_t tmp[64];
+ uint32_t i;
+
+ if (!bytes)
+ return;
+
+ j0 = x->input[0];
+ j1 = x->input[1];
+ j2 = x->input[2];
+ j3 = x->input[3];
+ j4 = x->input[4];
+ j5 = x->input[5];
+ j6 = x->input[6];
+ j7 = x->input[7];
+ j8 = x->input[8];
+ j9 = x->input[9];
+ j10 = x->input[10];
+ j11 = x->input[11];
+ j12 = x->input[12];
+ j13 = x->input[13];
+ j14 = x->input[14];
+ j15 = x->input[15];
+
+ for (;;) {
+ if (bytes < 64) {
+ for (i = 0; i < bytes; ++i)
+ tmp[i] = m[i];
+ m = tmp;
+ ctarget = c;
+ c = tmp;
+ }
+ x0 = j0;
+ x1 = j1;
+ x2 = j2;
+ x3 = j3;
+ x4 = j4;
+ x5 = j5;
+ x6 = j6;
+ x7 = j7;
+ x8 = j8;
+ x9 = j9;
+ x10 = j10;
+ x11 = j11;
+ x12 = j12;
+ x13 = j13;
+ x14 = j14;
+ x15 = j15;
+ for (i = 20; i > 0; i -= 2) {
+ QUARTERROUND(x0, x4, x8, x12)
+ QUARTERROUND(x1, x5, x9, x13)
+ QUARTERROUND(x2, x6, x10, x14)
+ QUARTERROUND(x3, x7, x11, x15)
+ QUARTERROUND(x0, x5, x10, x15)
+ QUARTERROUND(x1, x6, x11, x12)
+ QUARTERROUND(x2, x7, x8, x13)
+ QUARTERROUND(x3, x4, x9, x14)
+ }
+ x0 = PLUS(x0, j0);
+ x1 = PLUS(x1, j1);
+ x2 = PLUS(x2, j2);
+ x3 = PLUS(x3, j3);
+ x4 = PLUS(x4, j4);
+ x5 = PLUS(x5, j5);
+ x6 = PLUS(x6, j6);
+ x7 = PLUS(x7, j7);
+ x8 = PLUS(x8, j8);
+ x9 = PLUS(x9, j9);
+ x10 = PLUS(x10, j10);
+ x11 = PLUS(x11, j11);
+ x12 = PLUS(x12, j12);
+ x13 = PLUS(x13, j13);
+ x14 = PLUS(x14, j14);
+ x15 = PLUS(x15, j15);
+
+ x0 = XOR(x0, U8TO32_LITTLE(m + 0));
+ x1 = XOR(x1, U8TO32_LITTLE(m + 4));
+ x2 = XOR(x2, U8TO32_LITTLE(m + 8));
+ x3 = XOR(x3, U8TO32_LITTLE(m + 12));
+ x4 = XOR(x4, U8TO32_LITTLE(m + 16));
+ x5 = XOR(x5, U8TO32_LITTLE(m + 20));
+ x6 = XOR(x6, U8TO32_LITTLE(m + 24));
+ x7 = XOR(x7, U8TO32_LITTLE(m + 28));
+ x8 = XOR(x8, U8TO32_LITTLE(m + 32));
+ x9 = XOR(x9, U8TO32_LITTLE(m + 36));
+ x10 = XOR(x10, U8TO32_LITTLE(m + 40));
+ x11 = XOR(x11, U8TO32_LITTLE(m + 44));
+ x12 = XOR(x12, U8TO32_LITTLE(m + 48));
+ x13 = XOR(x13, U8TO32_LITTLE(m + 52));
+ x14 = XOR(x14, U8TO32_LITTLE(m + 56));
+ x15 = XOR(x15, U8TO32_LITTLE(m + 60));
+
+ j12 = PLUSONE(j12);
+ if (!j12) {
+ j13 = PLUSONE(j13);
+ /* stopping at 2^70 bytes per nonce is user's responsibility */
+ }
+
+ U32TO8_LITTLE(c + 0, x0);
+ U32TO8_LITTLE(c + 4, x1);
+ U32TO8_LITTLE(c + 8, x2);
+ U32TO8_LITTLE(c + 12, x3);
+ U32TO8_LITTLE(c + 16, x4);
+ U32TO8_LITTLE(c + 20, x5);
+ U32TO8_LITTLE(c + 24, x6);
+ U32TO8_LITTLE(c + 28, x7);
+ U32TO8_LITTLE(c + 32, x8);
+ U32TO8_LITTLE(c + 36, x9);
+ U32TO8_LITTLE(c + 40, x10);
+ U32TO8_LITTLE(c + 44, x11);
+ U32TO8_LITTLE(c + 48, x12);
+ U32TO8_LITTLE(c + 52, x13);
+ U32TO8_LITTLE(c + 56, x14);
+ U32TO8_LITTLE(c + 60, x15);
+
+ if (bytes <= 64) {
+ if (bytes < 64) {
+ for (i = 0; i < bytes; ++i)
+ ctarget[i] = c[i];
+ }
+ x->input[12] = j12;
+ x->input[13] = j13;
+ return;
+ }
+ bytes -= 64;
+ c += 64;
+ m += 64;
+ }
+}
--- /dev/null
+/*
+chacha-merged.c version 20080118
+D. J. Bernstein
+Public domain.
+*/
+
+#ifndef CHACHA_H
+#define CHACHA_H
+
+struct chacha_ctx {
+ uint32_t input[16];
+};
+
+#define CHACHA_MINKEYLEN 16
+#define CHACHA_NONCELEN 8
+#define CHACHA_CTRLEN 8
+#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN)
+#define CHACHA_BLOCKLEN 64
+
+void chacha_keysetup(struct chacha_ctx *x, const uint8_t *k, uint32_t kbits);
+void chacha_ivsetup(struct chacha_ctx *x, const uint8_t *iv, const uint8_t *ctr);
+void chacha_encrypt_bytes(struct chacha_ctx *x, const uint8_t *m, uint8_t * c, uint32_t bytes);
+
+#endif /* CHACHA_H */
--- /dev/null
+/*
+ * Public Domain poly1305 from Andrew Moon
+ * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna
+ */
+
+#include "../system.h"
+
+#include "poly1305.h"
+
+#define mul32x32_64(a,b) ((uint64_t)(a) * (b))
+
+#define U8TO32_LE(p) \
+ (((uint32_t)((p)[0])) | \
+ ((uint32_t)((p)[1]) << 8) | \
+ ((uint32_t)((p)[2]) << 16) | \
+ ((uint32_t)((p)[3]) << 24))
+
+#define U32TO8_LE(p, v) \
+ do { \
+ (p)[0] = (uint8_t)((v)); \
+ (p)[1] = (uint8_t)((v) >> 8); \
+ (p)[2] = (uint8_t)((v) >> 16); \
+ (p)[3] = (uint8_t)((v) >> 24); \
+ } while (0)
+
+void
+poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN])
+{
+ uint32_t t0, t1, t2, t3;
+ uint32_t h0, h1, h2, h3, h4;
+ uint32_t r0, r1, r2, r3, r4;
+ uint32_t s1, s2, s3, s4;
+ uint32_t b, nb;
+ size_t j;
+ uint64_t t[5];
+ uint64_t f0, f1, f2, f3;
+ uint32_t g0, g1, g2, g3, g4;
+ uint64_t c;
+ unsigned char mp[16];
+
+ /* clamp key */
+ t0 = U8TO32_LE(key + 0);
+ t1 = U8TO32_LE(key + 4);
+ t2 = U8TO32_LE(key + 8);
+ t3 = U8TO32_LE(key + 12);
+
+ /* precompute multipliers */
+ r0 = t0 & 0x3ffffff;
+ t0 >>= 26;
+ t0 |= t1 << 6;
+ r1 = t0 & 0x3ffff03;
+ t1 >>= 20;
+ t1 |= t2 << 12;
+ r2 = t1 & 0x3ffc0ff;
+ t2 >>= 14;
+ t2 |= t3 << 18;
+ r3 = t2 & 0x3f03fff;
+ t3 >>= 8;
+ r4 = t3 & 0x00fffff;
+
+ s1 = r1 * 5;
+ s2 = r2 * 5;
+ s3 = r3 * 5;
+ s4 = r4 * 5;
+
+ /* init state */
+ h0 = 0;
+ h1 = 0;
+ h2 = 0;
+ h3 = 0;
+ h4 = 0;
+
+ /* full blocks */
+ if (inlen < 16)
+ goto poly1305_donna_atmost15bytes;
+
+ poly1305_donna_16bytes:
+ m += 16;
+ inlen -= 16;
+
+ t0 = U8TO32_LE(m - 16);
+ t1 = U8TO32_LE(m - 12);
+ t2 = U8TO32_LE(m - 8);
+ t3 = U8TO32_LE(m - 4);
+
+ h0 += t0 & 0x3ffffff;
+ h1 += ((((uint64_t) t1 << 32) | t0) >> 26) & 0x3ffffff;
+ h2 += ((((uint64_t) t2 << 32) | t1) >> 20) & 0x3ffffff;
+ h3 += ((((uint64_t) t3 << 32) | t2) >> 14) & 0x3ffffff;
+ h4 += (t3 >> 8) | (1 << 24);
+
+ poly1305_donna_mul:
+ t[0] = mul32x32_64(h0, r0) + mul32x32_64(h1, s4) + mul32x32_64(h2, s3) + mul32x32_64(h3, s2) + mul32x32_64(h4, s1);
+ t[1] = mul32x32_64(h0, r1) + mul32x32_64(h1, r0) + mul32x32_64(h2, s4) + mul32x32_64(h3, s3) + mul32x32_64(h4, s2);
+ t[2] = mul32x32_64(h0, r2) + mul32x32_64(h1, r1) + mul32x32_64(h2, r0) + mul32x32_64(h3, s4) + mul32x32_64(h4, s3);
+ t[3] = mul32x32_64(h0, r3) + mul32x32_64(h1, r2) + mul32x32_64(h2, r1) + mul32x32_64(h3, r0) + mul32x32_64(h4, s4);
+ t[4] = mul32x32_64(h0, r4) + mul32x32_64(h1, r3) + mul32x32_64(h2, r2) + mul32x32_64(h3, r1) + mul32x32_64(h4, r0);
+
+ h0 = (uint32_t) t[0] & 0x3ffffff;
+ c = (t[0] >> 26);
+ t[1] += c;
+ h1 = (uint32_t) t[1] & 0x3ffffff;
+ b = (uint32_t) (t[1] >> 26);
+ t[2] += b;
+ h2 = (uint32_t) t[2] & 0x3ffffff;
+ b = (uint32_t) (t[2] >> 26);
+ t[3] += b;
+ h3 = (uint32_t) t[3] & 0x3ffffff;
+ b = (uint32_t) (t[3] >> 26);
+ t[4] += b;
+ h4 = (uint32_t) t[4] & 0x3ffffff;
+ b = (uint32_t) (t[4] >> 26);
+ h0 += b * 5;
+
+ if (inlen >= 16)
+ goto poly1305_donna_16bytes;
+
+ /* final bytes */
+ poly1305_donna_atmost15bytes:
+ if (!inlen)
+ goto poly1305_donna_finish;
+
+ for (j = 0; j < inlen; j++)
+ mp[j] = m[j];
+ mp[j++] = 1;
+ for (; j < 16; j++)
+ mp[j] = 0;
+ inlen = 0;
+
+ t0 = U8TO32_LE(mp + 0);
+ t1 = U8TO32_LE(mp + 4);
+ t2 = U8TO32_LE(mp + 8);
+ t3 = U8TO32_LE(mp + 12);
+
+ h0 += t0 & 0x3ffffff;
+ h1 += ((((uint64_t) t1 << 32) | t0) >> 26) & 0x3ffffff;
+ h2 += ((((uint64_t) t2 << 32) | t1) >> 20) & 0x3ffffff;
+ h3 += ((((uint64_t) t3 << 32) | t2) >> 14) & 0x3ffffff;
+ h4 += (t3 >> 8);
+
+ goto poly1305_donna_mul;
+
+ poly1305_donna_finish:
+ b = h0 >> 26;
+ h0 = h0 & 0x3ffffff;
+ h1 += b;
+ b = h1 >> 26;
+ h1 = h1 & 0x3ffffff;
+ h2 += b;
+ b = h2 >> 26;
+ h2 = h2 & 0x3ffffff;
+ h3 += b;
+ b = h3 >> 26;
+ h3 = h3 & 0x3ffffff;
+ h4 += b;
+ b = h4 >> 26;
+ h4 = h4 & 0x3ffffff;
+ h0 += b * 5;
+ b = h0 >> 26;
+ h0 = h0 & 0x3ffffff;
+ h1 += b;
+
+ g0 = h0 + 5;
+ b = g0 >> 26;
+ g0 &= 0x3ffffff;
+ g1 = h1 + b;
+ b = g1 >> 26;
+ g1 &= 0x3ffffff;
+ g2 = h2 + b;
+ b = g2 >> 26;
+ g2 &= 0x3ffffff;
+ g3 = h3 + b;
+ b = g3 >> 26;
+ g3 &= 0x3ffffff;
+ g4 = h4 + b - (1 << 26);
+
+ b = (g4 >> 31) - 1;
+ nb = ~b;
+ h0 = (h0 & nb) | (g0 & b);
+ h1 = (h1 & nb) | (g1 & b);
+ h2 = (h2 & nb) | (g2 & b);
+ h3 = (h3 & nb) | (g3 & b);
+ h4 = (h4 & nb) | (g4 & b);
+
+ f0 = ((h0) | (h1 << 26)) + (uint64_t) U8TO32_LE(&key[16]);
+ f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t) U8TO32_LE(&key[20]);
+ f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t) U8TO32_LE(&key[24]);
+ f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t) U8TO32_LE(&key[28]);
+
+ U32TO8_LE(&out[0], f0);
+ f1 += (f0 >> 32);
+ U32TO8_LE(&out[4], f1);
+ f2 += (f1 >> 32);
+ U32TO8_LE(&out[8], f2);
+ f3 += (f2 >> 32);
+ U32TO8_LE(&out[12], f3);
+}
--- /dev/null
+/* $OpenBSD: poly1305.h,v 1.2 2013/12/19 22:57:13 djm Exp $ */
+
+/*
+ * Public Domain poly1305 from Andrew Moon
+ * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna
+ */
+
+#ifndef POLY1305_H
+#define POLY1305_H
+
+#define POLY1305_KEYLEN 32
+#define POLY1305_TAGLEN 16
+
+void poly1305_auth(uint8_t out[POLY1305_TAGLEN], const uint8_t *m, size_t inlen, const uint8_t key[POLY1305_KEYLEN]);
+
+#endif /* POLY1305_H */
#include "system.h"
-#include "cipher.h"
+#include "chacha-poly1305/chacha-poly1305.h"
#include "crypto.h"
#include "ecdh.h"
#include "ecdsa.h"
char buffer[len + 21UL];
// Create header with sequence number, length and record type
- uint32_t seqno = htonl(s->outseqno++);
+ uint32_t seqno = s->outseqno++;
+ uint32_t netseqno = ntohl(seqno);
- memcpy(buffer, &seqno, 4);
+ memcpy(buffer, &netseqno, 4);
buffer[4] = type;
+ memcpy(buffer + 5, data, len);
if(s->outstate) {
// If first handshake has finished, encrypt and HMAC
- if(!cipher_set_counter(s->outcipher, &seqno, sizeof seqno))
- return error(s, EINVAL, "Failed to set counter");
-
- if(!cipher_gcm_encrypt_start(s->outcipher, buffer + 4, 1, buffer + 4, NULL))
- return error(s, EINVAL, "Error encrypting record");
-
- if(!cipher_gcm_encrypt_finish(s->outcipher, data, len, buffer + 5, NULL))
- return error(s, EINVAL, "Error encrypting record");
-
+ chacha_poly1305_encrypt(s->outcipher, seqno, buffer + 4, len + 1, buffer + 4, NULL);
return s->send_data(s->handle, type, buffer, len + 21UL);
} else {
// Otherwise send as plaintext
- memcpy(buffer + 5, data, len);
return s->send_data(s->handle, type, buffer, len + 5UL);
}
}
char buffer[len + 19UL];
// Create header with sequence number, length and record type
- uint32_t seqno = htonl(s->outseqno++);
+ uint32_t seqno = s->outseqno++;
uint16_t netlen = htons(len);
memcpy(buffer, &netlen, 2);
buffer[2] = type;
+ memcpy(buffer + 3, data, len);
if(s->outstate) {
// If first handshake has finished, encrypt and HMAC
- if(!cipher_set_counter(s->outcipher, &seqno, 4))
- return error(s, EINVAL, "Failed to set counter");
-
- if(!cipher_gcm_encrypt_start(s->outcipher, buffer, 3, buffer, NULL))
- return error(s, EINVAL, "Error encrypting record");
-
- if(!cipher_gcm_encrypt_finish(s->outcipher, data, len, buffer + 3, NULL))
- return error(s, EINVAL, "Error encrypting record");
-
+ chacha_poly1305_encrypt(s->outcipher, seqno, buffer + 2, len + 1, buffer + 2, NULL);
return s->send_data(s->handle, type, buffer, len + 19UL);
} else {
// Otherwise send as plaintext
- memcpy(buffer + 3, data, len);
return s->send_data(s->handle, type, buffer, len + 3UL);
}
}
static bool generate_key_material(sptps_t *s, const char *shared, size_t len) {
// Initialise cipher and digest structures if necessary
if(!s->outstate) {
- s->incipher = cipher_open_by_name("aes-256-gcm");
- s->outcipher = cipher_open_by_name("aes-256-gcm");
+ s->incipher = chacha_poly1305_init();
+ s->outcipher = chacha_poly1305_init();
if(!s->incipher || !s->outcipher)
return error(s, EINVAL, "Failed to open cipher");
}
// Allocate memory for key material
- size_t keylen = cipher_keylength(s->incipher) + cipher_keylength(s->outcipher);
+ size_t keylen = 2 * CHACHA_POLY1305_KEYLEN;
s->key = realloc(s->key, keylen);
if(!s->key)
return error(s, EIO, "Invalid ACK record length");
if(s->initiator) {
- if(!cipher_set_counter_key(s->incipher, s->key))
+ if(!chacha_poly1305_set_key(s->incipher, s->key))
return error(s, EINVAL, "Failed to set counter");
} else {
- if(!cipher_set_counter_key(s->incipher, s->key + cipher_keylength(s->outcipher)))
+ if(!chacha_poly1305_set_key(s->incipher, s->key + CHACHA_POLY1305_KEYLEN))
return error(s, EINVAL, "Failed to set counter");
}
// TODO: only set new keys after ACK has been set/received
if(s->initiator) {
- if(!cipher_set_counter_key(s->outcipher, s->key + cipher_keylength(s->incipher)))
- return error(s, EINVAL, "Failed to set counter");
+ if(!chacha_poly1305_set_key(s->outcipher, s->key + CHACHA_POLY1305_KEYLEN))
+ return error(s, EINVAL, "Failed to set key");
} else {
- if(!cipher_set_counter_key(s->outcipher, s->key))
- return error(s, EINVAL, "Failed to set counter");
+ if(!chacha_poly1305_set_key(s->outcipher, s->key))
+ return error(s, EINVAL, "Failed to set key");
}
return true;
char buffer[len];
- if(!cipher_set_counter(s->incipher, data, sizeof seqno))
- return error(s, EINVAL, "Failed to set counter");
size_t outlen;
- if(!cipher_gcm_decrypt(s->incipher, data + 4, len - 4, buffer, &outlen))
+ if(!chacha_poly1305_decrypt(s->incipher, seqno, data + 4, len - 4, buffer, &outlen))
return error(s, EIO, "Failed to decrypt and verify packet");
// Replay protection using a sliding window of configurable size.
if(s->buflen < 2)
return true;
- // Update sequence number.
-
- uint32_t seqno = htonl(s->inseqno++);
-
- // Decrypt the length bytes
-
- if(s->instate) {
- if(!cipher_set_counter(s->incipher, &seqno, 4))
- return error(s, EINVAL, "Failed to set counter");
-
- if(!cipher_gcm_decrypt_start(s->incipher, s->inbuf, 2, &s->reclen, NULL))
- return error(s, EINVAL, "Failed to decrypt record");
- } else {
- memcpy(&s->reclen, s->inbuf, 2);
- }
+ // Get the length bytes
+ memcpy(&s->reclen, s->inbuf, 2);
s->reclen = ntohs(s->reclen);
// If we have the length bytes, ensure our buffer can hold the whole request.
if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL))
return true;
+ // Update sequence number.
+
+ uint32_t seqno = s->inseqno++;
+
// Check HMAC and decrypt.
if(s->instate) {
- if(!cipher_gcm_decrypt_finish(s->incipher, s->inbuf + 2UL, s->reclen + 17UL, s->inbuf + 2UL, NULL))
+ if(!chacha_poly1305_decrypt(s->incipher, seqno, s->inbuf + 2UL, s->reclen + 17UL, s->inbuf + 2UL, NULL))
return error(s, EINVAL, "Failed to decrypt and verify record");
}
// Stop a SPTPS session.
bool sptps_stop(sptps_t *s) {
// Clean up any resources.
- cipher_close(s->incipher);
- cipher_close(s->outcipher);
- digest_close(s->indigest);
- digest_close(s->outdigest);
+ chacha_poly1305_exit(s->incipher);
+ chacha_poly1305_exit(s->outcipher);
ecdh_free(s->ecdh);
free(s->inbuf);
free(s->mykex);
#include "system.h"
-#include "cipher.h"
-#include "digest.h"
+#include "chacha-poly1305/chacha-poly1305.h"
#include "ecdh.h"
#include "ecdsa.h"
uint16_t reclen;
bool instate;
- cipher_t *incipher;
- digest_t *indigest;
+ chacha_poly1305_ctx_t *incipher;
uint32_t inseqno;
uint32_t received;
unsigned int replaywin;
char *late;
bool outstate;
- cipher_t *outcipher;
- digest_t *outdigest;
+ chacha_poly1305_ctx_t *outcipher;
uint32_t outseqno;
ecdsa_t *mykey;