Programujeme v jazyku C# III. Diel 11. – Šifrovanie III

Michal Čižmár  /  07. 11. 2007, 00:00

V tomto dieli si ukážeme maximálne jednoduchý a okomentovaný príklad použitia algoritmu RSA na šifrovanie prostého textu, využitím už nechystanej triedy RSACryptoServiceProvider. A bezpečné uloženie kľúčového páru v pamäti.


[Kľúčové slová]

Asymetrické šifrovanie, Verejný kľúč, Privátny kľúč, RSA

Začnem tak trochu oficiálne. Vážení čitatelia, veľmi sa ospravedlňujem za dlhšiu odmlku, ale do kedy bolo viac menej pekné počasie, tak sa vždy našla nejaká robota alebo príležitosť na výlet. ;-) Teraz už nastupujú dlhé večery, sychravé počasie, takže si nájdem oveľa viac času, dať si myšlienky do kopy a napísať ďalší diel.

Musím sa priznať, že tento článok píšem za úplne špeciálnych okolností, na zaujímavom mieste, ale viac Vám neprezradím ;-)

V minulom článku sme si teoreticky vysvetlili, aký je rozdiel medzi symetrickým a asymetrickým šifrovaním a prakticky sme si ukázali, ako funguje to symetrické. Takže ak ste náhodou pozabudli, čo tie pojmy znamenajú, tak sa zbežne mrknite na predchádzajúci diel, pretože teraz ideme rovno na príklady asymetrického šifrovania.

>>Triedy pre asymetrické šifrovanie

V .NET priestore mien System.Security.Cryptography máme nachystané tieto 2 triedy:
RSACryptoServiceProvider
– implementuje šifrovanie, podpisovanie
DSACryptoServiceProvider – implementuje len podpisovanie

>>RSA

Tento asymetrický šifrovací algoritmus sa volá podľa prvých písmen priezvisk jeho troch autorov:
Ron R, Adi Shamir a Leonard Adleman.
Myslím si, že algoritmus to nie je zložitý, ale nebudeme si ho tu vysvetľovať. Krok po kroku ho môžete nájsť opísaný na Wikipedii.
Je to veľmi používaný algoritmus a odporúčam s kľudným srdcom použiť tento už nachystaný, pretože vyhovuje potrebným normám, a radšej sa v programe rovno zamerajte na jeho využitie.

>>Jednoduché použitie RSA

Často, keď riešim nejaký problém počas programovania a hľadám to na Internete, vždy prescrollujem bežný text a hľadám rovno príklad. A najlepšie príklady sú také, ktorú sú kompletné, teda nie len vybraté časti a také, kde to základné je už vysvetlené v komentároch. Takže poďme na príklad a predpokladám, že tento odstavec aj tak skoro nikto nečítal ;-)

Príklad 3.11.1

using System;
using
System.Security.Cryptography;

class Program
{
    public static void Main(string[] args)
    {


        //Sifrovat dokazeme len pole typu Byte
        //takze si vstupny text musime prekonvertovat
        Console.WriteLine("Zadajte text na zasifrovanie:");
        string inputText = Console.ReadLine();
          byte []inputBytes =
              System
.Text.Encoding.UTF8.GetBytes(inputText);

        //Zavolanim bezparametrickeho konstruktora sa nie len
        //vytvori nova instancia, ale vygeneruje sa automaticky

        //aj klucovy par, ktory mozememe pouzit

        RSACryptoServiceProvider rsaProvider = new
                  
RSACryptoServiceProvider();


        //Na uchovanie vsetych parametrov kluca name
        //tiez nachystanu triedu RSAParameters

        //ExportParameters ma jeden bool parameter
        //TRUE - vyexportuju sa vsetky parametre ako o
        // privatnom tak aj verejnom kluci
        //FALSE - vyexportuje sa len verejny kluc
       
        RSAParameters parametersPrivate =
               rsaProvider.ExportParameters(true);

        RSAParameters parametersPublic =
            rsaProvider.ExportParameters(false);

        //Aby sme si ukazali aj pouzitie existujucich klucov, tak
        // vytvorime
        // instanciu RSACryptoServiceProvider este raz a

        //a prepiseme jej automatiky vygenerovane kluce
        //tymi uz vyexportovanymi v predchadzajucom kroku
   
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                rsa.ImportParameters(parametersPublic);

        //Kedze sme importovali len verejny kluc, mozeme data
        //LEN zasifrovat
          byte [] encryptetText = rsa.Encrypt(inputBytes,false);

        // Zas prakticke pouzitie triedy BitConvert
        Console.WriteLine("Zasifrovany text:");
        Console.WriteLine(BitConverter.ToString(encryptetText));


        //Desifrovnaie pomocou privatneho kluca
        RSACryptoServiceProvider rsa2 = new
            RSACryptoServiceProvider
();
        rsa2.ImportParameters(parametersPrivate);
          byte [] decryptedText = null;
          try{
              decryptedText = rsa2.Decrypt(encryptetText,false);
        }
catch(CryptographicException e)
        {
            //Ak sa pokusime desifrovat poocou nespravneho
            //kluca, nastane vynimka
            Console.WriteLine
                ("Asi ste pouzili zly kluc : " + e.Message);
            Console.ReadLine();
        return;
      }


       Console.WriteLine("Desifrovany text:");
       Console.WriteLine
            (System.Text.Encoding.UTF8.GetString(decryptedText));
       Console.ReadLine()
     }

}



