#
# This file is part of John the Ripper password cracker,
# Copyright (c) 1996-2006,2008-2013 by Solar Designer
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted.
#
# There's ABSOLUTELY NO WARRANTY, express or implied.
#
# Please note that although this configuration file is under the cut-down BSD
# license above, many source files in John the Ripper are under GPLv2.
# For licensing terms for John the Ripper as a whole, see doc/LICENSE.
#
# ...with changes in the jumbo patch, by various authors
#

# The [Options] section is for general options only.
# Note that MPI specific options have been moved
# to [Options.MPI]
# There is also a new section [Options.OpenCL]
# for OpenCL specific options
# Default settings for Markov mode have been moved
# to [Markov.Default], but you can define other
# Markov modes as well, see ../doc/MARKOV
[Options]
# Default wordlist file name (including in batch mode)
Wordlist = $JOHN/password.lst
# Use idle cycles only
Idle = Y
# Crash recovery file saving delay in seconds
Save = 60
# Beep when a password is found (who needs this anyway?)
Beep = N
# if set to Y then dynamic format will always work with bare hashes. Normally
# dynamic only uses bare hashes if a single dynamic type is selected with
# the -format=  (so -format=dynamic_0 would use valid bare hashes).
DynamicAlwaysUseBareHashes = N

# Default Single mode rules
SingleRules = Single

# Default batch mode Wordlist rules
BatchModeWordlistRules = Wordlist

# Default wordlist mode rules when not in batch mode (if any)
# If this is set and you want to run once without rules, use --rules:none
#WordlistRules = Wordlist

# Default loopback mode rules (if any)
# If this is set and you want to run once without rules, use --rules:none
LoopbackRules = Loopback

# Default/batch mode Incremental mode
# Warning: changing these might currently break resume on existing sessions
DefaultIncremental = ASCII
#DefaultIncrementalUTF8 = UTF8
DefaultIncrementalLM = LM_ASCII

# Time formatting string used in status ETA.
#
# TimeFormat24 is used when ETA is within 24h, so it is possible to omit
# the date then if you like, and show seconds instead.
#
# %c  means 'local' specific canonical form, such as:
# 05/06/11 18:10:34
#
# Other examples
# %d/%m/%y %H:%M   (day/mon/year hour:min)
# %m/%d/%y %H:%M   (mon/day/year hour:min)
# %Y-%m-%d %H:%M   (ISO 8601 style, 2011-05-06 18:10)
TimeFormat = %Y-%m-%d %H:%M
TimeFormat24 = %H:%M:%S

# For single mode, load the full GECOS field (before splitting) as one
# additional candidate. Normal behavior is to only load individual words
# from that field. Enabling this can help when this field contains email
# addresses or other strings that are better used unsplit, but it increases
# the number of words tried so it may also slow things down. If enabling this
# you might want to bump SingleWordsPairMax too, below, to 10 or more.
PristineGecos = N

# Over-ride SINGLE_WORDS_PAIR_MAX in params.h. This may slow down Single mode
# but it may also help cracking a few more candidates. Default in core John
# is 4 while the Jumbo default is 6.
SingleWordsPairMax = 6

# Emit a status line whenever a password is cracked (this is the same as
# passing the --crack-status option flag to john). NOTE: if this is set
# to true here, --crack-status will toggle it back to false.
CrackStatus = N

# When printing status, show number of candidates tried (eg. 123456p). Note
# that the number *is* now equal to "words tried" and nothing else.
# This is added to the "+ Cracked" line in the log as well.
StatusShowCandidates = N

# Write cracked passwords to the log file (default is just the user name)
LogCrackedPasswords = N

# Disable the dupe checking when loading hashes. For testing purposes only!
NoLoaderDupeCheck = N

# Default --encoding for input files (ie. login/GECOS fields) and wordlists
# etc.  If this is not set here (you need to uncomment it) and --encoding is
# not used either, the default is ISO-8859-1 for Unicode conversions and 7-bit
# ASCII encoding is assumed for rules - so eg. uppercasing of letters other
# than a-z will not work at all!
#DefaultEncoding = UTF-8

# Default --target-encoding for Microsoft hashes (LM, NETLM et al) when input
# encoding is UTF-8. CP850 would be a universal choice for covering most
# "Latin-1" countries.
#DefaultMSCodepage = CP850

# Default --internal-encoding to be used by mask mode, and within the rules
# engine when both input and "target" encodings are Unicode (eg. UTF-8
# wordlist and NT hashes). In some cases this hits performance but lets us
# do things like case conversions for UTF-8. You can pick any supported
# codepage that has as much support for the input data as possible - eg. for
# "Latin-1" language passwords you can use ISO-8859-1, CP850 or CP1252 and it
# will probably not make a difference.
#DefaultInternalEncoding = CP1252

# Warn if seeing UTF-8 when expecting some other encoding, or vice versa.
#WarnEncoding = Y

# Always report (to screen and log) cracked passwords as UTF-8, regardless of
# input encoding. This is recommended if you have your terminal set for UTF-8.
#AlwaysReportUTF8 = Y

# Always store Unicode (UTF-16) passwords as UTF-8 in john.pot, regardless
# of input encoding. This prevents john.pot from being filled with mixed
# and eventually unknown encodings. This is recommended if you have your
# terminal set for UTF-8 and/or you want to run --loopback for LM->NT
# including non-ASCII.
#UnicodeStoreUTF8 = Y

# Always report/store non-Unicode formats as UTF-8, regardless of input
# encoding. Note: The actual codepage that was used is not stored anywhere
# except in the log file. This is needed eg. for --loopback to crack LM->NT
# including non-ASCII.
#CPstoreUTF8 = Y

# Default verbosity is 3, valid figures are 1-5 right now.
# 4-5 enables some extra output
# 2 mutes rules & incremental output in logs (LOTS of lines)
# 1 even mutes printing (to screen) of cracked passwords
Verbosity = 2

# If set to Y, do not output, log  or store cracked passwords verbatim.
# This implies a different default .pot database file "secure.pot" instead
# of "john.pot" but it can still be overridden using --pot=FILE.
# This also overrides other options, eg. LogCrackedPasswords.
SecureMode = N

# If set to Y, a session using --fork or MPI will signal to other nodes when
# it has written cracks to the pot file (note that this writing is delayed
# by buffers and the "Save" timer above), so they will re-sync.
ReloadAtCrack = Y

# If set to Y, resync pot file when saving session.
ReloadAtSave = Y

# If this file exists, john will abort cleanly
AbortFile = /var/run/john/abort

# While this file exists, john will pause
PauseFile = /var/run/john/pause

[Options:MPI]
# Automagically disable OMP if MPI is used (set to N if
# you want to run one MPI process per multi-core host)
MPIOMPmutex = Y

# Print a notice if disabling OMP (when MPIOMPmutex = Y)
# or when running OMP and MPI at the same time
MPIOMPverbose = Y


# These formats come disabled because of problems with many drivers. Even
# when disabled, you can use them as long as you spell them out with the
# --format option. Or you can delete a line, comment it out, or change to 'N'
[Disabled:Formats]
DEScrypt-opencl = N


# Options that affect both CUDA and OpenCL:
[Options:GPU]
# Show GPU temperature, fan and utilization along with normal status output
SensorsStatus = Y

# Abort session if GPU hits this temperature (in C)
AbortTemperature = 95


[Options:OpenCL]
# Set default OpenCL platform and/or device. Command line options will
# override these. If neither is set, we will search for a GPU or fall-back
# to platform 0, device 0.
#Platform = 0
#Device = 0

# Global max. single kernel invocation duration, in ms. Setting this low
# (eg. 10-100 ms) gives you a better responding desktop but lower performance.
# Setting it high (eg. 200-500 ms) will maximize performance but your desktop
# may lag. Really high values may trip watchdogs (eg. 5 seconds). Some versions
# of AMD Catalyst may hang if you go above 200 ms, and in general any good
# kernel will perform optimally at 100-200 ms anyway.
#Global_MaxDuration = 200

