tls

tls.git
git clone git://git.lenczewski.org/tls.git
Log | Files | Refs

commit dc6bad5a121973d940ea9efbf34737644d65d0cd
parent c9f625de9349f34b63cf277ed7d08c4a10bb8b73
Author: MikoĊ‚aj Lenczewski <mikolaj@lenczewski.org>
Date:   Sun,  4 Oct 2026 15:24:53 +0100

Add initial chacha20-poly1305 implementation

Diffstat:
M.gitignore | 1+
Aaes.pdf | 0
Mbuild.sh | 26+++++++++++++++++++++-----
Achacha20.c | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Achacha20.h | 37+++++++++++++++++++++++++++++++++++++
Mhmac.c | 1+
Apoly1305.c | 38++++++++++++++++++++++++++++++++++++++
Apoly1305.h | 43+++++++++++++++++++++++++++++++++++++++++++
Atest/test-chacha20.c | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atls_common.c | 12++++++++++++
Atls_x86_64.S | 0
11 files changed, 339 insertions(+), 5 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1 +1,2 @@ bin/ +obj/ diff --git a/aes.pdf b/aes.pdf Binary files differ. diff --git a/build.sh b/build.sh @@ -3,13 +3,29 @@ set -ex CC="${CC:-clang}" -FLAGS="-std=c11 -O0 -g3 -Wall -Wextra -Wno-unused-parameter -Wno-format" +AS="${AS:-clang}" +AR="${AR:-llvm-ar}" +RANLIB="${RANLIBL:-llvm-ranlib}" -mkdir -p bin +TARGET="${TARGET:-$($CC -dumpmachine)}" +ARCH="${TARGET%%-*}" +CFLAGS="-std=c11 -O0 -g3 -Wall -Wextra -Wno-unused-parameter -Wno-format" +ASFLAGS="-g3" + +mkdir -p bin obj + +# build tls library +$CC -o obj/tls_common.o -c tls_common.c $CFLAGS +$AS -o obj/tls_native.o -c tls_$ARCH.S $ASFLAGS +$AR rcs bin/libtls.a obj/tls_common.o obj/tls_native.o +$RANLIB bin/libtls.a + +# build tls tests for src in test/*.c; do - $CC -o bin/$(basename -s .c $src) $src $FLAGS -I. + $CC -o bin/$(basename -s .c $src) $src bin/libtls.a $CFLAGS -I. -D_GNU_SOURCE=1 done -$CC -o bin/tls_client tls_client.c $FLAGS -$CC -o bin/tls_server tls_server.c $FLAGS +# build example program +$CC -o bin/tls_client tls_client.c $CFLAGS +$CC -o bin/tls_server tls_server.c $CFLAGS diff --git a/chacha20.c b/chacha20.c @@ -0,0 +1,114 @@ +#include "chacha20.h" + +#include <endian.h> +#include <string.h> + +struct chacha20_ctx { + alignas(CHACHA20_ALIGN) + chacha20_word_t vs[CHACHA20_BLOCK_WORDS]; +}; + +void +_chacha20_init(struct chacha20_ctx *ctx, + unsigned char key[static CHACHA20_KEY_SIZE], + uint32_t ctr, + unsigned char iv[static CHACHA20_IV_SIZE]) +{ + ctx->vs[0] = 0x61707865; + ctx->vs[1] = 0x3320646e; + ctx->vs[2] = 0x79622d32; + ctx->vs[3] = 0x6b206574; + + memcpy(&ctx->vs[4], key, CHACHA20_KEY_SIZE); + + ctx->vs[12] = ctr; + + memcpy(&ctx->vs[13], iv, CHACHA20_IV_SIZE); +} + +#define CHACHA20_ROTL(v, n, b) (((v) << (n)) | ((v) >> ((b) - (n)))) + +#define CHACHA20_QUARTERROUND(a, b, c, d) \ +{ \ + a += b; d ^= a; d = CHACHA20_ROTL(d, 16, 32); \ + c += d; b ^= c; b = CHACHA20_ROTL(b, 12, 32); \ + a += b; d ^= a; d = CHACHA20_ROTL(d, 8, 32); \ + c += d; b ^= c; b = CHACHA20_ROTL(b, 7, 32); \ +} + +static void +_chacha20_inner_block(struct chacha20_ctx *ctx) +{ + CHACHA20_QUARTERROUND(ctx->vs[0], ctx->vs[4], ctx->vs[8], ctx->vs[12]); + CHACHA20_QUARTERROUND(ctx->vs[1], ctx->vs[5], ctx->vs[9], ctx->vs[13]); + CHACHA20_QUARTERROUND(ctx->vs[2], ctx->vs[6], ctx->vs[10], ctx->vs[14]); + CHACHA20_QUARTERROUND(ctx->vs[3], ctx->vs[7], ctx->vs[11], ctx->vs[15]); + + CHACHA20_QUARTERROUND(ctx->vs[0], ctx->vs[5], ctx->vs[10], ctx->vs[15]); + CHACHA20_QUARTERROUND(ctx->vs[1], ctx->vs[6], ctx->vs[11], ctx->vs[12]); + CHACHA20_QUARTERROUND(ctx->vs[2], ctx->vs[7], ctx->vs[8], ctx->vs[13]); + CHACHA20_QUARTERROUND(ctx->vs[3], ctx->vs[4], ctx->vs[9], ctx->vs[14]); +} + +static void +_chacha20_block(struct chacha20_ctx *ctx, + unsigned char key[static CHACHA20_KEY_SIZE], + uint32_t ctr, + unsigned char iv[static CHACHA20_IV_SIZE]) +{ + _chacha20_init(ctx, key, ctr, iv); + + struct chacha20_ctx save; + memcpy(&save, ctx, sizeof *ctx); + + for (size_t i = 0; i < CHACHA20_ROUNDS; i++) { + _chacha20_inner_block(ctx); + } + + for (size_t i = 0; i < CHACHA20_BLOCK_WORDS; i++) { + save.vs[i] += ctx->vs[i]; + ctx->vs[i] = htole32(save.vs[i]); + } +} + +static void +_chacha20_round(unsigned char key[static CHACHA20_KEY_SIZE], + uint32_t ctr, + unsigned char iv[static CHACHA20_IV_SIZE], + void const *plaintext, size_t len, + void *ciphertext) +{ + struct chacha20_ctx keystream; + _chacha20_block(&keystream, key, ctr, iv); + + unsigned char const *in = plaintext, *end = in + len; + unsigned char *state = (void *) keystream.vs; + unsigned char *out = ciphertext; + + while (in < end) { + *out++ = *in++ ^ *state++; + } +} + +void +chacha20(unsigned char key[static CHACHA20_KEY_SIZE], + uint32_t ctr, + unsigned char iv[static CHACHA20_IV_SIZE], + void const *buf, size_t len, + void *out) +{ + size_t blocks = len / CHACHA20_BLOCK_SIZE; + size_t tail = len - (blocks * CHACHA20_BLOCK_SIZE); + unsigned char const *ptr = buf; + unsigned char *dst = out; + + size_t i; + for (i = 0; i < blocks; i++) { + _chacha20_round(key, ctr + i, iv, ptr, CHACHA20_BLOCK_SIZE, dst); + + ptr += CHACHA20_BLOCK_SIZE; + dst += CHACHA20_BLOCK_SIZE; + } + + _chacha20_round(key, ctr + i, iv, ptr, tail, dst); +} diff --git a/chacha20.h b/chacha20.h @@ -0,0 +1,37 @@ +// chacha20-poly1305: https://www.rfc-editor.org/info/rfc8439/ + +#ifndef CHACHA20_H +#define CHACHA20_H + +#include <limits.h> +#include <stdalign.h> +#include <stddef.h> +#include <stdint.h> + +#define CHACHA20_ALIGN 64 +#define CHACHA20_ROUNDS 10 + +typedef uint32_t chacha20_word_t; + +#define CHACHA20_WORD_BITS 32 +#define CHACHA20_BLOCK_BITS 512 +#define CHACHA20_KEY_BITS 256 +#define CHACHA20_IV_BITS 96 + +#define CHACHA20_BLOCK_WORDS (CHACHA20_BLOCK_BITS / CHACHA20_WORD_BITS) +#define CHACHA20_BLOCK_SIZE (CHACHA20_BLOCK_BITS / CHAR_BIT) + +#define CHACHA20_KEY_WORDS (CHACHA20_KEY_BITS / CHACHA20_WORD_BITS) +#define CHACHA20_KEY_SIZE (CHACHA20_KEY_BITS / CHAR_BIT) + +#define CHACHA20_IV_WORDS (CHACHA20_IV_BITS / CHACHA20_WORD_BITS) +#define CHACHA20_IV_SIZE (CHACHA20_IV_BITS / CHAR_BIT) + +void +chacha20(unsigned char key[static CHACHA20_KEY_SIZE], + uint32_t ctr, + unsigned char iv[static CHACHA20_IV_SIZE], + void const *buf, size_t len, + void *out); + +#endif /* CHACHA20_H */ diff --git a/hmac.c b/hmac.c @@ -1,6 +1,7 @@ #include "hmac.h" #include <assert.h> +#include <string.h> void hmac_gen_iv_block(struct hmac_ctx *ctx, diff --git a/poly1305.c b/poly1305.c @@ -0,0 +1,38 @@ +#include "poly1305.h" + +static void +_poly1305_clamp(unsigned char r[static 16]) +{ + // r &= 0x0ffffffc 0ffffffc 0ffffffc 0fffffff + // r &= 0x0ffffffc 0x0ffffffc 0x0ffffffc 0x0fffffff + // + uint32_t *vs = (void *) r; +} + +void +poly1305_init(struct poly1305_ctx *ctx, + unsigned char const key[static POLY1305_KEY_SIZE]) +{ +} + +void +poly1305_push(struct poly1305_ctx *ctx, void const *buf, size_t len) +{ +} + +void +poly1305_dgst(struct poly1305_ctx *ctx, + unsigned char digest[static POLY1305_DIGEST_SIZE]) +{ +} + +void +poly1305(unsigned char const key[static POLY1305_KEY_SIZE], + void const *buf, size_t len, + unsigned char digest[static POLY1305_DIGEST_SIZE]) +{ + struct poly1305_ctx ctx; + poly1305_init(&ctx, key); + poly1305_push(&ctx, buf, len); + poly1305_dgst(&ctx, digest); +} diff --git a/poly1305.h b/poly1305.h @@ -0,0 +1,43 @@ +// chacha20-poly1305: https://www.rfc-editor.org/info/rfc8439/ + +#ifndef POLY1305_H +#define POLY1305_H + +#include <stdalign.h> +#include <stdint.h> + +#define POLY1305_ALIGN 64 + +#define POLY1305_KEY_BITS 256 +#define POLY1305_KEY_SIZE (POLY1305_KEY_BITS / CHAR_BIT) + +#define POLY1305_BLOCK_BITS 128 +#define POLY1305_BLOCK_SIZE (POLY1305_BLOCK_BITS / CHAR_BIT) + +#define POLY1305_DIGEST_BITS 128 +#define POLY1305_DIGEST_SIZE (POLY1305_DIGEST_BITS / CHAR_BIT) + +struct poly1305_ctx { + alignas(POLY1305_ALIGN) + unsigned char r[16]; + unsigned char s[16]; + unsigned char a[17]; +}; + +void +poly1305_init(struct poly1305_ctx *ctx, + unsigned char const key[static POLY1305_KEY_SIZE]); + +void +poly1305_push(struct poly1305_ctx *ctx, void const *buf, size_t len); + +void +poly1305_dgst(struct poly1305_ctx *ctx, + unsigned char digest[static POLY1305_DIGEST_SIZE]); + +void +poly1305(unsigned char const key[static POLY1305_KEY_SIZE], + void const *buf, size_t len, + unsigned char digest[static POLY1305_DIGEST_SIZE]); + +#endif /* POLY1305_H */ diff --git a/test/test-chacha20.c b/test/test-chacha20.c @@ -0,0 +1,72 @@ +#include "chacha20.h" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int +main(void) +{ + char msg[] = "Ladies and Gentlemen of the class of '99: " + "If I could offer you only one tip for the future, " + "sunscreen would be it."; + + size_t len = strlen(msg); + unsigned char *enc = malloc(len); + + uint8_t key[CHACHA20_KEY_SIZE] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + }; + + uint32_t ctr = 1; + + uint8_t iv[CHACHA20_IV_SIZE] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x4a, + 0x00, 0x00, 0x00, 0x00, + }; + + chacha20(key, ctr, iv, msg, len, enc); + + uint8_t expected[] = { + 0x6e, 0x2e, 0x35, 0x9a, 0x25, 0x68, 0xf9, 0x80, + 0x41, 0xba, 0x07, 0x28, 0xdd, 0x0d, 0x69, 0x81, + 0xe9, 0x7e, 0x7a, 0xec, 0x1d, 0x43, 0x60, 0xc2, + 0x0a, 0x27, 0xaf, 0xcc, 0xfd, 0x9f, 0xae, 0x0b, + 0xf9, 0x1b, 0x65, 0xc5, 0x52, 0x47, 0x33, 0xab, + 0x8f, 0x59, 0x3d, 0xab, 0xcd, 0x62, 0xb3, 0x57, + 0x16, 0x39, 0xd6, 0x24, 0xe6, 0x51, 0x52, 0xab, + 0x8f, 0x53, 0x0c, 0x35, 0x9f, 0x08, 0x61, 0xd8, + 0x07, 0xca, 0x0d, 0xbf, 0x50, 0x0d, 0x6a, 0x61, + 0x56, 0xa3, 0x8e, 0x08, 0x8a, 0x22, 0xb6, 0x5e, + 0x52, 0xbc, 0x51, 0x4d, 0x16, 0xcc, 0xf8, 0x06, + 0x81, 0x8c, 0xe9, 0x1a, 0xb7, 0x79, 0x37, 0x36, + 0x5a, 0xf9, 0x0b, 0xbf, 0x74, 0xa3, 0x5b, 0xe6, + 0xb4, 0x0b, 0x8e, 0xed, 0xf2, 0x78, 0x5e, 0x42, + 0x87, 0x4d, + }; + + assert(sizeof expected == len); + + printf("msg: \"%.*s\" (%lu bytes)\n", sizeof msg, msg, strlen(msg)); + + printf("enc: "); + for (size_t i = 0; i < len; i++) { + printf("%.2x", enc[i]); + } + printf("\n"); + + printf("exp: "); + for (size_t i = 0; i < len; i++) { + printf("%.2x", expected[i]); + } + printf("\n"); + + return memcmp(expected, enc, len); +} + +#include "chacha20.c" diff --git a/tls_common.c b/tls_common.c @@ -0,0 +1,12 @@ +#define _GNU_SOURCE 1 + +#include "hkdf.c" +#include "hmac.c" +#include "hmac-sha2.c" +#include "sha.c" + +#include "poly1305.c" + +// TODO: replace with native assembly versions, using the correct SIMD +// implementation based on isa extensions supported at runtime +#include "chacha20.c" diff --git a/tls_x86_64.S b/tls_x86_64.S