From 5792db996c2ac60e3aeac17dec1890620a03bc8b Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 24 Oct 2026 00:44:29 +0200 Subject: [PATCH] Clarify crypto key derivation and actual module dependencies --- src/transport_layer/secure_channel.h | 4 +++- src/transport_layer/secure_channel_doc.md | 24 +++++++++++++---------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/transport_layer/secure_channel.h b/src/transport_layer/secure_channel.h index 73ce9936..0558f650 100644 --- a/src/transport_layer/secure_channel.h +++ b/src/transport_layer/secure_channel.h @@ -20,7 +20,7 @@ extern "C" { #define SC_PRIVKEY_SIZE 32 #define SC_PUBKEY_SIZE 32 #define SC_HASH_SIZE 32 -#define SC_NONCE_SIZE 13 // CCM requires exactly 13 bytes +#define SC_NONCE_SIZE 13 // Длина nonce в пакетном формате этого модуля #define SC_SHARED_SECRET_SIZE SC_HASH_SIZE #define SC_SESSION_KEY_SIZE 16 #define SC_TAG_SIZE 16 @@ -125,6 +125,8 @@ void sc_stream_sign_cleanup(struct sc_stream_sign_state *state); sc_status_t sc_ed25519_sign(const uint8_t privkey[32], const uint8_t* msg, size_t msg_len, uint8_t sig_out[64]); sc_status_t sc_ed25519_verify(const uint8_t pubkey[32], const uint8_t* msg, size_t msg_len, const uint8_t sig[64]); +/* Вход X25519 private[32], выход Ed25519 public[32]; seed — первые 32 байта SHA512 входа. + * Оба буфера обязательны; SC_OK при успехе, отрицательный SC_ERR_* при ошибке. */ sc_status_t sc_derive_ed25519_pubkey(const uint8_t *x25519_privkey, uint8_t *ed25519_pubkey_out); /* SHA256(public_key[32]): первые 8 байт memcpy в uint64_t хоста, старший бит обнуляется. diff --git a/src/transport_layer/secure_channel_doc.md b/src/transport_layer/secure_channel_doc.md index 494349ce..ff6b4245 100644 --- a/src/transport_layer/secure_channel_doc.md +++ b/src/transport_layer/secure_channel_doc.md @@ -136,10 +136,12 @@ sc_stream_sign_final(&state, stream_sig, &sig_len); // sig_len — capacity н sc_stream_sign_verify_init(&state, ed25519_pubkey); sc_stream_sign_update(&state, chunk1, len1); sc_stream_sign_update(&state, chunk2, len2); -int result = sc_stream_sign_verify(&state, stream_sig, sig_len); // SC_OK или SC_ERR_AUTH_FAILED +int result = sc_stream_sign_verify(&state, stream_sig, sig_len); // SC_OK при успехе, отрицательный SC_ERR_* при ошибке ``` -**Деривация Ed25519-ключа из X25519:** `sc_derive_ed25519_pubkey(x25519_privkey, ed25519_pubkey)` — SHA-512 от X25519-приватного ключа даёт Ed25519-приватный ключ (32 байта), из которого извлекается Ed25519-публичный ключ. Это позволяет одному ключу обслуживать и ECDH, и подписи. +**Деривация Ed25519-ключа из X25519:** `sc_derive_ed25519_pubkey(x25519_privkey, ed25519_pubkey)` +берёт первые 32 байта `SHA512(x25519_privkey[32])` как Ed25519 seed и извлекает из него публичный ключ (32 байта). +Потоковая подпись использует тот же производный ключ; one-shot API принимает непосредственно Ed25519-ключи. ### 2.5. Деривация node_id @@ -259,17 +261,17 @@ Nonce не зависит от часов, счётчиков контекста | Функция | Описание | |---|---| | `sc_ed25519_sign(privkey[32], msg, msg_len, sig_out[64])` | Подпись сообщения. `privkey` — 32-байтный Ed25519-приватный ключ (НЕ X25519). | -| `sc_ed25519_verify(pubkey[32], msg, msg_len, sig[64])` | Проверка подписи. Возвращает `SC_OK` или `SC_ERR_AUTH_FAILED`. | +| `sc_ed25519_verify(pubkey[32], msg, msg_len, sig[64])` | Проверка подписи. Возвращает `SC_OK` при успехе, отрицательный `SC_ERR_*` при ошибке. | #### Ed25519 подписи (стриминг) | Функция | Описание | |---|---| -| `sc_stream_sign_init(ctx, state)` | Инициализирует подпись. Извлекает Ed25519-ключ из X25519 через `SHA512(x25519_privkey)`. | +| `sc_stream_sign_init(ctx, state)` | Инициализирует подпись. Ed25519 seed — первые 32 байта `SHA512(x25519_privkey[32])`. | | `sc_stream_sign_verify_init(state, ed25519_pubkey)` | Инициализирует верификацию с переданным Ed25519 pubkey. | | `sc_stream_sign_update(state, data, len)` | SHA-512 update (инкрементальный). Нулевая длина — no-op. | | `sc_stream_sign_final(state, sig_out, &sig_len)` | Завершает SHA-512 → one-shot Ed25519 подпись хэша → **автоматический cleanup**. На входе sig_len задаёт capacity sig_out (не менее 64), при успехе на выходе 64. | -| `sc_stream_sign_verify(state, sig, sig_len)` | Завершает SHA-512 → one-shot Ed25519 проверка → **автоматический cleanup**. Возвращает `SC_OK` или `SC_ERR_AUTH_FAILED`. | +| `sc_stream_sign_verify(state, sig, sig_len)` | Завершает SHA-512 → one-shot Ed25519 проверка → **автоматический cleanup**. Возвращает `SC_OK` при успехе, отрицательный `SC_ERR_*` при ошибке. | | `sc_stream_sign_cleanup(state)` | Ручная очистка (если не вызван final/verify). | **Потоковая схема:** Ed25519 внутри делает SHA-512 от данных, поэтому для стриминга нужно было бы грузить все данные в память. Вместо этого: `SHA-512(данные)` делается инкрементально через `EVP_DigestUpdate`, затем 64-байтный хэш подписывается one-shot `EVP_DigestSign`. Результат: `Ed25519(SHA-512(данные))` — консистентно с обеих сторон. Память O(1). @@ -278,7 +280,7 @@ Nonce не зависит от часов, счётчиков контекста | Функция | Описание | |---|---| -| `sc_derive_ed25519_pubkey(x25519_privkey, ed25519_pubkey_out)` | Из X25519-приватного ключа (32 байта) выводит Ed25519-публичный ключ (32 байта) через `SHA512(x25519_privkey)`. | +| `sc_derive_ed25519_pubkey(x25519_privkey, ed25519_pubkey_out)` | Из X25519-приватного ключа (32 байта) выводит Ed25519-публичный ключ (32 байта); seed — первые 32 байта SHA512 входа. | | `sc_derive_node_id_from_pubkey(public_key)` | SHA256 бинарного X25519 pubkey[32] → первые 8 байт memcpy в uint64_t хоста, старший бит обнулён. При NULL возвращает 0 и логирует ошибку. | #### Утилиты @@ -292,15 +294,17 @@ Nonce не зависит от часов, счётчиков контекста | Зависимость | Использование | |---|---| | **OpenSSL EVP** (`openssl/evp.h`) | X25519 keygen/derive (`EVP_PKEY`), AES-128-CCM, AES-128-CTR, Ed25519 sign/verify, SHA-512 | -| **OpenSSL SHA** (`openssl/sha.h`) | `SHA256_Init/Update/Final` для построения nonce в `sc_build_nonce()` | -| **`../lib/sha256.h`** (`sc_sha256_*`) | SHA256 для вывода session_key, stream nonce, obfuscate pubkey, sha_transcode, node_id | +| **OpenSSL SHA** (`openssl/sha.h`) | SHA256 для session_key, CTR IV, обфускации, transcode и node_id; SHA512 для Ed25519 seed | +| **OpenSSL RAND** (`openssl/rand.h`) | `RAND_bytes` для случайного CCM nonce каждого пакета | | **`../lib/debug_config.h`** | `DEBUG_ERROR`, `DEBUG_WARN`, `DEBUG_INFO`, `DEBUG_DEBUG` (категория `DEBUG_CATEGORY_CRYPTO`) | | **`../lib/platform_compat.h`** | Общие платформенные определения; CCM nonce генерируется OpenSSL RAND_bytes | | **`crc32.h`** (`crc32_calc`) | Контроль целостности в шифрованных пакетах | -### 3.5. Отсутствующие функции +### 3.5. Границы транспортной сессии -- **`sc_rekey()`** упоминается в AGENTS.md, но **не реализована** в текущей версии. Ротация сессионного ключа не поддерживается — после ECDH ключ фиксирован на всё время сессии. +`sc_set_peer_public_key` выводит ключ через X25519 и может заменить ключ пира в существующем контексте. +Счётчики encrypt/decrypt служат статистикой, а не идентификатором сессии или защитой от повторов. +Согласование эпох и допуск DATA выполняет `etcp_session`; дедупликацию DATA обеспечивает ETCP. ---