# Some formats vectorize their kernels in case the device says it's a good
# idea. Some devices give "improper" hints which means we vectorize but get
# a performance drop. If you have such a device, uncommenting the below
# will disable vectorizing globally.
# With this set to N (or commented out) you can force it per session with
# the --force-scalar command-line option instead.
#ForceScalar = Y

# Global build options. Format-specific build options below may be
# concatenated to this.
GlobalBuildOpts = -cl-mad-enable

# Format-specific settings:

# Uncomment the below for nvidia sm_30 and beyond
#sha512crypt_BuildOpts = -cl-nv-maxrregcount=80

# Example: Override auto-tune for RAR format.
#rar_LWS = 128
#rar_GWS = 8192


# Markov modes, see ../doc/MARKOV for more information
[Markov:Default]
# Default Markov mode settings
#
# Statsfile cannot be specified on the command line, so
# specifying it here is mandatory
Statsfile = $JOHN/stats
# MkvLvl and MkvMaxLen should also be specified here, as a fallback for
# --markov usage without specifying LEVEL and/or LENGTH on the command line
MkvLvl = 200
MkvMaxLen = 12
# MkvMinLvl and MkvMinLen should not be specified at all in [Markov:Default],
# or they should be equal to 0 (which is the default if not specified.
# MkvMinLvl and MkvMinLen can be used in other Markov mode sections
# except [Markov:Default]
; MkvMinLvl = 0
; MkvMinLen = 0

# A user defined character class is named with a single digit, ie. 0..9. After
# the equal-sign, just list all characters that this class should match. You
# can specify ranges within brackets, much like pre-processor ranges in rules.
# BEWARE of encoding if using non-ASCII characters. If you put UTF-8 characters
# here, it will *not* work! You must use a singlebyte encoding and it should
# be the same here as you intend to use for your dictionary.
# You can however put characters here in \xA3 format (for codepoint 0xA3 - in
# many iso-8859 codepages that would mean a pound sign). This works in ranges
# too. Using \x00 is not supported though - it will not be parsed as null.
#
# This is a couple of example classes:
# ?0 matches (one version of) base64 characters
# ?1 matches hex digits
# ?2 matches the TAB character (never try to use \x00!)
[UserClasses]
0 = [a-zA-Z0-9/.]
1 = [0-9a-fA-F]
2 = \x09

[Mask]
# Default mask for -mask if none is given. This is same as Hashcat's default.
DefaultMask = ?1?2?2?2?2?2?2?3?3?3?3?d?d?d?d

# Default mask for Hybrid mask mode if none is given.
DefaultHybridMask = ?w?d?d?d?d

# Mask mode have custom placeholders ?1..?9 that look similar to user classes
# but are a different thing. They are merely defaults for the -1..-9 command
# line options. As delivered, they resemble Hashcat's defaults.
1 = ?l?d?u
2 = ?l?d
3 = ?l?d*!$@_
4 =
5 =
6 =
7 =
8 =
9 =

# these are user defined character sets.  There purpose is to allow custom salt
# values to be used within the salt_regen logic.  These will be the characters
# to use for this character within the salt.  So if we had a salt that was 4
# characters, and 0-9a-m, we can easily do this by 0 = [0-9a-m]  If this is used,
# the regen salt value would be ?0?0?0?0 and salts such as a47m 2kd5 would be valid.
[Regen_Salts_UserClasses]
1 = [1-9]

# A "no rules" rule for super fast Single mode (use with --single=none)
[List.Rules:None]
:

# A "drop all" rule for even faster Single mode (debugging :)
[List.Rules:Drop]
<1'0

