Cenni preliminari sul codice sorgente (esempio CNG)
In questa sezione viene fornita una descrizione generale delle interazioni tra i vari elementi di codice nell'esempio di comunicazione protetta tramite Cryptography Next Generation (CNG).
Vengono illustrati gli aspetti seguenti dell'esempio:
Applicazioni
File
Classi
Versioni di sicurezza
Cenni preliminari sulla sessione
Chiavi di crittografia (versioni 2-5)
Firme digitali scambiate su canale pubblico (versione 3)
Firme digitali scambiate su canale privato (versione 4)
Chiusura della sessione (versione 5)
Note aggiuntive
Limitazioni dell'esempio CNG
Applicazioni
L'esempio è costituito da tre applicazioni console distinte, Alice, Bob e Mallory.Ogni applicazione è compilata come progetto di Visual Studio distinto ed è costituita da un file principale e da tre file condivisi.Nella tabella seguente sono illustrate le applicazioni e i relativi file.
Nome applicazione (progetto) |
File |
---|---|
Alice |
|
Bob |
|
Mallory |
|
File
Nelle tabelle delle sezioni seguenti viene fornito un riepilogo delle classi e dei metodi utilizzati da ogni applicazione, nell'ordine in cui appaiono nel codice sorgente.
Alice.cs, Bob.cs e Mallory.cs
Nome di classe, metodo o variabile globale |
Utilizzo |
---|---|
CNG_SecureCommunicationExample |
Classe parziale a livello di progetto. |
MyColor OtherColor fDisplaySendMessage |
Variabili globali. |
Main |
Punto di ingresso del programma per ogni applicazione.Questo metodo gestisce quanto segue:
|
Run |
Metodo che chiama il metodo InitializeOptions e crea lo scenario di sicurezza selezionato. |
Utilities.cs
Nome di classe, metodo o variabile globale |
Utilizzo |
---|---|
CNG_SecureCommunicationExample |
Classe parziale a livello di progetto. |
Version fVerbose fMallory |
Variabili globali. |
Autoloader |
Metodo chiamato da Alice per caricare le applicazioni Bob.exe e Mallory.exe. |
InitConsole |
Metodo che gestisce il menu dell'interfaccia utente e i messaggi a livello di applicazione. |
SplashScreen |
Metodo che fornisce titoli della finestra della console. |
ReadALine |
Metodo di utilità che legge una riga immessa dall'utente dalla console. |
ReadAChar |
Metodo di utilità che visualizza una domanda e chiede all'utente di specificare una risposta di tipo sì/no. |
InitializeOptions |
Metodo che visualizza opzioni e chiede all'utente di effettuare una selezione.Questo metodo imposta inoltre i flag globali Version, fVerbose e fMallory. |
Display(string s) |
Primo di due metodi Display.Questo metodo passa la stringa e la variabile MyColor al secondo metodo Display. |
Display(string DisplayString, int color) |
Secondo di due metodi Display.Questo metodo esegue il wrapping delle istruzioni Console.WriteLine e fornisce supporto del colore per le righe di output. |
Per ulteriori informazioni su queste classi, metodi e variabili, vedere Analisi del codice delle classi di utilità (esempio CNG).
ChannelManager.cs
Nome di classe, metodo o variabile globale |
Utilizzo |
---|---|
CNG_SecureCommunicationExample |
Classe parziale a livello di progetto. |
AppControl |
Metodo che fornisce il controllo interno dell'applicazione e sincronizza le tre applicazioni console. Alice utilizza questo metodo per inviare le opzioni del programma (flag Version e fVerbose) a Bob e Mallory. AppControl non è un metodo di messaggistica.Il contenuto non è crittografato né firmato.Non chiama la classe Communicator. |
SendChannelName ReceiveChannelName |
Metodi utilizzati per passare dalla named pipe PublicChannel alle named pipe AliceAndBobChannel e AliceAndBobChannel1.Questi metodi consentono la violazione di sicurezza intenzionale descritta nella sezione Cenni preliminari sull'esempio CNG. |
ChannelManager |
Classe che fornisce il framework per la comunicazione interprocesso per l'applicazione. |
Per ulteriori informazioni su queste classi e metodi, vedere Analisi del codice della classe ChannelManager (esempio CNG).
Communicator.cs
Nome di classe, metodo o variabile globale |
Utilizzo |
---|---|
CNG_SecureCommunicationExample |
Classe parziale a livello di progetto. |
Communicator |
Classe che incapsula tutte le funzioni di crittografia.Questa classe elabora tutti i messaggi tra Alice, Bob e Mallory.Non elabora i messaggi inviati dal metodo AppControl di ChannelManager. |
m_DSKey m_ECDH_Cng m_ECDH_local_publicKey_XML m_ECDH_remote_publicKey ChMgr |
Variabili di classe. |
Communicator |
Metodo che costruisce un oggetto Communicator. |
Dispose |
Metodo che rilascia risorse mantenute privatamente. |
StoreDSKey |
Metodo che archivia una chiave di firma digitale. |
Send_or_Receive_PublicCryptoKey |
Metodo che fornisce supporto per lo scambio di chiavi. |
iv ciphertext signature |
Variabili di classe private utilizzate per la crittografia dei messaggi di testo normale.Queste variabili vengono dichiarate vicino al metodo ReceiveMessage(). |
ReceiveMessage |
Metodo che riceve messaggi di testo normale o crittografati, a seconda della versione di sicurezza. |
SendMessage |
Metodo che accetta un messaggio di testo normale e lo invia in formato di testo normale o crittografato, a seconda della versione di sicurezza. |
Per ulteriori informazioni su queste classi, metodi e variabili, vedere Analisi del codice della classe Communicator (esempio CNG).
Classi
Ogni progetto contiene tre classi:
public partial class CNG_SecureCommunicationExample
Questa classe si estende in tutti e quattro i file di progetto inclusi nelle applicazioni Alice, Bob e Mallory.Dopo la compilazione, la classe CNG_SecureCommunicationExample contiene tutte le classi, le variabili e i metodi per i quattro file di progetto.Per ulteriori informazioni sulle classi parziali, vedere Classi e metodi parziali (Guida per programmatori C#).
internal sealed class ChannelManager
Questa classe fornisce supporto per le named pipe.Ogni progetto crea diverse istanze di ChannelManager in momenti diversi durante l'esecuzione del programma.Per informazioni dettagliate su questa classe, vedere Analisi del codice della classe ChannelManager (esempio CNG).
internal sealed class Communicator
Questa classe fornisce supporto per la crittografia e la decrittografia.Ogni progetto crea diverse istanze di Communicator in momenti diversi durante l'esecuzione del programma.Per informazioni dettagliate su questa classe, vedere Analisi del codice della classe Communicator (esempio CNG).
Versioni di sicurezza
Il codice sorgente supporta lo scenario di sicurezza presentato nella sezione Cenni preliminari sull'esempio CNG.Implementa le cinque versioni seguenti, che rappresentano cinque livelli di sicurezza, dello strumento di messaggistica immediata:
Versione 1: utilizza messaggi di testo normale e named pipe.
Versione 2: utilizza messaggi crittografati.
Versione 3: utilizza messaggi crittografati e firme digitali.
Versione 4: utilizza messaggi crittografati e una firma digitale privata.
Versione 5: chiude l'applicazione quando vengono rilevati errori di sicurezza.
Nota
Nella parte rimanente di questo argomento si fa riferimento a tali versioni in base al numero.Inoltre, a seconda del contesto, i nomi "Alice", "Bob" e "Mallory" possono fare riferimento ai tre utenti coinvolti nello scenario di esempio e alle tre applicazioni di Visual Studio.
Cenni preliminari sulla sessione
Alice, Bob e Mallory includono ognuno un metodo Main e un metodo Run.
Il metodo Main sincronizza le applicazioni ed esegue le funzioni seguenti:
Visualizza una schermata iniziale di avvio.
Chiede all'utente di scegliere le opzioni della sessione (solo Alice).
Invia le opzioni della sessione a Bob e Mallory (solo Alice).
Riceve le opzioni della sessione da Alice (solo Bob e Mallory).
Chiama il metodo Run per eseguire la sessione di sicurezza richiesta.
Il metodo Run esegue gli scenari di sicurezza.
In ogni sessione viene illustrata una delle versioni descritte nella sezione precedente.
Una sessione viene avviata quando Alice, Bob e Mallory entrano nei relativi metodi Run e termina quando tornano ai metodi Main.
Alice, Bob e Mallory eseguono sempre la stessa versione durante una sessione.
Alice avvia tutte le transazioni che vengono eseguite durante una sessione.Mallory risponde ad Alice e avvia le transazioni con Bob.Bob si limita a rispondere.
Il codice sorgente per Alice e Bob è molto simile.La differenza principale è che Alice avvia ogni sessione e funge da server pipe, mentre Bob funge da client pipe.Il codice di Mallory è più complesso perché gestisce due pipe distinte, una con Alice e l'altra con Bob.
Metodo Main
Alice chiama il metodo InitializeOptions all'inizio del metodo Main e riceve le opzioni della sessione (Version, fVerbose, fMallory) dall'utente.Utilizza il metodo AppControl per inviare le opzioni a Bob e Mallory, che le ricevono tramite i metodi AppControl.Se l'utente decide di chiudere l'applicazione digitando la lettera "x", il metodo AppControl di Alice invia a Bob e Mallory la stringa "exit" anziché le opzioni della sessione.
Una volta ricevute le opzioni della sessione, le tre applicazioni chiamano i relativi metodi Run.
Metodo Run
Alice, Bob e Mallory eseguono la sessione richiesta effettuando i passaggi seguenti:
Alice chiama il metodo SendChannelName, che utilizza un canale denominato PublicChannel.Invia a Bob un nuovo nome di canale (AliceAndBobChannel).
Se il flag fMallory è impostato su true, Mallory rimane in ascolto su PublicChannel e intercetta il nuovo nome del canale (AliceAndBobChannel) da Alice.Invia quindi a Bob un nome di canale diverso (AliceAndBobChannel1).
Alice e Bob creano oggetti Communicator con i rispettivi nomi.Questi oggetti vengono creati all'interno di istruzioni using di C# e vengono eliminati alla fine del metodo Run.
Alice viene inizializzata come server pipe:
using (Communicator Alice = new Communicator("server", NewChannelName))
Bob viene inizializzato come client pipe:
using (Communicator Bob = new Communicator("client", NewChannelName))
Mallory crea due oggetti Communicator, MalloryAlice e MalloryBob,e viene inizializzato come client pipe con Alice:
using (Communicator MalloryAlice = new Communicator("client", AliceChannelName))
Mallory viene inizializzato come server pipe con Bob:
using (Communicator MalloryBob = new Communicator("server", BobChannelName"))
Il costruttore della classe Communicator accetta il nome del canale e crea che un oggetto ChannelManager pubblico a lungo termine denominato ChMgr:
ChMgr = new ChannelManager(mode, ChannelName);
Il costruttore ChannelManager accetta il nome del canale e crea una named pipe corrispondente.
Nota
In questa fase, Alice e Mallory comunicano su una pipe denominata AliceAndBobChannel, mentre Mallory e Bob comunicano su una pipe denominata AliceAndBobChannel1.
AliceAndBobChannel e AliceAndBobChannel1 sono canali a lungo termine che rimangono aperti fino alla fine dello scenario di sicurezza, ovvero fino alla fine del metodo Run .
I valori del flag fVersion, che controlla la versione di sicurezza, e del flag fMallory, che controlla il coinvolgimento di Mallory, determinano ciò che si verifica in seguito:
Nella versione 3 Alice invia una chiave di firma digitale a Bob su PublicChannel.Utilizzano questa chiave di firma digitale per firmare chiavi e messaggi.Se fMallory è true, Mallory intercetta la chiave di firma digitale e la utilizza per firmare le chiavi e i messaggi che invia ad Alice e Bob.
Nelle versioni 4 e 5 Alice invia due chiavi di firma digitale a Bob.La chiave di firma digitale 1 è la stessa chiave inviata da Alice nella versione 3.La chiave di firma digitale 2 è una chiave di firma digitale privata che Mallory non conosce.
Alice e Bob scambiano chiavi di crittografia pubbliche per le versioni da 2 a 5.Se fMallory è true, Mallory intercetta le chiavi pubbliche e sostituisce le proprie chiavi.
Alice e Bob si scambiano messaggi.Se fMallory è true, Mallory intercetta, modifica e reinvia i messaggi di Alice e Bob.
Al termine della conversazione tra Alice e Bob, viene richiesto di inviare i propri messaggi.In questo modo è possibile rilevare la modalità con cui i messaggi vengono crittografati e le operazioni effettuate da Mallory per modificarli.Al termine, premere INVIO per trasferire il controllo di nuovo ad Alice.
Alice termina la sessione.I metodi Run di Alice, Bob e Mallory restituiscono il controllo ai metodi Main e l'esempio viene riavviato.
Chiavi di crittografia (versioni 2-5)
Le versioni da 2 a 5 crittografano i messaggi tramite l'algoritmo AES (Advanced Encryption Standard).Lo scambio di chiavi di crittografica viene implementato nei metodi Run di Alice, Bob e Mallory dopo l'istruzione di codice seguente:
if (2 <= Version)
La chiave di crittografica viene inviata dall'oggetto ChannelManager pubblico a lungo termine (ChMgr) creato dal costruttore di classe Communicator.
Le due istruzioni di codice seguenti illustrano in che modo Alice invia e Bob riceve la chiave di crittografia:
Alice.Send_or_Receive_PublicCryptoKey("send", MyColor);
Bob.Send_or_Receive_PublicCryptoKey("receive", OtherColor);
Il secondo parametro definisce il colore che deve essere utilizzato dall'applicazione ricevente per la visualizzazione del contenuto della chiave di crittografia.
Le implementazioni AES sono considerate matematicamente impossibili da violare.Tuttavia, AES non offre protezione contro gli attacchi di tipo man-in-the-middle.Può sembrare contraddittorio che Mallory possa decrittografare i messaggi di Alice e Bob nonostante la crittografia avanzata AES.Ciò è possibile perché Mallory dispone delle chiavi private condivise di Alice e Bob.L'intercettazione e la sostituzione delle chiavi da parte di Mallory rendono inutile la crittografia avanzata AES.
L'utilizzo di chiavi di crittografia senza autenticazione fornisce un falso senso di sicurezza.Alice e Bob pensano di disporre di uno schema di trasmissione dei messaggi sicuro con la versione 2.In realtà, la sicurezza viene compromessa prima dell'invio del primo messaggio.
La società di Alice e Bob non è in grado di accertare se gli attacchi provengono dall'interno o dall'esterno dell'organizzazione.Viene progettata la versione 3 dello strumento di messaggistica immediata per individuare l'origine degli attacchi.
Firme digitali scambiate su canale pubblico (versione 3)
Con la versione 3 si tenta di correggere il difetto del sistema di sicurezza della versione 2 utilizzando una firma digitale per firmare chiavi e messaggi.Lo scambio di chiavi di firma digitale viene implementato nei metodi Run di Alice, Bob e Mallory dopo l'istruzione di codice seguente:
if (3 <= Version)
La chiave di firma digitale viene inviata tramite lo stesso canale pubblico a lungo termine delle chiavi di crittografia.L'invio della chiave di firma digitale viene eseguito con il codice seguente:
Alice.ChMgr.SendMessage(dsKeyBlob);
Nota
L'istanza di ChannelManager (ChMgr) che invia la chiave di firma digitale è un membro dell'oggetto Communicator di Alice.
Alice e Bob archiviano la chiave di firma digitale come membro privato dei rispettivi oggetti Communicator:
Alice.StoreDSKey(DSKey);
Bob.StoreDSKey(DSKey);
Purtroppo, Mallory riesce facilmente a copiare la firma digitale da PublicChannel e la salva:
Mallory.StoreDSKey(DSKey);
Quando Alice e Bob ricevono messaggi firmati l'una dall'altro, le firme digitali corrispondono perfettamente ai messaggi.Il motivo è che Mallory li ha firmati con la stessa chiave di firma digitale utilizzata da Alice e Bob.
Nella versione 3 le chiavi di crittografia e la firma digitale vengono scambiate su un canale pubblico tramite la rete aziendale.La società per cui lavorano Alice e Bob sospetta che i furti vengano eseguiti da qualcuno all'interno.Per verificare questa ipotesi, viene creata la versione 4.
Firme digitali scambiate su canale privato (versione 4)
Nella versione 4 si utilizzano due chiavi di firma digitale: la chiave utilizzata nella versione 3 e una seconda chiave segreta inviata tramite un canale privato.La prima chiave viene ora trattata come chiave digitale falsa, per intercettare il ladro.La seconda chiave viene utilizzata da Alice e Bob per applicare una firma digitale alle chiavi di crittografia e ai messaggi.
La versione 4 del software di messaggistica immediata viene fornita solo ad Alice e Bob.Mallory continua a utilizzare la versione 3.Pertanto, non è in grado di individuare che la firma digitale utilizzata non è valida.Tuttavia, lo strumento di messaggistica immediata di Alice e Bob visualizza un messaggio di avviso per ogni singola chiave e messaggio che ricevono.
La versione 4 dimostra anche che vengono intercettate sia le chiavi di crittografia che i messaggi.Questa situazione indica che è in corso un attacco di tipo man-in-the-middle, che inizia ancora prima che vengano inviate le chiavi di crittografia.Pertanto, un dipendente della società che dispone di accesso all'oggetto PublicChannel aziendale deve essersi connesso prima di Bob.L'utilizzo intelligente della chiave di firma digitale segreta rivela le attività segrete di Mallory.
La trasmissione della chiave di firma digitale segreta viene implementata nei metodi Run di Alice e Bob dopo l'istruzione di codice seguente:
if (4 <= Version)
La creazione di istanze private di ChannelManager di Alice e Bob viene eseguita con le istruzioni di codice seguenti:
ChannelManager ChMgr2 = new ChannelManager("server", "PrivateChannel")
ChannelManager ChMgr2 = new ChannelManager("client", "PrivateChannel")
Il canale privato utilizzato da Alice e Bob (ChMgr2) non è un membro dei rispettivi oggetti Communicator.Per verificarlo, è possibile confrontare le due istruzioni di codice seguenti:
Alice.ChMgr.SendMessage(dsKeyBlob); // Public channel - fake key
ChMgr2.SendMessage(dsKeyBlob); // Private channel - real key
La prima istruzione utilizza l'istanza di ChannelManager a lungo termine (ChMgr) creata all'inizio del metodo Run.Questa istanza viene mantenuta come membro pubblico degli oggetti Communicator di Alice, Bob e Mallory (vedere il passaggio 3 nella sezione Cenni preliminari sulla sessione) fino alla fine della sessione.La seconda istruzione utilizza un oggetto temporaneo che esiste solo per il tempo sufficiente per l'invio e la ricezione della chiave.Viene eliminato immediatamente dopo l'utilizzo.
Dopo che Alice invia la chiave di firma digitale segreta, Bob la riceve tramite l'istruzione seguente:
DSKey = ChMgr2.ReadMessage();
Alice e Bob archiviano la chiave come membro privato nei rispettivi oggetti Communicator:
Alice.StoreDSKey(DSKey);
Bob.StoreDSKey(DSKey);
Queste istruzioni sovrascrivono anche la chiave di firma digitale falsa.
Nella versione 4 Alice e Bob utilizzano la chiave di firma digitale segreta anziché quella falsa per firmare chiavi e messaggi.Nella versione 4 vengono inoltre firmate le chiavi di crittografia e vengono visualizzati messaggi di avviso ogni volta che la firma digitale di un messaggio non corrisponde al messaggio.
Chiusura della sessione (versione 5)
La versione 5 è identica alla versione 4, con la differenza che la sessione viene chiusa al primo errore.Alice riscontra il primo errore quando riceve la chiave di crittografia pubblica di Bob e individua una firma digitale non valida.Bob riscontra il primo errore quando riceve la chiave di crittografia pubblica di Alice e individua anche in questo caso una firma digitale non valida.
Note aggiuntive
Eliminazione dell'oggetto: le istruzioni using di C# forniscono una maggiore sicurezza.Vengono utilizzate per includere tutti gli oggetti ChannelManager e Communicator.Quando questi oggetti escono dall'ambito, vengono immediatamente chiamati i relativi oggetti Dispose e le risorse mantenute internamente vengono rilasciate.
Metodi di codifica: ogni volta che vengono trasmessi dati crittografati, è necessario codificarli come UTF8 o Unicode, mai come ASCII.
Limitazioni dell'esempio CNG
Lo scopo dell'esempio di comunicazioni protette tramite CNG viene fornito per dimostrare le funzioni CNG gestite.Di conseguenza, determinate funzionalità sono state omesse, incluse le seguenti:
Convalida dei parametri in tutti i metodi.
Utilizzo esteso di blocchi try/catch.
Individuazione affidabile della disconnessione di pipe.
Registrazione dell'output dello schermo in un file.
Configurabilità dinamica dell'algoritmo di crittografia.
Configurabilità dinamica dell'algoritmo di firma digitale.
Modalità diversa di trasmissione della chiave del segnale digitale a Bob.La named pipe PrivateChannel è una soluzione semplice; esistono altri metodi più sofisticati.
Persistenza, archiviazione e recupero delle chiavi.
Utilizzo di chiavi di firma digitale generate dal sistema operativo.
Utilizzo di chiavi fornite da un'infrastruttura a chiave pubblica (PKI).
Queste funzionalità aumentano la complessità del codice ed esulano dall'ambito di questo esempio.
Vedere anche
Concetti
Esempio di comunicazione protetta tramite Cryptography Next Generation (CNG)
Descrizione dettagliata dello scambio di chiavi e messaggi (esempio CNG)