Correct remaining crypto examples and streaming signature buffer contract

This commit is contained in:
evgeny committed 2026-10-24 00:37:18 +02:00
1 parent 3afd31e561
commit 16a33ac9f7
2 files changed
+11 -9

No files matched your search

+1
View File
@@ -117,6 +117,7 @@ struct sc_stream_sign_state {
sc_status_t sc_stream_sign_init(sc_context_t *ctx, struct sc_stream_sign_state *state);
sc_status_t sc_stream_sign_verify_init(struct sc_stream_sign_state *state, const uint8_t *ed25519_pubkey);
sc_status_t sc_stream_sign_update(struct sc_stream_sign_state *state, const uint8_t *data, size_t len);
/* sig_len задаёт capacity sig_out (не менее 64), при успехе получает длину 64; завершение освобождает sign state. */
sc_status_t sc_stream_sign_final(struct sc_stream_sign_state *state, uint8_t *sig_out, size_t *sig_len);
sc_status_t sc_stream_sign_verify(struct sc_stream_sign_state *state, const uint8_t *sig, size_t sig_len);
void sc_stream_sign_cleanup(struct sc_stream_sign_state *state);
+10 -9
View File
@@ -123,18 +123,20 @@ int ok = sc_ed25519_verify(pubkey, msg, msg_len, sig); // SC_OK при успе
**Стриминговая (потоковая) подпись:** SHA-512 аккумулятор + one-shot Ed25519 в финале. Подходит для данных любого размера (память O(1)):
```c
struct sc_stream_sign_state state;
uint8_t stream_sig[SC_SIGN_SIZE];
size_t sig_len = sizeof(stream_sig);
// Подпись
sc_stream_sign_init(&ctx, &state);
sc_stream_sign_update(&state, chunk1, len1);
sc_stream_sign_update(&state, chunk2, len2);
sc_stream_sign_final(&state, sig, &sig_len); // автоматический cleanup
sc_stream_sign_final(&state, stream_sig, &sig_len); // sig_len — capacity на входе, длина подписи на выходе; cleanup
// Верификация
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, sig, sig_len); // SC_OK или SC_ERR_AUTH_FAILED
int result = sc_stream_sign_verify(&state, stream_sig, sig_len); // SC_OK или SC_ERR_AUTH_FAILED
```
**Деривация Ed25519-ключа из X25519:** `sc_derive_ed25519_pubkey(x25519_privkey, ed25519_pubkey)` — SHA-512 от X25519-приватного ключа даёт Ed25519-приватный ключ (32 байта), из которого извлекается Ed25519-публичный ключ. Это позволяет одному ключу обслуживать и ECDH, и подписи.
@@ -142,8 +144,8 @@ int result = sc_stream_sign_verify(&state, sig, sig_len); // SC_OK или SC_ER
### 2.5. Деривация node_id
```c
uint64_t node_id = sc_derive_node_id(private_key);
// SHA256(private_key) → первые 8 байт, старший бит обнулён (0x7FFFFFFFFFFFFFFF)
uint64_t node_id = sc_derive_node_id_from_pubkey(public_key);
// SHA256(X25519 public_key[32]) → первые 8 байт memcpy в uint64_t хоста, старший бит обнулён
```
### 2.6. SHA256-based транскодирование
@@ -266,7 +268,7 @@ Nonce не зависит от часов, счётчиков контекста
| `sc_stream_sign_init(ctx, state)` | Инициализирует подпись. Извлекает Ed25519-ключ из X25519 через `SHA512(x25519_privkey)`. |
| `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=64`. |
| `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_cleanup(state)` | Ручная очистка (если не вызван final/verify). |
@@ -353,15 +355,14 @@ Nonce не зависит от часов, счётчиков контекста
```
- `session_ready` становится 1 только после успешного ECDH через `sc_set_peer_public_key()`
- Контекст привязан к конкретному пиру (peer_public_key фиксирован)
- Для смены пира нужен новый контекст
- Успешный `sc_set_peer_public_key` сохраняет ключ текущего пира и заново вычисляет session_key
- Счётчики не синхронизируются между сторонами — каждая сторона считает свои tx/rx независимо
---
## 6. Примечания по безопасности
- **Nonce должен быть уникальным** для каждого шифрования с одним ключом. Здесь nonce строится из `SHA256(random_seed || counter || время)`. При случайном seed и монотонном counter'е коллизии крайне маловероятны.
- **CCM nonce** — 13 байт из OpenSSL RAND_bytes; при отказе CSPRNG encrypt возвращает ошибку без готового пакета.
- **CRC32 — не криптографическая защита.** Он дополнительно ловит битовые ошибки после расшифровки (belt-and-suspenders), но основная защита целостности — CCM-тег.
- **Обфускация pubkey — не шифрование.** Это XOR с детерминированным хэшем, обратима для любого, кто знает salt и второй pubkey. Защищает от пассивного наблюдения (не видно публичный ключ в открытом виде), но не от активной подмены.
- **OpenSSL EVP API** используется для всех криптоопераций (реализации FIPS-сертифицированы при использовании FIPS-провайдера).
- X25519, AES-CCM, AES-CTR и Ed25519 выполняются через OpenSSL EVP.