Clarify crypto key derivation and actual module dependencies

This commit is contained in:
evgeny committed 2026-10-24 00:44:29 +02:00
1 parent 16a33ac9f7
commit 5792db996c
2 files changed
+17 -11

No files matched your search

+3 -1
View File
@@ -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 хоста, старший бит обнуляется.
+14 -10
View File
@@ -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.
---