Príklad 3.11.1 na stiahnutie.

>> Použitie bezpečného kontajneru na šifrovacie kľúče.

Predchádzajúci príklad mal jednu bezpečnostnú chybu, ktorá umožňuje iným aplikáciám zistiť šifrovacie kľúče. Asi sa pýtate, kde by sa k nim dostal, veď sa neukladajú ani na disk, ani sa neposielajú sieťou. Odpoveď je: Priamo v operačnej pamäti.

Ak by niekto pozeral obsah operačnej pamäti, našiel by naše kľúče, pretože sú uchovávané ako čistý text (plain text). Viem si predstaviť, že niektorý hačkovací ;-) softvér by sa zameral práve na túto oblasť, v programoch, ktoré sa hneď po použití nevypínajú a inštancie tried udržujúce kľúč sa automaticky neuvolňujú.

Ak chceme svoj program zabezpečiť voči takejto možnosti útoku, môžeme použiť existujúcu triedu : CspParameters.
Príklad 3.11.2

using System;
using
System.Security.Cryptography;
class
Program
{

    const string KEY_NAME = "klucJozo";

    public static void Main(string[] args)
    {
        //1. Vytvorit instanciu CspParameters
        CspParameters csp = new CspParameters();

        //2.Nastavit meno kluca, aby sme sa k nemu
        //neskor dostali pomocou mena
        csp.KeyContainerName = KEY_NAME;

        //3. Vytvorenie RSACrypto..
        //Do konstruktora predat CSP kontajner

        //a teda vygenerovene kluce sa budu
        //automaticiky ukladat do CSP namiesto plainText.

        RSACryptoServiceProvider rsa
                = new RSACryptoServiceProvider(csp);

        //... Praca s RSACrypto....
        string publicKey =
            rsa.ToXmlString(false);

        Console.WriteLine("Vygenerovany kluc je:");
        Console.WriteLine(publicKey);

        //Teraz skusime to iste
        //s tym istym menom kluca

        //v inej metode
         PrintPublicKeyByName(KEY_NAME);

        //4. Bezpecne vymazanie kontajnera
        // t.j. aj kluce s globalneho kontajnera

        rsa.PersistKeyInCsp = false;
        rsa.Clear();


        Console.ReadKey(true);
}


    private static void PrintPublicKeyByName(string name)
    {
        CspParameters csp = new CspParameters();
        csp.KeyContainerName = name;

        RSACryptoServiceProvider rsa =
                new RSACryptoServiceProvider(csp);

        string publicKey = rsa.ToXmlString(false);
        Console.WriteLine
             (
"Hodnota kluca vytiahnuta v inej casti kodu");

        Console.WriteLine(publicKey);
    }


}




Čo bolo ideou tohoto príkladu? Všimnite si jednu dôležitú vec, že kľúč uložený do CSPParameters je možné podľa jeho jedinečného mena, ktoré ste si zvolili Vy (u nás klucJozo), vytiahnúť v ktorejkoľvek časti programu, teda je to GLOBÁLNY KONTAJNER, v rámci celej aplikácie.
A preto je potrebné aj dodržať jeho korektné vymazanie – viď. bod 4 v poznámkach.
Výhody sú
:
Kľúč je bezpečne uloženy v pamäti
Jednoducho dosiahnuteľný podľa mena, t.j. nepredáva sa jeho hodnota medzi metódami ak je potrebná, ale len jeho meno.


>>Čo bude nabudúce?

Predpokladám, že to bude posledný diel o šifrovaní a pozrieme sa na jednu praktickú vec a to bezpečné podpisovanie súborov a to prakticky na príklade, ale samozrejme si povieme aj princíp. Myslím, že sa máte na čo tešiť.
Tie ďalšie diely plánujem, že sa oprieme do C# 3.5, čo poviete? A začali by sme s WorkFlowFondation.

[Iné zdroje]
Codeprojekt:
http://www.codeproject.com/dotnet/ComboEncryption.asp
http://www.codeproject.com/dotnet/SimpleEncryption.asp
http://www.codeproject.com/dotnet/RSACryptoPad.asp
MSDN:
http://msdn2.microsoft.com/en-us/library/ms229746.aspx
http://msdn2.microsoft.com/en-us/library/5e9ft273(VS.71).aspx
http://msdn2.microsoft.com/en-us/library/ms229745(vs.80).aspx
http://msdn2.microsoft.com/en-us/library/ms229746.aspx

Iné:
http://www.dotnet247.com/247reference/msgs/4/23842.aspx
http://www.dotnetspider.com/kb/Article949.aspx
http://www.dotnet247.com/247reference/msgs/4/23842.aspx


[Predchádzajúce diely]

Programujeme v jazyku C# III. Diel 10. – Šifrovanie II
Programujeme v jazyku C# III. Diel 9. – Regulárne výrazy IV
Programujeme v jazyku C# III. Diel 8. – Regulárne výrazy III


SEE YOU!


Autor: Michal Čižmár
micitn@orangemail.sk

Korekcie : Žužu.

Neprehliadnite: