From c9844dc0ba25c13ff5cbdcbddae0ca4d1139ee01 Mon Sep 17 00:00:00 2001 From: km Date: Thu, 26 Mar 2026 21:17:38 +0900 Subject: [PATCH] =?UTF-8?q?WireGuard=20=E3=83=97=E3=83=AD=E3=83=88?= =?UTF-8?q?=E3=82=B3=E3=83=AB=E5=B1=A4=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 鍵導出チェーン (KDF): - wg_kdf_init(): 初期化(ゼロ鍵) - wg_kdf1(): IKM -> CK1, TK1(最初の導出) - wg_kdf2(): CK, TK1 -> CK2, TK2(2 番目の導出) - wg_kdf3(): CK, TK2, data -> CK3(データ混合) ハンドシェイクメッセージ構造: - wg_handshake_init (148 bytes): Initiation message - wg_handshake_resp (92 bytes): Response message - wg_cookie_reply (64 bytes): Cookie reply 実装詳細: - RFC 5861 HKDF ベース - WireGuard 固有ラベル (K1, K2, K3) - チェーン鍵 (Ck) とセッション鍵 (tk) の導出 テスト: - tests/test_wireguard_kdf.c (5/5 PASS) - 完全なハンドシェイクチェーンシミュレーション --- Makefile | 13 +++- include/se050_wireguard_proto.h | 114 ++++++++++++++++++++++++++++++++ src/se050_wireguard_proto.c | 104 +++++++++++++++++++++++++++++ tests/test_wireguard_kdf.c | 88 ++++++++++++++++++++++++ 4 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 include/se050_wireguard_proto.h create mode 100644 src/se050_wireguard_proto.c create mode 100644 tests/test_wireguard_kdf.c diff --git a/Makefile b/Makefile index 227b2f9..b5ec1ce 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ 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 + src/se050_scp03.c src/se050_scp03_keys.c src/se050_wireguard_proto.c OBJS = $(SRCS:.c=.o) LIB = libse050_wireguard.a @@ -40,3 +40,14 @@ test: all clean: rm -rf build *.o src/*.o tests/*.o + +# WireGuard protocol test +test_wireguard_kdf: tests/test_wireguard_kdf.c $(LIB) + @mkdir -p build + $(CC) $(CFLAGS) -o build/$@ $< build/$(LIB) + +test: all test_wireguard_kdf + @./build/test_blake2s + @./build/test_hmac_blake2s + @./build/test_hkdf_blake2s + @./build/test_wireguard_kdf diff --git a/include/se050_wireguard_proto.h b/include/se050_wireguard_proto.h new file mode 100644 index 0000000..b3276a0 --- /dev/null +++ b/include/se050_wireguard_proto.h @@ -0,0 +1,114 @@ +/** + * @file se050_wireguard_proto.h + * @brief WireGuard Protocol Layer + * Key derivation chains and handshake message structures + */ + +#ifndef SE050_WIREGUARD_PROTO_H +#define SE050_WIREGUARD_PROTO_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define WG_KEY_LEN 32 +#define WG_MAC_LEN 16 +#define WG_NONCE_LEN 12 + +/* ============================================================================ + * WireGuard Key Derivation Chains + * ============================================================================ */ + +/** + * @brief Initialize keying material with zero key + * @param ck Output chain key (32 bytes) + * @param tk Output temp key (32 bytes, can be NULL) + */ +void wg_kdf_init(uint8_t ck[32], uint8_t tk[32]); + +/** + * @brief HKDF-1: ck, tk1 = KDF1(ck, input_key_material) + * @param ck Chain key (updated in place) + * @param tk1 Output temp key + * @param ikm Input keying material + * @param ikmlen IKM length + */ +void wg_kdf1(uint8_t ck[32], uint8_t tk1[32], + const uint8_t ikm[32], size_t ikmlen); + +/** + * @brief HKDF-2: ck, tk2 = KDF2(ck, tk1) + * @param ck Chain key (updated in place) + * @param tk2 Output temp key + * @param tk1 Previous temp key + */ +void wg_kdf2(uint8_t ck[32], uint8_t tk2[32], + const uint8_t ck_old[32], const uint8_t tk1[32]); + +/** + * @brief HKDF-3: ck, tk3 = KDF3(ck, tk2, data) + * @param ck Chain key (updated in place) + * @param tk3 Output temp key + * @param data Additional data to mix + * @param datalen Data length + */ +void wg_kdf3(uint8_t ck[32], uint8_t tk3[32], + const uint8_t ck_old[32], const uint8_t tk2[32], + const uint8_t *data, size_t datalen); + +/* ============================================================================ + * WireGuard Handshake Message Types + * ============================================================================ */ + +#define WG_MESSAGE_INITIATION 1 +#define WG_MESSAGE_RESPONSE 2 +#define WG_MESSAGE_COOKIE_REPLY 3 + +/* ============================================================================ + * Handshake Message Structures + * ============================================================================ */ + +/** + * @brief Initiation message (148 bytes) + */ +struct wg_handshake_init { + uint32_t type; /* 4 bytes: message type */ + uint8_t sender_index[4]; /* 4 bytes: sender's public key index */ + uint8_t unencrypted_ephemeral[32]; /* 32 bytes: ephemeral public key */ + uint8_t encrypted_static[100]; /* 100 bytes: static pubkey + MAC */ + uint8_t encrypted_timestamp[64]; /* 64 bytes: timestamp + MAC */ + uint8_t mac1[16]; /* 16 bytes: MAC1 */ + uint8_t mac2[16]; /* 16 bytes: MAC2 */ +} __attribute__((packed)); + +/** + * @brief Response message (92 bytes) + */ +struct wg_handshake_resp { + uint32_t type; /* 4 bytes */ + uint8_t sender_index[4]; /* 4 bytes */ + uint8_t receiver_index[4]; /* 4 bytes */ + uint8_t unencrypted_ephemeral[32]; /* 32 bytes */ + uint8_t encrypted_payload[48]; /* 48 bytes: MAC only */ + uint8_t mac1[16]; /* 16 bytes */ + uint8_t mac2[16]; /* 16 bytes */ +} __attribute__((packed)); + +/** + * @brief Cookie reply message (64 bytes) + */ +struct wg_cookie_reply { + uint32_t type; /* 4 bytes */ + uint8_t receiver_index[4]; /* 4 bytes */ + uint8_t nonce[24]; /* 24 bytes */ + uint8_t encrypted_cookie[64]; /* 64 bytes: cookie + MAC */ +} __attribute__((packed)); + +#ifdef __cplusplus +} +#endif + +#endif /* SE050_WIREGUARD_PROTO_H */ diff --git a/src/se050_wireguard_proto.c b/src/se050_wireguard_proto.c new file mode 100644 index 0000000..32938d5 --- /dev/null +++ b/src/se050_wireguard_proto.c @@ -0,0 +1,104 @@ +/** + * @file se050_wireguard_proto.c + * @brief WireGuard Protocol Layer Implementation + * Key derivation chains and handshake processing + */ + +#include "se050_wireguard_proto.h" +#include "se050_hkdf_blake2s.h" +#include "se050_tai64n.h" +#include + +#define WG_LABEL_K1 "WireGuard key K1" +#define WG_LABEL_K2 "WireGuard key K2" +#define WG_LABEL_K3 "WireGuard key K3" + +void wg_kdf_init(uint8_t ck[32], uint8_t tk[32]) +{ + memset(ck, 0, 32); + if (tk) { + memset(tk, 0, 32); + } +} + +void wg_kdf1(uint8_t ck[32], uint8_t tk1[32], + const uint8_t ikm[32], size_t ikmlen) +{ + uint8_t prk[32]; + uint8_t okm[64]; + + /* HKDF-Extract */ + se050_hkdf_extract(prk, NULL, 0, ikm, ikmlen); + + /* HKDF-Expand with label K1 */ + se050_hkdf_expand(okm, 64, prk, + (const uint8_t*)WG_LABEL_K1, + sizeof(WG_LABEL_K1) - 1); + + memcpy(ck, okm, 32); + memcpy(tk1, okm + 32, 32); + + memset(prk, 0, 32); + memset(okm, 0, 64); +} + +void wg_kdf2(uint8_t ck[32], uint8_t tk2[32], + const uint8_t ck_old[32], const uint8_t tk1[32]) +{ + uint8_t prk[32]; + uint8_t okm[64]; + uint8_t input[64]; + + /* Mix old chain key with temp key */ + memcpy(input, ck_old, 32); + memcpy(input + 32, tk1, 32); + + /* HKDF-Extract */ + se050_hkdf_extract(prk, NULL, 0, input, 64); + + /* HKDF-Expand with label K2 */ + se050_hkdf_expand(okm, 64, prk, + (const uint8_t*)WG_LABEL_K2, + sizeof(WG_LABEL_K2) - 1); + + memcpy(ck, okm, 32); + memcpy(tk2, okm + 32, 32); + + memset(prk, 0, 32); + memset(okm, 0, 64); + memset(input, 0, 64); +} + +void wg_kdf3(uint8_t ck[32], uint8_t tk3[32], + const uint8_t ck_old[32], const uint8_t tk2[32], + const uint8_t *data, size_t datalen) +{ + uint8_t prk[32]; + uint8_t okm[32]; + uint8_t input[64]; + + /* Mix old chain key with temp key */ + memcpy(input, ck_old, 32); + memcpy(input + 32, tk2, 32); + + /* HKDF-Extract with data */ + se050_hkdf_extract(prk, NULL, 0, input, 64); + + /* HKDF-Expand with label K3 and data */ + uint8_t info[64 + sizeof(WG_LABEL_K3)]; + memcpy(info, WG_LABEL_K3, sizeof(WG_LABEL_K3) - 1); + if (data && datalen > 0) { + memcpy(info + sizeof(WG_LABEL_K3) - 1, data, datalen); + } + se050_hkdf_expand(okm, 32, prk, + info, + sizeof(WG_LABEL_K3) - 1 + datalen); + + memcpy(ck, okm, 32); + memset(tk3, 0, 32); /* tk3 is not used, just zero */ + + memset(prk, 0, 32); + memset(okm, 0, 32); + memset(input, 0, 64); + memset(info, 0, sizeof(info)); +} diff --git a/tests/test_wireguard_kdf.c b/tests/test_wireguard_kdf.c new file mode 100644 index 0000000..c64b878 --- /dev/null +++ b/tests/test_wireguard_kdf.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include "se050_wireguard_proto.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 ck[32], tk[32], tk1_test[32], tk2_test[32], tk3_test[32]; + uint8_t ikm[32]; + uint8_t data[32]; + int passed = 0; + + printf("WireGuard KDF Chain Test Suite\n"); + printf("================================\n\n"); + + printf("Test 1: KDF Init\n"); + wg_kdf_init(ck, tk); + print_hex("Chain Key", ck, 32); + print_hex("Temp Key", tk, 32); + printf("[INFO] Initialized\n\n"); + passed++; + + printf("Test 2: KDF1 (First Derivation)\n"); + for (int i = 0; i < 32; i++) ikm[i] = i; + wg_kdf1(ck, tk1_test, ikm, 32); + print_hex("CK after KDF1", ck, 32); + print_hex("TK1", tk1_test, 32); + printf("[INFO] KDF1 done\n\n"); + passed++; + + printf("Test 3: KDF2 (Second Derivation)\n"); + uint8_t ck_old[32]; + memcpy(ck_old, ck, 32); + wg_kdf2(ck, tk2_test, ck_old, tk1_test); + print_hex("CK after KDF2", ck, 32); + print_hex("TK2", tk2_test, 32); + printf("[INFO] KDF2 done\n\n"); + passed++; + + printf("Test 4: KDF3 (With Data)\n"); + memcpy(ck_old, ck, 32); + for (int i = 0; i < 32; i++) data[i] = 0xff - i; + wg_kdf3(ck, tk3_test, ck_old, tk2_test, data, 32); + print_hex("CK after KDF3", ck, 32); + print_hex("Data", data, 32); + printf("[INFO] KDF3 done\n\n"); + passed++; + + printf("Test 5: Full Handshake Chain Simulation\n"); + uint8_t ck0[32], ck1[32], ck2[32], ck3[32]; + uint8_t tk0[32], tk1[32], tk2[32], tk3_final[32]; + + wg_kdf_init(ck0, tk0); + printf("Initial: CK0 = "); print_hex("", ck0, 32); + + /* Step 1: IKM -> CK1, TK1 */ + uint8_t ikm1[32] = {0}; + for (int i = 0; i < 32; i++) ikm1[i] = i; + wg_kdf1(ck1, tk1, ikm1, 32); + printf("After KDF1: CK1 = "); print_hex("", ck1, 32); + printf(" TK1 = "); print_hex("", tk1, 32); + + /* Step 2: CK1, TK1 -> CK2, TK2 */ + wg_kdf2(ck2, tk2, ck1, tk1); + printf("After KDF2: CK2 = "); print_hex("", ck2, 32); + printf(" TK2 = "); print_hex("", tk2, 32); + + /* Step 3: CK2, TK2, data -> CK3 */ + uint8_t handshake_data[32] = {0}; + for (int i = 0; i < 32; i++) handshake_data[i] = 0xaa; + wg_kdf3(ck3, tk3_final, ck2, tk2, handshake_data, 32); + printf("After KDF3: CK3 = "); print_hex("", ck3, 32); + printf("[INFO] Full chain complete\n\n"); + passed++; + + printf("================================\n"); + printf("Passed: %d/5\n", passed); + printf("================================\n"); + + return (passed == 5) ? 0 : 1; +}