WireGuard プロトコル層実装

鍵導出チェーン (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)
- 完全なハンドシェイクチェーンシミュレーション
This commit is contained in:
km
2026-03-26 21:17:38 +09:00
parent 0c9237324e
commit c9844dc0ba
4 changed files with 318 additions and 1 deletions
+12 -1
View File
@@ -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_rng.c src/se050_x25519.c src/se050_x25519_sw.c \
src/se050_chacha20_poly1305.c src/se050_blake2s.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_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) OBJS = $(SRCS:.c=.o)
LIB = libse050_wireguard.a LIB = libse050_wireguard.a
@@ -40,3 +40,14 @@ test: all
clean: clean:
rm -rf build *.o src/*.o tests/*.o 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
+114
View File
@@ -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 <stdint.h>
#include <stddef.h>
#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 */
+104
View File
@@ -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 <string.h>
#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));
}
+88
View File
@@ -0,0 +1,88 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#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;
}