天天看點

Tools - John The Ripper

John Files

lab:~/ $ ls -l /usr/share/john/
total 
-rw-r--r--  root root  Jul     all.chr
-rw-r--r--  root root  Jul     alnum.chr
-rw-r--r--  root root  Jul     alpha.chr
-rwxr-xr-x  root root    Jul     benchmark-unify
-rwxr-xr-x  root root     Jul     cracf2john.py
-rw-r--r--  root root    Jul     dictionary.rfc2865
-rw-r--r--  root root   Jul     digits.chr
-rw-r--r--  root root   Jul     dumb16.conf
-rw-r--r--  root root   Jul     dumb32.conf
-rw-r--r--  root root   Jul     dynamic.conf
-rwxr-xr-x  root root    Jul     genincstats.rb
-rw-r--r--  root root   Jul   : john.conf
-rw-r--r--  root root       Jul   : john.local.conf
-rw-r--r--  root root  Jul     lanman.chr
-rwxr-xr-x  root root     Jul     ldif2john.pl
-rwxr-xr-x  root root     Jul     lion2john-alt.pl
-rwxr-xr-x  root root     Jul     lion2john.pl
-rwxr-xr-x  root root    Jul     netntlm.pl
-rwxr-xr-x  root root    Jul     netscreen.py
-rwxr-xr-x  root root    Jul     odf2john.py
-rwxr-xr-x  root root   Jul     pass_gen.pl
-rw-r--r--  root root   Jul     password.lst
-rwxr-xr-x  root root    Jul     radius2john.pl
-rw-r--r--  root root   Jul   : rules.txt
-rwxr-xr-x  root root    Jul     sap2john.pl
-rwxr-xr-x  root root     Jul     sha-dump.pl
-rwxr-xr-x  root root     Jul     sha-test.pl
-rwxr-xr-x  root root     Jul     sipdump2john.py
-rw-r--r--  root root  Jul     stats
           

Command Lines

lab:~/ $ john
John the Ripper password cracker, ver: 1.7.9-jumbo-7_omp [linux-x86-64]
Copyright (c) 1996-2012 by Solar Designer and others
Homepage: http://www.openwall.com/john/

Usage: john [OPTIONS] [PASSWORD-FILES]
--config=FILE             use FILE instead of john.conf or john.ini
--single[=SECTION]        "single crack" mode
--wordlist[=FILE] --stdin wordlist mode, read words from FILE or stdin
                  --pipe  like --stdin, but bulk reads, and allows rules
--loopback[=FILE]         like --wordlist, but fetch words from a .pot file
--dupe-suppression        suppress all dupes in wordlist (and force preload)
--encoding=NAME           input data is non-ascii (eg. UTF-, ISO--).
                          For a full list of NAME use --list=encodings
--rules[=SECTION]         enable word mangling rules for wordlist modes
--incremental[=MODE]      "incremental" mode [using section MODE]
--markov[=OPTIONS]        "Markov" mode (see doc/MARKOV)
--external=MODE           external mode or word filter
--stdout[=LENGTH]         just output candidate passwords [cut at LENGTH]
--restore[=NAME]          restore an interrupted session [called NAME]
--session=NAME            give a new session the NAME
--status[=NAME]           print status of a session [called NAME]
--make-charset=FILE       make a charset file. It will be overwritten
--show[=LEFT]             show cracked passwords [if =LEFT, then uncracked]
--test[=TIME]             run tests and benchmarks for TIME seconds each
--users=[-]LOGIN|UID[,..] [do not] load this (these) user(s) only
--groups=[-]GID[,..]      load users [not] of this (these) group(s) only
--shells=[-]SHELL[,..]    load users with[out] this (these) shell(s) only
--salts=[-]COUNT[:MAX]    load salts with[out] COUNT [to MAX] hashes
--pot=NAME                pot file to use
--format=NAME             force hash type NAME: afs bf bfegg bsdi crc32 crypt
                          des django dmd5 dominosec dragonfly3-32 dragonfly3-64
                          dragonfly4-32 dragonfly4-64 drupal7 dummy dynamic_n
                          epi episerver gost hdaa hmac-md5 hmac-sha1
                          hmac-sha224 hmac-sha256 hmac-sha384 hmac-sha512
                          hmailserver ipb2 keepass keychain krb4 krb5 lm lotus5
                          md4-gen md5 md5ns mediawiki mscash mscash2 mschapv2
                          mskrb5 mssql mssql05 mysql mysql-sha1 nethalflm netlm
                          netlmv2 netntlm netntlmv2 nsldap nt nt2 odf office
                          oracle oracle11 osc pdf phpass phps pix-md5 pkzip po
                          pwsafe racf rar raw-md4 raw-md5 raw-md5u raw-sha
                          raw-sha1 raw-sha1-linkedin raw-sha1-ng raw-sha224
                          raw-sha256 raw-sha384 raw-sha512 salted-sha1 sapb
                          sapg sha1-gen sha256crypt sha512crypt sip ssh
                          sybasease trip vnc wbb3 wpapsk xsha xsha512 zip
--list=WHAT               list capabilities, see --list=help or doc/OPTIONS
--save-memory=LEVEL       enable memory saving, at LEVEL ..
--mem-file-size=SIZE      size threshold for wordlist preload (default  MB)
--nolog                   disables creation and writing to john.log file
--crack-status            emit a status line whenever a password is cracked
--max-run-time=N          gracefully exit after this many seconds
--regen-lost-salts=N      regenerate lost salts (see doc/OPTIONS)
--plugin=NAME[,..]        load this (these) dynamic plugin(s)

           

john.conf

#
# 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
#

# ------------------------------------------------------
# John the Ripper usage examples:
# http://www.openwall.com/john/doc/EXAMPLES.shtml
# ------------------------------------------------------
#
#  1. Unix Password:
#         unshadow /etc/passwd /etc/shadow > ~/hash.txt
#         john --format=crypt ~/hash.txt
#
#         john --show ~/hash.txt 
#         john --show --shells=-/etc/expired ~/hash.txt      
#         john --show --shells=-expired,newuser ~/hash.txt
#         john --show --users=0 ~/hash.txt
#         john --show --users=0 *passwd* *.pwd
#         john --show --users=root ~/hash.txt
#
#         john --wordlist=password.lst --rules ~/hash.txt
#
#         john --wordlist=all.lst --rules ~/hash.txt
#         john --session=allrules --wordlist=all.lst --rules ~/hash.txt 
#
#         john --status
#         john --status=allrules
#
#         john --restore
#         john --restore=allrules
#
#         john --incremental ~/hash.txt
#
#
# 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 = 
# 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 = 

# 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).
# This is added to the "+ Cracked" line in the log as well (and that figure
# will be exact while the screen output will be a multiple of batch size).
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 and --encoding is not used either, the default
# is ISO-8859-1 for Unicode conversions and 7-bit ASCII encoding is assumed
# for rules - eg. uppercasing of letters other than a-z will not work at all!
DefaultEncoding = UTF-

# 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 hardly make any difference but in some cases, ISO-8859-1 is faster.
DefaultInternalEncoding = ISO--

# 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 = 

# 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, so they will re-sync. Note that this
# may be delayed by buffers and the "Save" timer setting near top of this file.
ReloadAtCrack = Y

