Programujeme v jazyku C# III. Diel 10. – Šifrovanie II

Michal Čižmár  /  22. 08. 2007, 00:00

Keďže nie som odborník na šifrovanie, ale občas sa vyskytne požiadavka niečo jednoducho zašifrovať a zároveň bola už taká téma vyžadovaná v diskusii, tak sa Vám pokúsim ukázať jednoduché príklady.

[Kľúčové slová]
Hash, kľúč, inicializačný vektor IV, symetrické/asymetrické šifrovanie

Ináč..., vitajte pri jubilejnom dieli!!! Tak sa hor do ďalšej desiatky.
Možno, že sa divíte, prečo má tento diel už označenie II, keď jednotka mu nepredchádza.. Ale predchádzala!, lenže niekde v minulej sérii (2005) som ho napísal, ešte keď som bol mladý ;-) kde sa prebrali len základy hashovania.

Z tých základných informácií čo viem, je dôležité to, že spôsob šifrovania sa delí na dve hlavné skupiny. Symetrické – to sú tie štandardné, kde sa používa rovnaké heslo na zašifrovanie aj dešifrovanie.
Asymetrické – s
ú potrebné dva kľúče (heslá). Toto je trochu zložitejšie, tak si to vysvetlíme na príklade: chcete aby Vám ľudia posielali e-maily zašifrované, tak vygeneruje tieto dva kľúče. Verejný niekde zavesí na web, kde si ho ľudia môžu stiahnuť a použiť na zašifrovanie správy pre Vás. Ak by aj správu niekto po ceste odchytil, nehrozí, že by ju rýchlo dešifroval (aj keď, dá sa všetko) pomocou verejného kľúča, lebo dešifrovací kľúč – privátny, vlastníte iba Vy. Tu  si o tom môžete prečítať podrobnejšie.

>>Symetrické šifrovanie
V .net máme nachystané 4 triedy na symetrické šifrovanie:
- DES
- Rijndeal
- RC2
- 3DES (tripleDES) –
viac odporúčané ako DES, kvôli kompatibilite

Nebudeme si tu vysvetľovať ako fungujú jednotlivé algoritmy a dokonca budem taký drzí, že vám vôbec nerozpíšem čo znamenajú jednotlivé skratky, ale radšej ukážem ako tieto už v C# nachystané algoritmy chytiť a použiť, teda opačne ako sa robí v škole :-).
Väčšinou sa odlišujú len rýchlosťou a bezpečnosťou a trochu aj vhodnosťou na aplikovanie na určitý typ dát. Ak Vás to zaujme, môžete začať napr tu:



>>Šifrované Hello World!

Všetky potrebné tiredy,ktoré sú potrené pre šiforvanie sa v .NET nachadzaju v namespace 

System
.Security.Cryptography;
Pozrite si najprv príklad:


Príklad 3.10.1

using
System;
using
System.Security.Cryptography;
//------------------------------------------------------------------
class Program
{
    public static void Main(string[] args)
    {
               
        string
input = "Hello World!";

        System.Text.ASCIIEncoding encoding=new System.Text.ASCIIEncoding();       
        byte [] inputB = encoding.GetBytes(input);
        Console.WriteLine("Vstup:" + input);   

        SymmetricAlgorithm alg = new DESCryptoServiceProvider();

        //Nie je potrebne Generate.. volat,
        //vygeneruje sa to aj samo pri prvej
        // poziadavke na sifrovanie
        // IV = Inicializacny Vector
       
        alg.GenerateIV();   
        alg.GenerateKey();

        // Ulozime si vygenerovane hesla

        byte
[] Key = alg.Key;
        byte[] IV = alg.IV;

        Console.WriteLine("Kluc: " + encoding.GetString(Key));
        Console.WriteLine("Init. Vektor:" + encoding.GetString(IV));

        ICryptoTransform encrypt = alg.CreateEncryptor();
        byte [] output =
              encrypt.TransformFinalBlock(inputB, 0, input.Length);

        Console.WriteLine("Zasifrovane: " +
        encoding.GetString(output));

         ICryptoTransform decrypt = alg.CreateDecryptor();
         byte[] input2    =
             decrypt.TransformFinalBlock(output,0,output.Length );

         string desifrovane = encoding.GetString(input2);
         Console.WriteLine("Desifrovane:" + desifrovane);
         Console.ReadLine();

     }
}

//------------------------------------------------------------------



Príklad je dosť jednoduchý a nechal som tam ja komentáre, jediné čo si musíte všimnúť,že najprv sa vygeneruje trieda, ktorá obsahuje požadovaný šifrovací algoritmus. Parameter kľúč a inicializačný vektor si môžete naplniť sami alebo sa vygeneruje automaticky. Potom stačí vytiahnúť jeden z objektov, podľa toho čo idete robiť, pomocou metód CreteEncryptor alebo CreateDecryptor a ostatné už vidíte v príklade.

