Suggested Rules for Suggested Passwords

Web sites rely on passwords to authenticate users. It’s a way for users to prove who they claim to be — if you know an account’s password then you (are assumed to) own the account. Sites must protect passwords to prevent attackers from stealing them. Users must create strong passwords to prevent attackers from easily guessing them. The password suggestion feature of Safari 7 helps users do this. (Here are a few more ideas).

This case study demonstrates some of the features of John the Ripper, a password cracking tool. It gives a perspective on the strength of suggested passwords and reinforces why sites must manage passwords securely. The scenario assumes that a hacker has obtained a list of hashed passwords and they wish to target the format of Safari’s suggestions.

Safari suggests passwords that consist of four alphanumeric triples. This produces a 15-character password with 12 characters of entropy (the three dashes are static and predictable). They keyspace is 6212 (26 each of upper- and lower-case letters plus 10 digits), or about 271 if you prefer powers of 2.

With this in mind, let’s explore some of John’s features.

First, open the john.local.conf file and add the following line:

.include "$JOHN/john.ahtk.conf"

Now open the john.ahtk.conf file. Add custom rules from the following examples to this file.

Create a Charset File with an External Filter

John uses charset files when running in incremental mode. The charset file contains all the candidate symbols for a password, including probability measures based on position. John selects symbols based on filters and generates probabilities based on cracked passwords in its john.pot file.

Create a filter that extracts upper- and lower-case letters and numbers. Filters are defined by the filter() function that uses a subset of the C programming language.

void filter()
  int i, c;

  i = 0;
  while (c = word[i++]) {
    if(c < '0' || c > '9') {
      if((c < 'a' || c > 'z') && (c < 'A' || c > 'Z')) {
        word = 0;

Create a charset based on this filter. Your john.pot file influences the quality of the probabilities associated with each symbol. In the following example, the charset is generated from over 3 million plaintext passwords.

$ ./john --make-charset=alphanumeric.chr —external=Filter_Alphanumeric john.pot
Loaded 3190632 plaintexts
Generating charsets... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 DONE
Generating cracking order... DONE
Successfully written charset file: alphanumeric.chr (62 characters)

Define an Incremental Rule

Create a rule called Alphanumeric12 to generate 12-character passwords based on the charset that’s just been created.

File = $JOHN/alphanumeric.chr
MinLen = 12
MaxLen = 12
CharCount = 62

Verify that the rule works by using the--stdout option to print brute force guesses.

$ ./john --stdout --incremental:Alphanumeric12 | less

Define a Transformation Rule

Create a rule that inserts a dash (-) after every three letters. The following rule uses the insert (i) command. The insert command’s syntax is iNX, which the John documentation explains as “insert character X in position N and shift the rest right”.


Positions are 0-based (position 0 is before the first letter). Hence, we’ll insert a dash into positions 3, 7, and 11. Note that john requires a single-character position indicator, which means that position 11 needs a special representation (i.e. i11- would be invalid). John uses A-Z to represent positions 10 and greater, e.g. 11 maps to B.

Test your rule by piping the output of the incremental Alphanumeric12 rule into the AHTK_Safari rule. Your specific guesses will vary, but the output should be four triples separated by dashes.

$ ./john --stdout --incremental=Alphanumeric12 | ./john --rules=AHTK_Safari --pipe --stdout | less

Define a Word Generator with an External Rule

The previous technique that combined an incremental charset and a rule demonstrated some John concepts, but wasn’t the most efficient way to crack this password format.

John supports custom word generation using C functions similar to the filter() used previously. The init() function sets up global variables. The generate() function produces a guess based on the pre-defined word[] array.

The following rule generates four triples separated by dashes.

int alnum[63];
int character[15];
int length, maxlength;
int position;

void init()
  int c;
  int i;

  i = 0;
  alnum[0] = 'a';
  while(i < 26) {
    c = alnum[i++];
    alnum[i] = ++c;
  alnum[26] = 'A';
  while(i < 52) {
    c = alnum[i++];
    alnum[i] = ++c;
  alnum[52] = '0';
  while(i < 62) {
    c = alnum[i++];
    alnum[i] = ++c;
  alnum[62] = 0;

  length = 15;
  maxlength = 15;
  position = length - 1;
  i = 0;

  while(i < length) {
    character[i] = 0;
    word[i] = alnum[character[i]];
  --character[length - 1];
  --word[length - 1];
  word[length] = 0;

  word[3] = '-';
  word[7] = '-';
  word[11] = '-';

void generate()
  while(++character[position] > 61) {
    if(position) {
      character[position] = 0;
      word[position] = alnum[character[position]];
      if(3 == position || 7 == position || 11 == position)
    else {
      word = 0;

  word[position] = alnum[character[position]];
  position = length - 1;

Test your rule with the --stdout option. The output should be identical to the following:

$ ./john --stdout --external=AHTK_IncrementalSafari | less

Try Some Test Cases

Create the following four text files.


Now try the combined incremental/transform rules. Remember that it’s up to the web site to store passwords securely. The following examples demonstrate the relative cracking speed for different hashing algorithms. A real web app should store the hashed value of a password based on at least an hmac or, even better, PBKDF2 (with well-chosen parameters). But that’s out of scope for this discussion.

$ ./john --stdout --incremental=Alphanumeric12 | ./john --rules=AHTK_Safari --pipe --format=raw-sha256 safari_sha256.txt

$ ./john --stdout --incremental=Alphanumeric12 | ./john --rules=AHTK_Safari --pipe --format=raw-sha1 safari_sha1.txt

$ ./john --stdout --incremental=Alphanumeric12 | ./john --rules=AHTK_Safari --pipe --format=raw-md5 safari_md5.txt

To prove the point that the dashes do not increase entropy, the following command runs a brute force against 12-character passwords.

$ ./john --incremental=Alphanumeric12 --format=raw-md5 safari_no_dash_md5.txt

Finally, try each of the example sets against your custom generator.

$ ./john --external=AHTK_IncrementalSafari --format=raw-sha256 safari_sha256.txt 
Loaded 8 password hashes with no different salts (Raw SHA-256 [32/64])

The generator will be slightly faster and may seem more elegant than the piping technique. However, the order of guesses will be different because the charset-based approach creates sequences in a statistical order (based on observed passwords) whereas the custom generator works in lexicographic order (e.g. aaa, aab, aac, …). In practice, the distribution of characters in suggested passwords should be uniform. So, neither approach should be superior. They will both eventually exhaust the keyspace —- but not in any reasonable or feasible time.

That’s all for now. There’s plenty more to talk about regarding password security, let alone other security topics. Security has a keyspace of concepts that I won’t be exhausting any time soon.

2 thoughts on “Suggested Rules for Suggested Passwords”

Leave a Reply

Please log in using one of these methods to post your comment: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s