Press "Enter" to skip to content

Crittografare e decrittografare dati in C#

Un articolo che dimostra come implementare un sistema di crittografia basico che ci servirà  per rendere non direttamente leggibili i dati “accessori” alle nostre applicazioni.

Introduzione

Ogni applicazione da noi implementata può aver bisogno di una serie di dati a corredo che devono essere memorizzati sul PC dell’utente o per ogni utente di uno stesso PC, fra questi principalmente le preferenze, le opzioni, e i dati di base per la connessione e l’autenticazione dell’utente.

Il motivo per cui ho deciso di creare questo articolo è che in seguito, dovremo lavorare con SQL server, visto che abbiamo spiegato come creare un Database, poi vorremo anche provare ad inserirvi dentro dei dati. Per inserire dati in un database SQL Server usando .Net è necessaria una Connection String, la connection string di una applicazione usualmente si inserisce una volta quando si configura l’applicazione e poi non si tocca più, per questo si memorizza su un file sulla cartella applicazioni oppure sulla cartella documenti dell’utente o sulla cartella documenti pubblica del sistema.

Considerato che a SQL Server i dati di Username e Password vanno passati in chiaro, scrivere semplicemente un file di testo non è esattamente sicuro, pertanto, anche usare un semplice algoritmo di crittografia come quello che andiamo a implementare in questo progetto dimostrativo è  un modo per evitare che i dati siano in chiaro. Attenzione, non ci protegge certamente da un Hacker, perchè essendo scritto in .Net il codice sorgente può essere facilmente decompilato, ci protegge solo dal nostro Utente 1.0 evitando che in qualche modo possa modificare i dati di connessione senza usare il nostro sistema.

La classe Helper EncDec

Per le funzioni di crittografia abbiamo scelto di creare una classe helper statica, che contiene due metodi pubblici e due metodi privati che permettono di crittografare e decrittografare una stringa. Essendo un sistema modello base, per la crittografia utilizzeremo una stringa memorizzata nel file Resources.resx della libreria in cui mettiamo la nostra classe. Per le vostre soluzioni potete pensare a sistemi più interessanti per memorizzare le suddette stringhe crittografiche.

private static byte[] Encrypt(byte[] dData, byte[] outerKey, byte[] IV)
{
	using (MemoryStream memoryStream = new MemoryStream())
	{
		Rijndael key = Rijndael.Create();
		key.Key = outerKey;
		key.IV = IV;

		using (CryptoStream cryptoStream =
			new CryptoStream(memoryStream, key.CreateEncryptor(),
				CryptoStreamMode.Write))
		{
			cryptoStream.Write(dData, 0, (int)dData.Length);
			cryptoStream.Close();
		}
		byte[] array = memoryStream.ToArray();
		return array;
	}
}

public static string Encrypt(string dText)
{

	byte[] bytes = Encoding.Unicode.GetBytes(dText);
	PasswordDeriveBytes passwordDeriveByte = 
		new PasswordDeriveBytes(Properties.Resources.CryptoData,
			new byte[] { 0x44, 0x6f, 0x74, 0x4e, 0x65, 0x74, 0x57, 
				0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2e, 0x47,
				0x6f, 0x74, 0x74, 0x61 });
	byte[] encryptedArray = EncDec.Encrypt(bytes, 
		passwordDeriveByte.GetBytes(32), passwordDeriveByte.GetBytes(16));
	return Convert.ToBase64String(encryptedArray);

}

Esaminiamo la funzione di crittografia, Come potete notare, per crittografare una stringa è necessario trasformarla in un Byte array, fate attenzione all’ Encoding, se utilizzate un encoding diverso dall’ Unicode ricordatevi di utilizzarlo in tutte le funzioni. Per crittografare il Byte array ottenuto, ci servono due chiavi, utilizzando il metodo da noi scelto, ovvero il Rijndael, una è una stringa, l’altra è una serie di numeri, in realtà  usualmente anche questi numeri sono la trasposizione numerica di una serie di caratteri ASCII, a voi l’onere di vedere a cosa corrispondono nel nostro caso.

Una volta creata la chiave crittografica, chiamiamo la funzione di crittografia vera e propria, che utilizza un  memory stream per generare un CryptoStream utilizzando le due chiavi fornite per costruire un nuovo Byte array crittografato.

Il Byte array così ottenuto viene trasformato in una stringa in base 64 che restituiamo al programma chiamante.

private static byte[] Decrypt(byte[] eData, byte[] outerKey, byte[] IV)
{

	using (MemoryStream memoryStream = new MemoryStream())
	{
		Rijndael key = Rijndael.Create();
		key.Key = outerKey;
		key.IV = IV;
		using (CryptoStream cryptoStream =
			new CryptoStream(memoryStream, key.CreateDecryptor(),
				CryptoStreamMode.Write))
		{
			cryptoStream.Write(eData, 0, (int)eData.Length);
			cryptoStream.Close();
		}
		byte[] array = memoryStream.ToArray();
		return array;
	}
}

public static string Decrypt(string eText)
{

	byte[] dataArray = Convert.FromBase64String(eText);
	PasswordDeriveBytes passwordDeriveByte = 
		new PasswordDeriveBytes(Properties.Resources.CryptoData, 
			new byte[] { 0x44, 0x6f, 0x74, 0x4e, 0x65, 0x74, 0x57, 
				0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2e, 0x47, 0x6f, 
				0x74, 0x74, 0x61 });
	byte[] hiddenArray = EncDec.Decrypt(dataArray, 
		passwordDeriveByte.GetBytes(32), passwordDeriveByte.GetBytes(16));
	return Encoding.Unicode.GetString(hiddenArray);

}

Per la decrittografia, il metodo è¨ complementare al precedente, quindi passata la stringa crittografata, viene trasformata in un Byte Array, costruiamo le chiavi di decrittografia e chiamiamo la funzione di conversione del Byte array. Questa funzione, utilizza un MemoryStream per produrre un CryptoStream e decodificare l’array di Byte che poi viene riconvertito in stringa.

Ricordo che è importante utilizzare l’encoding corretto per le stringhe e che .NET ha le stringhe in Unicode per default.

Conclusioni

Abbiamo creato le funzionalità  che ci permettono di crittografare e decrittografare una stringa, nel prossimo articolo testeremo le funzionalità in una applicazione WPF.

Le librerie comuni ove è stato sviluppato il codice di queste funzioni possono essere scaricate al link seguente:

Il progetto esempio che utilizza i metodi di crittografia è disponibile al link seguente:

Per qualsiasi domanda, commento, approfondimento, o per segnalare un problema, potete utilizzare il link alla form di contatto in cima alla pagina.