/* * Test program for key generation * Standalone version that doesn't require FastCGI */ #include #include #include #include #include "../nostr_core_lib/nostr_core/nostr_common.h" #include "../nostr_core_lib/nostr_core/utils.h" // Forward declarations int generate_random_private_key_bytes(unsigned char *key_bytes, size_t len); int generate_server_keypair(const char *db_path); int store_blossom_private_key(const char *db_path, const char *seckey); // Generate random private key bytes using /dev/urandom int generate_random_private_key_bytes(unsigned char *key_bytes, size_t len) { FILE *fp = fopen("/dev/urandom", "rb"); if (!fp) { fprintf(stderr, "ERROR: Cannot open /dev/urandom for key generation\n"); return -1; } size_t bytes_read = fread(key_bytes, 1, len, fp); fclose(fp); if (bytes_read != len) { fprintf(stderr, "ERROR: Failed to read %zu bytes from /dev/urandom\n", len); return -1; } return 0; } // Store blossom private key in dedicated table int store_blossom_private_key(const char *db_path, const char *seckey) { sqlite3 *db; sqlite3_stmt *stmt; int rc; // Validate key format if (!seckey || strlen(seckey) != 64) { fprintf(stderr, "ERROR: Invalid blossom private key format\n"); return -1; } // Create blossom_seckey table if it doesn't exist rc = sqlite3_open_v2(db_path, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL); if (rc) { fprintf(stderr, "ERROR: Can't open database: %s\n", sqlite3_errmsg(db)); return -1; } // Create table const char *create_sql = "CREATE TABLE IF NOT EXISTS blossom_seckey (id INTEGER PRIMARY KEY CHECK (id = 1), seckey TEXT NOT NULL, created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')), CHECK (length(seckey) = 64))"; rc = sqlite3_exec(db, create_sql, NULL, NULL, NULL); if (rc != SQLITE_OK) { fprintf(stderr, "ERROR: Failed to create blossom_seckey table: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return -1; } // Store key const char *sql = "INSERT OR REPLACE INTO blossom_seckey (id, seckey) VALUES (1, ?)"; rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); if (rc != SQLITE_OK) { fprintf(stderr, "ERROR: SQL prepare failed: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return -1; } sqlite3_bind_text(stmt, 1, seckey, -1, SQLITE_STATIC); rc = sqlite3_step(stmt); sqlite3_finalize(stmt); sqlite3_close(db); if (rc != SQLITE_DONE) { fprintf(stderr, "ERROR: Failed to store blossom private key\n"); return -1; } return 0; } // Generate server keypair and store in database int generate_server_keypair(const char *db_path) { printf("Generating server keypair...\n"); unsigned char seckey_bytes[32]; char seckey_hex[65]; char pubkey_hex[65]; // Generate random private key printf("Generating random private key...\n"); if (generate_random_private_key_bytes(seckey_bytes, 32) != 0) { fprintf(stderr, "Failed to generate random bytes\n"); return -1; } // Validate the private key if (nostr_ec_private_key_verify(seckey_bytes) != NOSTR_SUCCESS) { fprintf(stderr, "ERROR: Generated invalid private key\n"); return -1; } // Convert to hex nostr_bytes_to_hex(seckey_bytes, 32, seckey_hex); // Derive public key unsigned char pubkey_bytes[32]; if (nostr_ec_public_key_from_private_key(seckey_bytes, pubkey_bytes) != NOSTR_SUCCESS) { fprintf(stderr, "ERROR: Failed to derive public key\n"); return -1; } // Convert public key to hex nostr_bytes_to_hex(pubkey_bytes, 32, pubkey_hex); // Store private key securely if (store_blossom_private_key(db_path, seckey_hex) != 0) { fprintf(stderr, "ERROR: Failed to store blossom private key\n"); return -1; } // Store public key in config sqlite3 *db; sqlite3_stmt *stmt; int rc; rc = sqlite3_open_v2(db_path, &db, SQLITE_OPEN_READWRITE, NULL); if (rc) { fprintf(stderr, "ERROR: Can't open database for config: %s\n", sqlite3_errmsg(db)); return -1; } const char *sql = "INSERT OR REPLACE INTO config (key, value, description) VALUES (?, ?, ?)"; rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); if (rc != SQLITE_OK) { fprintf(stderr, "ERROR: SQL prepare failed: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return -1; } sqlite3_bind_text(stmt, 1, "blossom_pubkey", -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, pubkey_hex, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 3, "Blossom server's public key for Nostr communication", -1, SQLITE_STATIC); rc = sqlite3_step(stmt); sqlite3_finalize(stmt); sqlite3_close(db); if (rc != SQLITE_DONE) { fprintf(stderr, "ERROR: Failed to store blossom public key in config\n"); return -1; } // Display keys for admin setup printf("========================================\n"); printf("SERVER KEYPAIR GENERATED SUCCESSFULLY\n"); printf("========================================\n"); printf("Blossom Public Key: %s\n", pubkey_hex); printf("Blossom Private Key: %s\n", seckey_hex); printf("========================================\n"); printf("IMPORTANT: Save the private key securely!\n"); printf("This key is used for decrypting admin messages.\n"); printf("========================================\n"); return 0; } int main(int argc, char *argv[]) { const char *db_path = "db/ginxsom.db"; if (argc > 1) { db_path = argv[1]; } printf("Test Key Generation\n"); printf("===================\n"); printf("Database: %s\n\n", db_path); // Initialize nostr crypto printf("Initializing nostr crypto system...\n"); if (nostr_crypto_init() != NOSTR_SUCCESS) { fprintf(stderr, "FATAL: Failed to initialize nostr crypto\n"); return 1; } printf("Crypto system initialized\n\n"); // Generate keypair if (generate_server_keypair(db_path) != 0) { fprintf(stderr, "FATAL: Key generation failed\n"); return 1; } printf("\nKey generation test completed successfully!\n"); return 0; }