# If set to Y, a session using --fork or MPI will signal to other nodes when
# it has cracked all hashes (there's nothing more to do!). This is ignored
# when ReloadAtCrack = Y because it's redundant.
ReloadAtDone = Y

# If set to Y, resync pot file when saving session. This does not involve any
# signalling, we just detect that someone else wrote to the pot file.
# This will sync with concurrent sessions even when not using --fork or MPI
# but it may be delayed by the "Save" timer setting near top of this file.
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

# if set to true, then uid will be appended to user name on crackes
# With:     password123      (Administrator:500)
# Without   password123      (Administrator)
# see https://github.com/magnumripper/JohnTheRipper/issues/517 for
# discussion of the usage of this variable.
ShowUIDinCracks = N

[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

# the set of dynamics was not disabled due to not working, but due to simply
# being academic formats, and test cases, and not ITW formats
dynamic_51 = Y
dynamic_52 = Y
dynamic_53 = Y
dynamic_54 = Y
dynamic_55 = Y
dynamic_56 = Y
dynamic_57 = Y
dynamic_58 = Y
# dyna-61 used by formspring and should not be disabled.
dynamic_61 = N
dynamic_62 = Y
dynamic_63 = Y
dynamic_64 = Y
dynamic_65 = Y
dynamic_66 = Y
dynamic_67 = Y
dynamic_68 = Y
dynamic_71 = Y
dynamic_72 = Y
dynamic_73 = Y
dynamic_74 = Y
dynamic_75 = Y
dynamic_76 = Y
dynamic_77 = Y
dynamic_78 = Y
dynamic_81 = Y
dynamic_82 = Y
dynamic_83 = Y
dynamic_84 = Y
dynamic_85 = Y
dynamic_86 = Y
dynamic_87 = Y
dynamic_88 = Y
dynamic_91 = Y
dynamic_92 = Y
dynamic_93 = Y
dynamic_94 = Y
dynamic_95 = Y
dynamic_96 = Y
dynamic_97 = Y
dynamic_98 = Y
dynamic_101 = Y
dynamic_102 = Y
dynamic_103 = Y
dynamic_104 = Y
dynamic_105 = Y
dynamic_106 = Y
dynamic_107 = Y
dynamic_108 = Y
dynamic_111 = Y
dynamic_112 = Y
dynamic_113 = Y
dynamic_114 = Y
dynamic_115 = Y
dynamic_116 = Y
dynamic_117 = Y
dynamic_118 = Y
dynamic_121 = Y
dynamic_122 = Y
dynamic_123 = Y
dynamic_124 = Y
dynamic_125 = Y
dynamic_126 = Y
dynamic_127 = Y
dynamic_128 = Y
dynamic_131 = Y
dynamic_132 = Y
dynamic_133 = Y
dynamic_134 = Y
dynamic_135 = Y
dynamic_136 = Y
dynamic_137 = Y
dynamic_138 = Y
dynamic_141 = Y
dynamic_142 = Y
dynamic_143 = Y
dynamic_144 = Y
dynamic_145 = Y
dynamic_146 = Y
dynamic_147 = Y
dynamic_148 = Y
dynamic_151 = Y
dynamic_152 = Y
dynamic_153 = Y
dynamic_154 = Y
dynamic_155 = Y
dynamic_156 = Y
dynamic_157 = Y
dynamic_158 = Y
dynamic_161 = Y
dynamic_162 = Y
dynamic_163 = Y
dynamic_164 = Y
dynamic_165 = Y
dynamic_166 = Y
dynamic_167 = Y
dynamic_168 = Y
dynamic_171 = Y
dynamic_172 = Y
dynamic_173 = Y
dynamic_174 = Y
dynamic_175 = Y
dynamic_176 = Y
dynamic_177 = Y
dynamic_178 = Y
dynamic_181 = Y
dynamic_182 = Y
dynamic_183 = Y
dynamic_184 = Y
dynamic_185 = Y
dynamic_186 = Y
dynamic_187 = Y
dynamic_188 = Y
dynamic_191 = Y
dynamic_192 = Y
dynamic_193 = Y
dynamic_194 = Y
dynamic_195 = Y
dynamic_196 = Y
dynamic_197 = Y
dynamic_198 = Y
dynamic_201 = Y
dynamic_202 = Y
dynamic_203 = Y
dynamic_204 = Y
dynamic_205 = Y
dynamic_206 = Y
dynamic_207 = Y
dynamic_208 = Y
dynamic_211 = Y
dynamic_212 = Y
dynamic_213 = Y
dynamic_214 = Y
dynamic_215 = Y
dynamic_216 = Y
dynamic_217 = Y
dynamic_218 = Y
dynamic_221 = Y
dynamic_222 = Y
dynamic_223 = Y
dynamic_224 = Y
dynamic_225 = Y
dynamic_226 = Y
dynamic_227 = Y
dynamic_228 = Y
dynamic_231 = Y
dynamic_232 = Y
dynamic_233 = Y
dynamic_234 = Y
dynamic_235 = Y
dynamic_236 = Y
dynamic_237 = Y
dynamic_238 = Y
dynamic_241 = Y
dynamic_242 = Y
dynamic_243 = Y
dynamic_244 = Y
dynamic_245 = Y
dynamic_246 = Y
dynamic_247 = Y
dynamic_248 = Y
dynamic_251 = Y
dynamic_252 = Y
dynamic_253 = Y
dynamic_254 = Y
dynamic_255 = Y
dynamic_256 = Y
dynamic_257 = Y
dynamic_258 = Y
dynamic_261 = Y
dynamic_262 = Y
dynamic_263 = Y
dynamic_264 = Y
dynamic_265 = Y
dynamic_266 = Y
dynamic_267 = Y
dynamic_268 = Y
dynamic_271 = Y
dynamic_272 = Y
dynamic_273 = Y
dynamic_274 = Y
dynamic_275 = Y
dynamic_276 = Y
dynamic_277 = Y
dynamic_278 = Y
dynamic_281 = Y
dynamic_282 = Y
dynamic_283 = Y
dynamic_284 = Y
dynamic_285 = Y
dynamic_286 = Y
dynamic_287 = Y
dynamic_288 = Y
dynamic_291 = Y
dynamic_292 = Y
dynamic_293 = Y
dynamic_294 = Y
dynamic_295 = Y
dynamic_296 = Y
dynamic_297 = Y
dynamic_298 = Y
dynamic_301 = Y
dynamic_302 = Y
dynamic_303 = Y
dynamic_304 = Y
dynamic_305 = Y
dynamic_306 = Y
dynamic_307 = Y
dynamic_308 = Y
dynamic_1033 = Y

# 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 = 


[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


[PRINCE]
# Default wordlist file name. Will fall back to standard wordlist if not
# defined.
#Wordlist = $JOHN/password.lst


# 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 = 
MkvMaxLen = 
# 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 = 
; MkvMinLen = 

# 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]
 = [a-zA-Z0-/.]
 = [-a-fA-F]
 = \x09

[Mask]
# Default mask for -mask if none is given. This is same as Hashcat's default.
DefaultMask = ????????????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.
 = ?l?d?u
 = ?l?d
 = ?l?d*!$@_
 =
 =
 =
 =
 =
 =

# 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]
 = [-]

#
# ======== List Rules ========
# [List.Rules:None]
# [List.Rules:Drop]
# [List.Rules:Single]
# [List.Rules:Extra]
# [List.Rules:Wordlist]
# [List.Rules:NT]
# [List.Rules:Split]
# [List.Rules:OldOffice]
# [List.Rules:o1]
# [List.Rules:o2]
# [List.Rules:o3]
# [List.Rules:o]
# [List.Rules:i1]
# [List.Rules:i2]
# [List.Rules:i3]
# [List.Rules:i]
# [List.Rules:oi]
# [List.Rules:Loopback]
# [List.Rules:Single-Extra]
# [List.Rules:Jumbo]
# [List.Rules:All]
# =======  List Rules =======
# http://www.openwall.com/john/doc/EXTERNAL.shtml
#
#
# 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]
<'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
-<7 >7 ' l
-< -c > '6 /?u l
-<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
-< -c > '5 /?u l
-c u Q
-c )?a r l
-[:c] <* !?A \p1[lc] p
-c <* c Q d
-<7 -c >7 ' /?u
-< > '4 l
-c <+ (?l c r
-c <+ )?l l Tm
-<3 >3 '
-< -c > '4 /?u
-<3 -c >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
>[-] x1\
> \[
# >3 x22 ... >9 x28
>[-] x2\p[-]
# >4 x32 ... >9 x37
>[-] x3\p[-]
# >2 x12 /?u l ... >8 x18 /?u l
-c >[-] x1\ /?u l
-c > \[ /?u l
# >3 x22 /?u l ... >9 x28 /?u l
-c >[-] x2\p[-] /?u l
# >4 x32 /?u l ... >9 x37 /?u l
-c >[-] x3\p[-] /?u l
# Now to the suffix stuff...
<* l $[-!a-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 $[-!]
-c <* /?a u $[-!]
-[:c] <- (?\p1[za] \p1[lc] Az"'s"
-[:c] <- (?\p1[za] \p1[lc] Az"!!"
-[:c] (?\p1[za] \p1[lc] $! <- Az"!!"
# Removing vowels...
-[:c] /?v @?v > (?\p1[za] \p1[lc]
/?v @?v > <* 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\\p[$] (?\p1[za] \p1[:c]
-[:c] l /a /[elos] sa4 s\\p[$] (?\p1[za] \p1[:c]
-[:c] l /e /[los] se3 s\\p[$] (?\p1[za] \p1[:c]
-[:c] l /l /[os] sl1 s\\p[$] (?\p1[za] \p1[:c]
-[:c] l /o /s so0 ss$ (?\p1[za] \p1[:c]
-[:c] l /a /e /[los] sa4 se3 s\\p[$] (?\p1[za] \p1[:c]
-[:c] l /a /l /[os] sa4 sl1 s\\p[$] (?\p1[za] \p1[:c]
-[:c] l /a /o /s sa4 so0 ss$ (?\p1[za] \p1[:c]
-[:c] l /e /l /[os] se3 sl1 s\\p[$] (?\p1[za] \p1[:c]
-[:c] l /[el] /o /s s\\p[] so0 ss$ (?\p1[za] \p1[:c]
-[:c] l /a /e /l /[os] sa4 se3 sl1 s\\p[$] (?\p1[za] \p1[:c]
-[:c] l /a /[el] /o /s sa4 s\\p[] 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 ^[a-z2-]
-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"[][-]"
-c <- (?a c Az"[][-]"
<- l Az"[][-]"
-c <- (?a c Az"[][-]"
<* 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!@#$%^&*\-=_+.?|:'"] $\
<- 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 >[-] l i\[a-z]
!?A l o0[a-z]
!?A >[-] l o\[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]" <+
<[\-] 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 > !?X l Q
# Capitalize every pure alphanumeric word
-c (?a > !?X c Q
# Lowercase and pluralize pure alphabetic words
<* > !?A l p
# Lowercase pure alphabetic words and append '1'
<* > !?A l $
# Capitalize pure alphabetic words and append '1'
-c <* > !?A c $
# Duplicate reasonably short pure alphabetic words (fred -> fredfred)
< > !?A l d
# Lowercase and reverse pure alphabetic words
> !?A l M r Q
# Prefix pure alphabetic words with '1'
> !?A l ^
# Uppercase pure alphanumeric words
-c > !?X u Q M c Q u
# Lowercase pure alphabetic words and append a digit or simple punctuation
<* > !?A l $[!?]
# Words containing punctuation, which is then squeezed out, lowercase
/?p @?p > l
# Words with vowels removed, lowercase
/?v @?v > l
# Words containing whitespace, which is then squeezed out, lowercase
/?w @?w > l
# Capitalize and duplicate short pure alphabetic words (fred -> FredFred)
-c < > !?A c d
# Capitalize and reverse pure alphabetic words (fred -> derF)
-c <+ > !?A c r
# Reverse and capitalize pure alphabetic words (fred -> Derf)
-c > !?A l M r Q c
# Lowercase and reflect pure alphabetic words (fred -> fredderf)
< > !?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 '' or ''
>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[-A-Z][ -~]

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

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

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

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

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

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

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

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

# Default Loopback mode rules.
[List.Rules:Loopback]
.include [List.Rules:NT]
.include [List.Rules:Split]

# For Single Mode against fast hashes
[List.Rules:Single-Extra]
.include [List.Rules:Single]
.include [List.Rules:Extra]
.include [List.Rules:OldOffice]

# For Wordlist mode and very fast hashes
[List.Rules:Jumbo]
.include [List.Rules:Wordlist]
.include [List.Rules:Single]
.include [List.Rules:Extra]
.include [List.Rules:NT]
.include [List.Rules:OldOffice]

# KoreLogic rules
.include "$JOHN/korelogic.conf"

# Everything, including all KoreLogic rules. Only for very fast hashes
# and/or Single mode.
[List.Rules:All]
.include [List.Rules:Jumbo]
.include [List.Rules:KoreLogic]

# Incremental modes

# This is for one-off uses (make your own custom.chr)
[Incremental:Custom]
File = $JOHN/custom.chr
MinLen = 

# The theoretical CharCount is 211, we've got 196.
[Incremental:UTF8]
File = $JOHN/utf8.chr
MinLen = 
CharCount = 

# This is CP1252, a super-set of ISO-8859-1.
# The theoretical CharCount is 219, we've got 203.
[Incremental:Latin1]
File = $JOHN/latin1.chr
MinLen = 
CharCount = 

[Incremental:ASCII]
File = $JOHN/ascii.chr
MinLen = 
MaxLen = 
CharCount = 

[Incremental:LM_ASCII]
File = $JOHN/lm_ascii.chr
MinLen = 
MaxLen = 
CharCount = 

# This is CP858 (CP850 + Euro sign, superset of CP437).
# The theoretical CharCount is 209 minus lowercase, we've got 132.
[Incremental:LanMan]
File = $JOHN/lanman.chr
MinLen = 
MaxLen = 
CharCount = 

#
# This is alnum (upper & lower case) as well as space.
#
# [Incremental:Custom]
# [Incremental:UTF8]
# [Incremental:Latin1]
# [Incremental:ASCII]
# [Incremental:LM_ASCII]
# [Incremental:LanMan]
# [Incremental:Alnumspace]
# [Incremental:Alnum]
# [Incremental:Alpha]
# [Incremental:LowerNum]
# [Incremental:UpperNum]
# [Incremental:LowerSpace]
# [Incremental:Lower]
# [Incremental:Upper]
# [Incremental:Digits]
#
#
[Incremental:Alnumspace]
File = $JOHN/alnumspace.chr
MinLen = 
MaxLen = 
CharCount = 

[Incremental:Alnum]
File = $JOHN/alnum.chr
MinLen = 
MaxLen = 
CharCount = 

[Incremental:Alpha]
File = $JOHN/alpha.chr
MinLen = 
MaxLen = 
CharCount = 

[Incremental:LowerNum]
File = $JOHN/lowernum.chr
MinLen = 
MaxLen = 
CharCount = 

[Incremental:UpperNum]
File = $JOHN/uppernum.chr
MinLen = 
MaxLen = 
CharCount = 

[Incremental:LowerSpace]
File = $JOHN/lowerspace.chr
MinLen = 
MaxLen = 
CharCount = 

[Incremental:Lower]
File = $JOHN/lower.chr
MinLen = 
MaxLen = 
CharCount = 

[Incremental:Upper]
File = $JOHN/upper.chr
MinLen = 
MaxLen = 
CharCount = 

[Incremental:Digits]
File = $JOHN/digits.chr
MinLen = 
MaxLen = 
CharCount = 

# Some pre-defined word filters as used to generate the supplied .chr files
# The following functions are currently used by John:
#
#     init()         - called at startup, should initialize global variables    
#     filter()       - called for each word to be tried, can filter some words out
#     generate()     - called for generate words, when no other cracking modes used
#     restore()      - called when restoring an interrupted session.
#
# http://www.openwall.com/john/doc/EXTERNAL.shtml
#
#
#
# [List.External:Filter_ASCII]
# [List.External:Filter_LanMan]
# [List.External:Filter_LM_ASCII]
# [List.External:Filter_Alnumspace]
# [List.External:Filter_Alnum]
# [List.External:Filter_Alpha]
# [List.External:Filter_LowerNum]
# [List.External:Filter_UpperNum]
# [List.External:Filter_LowerSpace]
# [List.External:Filter_Lower]
# [List.External:Filter_Upper]
# [List.External:Filter_Digits]
# [List.External:Filter_No_Cap_or_Symbols]
# [List.External:Filter_UTF8]
# [List.External:Filter_non-UTF8]
# [List.External:LanMan]
# [List.External_base:Double]
# [List.External:Double]
# [List.External:Double_alnum]
# [List.External:Double_all]
# [List.External:Strip]
# [List.External:DokuWiki]
# [List.External:KDEPaste]
# [List.External:AwesomePasswordGenerator]
# [List.External:Keyboard]
# [List.External:DumbDumb]
# [List.External:DumbForce]
# [List.External:KnownForce]
# [List.External:DateTime]
# [List.External_base:Repeats]
# [List.External:Repeats]
# [List.External:Repeats_digits]
# [List.External:Repeats_lowercase]
# [List.External:Repeats_printable_ASCII]
# [List.External_base:Sequence]
# [List.External:Sequence_0-9]
# [List.External:Sequence_a-z]
# [List.External:Sequence_z-a]
# [List.External:Sequence_printable_ascii]
# [List.External:Sequence_reversed_ascii]
# [List.External:Sequence]
# [List.External:Subsets]
# [List.External:AtLeast1-Simple]
# [List.External:AtLeast1-Generic]
# [List.External:Policy]
# [List.External:AppendLuhn]
# [List.External_base:Filter_Rotate]
# [List.External:Filter_ROT13]
# [List.External:Parallel]
# [List.External:AutoAbort]
# [List.External:AutoStatus]
#
#
[List.External:Filter_ASCII]
void filter()
{
    int i, c;

    i = ;
    while (c = word[i++])
    if (c <  || c >  || i > ) {
        word = ; return;
    }
}

[List.External:Filter_LanMan]
void filter()
{
    int i, c;

    i = ;
    while (c = word[i]) {
        if (i >= ) {          // of up to 14 characters long
            word = ; return;
        }
        if (c >= 'a' && c <= 'z')   // Convert to uppercase
            word[i] &= ;
        i++;
    }

    word[] = ;                // Truncate at 7 characters
}

[List.External:Filter_LM_ASCII]
void filter()
{
    int i, c;

    i = ;
    while (c = word[i]) {
        if (c <  || c >  || // Require ASCII-only
            i >= ) {          // of up to 14 characters long
            word = ; return;
        }
        if (c >= 'a' && c <= 'z')   // Convert to uppercase
            word[i] &= ;
        i++;
    }

    word[] = ;                // Truncate at 7 characters
}

[List.External:Filter_Alnumspace]
void filter()
{
    int i, c;

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

[List.External:Filter_Alnum]
void filter()
{
    int i, c;

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

[List.External:Filter_Alpha]
void filter()
{
    int i, c;

    i = ;
    while (c = word[i++])
    if ((c &= ) < 'A' || c > 'Z' || i > ) {
        word = ; return;
    }
}

[List.External:Filter_LowerNum]
void filter()
{
    int i, c;

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

[List.External:Filter_UpperNum]
void filter()
{
    int i, c;

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

[List.External:Filter_LowerSpace]
void filter()
{
    int i, c;

    i = ;
    while (c = word[i++])
    if (((c < 'a' || c > 'z') && c != ' ') || i > ) {
        word = ; return;
    }
}

[List.External:Filter_Lower]
void filter()
{
    int i, c;

    i = ;
    while (c = word[i++])
    if (c < 'a' || c > 'z' || i > ) {
        word = ; return;
    }
}

[List.External:Filter_Upper]
void filter()
{
    int i, c;

    i = ;
    while (c = word[i++])
    if (c < 'A' || c > 'Z' || i > ) {
        word = ; return;
    }
}

[List.External:Filter_Digits]
void filter()
{
    int i, c;

    i = ;
    while (c = word[i++])
    if (c < '0' || c > '9' || i > ) {
        word = ; return;
    }
}

[List.External:Filter_No_Cap_or_Symbols]
void filter()
{
    int i, c;

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


# Reject words that are illegal UTF-8
# We obviously let pure ASCII through too
[List.External:Filter_UTF8]
void filter()
{
    int s, a, p;

    p = ;
    while (s = word[p++] & ) {
        if (s > ) {
            if (s <  || s > ) { // illegal single-byte
                word = ; return;
            }
            // two-byte c2..df
            a = word[p++] & ;
            if (a <  || a > ) {
                word = ; return;
            }
            if (s > ) { // three-byte e0..ef
                if (s ==  && a < ) {
                    word = ; return;
                }
                if (s ==  && a > ) {
                    word = ; return;
                }
                if (s ==  && a < ) {
                    word = ; return;
                }
                if (s ==  && a > ) {
                    word = ; return;
                }
                a = word[p++] & ;
                if (a <  || a > ) {
                    word = ; return;
                }
                if (s > ) { // four-byte f0..f7
                    a = word[p++] & ;
                    if (a <  || a > ) {
                        word = ; return;
                    }
                }
            }
        }
    }
}

# Reject words that are LEGAL UTF-8 (also rejects pure ASCII)
[List.External:Filter_non-UTF8]
void filter()
{
    int s, a, p;

    p = ;
    while (s = word[p++] & ) {
        if (s > ) {
            if (s <  || s > ) { // illegal single-byte
                return;
            }
            // two-byte c2..df
            a = word[p++] & ;
            if (a <  || a > ) {
                return;
            }
            if (s > ) { // three-byte e0..ef
                if (s ==  && a < ) {
                    return;
                }
                if (s ==  && a > ) {
                    return;
                }
                if (s ==  && a < ) {
                    return;
                }
                if (s ==  && a > ) {
                    return;
                }
                a = word[p++] & ;
                if (a <  || a > ) {
                    return;
                }
                if (s > ) { // four-byte f0..f7
                    a = word[p++] & ;
                    if (a <  || a > ) {
                        return;
                    }
                }
            }
        }
    }
    word = ;
}

# A simple cracker for LM hashes
[List.External:LanMan]
int length;             // Current length
int maxlength;

void init()
{
    if (req_minlen)
        length = req_minlen;
    else
        length = ;
    if (req_maxlen)
        maxlength = req_maxlen;
    else                    // the format's limit
        maxlength = cipher_limit;
    word[] = 'A' - ;      // Start with "A"
    word[length] = ;
}

void generate()
{
    int i;

    i = length - ;         // Start from the last character
    while (++word[i] > 'Z')     // Try to increase it
    if (i)              // Overflow here, any more positions?
        word[i--] = 'A';    // Yes, move to the left, and repeat
    else                // No

    if (length < maxlength) {
        word[i = ++length] = ; // Switch to the next length
        while (i--)
            word[i] = 'A';
        return;
    } else {
        word = ; return;   // We're done
    }
}

void restore()
{
    length = ;         // Calculate the length
    while (word[length]) length++;
}

# Simple and well-commented, yet useful external mode example
# NOTE, this has now been 'split' up into a base extern, 'base', and then
# multiple External:double functions.  It still has same code as original
# double, but now can be easily expanded.
[List.External_base:Double]
/*
 * This cracking mode tries all the possible duplicated lowercase alphabetic
 * "words" of up to 8 characters long.  Since word halves are the same, it
 * only has to try about 500,000 words.
 */

/* Global variables: current length and word */
/* make this 'long' enough for other externs that include this one */
/* (up to 125 bytes long) */

int length, current[], max;

/* this new 'type' variable, is used to tell double what character set to
 * use. It can use the original (alpha).  If type is 0 (i.e. unset), then
 * a-z (alpha) character set is used.  If type is '0' (a zero ascii byte)
 * then alnum charset is used, a-z0-9.  If type is a space char, then all
 * charset is used  [space - tilde]  or [ -~].  This required setting the
 * type var in the init() of alnum or all doubles (it can be left unset
 * in the alpha versions).  It also requires some if logic in generate.
 * other than that, it works the same, with almost no performance hit */
int type;

/* Generates a new word */
void generate()
{
    int i;

/* Export last generated word, duplicating it at the same time; here "word"
 * is a pre-defined external variable. */
    word[(i = length) << ] = ;
    while (i--) word[length + i] = word[i] = current[i];

/* Generate a new word */
    i = length - ;         // Start from the last character
    if (type == ) {
        /* alpha */
        while (++current[i] > 'z')  // Try to increase it
        if (i)              // Overflow here, any more positions?
            current[i--] = 'a'; // Yes, move to the left, and repeat
        else {              // No
            current = ;        // Request a length switch
            break;          // Break out of the loop
        }
    } else if (type == '0') {
        /* alnum */
        if (current[i] == 'z') current[i] = '0'-;
        while (++current[i] == '9') { // Try to increase it
            if (i)              // Overflow here, any more positions?
                current[i--] = 'a'; // Yes, move to the left, and repeat
            else {              // No
                current = ;        // Request a length switch
                break;          // Break out of the loop
            }
            if (current[i] == 'z') current[i] = '0'-;
        }
    } else if (type == ' ') {
        /* all */
        while (++current[i] > '~') { // Try to increase it
            if (i)              // Overflow here, any more positions?
                current[i--] = ' '; // Yes, move to the left, and repeat
            else {              // No
                current = ;        // Request a length switch
                break;          // Break out of the loop
            }
        }
    }
    /* else ????? wtf?? */

/* Switch to the next length, unless we were generating 8 character long
 * words already. */
    if (!current && length < max) {
        i = ++length;
        if (type ==  || type == '0')
            while (i--) current[i] = 'a';
        else if (type == ' ')
            while (i--) current[i] = ' ';
    }
}

/* Called when restoring an interrupted session */
void restore()
{
    int i;

/* Import the word back */
    i = ;
    while (current[i] = word[i]) i++;

/* ...and calculate the half-word length */
    length = i >> ;
}

[List.External:Double]
.include [List.External_base:Double]

/* Called at startup to initialize the global variables */
void init()
{
    int i;

    if (req_minlen)
        i = length = (req_minlen + ) / ;
    else
        i = length = ;     // Start with 4 character long words
    while (i--) current[i] = 'a';   // Set our half-word to "aa"
    if (req_maxlen)
        max = (req_maxlen + ) / ;
    else if (length > )
        max = length;
    else
        max = ;
}

[List.External:Double_alnum]
.include [List.External_base:Double]

/* Called at startup to initialize the global variables */
void init()
{
    int i;

    if (req_minlen)
        i = length = (req_minlen + ) / ;
    else
        i = length = ;     // Start with 4 character long words
    while (i--) current[i] = 'a';   // Set our half-word to "aa"
    if (req_maxlen)
        max = (req_maxlen + ) / ;
    else if (length > )
        max = length;
    else
        max = ;

    type = '0';
}

[List.External:Double_all]
.include [List.External_base:Double]
void init()
{
    int i;

    if (req_minlen)
        i = length = (req_minlen + ) / ;
    else
        i = length = ;     // Start with 4 character long words
    while (i--) current[i] = ' ';   // Set our half-word to "  "
    if (req_maxlen)
        max = (req_maxlen + ) / ;
    else if (length > )
        max = length;
    else
        max = ;

    type = ' ';
}


# Strip 0.5 ("Secure Tool for Recalling Important Passwords") cracker,
# based on analysis done by Thomas Roessler and Ian Goldberg.  This will
# crack passwords you may have generated with Strip; other uses of Strip
# are unaffected.
[List.External:Strip]
int minlength, maxlength, mintype, maxtype;
int crack_seed, length, type;
int count, charset[];

void init()
{
    int c;

/* Password lengths to try; Strip can generate passwords of 4 to 16
 * characters, but traditional crypt(3) hashes are limited to 8. */
    minlength = req_minlen;
    if (minlength < )
        minlength = ;
    if (req_maxlen)
        maxlength = req_maxlen;
    else                    // the format's limit
        maxlength = cipher_limit;
    if (maxlength >) maxlength = ;

/* Password types to try (Numeric, Alpha-Num, Alpha-Num w/ Meta). */
    mintype = ;    // 0
    maxtype = ;    // 2

    crack_seed = ;
    length = minlength - ;
    type = mintype;

    count = ;
    c = '0'; while (c <= '9') charset[count++] = c++;
}

void generate()
{
    int seed, random;
    int i, c;

    if (crack_seed > ) {
        crack_seed = ;

        if (++length > maxlength) {
            length = minlength;

            if (++type > maxtype) {
                word[] = ;
                return;
            }
        }

        count = ;
        if (type >= ) {
            c = 'a'; while (c <= 'f') charset[count++] = c++;
            c = 'h'; while (c <= 'z') charset[count++] = c++;
            c = 'A'; while (c <= 'Z') charset[count++] = c++;
        }
        if (type == ) {
            charset[count++] = '!';
            c = '#'; while (c <= '&') charset[count++] = c++;
            c = '('; while (c <= '/') charset[count++] = c++;
            c = '<'; while (c <= '>') charset[count++] = c++;
            charset[count++] = '?'; charset[count++] = '@';
            charset[count++] = '['; charset[count++] = ']';
            charset[count++] = '^'; charset[count++] = '_';
            c = '{'; while (c <= '~') charset[count++] = c++;
        }
    }

    seed = (crack_seed++ <<  >> ) *  + ;

    i = ;
    while (i < length) {
        random = ((seed = seed *  + ) >> ) & ;
        word[i++] = charset[random % count];
    }

    word[i] = ;
}

# A variation of KnownForce configured to try all the 385641000 possible
# auto-generated passwords of DokuWiki versions up to at least 2013-05-10.
[List.External:DokuWiki]
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[];       // Current character indices for other positions
int charset[];    // Character sets, 0x100 elements for each position

void init()
{
    int A[], C[], V[];
    int length;
    int pos, ofs, i, c;

    i = ; while (i < ) { A[i] = C[i] = ; V[i++] = ; }
    i = 'a' - 'a'; C[i] = ; V[i] = ;
    i = 'e' - 'a'; C[i] = ; V[i] = ;
    i = 'i' - 'a'; C[i] = ; V[i] = ;
    i = 'o' - 'a'; C[i] = ; V[i] = ;
    i = 'u' - 'a'; C[i] = ; V[i] = ;
    i = 'q' - 'a'; A[i] = C[i] = ;
    i = 'x' - 'a'; A[i] = C[i] = ;
    i = 'y' - 'a'; A[i] = C[i] = ;

    length = ;

/* This defines the character sets for different character positions */
    pos = ;
    while (pos < ) {
        ofs = pos++ << ;
        i = ;
        c = 'a' - ;
        while (++c <= 'z')
            if (C[c - 'a'])
                charset[ofs + i++] = c;
        charset[ofs + i] = ;
        ofs = pos++ << ;
        i = ;
        c = 'a' - ;
        while (++c <= 'z')
            if (V[c - 'a'])
                charset[ofs + i++] = c;
        charset[ofs + i] = ;
        ofs = pos++ << ;
        i = ;
        c = 'a' - ;
        while (++c <= 'z')
            if (A[c - 'a'])
                charset[ofs + i++] = c;
        charset[ofs + i] = ;
    }
    c = '1';
    while (pos < length) {
        ofs = pos++ << ;
        i = ;
        while (c <= '9')
            charset[ofs + i++] = c++;
        charset[ofs + i] = ;
        c = '0';
    }

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

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 << ];
    }

    word = ;           // We're done
}

void restore()
{
    int i, c;

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

/*
 * This takes advantage of CVE-2013-2120 to find seeds that KDE Paste applet
 * uses to generate passwords.
 *
 * This software is Copyright (c) Michael Samuel <[email protected]>,
 * and it is hereby released to the general public under the following terms:
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 */
[List.External:KDEPaste]
int charset[];
int charset_length, password_length, endTime, startTime, msec;

void init()
{
    password_length = ;    /* Change this to match config */
    endTime = session_start_time;
    startTime = ; /* Aug 1 2012  - Change this as necessary */

    msec = ;       /* msec is never 0 - it would crash the applet */

    charset_length = ;
    int c;

    /* Comment out classes that you don't need, but keep the order the same */
    /* Lowers */
    c = 'a'; while (c <= 'z') charset[charset_length++] = c++;

    /* Uppers */
    c = 'A'; while (c <= 'Z') charset[charset_length++] = c++;

    /* Numbers */
    c = '0'; while (c <= '9') charset[charset_length++] = c++;
    charset[charset_length++] = '0';    /* Yep, it's there twice */

    /* Symbols */
    c = '!'; while (c <= '/') charset[charset_length++] = c++;
    c = ':'; while (c <= '@') charset[charset_length++] = c++;
    c = '['; while (c <= '`') charset[charset_length++] = c++;
    c = '{'; while (c <= '~') charset[charset_length++] = c++;
}

void generate()
{
    int i, rand_seed, rand_result;

    /* Terminate once we've generated for all *
     * of the time range (Plus a bit more...) */
    if (endTime +  < startTime) {
        word = ;
        return;
    }

    /* Skip msecs that would generate dupes */
    while (endTime % msec != ) {
        if (++msec > ) {
            endTime--;
            msec = ;
        }
    }

    rand_seed = endTime / msec;

    i = ;
    while (i < password_length) {
        /* this works like rand_r() from eglibc */
        rand_seed = rand_seed *  + ;
        rand_result = (rand_seed >> ) & ;

        rand_seed = rand_seed *  + ;
        rand_result <<= ;
        rand_result ^= (rand_seed >> ) & ;

        rand_seed = rand_seed *  + ;
        rand_result <<= ;
        rand_result ^= (rand_seed >> ) & ;

        word[i++] = charset[rand_result % charset_length];
    }
    word[i] = ;

    if (++msec > ) {
        endTime--;
        msec = ;
    }
}

void restore()
{
    int i, rand_seed, rand_result;

    i = ;

    /* Very crude restore, just dry-run until we hit last word */
    while (i != password_length) {

        while (endTime % msec != ) {
            if (++msec > ) {
                endTime--;
                msec = ;
            }
        }

        rand_seed = endTime / msec;

        i = ;
        while (i < password_length) {
            /* this works like rand_r() from eglibc */
            rand_seed = rand_seed *  + ;
            rand_result = (rand_seed >> ) & ;

            rand_seed = rand_seed *  + ;
            rand_result <<= ;
            rand_result ^= (rand_seed >> ) & ;

            rand_seed = rand_seed *  + ;
            rand_result <<= ;
            rand_result ^= (rand_seed >> ) & ;

            if (charset[rand_result % charset_length] != word[i++])
                break;
        }

        if (++msec > ) {
            endTime--;
            msec = ;
        }
    }
}

/* Awesome Password Generator RNG replay
 * Written by Michael Samuel <[email protected]>
 * Public Domain.
 *
 * This takes advantage of a subtle bug, where a crypto RNG is used to
 * seed the C# System.Random() class, which takes a 32-bit input, but
 * converts negative numbers into non-negative numbers, resulting in
 * only 31 bits of security.
 *
 * This only implements "easy to type" being *unticked*, and numbers,
 * lowers, uppers and symbols being ticked, in random password mode.
 * Changing the password length is easy, anything else is left as an
 * exercise to the reader.
 *
 * Running Awesome Password Generator (1.3.2 or lower) in Mono is still
 * vulnerable, but uses a different RNG, so this mode isn't compatible.
 */

/* Awesome Password Generator 1.3.2 does a two-pass run, selecting which
 * charset each position will have, then picking the character.  This
 * leads to heavy bias, and is fixed in 1.4.0 (along with many other
 * fixes).  If you have been using Awesome Password Generator, you should
 * upgrade immediately and change your passwords.
 */
[List.External:AwesomePasswordGenerator]
int numbers[];
int lowers[];
int uppers[];
int symbols[];

/* Since we don't have a double datatype, I simply pre-calculated the
 * transition numbers calculating the scale formula:
 * (double)randNum * 4.656612873077393e-10 * {4/10/26/32}
 */
int boundaries_charclass[];
int boundaries_numbers[];
int boundaries_letters[];
int boundaries_symbols[];

/* This is the bug we're exploiting - the seed for the RNG is 32 bits
 * from the crypto rng.  The non-crypto RNG converts negative numbers
 * into non-negative numbers, so there's only 2^31 possible seeds.
 */
int seed;

int password_length;

void init()
{
    password_length = ; /* Change this to match config */

    int c, i;

    c = '0'; i = ; while (c <= '9') numbers[i++] = c++;
    c = 'a'; i = ; while (c <= 'z') lowers[i++] = c++;
    c = 'A'; i = ; while (c <= 'Z') uppers[i++] = c++;

    /* Symbols */
    i = ;
    symbols[i++] = '!'; symbols[i++] = '@'; symbols[i++] = '#'; symbols[i++] = '$';
    symbols[i++] = '%'; symbols[i++] = '^'; symbols[i++] = '&'; symbols[i++] = '*';
    symbols[i++] = '('; symbols[i++] = ')'; symbols[i++] = '~'; symbols[i++] = '-';
    symbols[i++] = '_'; symbols[i++] = '='; symbols[i++] = '+'; symbols[i++] = '\\';
    symbols[i++] = '|'; symbols[i++] = '/'; symbols[i++] = '['; symbols[i++] = ']';
    symbols[i++] = '{'; symbols[i++] = '}'; symbols[i++] = ';'; symbols[i++] = ':';
    symbols[i++] = '`'; symbols[i++] = '\''; symbols[i++] = '"'; symbols[i++] = ',';
    symbols[i++] = '.'; symbols[i++] = '<'; symbols[i++] = '>'; symbols[i++] = '?';

    i = ;
    boundaries_charclass[i++] = ; boundaries_charclass[i++] = ;
    boundaries_charclass[i++] = ; boundaries_charclass[i++] = ;

    i = ;
    boundaries_numbers[i++] = ; boundaries_numbers[i++] = ;
    boundaries_numbers[i++] = ; boundaries_numbers[i++] = ;
    boundaries_numbers[i++] = ; boundaries_numbers[i++] = ;
    boundaries_numbers[i++] = ; boundaries_numbers[i++] = ;
    boundaries_numbers[i++] = ; boundaries_numbers[i++] = ;

    i = ;
    boundaries_letters[i++] = ; boundaries_letters[i++] = ;
    boundaries_letters[i++] = ; boundaries_letters[i++] = ;
    boundaries_letters[i++] = ; boundaries_letters[i++] = ;
    boundaries_letters[i++] = ; boundaries_letters[i++] = ;
    boundaries_letters[i++] = ; boundaries_letters[i++] = ;
    boundaries_letters[i++] = ; boundaries_letters[i++] = ;
    boundaries_letters[i++] = ; boundaries_letters[i++] = ;
    boundaries_letters[i++] = ; boundaries_letters[i++] = ;
    boundaries_letters[i++] = ; boundaries_letters[i++] = ;
    boundaries_letters[i++] = ; boundaries_letters[i++] = ;
    boundaries_letters[i++] = ; boundaries_letters[i++] = ;
    boundaries_letters[i++] = ; boundaries_letters[i++] = ;
    boundaries_letters[i++] = ; boundaries_letters[i++] = ;

    i = ;
    boundaries_symbols[i++] = ; boundaries_symbols[i++] = ;
    boundaries_symbols[i++] = ; boundaries_symbols[i++] = ;
    boundaries_symbols[i++] = ; boundaries_symbols[i++] = ;
    boundaries_symbols[i++] = ; boundaries_symbols[i++] = ;
    boundaries_symbols[i++] = ; boundaries_symbols[i++] = ;
    boundaries_symbols[i++] = ; boundaries_symbols[i++] = ;
    boundaries_symbols[i++] = ; boundaries_symbols[i++] = ;
    boundaries_symbols[i++] = ; boundaries_symbols[i++] = ;
    boundaries_symbols[i++] = ; boundaries_symbols[i++] = ;
    boundaries_symbols[i++] = ; boundaries_symbols[i++] = ;
    boundaries_symbols[i++] = ; boundaries_symbols[i++] = ;
    boundaries_symbols[i++] = ; boundaries_symbols[i++] = ;
    boundaries_symbols[i++] = ; boundaries_symbols[i++] = ;
    boundaries_symbols[i++] = ; boundaries_symbols[i++] = ;
    boundaries_symbols[i++] = ; boundaries_symbols[i++] = ;
    boundaries_symbols[i++] = ; boundaries_symbols[i++] = ;

    seed = ;
}

void generate()
{
    int i, j, s, next, nextp, val, bucket, randnum, used_charsets;
    int seedarray[];

    /* BEGIN System.Random(seed) */
    if(seed < ) {
        /* Only bother with non-negative integers */
        word = ;
        return;
    }

    s =  - seed++;
    seedarray[] = s;
    i = val = ;

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

    i = ;
    while(i < ) {
        j = ;
        while(j < ) {
            seedarray[j] -= seedarray[ + (j + ) % ];
            if(seedarray[j] < ) seedarray[j] += ;
            j++;
        }
        i++;
    }
    next = ;
    nextp = ;
    /* END System.Random(seed) */

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

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

            word[i] = j; /* Temporarily store in word[] */
            used_charsets |= ( << j);
            i++;
        }
    }

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

        if(word[i] == ) {
            while(boundaries_letters[j] < randnum) j++;
            word[i++] = lowers[j];
        } else if (word[i] == ) {
            while(boundaries_letters[j] < randnum) j++;
            word[i++] = uppers[j];
        } else if (word[i] == ) {
            while(boundaries_numbers[j] < randnum) j++;
            word[i++] = numbers[j];
        } else { /* if (word[i] == 3) */
            while(boundaries_symbols[j] < randnum) j++;
            word[i++] = symbols[j];
        }
    }
    word[i] = ;
}


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

    seed = ;

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

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

        i = ;
        while(i < ) {
            j = ;
            while(j < ) {
                seedarray[j] -= seedarray[ + (j + ) % ];
                if(seedarray[j] < ) seedarray[j] += ;
                j++;
            }
            i++;
        }
        next = ;
        nextp = ;
        /* END System.Random(seed) */

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

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

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

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

            if(candidate[i] == ) {
                while(boundaries_letters[j] < randnum) j++;
                if(lowers[j] != word[i++]) break;
            } else if (candidate[i] == ) {
                while(boundaries_letters[j] < randnum) j++;
                if(uppers[j] != word[i++]) break;
            } else if (candidate[i] == ) {
                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[];     // Current character indices for each position
int m[];       // The keys matrix
int mc[];      // Counts of adjacent keys
int f[], fc;    // Characters for the first position, their count

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

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

/*
 * This defines the keyboard layout, by default for a QWERTY keyboard.
 */
    i = ; while (i < ) k[i++] = ;
    k[] = '`';
    i = ; while (++i <= ) k[i] = '0' + i;
    k[] = '0'; k[] = '-'; k[] = '=';
    k[] = 'q'; k[] = 'w'; k[] = 'e'; k[] = 'r';
    k[] = 't'; k[] = 'y'; k[] = 'u'; k[] = 'i';
    k[] = 'o'; k[] = 'p'; k[] = '['; k[] = ']';
    k[] = '\\';
    k[] = 'a'; k[] = 's'; k[] = 'd'; k[] = 'f';
    k[] = 'g'; k[] = 'h'; k[] = 'j'; k[] = 'k';
    k[] = 'l'; k[] = ';'; k[] = '\'';
    k[] = 'z'; k[] = 'x'; k[] = 'c'; k[] = 'v';
    k[] = 'b'; k[] = 'n'; k[] = 'm'; k[] = ',';
    k[] = '.'; k[] = '/';

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

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

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

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

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

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

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

void restore()
{
    int i;

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

    /* Infer the first character index */
    i = -;
    while (++i < fc) {
        if (f[i] == word[]) {
            id[] = 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] = ;
    while (i--)
        word[i] = startchar;
    word[] = startchar - ;

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

void generate()
{
    int i;

    if (++word <= endchar)
        return;

    i = ;

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

    if (i >= maxlength)
        word = ;
}

/*
 * 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[];       // Current character indices for other positions
int charset[], 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 = ;
    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 = ;
    charset[i++] = ;       // 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' + ;            // Skip lowercase letters and
    while (c <= )       // proceed for all printable ASCII
        charset[i++] = c++;
    c++;                // Skip DEL (ASCII 127) and
    while (c < )        // proceed over 8-bit codes till IND
        charset[i++] = c++;
    charset[i++] = ;        // Skip IND (84 hex) and NEL (85 hex)
    charset[i++] = ;
    c = ;           // Skip HTS (88 hex)
    while (c < )        // Proceed till RI (8D hex)
        charset[i++] = c++;
    c = ;           // Skip RI, SS2, SS3, DCS
    while (c < )        // Proceed till SPA (96 hex)
        charset[i++] = c++;
    charset[i++] = ;        // Skip SPA, EPA, SOS
    c = ;           // Skip DECID, CSI, ST, OSC, PM, APC
    while (c <= )       // Proceed with the rest of 8-bit codes
        charset[i++] = c++;

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

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

void generate()
{
    int i;

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

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

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

void restore()
{
    int i, c;

/* Calculate the current length and infer the character indices */
    last = ;
    while (c = word[last]) {
        i = ; while (charset[i] != c && charset[i]) i++;
        if (!charset[i]) i = ; // 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[];       // Current character indices for other positions
int charset[];    // 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 = ; // 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 = ;
    while (pos < ) {
        ofs = pos++ << ;
        i = ;
        c = 'a';
        while (c <= 'z')
            charset[ofs + i++] = c++;
        c = 'A';
        while (c <= 'Z')
            charset[ofs + i++] = c++;
        charset[ofs + i] = ;
    }
    while (pos < length) {
        ofs = pos++ << ;
        i = ;
        c = '0';
        while (c <= '9')
            charset[ofs + i++] = c++;
        charset[ofs + i] = ;
    }

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

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 << ];
    }

    word = ;           // We're done
}

void restore()
{
    int i, c;

/* Calculate the current length and infer the character indices */
    last = ;
    while (c = word[last]) {
        i = lastofs = last << ;
        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[];       // Current character indices for other positions
int charset[];    // Character sets, 0x100 elements for each position

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

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

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

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

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 << ];
    }

    word = ;           // We're done
}

void restore()
{
    int i, c;

/* Calculate the current length and infer the character indices */
    last = ;
    while (c = word[last]) {
        i = lastofs = last << ;
        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 = ;
    while (i < length)
        word[i++] = c;
    word[i] = ;

    if (c++ < maxc)
        return;

    c = minc;

    if (++length > maxlength)
        c = ; // 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 = ;
    if (req_maxlen)
        maxlength = req_maxlen;
    else
        maxlength = cipher_limit;   // the format's limit
    minc = ;
    maxc = ;

    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 = ;
    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 = ;
    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 = ;
    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 = ;

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

    // 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 >  && first + (length - ) * inc > to) ||
        (direction <  && first - (length - ) * 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 - ) > 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 - ) > 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 = ;
    }
}

# 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-]
.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 = ;

    // 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 = ;

    // 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 + ;
        direction = ;
    } else {
        // We have to create sequences which decrement the previous character
        maxlength = from - to + ;
        direction = -;
    }
}

# 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 = ;
    inc = ;

    length = minlength;
    first = from;

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

# 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 = ;
    inc = ;

    length = minlength;
    first = from;

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

# 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 = ;
    inc = ;

    length = minlength;
    first = from;

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

# 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 = ;
    inc = ;

    length = minlength;
    first = from;

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

# 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 = ;
    minlength = ;
    inc = ;

    length = minlength;
    first = from;

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


# 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[];       // Current character indices for other positions
int subset[], c0;  // Current subset
int subcount;       // Number of characters in the current subset
int subid[];   // Indices into charset[] of characters in subset[]
int charset[]; // 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 = ;

    // 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 = ;

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

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

/* This defines the character set */
    i = ;
    c = ;
    while (c <= )
        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) - ;
    while (i--)
        subid[i] = charcount;
    subset[] = c0 = ;
    last = maxlength - ;
    lastid = -;
}

void generate()
{
    int i;

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

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

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

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

    if (subcount > maxdiff) {
        word = ;       // 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 - ;
    else
        last = minlength - ;
    c0 = subset[];
    i = ;
    while (i <= last) {
        id[i] = ;
        word[i++] = c0;
    }
    lastid = ;
    word[i] = ;
}

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

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

    word = ; // 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[];

void init()
{
    int c;

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

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

void filter()
{
    int i;

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

    word = ; // 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[];

void init()
{
    int c;

    mask[] = ;
    c = ;
    while (c < )
        mask[c++] = ;

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

void filter()
{
    int i, seen;

/*
 * This loop ends when we see NUL (sets 0x100) or a disallowed character
 * (sets 0x200).
 */
    i = -; seen = ;
    while ((seen |= mask[word[++i]]) < )
        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 !=  || i != )
        word = ; // 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[], map2[];

void init()
{
    int i;

    map1[] = ~;
    i = ;
    while (i < )
        map1[i++] = ~;
    i = -;
    while (++i < )
        map1['0' + i] = i + ((i *  %  + i / ) << );
    i = -;
    while (++i < ) {
        if (i % )
            map2[i] = '9' +  - i % ;
        else
            map2[i] = '0';
    }
}

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

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

# 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 = ;
    j = ; // j counts the number of changed characters

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

# 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 = ;

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

# 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 = ; total = ;        // Node 1 of 2, change as appropriate
    number = node - ;      // Speedup the filter a bit
}

void filter()
{
    if (number++ % total)       // Word for a different node?
        word = ;       // 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 = ;
    number = ;
}

void filter()
{
    if (++number > max)
        abort = ;      // 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 = ;
    number = ;
}

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

# dumb-force UTF-16, in an external file
.include "$JOHN/dumb16.conf"

# dumb-force UTF-32, in an external file
.include "$JOHN/dumb32.conf"

# repeats UTF-16, in an external file
.include "$JOHN/repeats16.conf"

# repeats UTF-32, in an external file
.include "$JOHN/repeats32.conf"

# Dynamic ($dynamic_n$) scripting code, in an external file
# also shows/tests that .include <file> works the same as .include "$JOHN/file"
.include <dynamic.conf>

# Regex alphabets
.include <regex_alphabets.conf>

# include john.local.conf (defaults to being empty, but never overwritten)
.include "$JOHN/john.local.conf"

# 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.
           

References

http://www.openwall.com/john/doc