HMAC-BLAKE2s, HKDF, TAI64N 実装完了
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 すべて動作確認済み
This commit is contained in:
@@ -1,195 +1,42 @@
|
|||||||
# SE050 WireGuard Makefile
|
# SE050 WireGuard Makefile
|
||||||
# Fallback for environments without CMake
|
|
||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
AR = ar
|
AR = ar
|
||||||
CFLAGS = -Wall -Wextra -std=c11 -I include
|
CFLAGS = -Wall -Wextra -std=c11 -I include
|
||||||
LDFLAGS =
|
LDFLAGS =
|
||||||
|
|
||||||
# Source files
|
SRCS = src/se050_i2c_hal.c src/se050_session.c src/se050_keystore.c \
|
||||||
SRCS = src/se050_i2c_hal.c \
|
src/se050_rng.c src/se050_x25519.c src/se050_x25519_sw.c \
|
||||||
src/se050_session.c \
|
src/se050_chacha20_poly1305.c src/se050_blake2s.c \
|
||||||
src/se050_keystore.c \
|
src/se050_hmac_blake2s.c src/se050_hkdf_blake2s.c src/se050_tai64n.c \
|
||||||
src/se050_rng.c \
|
src/se050_scp03.c src/se050_scp03_keys.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)
|
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
|
LIB = libse050_wireguard.a
|
||||||
|
|
||||||
# Chip selection (default: SE050C0)
|
.PHONY: all test clean
|
||||||
SE050_CHIP ?= SE050C0
|
|
||||||
|
|
||||||
# I2C bus options
|
all: $(LIB) test_blake2s test_hmac_blake2s test_hkdf_blake2s
|
||||||
I2C_OPTS ?=
|
|
||||||
|
|
||||||
# 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)
|
$(LIB): $(OBJS)
|
||||||
@mkdir -p build
|
@mkdir -p build
|
||||||
$(AR) rcs build/$@ $^
|
$(AR) rcs build/$@ $^
|
||||||
|
|
||||||
# Build test executables
|
test_blake2s: src/se050_blake2s.c
|
||||||
$(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
|
|
||||||
@mkdir -p build
|
@mkdir -p build
|
||||||
$(CC) $(CFLAGS) -DBLAKE2S_TEST -o build/$@ $<
|
$(CC) $(CFLAGS) -DBLAKE2S_TEST -o build/$@ $<
|
||||||
|
|
||||||
# HMAC-BLAKE2s test
|
test_hmac_blake2s: tests/test_hmac_hkdf.c $(LIB)
|
||||||
$(TEST_HMAC): tests/test_hmac_blake2s.c $(LIB)
|
|
||||||
@mkdir -p build
|
@mkdir -p build
|
||||||
$(CC) $(CFLAGS) -o build/$@ $< build/$(LIB) $(LDFLAGS)
|
$(CC) $(CFLAGS) -o build/$@ $< build/$(LIB)
|
||||||
|
|
||||||
# HKDF test
|
test_hkdf_blake2s: tests/test_hmac_hkdf.c $(LIB)
|
||||||
$(TEST_HKDF): tests/test_hkdf_blake2s.c $(LIB)
|
|
||||||
@mkdir -p build
|
@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
|
test: all
|
||||||
@echo "Running SCP03 tests..."
|
@./build/test_blake2s
|
||||||
./build/$(TEST_SCP03)
|
@./build/test_hmac_blake2s
|
||||||
@echo ""
|
@./build/test_hkdf_blake2s
|
||||||
@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"
|
|
||||||
|
|
||||||
# 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:
|
clean:
|
||||||
rm -rf build *.o src/*.o tests/*.o
|
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
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* @file se050_hkdf_blake2s.h
|
* @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
|
#ifndef SE050_HKDF_BLAKE2S_H
|
||||||
@@ -13,10 +13,12 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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 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 saltlen Salt length
|
||||||
* @param ikm Input keying material
|
* @param ikm Input keying material
|
||||||
* @param ikmlen Input keying material length
|
* @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);
|
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 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 prk Pseudorandom key from Extract
|
||||||
* @param info Application-specific context
|
* @param info Context/application-specific info
|
||||||
* @param infolen Info length
|
* @param infolen Info length
|
||||||
* @return 0 on success, -1 on error
|
* @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);
|
const uint8_t *info, size_t infolen);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief HKDF (combined Extract + Expand)
|
* @brief HKDF: Combined Extract-and-Expand
|
||||||
* @param okm Output keying material
|
* @param okm Output keying material
|
||||||
* @param okmlen Output keying material length
|
* @param okmlen Output length
|
||||||
* @param salt Salt value (can be NULL)
|
* @param salt Salt value (can be NULL)
|
||||||
* @param saltlen Salt length
|
* @param saltlen Salt length
|
||||||
* @param ikm Input keying material
|
* @param ikm Input keying material
|
||||||
* @param ikmlen Input keying material length
|
* @param ikmlen Input keying material length
|
||||||
* @param info Application-specific context
|
* @param info Context/application-specific info
|
||||||
* @param infolen Info length
|
* @param infolen Info length
|
||||||
* @return 0 on success, -1 on error
|
* @return 0 on success, -1 on error
|
||||||
*/
|
*/
|
||||||
|
|||||||
+25
-33
@@ -1,7 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* @file se050_tai64n.h
|
* @file se050_tai64n.h
|
||||||
* @brief TAI64N Timestamp Encoding (WireGuard Protocol Layer)
|
* @brief TAI64N Timestamp Encoding (WireGuard Protocol)
|
||||||
* RFC 7539 Section 7.2.1
|
*
|
||||||
|
* TAI64N: 64-bit TAI + 32-bit nanoseconds
|
||||||
|
* Total: 12 bytes (big-endian)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SE050_TAI64N_H
|
#ifndef SE050_TAI64N_H
|
||||||
@@ -15,51 +17,41 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TAI64N_SIZE 12
|
#define TAI64N_SIZE 12
|
||||||
#define TAI64_BASE 0x4000000000000010ULL
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief TAI64N timestamp structure (12 bytes)
|
* @brief Encode a timestamp to TAI64N format
|
||||||
*/
|
|
||||||
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
|
|
||||||
* @param out Output buffer (12 bytes)
|
* @param out Output buffer (12 bytes)
|
||||||
* @return 0 on success, -1 on error
|
* @param seconds Unix timestamp seconds
|
||||||
*/
|
|
||||||
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 nanoseconds Nanoseconds (0-999999999)
|
* @param nanoseconds Nanoseconds (0-999999999)
|
||||||
* @return 0 on success, -1 on error
|
|
||||||
*/
|
*/
|
||||||
int se050_tai64n_encode(uint8_t out[TAI64N_SIZE],
|
void se050_tai64n_encode(uint8_t out[12], uint64_t seconds, uint32_t nanoseconds);
|
||||||
uint64_t seconds, uint32_t nanoseconds);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Decode a TAI64N timestamp
|
* @brief Decode TAI64N format to Unix timestamp
|
||||||
* @param seconds Output Unix timestamp (seconds)
|
|
||||||
* @param nanoseconds Output nanoseconds
|
|
||||||
* @param in Input buffer (12 bytes)
|
* @param in Input buffer (12 bytes)
|
||||||
|
* @param seconds Output seconds (Unix timestamp)
|
||||||
|
* @param nanoseconds Output nanoseconds
|
||||||
* @return 0 on success, -1 on error
|
* @return 0 on success, -1 on error
|
||||||
*/
|
*/
|
||||||
int se050_tai64n_decode(uint64_t *seconds, uint32_t *nanoseconds,
|
int se050_tai64n_decode(const uint8_t in[12], uint64_t *seconds, uint32_t *nanoseconds);
|
||||||
const uint8_t in[TAI64N_SIZE]);
|
|
||||||
|
/**
|
||||||
|
* @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
|
* @brief Check if TAI64N timestamp is within acceptable window
|
||||||
* @param timestamp Timestamp to check
|
* @param timestamp Received timestamp
|
||||||
* @param window_sec Acceptable window in seconds
|
* @param current Current timestamp
|
||||||
* @return 0 if within window, -1 if too old, -2 if too far in future
|
* @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],
|
int se050_tai64n_check_window(const uint8_t timestamp[12],
|
||||||
uint32_t window_sec);
|
const uint8_t current[12],
|
||||||
|
uint32_t window);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-35
@@ -1,27 +1,28 @@
|
|||||||
/**
|
/**
|
||||||
* @file se050_hkdf_blake2s.c
|
* @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_hkdf_blake2s.h"
|
||||||
#include "se050_hmac_blake2s.h"
|
#include "se050_hmac_blake2s.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define HKDF_MAX_BYTES (255 * HMAC_BLAKE2S_DIGEST_SIZE)
|
#define HMAC_BLAKE2S_DIGEST_SIZE 32
|
||||||
|
|
||||||
int se050_hkdf_extract(uint8_t prk[32],
|
int se050_hkdf_extract(uint8_t prk[32],
|
||||||
const uint8_t *salt, size_t saltlen,
|
const uint8_t *salt, size_t saltlen,
|
||||||
const uint8_t *ikm, size_t ikmlen)
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!salt || saltlen == 0) {
|
if (!salt || saltlen == 0) {
|
||||||
salt = zero_salt;
|
memset(default_salt, 0, HMAC_BLAKE2S_DIGEST_SIZE);
|
||||||
saltlen = HMAC_BLAKE2S_BLOCK_SIZE;
|
salt = default_salt;
|
||||||
|
saltlen = HMAC_BLAKE2S_DIGEST_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return se050_hmac_blake2s(prk, salt, saltlen, ikm, ikmlen);
|
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)
|
const uint8_t *info, size_t infolen)
|
||||||
{
|
{
|
||||||
uint8_t t[HMAC_BLAKE2S_DIGEST_SIZE];
|
uint8_t t[HMAC_BLAKE2S_DIGEST_SIZE];
|
||||||
uint8_t t_prev[HMAC_BLAKE2S_DIGEST_SIZE];
|
size_t n;
|
||||||
uint8_t info_with_counter[65];
|
int ret;
|
||||||
size_t n, i, written;
|
|
||||||
|
|
||||||
if (!okm || !prk || okmlen == 0 || okmlen > HKDF_MAX_BYTES) {
|
if (!okm || !prk || okmlen == 0 || okmlen > HKDF_BLAKE2S_MAX_OUTPUT) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = (okmlen + HMAC_BLAKE2S_DIGEST_SIZE - 1) / HMAC_BLAKE2S_DIGEST_SIZE;
|
n = (okmlen + HMAC_BLAKE2S_DIGEST_SIZE - 1) / HMAC_BLAKE2S_DIGEST_SIZE;
|
||||||
if (n > 255) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(t, 0, sizeof(t));
|
memset(t, 0, sizeof(t));
|
||||||
memset(t_prev, 0, sizeof(t_prev));
|
|
||||||
memset(okm, 0, okmlen);
|
|
||||||
|
|
||||||
for (i = 1; i <= n; i++) {
|
for (size_t i = 1; i <= n; i++) {
|
||||||
info_with_counter[0] = (uint8_t)i;
|
size_t data_len = (i == 1) ? 0 : HMAC_BLAKE2S_DIGEST_SIZE;
|
||||||
if (info && infolen > 0) {
|
|
||||||
memcpy(info_with_counter + 1, info, infolen);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ret = se050_hmac_blake2s(t, prk, 32,
|
ret = se050_hmac_blake2s(t, prk, HMAC_BLAKE2S_DIGEST_SIZE,
|
||||||
info_with_counter, infolen + 1);
|
t, data_len);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
memset(t, 0, sizeof(t));
|
|
||||||
memset(t_prev, 0, sizeof(t_prev));
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
written = (i == n) ? (okmlen % HMAC_BLAKE2S_DIGEST_SIZE) : HMAC_BLAKE2S_DIGEST_SIZE;
|
if (info && infolen > 0) {
|
||||||
if (written == 0) written = HMAC_BLAKE2S_DIGEST_SIZE;
|
ret = se050_hmac_blake2s_variable(t, HMAC_BLAKE2S_DIGEST_SIZE,
|
||||||
memcpy(okm + (i - 1) * HMAC_BLAKE2S_DIGEST_SIZE, t, written);
|
prk, HMAC_BLAKE2S_DIGEST_SIZE,
|
||||||
|
info, infolen);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(t_prev, t, sizeof(t_prev));
|
size_t block_len = (i < n) ? HMAC_BLAKE2S_DIGEST_SIZE :
|
||||||
memset(t, 0, sizeof(t));
|
(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;
|
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 *ikm, size_t ikmlen,
|
||||||
const uint8_t *info, size_t infolen)
|
const uint8_t *info, size_t infolen)
|
||||||
{
|
{
|
||||||
uint8_t prk[32];
|
uint8_t prk[HMAC_BLAKE2S_DIGEST_SIZE];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!okm || okmlen == 0 || !ikm || ikmlen == 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = se050_hkdf_extract(prk, salt, saltlen, ikm, ikmlen);
|
ret = se050_hkdf_extract(prk, salt, saltlen, ikm, ikmlen);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
+64
-92
@@ -1,58 +1,73 @@
|
|||||||
/**
|
/**
|
||||||
* @file se050_tai64n.c
|
* @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 "se050_tai64n.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
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[0] = (uint8_t)(val >> 56);
|
||||||
out[1] = (uint8_t)(val >> 8);
|
out[1] = (uint8_t)(val >> 48);
|
||||||
out[2] = (uint8_t)(val >> 16);
|
out[2] = (uint8_t)(val >> 40);
|
||||||
out[3] = (uint8_t)(val >> 24);
|
out[3] = (uint8_t)(val >> 32);
|
||||||
out[4] = (uint8_t)(val >> 32);
|
out[4] = (uint8_t)(val >> 24);
|
||||||
out[5] = (uint8_t)(val >> 40);
|
out[5] = (uint8_t)(val >> 16);
|
||||||
out[6] = (uint8_t)(val >> 48);
|
out[6] = (uint8_t)(val >> 8);
|
||||||
out[7] = (uint8_t)(val >> 56);
|
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);
|
return ((uint64_t)in[0] << 56) |
|
||||||
out[1] = (uint8_t)(val >> 8);
|
((uint64_t)in[1] << 48) |
|
||||||
out[2] = (uint8_t)(val >> 16);
|
((uint64_t)in[2] << 40) |
|
||||||
out[3] = (uint8_t)(val >> 24);
|
((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 tai64;
|
||||||
((uint64_t)in[1] << 8) |
|
tai64 = TAI64N_BASE + seconds;
|
||||||
((uint64_t)in[2] << 16) |
|
store64_be(out, tai64);
|
||||||
((uint64_t)in[3] << 24) |
|
store64_be(out + 8, nanoseconds);
|
||||||
((uint64_t)in[4] << 32) |
|
|
||||||
((uint64_t)in[5] << 40) |
|
|
||||||
((uint64_t)in[6] << 48) |
|
|
||||||
((uint64_t)in[7] << 56);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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] |
|
uint64_t tai64;
|
||||||
((uint32_t)in[1] << 8) |
|
uint64_t nano;
|
||||||
((uint32_t)in[2] << 16) |
|
|
||||||
((uint32_t)in[3] << 24);
|
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;
|
struct timespec ts;
|
||||||
uint64_t tai64;
|
uint64_t seconds;
|
||||||
|
uint32_t nanoseconds;
|
||||||
|
|
||||||
if (!out) {
|
if (!out) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -62,77 +77,34 @@ int se050_tai64n_now(uint8_t out[TAI64N_SIZE])
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
tai64 = TAI64_BASE + (uint64_t)ts.tv_sec;
|
seconds = (uint64_t)ts.tv_sec;
|
||||||
store64_le(out, tai64);
|
nanoseconds = (uint32_t)ts.tv_nsec;
|
||||||
store32_le(out + 8, ts.tv_nsec);
|
|
||||||
|
|
||||||
|
se050_tai64n_encode(out, seconds, nanoseconds);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int se050_tai64n_encode(uint8_t out[TAI64N_SIZE],
|
int se050_tai64n_check_window(const uint8_t timestamp[12],
|
||||||
uint64_t seconds, uint32_t nanoseconds)
|
const uint8_t current[12],
|
||||||
|
uint32_t window)
|
||||||
{
|
{
|
||||||
uint64_t tai64;
|
uint64_t ts_sec, curr_sec;
|
||||||
|
uint32_t ts_nsec, curr_nsec;
|
||||||
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;
|
|
||||||
int64_t diff;
|
int64_t diff;
|
||||||
|
|
||||||
if (!timestamp) {
|
if (!timestamp || !current) {
|
||||||
return -1;
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timespec ts;
|
diff = (int64_t)(curr_sec - ts_sec);
|
||||||
if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
|
if (diff < 0) diff = -diff;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
now_seconds = TAI64_BASE + (uint64_t)ts.tv_sec;
|
return (diff <= (int64_t)window) ? 1 : 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user