tls

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

commit 0bd0fc1f03b21c8ee7abe98c231f4561b673d941
parent 25bebdfd32b2534f1f3b6d558753203e091b6aa1
Author: MikoĊ‚aj Lenczewski <mblenczewski@gmail.com>
Date:   Sat, 18 Apr 2026 00:08:07 +0100

Add x25519 implementation

Diffstat:
M.gitignore | 2--
MNOTES.txt | 2++
Mcommon.h | 25+++++++++++++++++--------
Acurve25519.pdf | 0
Mtest-client.c | 15++++++++++-----
Mtest-server.c | 2+-
Mtls.h | 7+++++++
Ax25519.h | 218+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 255 insertions(+), 16 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,5 +1,3 @@ -bin/ - **/.*.swp imgui.ini tags diff --git a/NOTES.txt b/NOTES.txt @@ -2,3 +2,5 @@ https://datatracker.ietf.org/doc/html/rfc8446 https://tls13.xargs.org/ https://datatracker.ietf.org/doc/html/rfc2246 https://tls12.xargs.org/ +https://datatracker.ietf.org/doc/html/rfc7748 +https://x25519.xargs.org/ diff --git a/common.h b/common.h @@ -8,17 +8,19 @@ #include <stdio.h> #include <unistd.h> +#include <sys/random.h> + #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> static int -get_socket(char *host, char *port, int passive) +get_socket(char *host, char *port, int socktype, int protocol, int passive) { struct addrinfo hints = { .ai_family = AF_UNSPEC, - .ai_socktype = SOCK_STREAM, - .ai_protocol = IPPROTO_TCP, + .ai_socktype = socktype, + .ai_protocol = protocol, }, *addrinfo, *ptr; int res; @@ -46,21 +48,28 @@ get_socket(char *host, char *port, int passive) break; } + res = fd; + + if (!ptr) { + fprintf(stderr, "getaddrinfo: failed to connect to %s:%s\n", + host, port); + } + freeaddrinfo(addrinfo); - return fd; + return res; } static int -get_client_socket(char *host, char *port) +get_client_socket(char *host, char *port, int socktype, int protocol) { - return get_socket(host, port, 0); + return get_socket(host, port, socktype, protocol, 0); } static int -get_server_socket(char *host, char *port) +get_server_socket(char *host, char *port, int socktype, int protocol) { - int fd = get_socket(host, port, 1); + int fd = get_socket(host, port, socktype, protocol, 1); if (fd < 0) return fd; diff --git a/curve25519.pdf b/curve25519.pdf Binary files differ. diff --git a/test-client.c b/test-client.c @@ -14,7 +14,7 @@ main(int argc, char **argv) char *host = argv[1], *port = argv[2]; - int sock = get_client_socket(host, port); + int sock = get_client_socket(host, port, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) { fprintf(stderr, "Failed to connect to %s:%s\n", host, port); exit(EXIT_FAILURE); @@ -32,17 +32,22 @@ main(int argc, char **argv) struct tls_session session; tls_session_init(&session, TLS_VERSION_1_3, tlsbuf, sizeof tlsbuf); - char client_privkey[32], client_pubkey[32]; + struct x25519_point client_privkey, client_pubkey; + getrandom(&client_privkey.vs, sizeof client_privkey.vs, 0); + x25519_genpubkey(&client_pubkey, &client_privkey); + // TODO: generate keys using x25519 - tls_session_set_keys(&session, TLS_KEX_X25519, - client_privkey, sizeof client_privkey, - client_pubkey, sizeof client_pubkey); + tls_session_set_keys(&session, TLS_NAMED_GROUP_X25519, + client_privkey.vs, sizeof client_privkey.vs, + client_pubkey.vs, sizeof client_pubkey.vs); +#if 0 char client_certificate[8192]; // TODO: generate certificate tls_session_set_cert(&session, client_certificate, sizeof client_certificate); +#endif // start client tls handshake tls_session_client_handshake(&session); diff --git a/test-server.c b/test-server.c @@ -14,7 +14,7 @@ main(int argc, char **argv) char *host = argv[1], *port = argv[2]; - int serv = get_server_socket(host, port); + int serv = get_server_socket(host, port, SOCK_STREAM, IPPROTO_TCP); if (serv < 0) { fprintf(stderr, "Failed to listen on %s:%s\n", host, port); exit(EXIT_FAILURE); diff --git a/tls.h b/tls.h @@ -268,10 +268,17 @@ tls_session_send(); void tls_session_send_commit(); +int tls_session_pull(); + +int tls_session_push(); + +int tls_session_flush(); /* crypto - replace with real crypto library */ +#include "x25519.h" + #endif /* TLS_H */ diff --git a/x25519.h b/x25519.h @@ -0,0 +1,218 @@ +// https://martin.kleppmann.com/papers/curve25519.pdf + +#include <stdint.h> +#include <string.h> + +struct x25519_point { + uint8_t vs[32]; +}; + +struct x25519_field_element { + int64_t vs[16]; // array of 16, 16-bit numbers (stored as 64-bit) +}; + +static inline void +x25519_unpack(struct x25519_field_element *out, struct x25519_point const *in) +{ + for (size_t i = 0; i < 16; i++) { + out->vs[i] = in->vs[2*i] + ((int64_t) in->vs[(2*i) + 1] << 8); + } + + out->vs[15] &= 0x7fff; +} + +static inline void +x25519_carry(struct x25519_field_element *elem) +{ + int64_t carry; + for (size_t i = 0; i < 16; i++) { + carry = elem->vs[i] >> 16; + + elem->vs[i] -= carry << 16; + + if (i < 15) { + elem->vs[i + 1] += carry; + } else { // i == 15 + elem->vs[0] += 38 * carry; + } + } +} + +static inline void +x25519_fadd(struct x25519_field_element *out, + struct x25519_field_element const *a, + struct x25519_field_element const *b) +{ + for (size_t i = 0; i < 16; i++) { + out->vs[i] = a->vs[i] + b->vs[i]; + } +} + +static inline void +x25519_fsub(struct x25519_field_element *out, + struct x25519_field_element const *a, + struct x25519_field_element const *b) +{ + for (size_t i = 0; i < 16; i++) { + out->vs[i] = a->vs[i] - b->vs[i]; + } +} + +static inline void +x25519_fmul(struct x25519_field_element *out, + struct x25519_field_element const *a, + struct x25519_field_element const *b) +{ + int64_t product[31]; + memset(product, 0, sizeof product); // TODO: is this elided? + + for (size_t i = 0; i < 16; i++) { + for (size_t j = 0; j < 16; j++) { + product[i + j] = a->vs[i] * b->vs[j]; + } + } + + for (size_t i = 0; i < 15; i++) { + product[i] += 38 * product[i + 16]; + } + + memcpy(out->vs, product, sizeof out->vs); + x25519_carry(out); + x25519_carry(out); +} + +static inline void +x25519_finv(struct x25519_field_element *out, + struct x25519_field_element const *in) +{ + struct x25519_field_element c; + memcpy(&c, in, sizeof c); + + for (int i = 253; i >= 0; i--) { + x25519_fmul(&c, &c, &c); + + if (i != 2 && i != 4) + x25519_fmul(&c, &c, in); + } + + memcpy(out, &c, sizeof c); +} + +static inline void +x25519_swap(struct x25519_field_element *p, + struct x25519_field_element *q, + size_t bit) +{ + int64_t c = ~(bit - 1); + for (size_t i = 0; i < 16; i++) { + int64_t t = c & (p->vs[i] ^ q->vs[i]); + p->vs[i] ^= t; + q->vs[i] ^= t; + } +} + +static inline void +x25519_pack(struct x25519_point *out, struct x25519_field_element const *in) +{ + int carry; + struct x25519_field_element m, t; + memcpy(&t, in, sizeof t); + + // reduce module p + x25519_carry(&t); x25519_carry(&t); x25519_carry(&t); + + for (size_t j = 0; j < 2; j++) { + m.vs[0] = t.vs[0] - 0xffed; + for (size_t i = 1; i < 15; i++) { + m.vs[i] = t.vs[i] - 0xffff - ((m.vs[i - 1] >> 16) & 1); + m.vs[i - 1] &= 0xffff; + } + + m.vs[15] = t.vs[15] - 0x7fff - ((m.vs[14] >> 16) & 1); + carry = (m.vs[15] >> 16) & 1; + m.vs[14] &= 0xffff; + + x25519_swap(&t, &m, 1 - carry); + } + + for (size_t i = 0; i < 16; i++) { + out->vs[2*i] = t.vs[i] & 0xff; + out->vs[(2*i) + 1] = t.vs[i] >> 8; + } +} + +static inline void +x25519_scalarmult(struct x25519_point *restrict out, + struct x25519_point const *restrict scalar, + struct x25519_point const *restrict point) +{ + static const struct x25519_field_element _121665 = { + .vs = { 0xdb41, 1 } + }; + + uint8_t clamped[32]; + int64_t bit; + + struct x25519_field_element a, b, c, d, e, f, x; + + memcpy(clamped, scalar, sizeof clamped); + clamped[0] &= 0xf8; + clamped[31] = (clamped[31] & 0x7f) | 0x40; + + x25519_unpack(&x, point); + + memcpy(&b, &x, sizeof b); + memset(&d, 0, sizeof d); + memset(&c, 0, sizeof c); + memset(&a, 0, sizeof a); + a.vs[0] = d.vs[0] = 1; + + for (int i = 254; i >= 0; i--) { + bit = (clamped[i >> 3] >> (i & 7)) & 1; + + x25519_swap(&a, &b, bit); + x25519_swap(&c, &d, bit); + + x25519_fadd(&e, &a, &c); + x25519_fsub(&a, &a, &c); + x25519_fadd(&c, &b, &d); + x25519_fsub(&b, &b, &d); + x25519_fmul(&d, &e, &f); + x25519_fmul(&f, &a, &a); + x25519_fmul(&a, &c, &a); + x25519_fmul(&c, &b, &e); + x25519_fadd(&e, &a, &c); + x25519_fsub(&a, &a, &c); + x25519_fmul(&b, &a, &a); + x25519_fsub(&c, &d, &f); + x25519_fmul(&a, &c, &_121665); + x25519_fadd(&a, &a, &d); + x25519_fmul(&c, &c, &a); + x25519_fmul(&a, &d, &f); + x25519_fmul(&d, &b, &x); + x25519_fmul(&b, &e, &e); + + x25519_swap(&a, &b, bit); + x25519_swap(&c, &d, bit); + } + + x25519_finv(&c, &c); + x25519_fmul(&a, &a, &c); + x25519_pack(out, &a); +} + +static inline void +x25519_genpubkey(struct x25519_point *restrict pk, + struct x25519_point const *restrict sk) +{ + static const struct x25519_point _9 = { .vs = {9} }; + x25519_scalarmult(pk, sk, &_9); +} + +static inline void +x25519(struct x25519_point *restrict out, + struct x25519_point const *restrict pk, + struct x25519_point const *restrict sk) +{ + x25519_scalarmult(out, sk, pk); +}