Przegląd technik kryptograficznych w zabezpieczaniu urządzeń elektronicznych

| Technika

Kryptografia jest dziedziną kryptologii, która obejmuje zagadnienia z zakresu utajniania informacji w celu zabezpieczenia ich przed nieuprawnionym dostępem. Jej mechanizmy są powszechnie wykorzystywane w systemach komputerowych do ochrony przechowywanych w nich danych oraz w komunikacji sieciowej. W artykule przedstawiamy funkcje oraz techniki kryptografii wykorzystywane w urządzeniach elektronicznych. Analizujemy także zagrożenia, którym można dzięki nim zapobiec.

Przegląd technik kryptograficznych w zabezpieczaniu urządzeń elektronicznych

Ostrzeżenia przed nowymi wirusami, które atakują komputery i urządzenia mobilne, i informacje o przypadkach różnego rodzaju naruszeń bezpieczeństwa, takich jak na przykład: włamania na strony internetowe, blokowanie ich działania przez ataki typu DDoS (Distributed Denial of Service), kradzieże danych uwierzytelniających (loginu, hasła) zapewniających dostęp na przykład do bankowości elektronicznej oraz włamania do sieci bezprzewodowych, pojawiają się w zasadzie codziennie.

Co jakiś czas dochodzi także do poważniejszych incydentów, w których przestępcy za cel ataku wybierają obiekty przemysłowe. Jak do tej pory najgłośniejszym tego typu przypadkiem było wprowadzenie do lokalnej sieci w elektrowni nuklearnej w Iranie wirusa Stuxnet. To złośliwe oprogramowanie miało za zadanie przeprogramować sterowniki PLC sterujące pracą instalacji w tym zakładzie. Na szczęście na skutek działania robaka nie doszło do katastrofy jądrowej, a jedynie do zakłóceń w działaniu wirówek, które są używane do wzbogacania uranu.

Był to dotychczas najsłynniejszy, ale niestety niejedyny taki incydent. Zarówno przed, jak i po wykryciu wirusa Stuxnet w 2010 roku, miało miejsce wiele podobnych ataków. Przykładowo w 2003 roku wirus SQL Slammer zablokował system SCADA jednej z amerykańskich elektrowni jądrowych. W 2015 roku hakerzy spowodowali natomiast awarię sieci energetycznej na Ukrainie.

Celów ataków będzie przybywać

Rys. 1. Bezpieczny firmware wymaga podpisu cyfrowego

Ponieważ coraz więcej urządzeń jest łączonych w sieci i korzysta z Internetu, wraz z rozwojem Internetu Rzeczy, smart grid, czyli inteligentnych sieci elektroenergetycznych i wprowadzeniem do użytku samochodów autonomicznych, celów ataków hakerskich będzie przybywać. Skutkami ich działania będą nie tylko straty materialne, lecz zagrożone będzie też ludzkie zdrowie i życie. Kwestię bezpieczeństwa konstruktorzy elektroniki powinni więc traktować bardzo poważnie, wykonując analizę ryzyka dla danej aplikacji, a następnie, na jej podstawie, wybierając zabezpieczenia w danym przypadku najskuteczniejsze.

Warto przy tym przyjąć założenie, że pomimo nawet najlepszej ochrony, jeżeli urządzenie znajdzie się na celowniku hakerów o odpowiedniej motywacji, wiedzy oraz doświadczeniu, dysponujących odpowiednim sprzętem oraz nieszczędzących czasu ani sił, możliwe jest pokonanie przez nich w zasadzie każdego zabezpieczenia.

Mając tego świadomość, należy oszacować i zestawić ze sobą koszty i wysiłek, jaki jest wymagany do zaimplementowania wybranych zabezpieczeń z wartością zasobów, które mają one chronić (na przykład informacji, kodu źródłowego, usług sieciowych, infrastruktury sieciowej) oraz kosztów, jakie pociągnie za sobą złamanie tych zabezpieczeń.

Klasyfikacja zagrożeń

Zagrożenia można podzielić ogólnie na kilka grup. Pierwszą z nich są ataki zdalne dokonywane za pośrednictwem sieci, przewodowych i bezprzewodowych. Są popularne ze względu na wciąż rosnącą liczbę urządzeń łączonych w sieci i podłączanych do Internetu.

