/* * dm_crypto.c — криптография прямого чата (DM) */ #include "dm_crypto.h" #include "../../lib/debug_config.h" #define OPENSSL_API_COMPAT 0x10100000L #include #include #include #include #define DM_ID "dm_crypto" /* Медиа использует тот же ключ target, но отдельное пространство nonce. */ uint64_t dm_derive_conv_id(uint64_t a, uint64_t b) { uint64_t lo = a < b ? a : b; uint64_t hi = a < b ? b : a; SHA256_CTX ctx; uint8_t hash[32]; SHA256_Init(&ctx); SHA256_Update(&ctx, "utun_dm_v1", 9); SHA256_Update(&ctx, &lo, 8); SHA256_Update(&ctx, &hi, 8); SHA256_Final(hash, &ctx); uint64_t id; memcpy(&id, hash, 8); id &= 0x7FFFFFFFFFFFFFFFULL; if (id == 0) id = 1; return id; } int dm_derive_content_key(const uint8_t my_priv[32], const uint8_t peer_pub[32], uint8_t out[DM_CONTENT_KEY_SIZE]) { if (!my_priv || !peer_pub || !out) return -1; EVP_PKEY* my_pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, my_priv, 32); if (!my_pkey) { DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: EVP_PKEY_new_raw_private_key failed", DM_ID); return -1; } EVP_PKEY* peer_pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL, peer_pub, 32); if (!peer_pkey) { EVP_PKEY_free(my_pkey); DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: EVP_PKEY_new_raw_public_key failed", DM_ID); return -1; } EVP_PKEY_CTX* dctx = EVP_PKEY_CTX_new(my_pkey, NULL); uint8_t shared[32]; size_t shared_len = sizeof(shared); int rc = -1; if (!dctx) goto out; if (EVP_PKEY_derive_init(dctx) <= 0) goto out; if (EVP_PKEY_derive_set_peer(dctx, peer_pkey) <= 0) goto out; if (EVP_PKEY_derive(dctx, shared, &shared_len) <= 0 || shared_len != sizeof(shared)) goto out; SHA256_CTX sctx; SHA256_Init(&sctx); SHA256_Update(&sctx, shared, sizeof(shared)); SHA256_Update(&sctx, "utun_dm_content", 15); SHA256_Final(out, &sctx); rc = 0; out: if (dctx) EVP_PKEY_CTX_free(dctx); EVP_PKEY_free(my_pkey); EVP_PKEY_free(peer_pkey); if (rc != 0) DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: X25519 derive failed", DM_ID); return rc; } void dm_build_nonce(uint64_t conv_id, uint64_t author, uint64_t seq, uint8_t nonce[DM_NONCE_SIZE]) { SHA256_CTX ctx; uint8_t hash[32]; SHA256_Init(&ctx); SHA256_Update(&ctx, &conv_id, 8); SHA256_Update(&ctx, &author, 8); SHA256_Update(&ctx, &seq, 8); SHA256_Final(hash, &ctx); memcpy(nonce, hash, DM_NONCE_SIZE); }