Anders Bergh ha decodificato l'OS X Password Assistant e ha scritto un'utilità della riga di comando che fa lo stesso lavoro. Da la sua fonte puoi scoprire che tutta la generazione della password è fatta da una funzione di libreria non documentata proprietaria SFPWAPasswordSuggest()
dal framework SecurityFoundation .
Sebbene la funzione sia proprietaria e non esista alcuna documentazione ufficiale di Apple, puoi giocare con la funzione stessa o con l'utilità della riga di comando che la circonda per capire che cosa produce. Allister Banks l'ha già fatto nel 2015 , ipoteticamente per OS X Yosemite, e ha prodotto uno snippet di codice che produce praticamente gli stessi risultati (ad eccezione di alcuni strane preferenze dell'autore, come limitare l'intervallo di numeri casuali disponibili).
In poche parole, SFPWAPasswordSuggest()
prende due parole casuali da un vocabolario e inserisce tra loro un numero casuale e un carattere speciale (in quest'ordine). La lunghezza del numero casuale è tale che la lunghezza complessiva della stringa sarà esattamente come richiesto e ci sarà sempre un singolo carattere speciale. Per quanto riguarda il vocabolario, OS X da Yosemite a High Sierra usa /System/Library/Frameworks/SecurityInterface.framework/Resources/pwa_dict_en.gz
, 287 kb di dimensione e con 83935 parole inglesi di lunghezza tra 2 e 24, per questo:
$ gzcat pwa_dict_en.gz | python2 -c 'import sys
> sys.stdin.read(512)
> word_counts = dict()
> for num_of_letters_index in range(64):
> value = int(sys.stdin.read(8).strip(), 16)
> if value:
> word_counts[num_of_letters_index] = value
> print "Distribution:", word_counts'
Distribution: {1: 26, 2: 191, 3: 1229, 4: 3170, 5: 5591, 6: 8913, 7: 12452, 8: 13462, 9: 12163, 10: 9820, 11: 7007, 12: 4516, 13: 2704, 14: 1429, 15: 691, 16: 329, 17: 150, 18: 61, 19: 21, 20: 5, 21: 3, 22: 1, 24: 1}
$
Ecco come puoi analizzare il file . In altre versioni di OS X, la funzione può essere progettata in modo leggermente diverso; usa dtruss ./sf-pwgen
per capire.
Si noti che la GUI limita la lunghezza della password generata con il numero 31. Per quanto posso vedere, la funzione non genera un errore per richieste più lunghe, tuttavia non è garantito il funzionamento per password più lunghe di 31 caratteri. In realtà, per le password sopra i 67 caratteri, è quasi garantito il fallimento; come puoi vedere sopra il vocabolario non contiene abbastanza parole di lunghezza sufficiente, e l'algoritmo di generazione non gestisce bene questo caso, semplicemente restituendo una passphrase breve composta solo da numeri e un carattere speciale:
$ ./sf-pwgen -c 1 -l 68
2814154076!
$
EDIT 24.01.2018: a nome di Alex Recuenco :
Calcolo dell'entropia
Seguendo la soluzione @ximaera.
import math
x = {1: 26, 2: 191, 3: 1229, 4: 3170, 5: 5591, 6: 8913, 7: 12452, 8: 13462, 9: 12163, 10: 9820, 11: 7007, 12: 4516, 13: 2704, 14: 1429, 15: 691, 16: 329, 17: 150, 18: 61, 19: 21, 20: 5, 21: 3, 22: 1, 24: 1}
def entropy(pass_length, n_symbols = 30):
combinations = 0
for key, value in x.items():
for key2, value2 in x.items():
if (key + key2) < (pass_length - 1):
combinations += value * value2 * n_symbols * (10 ** (pass_length - key - key2 - 1))
# last value
return {'combinations': combinations, 'entropy': math.log2(combinations)}
print(entropy(31))
Che quando lo esegui:
> {'combinations': 1124445877165765109161692550890600, 'entropy': 109.79284135298234}
110 bit di entropia, massimo ... Ho pensato che sarebbe stato meglio per qualche motivo. L'entropia di una password di soli caratteri numerici di lunghezza 30 è di circa 100