Czym jest entropia?
Entropia w teorii informacji to miara, ile informacji zostało zakodowanych w ciągu znaków. Dokładniej mówiąc jest to średnia ilość informacji, przypadająca na jeden znak z danego zbioru, z danym prawdopodobieństwem zdarzenia. W celu obliczenia entropii dla tekstu-dokumentu, musimy najpierw wykonać histogram dla wszystkich znaków. Dzięki temu będziemy mogli wyznaczyć prawdopodobieństwa wystąpienia każdego ze znaków. Także entropia dla danego tekstu wynosi:
![]() |
Źródło: wikipedia.org |
p(i) to prawdopodobieństwo wystąpienia danego znaku - obliczone na podstawie histogramu
n - liczba wszystkich niepowtarzalnych znaków
i - zmienna iterująca
r - podstawa logarytmu, w tym wypadku jest równa 2, ponieważ mówimy o bitach, jako o jednostce entropii
Po co mi entropia?
Entropia informacyjna (czyli ta o której tu mówimy) jest najprostszą miarą siły naszego hasła,
bowiem jest w ścisłym związku z ilością możliwych kombinacji potrzebnych do złamania hasła. Dokładniej, możemy obliczyć maksymalną liczbę kombinacji potrzebnych do złamania naszego hasła za pomocą wzoru:
2^liczba_bitów_entropii_hasła
Krótko mówiąc, im więcej bitów entropii w haśle, tym trudniej atakującemu będzie je złamać. Za
względnie bezpieczne hasło uznaje się hasło powyżej 56 bitów entropii.
Obliczanie entropii dla hasła
W przypadku obliczania entropii dla hasła sprawa wygląda prościej, ponieważ prawdopodobieństwo wystąpienia każdego ze znaku jest takie same. Obliczenie entropii hasła zaczynamy od obliczenia liczby bitów entropii w jednym znaku. W tym celu stosujemy wzór:
H(x) = log2(n)
log2(26) = około 4.7 bitu entropii na znak.
Entropia dla całego hasła wynosi:
entropia_jednego_znaku * liczba_znaków_w_haśle
Obliczanie entropii dla znaków z wielu zbiorów
Co zrobić w przypadku, gdy mamy hasło zawierające nie tylko małe znaki, ale również litery wielkie, cyfry i znaki specjalne? Otóż wystarczy zsumować wszystkie możliwe znaki z tych zbiorów, które utworzą nam zmienną n. Podstawiając do wzoru:
H(x) = log2(n)
Dla przykładu policzmy entropię hasła składającego się z 8 znaków (małych liter [a-z] oraz
cyfr [0-9]). Nasze n w tym przypadku wyniesie 26+10=36. 26 małych liter i 10 cyfr. Liczba bitów w jednym znaku to log2(36) = około 5,17. Z racji tego, że hasło ma 8 znaków otrzymujemy 8*5,17 = 41,36 bitów entropii hasła.
Przykład wzrostu liczby bitów entropii w zależności od hasła
Idąc dalej tym tropem możemy stwierdzić, że najwięcej bitów przypadnie na jeden znak w przypadku wykorzystania znaków z wszystkich zbiorów.
Dla znaków ze zbiorów:
-znaków specjalnych: !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
-małych liter: abcdefghijklmnopqrstuvwxyz
-wielkich liter: ABCDEFGHIJKLMNOPQRSTUVWXYZ
-cyfr: 0123456789
otrzymujemy w sumie 94 znaki i w haśle, w którym wykorzystujemy co najmniej jeden znak z każdego z tych zbiorów, w jednym znaku zapisanych jest aż 6,55 bitów entropii. Spójrzmy na przykłady:
Hasło: aaaa
Bitów entropii na znak: 4.7
Bitów entropii w haśle: 18.80
Hasło: aaa9
Bitów entropii na znak: 5.17
Bitów entropii w haśle: 20.68
Hasło: aa9C
Bitów entropii na znak: 5.95
Bitów entropii w haśle: 23.82
Hasło: a9C$
Bitów entropii na znak: 6.57
Bitów entropii w haśle: 26.28
Jak widać z powyższego przykładu, różnica miedzy hasłem zawierającym tylko małe litery, a hasłem, które zawiera co najmniej jeden znak z każdego zbioru jest bardo duża, bo aż 8 bitów entropii.
Prosty program do obliczania entropii dla hasła oraz maksymalnej liczby operacji potrzebnych do złamania hasła metodą BruteForce:
# -*- coding: utf-8 -*- #Tobiasz Siemiński import string, math def getEntropy(chars, passwordLength): """ zwraca liczbę bitów entropii w haśle """ charsLength = len(chars) entropyPerChar = math.log(charsLength,2) entropy = passwordLength*entropyPerChar print "\nDługość hasła: %d" %(passwordLength) print "Entropia jednego znaku: %f" %(float(entropyPerChar)) print "Entropia podanego hasła: %f" %(entropy) print "Do złamania hasła potrzeba około %d operacji\n" %(2**entropy) return entropy def checkPassword(): """ prosi o hasło i na jego podstawie określa zbiór znaków z jakiego składa się hasło """ haslo = raw_input("Podaj hasło:") lower = False upper = False digits = False special = False tab = "" for znak in haslo: if znak in string.ascii_lowercase: lower = True elif znak in string.ascii_uppercase: upper = True elif znak in string.digits: digits = True elif znak in string.punctuation: special = True if lower == True: tab+=string.ascii_lowercase if upper == True: tab+=string.ascii_uppercase if digits == True: tab+=string.digits if special == True: tab+=string.punctuation tab+=" " print "Zbiór znaków: %s" %(tab) entropy = getEntropy(tab, len(haslo)) return entropy entropy = checkPassword() if entropy < 56: print "Hasło SŁABE" entropy = 0 while entropy < 56: print "Podaj hasło jeszcze raz" entropy = checkPassword()
3 komentarze:
Widzialem gdzie indziej nieco inna metode liczenia entropii (troche mnie to dziwi), ale
chyba lepsza. Dlaczego?
W tamtej liczyla sie ilosc wystapien znaku,
bo np. haslo "aaaa" jest przeciez slabsze od "abcd" (nawet jesli tylko troche).
nie wiem dlaczego niby haslo aaaa jest slabsze od abcd.... nas logike: prawdopodbienstwo, ze ktos podal haslo aaaa, jest takie samo, ze podal abcd..., czy 1111 albo 1234, albo 4321.... nie bawmy sie w jakas metafizyke, ze haslo 2468 jest mniej prawdopodbne od 1234. Musimy traktowac ze jest tak samo prawdopodbne.
Hasła w których powtarzają się znaki po sobie, a szczególnie gdy całe hasło stanowią takie same znaki, np. "aaaa" czy "1111" są słabsze z jednego powodu. Po prostu program bruteforce może przyjąć taktykę łamania hasła "wzrostowo". Np. łamiąc maksymalnie 4 znakowe hasło, najpierw sprawdzi "a", potem "aa", "aaa", "aaaa" i jak widać łamie je w 4 próbie, chociaż entropia mówi że to hasło jest równe "abcd". To oczywiście bardzo trywialny przykład, ale pewne hasła faktycznie znajdują się tak blisko krawędzi pewnych zbiorów że mogą mieć (chwilową) niższą entropię (jeśli nadal można mówić o tym "entropia").
Prześlij komentarz