Właściwie w komentarzach do Zgadywanki pojawiły się odpowiedzi, ale tutaj je zbiorę i dodam kilka wyjaśnień.
Zgadywanka - rozwiązanie
Najpierw dla ułatwienia jeszcze raz pokażę te dane, ale tym razem nieco rozbite.
47233c3a3a1c47a8 0e7c7ad73dc16b71 3b1e0e725a2229bb 4c4e213d5c560700 0e7c7ad73dc16b71 3b1e0e725a2229bb 47233c3a3a1c47a8 4c4e213d5c560700 3b1e0e725a2229bb 47233c3a3a1c47a8 0e7c7ad73dc16b71 4c4e213d5c560700
W ten sposób wyraźnie widać powtarzające się bloki. Konkretnie w każdej linii są cztery bloki. Trzy z nich "zamieniają się" miejscami, ostatni pozostaje na tej samej pozycji, na końcu.
Efekt ten został osiągnięty przez zaszyfrowanie (oddzielnie, ale tym samym kluczem) trzech stringów przy pomocy DES (taki sam efekt można było osiągnąć przy pomocy innego szyfru blokowego) w trybie ECB. I właśnie ten tryb ECB jest tutaj kluczowy. W trybie ECB każdy z bloków tekstu jawnego szyfrowany jest oddzielnie. Skutek jest taki, że dwa takie same bloki tekstu jawnego na różnych pozycjach, dadzą takie same wartości bloku w komunikacie zaszyfrowanym. Dobrze to pokazuje obrazek z "szyfrowanym pingwinkiem" (patrz Wikipedia, wpis o ECB).
Ostatni blok to rzeczywiście padding, a właściwie efekt jego szyfrowania. W tym wypadku padding obejmuje cały ostatni blok, bo tekst jawny "wypełnia" dokładnie trzy pierwsze bloki. W związki z tym we wszystkich trzech przypadkach padding jest taki sam, a z uwagi na tryb ECB rezultat jego szyfrowania, również jest taki sam. Dzięki temu można snuć przypuszczenia dotyczące dokładnej długości tekstu jawnego przed zaszyfrowaniem.
Ponieważ operacja szyfrowania nie zapewnia integralności danych (no, przynajmniej nie "domyślnie", patrz authenticated encryption), zaszyfrowanym tekstem można manipulować i liczyć na to, że po operacji odszyfrowania otrzymany tekst jawny będzie zgodny z oczekiwaniami. W przypadku trybu ECB może to być łatwiejsze niż np. w przypadku CBC, bo:
- można budować z gotowych klocków (64 bity), mieszać klocki pochodzące z różnych zaszyfrowanych komunikatów,
- każdy blok ma "tylko" 2^64 możliwych wartości,
- modyfikacja bloku n nie powoduje modyfikacji bloku n+1 (ani żadnego następnego),
Załóżmy teraz taką hipotetyczną sytuację z tokenem SSO, który zawiera nazwę użytkownika, jego rolę oraz znacznik czasowy mówiący o dacie jego wystawienia. Znacznik czasowy jest po to, by ograniczyć czas życia tokenu. Token nie zawiera żadnego "potwierdzenia integralności" (podpis, HMAC), a jedynie jest "chroniony" przez szyfrowanie w trybie ECB. Jeśli złoży się tak (nie)szczęśliwie, że znacznik czasowy będzie w oddzielnym bloku, można praktycznie w nieskończoność wykorzystywać przechwycony token. Jak? Podmieniając stosowny blok zaszyfrowanego tokenu zawierający znacznik czasu na nowy blok pochodzący na przykład z własnego tokenu, jeśli atakujący ma dostęp do systemu (ale np. z mniejszymi uprawnieniami).
I warto tu przypomnieć o "zabawie" z szyfrem strumieniowym. Tam sytuacja była jeszcze bardziej radosna: Bootcamp IIa: rozwiązanie (prawie).