Sprzyja im także specyfika segmentowych topologii sieci komputerowych oraz warstwowych protokołów komunikacyjnych, z powodu której przestępcy mają do wyboru wiele newralgicznych punktów i dróg, którymi mogą je zaatakować. Oprócz tego atakujący nie musi się znajdować tam, gdzie atakowany zasób ani nawet w jego pobliżu, dzięki czemu łatwiej może zachować anonimowość.

Ataki za pośrednictwem sieci mogą przyjmować różnorakie formy. Są to m.in.: podsłuchiwanie w celu przechwycenia przesyłanych wiadomości, podsłuchiwanie i modyfikowanie wiadomości, na przykład w celu podszycia się pod jedną ze stron, które się ze sobą łączą, na przykład, by wykraść dane albo przedstawić nieprawdziwe informacje zamiast tych właściwych, przeprowadzenie ataku typu DoS (Denial of Service) lub DDoS (Distributed Denial of Service), zainfekowanie złośliwym oprogramowaniem.

Kolejnym typem zagrożenia są ataki na poziomie urządzenia, inwazyjne i nieinwazyjne. Te drugie polegają zwykle na obserwacji urządzenia lub manipulowaniu nim, jednak bez doprowadzenia do jego fizycznego uszkodzenia ani bezpośredniej w niego ingerencji. Dzieli się je na trzy grupy. Do pierwszej zaliczane są obserwacja i analiza zmian sygnałów w trakcie wykonywania operacji kryptograficznych, na przykład emisji zaburzeń elektromagnetycznych albo zużycia prądu.

Przegląd zagrożeń. Funkcje kryptografii

Do drugiej grupy należy zmienianie warunków pracy albo w otoczeniu urządzenia w taki sposób, by spowodować jego nieprawidłowe działanie, przez co nie będą również skuteczne zastosowane zabezpieczenia. Przykładowe działania to: celowe wprowadzanie zakłóceń, podłączanie napięcia zasilania o wartości przekraczającej dopuszczalny poziom, przekraczanie dopuszczalnej temperatury pracy (podgrzanie lutownicą MCU), wysyłanie zbyt krótkich impulsów zegarowych.

Do trzeciej grupy zaliczane są z kolei ataki polegające na zainfekowaniu urządzenia złośliwym oprogramowaniem za pośrednictwem interfejsów komunikacyjnych dostępnych w danym urządzenia, jak na przykład JTAG czy USB.

Ataki na poziomie urządzenia przeprowadzane inwazyjnie wymagają na przykład usunięcia jego obudowy. Kolejnym typem zagrożenia są ataki na poziomie pojedynczego układu scalonego. Ich celami są często inżynieria wsteczna i chęć wykradzenia danych, na przykład kluczy szyfrujących, których znajomość umożliwia przeprowadzenie na przykład ataku sieciowego.

Wiele z zagrożeń, zwłaszcza tych związanych ze zdalnym dostępem, można zmniejszyć, implementując mechanizmy kryptograficzne. Wyróżnia się kilka ich funkcji.

Pierwszą przychodzącą na myśl jest zapewnienie poufności informacji. Kolejna to uwierzytelnianie. Mechanizmy kryptograficzne gwarantują też integralność danych i zapobiegają przekłamaniom w zakresie przebiegu oraz wyniku procesu wymiany danych.

Poufność i uwierzytelnianie

Przez zapewnienie poufności informacji mechanizmy kryptograficzne gwarantują, że wyłącznie upoważnieni użytkownicy będą mogli je odczytać. Jeśli poufność nie jest zapewniona, na przykład w przypadku komunikacji sieciowej, każdy, kto ma dostęp do sieci i jest w stanie monitorować ruch sieciowy i przechwytywać transmitowane dane, będzie je także mógł bez problemu zrozumieć. Z kolei w przeciwieństwie do otwartego tekstu informacje zaszyfrowane nawet po przechwyceniu przez osoby nieuprawnione, które nie znają szyfru dostępnego użytkownikom autoryzowanym, pozostaną dla tych pierwszych całkowicie bezużyteczne.

Kolejną funkcją mechanizmów kryptograficznych jest uwierzytelnianie polegające na weryfikacji tożsamości podmiotów, które na przykład komunikują się ze sobą za pośrednictwem sieci. Dzięki zidentyfikowaniu nadawcy oraz odbiorcy wiadomości, na przykład na podstawie przedstawionych przez nich certyfikatów, które uzyskali od instytucji niezależnych lub podanych przez nich danych uwierzytelniających, nie jest możliwe, by pod którąkolwiek z tych stron mógł podszyć się ktoś inny.

