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:
- Otworzenie połączenia z provider'em kryptograficznym
- Utworzenie obiektu mieszającego (hash)
- Wymieszanie za pomocą powyższego obiektu,
naszego tajnego tekstu
- Utworzenie za pomocą naszego wymieszanego obiektu,
klucza kryptograficznego
- 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...
|
|
|
|
|
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
|
|
|
|
|
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..
|
|
|
|
|
a znacie program do odszyfriwania hasła?,,,tzn łamania hasła?
|
|
|
|
|
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.
|
|
|
|
|
~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ł!
|
|
|
|
|
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ę
|