Prerequisiti per la costruzione di un protocollo di comunicazione sicuro in C

Prima di immergersi in implementazione, assicurarsi che l'ambiente di sviluppo include un compilatore C (GCC o Clang), la conoscenza di base della programmazione socket, e la libreria OpenSSL installato. OpenSSL fornisce implementazioni robuste di algoritmi crittografici, rendendolo la scelta standard per le comunicazioni sicure in C. Su Linux, installare OpenSSL tramite il vostro gestore di pacchetti (ad esempio, ).

Comprendere i blocchi di costruzione crittografica

Un protocollo di comunicazione sicuro si basa su tre pilastri: riservatezza, integrità e autenticazione. La riservatezza è raggiunta attraverso la crittografia, assicurando che solo il destinatario interessato possa leggere il messaggio. L'integrità assicura che i dati non siano stati modificati in transito. L'autenticazione verifica le identità delle parti comunicanti. In un protocollo personalizzato, in genere si combina la crittografia simmetrica, hashing con i codici di autenticazione dei messaggi (HMAC) e un meccanismo di scambio chiave come Diffie.

Crittografia simmetrica con AES

Il codice di crittografia avanzato (AES) è il cifrario simmetrico più utilizzato. Funziona su blocchi a 128 bit e supporta le dimensioni chiave di 128, 192, o 256 bit. Per comunicazioni sicure, preferiscono AES in Galois/Counter Mode (GCM), che fornisce sia la riservatezza e l'integrità in un'unica operazione.

Scambio di chiavi con Diffie–Hellman

Per concordare in modo sicuro su un segreto condiviso su un canale non garantito, utilizzare lo scambio di chiavi Diffie-Hellman (DH) . Entrambe le parti generano chiavi private e scambiano i parametri pubblici, quindi calcolare un segreto comune. Diffie–Hellman] è vulnerabile agli attacchi uomo-in-the-middle se non autenticati, in modo da poter utilizzare in seguito con le chiavi di produzione digitali-shared.

Integrità e autenticità del messaggio con HMAC

Per verificare che un messaggio non sia stato manomesso, applica un codice di autenticazione dei messaggi basato su Hash (HMAC) a ciascun testo cifrato. HMAC utilizza una chiave segreta condivisa e una funzione di hash crittografico (ad esempio SHA‐256). Il ricevitore ricomprende l'HMAC sui dati ricevuti e lo confronta con il valore trasmesso.

Impostazione di OpenSSL nel tuo progetto C

OpenSSL richiede un'attenta inizializzazione. Includi le intestazioni necessarie e chiama [ e all'inizio del tuo programma. Per la gestione degli errori, usa e ]]. Quando si collega, aggiungi alle tue bandiere compilatrici.

#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/err.h>
// Initialize OpenSSL
void init_openssl() {
 SSL_load_error_strings();
 OpenSSL_add_all_algorithms();
}

Costruire il livello TCP Socket

Il trasporto sottostante per il vostro protocollo sarà TCP, che fornisce la consegna affidabile e ordinata. Creare un server che ascolta le connessioni in entrata e un client che avvia il handshake. Utilizzare le prese POSIX standard con , , , ]]] sul lato server e file di grazia [

Esempio di server Skeleton

int server_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);
bind(server_fd, (struct sockaddr*)&address, sizeof(address));
listen(server_fd, 3);
int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &addr_len);

Esempio cliente Skeleton

int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);
connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));

Attuazione della Scambio di chiavi Diffie-Hellman

Dopo aver stabilito la connessione TCP, il client e il server effettuano uno scambio di chiavi DH. Ogni lato genera una coppia di tasti DH utilizzando l'API di OpenSSL. La chiave pubblica viene inviata sopra la presa, e entrambi i lati derivano un segreto condiviso usando . Per semplicità, utilizzare un gruppo di primo fisso (ad esempio, [[FLT-17]] con parametri definiti da [[FLT reale negoziato gruppo]).

// Generate DH parameters
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DH, NULL);
EVP_PKEY_paramgen_init(pctx);
EVP_PKEY_CTX_set_dh_paramgen_prime_len(pctx, 2048);
EVP_PKEY *params = NULL;
EVP_PKEY_paramgen(pctx, &params);

// Generate key pair
EVP_PKEY_CTX *kctx = EVP_PKEY_CTX_new(params, NULL);
EVP_PKEY_keygen_init(kctx);
EVP_PKEY *my_key = NULL;
EVP_PKEY_keygen(kctx, &my_key);