Integralność i przekłamania

Integralność informacji jest z kolei gwarantowana przez sprawdzenie, czy ich oryginalna treść nie została zmodyfikowana lub uszkodzona. W tym celu danemu zbiorowi danych przypisywana jest unikalna, zależna od jego zawartości, wartość. Jest ona znana odbiorcy wiadomości. Osoba, która nie ma do tego uprawnień, zmieniając jej oryginalną treść, modyfikuje też tę wartość. Porównując ją z tą oczekiwaną, odbiorca może wykryć, że doszło do niepożądanej ingerencji z zewnątrz.

Ponadto, jeżeli działają mechanizmy kryptograficzne, nie dojdzie do sytuacji, w której którakolwiek ze stron komunikacji mogłaby się dopuścić jakiegokolwiek przekłamania na temat przebiegu i/albo wyniku tego procesu. Oznacza to, że nadawca nie może zaprzeczyć, że wysłał dany komunikat lub stwierdzić, że zrobił to w innym czasie niż w rzeczywistości, zaś odbiorca nie może się wyprzeć, że wiadomość tę w danym momencie odebrał. Dowodami są na przykład: sygnatury czasowe i podpisy cyfrowe.

Wyróżnić można kilka mechanizmów kryptograficznych. W systemach komputerowych do ochrony przechowywanych w nich danych i w komunikacji sieciowej korzysta się z nich niezależnie lub opiera zabezpieczenia na kilku z nich jednocześnie. Dalej przedstawiamy najpopularniejsze, wybrane, techniki: szyfrowania z kluczem, funkcje skrótu i podpis cyfrowy.

Szyfrowanie z kluczem

Jednym z podstawowych mechanizmów kryptograficznych są algorytmy szyfrowania z kluczem, który jest używany do szyfrowania informacji jawnych, a potem odszyfrowywania danych zaszyfrowanych. Można je podzielić na dwie grupy. Pierwszą z nich stanowią algorytmy symetryczne, natomiast drugą algorytmy asymetryczne z kluczem publicznym.

Do grupy algorytmów symetrycznych zaliczane są techniki, w których szyfrując i deszyfrując dane, używa się tego samego klucza lub w przypadku gdy w obu tych operacjach wykorzystuje się dwa różne klucze, na podstawie jednego z nich można wyznaczyć ten drugi. Klucz w algorytmie symetrycznym nazywany jest tajnym (prywatnym), gdyż znają go tylko nadawca i odbiorca wiadomości.

W szyfrowaniu asymetrycznym do szyfrowania i deszyfrowania danych używa się różnych kluczy. Wymagane są dwa: klucz prywatny oraz klucz publiczny. Pierwszy z nich jest znany tylko jego właścicielowi, natomiast klucz publiczny jest udostępniany wszystkim. Klucze prywatny oraz publiczny są różne, ale komplementarne. To oznacza, że informacje zaszyfrowane przy użyciu danego klucza publicznego mogą zostać odszyfrowane tylko z wykorzystaniem odpowiadającego mu klucza prywatnego.

Jeśli osoba nieupoważniona pozna klucz prywatny, może odczytać treść wiadomości zaszyfrowanej symetrycznie. Wtedy poufność informacji nie będzie zapewniona. Oprócz tego, jeżeli obie strony komunikujące się ze sobą posługują się tym samym kluczem, nie można udowodnić, która z nich jest nadawcą, a która odbiorcą wiadomości.

Z drugiej strony szyfrowanie symetryczne jest szybsze niż szyfrowanie z kluczem publicznym, nawet o kilkaset razy. To drugie charakteryzuje też większa złożoność obliczeniowa. Ponieważ przez to bardziej obciąża procesor, zamiast niego do szyfrowania większych ilości informacji chętniej wybierane jest szyfrowanie symetryczne.

Bezpieczne chipy

Dla potrzeb tworzonych aplikacji IoT, elektroniki przemysłowej i innych nowoczesnych rozwiązań wykorzystujących komunikację w sieciach producenci tworzą w ostatnim okresie specjalizowane rozwiązania specjalnych układów scalonych, zapewniających bezpieczne przechowywanie kluczy, szyfrowanie i uwierzytelnianie.

