Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00299 005011 12752747 na godz. na dobę w sumie
Łamanie i zabezpieczanie aplikacji w systemie iOS - książka
Łamanie i zabezpieczanie aplikacji w systemie iOS - książka
Autor: Liczba stron: 320
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-246-5147-4 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie mobilne >> iphone
Porównaj ceny (książka, ebook, audiobook).

Twoja lektura obowiązkowa!

iOS to obecnie jeden z najpopularniejszych systemów operacyjnych, wykorzystywany w urządzeniach firmy Apple. Jednak dzięki tej popularności jest on też łakomym kąskiem dla hakerów. Uzyskanie dostępu do danych przechowywanych w telefonie może mieć katastrofalne skutki. Dlatego jeżeli tworzysz aplikacje na platformę iOS, ta książka jest dla Ciebie pozycją obowiązkową.

Jak obronić się przed atakiem? Wszystkie niezbędne informacje znajdziesz w tym wyjątkowym podręczniku. W trakcie lektury dowiesz się, jak działają hakerzy, jak wyszukują słabe punkty aplikacji oraz jak modyfikują jej kod. Ponadto nauczysz się utrudniać śledzenie kodu Twojej aplikacji oraz bezpiecznie usuwać pliki (tak, aby nie było możliwe ich odtworzenie). Wśród poruszanych tematów znajdziesz również te związane z transmisją danych: wykorzystanie protokołu SSL to nie wszystko, musisz zadbać także o to, żeby nie było możliwe przejęcie sesji SSL. Weź książkę do ręki i obroń się przed atakiem!

Dzięki tej książce:

