#!/usr/bin/env python

'''
I wrote this code in order to generate leetspeak rules for oclHashcat-plus.

While I know oclHashcat-plus already comes with the rules/leetspeak.rule file,
I needed a more complete set of rules that would combine leet spellings between
them.

For instance, the word "password" would be expanded to: 
  p@ssword 
  p@ssw0rd
  pa$$word
  pa$$w0rd
  ...

Currently, this code only combines leet rules up to 4 different leet spellings.
Basically, this means that running this program will generate the following set of rules:

# leetspeak single
  sa@
  sb8
  ...

# leetspeak multi
  sa@ sb8
  sa4 sb8
  ...
  sa@ so0 st7
  sa4 so0 st7
  sa@ so0 st+
  ...

# maximum combinations set to 4 (hard-coded with the max_combi variable)
  sa@ sb8 sc< se3
  sa4 sb8 sc< se3
  sa@ sb6 sc< se3
  ...
  sb8 sc< se3 so0
  ...

NB. max_combi = 4 because oclHashcat-plus-0.05 only supports up to 8 mangling
functions per rule (lowercasing takes 4 functions), but with the 0.06 release
it will be increased to 16, so you may set max_combi to 8. But IMHO 5 provides
a good covering/perfomance ratio.

Usage:
$ python hashcat_l33t.pyt > rules/leet.rule
$ ./oclHashcat-plus ... -r rules/leet.rule
'''

import itertools

# Please note that this table is missing many leet speak spellings,
# I intentionnaly selected the most common ones.
leet_table = {
  'a': '@4',
  'b': '68',
  'c': '<',
  'e': '3i2',
  'g': '69',
  'i': '1!|e',
  'l': '1!|',
  'o': '0',
  's': '$5',
  't': '7+',
  'x': '%',
  }

# will only combine up to 4 different leet spellings
max_combi = 4

for cur_len in range(1, max_combi+1): 

  for combi in itertools.combinations(leet_table, cur_len):
     
    # rules to lowercase upper-cased letters -> sAa sBb ...
    lower = ['s%s%s' % (k.upper(), k) for k in combi]

    # lets go
    vals = [leet_table[k] for k in combi]
    for prod in itertools.product(*vals):
      subst = []
      for i, k in enumerate(combi):
        subst.append('s%s%s' % (k, prod[i]))

      print('%s' % (' '.join(subst)))
      print('%s %s' % (' '.join(lower), ' '.join(subst))) # lowercase before leet mangling
