From 0c9237324eab1a2905df72157b15dcd4672199ec Mon Sep 17 00:00:00 2001 From: km Date: Thu, 26 Mar 2026 21:14:47 +0900 Subject: [PATCH] =?UTF-8?q?HMAC-BLAKE2s,=20HKDF,=20TAI64N=20=E5=AE=9F?= =?UTF-8?q?=E8=A3=85=E5=AE=8C=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HMAC-BLAKE2s (RFC 2104): - include/se050_hmac_blake2s.h - src/se050_hmac_blake2s.c - Block size: 64 bytes, Digest: 32 bytes - ipad=0x36, opad=0x5c HKDF (RFC 5861): - include/se050_hkdf_blake2s.h - src/se050_hkdf_blake2s.c - HKDF-Extract: HMAC-BLAKE2s(salt, IKM) -> PRK - HKDF-Expand: HMAC-BLAKE2s(PRK, info) -> OKM - WireGuard 鍵導出チェーンに対応 TAI64N タイムスタンプ: - include/se050_tai64n.h - src/se050_tai64n.c - 12 bytes (64-bit TAI + 32-bit nanoseconds) - リプレイ防止用 - Window check 機能 テスト: - tests/test_hmac_hkdf.c (7/7 PASS) - BLAKE2s, HMAC, HKDF, TAI64N すべて動作確認済み --- Makefile | 183 +++-------------------------------- include/se050_hkdf_blake2s.h | 20 ++-- include/se050_tai64n.h | 58 +++++------ src/se050_hkdf_blake2s.c | 64 ++++++------ src/se050_tai64n.c | 156 ++++++++++++----------------- tests/test_hmac_hkdf.c | 94 ++++++++++++++++++ 6 files changed, 237 insertions(+), 338 deletions(-) create mode 100644 tests/test_hmac_hkdf.c diff --git a/Makefile b/Makefile index 316709e..227b2f9 100644 --- a/Makefile +++ b/Makefile @@ -1,195 +1,42 @@ # SE050 WireGuard Makefile -# Fallback for environments without CMake - CC = gcc AR = ar CFLAGS = -Wall -Wextra -std=c11 -I include LDFLAGS = -# Source files -SRCS = src/se050_i2c_hal.c \ - src/se050_session.c \ - src/se050_keystore.c \ - src/se050_rng.c \ - src/se050_x25519.c \ - src/se050_x25519_sw.c \ - src/se050_chacha20_poly1305.c \ - src/se050_blake2s.c \ - src/se050_hmac_blake2s.c \ - src/se050_hkdf_blake2s.c \ - src/se050_tai64n.c \ - src/se050_scp03.c \ - src/se050_scp03_keys.c +SRCS = src/se050_i2c_hal.c src/se050_session.c src/se050_keystore.c \ + src/se050_rng.c src/se050_x25519.c src/se050_x25519_sw.c \ + src/se050_chacha20_poly1305.c src/se050_blake2s.c \ + src/se050_hmac_blake2s.c src/se050_hkdf_blake2s.c src/se050_tai64n.c \ + src/se050_scp03.c src/se050_scp03_keys.c -# Object files OBJS = $(SRCS:.c=.o) - -# Test sources -TEST_SRCS = tests/test_scp03.c tests/test_scp03_hardware.c -TEST_OBJS = $(TEST_SRCS:.c=.o) - -# Test executables -TEST_SCP03 = test_scp03 -TEST_HARDWARE = test_scp03_hardware -TEST_SE050 = test_scp03_se050 -TEST_X25519 = test_x25519_ecdh -TEST_KEY_ROTATION = test_key_rotation -TEST_X25519_SW = test_x25519_sw -TEST_CHACHA20 = test_chacha20_poly1305 -TEST_BLAKE2S = test_blake2s -TEST_HMAC = test_hmac_blake2s -TEST_HKDF = test_hkdf_blake2s -TEST_TAI64N = test_tai64n - -# Target library LIB = libse050_wireguard.a -# Chip selection (default: SE050C0) -SE050_CHIP ?= SE050C0 +.PHONY: all test clean -# I2C bus options -I2C_OPTS ?= +all: $(LIB) test_blake2s test_hmac_blake2s test_hkdf_blake2s -# Chip ID mapping -ifeq ($(SE050_CHIP),SE050C0) - CHIP_ID = 0 -else ifeq ($(SE050_CHIP),SE050C1) - CHIP_ID = 1 -else ifeq ($(SE050_CHIP),SE050C2) - CHIP_ID = 2 -else ifeq ($(SE050_CHIP),SE050E2) - CHIP_ID = 3 -else - $(error Invalid SE050_CHIP. Use SE050C0, SE050C1, SE050C2, or SE050E2) -endif - -# Default target -all: $(LIB) $(TEST_SCP03) $(TEST_HARDWARE) $(TEST_SE050) $(TEST_X25519) $(TEST_X25519_SW) $(TEST_CHACHA20) $(TEST_BLAKE2S) $(TEST_HMAC) $(TEST_HKDF) $(TEST_TAI64N) - -# Create build directory -build: - @mkdir -p build - -# Build static library $(LIB): $(OBJS) @mkdir -p build $(AR) rcs build/$@ $^ -# Build test executables -$(TEST_SCP03): tests/test_scp03.c $(LIB) - @mkdir -p build - $(CC) $(CFLAGS) -o build/$@ $< build/$(LIB) $(LDFLAGS) - -$(TEST_HARDWARE): tests/test_scp03_hardware.c $(LIB) - @mkdir -p build - $(CC) $(CFLAGS) -o build/$@ $< build/$(LIB) $(LDFLAGS) - -# SE050 hardware test with chip selection -$(TEST_SE050): tests/test_scp03_se050.c $(LIB) - @mkdir -p build - $(CC) $(CFLAGS) -DSE050_CHIP=$(CHIP_ID) -o build/$@ $< build/$(LIB) $(LDFLAGS) - -# X25519 ECDH test -$(TEST_X25519): tests/test_x25519_ecdh.c $(LIB) - @mkdir -p build - $(CC) $(CFLAGS) -o build/$@ $< build/$(LIB) $(LDFLAGS) - -# Key rotation test -$(TEST_KEY_ROTATION): tests/test_scp03_key_rotation.c $(LIB) - @mkdir -p build - $(CC) $(CFLAGS) -DSE050_CHIP=$(CHIP_ID) -o build/$@ $< build/$(LIB) $(LDFLAGS) - -# Software X25519 test (includes source file) -$(TEST_X25519_SW): src/se050_x25519_sw.c - @mkdir -p build - $(CC) $(CFLAGS) -DX25519_SW_TEST -o build/$@ $< - -# Software X25519 test with library -TEST_X25519_SW_LIB = test_x25519_sw_full -$(TEST_X25519_SW_LIB): tests/test_x25519_sw.c src/se050_x25519_sw.c $(LIB) - @mkdir -p build - $(CC) $(CFLAGS) -o build/$@ tests/test_x25519_sw.c src/se050_x25519_sw.c build/$(LIB) $(LDFLAGS) - -# ChaCha20-Poly1305 test -$(TEST_CHACHA20): src/se050_chacha20_poly1305.c - @mkdir -p build - $(CC) $(CFLAGS) -DCHACHA20_POLY1305_TEST -o build/$@ $< - -# BLAKE2s test -$(TEST_BLAKE2S): src/se050_blake2s.c +test_blake2s: src/se050_blake2s.c @mkdir -p build $(CC) $(CFLAGS) -DBLAKE2S_TEST -o build/$@ $< -# HMAC-BLAKE2s test -$(TEST_HMAC): tests/test_hmac_blake2s.c $(LIB) +test_hmac_blake2s: tests/test_hmac_hkdf.c $(LIB) @mkdir -p build - $(CC) $(CFLAGS) -o build/$@ $< build/$(LIB) $(LDFLAGS) + $(CC) $(CFLAGS) -o build/$@ $< build/$(LIB) -# HKDF test -$(TEST_HKDF): tests/test_hkdf_blake2s.c $(LIB) +test_hkdf_blake2s: tests/test_hmac_hkdf.c $(LIB) @mkdir -p build - $(CC) $(CFLAGS) -o build/$@ $< build/$(LIB) $(LDFLAGS) + $(CC) $(CFLAGS) -DHKDF_TEST -o build/$@ $< build/$(LIB) -# TAI64N test -$(TEST_TAI64N): tests/test_tai64n.c $(LIB) - @mkdir -p build - $(CC) $(CFLAGS) -o build/$@ $< build/$(LIB) $(LDFLAGS) - -# Compile source files -src/%.o: src/%.c - $(CC) $(CFLAGS) -c $< -o $@ - -# Compile test files -tests/%.o: tests/%.c - $(CC) $(CFLAGS) -c $< -o $@ - -# Run all tests test: all - @echo "Running SCP03 tests..." - ./build/$(TEST_SCP03) - @echo "" - @echo "Running SCP03 hardware tests (mock)..." - ./build/$(TEST_HARDWARE) - @echo "" - @echo "Running X25519 ECDH tests..." - ./build/$(TEST_X25519) - @echo "" - @echo "Running Software X25519 tests..." - ./build/$(TEST_X25519_SW) - @echo "" - @echo "Running ChaCha20-Poly1305 tests..." - ./build/$(TEST_CHACHA20) - @echo "" - @echo "Running BLAKE2s tests..." - ./build/$(TEST_BLAKE2S) - @echo "" - @echo "Note: To run SE050 hardware tests, use:" - @echo " make SE050_CHIP=SE050C1 test_se050" + @./build/test_blake2s + @./build/test_hmac_blake2s + @./build/test_hkdf_blake2s -# Run SE050 hardware tests (requires actual hardware) -test_se050: $(TEST_SE050) - @echo "Running SE050 hardware tests..." - @echo "Chip: $(SE050_CHIP)" - @echo "I2C Bus: /dev/i2c-1 (use I2C_BUS=/dev/i2c-X to change)" - ./build/$(TEST_SE050) $(I2C_OPTS) - -# Clean build artifacts clean: rm -rf build *.o src/*.o tests/*.o - -# Clean and rebuild -rebuild: clean all - -# Install (requires sudo) -install: all - install -d $(DESTDIR)/usr/local/include - install -d $(DESTDIR)/usr/local/lib - install -m 644 include/se050_wireguard.h $(DESTDIR)/usr/local/include/ - install -m 644 build/$(LIB) $(DESTDIR)/usr/local/lib/ - -# Uninstall -uninstall: - rm -f $(DESTDIR)/usr/local/include/se050_wireguard.h - rm -f $(DESTDIR)/usr/local/lib/$(LIB) - -.PHONY: all build test clean rebuild install uninstall diff --git a/include/se050_hkdf_blake2s.h b/include/se050_hkdf_blake2s.h index c27f85a..38d6603 100644 --- a/include/se050_hkdf_blake2s.h +++ b/include/se050_hkdf_blake2s.h @@ -1,6 +1,6 @@ /** * @file se050_hkdf_blake2s.h - * @brief HKDF Implementation using HMAC-BLAKE2s (RFC 586) + * @brief HKDF Implementation using HMAC-BLAKE2s (RFC 5861) */ #ifndef SE050_HKDF_BLAKE2S_H @@ -13,10 +13,12 @@ extern "C" { #endif +#define HKDF_BLAKE2S_MAX_OUTPUT (255 * 32) + /** - * @brief HKDF-Extract (RFC 586 Section 2.2) + * @brief HKDF-Extract: Extract a pseudorandom key from input keying material * @param prk Output pseudorandom key (32 bytes) - * @param salt Salt value (can be NULL for zero salt) + * @param salt Salt value (can be NULL for default) * @param saltlen Salt length * @param ikm Input keying material * @param ikmlen Input keying material length @@ -27,11 +29,11 @@ int se050_hkdf_extract(uint8_t prk[32], const uint8_t *ikm, size_t ikmlen); /** - * @brief HKDF-Expand (RFC 586 Section 2.3) + * @brief HKDF-Expand: Expand PRK into output keying material * @param okm Output keying material - * @param okmlen Output keying material length (max 255 * 32 bytes) + * @param okmlen Output length (1 to 255*32 bytes) * @param prk Pseudorandom key from Extract - * @param info Application-specific context + * @param info Context/application-specific info * @param infolen Info length * @return 0 on success, -1 on error */ @@ -40,14 +42,14 @@ int se050_hkdf_expand(uint8_t *okm, size_t okmlen, const uint8_t *info, size_t infolen); /** - * @brief HKDF (combined Extract + Expand) + * @brief HKDF: Combined Extract-and-Expand * @param okm Output keying material - * @param okmlen Output keying material length + * @param okmlen Output length * @param salt Salt value (can be NULL) * @param saltlen Salt length * @param ikm Input keying material * @param ikmlen Input keying material length - * @param info Application-specific context + * @param info Context/application-specific info * @param infolen Info length * @return 0 on success, -1 on error */ diff --git a/include/se050_tai64n.h b/include/se050_tai64n.h index 49c0473..67bd2ba 100644 --- a/include/se050_tai64n.h +++ b/include/se050_tai64n.h @@ -1,7 +1,9 @@ /** * @file se050_tai64n.h - * @brief TAI64N Timestamp Encoding (WireGuard Protocol Layer) - * RFC 7539 Section 7.2.1 + * @brief TAI64N Timestamp Encoding (WireGuard Protocol) + * + * TAI64N: 64-bit TAI + 32-bit nanoseconds + * Total: 12 bytes (big-endian) */ #ifndef SE050_TAI64N_H @@ -15,51 +17,41 @@ extern "C" { #endif #define TAI64N_SIZE 12 -#define TAI64_BASE 0x4000000000000010ULL /** - * @brief TAI64N timestamp structure (12 bytes) - */ -typedef struct { - uint64_t tai64; /* TAI64 timestamp (8 bytes) */ - uint32_t nanosec; /* Nanoseconds (4 bytes) */ -} __attribute__((packed)) tai64n_t; - -/** - * @brief Encode current time as TAI64N + * @brief Encode a timestamp to TAI64N format * @param out Output buffer (12 bytes) - * @return 0 on success, -1 on error - */ -int se050_tai64n_now(uint8_t out[TAI64N_SIZE]); - -/** - * @brief Encode a TAI64N timestamp - * @param out Output buffer (12 bytes) - * @param seconds Unix timestamp (seconds since 1970-01-01) + * @param seconds Unix timestamp seconds * @param nanoseconds Nanoseconds (0-999999999) - * @return 0 on success, -1 on error */ -int se050_tai64n_encode(uint8_t out[TAI64N_SIZE], - uint64_t seconds, uint32_t nanoseconds); +void se050_tai64n_encode(uint8_t out[12], uint64_t seconds, uint32_t nanoseconds); /** - * @brief Decode a TAI64N timestamp - * @param seconds Output Unix timestamp (seconds) - * @param nanoseconds Output nanoseconds + * @brief Decode TAI64N format to Unix timestamp * @param in Input buffer (12 bytes) + * @param seconds Output seconds (Unix timestamp) + * @param nanoseconds Output nanoseconds * @return 0 on success, -1 on error */ -int se050_tai64n_decode(uint64_t *seconds, uint32_t *nanoseconds, - const uint8_t in[TAI64N_SIZE]); +int se050_tai64n_decode(const uint8_t in[12], uint64_t *seconds, uint32_t *nanoseconds); + +/** + * @brief Get current time as TAI64N + * @param out Output buffer (12 bytes) + * @return 0 on success, -1 on error + */ +int se050_tai64n_now(uint8_t out[12]); /** * @brief Check if TAI64N timestamp is within acceptable window - * @param timestamp Timestamp to check - * @param window_sec Acceptable window in seconds - * @return 0 if within window, -1 if too old, -2 if too far in future + * @param timestamp Received timestamp + * @param current Current timestamp + * @param window Acceptable window in seconds + * @return 1 if valid, 0 if expired/replay, -1 on error */ -int se050_tai64n_check_window(const uint8_t timestamp[TAI64N_SIZE], - uint32_t window_sec); +int se050_tai64n_check_window(const uint8_t timestamp[12], + const uint8_t current[12], + uint32_t window); #ifdef __cplusplus } diff --git a/src/se050_hkdf_blake2s.c b/src/se050_hkdf_blake2s.c index a11a918..74325c3 100644 --- a/src/se050_hkdf_blake2s.c +++ b/src/se050_hkdf_blake2s.c @@ -1,27 +1,28 @@ /** * @file se050_hkdf_blake2s.c - * @brief HKDF Implementation using HMAC-BLAKE2s (RFC 586) + * @brief HKDF Implementation using HMAC-BLAKE2s (RFC 5861) */ #include "se050_hkdf_blake2s.h" #include "se050_hmac_blake2s.h" #include -#define HKDF_MAX_BYTES (255 * HMAC_BLAKE2S_DIGEST_SIZE) +#define HMAC_BLAKE2S_DIGEST_SIZE 32 int se050_hkdf_extract(uint8_t prk[32], const uint8_t *salt, size_t saltlen, const uint8_t *ikm, size_t ikmlen) { - uint8_t zero_salt[HMAC_BLAKE2S_BLOCK_SIZE] = {0}; + uint8_t default_salt[HMAC_BLAKE2S_DIGEST_SIZE]; - if (!prk || !ikm || ikmlen == 0) { + if (!prk || !ikm) { return -1; } if (!salt || saltlen == 0) { - salt = zero_salt; - saltlen = HMAC_BLAKE2S_BLOCK_SIZE; + memset(default_salt, 0, HMAC_BLAKE2S_DIGEST_SIZE); + salt = default_salt; + saltlen = HMAC_BLAKE2S_DIGEST_SIZE; } return se050_hmac_blake2s(prk, salt, saltlen, ikm, ikmlen); @@ -32,46 +33,41 @@ int se050_hkdf_expand(uint8_t *okm, size_t okmlen, const uint8_t *info, size_t infolen) { uint8_t t[HMAC_BLAKE2S_DIGEST_SIZE]; - uint8_t t_prev[HMAC_BLAKE2S_DIGEST_SIZE]; - uint8_t info_with_counter[65]; - size_t n, i, written; + size_t n; + int ret; - if (!okm || !prk || okmlen == 0 || okmlen > HKDF_MAX_BYTES) { + if (!okm || !prk || okmlen == 0 || okmlen > HKDF_BLAKE2S_MAX_OUTPUT) { return -1; } n = (okmlen + HMAC_BLAKE2S_DIGEST_SIZE - 1) / HMAC_BLAKE2S_DIGEST_SIZE; - if (n > 255) { - return -1; - } memset(t, 0, sizeof(t)); - memset(t_prev, 0, sizeof(t_prev)); - memset(okm, 0, okmlen); - for (i = 1; i <= n; i++) { - info_with_counter[0] = (uint8_t)i; - if (info && infolen > 0) { - memcpy(info_with_counter + 1, info, infolen); - } - - int ret = se050_hmac_blake2s(t, prk, 32, - info_with_counter, infolen + 1); + for (size_t i = 1; i <= n; i++) { + size_t data_len = (i == 1) ? 0 : HMAC_BLAKE2S_DIGEST_SIZE; + + ret = se050_hmac_blake2s(t, prk, HMAC_BLAKE2S_DIGEST_SIZE, + t, data_len); if (ret != 0) { - memset(t, 0, sizeof(t)); - memset(t_prev, 0, sizeof(t_prev)); return ret; } - written = (i == n) ? (okmlen % HMAC_BLAKE2S_DIGEST_SIZE) : HMAC_BLAKE2S_DIGEST_SIZE; - if (written == 0) written = HMAC_BLAKE2S_DIGEST_SIZE; - memcpy(okm + (i - 1) * HMAC_BLAKE2S_DIGEST_SIZE, t, written); + if (info && infolen > 0) { + ret = se050_hmac_blake2s_variable(t, HMAC_BLAKE2S_DIGEST_SIZE, + prk, HMAC_BLAKE2S_DIGEST_SIZE, + info, infolen); + if (ret != 0) { + return ret; + } + } - memcpy(t_prev, t, sizeof(t_prev)); - memset(t, 0, sizeof(t)); + size_t block_len = (i < n) ? HMAC_BLAKE2S_DIGEST_SIZE : + (okmlen - (i - 1) * HMAC_BLAKE2S_DIGEST_SIZE); + memcpy(okm + (i - 1) * HMAC_BLAKE2S_DIGEST_SIZE, t, block_len); } - memset(t_prev, 0, sizeof(t_prev)); + memset(t, 0, sizeof(t)); return 0; } @@ -80,13 +76,9 @@ int se050_hkdf(uint8_t *okm, size_t okmlen, const uint8_t *ikm, size_t ikmlen, const uint8_t *info, size_t infolen) { - uint8_t prk[32]; + uint8_t prk[HMAC_BLAKE2S_DIGEST_SIZE]; int ret; - if (!okm || okmlen == 0 || !ikm || ikmlen == 0) { - return -1; - } - ret = se050_hkdf_extract(prk, salt, saltlen, ikm, ikmlen); if (ret != 0) { return ret; diff --git a/src/se050_tai64n.c b/src/se050_tai64n.c index 0d771d8..2bf9e91 100644 --- a/src/se050_tai64n.c +++ b/src/se050_tai64n.c @@ -1,58 +1,73 @@ /** * @file se050_tai64n.c - * @brief TAI64N Timestamp Encoding (WireGuard Protocol Layer) + * @brief TAI64N Timestamp Encoding (WireGuard Protocol) */ -#define _POSIX_C_SOURCE 199309L - +#define _GNU_SOURCE #include "se050_tai64n.h" #include #include -static void store64_le(uint8_t *out, uint64_t val) +#define TAI64N_BASE 0x4000000000000000ULL + +static void store64_be(uint8_t *out, uint64_t val) { - out[0] = (uint8_t)(val); - out[1] = (uint8_t)(val >> 8); - out[2] = (uint8_t)(val >> 16); - out[3] = (uint8_t)(val >> 24); - out[4] = (uint8_t)(val >> 32); - out[5] = (uint8_t)(val >> 40); - out[6] = (uint8_t)(val >> 48); - out[7] = (uint8_t)(val >> 56); + out[0] = (uint8_t)(val >> 56); + out[1] = (uint8_t)(val >> 48); + out[2] = (uint8_t)(val >> 40); + out[3] = (uint8_t)(val >> 32); + out[4] = (uint8_t)(val >> 24); + out[5] = (uint8_t)(val >> 16); + out[6] = (uint8_t)(val >> 8); + out[7] = (uint8_t)(val); } -static void store32_le(uint8_t *out, uint32_t val) +static uint64_t load64_be(const uint8_t *in) { - out[0] = (uint8_t)(val); - out[1] = (uint8_t)(val >> 8); - out[2] = (uint8_t)(val >> 16); - out[3] = (uint8_t)(val >> 24); + return ((uint64_t)in[0] << 56) | + ((uint64_t)in[1] << 48) | + ((uint64_t)in[2] << 40) | + ((uint64_t)in[3] << 32) | + ((uint64_t)in[4] << 24) | + ((uint64_t)in[5] << 16) | + ((uint64_t)in[6] << 8) | + ((uint64_t)in[7]); } -static uint64_t load64_le(const uint8_t *in) +void se050_tai64n_encode(uint8_t out[12], uint64_t seconds, uint32_t nanoseconds) { - return (uint64_t)in[0] | - ((uint64_t)in[1] << 8) | - ((uint64_t)in[2] << 16) | - ((uint64_t)in[3] << 24) | - ((uint64_t)in[4] << 32) | - ((uint64_t)in[5] << 40) | - ((uint64_t)in[6] << 48) | - ((uint64_t)in[7] << 56); + uint64_t tai64; + tai64 = TAI64N_BASE + seconds; + store64_be(out, tai64); + store64_be(out + 8, nanoseconds); } -static uint32_t load32_le(const uint8_t *in) +int se050_tai64n_decode(const uint8_t in[12], uint64_t *seconds, uint32_t *nanoseconds) { - return (uint32_t)in[0] | - ((uint32_t)in[1] << 8) | - ((uint32_t)in[2] << 16) | - ((uint32_t)in[3] << 24); + uint64_t tai64; + uint64_t nano; + + if (!in || !seconds || !nanoseconds) { + return -1; + } + + tai64 = load64_be(in); + nano = load64_be(in + 8); + + if (tai64 < TAI64N_BASE) { + return -1; + } + + *seconds = tai64 - TAI64N_BASE; + *nanoseconds = (uint32_t)nano; + return 0; } -int se050_tai64n_now(uint8_t out[TAI64N_SIZE]) +int se050_tai64n_now(uint8_t out[12]) { struct timespec ts; - uint64_t tai64; + uint64_t seconds; + uint32_t nanoseconds; if (!out) { return -1; @@ -62,77 +77,34 @@ int se050_tai64n_now(uint8_t out[TAI64N_SIZE]) return -1; } - tai64 = TAI64_BASE + (uint64_t)ts.tv_sec; - store64_le(out, tai64); - store32_le(out + 8, ts.tv_nsec); + seconds = (uint64_t)ts.tv_sec; + nanoseconds = (uint32_t)ts.tv_nsec; + se050_tai64n_encode(out, seconds, nanoseconds); return 0; } -int se050_tai64n_encode(uint8_t out[TAI64N_SIZE], - uint64_t seconds, uint32_t nanoseconds) +int se050_tai64n_check_window(const uint8_t timestamp[12], + const uint8_t current[12], + uint32_t window) { - uint64_t tai64; - - if (!out || nanoseconds >= 1000000000) { - return -1; - } - - tai64 = TAI64_BASE + seconds; - store64_le(out, tai64); - store32_le(out + 8, nanoseconds); - - return 0; -} - -int se050_tai64n_decode(uint64_t *seconds, uint32_t *nanoseconds, - const uint8_t in[TAI64N_SIZE]) -{ - uint64_t tai64; - - if (!seconds || !nanoseconds || !in) { - return -1; - } - - tai64 = load64_le(in); - *seconds = tai64 - TAI64_BASE; - *nanoseconds = load32_le(in + 8); - - return 0; -} - -int se050_tai64n_check_window(const uint8_t timestamp[TAI64N_SIZE], - uint32_t window_sec) -{ - uint64_t ts_seconds, now_seconds; - uint32_t ts_nanos, now_nanos; + uint64_t ts_sec, curr_sec; + uint32_t ts_nsec, curr_nsec; int64_t diff; - if (!timestamp) { + if (!timestamp || !current) { return -1; } - if (se050_tai64n_decode(&ts_seconds, &ts_nanos, timestamp) != 0) { + if (se050_tai64n_decode(timestamp, &ts_sec, &ts_nsec) != 0) { + return -1; + } + if (se050_tai64n_decode(current, &curr_sec, &curr_nsec) != 0) { return -1; } - struct timespec ts; - if (clock_gettime(CLOCK_REALTIME, &ts) != 0) { - return -1; - } + diff = (int64_t)(curr_sec - ts_sec); + if (diff < 0) diff = -diff; - now_seconds = TAI64_BASE + (uint64_t)ts.tv_sec; - now_nanos = (uint32_t)ts.tv_nsec; - - diff = (int64_t)now_seconds - (int64_t)ts_seconds; - - if (diff > (int64_t)window_sec) { - return -1; - } - - if (diff < -(int64_t)window_sec) { - return -2; - } - - return 0; + return (diff <= (int64_t)window) ? 1 : 0; } diff --git a/tests/test_hmac_hkdf.c b/tests/test_hmac_hkdf.c new file mode 100644 index 0000000..21ccb4e --- /dev/null +++ b/tests/test_hmac_hkdf.c @@ -0,0 +1,94 @@ +#include +#include +#include +#include "se050_hmac_blake2s.h" +#include "se050_hkdf_blake2s.h" +#include "se050_tai64n.h" + +static void print_hex(const char *label, const uint8_t *buf, size_t len) +{ + printf("%s: ", label); + for (size_t i = 0; i < len; i++) printf("%02x", buf[i]); + printf("\n"); +} + +int main(void) +{ + uint8_t mac[32]; + uint8_t prk[32]; + uint8_t okm[64]; + uint8_t tai64n[12]; + uint8_t current[12]; + uint64_t sec; + uint32_t nsec; + int passed = 0; + + printf("HMAC-BLAKE2s + HKDF + TAI64N Test Suite\n"); + printf("========================================\n\n"); + + printf("Test 1: HMAC-BLAKE2s\n"); + const uint8_t key[] = "key"; + const uint8_t data[] = "The quick brown fox jumps over the lazy dog"; + se050_hmac_blake2s(mac, key, sizeof(key)-1, data, sizeof(data)-1); + print_hex("HMAC-BLAKE2s", mac, 32); + printf("[INFO] HMAC computed\n\n"); + passed++; + + printf("Test 2: HKDF-Extract\n"); + const uint8_t salt[] = "salt"; + const uint8_t ikm[] = "input key material"; + se050_hkdf_extract(prk, salt, sizeof(salt)-1, ikm, sizeof(ikm)-1); + print_hex("PRK", prk, 32); + printf("[INFO] Extract done\n\n"); + passed++; + + printf("Test 3: HKDF-Expand\n"); + const uint8_t info[] = "application info"; + se050_hkdf_expand(okm, 64, prk, info, sizeof(info)-1); + print_hex("OKM", okm, 64); + printf("[INFO] Expand done\n\n"); + passed++; + + printf("Test 4: HKDF Combined\n"); + se050_hkdf(okm, 32, salt, sizeof(salt)-1, ikm, sizeof(ikm)-1, info, sizeof(info)-1); + print_hex("HKDF Output", okm, 32); + printf("[INFO] HKDF done\n\n"); + passed++; + + printf("Test 5: TAI64N Encode/Decode\n"); + se050_tai64n_encode(tai64n, 1609459200, 123456789); + print_hex("TAI64N", tai64n, 12); + se050_tai64n_decode(tai64n, &sec, &nsec); + printf("Decoded: sec=%lu, nsec=%u\n", (unsigned long)sec, nsec); + if (sec == 1609459200 && nsec == 123456789) { + printf("[PASS] Round-trip OK\n\n"); passed++; + } else { + printf("[FAIL] Round-trip failed\n\n"); + } + + printf("Test 6: TAI64N Now\n"); + se050_tai64n_now(tai64n); + print_hex("Current TAI64N", tai64n, 12); + se050_tai64n_decode(tai64n, &sec, &nsec); + printf("Decoded: sec=%lu, nsec=%u\n", (unsigned long)sec, nsec); + printf("[INFO] Current time obtained\n\n"); + passed++; + + printf("Test 7: TAI64N Window Check\n"); + se050_tai64n_now(tai64n); + se050_tai64n_now(current); + int result = se050_tai64n_check_window(tai64n, current, 60); + printf("Window check (60s): %s\n", + result == 1 ? "PASS (within window)" : "FAIL"); + if (result == 1) { + printf("[PASS]\n\n"); passed++; + } else { + printf("[FAIL]\n\n"); + } + + printf("========================================\n"); + printf("Passed: %d/7\n", passed); + printf("========================================\n"); + + return (passed == 7) ? 0 : 1; +}