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:
+28
-36
@@ -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 <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],
|
||||
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;
|
||||
|
||||
+64
-92
@@ -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 <time.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[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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user