Fix NIP-59 dynamic buffer sizing for NIP-17 gift wraps
This commit is contained in:
+86
-8
@@ -41,6 +41,39 @@ static time_t random_past_timestamp(long max_delay_sec) {
|
||||
return now - random_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* NIP-44 padding calculation (mirrors nip044.c for output sizing)
|
||||
*/
|
||||
static size_t calc_nip44_padded_len(size_t unpadded_len) {
|
||||
if (unpadded_len <= 32) {
|
||||
return 32;
|
||||
}
|
||||
|
||||
size_t next_power = 1;
|
||||
while (next_power < unpadded_len) {
|
||||
next_power <<= 1;
|
||||
}
|
||||
|
||||
size_t chunk = (next_power <= 256) ? 32 : (next_power / 8);
|
||||
return chunk * ((unpadded_len - 1) / chunk + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate safe output buffer size for NIP-44 encrypted base64 payload.
|
||||
* Returns 0 if plaintext length exceeds NIP-44 max.
|
||||
*/
|
||||
static size_t calc_nip44_encrypted_b64_size(size_t plaintext_len) {
|
||||
if (plaintext_len > NOSTR_NIP44_MAX_PLAINTEXT_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t padded_len = calc_nip44_padded_len(plaintext_len) + 2; // +2 for length prefix
|
||||
size_t payload_len = 1 + 32 + padded_len + 32; // version + nonce + ciphertext + mac
|
||||
size_t b64_len = ((payload_len + 2) / 3) * 4 + 1; // +1 for NUL terminator
|
||||
|
||||
return b64_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random private key for gift wrap
|
||||
*/
|
||||
@@ -160,18 +193,31 @@ cJSON* nostr_nip59_create_seal(cJSON* rumor, const unsigned char* sender_private
|
||||
}
|
||||
|
||||
// Encrypt the rumor using NIP-44
|
||||
char encrypted_content[4096]; // Should be large enough for most events
|
||||
size_t encrypted_size = calc_nip44_encrypted_b64_size(strlen(rumor_json));
|
||||
if (encrypted_size == 0) {
|
||||
free(rumor_json);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* encrypted_content = malloc(encrypted_size);
|
||||
if (!encrypted_content) {
|
||||
free(rumor_json);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int encrypt_result = nostr_nip44_encrypt(sender_private_key, recipient_public_key,
|
||||
rumor_json, encrypted_content, sizeof(encrypted_content));
|
||||
rumor_json, encrypted_content, encrypted_size);
|
||||
free(rumor_json);
|
||||
|
||||
if (encrypt_result != NOSTR_SUCCESS) {
|
||||
free(encrypted_content);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get sender's public key
|
||||
unsigned char sender_public_key[32];
|
||||
if (nostr_ec_public_key_from_private_key(sender_private_key, sender_public_key) != 0) {
|
||||
free(encrypted_content);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -181,6 +227,7 @@ cJSON* nostr_nip59_create_seal(cJSON* rumor, const unsigned char* sender_private
|
||||
// Create seal event (kind 13)
|
||||
cJSON* seal = cJSON_CreateObject();
|
||||
if (!seal) {
|
||||
free(encrypted_content);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -191,6 +238,7 @@ cJSON* nostr_nip59_create_seal(cJSON* rumor, const unsigned char* sender_private
|
||||
cJSON_AddNumberToObject(seal, "kind", 13);
|
||||
cJSON_AddItemToObject(seal, "tags", cJSON_CreateArray()); // Empty tags array
|
||||
cJSON_AddStringToObject(seal, "content", encrypted_content);
|
||||
free(encrypted_content);
|
||||
|
||||
// Calculate event ID
|
||||
char event_id[65];
|
||||
@@ -261,13 +309,27 @@ cJSON* nostr_nip59_create_gift_wrap(cJSON* seal, const char* recipient_public_ke
|
||||
}
|
||||
|
||||
// Encrypt the seal using NIP-44
|
||||
char encrypted_content[8192]; // Larger buffer for nested encryption
|
||||
size_t encrypted_size = calc_nip44_encrypted_b64_size(strlen(seal_json));
|
||||
if (encrypted_size == 0) {
|
||||
memory_clear(random_private_key, 32);
|
||||
free(seal_json);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* encrypted_content = malloc(encrypted_size);
|
||||
if (!encrypted_content) {
|
||||
memory_clear(random_private_key, 32);
|
||||
free(seal_json);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int encrypt_result = nostr_nip44_encrypt(random_private_key, recipient_public_key,
|
||||
seal_json, encrypted_content, sizeof(encrypted_content));
|
||||
seal_json, encrypted_content, encrypted_size);
|
||||
free(seal_json);
|
||||
|
||||
if (encrypt_result != NOSTR_SUCCESS) {
|
||||
memory_clear(random_private_key, 32);
|
||||
free(encrypted_content);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -275,6 +337,7 @@ cJSON* nostr_nip59_create_gift_wrap(cJSON* seal, const char* recipient_public_ke
|
||||
cJSON* gift_wrap = cJSON_CreateObject();
|
||||
if (!gift_wrap) {
|
||||
memory_clear(random_private_key, 32);
|
||||
free(encrypted_content);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -293,6 +356,7 @@ cJSON* nostr_nip59_create_gift_wrap(cJSON* seal, const char* recipient_public_ke
|
||||
cJSON_AddItemToObject(gift_wrap, "tags", tags);
|
||||
|
||||
cJSON_AddStringToObject(gift_wrap, "content", encrypted_content);
|
||||
free(encrypted_content);
|
||||
|
||||
// Calculate event ID
|
||||
char event_id[65];
|
||||
@@ -359,16 +423,23 @@ cJSON* nostr_nip59_unwrap_gift(cJSON* gift_wrap, const unsigned char* recipient_
|
||||
}
|
||||
|
||||
// Decrypt the content using NIP-44
|
||||
char decrypted_json[8192];
|
||||
size_t decrypted_size = strlen(encrypted_content) + 1;
|
||||
char* decrypted_json = malloc(decrypted_size);
|
||||
if (!decrypted_json) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int decrypt_result = nostr_nip44_decrypt(recipient_private_key, sender_public_key,
|
||||
encrypted_content, decrypted_json, sizeof(decrypted_json));
|
||||
encrypted_content, decrypted_json, decrypted_size);
|
||||
|
||||
if (decrypt_result != NOSTR_SUCCESS) {
|
||||
free(decrypted_json);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Parse the decrypted JSON as the seal event
|
||||
cJSON* seal = cJSON_Parse(decrypted_json);
|
||||
free(decrypted_json);
|
||||
if (!seal) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -394,16 +465,23 @@ cJSON* nostr_nip59_unseal_rumor(cJSON* seal, const unsigned char* sender_public_
|
||||
const char* encrypted_content = cJSON_GetStringValue(content_item);
|
||||
|
||||
// Decrypt the content using NIP-44
|
||||
char decrypted_json[4096];
|
||||
size_t decrypted_size = strlen(encrypted_content) + 1;
|
||||
char* decrypted_json = malloc(decrypted_size);
|
||||
if (!decrypted_json) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int decrypt_result = nostr_nip44_decrypt(recipient_private_key, sender_public_key,
|
||||
encrypted_content, decrypted_json, sizeof(decrypted_json));
|
||||
encrypted_content, decrypted_json, decrypted_size);
|
||||
|
||||
if (decrypt_result != NOSTR_SUCCESS) {
|
||||
free(decrypted_json);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Parse the decrypted JSON as the rumor event
|
||||
cJSON* rumor = cJSON_Parse(decrypted_json);
|
||||
free(decrypted_json);
|
||||
if (!rumor) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
#define NOSTR_CORE_H
|
||||
|
||||
// Version information (auto-updated by increment_and_push.sh)
|
||||
#define VERSION "v0.5.15"
|
||||
#define VERSION "v0.5.16"
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 5
|
||||
#define VERSION_PATCH 15
|
||||
#define VERSION_PATCH 16
|
||||
|
||||
/*
|
||||
* NOSTR Core Library - Complete API Reference
|
||||
|
||||
Reference in New Issue
Block a user