|
8 | 8 |
|
9 | 9 | Implementację wykonałem w środowisku .NET Core, w języku C#.
|
10 | 10 |
|
11 |
| -Wyrocznia została zaimplementowana w formie klasy [RemoteServerMock](RemoteServerMock.cs), zawierającej dwie kluczowe metody: Encrypt – szyfrującą przesłany ciąg znaków, IsPaddingCorrect – zwracającą informację, czy podczas deszyfrowania podanego szyfrogramu nastąpił błąd w związku z niepoprawnym dopełnieniem bloku. Szczegóły algorytmu szyfrowania, poza wykorzystywanym schematem dopełniania, nie są dostępne na zewnątrz klasy. |
| 11 | +Wyrocznia została zaimplementowana w formie klasy [`RemoteServerMock`](RemoteServerMock.cs), zawierającej dwie kluczowe metody: `Encrypt` – szyfrującą przesłany ciąg znaków, `IsPaddingCorrect` – zwracającą informację, czy podczas deszyfrowania podanego szyfrogramu nastąpił błąd w związku z niepoprawnym dopełnieniem bloku. Szczegóły algorytmu szyfrowania (klucz, wektor inicjujący), poza wykorzystywanym schematem dopełniania i trybem działania algorytmu (CBC), nie są dostępne na zewnątrz klasy. |
12 | 12 |
|
13 |
| -Algorytm deszyfrujący pojedynczy blok znajduje się w klasie [PaddingOracleDecryptor](PaddingOracleDecryptor.cs). Funkcja DecryptBlock przyjmuje jako argumenty blok do deszyfrowania oraz poprzedni, w formie tablic bajtów. Metoda polega na uzyskaniu kolejnych bajtów stanu pośredniego (I2 na rysunku poniżej) i wykorzystania ich do wyznaczenia kolejnych bajtów tekstu jawnego. Korzystając z wiedzy o (braku) poprawności dopełnienia po odszyfrowaniu, dostarczanej przez Wyrocznię, można za pomocą przesyłania do niej odpowiednio zmanipulowanego szyfrogramu, składającego się ze specjalnie przygotowanego bloku poprzedzającego i bloku, który pragnie się odszyfrować, uzyskać informację, dla jakiej wartości i-tego bajtu w zmanipulowanym bloku poprzedzającym wypełnienie jest poprawne. Zmanipulowany poprzedni blok C’1 początkowo może mieć dowolne wartości, poza ostatnią, którą należy iteracyjnie zmieniać. W momencie, gdy dla zmanipulowanego szyfrogramu Wyrocznia nie zwróci błędu dopełnienia, znana jest wartość i-tego (w tym wypadku pierwszego) bajtu z C’1, która w operacji xor z wartością i-tego bajtu stanu pośredniego I2 daje znaną wartość bajtu w tekście jawnym (np. w przypadku dopełnienia o długości 1, pierwszy bajt od końca w schemacie PKCS7 będzie miał wartość 1). Można więc uzyskać wartość stanu pośredniego na i-tej pozycji, a xorując ją z i-tym bajtem rzeczywistego poprzedniego bloku szyfrogramu, i-ty bajt tekstu jawnego P2. Korzystając z właściwości funkcji xor, należy następnie zamienić wartość i-tego bajtu zmanipulowanego bloku na taką, aby w otrzymywanym tekście jawnym na i-tej pozycji znalazła się wartość odpowiednia dla dopełnienia o jeden dłuższego (w PKCS7 dla wypełnienia o długości 2 jest to 2 – nowa wartość powinna więc równać się noweC’1[i] = C’1[i] xor 1 xor 2). Następnie opisaną pętlę powtarza się dla bajtu i-1, kolejnego „na lewo”, i kolejnych aż do początku bloku. |
| 13 | +Algorytm deszyfrujący pojedynczy blok znajduje się w klasie [`PaddingOracleDecryptor`](PaddingOracleDecryptor.cs). Funkcja `DecryptBlock` przyjmuje jako argumenty blok do deszyfrowania oraz poprzedni, w formie tablic bajtów. Metoda polega na uzyskaniu kolejnych bajtów stanu pośredniego (I2 na rysunku poniżej) i wykorzystania ich do wyznaczenia kolejnych bajtów tekstu jawnego. Korzystając z wiedzy o (braku) poprawności dopełnienia po odszyfrowaniu, dostarczanej przez Wyrocznię, można przesyłając do niej odpowiednio zmanipulowany szyfrogram, składający się ze specjalnie przygotowanego bloku poprzedzającego i bloku, który pragnie się odszyfrować, uzyskać informację, dla jakiej wartości i-tego bajtu w zmanipulowanym bloku poprzedzającym wypełnienie jest poprawne. Zmanipulowany poprzedni blok C’1 początkowo może mieć dowolne wartości, poza ostatnią, którą należy iteracyjnie zmieniać. W momencie, gdy dla zmanipulowanego szyfrogramu Wyrocznia nie zwróci błędu dopełnienia, znana jest wartość i-tego (w tym wypadku pierwszego) bajtu z C’1, która w operacji xor z wartością i-tego bajtu stanu pośredniego I2 daje znaną wartość bajtu w tekście jawnym (np. w przypadku dopełnienia o długości 1, pierwszy bajt od końca w schemacie PKCS7 będzie miał wartość 1). Można więc uzyskać wartość stanu pośredniego na i-tej pozycji, a xorując ją z i-tym bajtem rzeczywistego poprzedniego bloku szyfrogramu, i-ty bajt tekstu jawnego P2. Korzystając z właściwości funkcji xor, należy następnie zamienić wartość i-tego bajtu zmanipulowanego bloku na taką, aby w otrzymywanym tekście jawnym na i-tej pozycji znalazła się wartość odpowiednia dla dopełnienia o jeden dłuższego (w PKCS7 dla wypełnienia o długości 2 jest to 2 – nowa wartość powinna więc równać się noweC’1[i] = C’1[i] xor 1 xor 2). Następnie opisaną pętlę powtarza się dla bajtu i-1, kolejnego „na lewo”, i kolejnych aż do początku bloku. |
14 | 14 |
|
15 | 15 | 
|
16 | 16 |
|
17 | 17 | (żródło: https://robertheaton.com/2013/07/29/padding-oracle-attack/)
|
18 | 18 |
|
19 |
| -W programie przewidziano wsparcie dla dwóch algorytmów dopełnień – PKCS7 i ANSI X.923 (w celu zmiany stosowanej implementacji należy zmodyfikować pole paddingMode w pliku Program.cs). Funkcje pomocnicze zwracające ich wartości na zadanych pozycjach i usuwające dopełnienie z bloków znajdują się w klasie PaddingUtils. |
| 19 | +W programie przewidziano wsparcie dla dwóch algorytmów dopełnień – PKCS7 i ANSI X.923 (w celu zmiany stosowanej implementacji należy zmodyfikować pole `paddingMode` w pliku [Program.cs](Program.cs)). Funkcje pomocnicze zwracające ich wartości na zadanych pozycjach i usuwające dopełnienie z bloków znajdują się w klasie [`PaddingUtils`](PaddingUtils.cs). |
20 | 20 |
|
21 | 21 | Główny plik programu to [Program.cs](Program.cs) – zawiera on obsługę interakcji z użytkownikiem.
|
22 | 22 | Program należy uruchomić poleceniem `dotnet run`, wcześniej należy jednak pobrać zależności poleceniem „dotnet restore”. O dostępnych (opcjonalnych) argumentach wywołania programu można dowiedzieć się, wpisując `dotnet run -- --help`.
|
23 | 23 |
|
24 | 24 | ## Odpowiedzi na pytania
|
25 | 25 |
|
26 |
| -1. Jaki jest czas wykonania wykonania ataku dla szyfrogramu o wielkości 10 bloków? |
| 26 | +1. **Jaki jest czas wykonania wykonania ataku dla szyfrogramu o wielkości 10 bloków?** |
27 | 27 | Kolejne trzy wyniki (s): 3,5829065; 3,4902909; 3,5674863. Średnia: 3,5468946 s. (2.5374309 bloków / s).
|
28 | 28 | (Pierwszy blok nie był deszyfrowany.)
|
29 | 29 | Procesor: Intel® Core™ i5-4210U CPU @ 1.70GHz.
|
30 | 30 |
|
31 |
| -2. Kiedy możliwy jest odczyt również pierwszego bloku? |
| 31 | +2. **Kiedy możliwy jest odczyt również pierwszego bloku?** |
32 | 32 | Odczyt pierwszego bloku jest możliwy, jeśli jest dostępny wektor inicjujący (IV).
|
33 | 33 | (W mojej implementacji założyłem, że nie jest.)
|
34 | 34 |
|
35 |
| -3. Jaki błąd przy implementacji należy popełnić, aby atak był możliwy? |
| 35 | +3. **Jaki błąd przy implementacji należy popełnić, aby atak był możliwy?** |
36 | 36 | Aby atak był możliwy, musi istnieć możliwość przesłania własnego zmodyfikowanego szyfrogramu, a usługa odpowiadać błędem, w wypadku niepoprawnego dopełnienia (ang. padding) ostatniego bloku.
|
37 | 37 |
|
38 |
| -4. W jakich środowiskach zaimplementowano ten atak? |
| 38 | +4. **W jakich środowiskach zaimplementowano ten atak?** |
39 | 39 | Tego ataku użyto wobec protokołów SSL i IPSec, frameworków webowych JavaServer Faces, Ruby on Rails i ASP.NET oraz innego oprogramowania ([Wikipedia](https://en.wikipedia.org/wiki/Padding_oracle_attack#Attacks_using_padding_oracles)).
|
40 | 40 |
|
41 |
| -5. Czy atak działa tylko dla algorytmu AES? |
| 41 | +5. **Czy atak działa tylko dla algorytmu AES?** |
42 | 42 | Nie, atak opiera się na wykorzystaniu właściwości trybu łączenia bloków CBC w szyfrze blokowym, polegającym na wzajemnej relacji między blokami, takiej że blok tekstu jawnego jest sumowany modulo 2 (xor) z szyfrogramem poprzedzającego go bloku (a pierwszy blok z wektorem inicjującym).
|
43 | 43 |
|
44 |
| -6. Ile razy maksymalnie należy odpytać wyrocznię w celu odczytania jednego bloku? |
| 44 | +6. **Ile razy maksymalnie należy odpytać wyrocznię w celu odczytania jednego bloku?** |
45 | 45 | W najbardziej pesymistycznym przypadku należy odpytać ją 256⋅16 = 4096 razy.
|
46 | 46 | (256 – liczba możliwych wartości jednego bajtu, 16 – liczba bajtów w bloku, zakładając rozmiar bloku 128 bitów)
|
47 | 47 |
|
48 |
| -7. Czy w przypadku zastosowania innych schematów paddingu atak będzie działał? |
| 48 | +7. **Czy w przypadku zastosowania innych schematów paddingu atak będzie działał?** |
49 | 49 | Tak, o ile schemat dopełniania zawiera w sobie informację o jego długości i formacie (jakie wartości powinny przyjmować poszczególne bajty wypełnienia). Oprócz PKCS7, zadziała on również w przypadku ANSI X.923. Nie zadziała natomiast w przypadku dopełniania zerami (bez informacji o długości) albo schematu ISO 10126-2.
|
0 commit comments