Są one oferowane jako samodzielny produkt lub wbudowywane do wnętrza mikrokontrolerów. Takie rozwiązania w ostatnich miesiącach pojawiły się w ofertach firm Microchip, ST Micro, NXP, Infineon i innych. Poniżej pokazujemy skrócone charakterystyki dwóch takich rozwiązań.

ATECC608A

ATECC608A to chip autoryzacyjny firmy Microchip z algorytmami sprzętowymi opartymi na krzywych eliptycznych realizujący:

  • bezpieczne generowanie kluczy: RNG (Random Number Generator) kompatybilny ze standardem Federal Information Processing Standard (FIPS) generuje unikalne klucze zgodne z ostatnimi wymogami NIST, ułatwiając uzyskanie certyfikacji FIPS dla całego systemu,
  • walidację sygnatury podpisu oprogramowania firmware w aplikacjach z małymi mikrokontrolerami, takimi jak ARM Cortex-M0+,
  • zaufaną autoryzację węzłów sieci LoRa: silnik AES-128 umożliwia również wdrażanie zabezpieczeń dla infrastruktury LoRa poprzez uwierzytelnianie zaufanych węzłów sieciowych,
  • szybsze przetwarzanie danych: algorytmy sprzętowe oparte na krzywych eliptycznych (ECC - Elliptical Curve Cryptography) generują mniejsze klucze i tworzą certyfikowane źródło zaufania szybciej i w bezpieczniejszy sposób niż w przypadku implementacji bazujących na starszych metodach,
  • zabezpieczenia antysabotażowe: techniki zapobiegania naruszaniu zabezpieczeń chronią klucze przed fizycznymi atakami i próbami włamań już po wdrożeniu systemu. Zapewniają zachowanie bezpiecznej i zaufanej tożsamości.

A1006

Z kolei A1006 Secure Authenticator NXP Semiconductors to układ autoryzacyjny dla urządzeń przenośnych i systemów embedded. Układ ten, zapewniający silną autoryzację opartą na asymetrycznym protokole z krzywymi eliptycznymi oraz odporność na ataki inwazyjne i nieinwazyjne, stanowi doskonałe zabezpieczenie przed fałszowaniem produktów. Oferuje zaawansowane funkcje zabezpieczeń, w tym generator rzeczywistych liczb losowych (TRNG), aktywne ekranowanie, sensory bezpieczeństwa i wiele innych.

A1006 komunikuje się za pośrednictwem interfejsu I²C lub jednożyłowego. Zawiera 4 Kb pamięci EEPROM do przechowywania dwóch certyfikatów, danych systemowych i danych użytkownika. Pobiera średnio 50 μA prądu zasilania w stanie aktywnym i 3 μA w trybie deep sleep (3,3 V). Jest zamykany w miniaturowej obudowie WLCSP-4 o powierzchni wynoszącej zaledwie 1 mm² i grubości 0,5 mm.

Przykłady algorytmów symetrycznych

Jednym z popularniejszych algorytmów asymetrycznych jest RSA. Przykładem algorytmu symetrycznego jest z kolei DES (Data Encryption Standard). Jest to szyfr blokowy operujący na 64-bitowych blokach. Klucz składa się z 64 bitów, lecz w praktyce wykorzystuje się 56 bitów, zaś 8 pozostałych jest bitami parzystości. Na każdym z bloków wykonywanych jest kilka operacji.

Najpierw bity bloku są w sposób losowy przestawiane. Następnie dzieli się go na dwie równe, liczące po 32 bity, części. Dalej 16-krotnie powtarza się zbiór operacji, które w uproszczeniu polegają na przesuwaniu i podstawianiu bitów danych i klucza, co ma na celu ich połączenie.

W kolejnym kroku obie części bloku są ze łączone, a na koniec ponownie, lecz odwrotnie niż w pierwszym etapie, bity bloku są znów przestawiane. Deszyfrowanie polega na wykonaniu takich samych operacji, lecz w odwrotnej kolejności.

Algorytm DES można zaimplementować w trybach blokowych, ECB (Electronic CodeBook) lub CBC (Cipher Block Chaining), które najlepiej sprawdzają się w szyfrowaniu gotowych danych, a gorzej w przypadku tych o nieznanej z góry ilości i szybkości pojawiania się, w utajnianiu których wykorzystuje się tryby strumieniowe: CFB (Cipher FeedBack) i OFB (Output FeedBack).