# "Single crack" mode rules
[List.Rules:Single]
# Simple rules come first...
:
-s x**
-c (?a c Q
-c l Q
-s-c x** /?u l
# These were not included in crackers I've seen, but are pretty efficient,
# so I include them near the beginning
-<6 >6 '6
-<7 >7 '7 l
-<6 -c >6 '6 /?u l
-<5 >5 '5
# Weird order, eh? Can't do anything about it, the order is based on the
# number of successful cracks...
<* d
r c
-c <* (?a d c
-<5 -c >5 '5 /?u l
-c u Q
-c )?a r l
-[:c] <* !?A \p1[lc] p
-c <* c Q d
-<7 -c >7 '7 /?u
-<4 >4 '4 l
-c <+ (?l c r
-c <+ )?l l Tm
-<3 >3 '3
-<4 -c >4 '4 /?u
-<3 -c >3 '3 /?u l
-c u Q r
<* d M 'l f Q
-c <* l Q d M 'l f Q
# About 50% of single-mode-crackable passwords get cracked by now...
# >2 x12 ... >8 x18
>[2-8] x1\1
>9 \[
# >3 x22 ... >9 x28
>[3-9] x2\p[2-8]
# >4 x32 ... >9 x37
>[4-9] x3\p[2-7]
# >2 x12 /?u l ... >8 x18 /?u l
-c >[2-8] x1\1 /?u l
-c >9 \[ /?u l
# >3 x22 /?u l ... >9 x28 /?u l
-c >[3-9] x2\p[2-8] /?u l
# >4 x32 /?u l ... >9 x37 /?u l
-c >[4-9] x3\p[2-7] /?u l
# Now to the suffix stuff...
<* l $[1-9!0a-rt-z"-/:-@\[-`{-~]
-c <* (?a c $[1-9!0a-rt-z"-/:-@\[-`{-~]
-[:c] <* !?A (?\p1[za] \p1[lc] $s M 'l p Q X0z0 'l $s
-[:c] <* /?A (?\p1[za] \p1[lc] $s
<* l r $[1-9!]
-c <* /?a u $[1-9!]
-[:c] <- (?\p1[za] \p1[lc] Az"'s"
-[:c] <- (?\p1[za] \p1[lc] Az"!!"
-[:c] (?\p1[za] \p1[lc] $! <- Az"!!"
# Removing vowels...
-[:c] /?v @?v >2 (?\p1[za] \p1[lc]
/?v @?v >2 <* d
# crack -> cracked, crack -> cracking
<* l [PI]
-c <* l [PI] (?a c
# mary -> marie
-[:c] <* (?\p1[za] \p1[lc] )y omi $e
# marie -> mary
-[:c] <* (?\p1[za] \p1[lc] )e \] )i val1 oay
# The following are some 3l33t rules
-[:c] l /[aelos] s\0\p[4310$] (?\p1[za] \p1[:c]
-[:c] l /a /[elos] sa4 s\0\p[310$] (?\p1[za] \p1[:c]
-[:c] l /e /[los] se3 s\0\p[10$] (?\p1[za] \p1[:c]
-[:c] l /l /[os] sl1 s\0\p[0$] (?\p1[za] \p1[:c]
-[:c] l /o /s so0 ss$ (?\p1[za] \p1[:c]
-[:c] l /a /e /[los] sa4 se3 s\0\p[10$] (?\p1[za] \p1[:c]
-[:c] l /a /l /[os] sa4 sl1 s\0\p[0$] (?\p1[za] \p1[:c]
-[:c] l /a /o /s sa4 so0 ss$ (?\p1[za] \p1[:c]
-[:c] l /e /l /[os] se3 sl1 s\0\p[0$] (?\p1[za] \p1[:c]
-[:c] l /[el] /o /s s\0\p[31] so0 ss$ (?\p1[za] \p1[:c]
-[:c] l /a /e /l /[os] sa4 se3 sl1 s\0\p[0$] (?\p1[za] \p1[:c]
-[:c] l /a /[el] /o /s sa4 s\0\p[31] so0 ss$ (?\p1[za] \p1[:c]
-[:c] l /e /l /o /s se3 sl1 so0 ss$ (?\p1[za] \p1[:c]
-[:c] l /a /e /l /o /s sa4 se3 sl1 so0 ss$ (?\p1[za] \p1[:c]
# Now to the prefix stuff...
l ^[1a-z2-90]
-c l Q ^[A-Z]
^[A-Z]
l ^["-/:-@\[-`{-~]
-[:c] <9 (?a \p1[lc] A0"[tT]he"
-[:c] <9 (?a \p1[lc] A0"[aA]my"
-[:c] <9 (?a \p1[lc] A0"[mdMD]r"
-[:c] <9 (?a \p1[lc] A0"[mdMD]r."
-[:c] <9 (?a \p1[lc] A0"__"
<- !?A l p ^[240-9]
# Some word pair rules...
# johnsmith -> JohnSmith, johnSmith
-p-c (?a 2 (?a c 1 [cl]
# JohnSmith -> john smith, john_smith, john-smith
-p 1 <- $[ _\-] + l
# JohnSmith -> John smith, John_smith, John-smith
-p-c 1 <- (?a c $[ _\-] 2 l
# JohnSmith -> john Smith, john_Smith, john-Smith
-p-c 1 <- l $[ _\-] 2 (?a c
# johnsmith -> John Smith, John_Smith, John-Smith
-p-c 1 <- (?a c $[ _\-] 2 (?a c
# Applying different simple rules to each of the two words
-p-[c:] 1 \p1[ur] 2 l
-p-c 2 (?a c 1 [ur]
-p-[c:] 1 l 2 \p1[ur]
-p-c 1 (?a c 2 [ur]
# jsmith -> smithj, etc...
-[:c] (?a \p1[lc] [{}]
-[:c] (?a \p1[lc] [{}] \0
# Toggle case...
-c <+ )?u l Tm
-c T0 Q M c Q l Q u Q C Q X0z0 'l
-c T[1-9A-E] Q M l Tm Q C Q u Q l Q c Q X0z0 'l
-c l Q T[1-9A-E] Q M T\0 Q l Tm Q C Q u Q X0z0 'l
-c >2 <G %2?a [lu] T0 M T2 T4 T6 T8 TA TC TE Q M l Tm Q X0z0 'l
-c >2 /?l /?u t Q M c Q C Q l Tm Q X0z0 'l
# Deleting chars...
>[2-8] D\p[1-7]
>[8-9A-E] D\1
-c /?u >[2-8] D\p[1-7] l
-c /?u >[8-9A-E] D\1 l
=1?a \[ M c Q
-c (?a >[1-9A-E] D\1 c
# Inserting a dot...
-[:c] >3 (?a \p1[lc] i[12].
# More suffix stuff...
<- l Az"[190][0-9]"
-c <- (?a c Az"[190][0-9]"
<- l Az"[782][0-9]"
-c <- (?a c Az"[782][0-9]"
<* l $[A-Z]
-c <* (?a c $[A-Z]
# cracking -> CRACKiNG
-c u /I sIi
# Crack96 -> cRACK96
%2?a C Q
# Crack96 -> cRACK(^
/?A S Q
# Crack96 -> CRaCK96
-c /?v V Q
# Really weird charset conversions, like "england" -> "rmh;smf"
:[RL] Q
l Q [RL]
-c (?a c Q [RL]
:[RL] \0 Q
# Both prefixing and suffixing...
<- l ^[1!@#$%^&*\-=_+.?|:'"] $\1
<- l ^[({[<] $\p[)}\]>]
# The rest of two-digit suffix stuff, less common numbers...
<- l Az"[63-5][0-9]"
-c <- (?a c Az"[63-5][0-9]"
# Some multi-digit numbers...
-[:c] (?a \p1[lc] Az"007" <+
-[:c] (?a \p1[lc] Az"123" <+
-[:c] (?a \p1[lc] Az"[0-9]\0\0" <+
-[:c] (?a \p1[lc] Az"1234" <+
-[:c] (?a \p1[lc] Az"[0-9]\0\0\0" <+
-[:c] (?a \p1[lc] Az"12345" <+
-[:c] (?a \p1[lc] Az"[0-9]\0\0\0\0" <+
-[:c] (?a \p1[lc] Az"123456" <+
-[:c] (?a \p1[lc] Az"[0-9]\0\0\0\0\0" <+
# Some [birth] years...
l Az"19[7-96-0]" <+ >-
l Az"20[01]" <+ >-
l Az"19[7-9][0-9]" <+
l Az"20[01][0-9]" <+
l Az"19[6-0][9-0]" <+

[List.Rules:Extra]
# Insert/overstrike some characters...
!?A >[1-6] l i\0[a-z]
!?A l o0[a-z]
!?A >[1-7] l o\0[a-z]
# Toggle case everywhere (up to length 8), assuming that certain case
# combinations were already tried.
-c T1 Q M T0 Q
-c T2 Q M T[z0] T[z1] Q
-c T3 Q M T[z0] T[z1] T[z2] Q
-c T4 Q M T[z0] T[z1] T[z2] T[z3] Q
-c T5 Q M T[z0] T[z1] T[z2] T[z3] T[z4] Q
-c T6 Q M T[z0] T[z1] T[z2] T[z3] T[z4] T[z5] Q
-c T7 Q M T[z0] T[z1] T[z2] T[z3] T[z4] T[z5] T[z6] Q
# Very slow stuff...
l Az"[1-90][0-9][0-9]" <+
-c (?a c Az"[1-90][0-9][0-9]" <+
<[\-9] l A\p[z0]"[a-z][a-z]"
<- l ^[a-z] $[a-z]

# Wordlist mode rules
[List.Rules:Wordlist]
# Try words as they are
:
# Lowercase every pure alphanumeric word
-c >3 !?X l Q
# Capitalize every pure alphanumeric word
-c (?a >2 !?X c Q
# Lowercase and pluralize pure alphabetic words
<* >2 !?A l p
# Lowercase pure alphabetic words and append '1'
<* >2 !?A l $1
# Capitalize pure alphabetic words and append '1'
-c <* >2 !?A c $1
# Duplicate reasonably short pure alphabetic words (fred -> fredfred)
<7 >1 !?A l d
# Lowercase and reverse pure alphabetic words
>3 !?A l M r Q
# Prefix pure alphabetic words with '1'
>2 !?A l ^1
# Uppercase pure alphanumeric words
-c >2 !?X u Q M c Q u
# Lowercase pure alphabetic words and append a digit or simple punctuation
<* >2 !?A l $[2!37954860.?]
# Words containing punctuation, which is then squeezed out, lowercase
/?p @?p >3 l
# Words with vowels removed, lowercase
/?v @?v >3 l
# Words containing whitespace, which is then squeezed out, lowercase
/?w @?w >3 l
# Capitalize and duplicate short pure alphabetic words (fred -> FredFred)
-c <7 >1 !?A c d
# Capitalize and reverse pure alphabetic words (fred -> derF)
-c <+ >2 !?A c r
# Reverse and capitalize pure alphabetic words (fred -> Derf)
-c >2 !?A l M r Q c
# Lowercase and reflect pure alphabetic words (fred -> fredderf)
<7 >1 !?A l d M 'l f Q
# Uppercase the last letter of pure alphabetic words (fred -> freD)
-c <+ >2 !?A l M r Q c r
# Prefix pure alphabetic words with '2' or '4'
>2 !?A l ^[24]
# Capitalize pure alphabetic words and append a digit or simple punctuation
-c <* >2 !?A c $[2!3957468.?0]
# Prefix pure alphabetic words with digits
>2 !?A l ^[379568]
# Capitalize and pluralize pure alphabetic words of reasonable length
-c <* >2 !?A c p
# Lowercase/capitalize pure alphabetic words of reasonable length and convert:
# crack -> cracked, crack -> cracking
-[:c] <* >2 !?A \p1[lc] M [PI] Q
# Try the second half of split passwords
-s x**
-s-c x** M l Q

# Case toggler for cracking MD4-based NTLM hashes (with the contributed patch)
# given already cracked DES-based LM hashes.
# Use --rules=NT to use this
[List.Rules:NT]
:
-c T0Q
-c T1QT[z0]
-c T2QT[z0]T[z1]
-c T3QT[z0]T[z1]T[z2]
-c T4QT[z0]T[z1]T[z2]T[z3]
-c T5QT[z0]T[z1]T[z2]T[z3]T[z4]
-c T6QT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]
-c T7QT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]
-c T8QT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]
-c T9QT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]
-c TAQT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]T[z9]
-c TBQT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]T[z9]T[zA]
-c TCQT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]T[z9]T[zA]T[zB]
-c TDQT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]T[z9]T[zA]T[zB]T[zC]

# Used for loopback. This rule will produce candidates "PASSWOR" and "D" for
# an input of "PASSWORD" (assuming LM, which has halves of length 7).
[List.Rules:Split]
:
-s x**

# Some Office <=2003 files have passwords truncated at 15
[List.Rules:OldOffice]
:
->F>F'F

# Rules from Hash Runner 2014
[List.Rules:o1]
o[0-9A-Z][ -~]

[List.Rules:o2]
o[0-9A-E][ -~] Q M o[0-9A-E][ -~] Q

[List.Rules:o3]
o[0-9][ -~] Q M o[0-9][ -~] Q M o[0-9][ -~] Q

[List.Rules:o]
o[0-9A-Z][ -~]
o[0-9A-E][ -~] Q M o[0-9A-E][ -~] Q

[List.Rules:i1]
i[0-9A-Z][ -~]

[List.Rules:i2]
i[0-9A-E][ -~] i[0-9A-E][ -~]

[List.Rules:i3]
i[0-9][ -~] i[0-9][ -~] i[0-9][ -~]

[List.Rules:i]
i[0-9A-Z][ -~]
i[0-9A-E][ -~] i[0-9A-E][ -~]

[List.Rules:oi]
o[0-9A-Z][ -~]
i[0-9A-Z][ -~]
o[0-9A-E][ -~] Q M o[0-9A-E][ -~] Q
i[0-9A-E][ -~] i[0-9A-E][ -~]

	int i, j, s, next, nextp, val, bucket, randnum, used_charsets;
	int seedarray[56];
	int candidate[32]; /* This needs to be at-least as big as password-length */

	seed = 0;

	while(seed > 0) {
		/* BEGIN System.Random(seed) */
		s = 161803398 - seed++;
		seedarray[55] = s;
		i = val = 1;

		while(i < 55) {
			bucket = 21 * i % 55;
			seedarray[bucket] = val;
			val = s - val;
			if(val < 0) val += 2147483647;
			s = seedarray[bucket];
			i++;
		}

		i = 1;
		while(i < 5) {
			j = 1;
			while(j < 56) {
				seedarray[j] -= seedarray[1 + (j + 30) % 55];
				if(seedarray[j] < 0) seedarray[j] += 2147483647;
				j++;
			}
			i++;
		}
		next = 0;
		nextp = 21;
		/* END System.Random(seed) */

		used_charsets = 0;
		while(used_charsets != 15) {
			i = 0;
			while(i < password_length) {
				/* BEGIN Random.Sample() */
				if (++next >= 56) next = 1;
				if (++nextp >= 56) nextp = 1;
				randnum = seedarray[next] - seedarray[nextp];
				if (randnum == 2147483647) randnum--;
				if (randnum < 0) randnum += 2147483647;
				seedarray[next] = randnum;
				/* END Random.Sample() */

				j = 0;
				while(boundaries_charclass[j] < randnum) j++;

				candidate[i] = j;
				used_charsets |= (1 << j);
				i++;
			}
		}

		i = 0;
		while(i < password_length) {
			/* BEGIN Random.Sample() */
			if (++next >= 56) next = 1;
			if (++nextp >= 56) nextp = 1;
			randnum = seedarray[next] - seedarray[nextp];
			if (randnum == 2147483647) randnum--;
			if (randnum < 0) randnum += 2147483647;
			seedarray[next] = randnum;
			/* END Random.Sample() */
			j = 0;

			if(candidate[i] == 0) {
				while(boundaries_letters[j] < randnum) j++;
				if(lowers[j] != word[i++]) break;
			} else if (candidate[i] == 1) {
				while(boundaries_letters[j] < randnum) j++;
				if(uppers[j] != word[i++]) break;
			} else if (candidate[i] == 2) {
				while(boundaries_numbers[j] < randnum) j++;
				if(numbers[j] != word[i++]) break;
			} else { /* if (word[i] == 3) */
				while(boundaries_symbols[j] < randnum) j++;
				if(symbols[j] != word[i++]) break;
			}
		}
		if(i == password_length) return;
	}
}

# Try sequences of adjacent keys on a keyboard as candidate passwords
[List.External:Keyboard]
int maxlength, length;	// Maximum password length to try, current length
int fuzz;		// The desired "fuzz factor", either 0 or 1
int id[15];		// Current character indices for each position
int m[0x800];		// The keys matrix
int mc[0x100];		// Counts of adjacent keys
int f[0x40], fc;	// Characters for the first position, their count

void init()
{
	int minlength;
	int i, j, c, p;
	int k[0x40];

	// Initial password length to try
	if (req_minlen)
		minlength = req_minlen;
	else
		minlength = 1;
	if (req_maxlen)
		maxlength = req_maxlen;
	else
		maxlength = cipher_limit;	// the format's limit
	fuzz = 1;			// "Fuzz factor", set to 0 for much quicker runs

/*
 * This defines the keyboard layout, by default for a QWERTY keyboard.
 */
	i = 0; while (i < 0x40) k[i++] = 0;
	k[0] = '`';
	i = 0; while (++i <= 9) k[i] = '0' + i;
	k[10] = '0'; k[11] = '-'; k[12] = '=';
	k[0x11] = 'q'; k[0x12] = 'w'; k[0x13] = 'e'; k[0x14] = 'r';
	k[0x15] = 't'; k[0x16] = 'y'; k[0x17] = 'u'; k[0x18] = 'i';
	k[0x19] = 'o'; k[0x1a] = 'p'; k[0x1b] = '['; k[0x1c] = ']';
	k[0x1d] = '\\';
	k[0x21] = 'a'; k[0x22] = 's'; k[0x23] = 'd'; k[0x24] = 'f';
	k[0x25] = 'g'; k[0x26] = 'h'; k[0x27] = 'j'; k[0x28] = 'k';
	k[0x29] = 'l'; k[0x2a] = ';'; k[0x2b] = '\'';
	k[0x31] = 'z'; k[0x32] = 'x'; k[0x33] = 'c'; k[0x34] = 'v';
	k[0x35] = 'b'; k[0x36] = 'n'; k[0x37] = 'm'; k[0x38] = ',';
	k[0x39] = '.'; k[0x3a] = '/';

	i = 0; while (i < 0x100) mc[i++] = 0;
	fc = 0;

	/* rows */
	c = 0;
	i = 0;
	while (i < 0x40) {
		p = c;
		c = k[i++] & 0xff;
		if (!c) continue;
		f[fc++] = c;
		if (!p) continue;
		m[(c << 3) + mc[c]++] = p;
		m[(p << 3) + mc[p]++] = c;
	}
	f[fc] = 0;

	/* columns */
	i = 0;
	while (i < 0x30) {
		p = k[i++] & 0xff;
		if (!p) continue;
		j = 1 - fuzz;
		while (j <= 1 + fuzz) {
			c = k[i + 0x10 - j++] & 0xff;
			if (!c) continue;
			m[(c << 3) + mc[c]++] = p;
			m[(p << 3) + mc[p]++] = c;
		}
	}

	length = 0;
	while (length < minlength)
		id[length++] = 0;
}

void generate()
{
	int i, p, maxcount;

	word[i = 0] = p = f[id[0]];
	while (++i < length)
		word[i] = p = m[(p << 3) + id[i]];
	word[i--] = 0;

	if (i) maxcount = mc[word[i - 1]]; else maxcount = fc;
	while (++id[i] >= maxcount) {
		if (!i) {
			if (length < maxlength) {
				id[0] = 0;
				id[length++] = 0;
			}
			return;
		}
		id[i--] = 0;
		if (i) maxcount = mc[word[i - 1]]; else maxcount = fc;
	}
}

void restore()
{
	int i;

	/* Calculate the length */
	length = 0;
	while (word[length])
		id[length++] = 0;

	/* Infer the first character index */
	i = -1;
	while (++i < fc) {
		if (f[i] == word[0]) {
			id[0] = i;
			break;
		}
	}

	/* This sample can be enhanced to infer the rest of the indices here */
}

# Simplest (fastest?) possible dumb exhaustive search, demonstrating a
# mode that does not need any special restore() handling.
# Defaults to printable ASCII.
[List.External:DumbDumb]
int maxlength;		// Maximum password length to try
int startchar, endchar;	// Range of characters (inclusive)

void init()
{
	int i;

	startchar = ' ';	// Start with space
	endchar = '~';		// End with tilde

	// Create first word, honoring --min-len
	if (!(i = req_minlen))
		i++;
	word[i] = 0;
	while (i--)
		word[i] = startchar;
	word[0] = startchar - 1;

	if (req_maxlen)
		maxlength = req_maxlen;		// --max-len
	else
		maxlength = cipher_limit;	// format's limit
}

void generate()
{
	int i;

	if (++word <= endchar)
		return;

	i = 0;

	while (word[i] > endchar) {
		word[i++] = startchar;
		if (!word[i]) {
			word[i] = startchar;
			word[i + 1] = 0;
		} else
			word[i]++;
	}

	if (i >= maxlength)
		word = 0;
}

/*
 * This mode will resume correctly without any restore handing.
 * The empty function just confirms to John that everything is in order.
 */
void restore()
{
}

# Generic implementation of "dumb" exhaustive search, given a range of lengths
# and an arbitrary charset.  This is pre-configured to try 8-bit characters
# against LM hashes, which is only reasonable to do for very short password
# half lengths.
[List.External:DumbForce]
int maxlength;		// Maximum password length to try
int last;		// Last character position, zero-based
int lastid;		// Character index in the last position
int id[0x7f];		// Current character indices for other positions
int charset[0x100], c0;	// Character set

void init()
{
	int minlength;
	int i, c;

	// Initial password length to try, must be at least 1
	if (req_minlen)
		minlength = req_minlen;
	else
		minlength = 1;
	if (req_maxlen)
		maxlength = req_maxlen;
	else
		maxlength = cipher_limit;	// the format's limit

/*
 * This defines the character set.
 *
 * Let's say, we want to try TAB, all non-control ASCII characters, and all
 * 8-bit characters, including the 8-bit terminal controls range (as these are
 * used as regular national characters with some 8-bit encodings), but except
 * for known terminal controls (risky for the terminal we may be running on).
 *
 * Also, let's say our hashes are case-insensitive, so skip lowercase letters
 * (this is right for LM hashes).
 */
	i = 0;
	charset[i++] = 9;		// Add horizontal TAB (ASCII 9), then
	c = ' ';			// start with space (ASCII 32) and
	while (c < 'a')			// proceed till lowercase 'a'
		charset[i++] = c++;
	c = 'z' + 1;			// Skip lowercase letters and
	while (c <= 0x7e)		// proceed for all printable ASCII
		charset[i++] = c++;
	c++;				// Skip DEL (ASCII 127) and
	while (c < 0x84)		// proceed over 8-bit codes till IND
		charset[i++] = c++;
	charset[i++] = 0x86;		// Skip IND (84 hex) and NEL (85 hex)
	charset[i++] = 0x87;
	c = 0x89;			// Skip HTS (88 hex)
	while (c < 0x8d)		// Proceed till RI (8D hex)
		charset[i++] = c++;
	c = 0x91;			// Skip RI, SS2, SS3, DCS
	while (c < 0x96)		// Proceed till SPA (96 hex)
		charset[i++] = c++;
	charset[i++] = 0x99;		// Skip SPA, EPA, SOS
	c = 0xa0;			// Skip DECID, CSI, ST, OSC, PM, APC
	while (c <= 0xff)		// Proceed with the rest of 8-bit codes
		charset[i++] = c++;

/* Zero-terminate it, and cache the first character */
	charset[i] = 0;
	c0 = charset[0];

	last = minlength - 1;
	i = 0;
	while (i <= last) {
		id[i] = 0;
		word[i++] = c0;
	}
	lastid = -1;
	word[i] = 0;
}

void generate()
{
	int i;

/* Handle the typical case specially */
	if (word[last] = charset[++lastid]) return;

	lastid = 0;
	word[i = last] = c0;
	while (i--) {			// Have a preceding position?
		if (word[i] = charset[++id[i]]) return;
		id[i] = 0;
		word[i] = c0;
	}

	if (++last < maxlength) {	// Next length?
		id[last] = lastid = 0;
		word[last] = c0;
		word[last + 1] = 0;
	} else				// We're done
		word = 0;
}

void restore()
{
	int i, c;

/* Calculate the current length and infer the character indices */
	last = 0;
	while (c = word[last]) {
		i = 0; while (charset[i] != c && charset[i]) i++;
		if (!charset[i]) i = 0;	// Not found
		id[last++] = i;
	}
	lastid = id[--last];
}

# Generic implementation of exhaustive search for a partially-known password.
# This is pre-configured for length 8, lowercase and uppercase letters in the
# first 4 positions (52 different characters), and digits in the remaining 4
# positions - however, the corresponding part of init() may be modified to use
# arbitrary character sets or even fixed characters for each position.
[List.External:KnownForce]
int last;		// Last character position, zero-based
int lastofs;		// Last character position offset into charset[]
int lastid;		// Current character index in the last position
int id[0x7f];		// Current character indices for other positions
int charset[0x7f00];	// Character sets, 0x100 elements for each position

void init()
{
	int length, maxlength;
	int pos, ofs, i, c;

	if (req_minlen)
		length = req_minlen;
	else
		length = 8;	// Password length to try (NOTE: other [eg. shorter]
				// lengths will not be tried!)
	if (req_maxlen)
		maxlength = req_maxlen;
	else
		maxlength = cipher_limit;	// the format's limit

/* This defines the character sets for different character positions */
	if (length > maxlength)
		length = maxlength;
	pos = 0;
	while (pos < 4) {
		ofs = pos++ << 8;
		i = 0;
		c = 'a';
		while (c <= 'z')
			charset[ofs + i++] = c++;
		c = 'A';
		while (c <= 'Z')
			charset[ofs + i++] = c++;
		charset[ofs + i] = 0;
	}
	while (pos < length) {
		ofs = pos++ << 8;
		i = 0;
		c = '0';
		while (c <= '9')
			charset[ofs + i++] = c++;
		charset[ofs + i] = 0;
	}

	last = length - 1;
	pos = -1;
	while (++pos <= last)
		word[pos] = charset[id[pos] = pos << 8];
	lastid = (lastofs = last << 8) - 1;
	word[pos] = 0;
}

void generate()
{
	int pos;

/* Handle the typical case specially */
	if (word[last] = charset[++lastid]) return;

	word[pos = last] = charset[lastid = lastofs];
	while (pos--) {			// Have a preceding position?
		if (word[pos] = charset[++id[pos]]) return;
		word[pos] = charset[id[pos] = pos << 8];
	}

	word = 0;			// We're done
}

void restore()
{
	int i, c;

/* Calculate the current length and infer the character indices */
	last = 0;
	while (c = word[last]) {
		i = lastofs = last << 8;
		while (charset[i] != c && charset[i]) i++;
		if (!charset[i]) i = lastofs; // Not found
		id[last++] = i;
	}
	lastid = id[--last];
}

# A variation of KnownForce configured to try likely date and time strings.
[List.External:DateTime]
int last;		// Last character position, zero-based
int lastofs;		// Last character position offset into charset[]
int lastid;		// Current character index in the last position
int id[0x7f];		// Current character indices for other positions
int charset[0x7f00];	// Character sets, 0x100 elements for each position

void init()
{
	int length;
	int pos, ofs, i, c;

	length = 8;	// Must be one of: 4, 5, 7, 8

/* This defines the character sets for different character positions */
	pos = 0;
	while (pos < length - 6) {
		ofs = pos++ << 8;
		i = 0;
		c = '0';
		while (c <= '9')
			charset[ofs + i++] = c++;
		charset[ofs + i] = 0;
	}
	if (pos) {
		ofs = pos++ << 8;
		charset[ofs] = '/';
		charset[ofs + 1] = '.';
		charset[ofs + 2] = ':';
		charset[ofs + 3] = 0;
	}
	while (pos < length - 3) {
		ofs = pos++ << 8;
		i = 0;
		c = '0';
		while (c <= '9')
			charset[ofs + i++] = c++;
		charset[ofs + i] = 0;
	}
	ofs = pos++ << 8;
	charset[ofs] = '/';
	charset[ofs + 1] = '.';
	charset[ofs + 2] = ':';
	charset[ofs + 3] = 0;
	while (pos < length) {
		ofs = pos++ << 8;
		i = 0;
		c = '0';
		while (c <= '9')
			charset[ofs + i++] = c++;
		charset[ofs + i] = 0;
	}

	last = length - 1;
	pos = -1;
	while (++pos <= last)
		word[pos] = charset[id[pos] = pos << 8];
	lastid = (lastofs = last << 8) - 1;
	word[pos] = 0;
}

void generate()
{
	int pos;

/* Handle the typical case specially */
	if (word[last] = charset[++lastid]) return;

	word[pos = last] = charset[lastid = lastofs];
	while (pos--) {			// Have a preceding position?
		if (word[pos] = charset[++id[pos]]) return;
		word[pos] = charset[id[pos] = pos << 8];
	}

	word = 0;			// We're done
}

void restore()
{
	int i, c;

/* Calculate the current length and infer the character indices */
	last = 0;
	while (c = word[last]) {
		i = lastofs = last << 8;
		while (charset[i] != c && charset[i]) i++;
		if (!charset[i]) i = lastofs; // Not found
		id[last++] = i;
	}
	lastid = id[--last];
}

# Try strings of repeated characters.
#
# This is the code which is common for all [List.External:Repeats*]
# sections which include this External_base section.
# The generate() function will limit the maximum length of generated
# candidates to either the format's limit (maximum password length)
# or to the limit specified with --stdout=LENGTH (Default: 125),
# thus avoiding duplicate candidates for formats with limited maximum
# passwortd length.
# The comparison of the current length and the limit is only done
# after switching to a new length.
# So, if the minimum length specified already exceeds this limit,
# then all the candidates for the minimum length will be generated
# nevertheless.
[List.External_base:Repeats]
int minlength, maxlength, minc, maxc, length, c;

void generate()
{
	int i;

	i = 0;
	while (i < length)
		word[i++] = c;
	word[i] = 0;

	if (c++ < maxc)
		return;

	c = minc;

	if (++length > maxlength)
		c = 0; // Will NUL out the next "word" and thus terminate
}

# Try strings of repeated characters (range: space - 0xff).
[List.External:Repeats]
.include [List.External_base:Repeats]
void init()
{
	if (req_minlen)
		minlength = req_minlen;
	else
		minlength = 1;
	if (req_maxlen)
		maxlength = req_maxlen;
	else
		maxlength = cipher_limit;	// the format's limit
	minc = 0x20;
	maxc = 0xff;

	length = minlength; c = minc;
}

# Try strings of repeated digits (range: '0' - '9').
[List.External:Repeats_digits]
.include [List.External_base:Repeats]
void init()
{
	if (req_minlen)
		minlength = req_minlen;
	else
		minlength = 1;
	if (req_maxlen)
		maxlength = req_maxlen;
	else
		maxlength = cipher_limit;	// the format's limit
	minc = '0';
	maxc = '9';

	length = minlength; c = minc;
}

# Try strings of repeated lowercase letters (range: 'a' - 'z').
[List.External:Repeats_lowercase]
.include [List.External_base:Repeats]
void init()
{
	if (req_minlen)
		minlength = req_minlen;
	else
		minlength = 1;
	if (req_maxlen)
		maxlength = req_maxlen;
	else
		maxlength = cipher_limit;	// the format's limit
	minc = 'a';
	maxc = 'z';

	length = minlength; c = minc;
}

# Try strings of repeated printable ASCII characters
# (range: ' ' - '~').
[List.External:Repeats_printable_ASCII]
.include [List.External_base:Repeats]
void init()
{
	if (req_minlen)
		minlength = req_minlen;
	else
		minlength = 1;
	if (req_maxlen)
		maxlength = req_maxlen;
	else
		maxlength = cipher_limit;	// the format's limit
	minc = ' ';
	maxc = '~';

	length = minlength; c = minc;
}

# Try character sequences ("0123456", "acegikmoqs", "ZYXWVU", etc.).
#
# The generate() function will limit the maximum length of generated
# candidates to either the format's limit (maximum password length)
# or to the limit specified with --stdout=LENGTH (Default: 125),
# thus avoiding duplicate candidates for formats with limited maximum
# passwortd length.
# The comparison of the current length and the limit is only done
# after switching to a new length.
# So, if the minimum length specified already exceeds this limit,
# then all the candidates for the minimum length will be generated
# nevertheless.
# External modes reusing this External_base mode should only need to
# adjust the init() function.
# In the init() function, a minimum length which is > 1 should be
# specified.
# Otherwise, the generated candidates will not depend on the increment
# specified.
# For length = 1, the candidates will be the same as for external mode
# Repeats with length 1.
# Actually, Repeats is a special case of Sequence, using increment = 0.
# External modes reusing this External_base mode should also make sure
# that the number of different characters (specified as a range from "from"
# to "to") is not smaller than the minimum length ("minlength"),
# if the start increment "inc" is 1.
# For a start increment > 1, the number of different characters in the
# range "from" - "to" must be greater than or equal to
# (1 + ("minlength" - 1) * "inc").
# Otherwise you might get unexpected results.
# The range of characters to be used for the sequences needs to be
# specified by adjusting the "from" and "to" variables.
# To generate sequences which decrement characters ("987654"),
# "from" must be > "to".
# Otherwise, the generated sequences will increment characters ("abcdef").
#
# Variables to be used and the generate() function are common
# for all sections which include this External_base section.
[List.External_base:Sequence]
/*
 * See the [List.External:Sequence_0-9] section to learn more about
 * the meaning of these variables which can be adjusted to define
 * new external modes based on an existing one:
 */
int minlength, from, to, maxlength, inc, direction;

/*
 * The value of these variables shouldn't be changed when copying
 * an existing external mode:
 */
int length, first;

void generate()
{
	int i;

	i = 0;

	while (i < length) {
		word[i] = first + (i * inc * direction);
		++i;
	}
	word[i] = 0;

	// start the next sequence of the same length
	// with the next character
	first = first + direction;

	// But check that a sequence of the current length
	// is still possible (without leaving the range of
	// characters allowed
	if ((direction > 0 && first + (length - 1) * inc > to) ||
	    (direction < 0 && first - (length - 1) * inc < to)) {
		// No more sequence is possible. Reset start character
		first = from;
		// Now try the next length.
		// But just in case an individual External mode reusing
		// this External_base mode did specify a maxlength
		// which is larger than the one supported by the format
		// or by --stdout=LENGTH, make sure no more candidates
		// are generated.
		// Checking this just once per length per increment
		// doen't really hurt performance.
		if (maxlength > cipher_limit)
			maxlength = cipher_limit;

		// For a similar reason, the maximum length of a
		// sequence is limited by the number of different
		// characters and by the increment.
		// The larger the increment, the smaller
		// the maximum possible length for a given
		// character range.
		while (inc  * (maxlength - 1) > direction * (to - from))
			--maxlength;

		if (++length > maxlength) {
			// The maximum length for this increment has been reached.
			// Restart at minimum length with the next possible
			// increment
			++inc;
			// Unfortunately, we have to check again
			// if the maximum length needs to be reduced
			// for the new increment
			while (inc * (maxlength - 1) > direction * (to - from))
				--maxlength;

			length = minlength;
		}
		if (maxlength < minlength)
			// With the current increment, we can't even generate
			// sequences of the minimum required length.
			// So we need to stop here.
			// This will make sure that no more candidiates
			//  will be generated:
			first = 0;
	}
}

# Try sequences of digits (range: '0' - '9').
#
# Aditional comments can be found in the
# section [List.External_base:Sequence]
#
# This external mode is thoroughly commented,
# to make it easier to copy and adjust it as needed.
[List.External:Sequence_0-9]
.include [List.External_base:Sequence]
void init()
{
	// Adjust the following 4 variables if you want to define
	// a different external mode.

	// This is the start character for the generated sequence
	// if "from" is smaller than "to", the increment from
	// first to second character ... will be positive ("0123456789").
	// Otherwise, it will be negative ("987654321").
	from = '0';
	to = '9';

	// minimum length of the sequence
	// make sure it is not larger than the number of different characters
	// in the range between "from" and "to" specified above
	minlength = 2;

	// start increment for generating the sequence, usually 1
	// if it is larger than 1, you need even more characters
	// in the range between "from" and "to"
	// Don't specify a negative value here.
	// If you want to generate sequences like "zyxwvu" or "86420",
	// adjust "from" and "to" so that "from" is larger than "to".
	// (A start increment of 0 is also possible, in that case the first
	// sequences will be candidates which just repeat the same character.)
	inc = 1;

	// For copied external modes, no further changes should be required
	// in the statements following this comment

	length = minlength;
	first = from;

	if (from <= to) {
		maxlength = to - from + 1;
		direction = 1;
	} else {
		// We have to create sequences which decrement the previous character
		maxlength = from - to + 1;
		direction = -1;
	}
}

# Try sequence of lower case letters (range: 'a' - 'z').
# This external mode is not very well documented.
# Refer to [List.External:Sequence_0-9] for more detailed information.
[List.External:Sequence_a-z]
.include [List.External_base:Sequence]
void init()
{
	from = 'a';
	to = 'z';
	minlength = 2;
	inc = 1;

	length = minlength;
	first = from;

	if (from <= to) {
		maxlength = to - from + 1;
		direction = 1;
	} else {
		maxlength = from - to + 1;
		direction = -1;
	}
}

# Try sequence of lower case letters (range: 'a' - 'z'), but reversed
# ("zxywvu").
# This external mode is not very well documented.
# Refer to [List.External:Sequence_0-9] for more detailed information.
[List.External:Sequence_z-a]
.include [List.External_base:Sequence]
void init()
{
	from = 'z';
	to = 'a';
	minlength = 2;
	inc = 1;

	length = minlength;
	first = from;

	if (from <= to) {
		maxlength = to - from + 1;
		direction = 1;
	} else {
		maxlength = from - to + 1;
		direction = -1;
	}
}

# Try sequence of printable ASCII characters (range: ' ' - '~').
# This external mode is not very well documented.
# Refer to [List.External:Sequence_0-9] for more detailed information.
[List.External:Sequence_printable_ascii]
.include [List.External_base:Sequence]
void init()
{
	from = ' ';
	to = '~';
	minlength = 2;
	inc = 1;

	length = minlength;
	first = from;

	if (from <= to) {
		maxlength = to - from + 1;
		direction = 1;
	} else {
		maxlength = from - to + 1;
		direction = -1;
	}
}

# Try sequence of printable ASCII characters (range: ' ' - '~'),
# but decrementing characters ("fedcba") instead of incrementing.
# This external mode is not very well documented.
# Refer to [List.External:Sequence_0-9] for more detailed information.
[List.External:Sequence_reversed_ascii]
.include [List.External_base:Sequence]
void init()
{
	from = '~';
	to = ' ';
	minlength = 2;
	inc = 1;

	length = minlength;
	first = from;

	if (from <= to) {
		maxlength = to - from + 1;
		direction = 1;
	} else {
		maxlength = from - to + 1;
		direction = -1;
	}
}

# Try sequence of characters (range: space - 0xff).
# This external mode is not very well documented.
# Refer to [List.External:Sequence_0-9] for more detailed information.
[List.External:Sequence]
.include [List.External_base:Sequence]
void init()
{
	from = ' ';
	to = 0xff;
	minlength = 2;
	inc = 1;

	length = minlength;
	first = from;

	if (from <= to) {
		maxlength = to - from + 1;
		direction = 1;
	} else {
		maxlength = from - to + 1;
		direction = -1;
	}
}


# Generate candidate passwords from many small subsets of characters from a
# much larger full character set.  This will test for passwords containing too
# few different characters.  As currently implemented, this code will produce
# some duplicates, although their number is relatively small when the maximum
# number of different characters (the maxdiff setting) is significantly lower
# than the maximum length (the maxlength setting).  Nevertheless, you may want
# to pass the resulting candidate passwords through "unique" if you intend to
# test them against hashes that are salted and/or of a slow to compute type.
[List.External:Subsets]
int minlength;		// Minimum password length to try
int maxlength;		// Maximum password length to try
int startdiff;		// Initial number of characters in a subset to try
int maxdiff;		// Maximum number of characters in a subset to try
int last;		// Last character position, zero-based
int lastid;		// Character index in the last position
int id[0x7f];		// Current character indices for other positions
int subset[0x100], c0;	// Current subset
int subcount;		// Number of characters in the current subset
int subid[0x100];	// Indices into charset[] of characters in subset[]
int charset[0x100];	// Full character set
int charcount;		// Number of characters in the full charset

void init()
{
	int i, c;

	// Minimum password length to try, must be at least 1
	if (req_minlen)
		minlength = req_minlen;
	else
		minlength = 1;

	// Maximum password length to try, must be at least same as minlength
	// This external mode's default maximum length can be adjusted
	// using --max-length= on the command line
	if (req_maxlen)
		maxlength = req_maxlen;
	else
		maxlength = 8;

	// "cipher_limit" is the variable which contains the format's
	// maximum password length
	if (maxlength > cipher_limit)
		maxlength = cipher_limit;

	startdiff = 1;	// Initial number of different characters to try
	maxdiff = 3;	// Maximum number of different characters to try

/* This defines the character set */
	i = 0;
	c = 0x20;
	while (c <= 0x7e)
		charset[i++] = c++;

	if (maxdiff > (charcount = i))
		maxdiff = i;
	if (maxdiff > maxlength)
		maxdiff = maxlength;

/*
 * Initialize the variables such that generate() gets to its "next subset"
 * code, which will initialize everything for real.
 */
	subcount = (i = startdiff) - 1;
	while (i--)
		subid[i] = charcount;
	subset[0] = c0 = 0;
	last = maxlength - 1;
	lastid = -1;
}

void generate()
{
	int i;

/* Handle the typical case specially */
	if (word[last] = subset[++lastid]) return;

	lastid = 0;
	word[i = last] = c0;
	while (i--) {			// Have a preceding position?
		if (word[i] = subset[++id[i]]) return;
		id[i] = 0;
		word[i] = c0;
	}

	if (++last < maxlength) {	// Next length?
		id[last] = lastid = 0;
		word[last] = c0;
		word[last + 1] = 0;
		return;
	}

/* Next subset */
	if (subcount) {
		int j;
		i = subcount - 1;
		j = charcount;
		while (++subid[i] >= j) {
			if (i--) {
				j--;
				continue;
			}
			subid[i = 0] = 0;
			subset[++subcount] = 0;
			break;
		}
	} else {
		subid[i = 0] = 0;
		subset[++subcount] = 0;
	}
	subset[i] = charset[subid[i]];
	while (++i < subcount)
		subset[i] = charset[subid[i] = subid[i - 1] + 1];

	if (subcount > maxdiff) {
		word = 0;		// Done
		return;
	}

/*
 * We won't be able to fully use the subset if the length is smaller than the
 * character count.  We assume that we've tried all smaller subsets before, so
 * we don't bother with such short lengths.
 */
	if (minlength < subcount)
		last = subcount - 1;
	else
		last = minlength - 1;
	c0 = subset[0];
	i = 0;
	while (i <= last) {
		id[i] = 0;
		word[i++] = c0;
	}
	lastid = 0;
	word[i] = 0;
}

# Simple password policy matching: require at least one digit.
[List.External:AtLeast1-Simple]
void filter()
{
	int i, c;

	i = 0;
	while (c = word[i++])
		if (c >= '0' && c <= '9')
			return; // Found at least one suitable character, good

	word = 0; // No suitable characters found, skip this "word"
}

# The same password policy implemented in a more efficient and more generic
# fashion (easy to expand to include other "sufficient" characters as well).
[List.External:AtLeast1-Generic]
int mask[0x100];

void init()
{
	int c;

	mask[0] = 0; // Terminate the loop in filter() on NUL
	c = 1;
	while (c < 0x100)
		mask[c++] = 1; // Continue looping in filter() on most chars

	c = '0';
	while (c <= '9')
		mask[c++] = 0; // Terminate the loop in filter() on digits
}

void filter()
{
	int i;

	i = -1;
	while (mask[word[++i]])
		continue;
	if (word[i])
		return; // Found at least one suitable character, good

	word = 0; // No suitable characters found, skip this "word"
}

# An efficient and fairly generic password policy matcher.  The policy to match
# is specified in the check at the end of filter() and in mask[].  For example,
# lowercase and uppercase letters may be treated the same by initializing the
# corresponding mask[] elements to the same value, then adjusting the value to
# check "seen" for accordingly.
[List.External:Policy]
int mask[0x100];

void init()
{
	int c;

	mask[0] = 0x100;
	c = 1;
	while (c < 0x100)
		mask[c++] = 0x200;

	c = 'a';
	while (c <= 'z')
		mask[c++] = 1;
	c = 'A';
	while (c <= 'Z')
		mask[c++] = 2;
	c = '0';
	while (c <= '9')
		mask[c++] = 4;
}

void filter()
{
	int i, seen;

/*
 * This loop ends when we see NUL (sets 0x100) or a disallowed character
 * (sets 0x200).
 */
	i = -1; seen = 0;
	while ((seen |= mask[word[++i]]) < 0x100)
		continue;

/*
 * We should have seen at least one character of each type (which "add up"
 * to 7) and then a NUL (adds 0x100), but not any other characters (would
 * add 0x200).  The length must be 8.
 */
	if (seen != 0x107 || i != 8)
		word = 0; // Does not conform to policy
}

# Append the Luhn algorithm digit to arbitrary all-digit strings.  Optimized
# for speed, not for size nor simplicity.  The primary optimization trick is to
# compute the length and four sums in parallel (in two SIMD'ish variables).
# Then whether the length is even or odd determines which two of the four sums
# are actually used.  Checks for non-digits and for NUL are packed into the
# SIMD'ish bitmasks as well.
[List.External:AppendLuhn]
int map1[0x100], map2[0x1fff];

void init()
{
	int i;

	map1[0] = ~0x7fffffff;
	i = 1;
	while (i < 0x100)
		map1[i++] = ~0x7effffff;
	i = -1;
	while (++i < 10)
		map1['0' + i] = i + ((i * 2 % 10 + i / 5) << 12);
	i = -1;
	while (++i < 0x1fff) {
		if (i % 10)
			map2[i] = '9' + 1 - i % 10;
		else
			map2[i] = '0';
	}
}

void filter()
{
	int i, o, e;

	i = o = e = 0;
	while ((o += map1[word[i++]]) >= 0) {
		if ((e += map1[word[i++]]) >= 0)
			continue;
		if (e & 0x01000000)
			return; // Not all-digit, leave unmodified
		word[i--] = 0;
		word[i] = map2[(e & 0xfff) + (o >> 12)];
		return;
	}
	if (o & 0x01000000)
		return; // Not all-digit, leave unmodified
	word[i--] = 0;
	word[i] = map2[(o & 0xfff) + (e >> 12)];
}

# Trivial Rotate function, which rotates letters in a word
# by a given number of places (like 13 in case of ROT13).
# Words which don't contain any letters (and thus wouldn't be changed
# by this filter) are skipped, because these unchanged words probably
# should have been tried before trying a mangled version.
[List.External_base:Filter_Rotate]

int rot; // The number of places to rotate each letter in a word

void filter()
{
	int i, j, c;

	i = 0;
	j = 0; // j counts the number of changed characters

	while (c = word[i]) {
		if (c >= 'a' && c <= 'z') {
			c = c - 26 + rot;
			if (c < 'a') c += 26;
			word[i] = c;
			j++;
		} else if (c >= 'A' && c <= 'Z' ) {
			c = c - 26 + rot;
			if (c < 'A') c += 26;
			word[i] = c;
			j++;
		}
		i++;
	}
	if (j == 0)
		// Noting changed. Reject this word.
		word = 0;
}

# ROT13 Example
[List.External:Filter_ROT13]
.include [List.External_base:Filter_Rotate]
void init()
{
	// Just in case someone wants to "rotate" by other values,
	// adjust the value of the rot variable
	// (may be in a copied external mode):
	// 	13: "abcABCxyzXYZ" -> "nopNOPklmKLM"
	// 	 1: "abcABCxyzXYZ" -> "bcdBCDyzaYZA"
	// 	25: "abcABCxyzXYZ" -> "zabZABwxyWXY"
	// 	-1: "abcABCxyzXYZ" -> "zabZABwxyWXY"
	// and so on
	// Allowed range: -25 <= rot <= -1, or 1 <= rot <= 25
	rot = 13;

	// Don't change the following statement.
	// It is supposed to "sanitize" the value to be in the
	// range
	rot = (rot + 26) % 26;
}

# Trivial parallel processing example (obsoleted by the "--node" option)
[List.External:Parallel]
/*
 * This word filter makes John process some of the words only, for running
 * multiple instances on different CPUs.  It can be used with any cracking
 * mode except for "single crack".  Note: this is not a good solution, but
 * is just an example of what can be done with word filters.
 */

int node, total;			// This node's number, and node count
int number;				// Current word number

void init()
{
	node = 1; total = 2;		// Node 1 of 2, change as appropriate
	number = node - 1;		// Speedup the filter a bit
}

void filter()
{
	if (number++ % total)		// Word for a different node?
		word = 0;		// Yes, skip it
}

# Interrupt the cracking session after "max" words tried
[List.External:AutoAbort]
int max;				// Maximum number of words to try
int number;				// Current word number

void init()
{
	max = 1000;
	number = 0;
}

void filter()
{
	if (++number > max)
		abort = 1;		// Interrupt the cracking session
}

# Print the status line after every "interval" words tried
[List.External:AutoStatus]
int interval;				// How often to print the status
int number;				// Current word number

void init()
{
	interval = 1000;
	number = 0;
}

void filter()
{
	if (number++ % interval)
		return;
	status = 1;			// Print the status line
}

# End of john.conf file.
# Keep this comment, and blank line above it, to make sure a john.local.conf
# that does not end with \n is properly loaded.