Table of Contents
Προαπαιτούμενα για την οικοδόμηση ενός πρωτοκόλλου ασφαλούς επικοινωνίας σε Γ
Πριν από την κατάδυση στην υλοποίηση, εξασφαλίστε ότι το περιβάλλον ανάπτυξης σας περιλαμβάνει έναν μεταγλωττιστή C (GCC ή Clang), βασικές γνώσεις προγραμματισμού υποδοχής, και την εγκατεστημένη βιβλιοθήκη OpenSSL. Το OpenSSL παρέχει στιβαρές υλοποιήσεις κρυπτογραφικών αλγορίθμων, καθιστώντας το την την τυπική επιλογή για ασφαλείς επικοινωνίες σε C. On Linux, εγκαθιστά το OpenSSL μέσω του διαχειριστή πακέτων σας (π.χ., ).Στα Windows, χρησιμοποιήστε προσυνοδευμένα δυαδικά ή χτίστε από την πηγή.
Κατανόηση των Κρυπτογραφικών Κτιρίων
Ένα ασφαλές πρωτόκολλο επικοινωνίας στηρίζεται σε τρεις πυλώνες: εμπιστευτικότητα, ακεραιότητα και εξακρίβωση ταυτότητας. Εμπιστευτικότητα επιτυγχάνεται μέσω κρυπτογράφησης, εξασφαλίζοντας ότι μόνο ο αποδέκτης που προορίζεται μπορεί να διαβάσει το μήνυμα. Ακεραιότητα εξασφαλίζει ότι τα δεδομένα δεν έχουν τροποποιηθεί κατά τη διέλευση. Η ταυτοποίηση επαληθεύει τις ταυτότητες των μερών επικοινωνίας. Σε ένα προσαρμοσμένο πρωτόκολλο, συνήθως συνδυάζουν συμμετρική κρυπτογράφηση, hashing με κωδικούς ταυτοποίησης μηνυμάτων (HMAC), και ένα βασικό μηχανισμό ανταλλαγής, όπως Diffie ⁇ Hellman.
Συμμετρική κρυπτογράφηση με AES
Το Advanced Encryption Standard (AES) είναι ο πιο ευρέως χρησιμοποιούμενος συμμετρικός κρυπτογραφημένος κώδικας. Λειτουργεί σε μπλοκ 128 bit και υποστηρίζει βασικά μεγέθη 128, 192, ή 256 bit. Για ασφαλείς επικοινωνίες, προτιμάτε το AES σε λειτουργία Galois/Counter (GCM), το οποίο παρέχει τόσο εμπιστευτικότητα όσο και ακεραιότητα σε μια ενιαία λειτουργία. Η διεπαφή SVP του OpenSSL καθιστά απλή την κρυπτογράφηση και αποκρυπτογράφηση δεδομένων με AES ⁇ GCM. Αποφύγετε παλαιότερες λειτουργίες όπως η ΕΚΤ ή η CBC εκτός αν συνδυαστεί με προσεκτική πλήρωση και πιστοποίηση.
Ανταλλαγή κλειδιών με τον Diffie ⁇ Hellman
Για να συμφωνήσετε με ασφάλεια σε ένα κοινό μυστικό πάνω από ένα μη ασφαλές κανάλι, χρησιμοποιήστε το βασικό ανταλλακτικό Diffie ⁇ Hellman (DH). Και τα δύο μέρη δημιουργούν ιδιωτικά κλειδιά και ανταλλάσσουν δημόσιες παραμέτρους, και μετά υπολογίστε ένα κοινό μυστικό. Η Diffie ⁇ Hellman είναι ευάλωτη στον άνθρωπο ⁇ στις μεσαίες επιθέσεις αν δεν πιστοποιηθεί, οπότε μπορεί αργότερα να το επεκτείνετε αυτό με ψηφιακές υπογραφές ή προ-μεριζόμενα κλειδιά. Για χρήση στην παραγωγή, σκεφτείτε να χρησιμοποιήσετε την ephemeral Diffie ⁇ Hellman για να παράσχετε τέλεια προθεσμιακή μυστικότητα.
Ακεραιότητα και ταυτοποίηση μηνύματος με HMAC
Για να επαληθεύσετε ότι ένα μήνυμα δεν έχει παραποιηθεί, προσαρτήστε έναν κώδικα ταυτοποίησης μηνυμάτων με βάση το Hash (HMAC) σε κάθε κρυπτογραφημένο κείμενο κρυπτογράφησης. HMAC χρησιμοποιεί ένα κοινό μυστικό κλειδί και μια κρυπτογραφική λειτουργία hash (π.χ., SHA ⁇ 256). Ο δέκτης επαναπροσδιορίζει το HMAC στα δεδομένα που λαμβάνονται και το συγκρίνει με τη μεταδιδόμενη τιμή. Αυτό το βήμα αποτρέπει την επανάληψη και την παραποίηση επιθέσεων. Εναλλακτικά, το AES ⁇ GCM περιλαμβάνει μια ετικέτα ταυτοποίησης που εξυπηρετεί τον ίδιο σκοπό, απλοποιώντας το πρωτόκολλο.
⁇ OpenSSL στο C σας έργο
Το OpenSSL απαιτεί προσεκτική αρχικοποίηση. Συμπεριλάβετε τις απαραίτητες κεφαλίδες και καλέστε και στην αρχή του προγράμματος σας. Για χειρισμό σφαλμάτων, χρησιμοποιήστε και . Όταν συνδέεστε, προσθέστε στις σημαίες μεταγλωττιστή σας. Μια ελάχιστη ρύθμιση μοιάζει με αυτή:
#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();
}
Κατασκευή του στρώματος υποδοχής TCP
Η υποκείμενη μεταφορά για το πρωτόκολλό σας θα είναι η TCP, η οποία παρέχει αξιόπιστη, παραγγελία παράδοσης. Δημιουργήστε έναν εξυπηρετητή που ακούει για εισερχόμενες συνδέσεις και έναν πελάτη που ξεκινά τη χειραψία. Χρησιμοποιήστε τυπικές υποδοχές POSIX με , ], ], στην πλευρά του διακομιστή, και , στην πλευρά του πελάτη. Θυμηθείτε να χειρίζεστε λάθη με χάρη και στενή περιγραφή αρχείων μετά τη χρήση.
Παράδειγμα εξυπηρετητή 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);
Παράδειγμα πελάτη 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));
Εφαρμογή του Ανταλλάγματος Κλειδιού Ντίφι ⁇ Χέλμαν
Μετά την καθιέρωση της σύνδεσης TCP, ο πελάτης και ο διακομιστής εκτελούν μια ανταλλαγή κλειδιών DH. Κάθε πλευρά δημιουργεί ένα ζεύγος κλειδιών DH χρησιμοποιώντας το API του OpenSSL . Το δημόσιο κλειδί αποστέλλεται πάνω από την υποδοχή, και οι δύο πλευρές αντλούν ένα κοινό μυστικό χρησιμοποιώντας [[LFT:16]]]. Για απλότητα, χρησιμοποιήστε μια σταθερή αρχική ομάδα (π.χ., με παραμέτρους από [[LFT:18]]). Σε ένα πραγματικό πρωτόκολλο, θα διαπραγματευτείτε την ομάδα ή θα χρησιμοποιήσετε προκαθορισμένες παραμέτρους.
// 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, ¶ms);
// 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);
Στο τέλος της παραλαβής, ο ομότιμος εισάγει το δημόσιο κλειδί χρησιμοποιώντας [] και στη συνέχεια αντλεί το κοινό μυστικό. Το παράγωγο μυστικό μπορεί να διοχετευθεί (π.χ., με SHA ⁇ 256) για να παραχθεί ένα ενιαίο κλειδί για την AES και την HMAC.
Κρυπτογράφηση και αποκρυπτογράφηση μηνυμάτων με AES ⁇ GCM
AES ⁇ GCM είναι η προτιμώμενη λειτουργία, επειδή παρέχει τόσο κρυπτογράφηση και μια ετικέτα ταυτοποίησης σε μία λειτουργία. Χρησιμοποιήστε το κλειδί OpenSSL με . Χρειάζεστε ένα 12-byte nonnce (IV) και το 256-bit κλειδί που προέρχεται από το κοινό μυστικό DH. Το κρυπτοκείμενο παράγεται σε κομμάτια, και μετά την τελική ενημέρωση, ανακτάτε την ετικέτα 16-byte. Αποστολή του nonnce, κρυπτογραφημένο κείμενο, και ετικέτα μαζί. Ο δέκτης εκτελεί , ορίζει την ετικέτα και αποκρυπτογραφεί. Αν η επαλήθευση ετικέτας αποτύχει, το μήνυμα απορρίπτεται.
// 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);
Προσθήκη ακεραιότητας με HMAC (ή μόχλευση ετικέτας GCM)
Αν επιλέξετε να μην χρησιμοποιήσετε το AES ⁇ GCM, μπορείτε να κρυπτογραφήσετε με το AES ⁇ CBC και στη συνέχεια να υπολογίσετε ένα HMAC πάνω από το κείμενο κρυπτογράφησης. Χρησιμοποιήστε [[LPT:25]] από το OpenSSL με SHA ⁇ 256. Προσθήκη του HMAC μετά το κείμενο κρυπτογράφησης. Ο δέκτης επαναυπολογίζει και συγκρίνει. Αυτή η προσέγγιση απαιτεί δύο κλειδιά: ένα για κρυπτογράφηση, ένα για HMAC. Αποκομίζοντας και τα δύο από το κοινό μυστικό χρησιμοποιώντας μια βασική λειτουργία derivation (KDF) όπως το HKDF. Ωστόσο, το AES ⁇ GCM εξαλείφει την ανάγκη για ένα ξεχωριστό HMAC, μειώνοντας την πολυπλοκότητα και πιθανά λάθη.
Το να το βάλουμε μαζί: Πλήρης ροή εργασίας
- Καθιέρωση σύνδεσης TCP μεταξύ πελάτη και διακομιστή.
- Και οι δύο πλευρές παράγουν εφήμερο ζεύγος κλειδιών Diffie ⁇ Hellman.
- Ανταλλαγή δημόσιων κλειδιών και υπολογισμός του κοινού μυστικού.
- Παράγετε ένα κλειδί AES 256 ⁇ bit και ένα κλειδί HMAC 256 ⁇ bit (ή χρησιμοποιήστε το ίδιο κλειδί για GCM).
- Ο πελάτης στέλνει ένα nonnce (12 bytes τυχαία) και στη συνέχεια το κρυπτογραφημένο μήνυμα AES ⁇ GCM συν ετικέτα. Ο εξυπηρετητής αποκρυπτογραφεί και επαληθεύει.
- Ο εξυπηρετητής στέλνει μια απάντηση χρησιμοποιώντας ένα νέο nonnce (ποτέ μη επαναχρησιμοποίηση μη nonces με το ίδιο κλειδί).
- Και οι δύο πλευρές μπορούν να συνεχίσουν την ανταλλαγή μηνυμάτων· για μακρές συνεδρίες, επαναπλήρωσης περιοδικά χρησιμοποιώντας την ίδια χειραψία DH ή έναν μηχανισμό καστάνιας.
Βέλτιστες Πρακτικές Ασφάλειας
- Χρησιμοποιήστε ισχυρές γεννήτριες τυχαίων αριθμών. Καλέστε από το OpenSSL για να δημιουργήσετε κλειδιά, μη insecs, και DH ιδιωτικά πλήκτρα. Ποτέ μην χρησιμοποιείτε ή για κρυπτογραφικούς σκοπούς.
- Επιβεβαιώστε όλα τα δεδομένα που ελήφθησαν. Ελέγξτε τα μήκη, τις παραμέτρους δημόσιου κλειδιού (π.χ., βεβαιωθείτε ότι το p είναι πρώτο, το g είναι γεννήτρια), και τις ετικέτες HMAC πριν την επεξεργασία.
- Αποφύγετε τα σκληροκωδικοποιημένα κλειδιά ή τις προεπιλεγμένες ρυθμίσεις. Πάντα διαπραγματεύονται τα κλειδιά φρέσκα ανά συνεδρία για να παρέχουν τέλεια μυστικότητα προς τα εμπρός.
- Κρατήστε τα λάθη με χάρη. Αν η αποκρυπτογράφηση αποτύχει ή αποτύχει η επαλήθευση HMAC, κλείστε τη σύνδεση και συνδεθείτε το γεγονός. Μην αποκαλύψετε γιατί συνέβη η αποτυχία.
- Κρατήστε τις εξαρτήσεις ενημερωμένες. Τακτική ενημέρωση OpenSSL για να επισυνάψετε γνωστές ευπαθείς καταστάσεις. OpenSSL documentation παρέχει καθοδήγηση για την απαξίωση και τις βέλτιστες πρακτικές.
- Σκεφθείτε τη χρήση TLS και όχι προσαρμοσμένου πρωτοκόλλου. Για συστήματα παραγωγής, βασιστείτε σε καλά δοκιμασμένα πρωτόκολλα όπως TLS 1.3. Η κατασκευή ενός προσαρμοσμένου πρωτοκόλλου από το μηδέν είναι σφάλμα ⁇ επωφελές και δεν συνιστάται εκτός αν έχετε βαθιά κρυπτογραφική εμπειρία.
Δοκιμή του πρωτοκόλλου
Δοκιμάστε την εφαρμογή σας με την εκτέλεση του πελάτη και του διακομιστή στην ίδια μηχανή (τοπικός υπολογιστής) και επαληθεύοντας ότι τα μηνύματα αποκρυπτογραφούν σωστά. Εισαγάγετε λάθη όπως αλλοιωμένο κρυπτοκείμενο ή άκυρες μη-επιχειρήσεις για να διασφαλίσετε ότι το πρωτόκολλο τα απορρίπτει. Χρησιμοποιήστε εργαλεία όπως το Wireshark για να επιθεωρήσετε την κυκλοφορία του ακατέργαστου δικτύου και να επιβεβαιώσετε ότι το απλό κείμενο δεν είναι ορατό. Για δοκιμή μονάδας, χλευάστε το στρώμα υποδοχής και δοκιμαστικά κρυπτογραφικά πρωτόγονα ξεχωριστά. Το OpenSSL’s αποσφαλμάτωση μπορεί να βοηθήσει στην επαλήθευση των ενδιάμεσων τιμών που ταιριάζουν με τις αναμενόμενες εξόδους.
Συμπέρασμα
Η δημιουργία ενός ασφαλούς πρωτοκόλλου επικοινωνίας σε C είναι μια εξαιρετική άσκηση μάθησης, αλλά απαιτεί σχολαστική προσοχή στη λεπτομέρεια. Με τη χρήση αποδεδειγμένων εφαρμογών του OpenSSL των Diffie ⁇ Hellman, AES ⁇ GCM, και HMAC, μπορείτε να δημιουργήσετε ένα σύστημα που παρέχει εμπιστευτικότητα, ακεραιότητα και πιστοποίηση. Ακολουθήστε πάντα κρυπτογραφικές βέλτιστες πρακτικές: χρησιμοποιήστε ισχυρή τυχαιότητα, αντλήστε κλειδιά συνεδρίας με KDF, ποτέ επαναχρησιμοποιήστε μη-ές, και επικυρώστε πλήρως όλα τα δεδομένα. Για οτιδήποτε πέρα από ένα πρόγραμμα μάθησης, εξετάστε την υιοθέτηση ενός τυποποιημένου πρωτοκόλλου όπως TLS 1.3, το οποίο έχει αναθεωρηθεί και αναπτυχθεί σε κλίμακα.Η ασφαλής επικοινωνία είναι μια συνεχής διαδικασία βελτίωσης, μείνετε ενημερωμένοι για τις αναδυόμενες απειλές και ενημερώστε τις υλοποιήσεις σας αναλόγως.