Powrót do klastra głownego
Informatyka
Programy
Różne rzeczy do ściągnięcia
Programowanie
Moje przygody z Delphi
Jak się ze mną skontaktować
Różne rzeczy do ściągnięciaProgramy
English version  
Szyfrowanie haseł za pomocą CryptoAPI 2.0

Wraz z IE 3.02, Microsoft dodał do swoich standardowych bibliotek, mechanizm szyfrowania zwany CryptoAPI. Dzięki rozbudowanemu interfejsowi można w prosty sposób robić takie rzeczy jak na przykład: szyfrowanie haseł, szyfrowanie danych przesyłanych w sieci, cyfrowe podpisywanie danych, itp.
Ja miałem okazję skorzystać z niektórych funkcji CryptoAPI kiedy pojawiła się konieczność przechowywania haseł w rejestrze.
Algorytm (de)szyfrowania wygląda następująco:
  1. Otworzenie połączenia z provider'em kryptograficznym
  2. Utworzenie obiektu mieszającego (hash)
  3. Wymieszanie za pomocą powyższego obiektu, naszego tajnego tekstu
  4. Utworzenie za pomocą naszego wymieszanego obiektu, klucza kryptograficznego
  5. Zaszyfrowanie lub odszyfrowanie naszego hasła, lub innej wiadomości
Otworzenie połączenia z provider'em kryptograficznym
CryptoAPI w wersji 2.0 zawiera kilka standardowych provider'ów (CSP - Cryptographic Service Providers). Najbardziej standardowy z nich to The Microsoft Base Cryptographic Provider i to właśnie z niego będziemy korzystać. Listę aktualnych provider'ów można znaleźć w rejestrze pod kluczem: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider. Każdy provider należy do jednego z typów. Również w rejestrze można się dowiedzieć do którego typu należy nasz provider. Oczywiście wszystkie te informacje można uzyskać za pomocą odpowiednich funkcji CryptoAPI, o których nie wspomnę tu ani słowem :). W każdym razie, nasz provider należy do typu PROV_RSA_FULL.
Po krótkim wstępie niby-teoretycznym, czas na praktykę. Musimy uzyskać uchwyt do naszego provider'a. Robimy to za pomocą funkcji CryptAcquireContext:
var
  hProv    : HCRYPTPROV;
begin  
  if not CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL, 0) then Exit;
Może się zdażyć, że wywołanie funkcji CryptAcquireContext się nie powiedzie i dostaniemy błąd NTE_KEYSET_NOT_DEF. Wtedy należy wywołać tę fukcję ponownie z flagą CRYPT_NEWKEYSET.
var
  hProv    : HCRYPTPROV;
begin  
  if not CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL, 0) then
     begin
       if GetLastError <> NTE_KEYSET_NOT_DEF then Exit;
       if not CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL, CRYPT_NEWKEYSET) 
          then Exit;
     end;
  


Utworzenie obiektu mieszającego (hash)
Nasz provider zawiera następujące algorytmy mieszające (lub haszujące jak kto woli): MD2, MD5, SHA i MAC. Ja wykorzystywałem tylko MD5, ale chyba nic nie stoi na przeszkodzie aby użyć inne. Do utworzenia obiektu mieszającego, należy wykorzystać funkcję CryptCreateHash. Kod mógłby wyglądać tak:
var
  hHash    : HCRYPTHASH;
begin  
  {...}
  if not CryptCreateHash(hProv, CALG_MD5, 0, 0, @hHash) then Exit;
Uchwyt hHash wskazuje na nasz obiekt mieszający, wykorzystujący algorytm MD5.

Wymieszanie za pomocą powyższego obiektu, naszego tajnego tekstu
Nasz klucz będzie tajny i będzie tylko jeden, zawsze taki sam, nigdzie nie przechowywany. W związku z tym, aplikacja musi mieć możliwość obliczenia klucza za każdym razem, kiedy zachodzi potrzeba zaszyfrowania lub odszyfrowania informacji. Dlatego właśnie stworzyliśmy obiekt mieszający, aby później za pomocą niego wygenerować klucz. Najpierw jednak musimy zamieszać. Ogólnie wygląda to tak, że mamy jakieś tajne hasło (tajny tekst), mieszamy je i tworzymy z niego klucz. Algorytm mieszający działa tak, że przy identycznym wejściu (haśle), generuje zawsze takie same wyjście. Jednak wystarczy zmienić jeden bit w haśle, a wyjście zmieni się diametralnie. A więc do rzeczy, zamieszajmy trochę. Do tego wykorzystamy funkcję CryptHashData. A oto kawałek kodu:
var
  dwLength : DWORD;
  Key      : String;
begin
  {...}
  dwLength := Length(Key);
  if not CryptHashData(hHash, PByte(Key), dwLength, 0) then Exit;
I w ten sposób mamy wymieszany ciąg bitów, który posłuży nam do utworzenia klucza.

Utworzenie za pomocą naszego wymieszanego obiektu, klucza kryptograficznego
Teraz wystarczy utworzyć klucz. Trzeba też podać wg jakiego algorytmu ma się odbywać szyfrowanie. Mamy do dyspozycji następujące algorytmy: RC2 i RC4. Nie dużo tego, ale tyle właśnie szyfrów blokowych udostępnia nasz provider. Funkcja tworząca klucz na podstawie wymieszanego hasła, nazywa się CryptDeriveKey. Kod powinien wyglądać mniej więcej tak:
var
  hKey : HCRYPTKEY;