Obecnie algorytm DES nie jest już uważany za silne zabezpieczenie. Jego następcą jest standard AES (Advanced Encryption Standard) bazujący na algorytmie Rijndeal. Szyfr ten jest szybszy i trudniej go złamać niż DES. Do tytułowej kategorii algorytmów zaliczane są również szyfry blokowe: RC2, RC5 i RC6 oraz szyfr strumieniowy: RC4.

Funkcje skrótu

Funkcje skrótu, inaczej funkcje mieszające lub funkcje haszujące, są funkcjami matematycznymi, które przetwarzają zbiór informacji w celu przypisania mu unikalnej, zależnej od jego zawartości, wartości, tzw. skrótu, inaczej sygnatury. Przeważnie ma ona długość 128-160 bitów. Identyczne zbiory danych mają takie same sygnatury, zaś zmiana nawet pojedynczego bitu w jednym z nich powoduje modyfikację odpowiadającego mu skrótu.

Ponieważ sygnatury są znacznie krótsze niż wiadomości, a funkcje skrótu zwracają skończenie wiele ich wartości, możliwe jest wystąpienie kolizji. Wtedy dwie różne informacje mogą mieć identyczną sygnaturę. W przypadku funkcji mieszających do zastosowań kryptograficznych powinno to być jednak praktycznie niemożliwe. Oprócz tego zagwarantowana musi być jednokierunkowość. Dzięki niej nie jest wykonalne odczytanie wiadomości wejściowej na podstawie jej skrótu.

Funkcje haszujące w połączeniu z szyfrowaniem z kluczem publicznym są wykorzystywane m.in. do generowania podpisów cyfrowych. Realizują one trzy z wymienionych funkcji bezpieczeństwa: weryfikują komunikujące się podmioty, zapewniają integralność danych oraz gwarantują niezaprzeczalność, na przykład autorstwa danej wiadomości.

Przykładami funkcji skrótu są: MD5 i SHA-1. Pierwsza tworzy sygnaturę o długości 128, a druga 160 bitów. SHA-1 zapewnia większy poziom bezpieczeństwa, ponieważ tworzy dłuższe skróty, odporne na niektóre ataki, na które podatne są sygnatury wygenerowane przez funkcję MD5. Niestety obecnie ani MD5, ani SHA-1 nie są już zalecane do użycia w nowych projektach. Bezpieczniejsze są funkcje SHA-2 oraz SHA-3.

Cyfrowy podpis

Jeżeli chodzi o wspomniany wcześniej cyfrowy podpis, to dwie najpopularniejsze techniki jego generowania i weryfikacji to RSA oraz DSA (Digital Signature Security Standard). W pierwszej sygnatura wiadomości jest szyfrowana z wykorzystaniem klucza prywatnego. Szyfrogram ten jest następnie przesyłany razem z wiadomością do jej odbiorcy.

Aby zweryfikować prawdziwość odebranych danych, które zostały cyfrowo podpisane, ich adresat generuje dla nich nowy skrót. Następnie wykorzystując klucz publiczny nadawcy, odszyfrowuje odebraną sygnaturę. Jeżeli oba skróty są identyczne, autentyczność wiadomości zostaje potwierdzona. Równocześnie weryfikowana jest tożsamość nadawcy. Dane, które zostały zaszyfrowane przy użyciu danego klucza prywatnego, można bowiem odszyfrować wyłącznie posługując się odpowiadającym mu kluczem publicznym.

Choć algorytm DSA jest podobny do RSA, pod pewnymi względami zasadniczo się od niego różni. Przede wszystkim w tym pierwszym nie szyfruje się sygnatury przy użyciu klucza prywatnego ani nie deszyfruje się jej, posługując się kluczem publicznym. W zamian w DSA wykorzystywana jest specjalna funkcja, która generuje cyfrowy podpis składający się z dwóch 160-bitowych ciągów wyznaczanych na podstawie skrótu wiadomości oraz klucza prywatnego. Do zweryfikowania sygnatury, jak w przypadku RSA, także używa się klucza publicznego, jednak to zadanie jest realizowane w DSA w dużo bardziej złożony sposób.

