Niniejszy, krótki artykuł poświęcony jest podstawom związanym z zabezpieczeniem przesyłanych informacji przy pomocy podpisu elektronicznego. Do wygenerowania podpisu zostanie wykorzystany algorytm RSA. Według Polskiej Wikipedii RSA, to pierwszy i obecnie jeden z dwóch najpopularniejszych (obok ElGamala) algorytmów kryptografii asymetrycznej. Został stworzony w 1978 przez zespół: Ronald Rivest, Adi Shamir, Leonard Adleman (nazwa RSA jest akronimem utworzonym z pierwszych liter nazwisk jego twórców). RSA opiera się na trudności faktoryzacji dużych liczb. Znalezienie szybkiej metody faktoryzacji doprowadziłoby do złamania RSA, aczkolwiek nie ma dowodu, że nie da się go złamać w inny sposób. Do generacji kluczy, podpisu i jego weryfikacji, zostaną wykorzystane klasy wbudowane w .NET Framework.
Generowanie kluczy
Przed przystąpieniem do podpisywania wiadomości, czy późniejszej weryfikacji potrzebna jest para kluczy: prywatny i publiczny. Klucze te mogą pochodzić z certyfikatu zainstalowanego w systemie, jak również można je wygenerować samodzielnie. Przed przystąpieniem do generacji kluczy, należy utworzyć bezpieczny pojemnik na klucze - wykorzystamy do tego klasę CspParameters, w której po inicjacji należy ustawić nazwę kontenera (KeyContainerName). Następnie tworzymy obiekt klasy RSACryptoServiceProvider, który jest dostawcą implementacji algorytmy RSA na platformie .NET. Z tak utworzonego obiektu możemy wyeksportować sobie klucze (publiczny i prywatny), format w jakim eksportujemy te klucze w zasadzie może być dowolny. W poniższym przypadku jako format przechowywania kluczy został wybrany format XML. Poniższy przykład generuje klucze, które ostatecznie zapisuje (w postaci XML) w dwóch string’ach. Pierwszy zwiera część prywatną i publiczną (zostanie wykorzystany do podpisania wiadomości), drugi zawiera tylko część publiczną (wykorzystany zostanie do weryfikacji podpisu).
// Declare a CspParameters variable, which will identify the // key container in which the recipients PRIVATE KEY is stored. CspParameters csp = new CspParameters(); csp.KeyContainerName = "MyKeys"; // Initialize an RSACryptoServiceProvider object using // the CspParameters object. RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp); //XML representation of the key (public and private part is included): string private_part = rsa.ToXmlString(true); //XML representation of the key (only public part is included): string public_part = rsa.ToXmlString(false);
Podpisywanie wiadomości
Wygenerowaliśmy wcześniej klucze, teraz można przejść do podpisania wiadomości. W tym celu wykorzystamy klasę RSACryptoServiceProvider, której obiekt zainicjujemy, a następnie zaimportujemy do niego wygenerowany wcześniej klucz (publiczny i prywatny) przy pomocy metody: FromXmlString.. Następnie wybieramy algorytm hash’ujący, do najpopularniejszych należą SHA1 i MD5. Kolejnym krokiem jest przygotowanie wiadomości do wysłania, zakładając że pierwotnie jest to string, zamieniamy go na ciąg byte’ów (np. przy pomocy metody GetBytes klasy ASCIIEncoding). Ostatecznie generujemy podpis przy pomocy SignData klasy RSACryptoServiceProvider.
RSACryptoServiceProvider rsa_with_private = new RSACryptoServiceProvider(); rsa_with_private.FromXmlString(private_part); //selection the algorithm: //const string algorithm = "SHA1"; const string algorithm = "MD5"; // Create some data to sign. string message = @"Hello World! Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec euismod neque. Nam quam orci, ultrices vitae viverra vel, vehicula at purus. Integer tincidunt venenatis neque, eget commodo neque molestie at. Aenean porttitor elementum nisi, a scelerisque urna pulvinar vitae. "; byte[] data = (new System.Text.ASCIIEncoding()).GetBytes(message); // Sign the data using the Smart Card CryptoGraphic Provider. byte[] sig = rsa_with_private.SignData(data, algorithm);
Weryfikacja podpisu
Podpisaliśmy wcześnie wiadomość, przesyłamy ją razem z podpisem, a teraz czas na weryfikację podpisu. W tym celu inicjujemy obiekt klasy RSACryptoServiceProvider, do którego przekazujemy (podobnie jak wcześniej) klucz (tym razem tylko jego część publiczną i weryfikujemy podpis przy pomocy metody VerifyData.
RSACryptoServiceProvider rsa_only_public = new RSACryptoServiceProvider(); rsa_only_public.FromXmlString(public_part); // Verify the data using the Smart Card CryptoGraphic Provider. bool verified = rsa_only_public.VerifyData(data, algorithm, sig);
Podsumowanie
W tym artykule starałem się nie wchodzić za bardzo w szczegóły algorytmów, czy metod bezpiecznego przechowywania kluczy. Moim celem było pokazanie procedury podpisywania wiadomości w sposób jak najbardziej prosty. Mam nadzieję że to mi się udało.
Gneracja kluczy, a nic nie ma o generacjach. A może chodziło o generowanie?
OdpowiedzUsuńDziękuję za sugestię językową ;)
OdpowiedzUsuńjuż poprawiłem
mam pewien problem - tworzę parę kluczy jak w powyższym przykładzie, jednak za każdym razem są to takie same klucze - błąd u mnie czy jakaś nieścisłość tutaj?
OdpowiedzUsuńPozdrawiam
Może i można uznać, że w powyższym post'cie jest pewna nieścisłość (a może raczej "niedopowiedzenie"), mam nadzieję że moim dzisiejszym post'cie znajdziesz rozwiązanie: Maciej Zbrzezny: Programowanie i Technologie: Bezpieczne przechowywanie pary kluczy algorytmu RSA na platformie .NET (przykłady w C#)
OdpowiedzUsuńBardzo fajny artykuł.
OdpowiedzUsuń