Pozn.: Inicializačný vektor, by mal slúžiť na to, že … no ako to zjednodušene povedať..., že slovo sa zašifruje nielen na základe kľúča, ale aj slova, ktoré sa nachádzalo pred ním. Takže to isté slovo je zakaždým zašifrované ináč, v závislosti od toho, kde sa nachádzalo. Prosím, kľudne ma v diskusii opravte alebo doplnte.

>>Vytvorenie kľúču podla zapamätateľného hesla
Ak ste pozorne pozerali predchádzajúci príklad, tak Vám tam určite jedna vec vadí a to, že šifrovací kľúč a inicializačný vektor sa generuje náhodne (ak ho ručne natvrdo nezadáme) a nehrozí si ho pamätať a jedine je ho možné niekam uložiť pre neskoršie dešifrovanie. Bežný užívateľ je ale rád, keď môže použiť ľahko zapamätateľné heslo.
Tak čo, rozmýšľate ako na to? To by sme nežili v 21 storočí, keby už na to nebola vo frameworku pripravená trieda, ktorá to už vie spraviť. Stačí vedieť, len kde hľadať. Pozrite sa na triedu PasswordDeriveBytes. (pozor, je až v .net 2) . Mne ale nevyhovuje, pretože ak chcete dosiahnuť stále ten istý kľúč na základe toho istého hesla ako druhý parameter vyžaduje konštruktor konštantu, alebo náhodné číslo, ktoré potom treba tak či tak niekde uložiť. Keďže my si v príklade spravíme jej obdobu, aspoň uvidíte ako vnútorne funguje.

Príklad 3.10.2

using
System;
using
System.Security.Cryptography;
using
System.Text; // pre Encoding
//-------------------------------------------------------------

class
Program
{
    public static void Main(string[] args)
    {
        Console.Write("Vlozte heslo:");
        string password = Console.ReadLine();

        byte [] key = GenerateKey(password, 100);
        string strKey = BitConverter.ToString(key);

        Console.WriteLine("Vas sifr. kluc bude:");
        Console.WriteLine("Key = {0}",strKey);

        Console.Write("Press any key to continue . . . ");
        Console.ReadKey(true);
     }


     static byte [] GenerateKey(string password, int iterations)
     {


        byte [] passwd = Encoding.ASCII.GetBytes(password);
        HashAlgorithm ha = new MD5CryptoServiceProvider();
        byte [] result = ha.ComputeHash(passwd);

        for(int i = 0; i< iterations - 1 ; i++)
        {
           result = ha.ComputeHash(result);
        }
        return result;

     }

}
//----------------------------------------------------------




Ako vidíte, bolo to jednoduché. Ak potrebujeme z textu (hesla) vygenerovať vždy kľúč o rovnakej dĺžke, tak je na to ideálne použiť Hash. Podľa typu hashu môžme vygenerovať kľúče so žiadanou dĺžkou. V našom príklade sme použili MD5, teda dĺžka bude 128 bitov. Ak by sme chceli 256 alebo 512 bytov, môžeme napr. skúsiť SHA. A keďže vždy exituje možnosť dešifrovania zaheshovaného kľúča pomocou hrubej sily, tak to sťažíme tým, že hash preiterujeme viac krát.

Pozn.: Je to trochu mimo tému,ale odporúčam si všimnút použitie triedy BitConvert. Všímajte, čo pekné sa s ňou dá,vid. príklad hore.


>>Čo bude nabudúce?
Myslím, že budúci diel sa Vám bude páčiť, ukážeme si asymetrické šifrovanie a ako ukážka bude šifrovanie súboru. Takže to bude hlavne o príklade. Môže byť? ;-)

[Predchádzajúce diely]

Programujeme v jazyku C# III. Diel 9. – Regulárne výrazy IV
Programujeme v jazyku C# III. Diel 8. – Regulárne výrazy III
Programujeme v jazyku C# III. Diel 7. – Regulárne výrazy II
Programujeme v jazyku C# III. Diel 6. – Regulárne výrazy I
Programujeme v jazyku C# III. Diel 5. –Všetko o DataSet II.

[Príklady na stiahnutie]
Príklad 3.10.1 -
jednoduché sym.sifrovanie
Príklad 3.10.2 - generovanie kľúča na základe hesla

[Zaujímavé odkazy]

http://www.koders.com/

- nieco podobne spravil uz aj Google, teda vyhľadávanie v zdrojových súboroch, ale toto je trochu viac sofistikovanejšie. Určite stojí za to vyskúšať.

[Iné zdroje]
O šifrovaní trochu učenejšie.

Použitie triedy PasswordDerivedBytes na kompletnom príklade.



SEE YOU!


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

Neprehliadnite: