Analisi del codice della classe Communicator (esempio CNG)
Aggiornamento: Luglio 2008
Il file Communicator.cs incapsula i metodi di crittografia e decrittografia utilizzati nell'esempio di comunicazione protetta tramite Cryptography Next Generation (CNG). È costituito da un'unica classe, denominata Communicator, che contiene i membri e i metodi descritti nelle sezioni seguenti:
Membri della classe
Costruttore di classe
Metodo Dispose
Metodo StoreDSKey
Metodo Send_or_Receive_PublicCryptoKey
Metodo SendMessage
Metodo ReceiveMessage
Per una panoramica dell'esempio e le descrizioni delle versioni citate in questo argomento, vedere Esempio di comunicazione protetta tramite Cryptography Next Generation (CNG).
Membri della classe
La classe Communicator contiene i membri privati seguenti:
CngKey m_DSKey
Questo membro viene utilizzato da Communicator.StoreDSKey per archiviare una chiave di firma digitale.
ECDiffieHellmanCng m_ECDH_Cng
Questo membro viene utilizzato dal costruttore per archiviare un'istanza della classe ECDiffieHellmanCng. I metodi ReceiveMessage e SendMessage utilizzano questo membro per derivare il materiale della chiave.
string m_ECDH_local_publicKey_XML
Questo membro viene utilizzato dal costruttore per archiviare una rappresentazione di stringa XML della chiave di crittografia ECDH (Elliptic Curve Diffie-Hellman (ECDH) pubblica locale. Alice, Bob e Mallory utilizzano il metodo Send_or_Receive_PublicCryptoKey per scambiarsi questa stringa XML.
ECDiffieHellmanPublicKey m_ECDH_remote_publicKey
Questo membro viene utilizzato dal metodo Send_or_Receive_PublicCryptoKey per archiviare una chiave di crittografia ECDH pubblica remota.
La classe Communicator include inoltre il membro pubblico seguente:
ChannelManager ChMgr
Questo membro viene utilizzato da Alice, Bob e Mallory per fornire servizi di named pipe.
Costruttore di classe
public Communicator(string mode, string ChannelName)
Il costruttore crea i tre oggetti seguenti:
Un'istanza della classe ECDiffieHellmanCng con una coppia di chiavi casuale, utilizzando una dimensione di chiave di 521 bit:
m_ECDH_Cng = new ECDiffieHellmanCng(521)
L'oggetto risultante è associato alla classe Communicator come membro privato. Ogni oggetto Communicator crea una singola istanza della classe.
Alice e Bob creano ognuno un singolo oggetto Communicator e possono accedere a un singolo membro m_ECDH_Cng. Mallory crea due oggetti Communicator: uno da utilizzare con Alice e l'altro da utilizzare con Bob. Pertanto, Mallory può accedere a due membri m_ECDH_Cng.
La chiave ECDH come stringa XML privata:
m_ECDH_XmlString = m_ECDH_CryptoKey.ToXmlString(ECKeyXmlFormat.Rfc4050)
Il metodo ECDiffieHellmanCng.ToXmlString serializza la chiave ECDH pubblica utilizzando il formato ECKeyXmlFormat.Rfc4050.
Nelle versioni 2-5 dell'esempio, Alice invia la stringa XML risultante a Bob nel proprio metodo Run tramite l'istruzione di codice seguente:
Alice.Send_or_Receive_PublicCryptoKey("send", MyColor);
Un'istanza pubblica della classe ChannelManager:
ChMgr = new ChannelManager(mode, ChannelName)
Il costruttore accetta i due parametri seguenti:
mode: stringa che indica come creare la named pipe. Il parametro può essere "server" o "client".
ChannelName: stringa che fornisce un nome per identificare la nuova named pipe.
Metodo Dispose
public void Dispose()
La classe Communicator eredita l'interfaccia IDisposable e fornisce il metodo Dispose per liberare immediatamente risorse sensibili, tra cui oggetti m_ECDH_Cng, m_ECDH_local_publicKey_XML e ChMgr.
Ogni oggetto viene creato all'interno di un'istruzione using C# per assicurare che verrà rilasciato immediatamente quando esce dall'ambito.
Metodo StoreDSKey
public void StoreDSKey(byte[] DSKeyBlob)
Questo metodo accetta un oggetto binario di grandi dimensioni (BLOB) contenuto in una matrice di byte. Estrae una chiave di firma digitale dall'oggetto BLOB della chiave tramite il metodo CngKey.Import(array<Byte[], CngKeyBlobFormat). La chiave viene quindi archiviata dal codice seguente:
m_DSKey = CngKey.Import(DSKeyBlob,CngKeyBlobFormat.Pkcs8PrivateBlob);
Il metodo StoreDSKey viene chiamato da Alice, Bob e Mallory nei metodi Run, dalle versioni seguenti:
Nelle versioni 3-5 Alice, Bob e Mallory utilizzano questo metodo per archiviare la stessa chiave trasmessa pubblicamente.
Nelle versioni 4 e 5 Alice e Bob chiamano questo metodo una seconda volta e sovrascrivono il membro m_DSKey con una chiave trasmessa privatamente.
Metodo Send_or_Receive_PublicCryptoKey
Send_or_Receive_PublicCryptoKey(string mode, int color)
Questo metodo accetta due parametri:
mode: stringa che indica se creare un server pipe per inviare una chiave oppure un client pipe per ricevere una chiave. Il parametro può essere "server" o "client".
color: valore integer che specifica il colore utilizzato per visualizzare la chiave.
Il metodo Send_or_Receive_PublicCryptoKey è simile ai metodi ReceiveMessage e SendMessage di Communicator, con la differenza che invia o riceve chiavi di crittografia non crittografate anziché messaggi crittografati. I metodi ReceiveMessage e SendMessage non possono essere utilizzati per le chiavi di crittografia perché tenterebbero di crittografare e decrittografare le chiavi.
Dopo lo scambio delle chiavi, nelle versioni 3-5 dell'esempio vengono convalidate le relative firme digitali. Nella versione 3 viene utilizzata una firma digitale trasmessa tramite la named pipe PublicChannel. Questa firma viene intercettata e utilizzata da Mallory per firmare le chiavi e i messaggi sostitutivi che invia ad Alice e Bob. Nella versione 3 la convalida della firma ha sempre esito positivo, perché Alice, Bob e Mallory utilizzano la stessa chiave di firma digitale.
Nota: |
---|
Nelle versioni 4 e 5 viene utilizzata una firma digitale privata per firmare chiavi e messaggi e vengono visualizzati avvisi di sicurezza. Queste versioni vengono fornite solo ad Alice e Bob. Pertanto, Mallory non sa che le sue intercettazioni sono state rilevate. |
Metodo SendMessage
public bool SendMessage(string plainTextMessage, bool fShowMsg)
Questo metodo viene chiamato dai metodi Run di Alice, Bob e Mallory. Crittografa, firma digitalmente e invia messaggi tramite le operazioni seguenti:
Visualizza il messaggio di testo normale se il valore fShowMsg è true.
Converte il messaggio in una matrice di byte Unicode tramite il codice seguente:
byte[] UnicodeText = Encoding.Unicode.GetBytes(plainTextMessage);
Determina se il messaggio deve essere inviato come testo normale. Se viene eseguita la versione 1 dell'esempio, SendMessage viene restituito dopo l'invio del messaggio tramite il codice seguente:
ChMgr.SendMessage(UnicodeText);
Deriva il materiale della chiave chiamando il metodo ECDiffieHellmanCng.DeriveKeyMaterial(ECDiffieHellmanPublicKey).
byte[] aesKey = m_ECDH_Cng.DeriveKeyMaterial(m_ECDH_remote_publicKey)
Crea un oggetto Aes temporaneo:
Aes aes = new AesCryptoServiceProvider()
Inizializza l'oggetto Aes con il materiale della chiave derivato nel passaggio 4:
aes.Key = aesKey;
Crea un oggetto MemoryStream temporaneo per mantenere una stringa crittografata.
Crea un oggetto CryptoStream temporaneo e lo utilizza per crittografare il messaggio e scriverlo nell'oggetto MemoryStream.
Salva il testo crittografato e il vettore di inizializzazione:
iv = aes.IV ciphertext = ms.ToArray();
Firma il testo crittografato come segue, se viene eseguita la versione 3, 4 o 5 dell'esempio:
Crea un oggetto ECDsaCng.ECDsaCng(CngKey) temporaneo:
ECDsaCng ecdsa = new ECDsaCng(m_DSKey)
Inizializza la proprietà HashAlgorithm dell'oggetto come Secure Hash Algorithm Sha512:
ecdsa.HashAlgorithm = CngAlgorithm.Sha512
Crea una firma digitale firmando il testo crittografato:
signature = ecdsa.SignData(ciphertext);
Prepara il messaggio di output come segue:
Crea una matrice di tre byte per mantenere le lunghezze del vettore di inizializzazione, del testo crittografato e della firma del messaggio.
Crea quattro oggetti System.Collections.Generic.List<T> per mantenere la matrice di lunghezze del passaggio precedente, il vettore di inizializzazione, il testo crittografato e la firma.
Concatena i quattro oggetti System.Collections.Generic.List<T> e li converte in una singola matrice ola matrice di byte del messaggio di output:
byte[] message = list1.ToArray();
Invia il messaggio di output:
ChMgr.SendMessage(message)
Metodo ReceiveMessage
public string ReceiveMessage()
Questo metodo viene chiamato dai metodi Run di Alice, Bob e Mallory. Riceve e decrittografa i messaggi e ne convalida le firme digitali.
I messaggi non vengono passati come parametri a questo metodo. Al contrario, il membro ChannelManager della classe Communicator legge il messaggio tramite il codice seguente:
byteBuffer = ChMgr.ReadMessage();
Il metodo ReceiveMessage effettua le operazioni seguenti:
Determina se il messaggio è stato inviato come testo normale. Se viene eseguita la versione 1 dell'esempio, il messaggio è di testo normale e la decrittografia non è richiesta. In questo caso, il messaggio viene restituito dopo che è stato convertito in una stringa ASCII tramite il codice seguente:
AsciiMessage = Encoding.Unicode.GetString(byteBuffer);
Suddivide il messaggio in componenti. Nelle versioni 2-5 il messaggio verrà crittografato. In questo caso, viene suddiviso in tre matrici di byte distinte. La prima matrice contiene il vettore di inizializzazione, la seconda contiene il testo crittografato e la terza contiene la firma digitale del testo crittografato.
Visualizza il vettore di inizializzazione, il testo crittografato e la firma come file ASCII se il flag fVerbose è impostato.
Deriva il materiale della chiave. Il membro ECDiffieHellmanCng privato, m_ECDH_Cng, della classe Communicator utilizza il metodo ECDiffieHellmanCng.DeriveKeyMaterial per derivare il materiale della chiave condiviso, come illustrato dal codice seguente:
byte[] aesKey = m_ECDH_Cng.DeriveKeyMaterial(m_ECDH_remote_publicKey);
Crea un oggetto Aes creando un'istanza di un oggetto AesCryptoServiceProvider:
Aes aes = new AesCryptoServiceProvider()
Inizializza l'oggetto Aes con il materiale della chiave e il vettore di inizializzazione derivati nei passaggi precedenti.
Decrittografa il messaggio tramite oggetti System.IO.MemoryStream e System.Security.Cryptography.CryptoStream.
Visualizza il messaggio decrittografato.
Convalida il testo crittografato del messaggio nelle versioni 3-5 tramite la firma digitale. Nella versione 3 non vengono visualizzati avvisi di sicurezza perché Alice, Bob e Mallory utilizzano la stessa firma. Nella versione 4 vengono visualizzati avvisi di sicurezza quando il testo crittografato di un messaggio include una firma non valida. Tuttavia, la versione 4 viene fornita solo ad Alice e Bob, quindi Mallory non visualizza mai avvisi. Nella versione 5 le chiavi di crittografia con firme non valide provocano la chiusura del programma prima della trasmissione e della convalida dei messaggi.
Vedere anche
Concetti
Esempio di comunicazione protetta tramite Cryptography Next Generation (CNG)
Codice sorgente di Communicator.cs (esempio CNG)
Cenni preliminari sul codice sorgente (esempio CNG)
Descrizione dettagliata dello scambio di chiavi e messaggi (esempio CNG)
Cronologia delle modifiche
Data |
Cronologia |
Motivo |
---|---|---|
Luglio 2008 |
Argomento aggiunto. |
Miglioramento delle informazioni. |