6#include <ascii-chat/discovery/identity.h>
7#include <ascii-chat/crypto/crypto.h>
8#include <ascii-chat/log/logging.h>
9#include <ascii-chat/platform/abstraction.h>
10#include <ascii-chat/platform/filesystem.h>
11#include <ascii-chat/platform/util.h>
19 if (!public_key || !secret_key) {
20 return SET_ERRNO(ERROR_INVALID_PARAM,
"public_key and secret_key cannot be NULL");
24 if (crypto_sign_keypair(public_key, secret_key) != 0) {
25 return SET_ERRNO(ERROR_CRYPTO,
"Failed to generate Ed25519 keypair");
28 log_debug(
"Generated new Ed25519 identity keypair");
32asciichat_error_t
acds_identity_load(
const char *path, uint8_t public_key[32], uint8_t secret_key[64]) {
33 if (!path || !public_key || !secret_key) {
34 return SET_ERRNO(ERROR_INVALID_PARAM,
"path, public_key, and secret_key cannot be NULL");
40 if (errno == ENOENT) {
41 return SET_ERRNO(ERROR_CONFIG,
"Identity file does not exist: %s", path);
43 return SET_ERRNO_SYS(ERROR_CONFIG,
"Failed to open identity file: %s", path);
47 size_t read = fread(secret_key, 1, 64, fp);
50 return SET_ERRNO(ERROR_CONFIG,
"Identity file corrupted (expected 64 bytes, got %zu): %s", read, path);
54 memcpy(public_key, secret_key + 32, 32);
57 log_info(
"Loaded identity from %s", path);
61asciichat_error_t
acds_identity_save(
const char *path,
const uint8_t public_key[32],
const uint8_t secret_key[64]) {
62 if (!path || !public_key || !secret_key) {
63 return SET_ERRNO(ERROR_INVALID_PARAM,
"path, public_key, and secret_key cannot be NULL");
68 SAFE_STRNCPY(dir_path, path,
sizeof(dir_path));
71 char *last_sep = strrchr(dir_path,
'/');
73 last_sep = strrchr(dir_path,
'\\');
81 if (result != ASCIICHAT_OK) {
87 int fd =
platform_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
89 return SET_ERRNO_SYS(ERROR_CONFIG,
"Failed to create identity file: %s", path);
93 ssize_t written = write(fd, secret_key, 64);
97 return SET_ERRNO(ERROR_CONFIG,
"Failed to write identity file (wrote %zd/64 bytes): %s", written, path);
100 log_info(
"Saved identity to %s", path);
105 if (!public_key || !fingerprint) {
106 log_error(
"acds_identity_fingerprint: NULL parameters");
112 crypto_hash_sha256(hash, public_key, 32);
115 for (
int i = 0; i < 32; i++) {
118 fingerprint[64] =
'\0';
122 if (!path_out || path_size == 0) {
123 return SET_ERRNO(ERROR_INVALID_PARAM,
"path_out cannot be NULL and path_size must be > 0");
129 return SET_ERRNO(ERROR_CONFIG,
"Failed to get config directory");
133 int written =
safe_snprintf(path_out, path_size,
"%sacds_identity", config_dir);
134 SAFE_FREE(config_dir);
136 if (written < 0 || (
size_t)written >= path_size) {
137 return SET_ERRNO(ERROR_CONFIG,
"Path buffer too small");
asciichat_error_t acds_identity_load(const char *path, uint8_t public_key[32], uint8_t secret_key[64])
asciichat_error_t acds_identity_default_path(char *path_out, size_t path_size)
asciichat_error_t acds_identity_save(const char *path, const uint8_t public_key[32], const uint8_t secret_key[64])
void acds_identity_fingerprint(const uint8_t public_key[32], char fingerprint[65])
asciichat_error_t acds_identity_generate(uint8_t public_key[32], uint8_t secret_key[64])
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.
#define PLATFORM_MAX_PATH_LENGTH
char * platform_get_config_dir(void)
FILE * platform_fopen(const char *filename, const char *mode)
asciichat_error_t platform_mkdir_recursive(const char *path, int mode)
int platform_open(const char *pathname, int flags,...)