Kryptografia w praktyce - przykład

Przykładem sytuacji, w której wymagane jest zaimplementowanie dwóch funkcji bezpieczeństwa: weryfikacji autentyczności danych i ich integralności, jest instalacja albo aktualizacja firmware'u, w urządzeniach wbudowanych. Łatwo przewidzieć, jakie groźne konsekwencje może za sobą pociągnąć udana próba ingerencji hakerów w to oprogramowanie.

Mogą oni m.in.: wpływać na funkcjonowanie urządzenia albo nawet przejąć nad nim całkowitą kontrolę. Dzięki temu mogą przykładowo sprawić, że zacznie ono upubliczniać krytyczne dane. W czasie upowszechniania się elektroniki noszonej, zwłaszcza tej w zastosowaniach medycznych, takie działanie na przykład w przypadku mierników parametrów życiowych stwarzałoby poważne zagrożenie dla prywatności użytkowników.

Innym przykładem są urządzenia do monitorowania pomieszczenia, w którym przebywa dziecko, na odległość. Haker włamywacz, który odpowiednio przeprogramuje tzw. elektroniczną nianię, może na przykład za jej pośrednictwem podsłuchiwać i/lub podglądać to, co się dzieje w domu, dzięki czemu może na przykład sprawdzać, czy w danym momencie ktoś w nim przebywa.

W dobie upowszechniania się Internetu Rzeczy niebezpieczna mogłaby także być sytuacja, w której hakerzy spowodują, że urządzenie będzie działało nieprawidłowo albo w sposób nieprzewidywalny. Łatwo można sobie wyobrazić skutki rozregulowania przez przestępców na przykład systemu automatyki domowej, do którego włamali się, przeprogramowując jeden z jego elementów.

Aby takich sytuacji uniknąć, należy zadbać o to, by oprogramowanie instalowane lub aktualizowane pochodziło z pewnego źródła i nie zostało później zmodyfikowane przez osoby nieuprawnione. W tym celu firmware instalowany na etapie produkcji i wszelkie jego kolejne aktualizacje powinny być podpisywane cyfrowo.

Dylemat

Przykładowa realizacja mogłaby zakładać zastosowanie szyfrowania asymetrycznego. W takim przypadku twórca oprogramowania podpisywałby je, używając klucza prywatnego, natomiast w pamięci urządzenia zapisywany byłby klucz publiczny używany następnie do weryfikacji. Dzięki temu haker nie byłby w stanie poznać klucza prywatnego, nawet przeprowadzając atak inwazyjny.

W taki sposób mógłby on co najwyżej uzyskać dostęp do bezużytecznego, z jego punktu widzenia, klucza publicznego. Problemem na etapie wdrożenia takiego mechanizmu zabezpieczającego mogą okazać się ograniczone możliwości urządzenia w zakresie jego wydajności obliczeniowej. Wówczas konstruktor staje przed dylematem, czy ochronę zrealizować programowo, czy sprzętowo.

W wielu przypadkach implementacja sprzętowa jest lepszym wyjściem, na przykład wtedy, gdy przetwarzane mają być duże ilości danych. W zależności od tego, jakie parametry charakteryzują blok sprzętowy wykorzystywany w tym celu, możliwe jest, że będą one przetwarzane szybciej niż w razie realizacji programowej. Oprócz tego, jeśli operacje kryptograficzne nie obciążają głównego procesora, nie zakłóca to pracy innych jednocześnie działających aplikacji. Implementacja sprzętowa może być jednak droższa.

Podsumowanie

Systemy i sieci komputerowe zabezpiecza się, w zależności od potrzeb, jednym lub jednocześnie za pomocą wielu mechanizmów kryptograficznych. Największą skuteczność uzyskuje się, korzystając z nich w ramach ich możliwości i ograniczeń. Trzeba również pamiętać, że mimo nawet najlepszej ochrony, bezpieczeństwo systemu jest zdeterminowane przez jego najsłabsze ogniwo, którym jest zazwyczaj człowiek. Dobrze ilustruje to przykład z życia codziennego - szyfrowanie informacji przesłanych e-mailem okaże się bezużyteczne, jeżeli jego odbiorca zapisze je na komputerze w postaci jawnej albo ich wydruki będą łatwo dostępne dla każdego.

Monika Jaworowska

Zobacz również