Zadbaj o bezpieczeństwo danych użytkowników Twojej aplikacji!

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Tytuł oryginału: Hacking and Securing iOS Applications Tłumaczenie: Łukasz Piwko ISBN: 978-83-246-5147-4 © 2012 Helion S.A. Authorized Polish translation of the English edition of Hacking and Securing iOS Applications ISBN 9781449318741 © 2012 Jonathan Zdziarski. This translation is published and sold by permission of O’Reilly Media, Inc., which owns or controls all rights to publish and sell the same. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the Publisher. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/lamzab Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis treļci Skäadniki modelu zabezpieczeþ systemu iOS Mit monokultury Model zabezpieczeþ systemu iOS KradzieĔ danych jest... bäyskawiczna Nie ufaj nikomu, nawet wäasnym aplikacjom Fizyczny dostöp nie jest niezbödny Podsumowanie Przechowywanie klucza i zamka w jednym miejscu Hasäa jako säabe zabezpieczenie ćlady pozostawiane przez system niweczñ szyfrowanie Dane zewnötrzne równieĔ sñ zagroĔone Przechwytywanie ruchu Wstýp........................................................................................................................................11 1. Wszystko, co wiesz, jest bĥýdne .................................................................................. 15 16 18 19 21 22 24 24 25 25 26 27 29 Czýļë I. Hakowanie ................................................................................................................. 31 2. Podstawowe techniki ĥamania zabezpieczeħ systemu iOS .......................................33 33 34 34 36 37 38 40 40 41 42 45 46 49 50 60 61 Budowa wäasnego kodu Analizowanie pliku binarnego Testowanie pliku binarnego Demonizowanie kodu WdraĔanie zäoĈliwego kodu przy uĔyciu archiwum tar WdraĔanie zäoĈliwego kodu przy uĔyciu dysku RAM Dlaczego naleĔy wiedzieè, jak äamie siö zabezpieczenia Zdejmowanie blokady Narzödzia programistyczne Zdejmowanie blokady dla uĔytkownika Zdejmowanie blokady w iPhonie Tryb DFU Tethered jailbreak a untethered jailbreak Usuwanie blokady z urzñdzeþ i wstawianie kodu çwiczenia Podsumowanie 5 Peäne szyfrowanie dysku Pamiöè NAND Szyfrowanie dysków Kiedy szyfrowanie dysku systemu iOS zawodzi Kopiowanie systemu plików w czasie jego dziaäania Program DataTheft Dostosowywanie narzödzia launchd Przygotowywanie dysku RAM Tworzenie obrazu systemu plików Kopiowanie surowego systemu plików Program do kopiowania surowego systemu plików Dostosowywanie narzödzia launchd Przygotowywanie dysku RAM Tworzenie obrazu systemu plików Wyäñczenie podmienionego urzñdzenia Dezaktywacja podmienionego urzñdzenia Podrzucenie urzñdzenia ze zäoĈliwym oprogramowaniem Aplikacja do przechwytywania hasäa 3. Wykradanie systemu plików .......................................................................................63 63 63 64 66 66 67 74 78 79 80 81 84 85 86 87 87 88 88 89 90 90 4. Ļlady pozostawiane przez aplikacje i wycieki danych...............................................93 94 95 96 97 97 98 99 99 101 102 106 107 108 109 109 110 110 111 111 ãñczenie siö z bazñ danych Polecenia bazy danych SQLite Wydawanie poleceþ SQL WaĔne pliki bazy danych Kontakty ksiñĔki adresowej Obrazy graficzne z ksiñĔki adresowej Dane Map Google Wydarzenia kalendarzowe Historia rozmów Baza danych wiadomoĈci e-mail Notatki Metadane zdjöè WiadomoĈci SMS Zakäadki przeglñdarki Safari Pamiöè podröczna SMS-ów funkcji Spotlight Pamiöci podröczne przeglñdarki Safari çwiczenia Rola inĔynierii spoäecznej Podsumowanie Wydobywanie geotagów zdjöè Skonsolidowana pamiöè podröczna GPS Bazy danych SQLite 6 _ Spis treļci Pamiöè podröczna aplikacji sieciowych Pamiöè WebKit Poczta gäosowa Inne waĔne pliki Podsumowanie Narzödzia ochrony danych firmy Sogeti Wydobywanie kluczy szyfrowania Program KeyTheft Dostosowywanie programu launchd Przygotowywanie dysku RAM Przygotowywanie jñdra Przeprowadzanie ataku metodñ brute force InĔynieria wsteczna niepeänych pól bazy danych Wersje robocze SMS-ów Listy wäaĈciwoĈci WaĔne pliki list wäaĈciwoĈci Instalowanie narzödzi ochrony danych Kompilowanie narzödzia do wykonywania ataków metodñ brute force Kompilowanie potrzebnych bibliotek Pythona 111 111 111 112 113 114 114 118 120 5. Ĥamanie szyfrów .........................................................................................................121 121 122 122 123 124 124 125 126 126 127 129 131 132 133 133 137 137 138 139 139 139 6. Odzyskiwanie skasowanych plików...........................................................................141 142 143 144 144 145 145 146 146 146 Rozszyfrowywanie pöku kluczy Rozszyfrowywanie surowego dysku Rozszyfrowywanie kopii zapasowych z iTunes ãamanie zabezpieczeþ przy uĔyciu programów szpiegujñcych Program SpyTheft Demonizowanie programu spyd Dostosowywanie launchd Przygotowywanie dysku RAM Uruchamianie programu szpiegujñcego Wydobywanie danych z kroniki HFS Wydobywanie danych z pustej przestrzeni NajczöĈciej odzyskiwane dane Zrzuty ekranu aplikacji Usuniöte listy wäaĈciwoĈci Usuniöte nagrania i poczta gäosowa Usuniöta pamiöè klawiatury Zdjöcia i inne dane osobiste Podsumowanie çwiczenia Podsumowanie Spis treļci _ 7 Analizowanie plików binarnych Zaszyfrowane pliki binarne çwiczenia Podsumowanie Animacje SpringBoard Odbieranie rozmów... z przymusu Robienie zrzutów ekranu Format Mach-O Podstawy uĔywania narzödzia class-dump-z Tablice symboli Instalowanie Cycript UĔywanie Cycript ãamanie prostych blokad Podmienianie metod Poszukiwanie danych Rejestrowanie danych PowaĔniejsze konsekwencje Obliczanie pozycji Wykonywanie zrzutu pamiöci Kopiowanie rozszyfrowanego kodu z powrotem do pliku Zerowanie wartoĈci cryptid 7. Szperanie w systemie wykonawczym....................................................................... 147 148 148 151 152 153 155 156 157 158 160 160 161 162 167 169 171 172 178 179 179 180 180 8. Hakowanie biblioteki systemu wykonawczego ........................................................181 181 183 183 184 184 188 190 191 193 193 194 196 197 198 9. Przechwytywanie ruchu ............................................................................................ 199 199 201 203 Dezasemblacja i debugowanie Podsäuchiwanie ćrodowisko jözyka Objective-C ãñczenie z Objective-C Wstawianie zäoĈliwego kodu Rozkäadanie Objective-C Zmienne egzemplarzowe Metody Pamiöè podröczna metod Przechwytywanie APN Dostarczanie zäoĈliwego kodu Usuwanie Program CodeTheft Wstawianie kodu za pomocñ debugera Wstawianie kodu za pomocñ dynamicznego konsolidatora Atakowanie systemu wykonawczego przy uĔyciu Cycript Peäna infekcja urzñdzenia Podsumowanie 8 _ Spis treļci çwiczenia Podsumowanie 10. Atakowanie mechanizmu weryfikacji SSL na poziomie aplikacji Program SSLTheft Przechwytywanie klas HTTP z biblioteki Foundation Prosta konfiguracja serwera proxy Atakowanie protokoäu SSL Program POSTTheft Analizowanie danych Driftnet Kompilacja Uruchamianie narzödzia SSLStrip Paros Proxy OstrzeĔenia przeglñdarek internetowych 204 204 204 206 207 209 209 214 214 216 218 218 219 219 221 Czýļë II. Zabezpieczanie aplikacji.........................................................................................223 Implementowanie algorytmów szyfrowania ........................................................225 225 Siäa hasäa 228 228 229 232 235 239 242 243 245 246 247 251 11. Zacieranie ļladów ......................................................................................................253 253 254 255 257 261 262 263 Kasowanie rekordów SQLite Pamiöè klawiatury Randomizowanie cyfr kodu PIN Zrzuty widoku okien aplikacji Geoszyfrowanie z hasäem Dzielenie kluczy na serwerze Zabezpieczanie pamiöci Czyszczenie pamiöci Kasowanie przy uĔyciu algorytmu DOD 5220.22-M Objective-C Uwaga na generatory losowych haseä Wprowadzenie do Common Crypto Operacje bezstanowe Szyfrowanie stanowe Szyfrowanie z kluczem gäównym Geoszyfrowanie Kryptografia klucza publicznego çwiczenia Bezpieczne kasowanie plików Spis treļci _ 9 Funkcje Ĉródliniowe Utrudnianie dezasemblacji Flagi optymalizacyjne Usuwanie symboli Flaga -funroll-loops Sprawdzanie danych procesu Blokowanie debugerów Sprawdzanie integralnoĈci klas systemu wykonawczego Sprawdzanie poprawnoĈci przestrzeni adresowej Reagowanie na próby modyfikacji Kasowanie danych uĔytkownika Wyäñczanie dostöpu do sieci Raportowanie do centrali Rejestrowanie zdarzeþ Faäszywe kontakty i wyäñczniki awaryjne 12. Zabezpieczanie systemu wykonawczego.................................................................265 265 266 266 267 267 267 268 270 272 272 281 287 287 291 296 çwiczenia 299 Wykrywanie zdjýcia blokady.................................................................................... 301 301 Test integralnoĈci piaskownicy 303 303 304 305 305 14. Dalszy rozwój .............................................................................................................307 307 307 308 309 310 Skorowidz ..............................................................................................................................311 MyĈl jak haker Inne narzödzia do inĔynierii wstecznej Bezpieczeþstwo a zarzñdzanie kodem Elastyczne podejĈcie do kwestii bezpieczeþstwa Inne wartoĈciowe ksiñĔki 13. Testy systemu plików ObecnoĈè plików zwiñzanych ze zdejmowaniem blokady Rozmiar pliku /etc/fstab ćlady dowiñzaþ symbolicznych Test wykonywania strony 10 _ Spis treļci ROZDZIAĤ 10. Implementowanie algorytmów szyfrowania Szyfrowanie to jedna z najskuteczniejszych form ochrony danych aplikacji, a wiöc naleĔy je wy- jñtkowo starannie zaimplementowaè. Niestety, jak przekonaäeĈ siö w poprzednich rozdziaäach, nie jest to wcale äatwe. Istnieje wiele publikacji na ten temat, ale sñ one czösto zawiäe i niezro- zumiaäe, a wachlarz dostöpnych metod i algorytmów jest naprawdö bardzo szeroki. Dlatego wäaĈnie wiökszoĈè hakerów skupia siö na samej implementacji algorytmu szyfrowania, zamiast próbowaè wäasnoröcznie rozszyfrowaè dane. Danych nie moĔna skutecznie chroniè, jeĈli po rozszyfrowaniu zostanñ zapisane w pamiöci. Dlatego najwaĔniejsze w implementacji szyfro- wania jest niedopuszczanie do takich sytuacji. NieuĔywane dane muszñ byè tak zabezpieczo- ne, aby w razie kradzieĔy lub sklonowania urzñdzenia nie daäo siö ich rozszyfrowaè, przy- najmniej nie bez uĔycia klastrów potöĔnych komputerów. W tym rozdziale znajduje siö opis róĔnych technik szyfrowania i wymieniania kluczy, które znacznie utrudniajñ przeprowa- dzenie ataku na aplikacjö. Siĥa hasĥa SkutecznoĈè wszystkich dobrych algorytmów szyfrowania zaleĔy od siäy klucza, który w wiök- szoĈci aplikacji jest chroniony hasäem. MoĔna zatem powiedzieè, Ĕe bezpieczeþstwo takich implementacji algorytmów szyfrujñcych zaleĔy przede wszystkim od siäy hasäa ustanowione- go przez uĔytkownika. ChoèbyĈ napisaä najdoskonalszñ implementacjö, caäy Twój wysiäek pójdzie na marne, jeĔeli w Twoim programie bödzie moĔliwoĈè uĔywania säabych haseä. Dlatego teĔ obok mechanizmu szyfrujñcego drugim filarem bezpieczeþstwa aplikacji sñ zasady dotyczñce tworzenia haseä. Wymuszajñc stosowanie haseä o odpowiedniej däugoĈci i wäaĈciwym stopniu skomplikowania, moĔna sprawiè, Ĕe przeprowadzenie udanego ataku na program stanie siö prawie niemoĔliwe. Silne hasäo powinno mieè nastöpujñce cechy: x duĔa liczba znaków; x poäaczenie maäych i duĔych liter; x zawartoĈè cyfr; x obecnoĈè specjalnych znaków, takich jak # i znaki interpunkcyjne; 225 x brak typowych wzorców klawiszowych, jak np. ciñg QWERTY; x brak säów naleĔñcych do säowników popularnych jözyków; x brak dat i innych tego typu danych. Przestrzeganie niektórych z tych zasad, np. däugoĈci hasäa, moĔna bardzo äatwo wyegzekwo- waè. Za bezpieczne aktualnie uznaje siö hasäa o däugoĈci przynajmniej 12 znaków. Nietrudno teĔ zmusiè uĔytkownika do stosowania okreĈlonych mieszanek znaków, a dobre narzödzie do weryfikacji haseä moĔe nawet wykrywaè odlegäoĈè miödzy naciĈniötymi klawiszami, aby wykryè ewentualne wzorce. Prosty mechanizm sprawdzania haseä moĔna zaimplementowaè, stosujñc system punktowy polegajñcy na przyznawaniu hasäu od jednego do trzech punktów za to, ile razy kaĔda z okre- Ĉlonych cech wystöpuje w tym haĈle. Na przykäad hasäo zawierajñce cyfry moĔe otrzymaè maksymalnie trzy punkty, jeĈli bödzie zawieraäo przynajmniej trzy cyfry itd. Przedstawiony na listingu 10.1 program sprawdza däugoĈè hasäa oraz czy zawiera ono cyfry, maäe i wielkie li- tery oraz znaki specjalne, a takĔe sprawdza odlegäoĈè od siebie poszczególnych klawiszy i przyznaje dodatkowe punkty, jeĈli nie da siö w nich wykryè Ĕadnego wzorca. Listing 10.1. Narzödzie do sprawdzania siäy haseä (passphrase_strength.m) #include stdio.h #include string.h #include sys/param.h #include ctype.h #include stdlib.h int key_distance(char a, char b) { const char *qwerty_lc = `1234567890-= qwertyuiop[]\\ asdfghjkl; zxcvbnm,./ ; const char *qwerty_uc = ~!@#$ ^ *()_+ QWERTYUIOP{}| ASDFGHJKL:\ ZXCVBNM ? ; int pos_a, pos_b, dist; if (strchr(qwerty_lc, a)) pos_a = strchr(qwerty_lc, a) - qwerty_lc; else if (strchr(qwerty_uc, a)) pos_a = strchr(qwerty_uc, a) - qwerty_uc; else return -2; if (strchr(qwerty_lc, b)) pos_b = strchr(qwerty_lc, b) - qwerty_lc; else if (strchr(qwerty_uc, b)) pos_b = strchr(qwerty_uc, b) - qwerty_uc; else return -1; dist = abs((pos_a/13) - (pos_b/13)) + abs(pos_a 13 - pos_b 13); return dist; } int score_passphrase(const char *passphrase) { int total_score = 0; int unit_score; 226 _ Rozdziaĥ 10. Implementowanie algorytmów szyfrowania int distances[strlen(passphrase)]; int i; /* DáugoĞü hasáa */ unit_score = strlen(passphrase) / 4; total_score += MIN(3, unit_score); /* Wielkie litery */ for(unit_score = i = 0; passphrase[i]; ++i) if (isupper(passphrase[i])) unit_score++; total_score += MIN(3, unit_score); /* Maáe litery */ for(unit_score = i = 0; passphrase[i]; ++i) if (islower(passphrase[i])) unit_score++; total_score += MIN(3, unit_score); /* Cyfry */ for(unit_score = i = 0; passphrase[i]; ++i) if (isdigit(passphrase[i])) unit_score++; total_score += MIN(3, unit_score); /* Znaki specjalne */ for(unit_score = i = 0; passphrase[i]; ++i) if (!isalnum(passphrase[i])) unit_score++; total_score += MIN(3, unit_score); /* OdlegáoĞci miĊdzy klawiszami */ distances[0] = 0; for(unit_score = i = 0; passphrase[i]; ++i) { if (passphrase[i+1]) { int dist = key_distance(passphrase[i], passphrase[i+1]); if (dist 1) { int j, exists = 0; for(j=0;distances[j];++j) if (distances[j] == dist) exists = 1; if (!exists) { distances[j] = dist; distances[j+1] = 0; unit_score++; } } } } total_score += MIN(3, unit_score); return ((total_score / 18.0) * 100); } int main(int argc, char *argv[]) { if (argc 2) { printf( SkĪadnia: s hasĪo \n , argv[0]); return EXIT_FAILURE; } printf( SiĪa hasĪa: d \n , score_passphrase(argv[1])); return EXIT_SUCCESS; } Siĥa hasĥa _ 227 Funkcja score_passphrase zwraca wartoĈè procentowñ od 0 do 100, okreĈlajñcñ jakoĈè hasäa. Do programu moĔna by jeszcze dodaè moduä sprawdzajñcy na podstawie säownika, czy w ha- Ĉle nie ma jakichĈ säownikowych haseä. To jednak stanowi dodatkowe obciñĔenie dla procesora i moĔe powodowaè opóĒnienia w tworzeniu nowych haseä. Uwaga na generatory losowych haseĥ Generatory losowych haseä bywajñ bardzo pomocne w tworzeniu wysokiej jakoĈci haseä, ale czasami mogñ uäatwiaè dokonywanie ataków metodñ brutalnej siäy. Algorytmy stosujñce äatwe do wpisania wzorce ograniczajñ liczby moĔliwych kombinacji. Przeprowadzenie uda- nego ataku na takñ aplikacjö moĔe byè nawet äatwiejsze niĔ na aplikacjö niemajñcñ Ĕadnej kontroli jakoĈci haseä, poniewaĔ atakujñcy wie, Ĕe wszystkie hasäa sñ tworzone wedäug okre- Ĉlonego wzorca. Wprowadzenie do Common Crypto Biblioteka Common Crypto, zwana teĔ CCCrypt i 3CC, zawiera kilka rodzajów algorytmów szyfrujñcych. Obsäuguje m.in. takie standardy jak AES, DES i 3DES. W zaleĔnoĈci od uĔywanego algorytmu moĔna stosowaè szyfry blokowe i strumieniowe. Szyfr blokowy dzieli dane na bloki o jednakowym rozmiarze i szyfruje kaĔdy z nich z osob- na, a nastöpnie skäada te bloki z powrotem w jednñ caäoĈè. Tego typu szyfrowanie stosuje siö w algorytmach z kluczem prywatnym. Technika ta jest bardzo wydajna, gdy rozmiar danych wejĈciowych jest z góry znany. Natomiast szyfr strumieniowy jest stosowany do szyfrowania danych o duĔych rozmiarach lub strumieniowych, których nie da siö zaszyfrowaè jako caäoĈci. Szyfry strumieniowe sñ zazwyczaj szybsze od blokowych, ale sñ równieĔ nieodporne na pewne formy ataku, takie jak przerzucanie bitów (ang. bit flipping) czy powtórne uĔycie klucza (ang. key replay). Szyfr strumieniowy wymaga synchronizacji, poniewaĔ dane sñ przesyäane strumieniowo do algorytmu szyfrujñcego. Kolejnñ funkcjñ udostöpnianñ przez bibliotekö Common Crypto jest äaþcuchowanie szyfro- wanych bloków. W trybie tym kaĔdy blok jest najpierw mieszany za pomocñ operacji XOR z zaszyfrowanym tekstem z poprzedniego bloku, a dopiero potem zostaje sam zaszyfrowany. Dziöki temu kaĔdy zaszyfrowany blok jest zaleĔny od wszystkich poprzednich bloków. Zwiök- sza to poziom bezpieczeþstwa, poniewaĔ haker, dokonujñc ataku typu czäowiek poĈrodku, nie moĔe zmodyfikowaè danych w okreĈlonym miejscu w strumieniu, nie naruszajñc caäego äaþ- cucha od tego miejsca do koþca. UniemoĔliwia to takĔe przeprowadzanie ataków polegajñ- cych na ponownym wstawianiu do poäñczenia okreĈlonych zaszyfrowanych pakietów. ãaþ- cuchowanie stosuje siö w kombinacji z wektorem inicjujñcym (ang. initialization vector), czyli losowñ wartoĈciñ uĔywanñ do zaszyfrowania pierwszego bloku. JeĈli wektor inicjujñcy zo- stanie dobrze zaimplementowany, to dla wielu kopii tych samych danych zostanie zwrócony inny tekst szyfru, co uniemoĔliwi przeprowadzenie ataków metodñ powtórkowñ (ang. replay) i kryptoanalitycznych. Ponadto uniemoĔliwia to atakujñcemu rozszyfrowanie danych, nawet jeĈli uda mu siö zdobyè klucz szyfrowania, poniewaĔ potrzebna jest jeszcze znajomoĈè wektora inicjujñcego. 228 _ Rozdziaĥ 10. Implementowanie algorytmów szyfrowania Szyfry blokowe okreĈla siö jako bezstanowe, mimo iĔ w procesie äaþcuchowania informacje z jednego bloku wykorzystywane sñ do zaszyfrowania kolejnego, poniewaĔ na koniec wszystkie informacje oprócz samego tekstu szyfru sñ usuwane. Natomiast szyfry strumieniowe zalicza siö do stanowych, poniewaĔ wiadomo w procesie szyfrowania, w którym miejscu odbywa siö akcja. Operacje bezstanowe Najprostszym sposobem uĔycia biblioteki Common Crypto jest bezstanowe zaszyfrowanie lub rozszyfrowanie danych. W bibliotece tej znajduje siö funkcja o nazwie CCCrypt, której opis w dokumentacji jest nastöpujñcy: „bezstanowa jednorazowa operacja szyfrowania lub de- szyfrowania”. Funkcja ta wykonuje wszystkie dziaäania potrzebne do zaszyfrowania lub rozszy- frowania danych w tle. Programista musi tylko podaè klucz oraz kilka parametrów i buforów. Prototyp funkcji CCCrypt jest nastöpujñcy: CCCryptorStatus CCCrypt(CCOperation op, CCAlgorithm alg, CCOptions options, const void *key, size_t keyLength, const void *iv, const void *dataIn, size_t dataInLength, void *dataOut, size_t dataOutAvailable, size_t *dataOutMoved); CCOperation op MoĔe byè kCCEncrypt albo kCCDecrypt. Parametr ten okreĈla, czy dane wejĈciowe majñ zostaè zaszyfrowane, czy rozszyfrowane. CCAlgorithm alg OkreĈla, który algorytm szyfrowania ma zostaè uĔyty. Aktualnie dostöpne sñ nastöpujñce al- gorytmy: kCCAlgorithmAES128, kCCAlgorithmDES, kCCAlgorithm3DES, kCCAlgorithmCAST, kCCAlgorithmRC4, kCCAlgorithmRC2 oraz kCCAlgorithmBlowfish. CCOptions options OkreĈla opcje szyfrowania reprezentowane w zmiennej jako flagi. Aktualnie obsäugiwane sñ dwie opcje: kCCOptionPKCS7Padding i kCCOptionECBMode. Pierwsza instruuje funkcjö CCCryptor, aby w swoich operacjach przyjmowaäa, Ĕe stosowane jest dopeänienie PKCS7. Druga natomiast wäñcza tryb szyfrowania Electronic Code Block (ECB), w którym kaĔdy blok jest szyfrowany osobno. Trybu ECB powinni uĔywaè tylko doĈwiadczeni programiĈci, którzy dobrze wiedzñ, do czego on säuĔy, poniewaĔ tryb ten moĔe powodowaè osäabie- nie bezpieczeþstwa, jeĈli nie zostanie wäaĈciwie zaimplementowany. const void *key size_t keyLength Klucz szyfrowania i däugoĈè tego klucza. DäugoĈè klucza w duĔym stopniu zaleĔy od ty- pu szyfrowania. Aktualnie dostöpne sñ nastöpujñce däugoĈci kluczy: kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256, kCCKeySizeDES, kCCKeySize3DES, kCCKeySizeMin- CAST, kCCKeySizeMaxCAST, kCCKeySizeMinRC4, kCCKeySizeMaxRC4, kCCKeySizeMinRC2, kCCKeySizeMaxRC2, kCCKeySizeMinBlowfish oraz kCCKeySizeMaxBlowfish. Wprowadzenie do Common Crypto _ 229 const void *iv Wektor inicjujñcy, dziöki któremu kaĔdy szyfr jest niepowtarzalny. Dziöki jego zastoso- waniu niemoĔliwe jest dokonywanie ataków powtórzeniowych i kryptoanalitycznych, poniewaĔ ten sam tekst zaszyfrowany przy uĔyciu tego samego klucza dziöki wektorowi inicjujñcemu da za kaĔdym razem inny wynik. Do szyfrowania zawsze powinno siö uĔy- waè losowego wektora inicjujñcego. const void *dataIn size_t dataInLength Dane do zaszyfrowania lub rozszyfrowania. Muszñ one zostaè dopeänione do rozmiaru bloku. void *dataOut size_t dataOutAvailable size_t *dataOutMoved Bufor wyjĈciowy dataOut alokowany przez wywoäujñcego i przeznaczony do przecho- wywania czystego lub zaszyfrowanego tekstu, w zaleĔnoĈci od rodzaju operacji. Rozmiar bufora okreĈla siö w zmiennej dataOutAvailable. Liczba zaszyfrowanych lub rozszyfro- wanych bajtów jest zapisana w zmiennej, której adres zawiera parametr dataOutMoved. Rozmiar danych wyjĈciowych nie przekracza rozmiaru danych wejĈciowych plus roz- miar bloku. Przedstawiony na listingu 10.2 program pobiera tekst z wiersza poleceþ i szyfruje go przy uĔyciu losowo utworzonego klucza. Dziöki temu, Ĕe bibliotekö Common Crypto obsäuguje zarówno system Mac OS X, jak i iOS, kod ten moĔna skompilowaè w obu tych systemach. Listing 10.2. Szyfrowanie tekstu algorytmem AES-128 (textcrypt.m) #include CommonCrypto/CommonCryptor.h #include Foundation/Foundation.h #include stdio.h int encryptText(const unsigned char *clearText) { CCCryptorStatus status; unsigned char cipherKey[kCCKeySizeAES128]; unsigned char cipherText[strlen(clearText) + kCCBlockSizeAES128]; size_t nEncrypted; int i; printf( Szyfrowanie tekstu: s\n , clearText); printf( Ušyty klucz szyfrowania: ); for(i=0;i kCCKeySizeAES128;++i) { cipherKey[i] = arc4random() 255; printf( 02x , cipherKey[i]); } printf( \n ); status = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, cipherKey, kCCKeySizeAES128, NULL, clearText, strlen(clearText), cipherText, sizeof(cipherText), 230 _ Rozdziaĥ 10. Implementowanie algorytmów szyfrowania nEncrypted); if (status != kCCSuccess) { printf( Funkcja CCCrypt() zwróciĪa bĪîd d\n , status); return status; } printf( Zaszyfrowano ld bajtów\n , nEncrypted); for(i=0;i nEncrypted;++i) printf( 02x , (unsigned int) cipherText[i]); printf( \n ); return 0; } int main(int argc, char *argv[]) { if (argc 2) { printf( SkĪadnia: s tekst do zaszyfrowania \n , argv[0]); return EXIT_FAILURE; } encryptText(argv[1]); } W systemie Mac OS X program ten moĔna skompilowaè przy uĔyciu kompilatora gcc. $ gcc -o textcrypt textcrypt.m -lobjc Uruchom program i obserwuj, co siö dzieje. $ ./textcrypt The quick brown fox jumped over the lazy dog Szyfrowanie tekstu: The quick brown fox jumped over the lazy dog Ušyty klucz szyfrowania: 606c64fd3adc1c684be94f5fdf1cc718 Zaszyfrowano 48 bajtów 0d462b3ec789cfafc50f0bba49cc73507015ac24ec548bd1ef5a45a770eb34985296256a1c0073021b26c ebc75b63aeb Aby rozszyfrowaè tekst, naleĔy odwróciè czynnoĈci. Program przedstawiony na listingu 10.3 dekoduje dane wejĈciowe do postaci surowych bajtów, a nastöpnie wywoäuje funkcjö CCCrypt, aby rozszyfrowaè tekst szyfru do oryginalnej postaci. Listing 10.3. Deszyfrowanie tekstu przy uĔyciu algorytmu AES-128 (textdecrypt.m) #include CommonCrypto/CommonCryptor.h #include Foundation/Foundation.h #include stdio.h int decode(unsigned char *dest, const char *buf) { char b[3]; int i; b[2] = 0; for(i=0;buf[i];i+=2) { b[0] = buf[i]; b[1] = buf[i+1]; dest[i/2] = (int) strtol(b, NULL, 0x10); } return 0; } int decryptText( const unsigned char *cipherKey, const unsigned char *cipherText ) { Wprowadzenie do Common Crypto _ 231 CCCryptorStatus status; int len = strlen(cipherText) / 2; unsigned char clearText[len]; unsigned char decodedCipherText[len]; unsigned char decodedKey[len]; size_t nDecrypted; int i; decode(decodedKey, cipherKey); decode(decodedCipherText, cipherText); printf( Deszyfrowanie...\n ); status = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, decodedKey, kCCKeySizeAES128, NULL, decodedCipherText, len, clearText, sizeof(clearText), nDecrypted); if (status != kCCSuccess) { printf( Funkcja CCCrypt() zwróciĪa bĪîd d\n , status); return status; } printf( Rozszyfrowano ld bajtów\n , nDecrypted); printf( = s\n , clearText); return 0; } int main(int argc, char *argv[]) { if (argc 3) { printf( SkĪadnia: s klucz zaszyfrowany tekst \n , argv[0]); return EXIT_FAILURE; } decryptText(argv[1], argv[2]); } Do kompilacji tego programu uĔyj kompilatora gcc. $ gcc -o textdecrypt textdecrypt.m -lobjc Aplikacja przyjmuje dwa argumenty: klucz szyfrowania uĔyty podczas szyfrowania tekstu i zaszyfrowany tekst z programu textencrypt. $ ./textdecrypt 606c64fd3adc1c684be94f5fdf1cc7180d462b3ec789cfafc50f0bba49cc73507015ac24ec548bd1ef ´5a45a770eb Deszyfrowanie... Rozszyfrowano 44 bajtów = The quick brown fox jumped over the lazy dog Szyfrowanie stanowe Korzystanie z biblioteki Common Crypto w trybie stanowym wymaga utworzenia obiektu klasy CCCryptor oraz zainicjowania go kluczem i konfiguracjñ, które dostarcza siö jako typ danych CCCryptorRef. Nastöpnie wprowadza siö dane wejĈciowe, a dane do bufora wyj- Ĉciowego sñ wysyäane po kaĔdym wywoäaniu funkcji CCCryptorUpdate. W przypadku szyfru 232 _ Rozdziaĥ 10. Implementowanie algorytmów szyfrowania blokowego na wejĈciu moĔna podaè pojedynczy blok danych (w razie potrzeby dopeäniony, aby speäniaè wymagania dotyczñce rozmiaru bloku). W przypadku szyfru strumieniowego na wejĈciu moĔna podaè dane dowolnej däugoĈci, a na wyjĈciu otrzymuje siö dane o takiej samej däugoĈci. Po zaszyfrowaniu lub rozszyfrowaniu wszystkich danych nastöpuje opróĔnienie obiektu za pomocñ funkcji CCCryptorFinal i zapis wyniku. Nastöpnie obiekt moĔna zwolniè przy uĔyciu funkcji CCCryptorRelease. Obiektu klasy CCCryptor moĔna wielokrotnie uĔy- waè do strumieniowania lub innych operacji stanowych. Nie trzeba go inicjowaè dla kaĔdego nowego pakietu. Implementacja szyfrowania stanowego jest przedstawiona na listingu 10.4. Dodany zostaä losowy wektor inicjujñcy. Aby uäatwiè wdroĔenie tego kodu w aplikacjach, do pracy z danymi zostaäa uĔyta klasa NSData. Listing 10.4. Funkcja szyfrujñca wykorzystujñca stanowy obiekt szyfrowania (stateful_crypt.m) #include CommonCrypto/CommonCryptor.h #include Foundation/Foundation.h #include stdio.h NSData *encrypt_AES128( NSData *clearText, NSData *key, NSData *iv ) { CCCryptorStatus cryptorStatus = kCCSuccess; CCCryptorRef cryptor = NULL; NSData *cipherText = nil; size_t len_outputBuffer = 0; size_t nRemaining = 0; size_t nEncrypted = 0; size_t len_clearText = 0; size_t nWritten = 0; unsigned char *ptr, *buf; int i; len_clearText = [ clearText length ]; cryptorStatus = CCCryptorCreate( kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, (const void *) [ key bytes ], kCCBlockSizeAES128, (const void *) [ iv bytes ], cryptor ); /* OkreĞlenie rozmiaru danych wyjĞciowych na podstawie rozmiaru danych wejĞciowych */ len_outputBuffer = CCCryptorGetOutputLength(cryptor, len_clearText, true); nRemaining = len_outputBuffer; buf = calloc(1, len_outputBuffer); ptr = buf; cryptorStatus = CCCryptorUpdate( cryptor, (const void *) [ clearText bytes ], len_clearText, ptr, nRemaining, nEncrypted ); Wprowadzenie do Common Crypto _ 233 ptr += nEncrypted; nRemaining -= nEncrypted; nWritten += nEncrypted; cryptorStatus = CCCryptorFinal( cryptor, ptr, nRemaining, nEncrypted ); nWritten += nEncrypted; CCCryptorRelease(cryptor); cipherText = [ NSData dataWithBytes: (const void *) buf length: (NSUInteger) nWritten ]; free(buf); return cipherText; } Aby uĔyè tej funkcji, naleĔy utworzyè losowy klucz i wektor inicjujñcy. Nastöpnie naleĔy jej przekazaè te informacje wraz z tekstem do zaszyfrowania. Funkcja zwraca obiekt NSData za- wierajñcy zaszyfrowany tekst. Na listingu 10.5 znajduje siö przykäad uĔycia powyĔszej funkcji. Ten zawierajñcy funkcjö main kod moĔna dodaè do pliku Ēródäowego z funkcjñ, aby otrzymaè program szyfrujñcy dane w wierszu poleceþ. Listing 10.5. Przykäad uĔycia funkcji encrypt_AES128 int main(int argc, char *argv[]) { NSData *clearText, *key, *iv, *cipherText; unsigned char u_key[kCCKeySizeAES128], u_iv[kCCBlockSizeAES128]; int i; NSAutoreleasePool *pool = [ [ NSAutoreleasePool alloc ] init ]; if (argc 2) { printf( SkĪadnia: s czystytekst \n , argv[0]); return EXIT_FAILURE; } /* Generowanie losowego klucza i wektora inicjującego */ for(i=0;i sizeof(key);++i) u_key[i] = arc4random() 255; for(i=0;i sizeof(iv);++i) u_iv[i] = arc4random() 255; key = [ NSData dataWithBytes: u_key length: sizeof(key) ]; iv = [ NSData dataWithBytes: u_iv length: sizeof(iv) ]; clearText = [ NSData dataWithBytes: argv[1] length: strlen(argv[1]) ]; cipherText = encrypt_AES128(clearText, key, iv); for(i=0;i [ cipherText length];++i) printf( 02x , ((unsigned char *) [ cipherText bytes ])[i]); printf( \n ); [ pool release ]; } Program do uĔytku na komputerze moĔna skompilowaè za pomocñ kompilatora gcc. $ gcc -o stateful_crypt stateful_crypt.m -lobjc -framework Foundation 234 _ Rozdziaĥ 10. Implementowanie algorytmów szyfrowania Aby móc go przetestowaè w urzñdzeniu iOS, naleĔy go skopiowaè przy uĔyciu kompilatora krzyĔowego z Xcode. $ export PLATFORM=/Developer/Platforms/iPhoneOS.platform $ $PLATFORM/Developer/usr/bin/arm-apple-darwin10-llvm-gcc-4.2 \ -o stateful_crypt stateful_crypt.m \ -isysroot $PLATFORM/Developer/SDKs/iPhoneOS5.0.sdk \ -framework Foundation -lobjc Szyfrowanie z kluczem gĥównym W przedstawionych do tej pory przykäadowych programach do szyfrowania uĔywany byä lo- sowo wybierany klucz. WiñĔe siö z tym problem ochrony tego klucza. Wiemy juĔ, Ĕe zäamanie zabezpieczeþ pöku kluczy urzñdzenia jest moĔliwe, a wiöc to rozwiñzanie nie wchodzi w grö. Gäówny klucz szyfrowania musi byè gdzieĈ przechowywany, ale musi teĔ byè zabezpieczony. W poprzednich rozdziaäach dowiedziaäeĈ siö, Ĕe w dobrych implementacjach do rozszyfro- wania danych potrzebne sñ informacje podawane przez uĔytkownika. Wówczas szyfrowanie zaleĔy od „czegoĈ, co mamy” (danych i zaszyfrowanego klucza gäównego) oraz „czegoĈ, co wiemy” (hasäa). Funkcje derywacyjne kluczy (ang. key derivation function — KDF) tworzñ klucze na bazie jakiejĈ tajnej wartoĈci, np. hasäa. Funkcja KDF przyjmuje takñ wartoĈè i wyko- nujñc seriö permutacji, tworzy z niej klucz szyfrowania o Ĕñdanym rozmiarze. Tergo klucza moĔna nastöpnie uĔyè do zaszyfrowania klucza gäównego. Nasuwa siö pytanie, po co w ogóle uĔywaè gäównego klucza szyfrowania, zamiast po prostu uĔyè klucza derywowanego. Gäówny klucz szyfrowania, jeĈli jest caäy czas chroniony, nigdy nie musi byè zmieniany. Gdy uĔytkownik zmieni swoje hasäo, to wystarczy ponownie wygenerowaè klucz gäówny przy uĔyciu nowego klucza derywowanego. Gdyby dane byäy bezpoĈrednio powiñzane z hasäem, to przy kaĔdej zmianie hasäa trzeba by byäo wszystkie te dane szyfrowaè od nowa. Innñ zaletñ tego podejĈcia jest to, Ĕe moĔna zaszyfrowaè na róĔne sposoby wiele kopii klucza gäównego. Na przykäad druga kopia tego klucza mogäaby zostaè zaszyfrowana przy uĔyciu klucza derywowanego z odpowiedzi na pytania bezpieczeþstwa (np. Jak ma na imiö Twój zwierzak?). Takie pytania sñ przydatne, gdy uĔytkownik zapomni swojego hasäa. Ponadto aplikacja moĔe zezwalaè, aby wielu uĔytkowników korzystaäo z tych samych zaszy- frowanych danych, np. poprzez sieè albo iCloud. Szyfrujñc te wspólne dane jednym kluczem gäównym, aplikacja moĔe przechowywaè wiele kopii wspólnego klucza gäównego i chroniè go kluczami derywowanymi z haseä uĔytkowników. Nie wszystkie aplikacje chroniñ klucz gäówny przy uĔyciu funkcji derywujñcej klucze, przez co sñ bardziej podatne na niektóre rodzaje ataku. NajczöĈciej spotykanym niewäaĈciwym spo- sobem uĔycia hasäa jest utworzenie z niego zwykäego skrótu kryptograficznego i uĔycie go jako klucza szyfrowania. W projektowaniu metod szyfrowania odpornych na ataki metodñ brutalnej siäy najwaĔniejszñ rolö odgrywajñ funkcje derywujñce klucze. UĔycie tylko krypto- graficznego algorytmu mieszajñcego typu MD5 albo SHA1 sprawia, Ĕe klucz moĔna zäamaè metodñ brutalnej siäy lub säownikowñ przy uĔyciu niewielkiego klastra komputerów, a nawet w niektórych przypadkach potöĔnego jednego komputera stacjonarnego. Niektóre rzñdy dysponujñ nawet moĔliwoĈciami zaprojektowania i wyprodukowania specjalnych ukäadów elektronicznych do wykonywania ataków metodñ siäowñ, które mogñ znaczñco przyspieszyè operacjö äamania hasäa. Proste mieszanie hasäa jest säabym rozwiñzaniem nawet dla zwykäych programów, nie mówiñc juĔ o aplikacjach, które mogäyby zainteresowaè jakiĈ rzñd. Szyfrowanie z kluczem gĥównym _ 235 Funkcje derywacyjne kluczy w porównaniu z mieszaniem kryptograficznym i innymi technikami majñ wiele zalet. Po pierwsze: funkcje te przepuszczajñ dane wejĈciowe przez seriö iteracji kryptograficznych, w wyniku których powstaje klucz szyfrowania. W odróĔnieniu od prostego skrótu kryptograficznego funkcja KDF moĔe wykonaè 1000, a nawet 10 000 powtórzeþ. KaĔda iteracja obliczania klucza zwiöksza iloĈè zuĔywanych cykli procesora, co znacznie utrudnia przeprowadzenie skutecznego ataku metodñ brutalnej siäy. WeĒmy na przykäad klucz dery- wowany, którego wygenerowanie na urzñdzeniu zajmuje jednñ sekundö. Podczas logowania do aplikacji przy uĔyciu prawidäowego hasäa to sekundowe opóĒnienie byäoby praktycznie niezauwaĔalne, ale atak metodñ brutalnej siäy zostaäby przez to znacznie bardziej wydäuĔo- ny, niĔ gdyby uĔyto tylko prostego skrótu. Obliczenia dla kaĔdej zgadywanej wartoĈci zaj- mowaäyby okoäo jednej sekundy. Kolejnñ zaletñ funkcji derywacyjnej jest to, Ĕe moĔe ona przedäuĔyè lub skróciè hasäo, aby wygenerowaè klucz o Ĕñdanej däugoĈci. Dziöki temu nawet z czterocyfrowego hasäa moĔna by byäo utworzyè klucz 128- lub 256-bitowy albo o jeszcze jakimĈ innym rozmiarze. PBKDF2 (ang. password-based key derivation function) to funkcja derywujñca klucze opisana w specyfikacji PKCS algorytmu RSA jako funkcja derywujñca klucze szyfrowania z haseä. UĔywa siö jej w wielu popularnych implementacjach szyfrowania, wliczajñc program File Vault fir- my Apple, TrueCrypt oraz WPA/WPA2 do zabezpieczania sieci WiFi. Funkcja PBKDF2 przyjmuje na wejĈciu hasäo i tworzy przy jego uĔyciu klucz szyfrowania, stosujñc Ĕñdanñ liczbö iteracji. W kryptografii säowem sól okreĈla siö szereg bitów majñcych za zadanie utrudniè przepro- wadzenie niektórych rodzajów ataków kryptoanalitycznych, takich jak ataki säownikowe wykonywane przy uĔyciu töczowych tablic. Gdy do hasäa zostanie dodana domieszka soli, wtedy to samo hasäo w innym miejscu da inny klucz. Sposób uzyskiwania soli leĔy caäkowicie w gestii programisty. Do wersji systemu iOS 5 jako soli uĔywano niepowtarzalnego numeru sprzötowego UDID urzñdzenia. Dziöki temu zaszyfrowany klucz pasowaä tylko wtedy, gdy algorytm byä uruchamiany na tym samym urzñdzeniu, na którym dokonano szyfrowania (pod warunkiem, Ĕe atakujñcy go nie sfaäszowaä). Gdy w systemie iOS 5 zabroniono uĔywania tego identyfikatora do tych celów, programiĈci byli zmuszeni poszukaè czegoĈ innego. Padäo na adres MAC karty sieciowej urzñdzenia, który jest niepowtarzalny i obecny w kaĔdym urzñdze- niu. Na listingu 10.6 jest przedstawiona przykäadowa metoda, która pobiera tö informacjö i zwra- ca jñ jako obiekt klasy NSString gotowy do uĔytku jako sól. Listing 10.6. Pobieranie adresu MAC karty sieciowej urzñdzenia #import Foundation/Foundation.h #include openssl/evp.h #include sys/socket.h #include sys/sysctl.h #include net/if.h #include net/if_dl.h - (NSString *)query_mac { int mib[6]; size_t len; char *buf; unsigned char *ptr; struct if_msghdr *ifm; struct sockaddr_dl *sdl; 236 _ Rozdziaĥ 10. Implementowanie algorytmów szyfrowania mib[0] = CTL_NET; mib[1] = AF_ROUTE; mib[2] = 0; mib[3] = AF_LINK; mib[4] = NET_RT_IFLIST; if ((mib[5] = if_nametoindex( en0 )) == 0) return NULL; if (sysctl(mib, 6, NULL, len, NULL, 0) 0) return NULL; if ((buf = malloc(len)) == NULL) return NULL; if (sysctl(mib, 6, buf, len, NULL, 0) 0) return NULL; ifm = (struct if_msghdr *)buf; sdl = (struct sockaddr_dl *)(ifm + 1); ptr = (unsigned char *)LLADDR(sdl); NSString *out = [ NSString stringWithFormat:@ 02X: 02X: 02X: 02X: 02X: 02X , *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5) ]; free(buf); return out; } Gdy wartoĈè soli jest ĈciĈle zwiñzana z urzñdzeniem, tak jak w tym przypadku, zaszyfrowanych danych nie da siö odczytaè z kopii na innym urzñdzeniu. W zaleĔnoĈci od potrzeby moĔe to byè dokäadnie to, czego szukasz, lub wröcz odwrotnie. JeĔeli dane muszñ daè siö odczytaè na dowolnym urzñdzeniu, sól moĔna generowaè losowo za pierwszym razem przy ustawianiu hasäa i przechowywaè wraz z zaszyfrowanym kluczem gäównym na urzñdzeniu. NiezaleĔnie od sposobu wygenerowania soli jej wartoĈci, hasäa i liczby iteracji moĔna uĔyè do wygenerowania klucza szyfrowania, przy uĔyciu którego nastöpnie moĔna zaszyfrowaè klucz gäówny. PKCS5_PBKDF2_HMAC_SHA1 jest popularnñ funkcjñ PBKDF2 dostöpnñ w OpenSSL. Na listingu 10.7 przedstawiona jest implementacja dla systemu iOS napisana przy uĔyciu biblioteki Common Crypto. Listing 10.7. Implementacja funkcji PKCS5_PBKDF2_HMAC_SHA1 #include CommonCrypto/CommonDigest.h #include CommonCrypto/CommonHMAC.h #include CommonCrypto/CommonCryptor.h #include stdlib.h #include stdio.h #include string.h int PKCS5_PBKDF2_HMAC_SHA1( const char *pass, int passlen, const unsigned char *salt, int saltlen, int iter, int keylen, unsigned char *out) { unsigned char digtmp[CC_SHA1_DIGEST_LENGTH], *p, itmp[4]; int cplen, j, k, tkeylen; Szyfrowanie z kluczem gĥównym _ 237 unsigned long i = 1; CCHmacContext hctx; p = out; tkeylen = keylen; if (!pass) passlen = 0; else if (passlen == -1) passlen = strlen(pass); while(tkeylen) { if (tkeylen CC_SHA1_DIGEST_LENGTH) cplen = CC_SHA1_DIGEST_LENGTH; else cplen = tkeylen; itmp[0] = (unsigned char)((i 24) 0xff); itmp[1] = (unsigned char)((i 16) 0xff); itmp[2] = (unsigned char)((i 8) 0xff); itmp[3] = (unsigned char)(i 0xff); CCHmacInit( hctx, kCCHmacAlgSHA1, pass, passlen); CCHmacUpdate( hctx, salt, saltlen); CCHmacUpdate( hctx, itmp, 4); CCHmacFinal( hctx, digtmp); memcpy(p, digtmp, cplen); for (j = 1; j iter; j++) { CCHmac(kCCHmacAlgSHA1, pass, passlen, digtmp, CC_SHA1_DIGEST_LENGTH, digtmp); for(k = 0; k cplen; k++) p[k] ^= digtmp[k]; } tkeylen-= cplen; i++; p+= cplen; } return 1; } Przy uĔyciu tej implementacji moĔna derywowaè klucz z hasäa i soli. Jako argumenty wywoäa- nia tej funkcji naleĔy przekazaè hasäo, däugoĈè hasäa, sól, däugoĈè soli, liczbö iteracji, rozmiar klucza oraz wskaĒnik na alokowany bufor: NSString *device_id = [ myObject query_mac ]; unsigned char out[16]; char *passphrase = secret! ; int r = PKCS5_PBKDF2_HMAC_SHA1( passphrase, strlen(passphrase), [ device_id UTF8String ], strlen([ device_id UTF8String]), 10000, 16, out); W powyĔszym przykäadzie zostaäa ustawiona liczba 10 000 iteracji, co oznacza, Ĕe zanim funkcja PKCS5_PBKDF2_HMAC_SHA1 zwróci klucz, najpierw wykona na nim 10 000 operacji. WartoĈè tö moĔna zwiökszyè albo zmniejszyè w zaleĔnoĈci od tego, ile zasobów procesora chce siö zuĔyè do wygenerowania klucza (co ma bezpoĈrednie przeäoĔenie na to, ile zasobów proce- sora bödzie potrzebnych do wykonania ataku brutalnñ siäñ). W typowym iPadzie pierwszej generacji wykonanie 10 000 powtórzeþ zajmuje okoäo jednej sekundy. NaleĔy wziñè to pod uwagö, planujñc ergonomiö korzystania z urzñdzenia. 238 _ Rozdziaĥ 10. Implementowanie algorytmów szyfrowania Wygenerowanego klucza moĔna nastöpnie uĔyè do zaszyfrowania klucza gäównego. Nastöp- nie zaszyfrowany klucz gäówny i sól moĔna zapisaè na urzñdzeniu. Na listingu 10.8 przedsta- wiony jest program szyfrujñcy klucz gäówny przy uĔyciu klucza derywowanego przy uĔyciu funkcji PKCS5_PBKDF2_HMAC_SHA1. Listing 10.8. Funkcja szyfrujñca klucz gäówny przy uĔyciu funkcji PBKDF2 int encrypt_master_key( unsigned char *dest, const unsigned char *master_key, size_t key_len, const char *passphrase, const unsigned char *salt, int slen ) { CCCryptorStatus status; unsigned char cipherKey[key_len]; unsigned char cipherText[key_len + kCCBlockSizeAES128]; size_t nEncrypted; int r; r = PKCS5_PBKDF2_HMAC_SHA1( passphrase, strlen(passphrase), salt, slen, 10000, key_len, cipherKey); if (r 0) return r; status = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, cipherKey, key_len, NULL, master_key, key_len, cipherText, sizeof(cipherText), nEncrypted); if (status != kCCSuccess) { printf( Funkcja CCCrypt() zwróciĪa bĪîd d\n , status); return status; } memcpy(dest, cipherText, key_len); return 0; } Geoszyfrowanie Mimo Ĕe gäówny klucz szyfrowania jest juĔ zabezpieczony hasäem, jego ochronö moĔna jesz- cze wzmocniè dodatkowymi technikami. Biorñc pod uwagö, Ĕe wiökszoĈè pracowników firm uĔywa haseä äatwych do zäamania, warto zwiökszyè poziom bezpieczeþstwa poprzez zasto- sowanie technik lokalizacyjnych. Geoszyfrowanie (ang. geo-encryption) polega na wykorzy- staniu do szyfrowania danych okreĈlonych lokalizacji geograficznych. Atakujñcy, chcñc rozszy- frowaè tak zaszyfrowane dane, musi znaè wspóärzödne jakiegoĈ tajnego miejsca, np. jakiejĈ jednostki rzñdowej. Geoszyfrowanie _ 239 Szyfrowanie lokalizacyjne to zaawansowana technika, o wiele bardziej wyrafinowana niĔ zwykäa logika kodu dotyczñca lokalizacji. Wiesz juĔ z pierwszej czöĈci tej ksiñĔki, Ĕe atakujñcy moĔe z äatwoĈciñ ominñè wewnötrzne testy logiczne, a nawet sforsowaè je metodñ brutalnej siäy. Wspóärzödne GPS moĔna sfaäszowaè tak, aby urzñdzenie „myĈlaäo”, Ĕe znajduje siö w okre- Ĉlonym miejscu. Ponadto testy sprawdzajñce lokalizacjö wymagajñ zapisania w urzñdzeniu wspóärzödnych GPS wybranego tajnego miejsca, które same w sobie mogñ byè äakomym kñskiem dla przestöpcy. Gdy hakerowi uda siö zäamaè zabezpieczenia urzñdzenia, to jego nastöpnym krokiem moĔe byè fizyczny atak na miejsce, którego lokalizacjö uda mu siö odnaleĒè. Wszystkie te techniki dajñ tylko pozorne poczucie bezpieczeþstwa. TrudnoĈciñ w opracowywaniu dobrego systemu kryptograficznego z wykorzystaniem geo- szyfrowania jest entropia. WyobraĒmy sobie, Ĕe haker dokonuje ataku säownikowego z wykorzy- staniem zamiast säów wszystkich moĔliwych par wartoĈci däugoĈci i szerokoĈci geograficznych. Kluczem w geoszyfrowaniu jest fizyczna lokalizacja, z którñ zwiñzany jest szyfr, w zwiñzku z czym w tego rodzaju szyfrowaniu nie naleĔy wykorzystywaè lokalizacji zapisanych w ksiñĔce adresowej urzñdzenia ani pamiöci map Google. Atakujñcy na podstawie informacji o tym, gdzie zdobyä urzñdzenie, a takĔe danych pochodzñcych z samego urzñdzenia moĔe odgad- nñè przybliĔonñ lokalizacjö uĔytñ do szyfrowania w promieniu okoäo 32 kilometrów. JeĔeli za- szyfrowany plik zostaä powiñzany z lokalizacjñ z dokäadnoĈciñ do jednego metra, to w tym okrögu o promieniu 32 kilometrów istnieje okoäo miliarda moĔliwych kombinacji lokalizacyjnych. Liczba ta znacznie siö zmniejsza wraz ze stopniem dokäadnoĈci lokalizacji. Przy 10-metrowym promieniu liczba kombinacji szerokoĈci i däugoĈci geograficznych spada do stu milionów, a przy 100 metrach jest ich juĔ tylko 10 milionów. Wykonanie ataku metodñ brutalnej siäy przy 10 mi- lionach kombinacji zajöäoby bardzo maäo czasu — zapewne zaledwie kilka godzin. Dlatego w technice tej waĔnñ rolö odgrywajñ funkcje derywujñce klucze. UĔywajñc funkcji derywacji kluczy w poäñczeniu z geoszyfrowaniem, moĔna sprawiè, Ĕe iloĈè obliczeþ potrzebna do wygenerowania klucza w znacznym stopniu udaremni ataki, nie po- wodujñc zbyt duĔych niedogodnoĈci dla uĔytkownika. WeĒmy na przykäad funkcjö PBKDF2, o której byäa mowa wczeĈniej w tym rozdziale. JeĈli zastosuje siö duĔñ liczbö iteracji, aby wyge- nerowanie klucza zajmowaäo od 5 do 10 sekund, atak metodñ säownikowñ zajmowaäby bardzo duĔo czasu. Przy 10 milionach kombinacji, jeĈli kaĔda próba zajmuje piöè sekund, na rozszy- frowanie urzñdzenia potrzeba 578 dni. Gdyby zwiökszyè poziom zabezpieczeþ i ograniczyè promieþ do 10 metrów, to atak w obszarze o promieniu 32 kilometrów zajñäby okoäo 15 lat. Aby skróciè iloĈè czasu potrzebnego na wykonanie ataku, haker musiaäby zdezasemblowaè i przenieĈè algorytm derywacji klucza oraz kod obiektu deszyfrujñcego dane do potöĔniejszego systemu. To takĔe wymaga czasu. Przyjmujñc, Ĕe nowoczesne urzñdzenia z systemem iOS sñ wyposaĔone w szybkie dwurdzeniowe procesory, moĔna spodziewaè siö tylko niewielkiego przyspieszenia, chyba Ĕe do ataku zostanie uĔyty caäy klaster komputerów. Im krótszy okres przydatnoĈci chronionych danych, tym wiöcej zasobów trzeba mieè, aby przeprowadziè sku- teczny atak. Entropiö moĔna dodatkowo powiökszyè poprzez dodanie czynnika czasu. Rozszerzajñc szyfro- wanie geograficzne o dodatkowy parametr, jakim jest czas, moĔna jeszcze bardziej zmniejszyè okno, w którym moĔliwe jest rozszyfrowanie danych. JeĈli na przykäad dane moĔna bödzie rozszyfrowaè tylko w czasie jednej godziny w ciñgu doby, czas potrzebny na przeprowadzenie ataku wydäuĔy siö 24-krotnie. Ta technika szyfrowania moĔe byè uĔyta do zabezpieczenia ma- teriaäów, których tajnoĈè zaleĔy od czasu i lokalizacji, np. hitu filmowego. Skrócenie czasu do póä godziny powoduje wydäuĔenie ataku 48 razy. 240 _ Rozdziaĥ 10. Implementowanie algorytmów szyfrowania Aby zastosowaè geoszyfrowanie w swojej aplikacji, moĔesz uĔyè znanej Ci juĔ funkcji PBKDF2. OkreĈl najlepszñ liczbö iteracji, biorñc pod uwagö wymagany poziom zabezpieczeþ. Na przy- käad w iPhonie 4 wykonanie 650 000 iteracji zajmuje okoäo piöciu sekund. Pamiötaj jednak, Ĕe przestöpca moĔe mieè nowszy i znacznie szybszy model urzñdzenia. Na listingu 10.9 przed- stawiona jest zmodyfikowana wersja funkcji wywoäujñca funkcjö PBKDF2 w celu zaszyfrowa- nia klucza gäównego przy uĔyciu danych GPS jako hasäa i wykonujñca 650 000 iteracji w celu wygenerowania klucza. Listing 10.9. Funkcja geoszyfrowania szyfrujñca klucz gäówny przy uĔyciu wspóärzödnych GPS int geo_encrypt_master_key( unsigned char *dest, const unsigned char *master_key, size_t key_len, const char *geo_coordinates, const unsigned char *salt, int slen ) { CCCryptorStatus status; unsigned char cipherKey[key_len]; unsigned char cipherText[key_len + kCCBlockSizeAES128]; size_t nEncrypted; int r; r = PKCS5_PBKDF2_HMAC_SHA1( geo_coordinates, strlen(geo_coordinates), salt, slen, 650000, key_len, cipherKey); if (r 0) return r; status = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, cipherKey, key_len, NULL, master_key, key_len, cipherText, sizeof(cipherText), nEncrypted); if (status != kCCSuccess) { printf( Funkcja CCCrypt() zwróciĪa bĪîd d\n , status); return status; } memcpy(dest, cipherText, key_len); return 0; } Funkcji tej naleĔy podaè parö wspóärzödnych zamiast hasäa. unsigned char encrypted_master_key[16]; char *coords = 30.2912,-97.7385 ; geo_encrypt_master_key( encrypted_master_key, master_key, kCCKeySizeAES128, coords, salt, salt_len); Geoszyfrowanie _ 241 Wspóärzödne GPS moĔna zaokrñgliè do najbliĔszego miejsca dziesiötnego w zaleĔnoĈci od pro- mienia obszaru blokady (tabela 10.1). Pamiötaj, Ĕe moduä GPS w wiökszoĈci urzñdzeþ z sys- temem iOS wskazuje wspóärzödne z ograniczonñ precyzjñ, zazwyczaj do okoäo 10 metrów. Tabela 10.1. Tabela zaokrñgleþ wartoĈci GPS Jednostki 1,0 0,1 0,01 0,001 0,0001 0,00001 Precyzja szerokoļci geograficznej 111 km 11 km 1,11 km 111 m 11,1 m 1,1 m Precyzja dĥugoļci geograficznej 67,5 km 6,75 km 676 m 67,6 m 6,76 m 67,6 cm Geoszyfrowanie z hasĥem Bezpieczeþstwo geoszyfrowania jest caäkowicie zaleĔne od utrzymania w tajemnicy wspóä- rzödnych geograficznych wybranego miejsca (i ewentualnie czasu). JeĈli zostanie uĔyta funkcja derywacyjna kluczy zajmujñca odpowiedniñ iloĈè czasu, atakujñcy bödzie potrzebowaä bardzo precyzyjnych informacji na temat lokalizacji geograficznej wykorzystanej do szyfrowania. Atak moĔna jeszcze bardziej utrudniè, dodajñc do tego wszystkiego hasäo. NaleĔy zmodyfiko- waè funkcjö PBKDF2 w taki sposób, aby generowaäa dwa klucze szyfrowania: jeden na pod- stawie hasäa i drugi na podstawie wspóärzödnych geograficznych. Nastöpnie klucze te äñczy siö za pomocñ operacji XOR w jeden klucz, którego z kolei uĔywa siö do zaszyfrowania klucza gäównego (listing 10.10). Listing 10.10. Funkcja szyfrujñca klucz gäówny przy uĔyciu hasäa i wspóärzödnych GPS int geo_encrypt_master_key( unsigned char *dest, const unsigned char *master_key, size_t key_len, const char *geocoordinates, const char *passphrase, const unsigned char *salt, int slen ) { CCCryptorStatus status; unsigned char cKey1[key_len], cKey2[key_len]; unsigned char cipherText[key_len + kCCBlockSizeAES128]; size_t nEncrypted; int r, i; /* Derywacja klucza z hasáa */ r = PKCS5_PBKDF2_HMAC_SHA1( passphrase, strlen(passphrase), salt, slen, 10000, key_len, cKey1); if (r 0) return r; /* Derywacja klucza z danych GPS */ r = PKCS5_PBKDF2_HMAC_SHA1( geocoordinates, strlen(geocoordinates), salt, slen, 650000, key_len, cKey2); if (r 0) return r; 242 _ Rozdziaĥ 10. Implementowanie algorytmów szyfrowania /* Poáączenie kluczy operacją XOR */ for(i=0;i key_len;++i) cKey1[i] ^= cKey2[i]; status = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, cKey1, key_len, NULL, master_key, key_len, cipherText, sizeof(cipherText), nEncrypted); if (status != kCCSuccess) { printf( Funkcja CCCrypt() zwróciĪa bĪîd d\n , status); return status; } memcpy(dest, cipherText, key_len); return 0; } Funkcjö tö wywoäuje siö w podobny sposób jak pozostaäe funkcje encrypt_master_key przed- stawione w tym rozdziale. W tym przypadku naleĔy tylko podaè zarówno wspóärzödne GPS, jak i hasäo. unsigned char encrypted_master_key[16]; char *coords = 30.2912,-97.7385 ; char *passphrase = passphrase ; geo_encrypt_master_key( encrypted_master_key, master_key, kCCKeySizeAES128, coords, passphrase, salt, salt_len); Aby dodaè czynnik czasu, naleĔy tylko wkomponowaè w kod godzinö, póä godziny, kwadrans lub dowolny inny okres. unsigned char encrypted_master_key[16]; char *coords = 30.2912,-97.7385,05:00 ; char *passphrase = passphrase ; geo_encrypt_master_key( encrypted_master_key, master_key, kCCKeySizeAES128, coords, passphrase, salt, salt_len); Teraz atakujñcy musi znaè (lub zdobyè) hasäo, wspóärzödne GPS i czas, aby rozszyfrowaè klucz gäówny. Dzielenie kluczy na serwerze Podobnie jak za pomocñ danych geograficznych algorytm szyfrowania moĔna wzmocniè tak- Ĕe poprzez zastosowanie kluczy przechowywanych na serwerze, aby przed rozszyfrowaniem danych urzñdzenie musiaäo najpierw uwierzytelniè siö w zdalnym systemie. W tym przypadku generuje siö dwa klucze, które miesza siö za pomocñ operacji XOR i za pomocñ uzyskanego klucza szyfruje siö klucz gäówny. Jeden z tych kluczy jest generowany przy uĔyciu podanego Dzielenie kluczy na serwerze _ 243 przez uĔytkownika hasäa. Drugi natomiast jest generowany losowo i zapisywany na zaufanym zdalnym serwerze przy pierwszym instalowaniu aplikacji. Po uruchomieniu programu uĔyt- kownik wpisuje hasäo, aby wygenerowaè swojñ poäowö klucza, ale dodatkowo musi uwierzytel- niè siö na serwerze, aby uzyskaè drugñ poäowö. Dziöki temu ani serwer, ani urzñdzenie nie ma wszystkiego, co jest potrzebne do rozszyfrowania danych aplikacji. To dodatkowo utrudnia atakowanie haseä, poniewaĔ samo hasäo nie wystarcza do rozszyfrowania danych. Przestöpca musi nie tylko zäamaè hasäo, ale dodatkowo zabezpieczenia serwera zawierajñcego drugñ poäowö klucza. Kolejnñ korzyĈciñ jest moĔliwoĈè usuniöcia klucza z serwera, gdy zostanie odkryte, Ĕe urzñdzenie skradziono lub Ĕe zäamano jego zabezpieczenia. W rozdziale 12. poznasz techniki reagowania na próby szperania w zabezpieczeniach i sposoby ich praktycznego zastosowania do ochrony danych, które nie sñ w danej chwili w uĔyciu. Usuniöcie klucza z serwera jest efektywnym sposobem na uniemoĔliwienie eskalacji problemu. Opisywana technika ma jednak teĔ wady. KradzieĔ danych z urzñdzenia moĔe nastñpiè dopiero po ich rozszyfrowaniu. Podczas uĔywania danych w aplikacji w pamiöci muszñ byè przecho- wywane te dane albo klucze szyfrowania. Jednak technika ta w niektórych zastosowaniach sprawdza siö doskonale. Na listingu 10.11 przedstawiony jest program generujñcy dwa klucze. Dziaäa on podobnie do wczeĈniej prezentowanych programów. Pierwszy klucz, userKey, jest generowany z podanego przez uĔytkownika hasäa. Drugi, serverKey, jest generowany losowo. Listing 10.11. Funkcja generujñca parö kluczy #include CommonCrypto/CommonCryptor.h #include string.h #include stdio.h int split_encrypt_master_key( unsigned char *encryptedMasterKey, /* Zapisywany w buforze */ unsigned char *serverKey, /* Zapisywany w buforze */ const unsigned char *master_key, size_t key_len, const char *passphrase, const unsigned char *salt, int slen ) { CCCryptorStatus status; unsigned char userKey[key_len]; unsigned char cipherText[key_len + kCCBlockSizeAES128]; size_t nEncrypted; int r, i; /* Derywacja klucza uĪytkownika z hasáa */ r = PKCS5_PBKDF2_HMAC_SHA1( passphrase, strlen(passphrase), salt, slen, 10000, key_len, userKey); if (r 0) return r; /* Generowanie losowego klucza, zapis w serverKey */ for(i=0;i key_len;++i) serverKey[i] = arc4random() 255; /* Poáączenie XOR kluczy w kluczu userKey */ for(i=0;i key_len;++i) userKey[i] ^= serverKey[i]; 244 _ Rozdziaĥ 10. Implementowanie algorytmów szyfrowania status = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, userKey, key_len, NULL, master_key, key_len, cipherText, sizeof(cipherText), nEncrypted); if (status != kCCSuccess) { printf( CCCrypt() failed with error d\n , status); return status; } memcpy(encryptedMasterKey, cipherText, key_len); return 0; } Aby uĔyè tej funkcji, naleĔy alokowaè dwa bufory: jeden na zaszyfrowany klucz gäówny, a drugi na klucz serwerowy. Jako argumenty wywoäania podaje siö hasäo, sól i inne informacje. unsigned char encryptedMasterKey[kCCKeySizeAES128]; unsigned char serverKey[kCCKeySizeAES128]; split_encrypt_master_key( encryptedMasterKey, serverKey, master_key, kCCKeySizeAES128, passphrase, salt, slen); Po zakoþczeniu dziaäania przez funkcjö klucz serwerowy bödzie zapisany w alokowanym dla niego buforze. Powinien on zostaè zarejestrowany na serwerze i usuniöty z urzñdzenia przy pierwszym uruchomieniu aplikacji. Miödzy urzñdzeniem a serwerem musi znajdowaè siö me- chanizm uwierzytelniajñcy zabezpieczajñcy operacjö przesyäania klucza z powrotem z serwera na urzñdzenie w przyszäoĈci. PoniewaĔ klucze sñ wymieniane podczas pierwszego uruchomienia aplikacji, naleĔy siö upewniè, Ĕe urzñdzenie nie jest w tym momencie w Ĕaden sposób zaatakowane. Klucz z serwera moĔna dostarczaè takĔe na inne sposoby. Wstawienie do aplikacji dodatkowego pola tekstowego na klucz serwerowy moĔe pomóc zapobiec atakom podmiany kluczy. Zabezpieczanie pamiýci Jak juĔ wiesz, przechowywanie kluczy szyfrowania i innych danych w pamiöci jest niebez- pieczne, poniewaĔ jeĈli urzñdzenie jest zaatakowane, to mogñ one zostaè skradzione podczas wczytywania ich do pamiöci. W nowszych wersjach systemu iOS wbudowane sñ mechanizmy losowej zmiany rozkäadu przestrzeni adresowej, które majñ za zadanie ukrywaè lokalizacje frag- mentów pamiöci na tyle skutecznie, Ĕe zanim haker je znajdzie, to spowoduje awariö programu. Niestety, jak widzieliĈmy, zmienne egzemplarzowe jözyka Objective-C moĔna z äatwoĈciñ znaleĒè poprzez mapowanie systemu wykonawczego, co w znacznym stopniu ogranicza przy- datnoĈè techniki ASLR. PoniĔej znajdujñ siö wskazówki, jak zabezpieczyè pamiöè: Zabezpieczanie pamiýci _ 245 x Nie zapisuj niczego w pamiöci, dopóki uĔytkownik nie uwierzytelni siö i dane nie zostanñ rozszyfrowane. Dopóki uĔytkownik nie wpisze hasäa, nie powinno siö nawet zapisywaè haseä, danych uwierzytelniajñcych ani Ĕadnych innych informacji. JeĈli jest to moĔliwe, to znaczy, Ĕe szyfrowanie w aplikacji jest Ēle zaimplementowane. x Nie przechowuj kluczy szyfrowania ani innych waĔnych danych w zmiennych egzempla- rzowych w jözyku Objective-C, poniewaĔ moĔna äatwo uzyskaè do nich dostöp. Zamiast tego röcznie alokuj dla nich pamiöè. To nie uniemoĔliwi hakerowi podpiöcia siö pod Twojñ aplikacjö za pomocñ debugera, ale utrudni przeprowadzenie ataku. Ataki dokonywane podczas uĔywania urzñdzenia sñ najczöĈciej przeprowadzane przez automaty, a nie ludzi. Oprogramowanie takie najpierw siöga po najprostsze Ĉrodki dziaäania i jeĈli nie zostaäo specjalnie zaprojektowane pod kñtem konkretnej aplikacji, rzadko kiedy znajduje inne dane niĔ te zapisane w zmiennych egzemplarzowych. x Nie zapisuj w zmiennych egzemplarzowych wskaĒników na klucze szyfrowania i inne waĔne dane. x JeĈli to tylko moĔliwe, usuwaj dane z pamiöci natychmiast, gdy przestajñ byè potrzebne. Je- Ĕeli na przykäad program zostaje przeniesiony do dziaäania w tle w trybie zawieszonym albo uĔytkownik zamknie jakiĈ plik, klucze szyfrowania potrzebne do korzystania z tych zasobów powinny zostaè usuniöte. Czyszczenie pamiýci JeĈli uĔywane dane sñ zapisywane w pamiöci, to po zakoþczeniu pracy powinny byè zawsze usuwane. Takie informacje jak klucze szyfrowania, numery kart kredytowych itp. nie muszñ zalegaè na dysku podczas dziaäania aplikacji, a pozostawienie ich stanowi tylko dodatkowe ryzyko utraty. Na szczöĈcie wiökszoĈè klas z biblioteki Foundation umoĔliwia odwoäywanie siö do wskaĒników na rzeczywiste dane, co pozwala na ich usuniöcie przed zwolnieniem. W obiektach klasy NSData dostöpna jest metoda bytes pozwalajñca tworzyè wskaĒniki na dane w pamiöci. Przy uĔyciu funkcji memset dane te moĔna z äa
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Łamanie i zabezpieczanie aplikacji w systemie iOS
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: