diff --git a/src/media_async/media_crypto.h b/src/media_async/media_crypto.h index 4ba5de4f..9b05b48d 100644 --- a/src/media_async/media_crypto.h +++ b/src/media_async/media_crypto.h @@ -1,8 +1,10 @@ -/* Общие AES-256-CCM примитивы. Файлы обрабатываются порциями с независимыми tags. - * nonce определяется author/UUID/part; UUID новый для каждой подготовки. Домен nonce - * utun_dm_media сохранён для существующего формата DM. Повторы используют готовый ciphertext. - * Файловые функции вызываются в worker; caller открывает файлы и публикует результат - * только после успешной проверки и durable сохранения. 0 = успех, -1 = ошибка. */ +/* media_crypto — AES-256-CCM сообщений и файлов без БД, транспорта и владения файлами. + * Ключ 32 байта, nonce 13 байт, tag 16 байт; AAD нет. UUID новый для каждой подготовки + * с данным ключом/автором; сетевые повторы используют уже готовый ciphertext. + * FILE-функции вызываются в worker и работают с текущих позиций до EOF источника. + * Caller открывает отдельные src/dst, закрывает их и публикует результат только после + * успешной проверки и durable сохранения. Здесь есть fflush(dst), но нет close/fsync/rename. + * Ключи, буферы и FILE заимствованы на время вызова. int-функции: 0 = успех, -1 = ошибка. */ #ifndef MEDIA_CRYPTO_H #define MEDIA_CRYPTO_H #include @@ -16,16 +18,31 @@ extern "C" { #define MEDIA_CIPHER_TAG_SIZE 16 #define MEDIA_CIPHER_PLAIN_MAX 65535u #define MEDIA_CIPHER_CHUNK_SIZE 32768u +/* Первые 13 байт SHA256("utun_dm_media"[13] || author:uint64 || id:16 || part:uint64). + * Числа в native byte order текущего формата; id/nonce обязательны, проверок аргументов нет. + * part — номер порции с нуля; разным plaintext с тем же ключом нужен новый id. */ void media_cipher_nonce(uint64_t author, const uint8_t id[16], uint64_t part, uint8_t nonce[MEDIA_CIPHER_NONCE_SIZE]); -/* out вмещает plain_len+16; расшифровка проверяет tag до возврата plaintext. */ +/* plain_len 0..65535, plain=NULL допустим только при нулевой длине; out вмещает plain_len+16. + * out/key/nonce/out_len обязательны; успех даёт ciphertext||tag и его длину. + * После проверки аргументов *out_len=0 до успеха; при неверных аргументах выходы не меняются. */ int media_ccm_encrypt(const uint8_t key[32], const uint8_t nonce[13], const uint8_t* plain, size_t plain_len, uint8_t* out, size_t* out_len); +/* cipher_len 16..65551, out вмещает cipher_len-16 байт; все указатели обязательны. + * Только rc=0 разрешает использовать plaintext. При ошибке содержимое out не определено; + * после проверки аргументов *out_len=0 до успешной проверки tag. При неверных аргументах выходы не меняются. */ int media_ccm_decrypt(const uint8_t key[32], const uint8_t nonce[13], const uint8_t* cipher, size_t cipher_len, uint8_t* out, size_t* out_len); -/* Поток plaintext → ciphertext; возвращает размер оригинала и SHA256 ciphertext. */ +/* Порции по 32768 plaintext-байт, каждая с отдельным tag; пустой файл тоже даёт один tag. + * author!=0, все указатели обязательны, src!=dst; файлы должны обозначать разные данные. + * При корректных аргументах plain_size/hash обнуляются и выдаются только при успехе: + * фактический размер plaintext и SHA256 всего ciphertext, без внешнего заголовка контейнера. + * Ошибка может оставить частичный dst; выходные FILE не закрываются. */ int media_encrypt_stream(const uint8_t key[32], uint64_t author, const uint8_t id[16], FILE* src, FILE* dst, uint64_t* plain_size, uint8_t hash[32]); -/* Проверяет каждый tag, точный размер и полный hash; dst должен быть временным. */ +/* Те же требования к аргументам/файлам; plain_size/hash берутся из проверенного manifest. + * Проверяет каждый tag, точный размер (включая EOF) и полный hash ciphertext. + * dst должен быть собственным временным файлом: до общей проверки в него уже записываются порции. + * Частичный/непроверенный dst при ошибке отбрасывает вызывающий. */ int media_decrypt_stream(const uint8_t key[32], uint64_t author, const uint8_t id[16], uint64_t plain_size, const uint8_t hash[32], FILE* src, FILE* dst); #ifdef __cplusplus diff --git a/src/media_delivery/file_transfer.h b/src/media_delivery/file_transfer.h index 2e520cbe..3c25d1ec 100644 --- a/src/media_delivery/file_transfer.h +++ b/src/media_delivery/file_transfer.h @@ -3,7 +3,11 @@ * и возвращает путь; получатель проверяет содержимое в своём done. * Каждая операция владеет CM handle до завершения/отмены, включая DOWN/TIMEOUT. * Все API/callbacks в uasync; destroy вызывается вне callbacks, до удаления групп. - * Файл назначения принадлежит вызывающему; при ошибке его нужно отбросить. + * До 16 входящих/исходящих операций суммарно. DATA до 8192 байт; router-пакеты подписаны, + * uint64 wire-поля имеют native byte order. Простой 30с завершает операцию ошибкой; + * при восстановлении пути/простое приём повторяет REQUEST с непрерывного полученного offset. + * Собственное временное назначение передаёт вызывающий: файл открывается с усечением, + * в том числе до возможного отказа запуска. При ошибке/cancel файл не удаляется и отбрасывается caller. */ #ifndef FILE_TRANSFER_H #define FILE_TRANSFER_H @@ -15,21 +19,33 @@ struct UTUN_INSTANCE; struct file_transfer; struct file_transfer_op; +/* Вызывается для каждого REQUEST, включая повторы: проверить права group/peer/object/size. + * 0 — записан NUL-терминированный путь (