Crittografia RSA

Mi sono imbattuta sulla crittografia con chiavi asimettriche e dopo essermi informata per giorni e aver letto un po' di documentazione su Msdn, sono riuscita a scrivere questo pezzo di codice che cripta un file usando la chiave pubblica e lo decrypta usando la chiave privata.

(L'esempio è scritto in C# e compilato con il Framework 1.1)

Innanzitutto bisogna ricordarsi di includere la libreria:

using System.Security.Cryptography;

per utilizzare la classe RSACryptoServiceProvider che si occupa di eseguire la crittografia e la decrittografia asimmetrica utilizzando l'implementazione dell'algoritmo RSA fornito dal provider del servizio di crittografia (CSP).

Vediamo come generare le chiavi (chiave pubblica e privata):

private string pubprivkey = Application.StartupPath + @"\pubprivkey.xml";
private string pubkey = Application.StartupPath + @"\pubkey.xml";

private int sizekey = 2048; 

public void CreateAndSaveKeys()
        {
            RSACryptoServiceProvider cryptoProvider = new RSACryptoServiceProvider(sizekey);
            SaveKeyInfoAsXml(cryptoProvider, pubprivkey, true); //Salvataggio della chiave privata e pubblica
            SaveKeyInfoAsXml(cryptoProvider, pubkey, false); //Salvataggio della chiave pubblica
            cryptoProvider.Clear();
        }

private void SaveKeyInfoAsXml( AsymmetricAlgorithm cryptoProvider, string fileName, bool includePrivateKey )
        {
            StreamWriter writer = new StreamWriter(fileName);
            writer.Write(cryptoProvider.ToXmlString(includePrivateKey));
            writer.Close();
        }

 

Ora vediamo come eseguire la crittografia di un file.
Il metodo che andremo ad usare è "Encrypt" che accetta in ingresso 2 parametri, l'array di byte da crittografare e il parametro OAEP.
La dimensione massima dell'array di byte è di:

(sizekey/ 8) - 11 se il parametro OAEP è false

(sizekey / 8) - 41 se il parametro OAEP è true

quindi per crittografare il contenuto di un file, dovremmo leggere il nostro file e caricarlo in un'array di byte e suddividerlo in sottoarray da passare al metodo Encrypt per crittografare i nostri dati.
Ovviamente per crittografare il nostro file ci sarà bisogno della chiave pubblica.

private void Encrypt( string inputfile, string outputfile )
        {
            RSACryptoServiceProvider cryptoProvider = new RSACryptoServiceProvider();
            cryptoProvider.FromXmlString(GetKeyInfoAsXml(pubkey));
            byte[] data = LeggiDati(inputfile);

            try
            {
                EncryptString(cryptoProvider, data, outputfile);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }

            cryptoProvider.Clear();
        }

private string GetKeyInfoAsXml( string fileName )
        {
            StreamReader reader = new StreamReader(fileName);
            string keyInfo = reader.ReadToEnd();
            reader.Close();
            return(keyInfo);
        }

private byte[] LeggiDati( string fileName )
        {
            FileInfo fileInfo = new FileInfo(fileName);
            BinaryReader reader = new BinaryReader(File.OpenRead(fileName));
            byte[] data = new byte[fileInfo.Length];
            reader.Read(data, 0, data.Length);
            reader.Close();
            return(data);
        }

public void EncryptString(RSACryptoServiceProvider cryptoProvider, byte[] bytes, string filename )
        {
            int maxLength = (sizekey/8)-11;
            int dataLength = bytes.Length;
            int iterations = dataLength / maxLength;

            byte [] totalbytes = new byte[0]; //ARRAY CONTENENTE LA CRITTOGRAFIA TOTALE DEL FILE

            for( int i = 0; i <= iterations; i++ )
            {
                byte[] tempBytes = new byte[
                    ( dataLength - maxLength * i > maxLength ) ? maxLength :
                    dataLength - maxLength * i ];
                Buffer.BlockCopy( bytes, maxLength * i, tempBytes, 0,
                    tempBytes.Length );
                byte[] encryptedBytes = cryptoProvider.Encrypt( tempBytes, false );  //applico la crittografia RSA al mio sottoarray

                //UNISCO IL SOTTOARRAY CRIPTATO AL RESTO
                byte [] tempbyte = new byte[totalbytes.Length + encryptedBytes.Length];
                int indice = 0;
                for (int j=0; j< totalbytes.Length; j++)
                {
                    tempbyte[indice] = totalbytes[j];
                    indice++;
                }
                for (int j=0; j<encryptedBytes.Length; j++)
                {
                    tempbyte[indice] = encryptedBytes[j];
                    indice++;
                }

                totalbytes = tempbyte;
            }

            ScriviDatiB64(filename, totalbytes); //SCRITTURA DEL FILE CRITTOGRAFATO
        }

 

private void ScriviDatiB64( string fileName, byte[] data )
        {
            ASCIIEncoding encoding = new ASCIIEncoding();
            long arrayLength = (long) ((4.0d/3.0d) * data.Length);
            if (arrayLength % 4 != 0)
                arrayLength += 4 - arrayLength % 4;

            char [] base64 = new char[arrayLength];
            System.Convert.ToBase64CharArray(data, 0, data.Length, base64, 0);

            BinaryWriter writer;
            FileStream fs;
            if (File.Exists(fileName))
                fs= new FileStream(fileName, FileMode.Append, FileAccess.Write);
            else
                fs= new FileStream(fileName, FileMode.CreateNew, FileAccess.Write);
            writer = new BinaryWriter(fs);
            writer.Write(base64);
            writer.Close();
        }

 

Come si può vedere il file crittografato viene scritto in base64.

A questo punto abbiamo il nostro file salvato e crittografato, ora dobbiamo verificarlo ed estrarre l'originale.
Il metodo che andremo ad usare è "Decrypt" che accetta in ingresso 2 parametri, l'array di byte da crittografare e il parametro OAEP.
La dimensione massima dell'array di byte è di:

(sizekey/ 8)  se il parametro OAEP è false

(sizekey / 8) se il parametro OAEP è true

quindi, come per la crittografia, dovremmo leggere il nostro file e caricarlo in un'array di byte e suddividerlo in sottoarray da passare al metodo Decrypt per decrittografare i nostri dati.
In questo caso è necessaria la chiave privata che andremmo a leggere dal relativo file.

private void VerifyFile( string outputfile, string inputfile)
        {
            try
            {
                RSACryptoServiceProvider cryptoProvider = new RSACryptoServiceProvider();
                cryptoProvider.FromXmlString(GetKeyInfoAsXml(pubprivkey));

                byte[] dati = LeggiDatiB64(inputfile);

                DecryptString(cryptoProvider, dati, outputfile);

                cryptoProvider.Clear();
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

 private byte[] LeggiDatiB64( string fileName )
        {
            FileInfo fileInfo = new FileInfo(fileName);
            BinaryReader reader = new BinaryReader(File.OpenRead(fileName));
            char[] data = new char[fileInfo.Length];
            reader.Read(data, 0, data.Length);
            reader.Close();

            ASCIIEncoding encoding = new ASCIIEncoding();
            byte [] dataout = System.Convert.FromBase64CharArray(data, 0, data.Length);
            return(dataout);
        }

public void DecryptString(RSACryptoServiceProvider cryptoProvider, byte [] bytes, string filename)
        {
            int maxLength = (sizekey/8);
            int dataLength = bytes.Length;
            int iterations = dataLength / maxLength;

            byte [] totalbytes = new byte[0];

            for( int i = 0; i < iterations; i++ )
            {
                byte[] tempBytes = new byte[
                    ( dataLength - maxLength * i > maxLength ) ? maxLength :
                    dataLength - maxLength * i ];
                Buffer.BlockCopy( bytes, maxLength * i, tempBytes, 0,
                    tempBytes.Length );
                byte[] encryptedBytes = cryptoProvider.Decrypt( tempBytes, false );


                byte [] tempbyte = new byte[totalbytes.Length + encryptedBytes.Length];
                int indice = 0;
                for (int j=0; j< totalbytes.Length; j++)
                {
                    tempbyte[indice] = totalbytes[j];
                    indice++;
                }
                for (int j=0; j<encryptedBytes.Length; j++)
                {
                    tempbyte[indice] = encryptedBytes[j];
                    indice++;
                }

                totalbytes = tempbyte;
            }

            ScriviDati(filename, totalbytes);
        }

 

private void ScriviDati( string fileName, byte[] data )
        {
            BinaryWriter writer;
            FileStream fs;
            if (File.Exists(fileName))
                fs= new FileStream(fileName, FileMode.Append, FileAccess.Write);
            else
                fs= new FileStream(fileName, FileMode.CreateNew, FileAccess.Write);
            writer = new BinaryWriter(fs);
            writer.Write(data);
            writer.Close();
        }

 

Vi allego anche la Classe (togliete l'estensione .doc al file allegato per avere la classe).

Spero vi sia di aiuto!

Ciao a tutti.

 

Un ringraziamento a Marcello Cantelmo per l'aiuto durante lo sviluppo

Search

Go

This Blog

Tags

No tags have been created or used yet.

Archives

Syndication