|
|
|
@ -5,7 +5,7 @@ |
|
|
|
* - conv_id и content_key детерминированно выводятся обеими сторонами |
|
|
|
* - conv_id и content_key детерминированно выводятся обеими сторонами |
|
|
|
* из своих ключей и pubkey пира (см. dm_crypto.h) — без переговоров. |
|
|
|
* из своих ключей и pubkey пира (см. dm_crypto.h) — без переговоров. |
|
|
|
* - сообщения идут через etcp_router (прямое соединение или релей), |
|
|
|
* - сообщения идут через etcp_router (прямое соединение или релей), |
|
|
|
* при недоступности пира — через dm_mailbox (storage-узлы). |
|
|
|
* при недоступности пира — через dm_mailbox (суперузлы). |
|
|
|
* - содержимое шифруется E2E (AES-256-CCM), запись подписывается Ed25519. |
|
|
|
* - содержимое шифруется E2E (AES-256-CCM), запись подписывается Ed25519. |
|
|
|
* |
|
|
|
* |
|
|
|
* Два независимых направленных потока (я→пир и пир→я) с монотонным seq. |
|
|
|
* Два независимых направленных потока (я→пир и пир→я) с монотонным seq. |
|
|
|
@ -29,21 +29,38 @@ extern "C" { |
|
|
|
* data_enc — AES-256-CCM (шифротекст + tag), sig — Ed25519 автора по всем полям до sig. */ |
|
|
|
* data_enc — AES-256-CCM (шифротекст + tag), sig — Ed25519 автора по всем полям до sig. */ |
|
|
|
#define DM_MSG_FIXED_HDR 33 /* conv_id+seq+ts+author(32) + ct_len(1) — до ct */ |
|
|
|
#define DM_MSG_FIXED_HDR 33 /* conv_id+seq+ts+author(32) + ct_len(1) — до ct */ |
|
|
|
#define DM_MSG_SIG_SIZE 64 |
|
|
|
#define DM_MSG_SIG_SIZE 64 |
|
|
|
|
|
|
|
#define DM_DATA_MAX 1024 |
|
|
|
|
|
|
|
#define DM_RECEIPT_SIZE 136 |
|
|
|
|
|
|
|
|
|
|
|
/* Вычислить полную длину канонического тела из его заголовка.
|
|
|
|
/* Вычислить полную длину канонического тела из его заголовка.
|
|
|
|
* Возвращает 1 и *out_len, либо 0 если буфер мал/повреждён. */ |
|
|
|
* Возвращает 1 и *out_len, либо 0 если буфер мал/повреждён. */ |
|
|
|
static inline int dm_msg_len(const uint8_t* msg, size_t avail, size_t* out_len) { |
|
|
|
static inline int dm_msg_len(const uint8_t* msg, size_t avail, size_t* out_len) { |
|
|
|
if (!msg || avail < DM_MSG_FIXED_HDR) return 0; |
|
|
|
if (!msg || !out_len || avail < DM_MSG_FIXED_HDR) return 0; |
|
|
|
uint8_t ct_len = msg[32]; |
|
|
|
uint8_t ct_len = msg[32]; |
|
|
|
if (avail < (size_t)DM_MSG_FIXED_HDR + ct_len + 2) return 0; |
|
|
|
if (avail < (size_t)DM_MSG_FIXED_HDR + ct_len + 2) return 0; |
|
|
|
uint16_t data_len; |
|
|
|
uint16_t data_len; |
|
|
|
memcpy(&data_len, msg + DM_MSG_FIXED_HDR + ct_len, 2); |
|
|
|
memcpy(&data_len, msg + DM_MSG_FIXED_HDR + ct_len, 2); |
|
|
|
|
|
|
|
if (data_len < 16 || data_len > DM_DATA_MAX + 16) return 0; |
|
|
|
size_t total = (size_t)DM_MSG_FIXED_HDR + ct_len + 2 + data_len + DM_MSG_SIG_SIZE; |
|
|
|
size_t total = (size_t)DM_MSG_FIXED_HDR + ct_len + 2 + data_len + DM_MSG_SIG_SIZE; |
|
|
|
if (avail < total) return 0; |
|
|
|
if (avail < total) return 0; |
|
|
|
*out_len = total; |
|
|
|
*out_len = total; |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Общие операции протокола DM; все вызовы в uasync-потоке.
|
|
|
|
|
|
|
|
* group_id — только область маршрутизации, идентичность беседы от неё не зависит. |
|
|
|
|
|
|
|
* route_group выбирает общую группу с живым путём, возвращает 1/0. |
|
|
|
|
|
|
|
* verify_message проверяет каноническое тело и подпись автора для recipient. |
|
|
|
|
|
|
|
* accept_message возвращает 0 только после commit (включая точный повтор). |
|
|
|
|
|
|
|
* Квитанция: ["DMACK001":8][conv:8][seq:8][author:8][recipient:8][SHA256(msg):32][sig:64]. |
|
|
|
|
|
|
|
* verify_receipt проверяет подпись получателя и при msg!=NULL точное соответствие телу. |
|
|
|
|
|
|
|
* accept_receipt удаляет только соответствующее исходящее pending-сообщение. */ |
|
|
|
|
|
|
|
int dm_route_group(struct UTUN_INSTANCE* inst, uint64_t peer, uint64_t preferred, uint64_t* group_id); |
|
|
|
|
|
|
|
int dm_verify_message(struct UTUN_INSTANCE* inst, uint64_t recipient, const uint8_t* msg, size_t len); |
|
|
|
|
|
|
|
int dm_accept_message(struct UTUN_INSTANCE* inst, const uint8_t* msg, size_t len, uint8_t receipt[DM_RECEIPT_SIZE]); |
|
|
|
|
|
|
|
int dm_verify_receipt(struct UTUN_INSTANCE* inst, const uint8_t receipt[DM_RECEIPT_SIZE], const uint8_t* msg, size_t len); |
|
|
|
|
|
|
|
int dm_accept_receipt(struct UTUN_INSTANCE* inst, const uint8_t receipt[DM_RECEIPT_SIZE]); |
|
|
|
|
|
|
|
|
|
|
|
/* Жизненный цикл: инициализация после chat_core_init, destroy перед chat_core_destroy. */ |
|
|
|
/* Жизненный цикл: инициализация после chat_core_init, destroy перед chat_core_destroy. */ |
|
|
|
int dm_core_init(struct UTUN_INSTANCE* inst); |
|
|
|
int dm_core_init(struct UTUN_INSTANCE* inst); |
|
|
|
void dm_core_destroy(struct UTUN_INSTANCE* inst); |
|
|
|
void dm_core_destroy(struct UTUN_INSTANCE* inst); |
|
|
|
|