// Export public key to send
unsigned char *pub_key_der = NULL;
int pub_len = i2d_PUBKEY(my_key, &pub_key_der);
send(sock, pub_key_der, pub_len, 0);

Alla fine del ricevimento, il coetaneo importa la chiave pubblica usando [] e poi deriva il segreto condiviso. Il segreto derivato può essere schiacciato (ad esempio, con SHA‐256) per produrre una chiave uniforme per AES e HMAC.

Crittografia e Decrittografia dei messaggi con AES‐GCM

AES‐GCM è la modalità preferita perché fornisce sia la crittografia che un tag di autenticazione in una sola operazione. Usate il tasto OpenSSL con . Avete bisogno di un nonce da 12 byte (IV) e il tasto a 256 bit derivato dal segreto condiviso DH. Il testo cifrario è prodotto in blocchi, e dopo l'aggiornamento finale, si recupera il tag 16 byte.

// Encryption
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, key, nonce);
unsigned char ciphertext[1024];
int outlen;
EVP_EncryptUpdate(ctx, ciphertext, &outlen, plaintext, len);
int tmplen;
EVP_EncryptFinal_ex(ctx, ciphertext + outlen, &tmplen);
unsigned char tag[16];
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag);

Aggiungere l'integrità con HMAC (o Leveraging GCM Tag)

Se si opta per non utilizzare AES‐GCM, è possibile crittografare con AES‐CBC e quindi calcolare un HMAC sul testo cifrario. Utilizzare [ da OpenSSL con SHA‐256. Appendere l'HMAC dopo il testo cifrato. Il ricevitore ricalcola e confronta. Questo approccio richiede due chiavi: una per la crittografia, una per la funzione HMAC.

Metterlo insieme: Flusso di lavoro completo

  1. Stabilire una connessione TCP tra client e server.
  2. Entrambi i lati generano coppie chiave effimere Diffie-Hellman.
  3. Scambiare le chiavi pubbliche e calcolare il segreto condiviso.
  4. Dedicare una chiave AES a 256 bit e una chiave HMAC a 256 bit (o utilizzare la stessa chiave per GCM).
  5. Il client invia un nonce (12 byte casuali) e poi il messaggio crittografato AES‐GCM più tag.
  6. Server invia una risposta utilizzando un nuovo nonce (mai riutilizzare le nonze con la stessa chiave).
  7. Entrambi i lati possono continuare a scambiare messaggi; per lunghe sessioni, richiamare periodicamente utilizzando lo stesso handshake DH o un meccanismo di cricchetto.

Migliori Pratiche di Sicurezza

  • Utilizzare forti generatori di numeri casuali.] Chiama [ da OpenSSL per generare chiavi, nonces e chiavi private DH. Non usare mai o ] per scopi crittografici.
  • Validare tutti i dati ricevuti.[ Controllare le lunghezze, i parametri chiave pubblici (ad esempio, assicurarsi che p sia primo, g è un generatore), e tag HMAC prima dell'elaborazione.
  • Avoid chiavi o default in codice duro[] Negozia sempre le chiavi fresche per sessione per fornire una perfetta segretezza in avanti.
  • Handle errori con grazia.[] Se la decrittazione non riesce o la verifica HMAC fallisce, chiudi la connessione e registri l'evento.
  • Aggiungi le dipendenze aggiornate.[] Aggiornare regolarmente OpenSSL per patchare le vulnerabilità note. [ La documentazione OpenSSL[[]] fornisce una guida sulla deprecazione e sulle migliori pratiche.
  • Consider usando TLS piuttosto che un protocollo personalizzato. Per i sistemi di produzione, si affida a protocolli ben testati come TLS 1.3. La costruzione di un protocollo personalizzato da zero è di errore-prone e non è raccomandato a meno che non si dispone di profonda esperienza crittografica.

Testare il protocollo

Prova la tua implementazione eseguendo client e server sulla stessa macchina (localhost) e verificando che i messaggi decidano correttamente. Introdurre errori come il codice manomesso o le nonze non valide per garantire che il protocollo li rifiuti. Utilizza strumenti come Wireshark per ispezionare il traffico di rete grezzo e confermare che il testo normale non è visibile.

Conclusioni

Costruire un protocollo di comunicazione sicuro in C è un eccellente esercizio di apprendimento, ma richiede una meticolosa attenzione ai dettagli. Sfruttando le implementazioni provate di OpenSSL di Diffie‐Hellman, AES‐GCM e HMAC, è possibile creare un sistema che fornisce riservatezza, integrità e autenticazione.