begin  
  {...}
  if not CryptDeriveKey(hProv, CALG_RC2, hHash, 0, @hKey) then Exit;
W hKey mamy uchwyt do klucza szyfru blokowego RC2.

Zaszyfrowanie lub odszyfrowanie naszego hasła, lub innej wiadomości
Czas na ostatni krok, najbardziej skomplikowany, co nie znaczy że trudny :). Za pomocą funkcji CryptEncrypt/CryptDecrypt musimy zaszyfrować/odszyfrować hasło lub inną wiadomość. Fragment kodu szyfrującego hasło mógłby wyglądać tak:
var
  dwLength : DWORD;
  pbKeyBlob: PByte;
  dwBlobLen: Integer;
  s        : String;
  Password : String;
begin
  {...}
  dwBlobLen := Length(Password);
  CryptEncrypt(hKey, 0, True, 0, nil, @dwBlobLen, 0);

  dwLength  := Length(Password);
  GetMem(pbKeyBlob, dwBlobLen);
  try
    Move(Password[1], pbKeyBlob^, dwLength);
    if not CryptEncrypt(hKey, 0, True, 0, pbKeyBlob, @dwLength, dwBlobLen) then Exit;
    SetLength(s, dwBlobLen);
    Move(pbKeyBlob^, s[1], dwBlobLen);
  finally
    FreeMem(pbKeyBlob);
  end;
Kodu deszyfrującego nie podaję, ponieważ jest jeszcze prostszy. Na koniec należy oczywiście zwolnić wszystkie uchwyty. Służą do tego funkcje: CryptDestroyHash, CryptDestroyKey i CryptReleaseContext.
Jeśli ktoś chce zobaczyć jak to wygląda w moich źródłach to udostępniam tutaj dwa moduły. Jeden, to tłumaczenie wincrypt.h na Pascala, niezbędne do zrobienia czegokolwiek z opisanych tu rzeczy, a drugi zawiera dwie funkcje - jedna do szyfrowania, a druga do deszyfrowania haseł.

To wszystko, miłego szyfrowania, życzy...

Michał Bąkowski


Waszym zdaniem:
[opinie od 1 do 10]

Autor: Makaron 
Trochę trzeba "wklepywać" ale ok. Jeszcze nie wiem Jak działa bo nie wklepałem ale, myśle że spoko
Nie jest to Super Program bo napewno go można...

Autor: Loadspeed 
Hi ,
i want to know if the cryptoapi are used for making the hash
of account password. If i have a string password how can i create its
hash by the api ?

thanx

LOAD

Autor: Forma 
Troche przeginasz,ale chyba sie nie orientujesz..
Rc4 - jest algorytmem strumieniowym, a mozliwosc korzystania z
innych algorytmow tez istnieje- malo tego - jest ich sporo - zarowno
symetrycznych, jak i niesymetrycznych (z kluczem publicznym) - np.IDEA,
SKIPJACK, DES - we wszystkich trybach - zachecam wiec do nauki..

Autor: VEDI 
a znacie program do odszyfriwania hasła?,,,tzn łamania hasła?

Autor: michbak 
Racja, RC4 jest szyfrem strumieniowym. Jesli chodzi o resztę to opisuję tu tylko "Microsoft Base Cryptographic Provider", który nie obsługuje algorytmów IDEA i SKIPJACK.
Obsługuje DES, ale ten jest obsługiwany od Windows 2000. Jak pisałem artykuł - a było to dawno - nie był jeszcze wspierany.

Autor: chris 
~cytuję~
VEDI napisał:
a znacie program do odszyfriwania hasła?,,,tzn łamania hasła?

Jak wiesz złamanie takiego hasła jest praktycznie niemożliwe, jedyną metodą jest brute-force...Jednak jest mało znany program RainbowCrack, a co wiecej na stronie http://passcracking.com/ można podać hasełko do 8 znaków, a tabela RainbowCrackera, ktora mam okolo 47 GB złamie ci za darmo! hasło. Jedak ma to swoje minusy w ciagu doby łamanych jest "tylko" 150 haseł!

Autor: Marcin Graboń 
Programuję długo w Delphi, głównie zawodowo (Huzar Software).
Człowiek uczy się jednak całe życie i na Twojej stronie
znalazłem potrzebne mi informacje. To miło, że ktoś chce się
dzielić swoją wiedzą - dziekuję.

Autor: mika 
wiesz...fajna stronka...i ja si na haslach nie orjetuje ale spoko..ze jest taka stronka......

Autor: Bart 
Stronka ciekawa. Czy autor probowal juz rowniez kompresji strumieniowej? Obecnie poszukuję kompresji w "locie" gdzie nie ma jak normalnie zdekompresowacw postaci pliku (dane sa zbyt duze lecz skompresowane zmiescilyby sie na dysku. Moze ktos mi odpisze. Dziekuję

fajoeskiw

[opinie od 1 do 10]

Nick/Pseudo/Imię i nazwisko:
Adres e-mail:
Twoje zdanie:
Aby udowodnić, że jesteś człowiekiem myślącym, powiedz ile jest siedem razy dziewięć:



To już 147300 odwiedziny od 24 października 1999

© Copyright 1999-2007, Michał Bąkowski
Najlepszy weterynarz w Szczecinie! Szczecin, Chopina 53A. Jedyny w swoim rodzaju czytnik RSS! Oprogramowanie do optymalizacji rozkroju! Optymalizacja rozkroju. Drzwi drewniane, okna drewniane, luksusowe okna, luksusowe drzwi, stolarka budowlana. Słupsk. Kobylnica.