XKPasswd - A secure memorable password generator
This documentation refers to XKPasswd version 2.1.1.
use XKPasswd;
#
# Functional Interface - for single passwords generated from simple configs
#
# generate a single password using words from the file
# sample_dict.txt using the default configuration
my $password = xkpasswd('sample_dict.txt');
# generate a single password using one of the module's
# predefined presets exactly
my $password = xkpasswd('sample_dict.txt', 'XKCD');
# generate a single password using one of the module's
# predefined presets as a starting point, but with a
# small customisation
my $password = xkpasswd('sample_dict.txt', 'XKCD', {separator_character => q{ }});
#
# Object Oriented Interface
#
# create a new instance with the default config
my $xkpasswd_instance = XKPasswd->new('sample_dict.txt');
# create an instance from the preset 'XKCD'
my $xkpasswd_instance = XKPasswd->new('sample_dict.txt', 'XKCD');
# create an instance based on the preset 'XKCD' with one customisation
my $xkpasswd_instance = XKPasswd->new('sample_dict.txt', 'XKCD', {separator_character => q{ }});
# create an instance from a config based on a preset
# but with many alterations
my $config = XKPasswd->preset_config('XKCD');
$config->{separator_character} = q{ };
$config->{case_transform} = 'INVERT';
$config->{padding_type} = "FIXED";
$config->{padding_characters_before} = 1;
$config->{padding_characters_after} = 1;
$config->{padding_character} = '*';
my $xkpasswd_instance = XKPasswd->new('sample_dict.txt', $config);
# create an instance from an entirely custom configuration
my $config = {
padding_alphabet => [qw{! @ $ % ^ & * + = : ~ ?}],
separator_alphabet => [qw{- + = . _ | ~}],
word_length_min => 6,
word_length_max => 6,
num_words => 3,
separator_character => 'RANDOM',
padding_digits_before => 2,
padding_digits_after => 2,
padding_type => 'FIXED',
padding_character => 'RANDOM',
padding_characters_before => 2,
padding_characters_after => 2,
case_transform => 'CAPITALISE',
random_function => \&XKPasswd::basic_random_generator,
random_increment => 'AUTO',
}
my $xkpasswd_instance = XKPasswd->new('sample_dict.txt', $config);
# generate a single password
my $password = $xkpasswd_instance->password();
# generate multiple passwords
my @passwords = $xkpasswd_instance->passwords(10);
A secure memorable password generator inspired by the wonderful XKCD webcomic at http://www.xkcd.com/ and Steve Gibson's Password Haystacks page at https://www.grc.com/haystack.htm. This is the Perl library that powers https://www.xkpasswd.net.
More and more of the things we do on our computer require passwords, and at the same time it seems we hear about organisations or sites losing user database on every day that ends in a y. If we re-use our passwords we expose ourself to an ever greater risk, but we need more passwords than we can possibly remember or invent. Coming up with one good password is easy, but coming up with one good password a week is a lot harder, let alone one a day!
Obviously we need some technological help. We need our computers to help us generate robust password and store them securely. There are many great password managers out there to help us securely store and sync our passwords, including commercial offerings and open-source projects. Many of these managers also offer to generate random passwords for us, usually in the form of a random string of meaningless letters numbers and symbols. These kinds of nonsense passwords are certainly secure, but they are often impractical.
Regardless of how good your chosen password manager is, there will always be times when you need to type in your passwords, and that's when random gibberish passwords become a real pain point. As annoying as it is to have to glance over and back at a small cellphone screen to manually type a gibberish password into a computer, that's nothing compared to the annoyance of trying to communicate such a password to a family member, friend, colleague or customer over the phone.
Surely it would be better to have passwords that are still truly random in the way humans can't be, but are also human-friendly in the way random gibberish never will be? This is the problem this module aims to solve.
Rather than randomly choosing many letters, digits, and symbols from a fairly small alphabet of possible characters, this library chooses a small number of words from a large alphabet of possible words as the basis for passwords. Words are easy to remember, easy to read from a screen, easy to type, and easy to communicate over the telephone.
This module uses words to make up the bulk of the passwords it generates, but it also adds carefully placed random symbols and digits to add more security without the passwords difficult to remember, read, type, or speak.
In shot, this module is for people who prefer passwords that look like this:
!15.play.MAJOR.fresh.FLAT.23!
to passwords that look like this:
eB8.GJXa@TuM
Before examining the password strength of passwords generated with this module we need to lay out the relatively simple maths underlying it all.
A coin could be used as a very simple password generator. Each character in the password would be the result of a single coin toss. If the coin lands heads up, we add a H
to our password, if it lands tails up, we add a T
.
If you made a one-letter password in this way there would only be two possibilities, H
, or T
, or two permutations. If you made a two-letter password in this way there would be four possible combinations, or permutations, HH
, HT
, TH
, and TT
. If you made a three-character password in this way there would be 16 permutations, a five character one would have 32 permutations, and so forth.
So, for a coin toss, which has two possible values for each character, the formula for the number of permutations P
for a given length of password L
is:
P = 2^L
Or, two to the power of the length of the password.
If we now swapped our coin for a dice, we would go from two possible values per letter, to six possible values per letter. For one dice roll there would be six permutations, for two there would be 36, for three there would be 108 and so on.
This means that for a dice, the number of permutations can be calculated with the formula:
P = 6^L
When talking about passwords, the set of possible symbols used for each character in the password is referred to as the password's alphabet. So, for the coin toss the alphabet was just H
and T
, and for the dice it was 1
, 2
, 3
, 4
, 5
, and 6
. The actual characters used in the alphabet make no difference to the strength of the password, all that matters is the size of the alphabet, which we'll call A
.
As you can probably infer from the two examples above, the formula for the number of possible permutations P
for a password of length L
created from an alphabet of size A
is:
P = A^L
In the real world our passwords are generally made up of a mix of letters, digits, and symbols. If we use mixed case that gives us 52 letters alone, then add in the ten digits from 0
to 9
and we're already up to 62 possible characters before we even start on the array of symbols and punctuation characters on our keyboards. It's generally accepted that if you include symbols and punctuation, there are 95 characters available for use in randomly generated passwords. Hence, in the real-world, the value for A
is assumed to be 95. When you start raising a number as big as 95 to even low powers the number of permutations quickly rises.
A two character password with alphabet of 95 has 9025 permutations, increasing the length to three characters brings that up to 857,375, and so on. These numbers very quickly become too big to handle. For just an 8 character password we are talking about 6,634,204,312,890,625 permutations, which is a number so big most people couldn't say it (what do you call something a thousand times bigger than a trillion?).
Because the numbers get so astronomically big so quickly, computer scientists use bits of entropy to measure password strength rather than the number of permutations. The formula to turn permutations into bits of entropy E
is very simple:
E = Log(2)P
In other words, the entropy is the log to base two of the permutations. For our eight character example that equates to about 52 bits.
There are two approaches to increasing the number of permutations, and hence the entropy, you can choose more characters, or, you can make the alphabet you are choosing from bigger.
Exactly how much entropy does a password need? That's the subject of much debate, and the answer ultimately depends on the value of the assets being protected by the password.
Two common recommendations you hear are 8 characters containing a mix of upper and lower case letters, digits, and symbols, or 12 characters with the same composition. These evaluation to approximately 52 bits of entropy and 78 bits of entropy respectively.
When evaluating the entropy of passwords generated by this module, it has to be done from two points of view for the answer to be meaningful. Firstly, a best-case scenario - the attacker has absolutely no knowledge of how the password was generated, and hence must mount a brute-force attack. Then, secondly from the point of view of an attacker with full knowledge of how the password was generated. Not just the knowledge that this module was used, but a copy of the dictionary file used, and, a copy of the configuration settings used.
For the purpose of this documentation, the entropy in the first scenario, the brute force attack, will be referred to as the blind entropy, and the entropy in the second scenario the seen entropy.
The blind entropy is solely determined by the configuration settings, the seen entropy depends on both the settings and the dictionary file used.
Calculating the bind entropy Eb
is quite straightforward, we just need to know the size of the alphabet resulting from the configuration A
, and the minimum length of passwords generated with the configuration L
, and plug those values into this formula:
Eb = Log(2)(A^L)
Calculating A
simply involves determining whether or not the configuration results in a mix of letter cases (26 or 52 characters), the inclusion of at least one symbol (if any one is present, assume the industry standard of a 33 character search space), and the inclusion of at least one digit (10 character). This will result in a value between 26 and 95.
Calculating L
is also straightforward. The one minor complication is that some configurations result in a variable length password. In this case, assume the shortest possible length the configuration could produce.
The example password from the "PHILOSOPHY" section (!15.play.MAJOR.fresh.FLAT.23!
) was generated using the preset WEB32
. This preset uses four words of between four and five letters long, with the case of each word randomly set to all lower or all upper as the basis for the password, it then chooses two pairs of random digits as extra words to go front and back, before separating each word with a copy of a randomly chosen symbol, and padding the front and back of the password with a copy of a different randomly chosen symbol. This results in passwords that contain a mix of cases, digits, and symbols, and are between 27 and 31 characters long. If we add these values into the formula we find that the blind entropy for passwords created with this preset is:
Eb = Log(2)(95^27) = 163 bits
This is spectacularly secure! And, this is the most likely kind of attack for a password to face. However, to have confidence in the password we must also now calculate the entropy when the attacker knows everything about how the password was generated.
We will calculate the entropy resulting from the same WEB32
config being used to generate a password using the sample library file that ships with the module.
The number of permutations the attacker needs to check is purely the product of possibly results for each random choice made during the assembly of the password.
Lets start with the words that will form the core of the password. The configuration chooses four words of between four and five letters long from the dictionary, and then randomises their case, effectively making it a choice from twice as many words (each word in each case).
The sample dictionary file contains 698 words of the configured length, which doubles to 1396. Choosing four words from that very large alphabet gives a starting point of 1396^4
, or 3,797,883,801,856 permutations.
Next we need to calculate the permutations for the separator character. The configuration specifies just nine permitted characters, and we choose just one, so that equates to 9 permutations.
Similarly, the padding character on the end is chosen from 13 permitted symbols giving 13 more permutations.
Finally, there are four randomly chosen digits, giving 10^4
, or 10,000 permutations.
The total number of permutations is the product of all these permutations:
Pseen = 3,797,883,801,856 * 9 * 13 * 10,000 = 2.77x10^17
Finally, we convery this to entropy by taking the base 2 log:
Eseen = Log(2)2.77x10^17 = ~57bits
What this means is that most probably, passwords generated with this preset using the sample dictionary file are spectacularly more secure than even 12 randomly chosen characters, and, that in the very unlikely event that an attackers knows absolutely everything about how the password was generated, it is still significantly more secure than 8 randomly chosen characters.
Because the exact strength of the passwords produced by this module depend on the configuration and dictionary file used, the constructor does the above math when creating an XKPasswd object, and throws a warning if either the blind entropy falls below 78bits, or the seen entropy falls below 52 bits.
XKPasswd instances load their word lists from text files. The constructor loads the words contained in a single file into memory when assembling an XKPasswd object. Once constructed, the object never reads from the file again. Throughout this documentation, the text file containing the words to be used is referred to as the Dictionary File, and specified via the dictionary_file_path
config variable.
The rules for the formatting of dictionary files are simple. Dictionary files must contain one word per line. Words shorter than four letters will be ignored, as will all lines starting with the # symbol.
This format is the same as that of the standard Unix Words file, usually found at /usr/share/dict/words
on Unix and Linux operating systems (including OS X).
In order to produce secure passwords it's important to use a dictionary file that contains a large selection of words with a good mix of different word lengths.
A sample dictionary file (sample_dict.txt
) is distributed with this module.
A number of subroutines require a configuration hashref as an argument. The following are the valid keys for that hashref, what they mean, and what values are valid for each.
case_transform
- the alterations that should be made to the case of the letters in the randomly chosen words that make up the bulk of the randomly generated passwords. Must be a scalar, and the only valid values for this key are:
ALTERNATE
- each alternate word will be converted to all upper case and all lower case.
CAPITALISE
- the first letter in every word will be converted to upper case, all other letters will be converted to lower case.
INVERT
- the first letter in every word will be converted to lower case, all other letters will be converted to upper case.
LOWER
- all letters in all the words will be converted to lower case. Use of this option is strongly discouraged for security reasons.
NONE
- the capitalisation used in the randomly generated password will be the same as it is in the dictionary file.
RANDOM
- each word will be randomly converted to all upper case or all lower case.
UPPER
- all letters in all the words will be converted to upper case. Use of this option is strongly discouraged for security reasons.
The default value returned by default_config()
is CAPITALISE
.
character_substitutions
- a hashref containing zero or more character substitutions to be applied to the words that make up the bulk of the generated passwords. The keys in the hashref are the characters to be replaced, and must be single alpha numeric characters, while the values in the hashrefs are the replacements, and can be longer.
num_words
- the number of randomly chosen words use as the basis for the generated passwords. The default value is four. For security reasons, at least two words must be used.
pad_to_length
- the total desired length of the password when using adaptive padding (padding_type
set to ADAPTIVE
). Must be a scalar with an integer values greater than or equal to 12 (for security reasons).
padding_alphabet
- this key is optional. It can be used to override the contents of symbol_alphabet
when padding_character
is set to RANDOM
. If present this key must contain an arrayref containing at least two single characters as scalars.
padding_character
- the character to use when padding the front and/or back of the randomly generated password. Must be a scalar containing either a single character or one of the special values RANDOM
(indicating that a character should be chosen at random from the symbol_alphabet
), or SEPARATOR
(use the same character used to separate the words). This key is only needed if padding_type
is set to FIXED
or ADAPTIVE
. The default value returned by default_config
is RANDOM
.
padding_characters_before
& padding_characters_after
- the number of symbols to pad the front and end of the randomly generated password with. Must be a scalar with an integer value greater than or equal to zero. These keys are only needed if padding_type
is set to FIXED
. The default value returned by default_config()
for both these keys is 2.
padding_digits_before
& padding_digits_after
- the number of random digits to include before and after the randomly chosen words making up the bulk of the randomly generated password. Must be scalars containing integer values greater than or equal to zero. The default value returned by default_config()
for both these keys is 2.
padding_type
- the type of symbol padding to be added at the start and/or end of the randomly generated password. Must be a scalar with one of the following values:
NONE
- do not pad the generated password with any symbol characters.
FIXED
- a specified number of symbols will be added to the front and/or back of the randomly generated password. If this option is chosen, you must also specify the keys padding_character
, padding_characters_before
& padding_characters_after
.
ADAPTIVE
- no symbols will be added to the start of the randomly generated password, and the appropriate number of symbols will be added to the end to make the generated password exactly a certain length. The desired length is specified with the key pad_to_length
, which is required if this padding type is specified.
The default value returned by default_config()
is FIXED
.
random_function
- a reference to the function to be used use to generate random numbers during the password generation process. The function generate an array of random decimal numbers between 0 and 1, take one argument, the number of random numbers to generate, and it must return an array. By default the function XKPasswd::basic_random_generator()
is used.
random_increment
- the number of random digits to generate at a time when ever the instance's cache of randomness runs low. Must be an integer greater than or equal to 1, or the special value AUTO
. When the value is set to AUTO
a call to config_stats()
is used to determine the amount of random numbers needed to generate a single password, and this value is used as the random increment. The default value is c<AUTO>.
separator_alphabet
- this key is optional. It can be used to override the contents of symbol_alphabet
when separator_character
is set to RANDOM
. If present this key must contain an arrayref containing at least two single characters as scalars.
separator_character
- the character to use to separate the words in the generated password. Must be a scalar, and acceptable values are a single character, or, the special values NONE
(indicating that no separator should be used), or RANDOM
, indicating that a character should be chosen at random from the symbol_alphabet
. The default value returned by default_config()
is RANDOM
.
symbol_alphabet
- an arrayref containing at least two single characters as scalars. This alphabet will be used when selecting random characters to act as the separator between words, or the padding at the start and/or end of generated passwords. Note that this key can be overridden by setting either or both padding_alphabet
and separator_alphabet
. The default value returned by default_config()
is [qw{! @ $ % ^ & * - _ + = : | ~ ?}]
word_length_min
& word_length_max
- the minimum and maximum length of the words that will make up the generated password. The two keys must be scalars, and can hold equal values, but word_length_max
may not be smaller than word_length_min
. For security reasons, both values must be greater than 3. The default values returned by default_config()
is are 4 & 8.
For ease of use, this module comes with a set of pre-defined presets. Preset names can be used in place of config hashrefs when instantiating an XKPasswd object, or, when using the functional interface to XKPasswd.
Presets can be used as-is, or, they can be used as a starting point for creating your own config hashref, as demonstrated by the following example:
my $config = XKPasswd->preset_config('XKCD');
$config->{separator_character} = q{ }; # change the separator to a space
my $xkpasswd = XKPasswd->new('sample_dict.txt', $config);
If you only wish to alter a small number of config settings, the following two shortcuts might be of interest (both produce the same result as the example above):
my $config = XKPasswd->preset_config('XKCD', {separator_character => q{ }});
my $xkpasswd = XKPasswd->new('sample_dict.txt', $config);
or
my $xkpasswd = XKPasswd->new('sample_dict.txt', 'XKCD', {separator_character => q{ }});
For more see the definitions for the class functions defined_presets()
, presets_to_string()
, preset_description()
, and preset_config()
.
The following presets are defined:
APPLEID
- a preset respecting the many prerequisites Apple places on Apple ID passwords. Apple's official password policy is located here: http://support.apple.com/kb/ht4232. Note that Apple's knowledge base article omits to mention that passwords can't be longer than 32 characters. This preset is also configured to use only characters that are easy to type on the standard iOS keyboard, i.e. those appearing on the letters keyboard (ABC
) or the numbers keyboard .?123
, and not those on the harder to reach symbols keyboard #+=
. Below is a sample password generated with this preset:
@60:london:TAUGHT:forget:70@
DEFAULT
- the default configuration. Below is a sample password generated with this preset:
~~12:settle:SUCCEED:summer:48~~
NTLM
- a preset for 14 character NTMLv1 (NTLM Version 1) passwords. ONLY USE THIS PRESET IF YOU MUST! The 14 character limit does not allow for sufficient entropy in the case where the attacker knows the dictionary and config used to generate the password, hence this preset will generate low entropy warnings. Below is a sample password generated with this preset:
0=mAYAN=sCART@
SECURITYQ
- a preset for creating fake answers to security questions. It generates long nonsense sentences ending in .
!
or ?
, for example:
Wales outside full month minutes gentle?
WEB16
- a preset for websites that don't allow more than 16 character long passwords. Because 16 characters is not very long, a large set of symbols are chosen from for the padding and separator. Below is a sample password generated with this preset:
:baby.ohio.DEAR:
WEB32
- a preset for websites that don't allow more than 32 character long passwords. Below is a sample password generated with this preset:
+93-took-CASE-money-AHEAD-31+
WIFI
- a preset for generating 63 character long WPA2 keys (most routers allow 64 characters, but some only 63, hence the odd length). Below is a sample password generated with this preset:
2736_ITSELF_PARTIAL_QUICKLY_SCOTLAND_wild_people_7441!!!!!!!!!!
XKCD
- a preset inspired by the original XKCD comic (http://xkcd.com/936/), but with some alterations to provide sufficient entropy to avoid low entropy warnings. Below is a sample password generated with this preset:
KING-madrid-exercise-BELGIUM
For security reasons, this module's default behaviour is to warn (using carp()
) when ever the loaded combination dictionary file and configuration would result in low-entropy passwords. When the constructor is invoked, or when a new dictionary file or new config hashref are loaded into an object (using dictionary()
or config()
) the entropy of the resulting new state of the object is calculated and checked against the defined minima.
Entropy is calculated and checked for two scenarios. Firstly, for the best-case scenario, when an attacker has no prior knowledge about the password, and must resort to brute-force attacks. And secondly, for the worst-case scenario, when the attacker is assumed to know that this module was used to generate the password, and, that the attacker has a copy of the dictionary file and config settings used to generate the password.
Entropy checking is controlled via three package variables:
$XKPasswd::ENTROPY_MIN_BLIND
- the minimum acceptable entropy (in bits) for a brute-force attack. The default value for this variable is 78 (equivalent to a 12 character password consisting of mixed-case letters, digits, and symbols).
$XKPasswd::ENTROPY_MIN_SEEN
- the minimum acceptable entropy (in bits) for a worst-case attack (where the dictionary and configuration are known). The default value for this variable is 52 (equivalent to an 8 character password consisting of mixed-case letters, digits, and symbols).
$XKPasswd::SUPRESS_ENTROPY_WARNINGS
- this variable can be used to suppress one or both of the entropy warnings. The following values are valid (invalid values are treated as being NONE
):
NONE
- no warnings are suppressed. This is the default value.
SEEN
- only warnings for the worst-case scenario are suppressed.
BLIND
- only warnings for the best-case scenario are suppressed.
ALL
- all entryopy warnings are suppressed.
The entropy calculations make some assumptions which may in some cases lead to the results being inaccurate. In general, an attempt has been made to always round down, meaning that in reality the entropy of the produced passwords may be higher than the values calculated by the package.
When calculating the entropy for brute force attacks on configurations that can result in variable length passwords, the shortest possible password is assumed.
When calculating the entropy for brute force attacks on configurations that contain at least one symbol, it is assumed that an attacker would have to brute-force-check 33 symbols. This is the same value used by Steve Gibson's Password Haystacks calculator (https://www.grc.com/haystack.htm).
When calculating the entropy for worst-case attacks on configurations that contain symbol substitutions where the replacement is more than 1 character long the possible extra length is ignored.
In order to avoid this module relying on any non-standard modules, the default source of randomness is Perl's built-in rand()
function. This provides a reasonable level of randomness, and should suffice for most users, however, some users will prefer to make use of one of the many advanced randomisation modules in CPAN, or, reach out to a web service like http://random.org for their randomness. To facilitate both of these options, this module uses a cache of randomness, and allows a custom randomness function to be specified by setting the config variable random_function
to a coderef to the function.
Functions specified in this way must take exactly one argument, an integer number greater than zero, and then return that many random decimal numbers between zero and one.
The random function is not called each time a random number is needed, instead a number of random numbers are generated at once, and cached until they are needed. The amount of random numbers generated at once is controlled by the random_increment
config variable. The reason the module works in this way is to facilitate web-based services which prefer you to generate many numbers at once rather than invoking them repeatedly. For example, Random.org ask developers to query them for more random numbers less frequently.
Although the package was primarily designed to be used in an object-oriented way, there is a functional interface too. The functional interface initialises an object internally and then uses that object to generate a single password. If you only need one password, this is no less efficient than the object-oriented interface, however, if you are generating multiple passwords it is much less efficient.
There is only a single function exported by the module:
my $password = xkpasswd('sample_dict.txt');
This function call is equivalent to the following Object-Oriented code:
my $xkpasswd = XKPasswd->new('sample_dict.txt');
my $password = $xkpasswd->password();
This function passes its arguments through to the constructor, so all arguments that are valid in new()
are valid here.
This function Croaks if there is a problem generating the password.
Note that it is inefficient to use this function to generate multiple passwords because the dictionary file will be re-loaded, and the entropy calculations for ensuring security repeated, each time a password is generated.
# create a new instance with the default config
my $xkpasswd_instance = XKPasswd->new('sample_dict.txt');
# create an instance from the preset 'XKCD'
my $xkpasswd_instance = XKPasswd->new('sample_dict.txt', 'XKCD');
# create an instance based on the preset 'XKCD' with one customisation
my $xkpasswd_instance = XKPasswd->new('sample_dict.txt', 'XKCD', {separator_character => q{ }});
# create an instance from a config hashref
my $xkpasswd_instance = XKPasswd->new('sample_dict.txt', $config_hashref);
The constructor must be called via the package name, and at least one argument must be passed, the path to the dictionary file to be used when generating the words.
If only one argument is passed the default values are used for all config keys. To use a different configuration, a second argument can be passed. If this argument is a scalar it will be assumed to be the name of a preset, and if it is a hashref it is assumed to be the config to load.
If a preset name is passed as a second argument, a hashref with config key overrides can be passed as a third argument. If the second argument is a hashref the third argument is ignored.
NOTE - All class methods must be invoked via the package name, or they will croak.
my $clone = XKPasswd->clone_config($config);
This function must be passed a valid config hashref as the first argument or it will croak. The function returns a hashref.
my %stats = XKPasswd->config_stats($config);
This function requires one argument, a valid config hashref. It returns a hash of statistics about a given configuration. The hash is indexed by the following:
length_min
- the minimum length a password generated with the given config could be.
length_max
- the maximum length a password generated with the given config could be. (see caveat below)
random_numbers_required
- the amount of random numbers needed to generate a password using the given config.
There is one scenario in which the calculated maximum length will not be reliably accurate, and that's when a character substitution with a length greater than 1 is specified, and padding_type
is not set to ADAPTIVE
. If the config passed contains such a character substitution, the length will be calculated ignoring the possibility that one or more extra characters could be introduced depending on how many, if any, of the long substitutions get triggered by the randomly chosen words. If this happens the function will also carp with a warning.
my $config_string = XKPasswd->config_to_string($config);
This function returns the content of the passed config hashref as a scalar string. The function must be passed a valid config hashref or it will croak.
my $config = XKPasswd->default_config();
This function returns a hashref containing a config with default values.
This function can optionally be called with a single argument, a hashref containing keys with values to override the defaults with.
my $config = XKPasswd->default_config({num_words => 3});
When overrides are present, the function will carp if an invalid key or value is passed, and croak if the resulting merged config is invalid.
This function is a shortcut for preset_config()
, and the two examples above are equivalent to the following:
my $config = XKPasswd->preset_config('DEFAULT');
my $config = XKPasswd->preset_config('DEFAULT', {num_words => 3});
my @preset_names = XKPasswd->defined_presets();
This function returns the list of defined preset names as an array of scalars.
my $is_ok = XKPasswd->is_valid_config($config);
This function must be passed a hashref to test as the first argument or it will croak. The function returns 1 if the passed config is valid, and 0 otherwise.
Optionally, any truthy value can be passed as a second argument to indicate that the function should croak on invalid configs rather than returning 0;
use English qw( -no_match_vars );
eval{
XKPasswd->is_valid_config($config, 'do_croak');
}or do{
print "ERROR - config is invalid because: $EVAL_ERROR\n";
}
my $config = XKPasswd->preset_config('XKCD');
This function returns the config hashref for a given preset. See above for the list of available presets.
The first argument this function accpets is the name of the desired preset as a scalar. If an invalid name is passed, the function will carp. If no preset is passed the preset DEFAULT
is assumed.
This function can optionally accept a second argument, a hashref containing keys with values to override the defaults with.
my $config = XKPasswd->preset_config('XKCD', {case_transform => 'INVERT'});
When overrides are present, the function will carp if an invalid key or value is passed, and croak if the resulting merged config is invalid.
my $description = XKPasswd->preset_description('XKCD');
This function returns the description for a given preset. See above for the list of available presets.
The first argument this function accpets is the name of the desired preset as a scalar. If an invalid name is passed, the function will carp. If no preset is passed the preset DEFAULT
is assumed.
print XKPasswd->presets_to_string();
This function returns a string containing a description of each defined preset and the configs associated with the presets.
NOTE - all methods must be invoked on an XKPasswd object or they will croak.
my $config = $xkpasswd_instance->config(); # getter
$xkpasswd_instance->config($config); # setter
When called with no arguments the function returns a clone of the instance's config hashref.
When called with a single argument the function sets the config of the instance to a clone of the passed hashref. If present, the argument must be a hashref, and must contain valid config keys and values. The function will croak if an invalid config is passed.
my $config_string = $xkpasswd_instance->config_string();
This function returns the content of the passed config hashref as a scalar string. The function must be passed a valid config hashref or it will croak.
print $xkpasswd_instance->dictionary();
$xkpasswd_instance->dictionary('sample_dict.txt');
When called with no arguments this function returns the path to the currently loaded dictionary file. To load a dictionary file into an instance call this function with the path to the dictionary file.
my $password = $xkpasswd_instance->password();
This function generates a random password based on the instance's loaded config and returns it as a scalar. The function takes no arguments.
The function croaks if there is an error generating the password. The most likely cause of and error is the random number generation, particularly if the loaded random generation function relies on a cloud service or a non-standard library.
my @passwords = $xkpasswd_instance->passwords(10);
This function generates a number of passwords and returns them all as an array.
The function uses password()
to genereate the passwords, and hence will croak if there is an error generating any of the requested passwords.
my %stats = $xkpasswd_instance->stats();
This function generates a hash containing stats about the instance indexed by the following keys:
dictionary_filter_length_min
& dictionary_filter_length_max
- the minimum and maximum word lengths allowed by the dictionary filter (defined by config keys word_length_min
and word_length_max
)
dictionary_path
- the path to the dictionary file loaded into the instance.
dictionary_words_filtered
- the number of words loaded from the dictionary file that meet the criteria defined by the loaded config.
dictionary_words_percent_avaialable
- the percentage of the words in the dictionary file that are available for use with the loaded config.
dictionary_words_total
- the total number of words loaded from the dictionary file.
password_entropy_blind_min
- the entropy (in bits) of the shortest password the loaded config can generate from the point of view of a brute-force attacker.
password_entropy_blind_max
- the entropy (in bits) of the longest password the loaded config can generate from the point of view of a brute-force attacker.
password_entropy_blind
- the entropy (in bits) of the average length of passwords the loaded config can generate from the point of view of a brute-force attacker.
password_entropy_seen
- the entropy (in bits) of passwords generated by the instance assuming the dictionary and config are known to the attacker.
password_length_min
- the minimum length of passwords generated by the loaded config.
password_length_max
- the maximum length of passwords generated by the loaded config.
password_permutations_blind_min
- the number of permutations a brute-force attacker would have to try to be sure of cracking the shortest possible passwords generated by this instance. Because this number can be very big, it's returned as a Math::BigInt
object.
password_permutations_blind_max
- the number of permutations a brute-force attacker would have to try to be sure of cracking the longest possible passwords generated by this instance. Because this number can be very big, it's returned as a Math::BigInt
object.
password_permutations_blind
- the number of permutations a brute-force attacker would have to try to be sure of cracking an average length password generated by this instance. Because this number can be very big, it's returned as a Math::BigInt
object.
password_permutations_seen
- the number of permutations an attacker with a copy of the dictionary and config would need to try to be sure of cracking a password generated by this instance. Because this number can be very big, it's returned as a Math::BigInt
object.
passwords_generated
- the number of passwords this instance has generated.
password_random_numbers_required
- the number of random numbers needed to generate a single password using the loaded config.
randomnumbers_cached
- the number of random numbers currently cached within the instance.
randomnumbers_cache_increment
- the number of random numbers generated at once to replenish the cache when it's empty.
randomnumbers_generator_function
- the function used by the instance to generate random numbers.
print $xkpasswd_instance->status();
Generates a string detailing the internal status of the instance. Below is a sample status string:
*DICTIONARY*
File path: /usr/share/dict/words
# words: 234252
# words of valid length: 87066
*CONFIG*
case_transform: 'CAPITALISE'
character_substitutions: {}
num_words: '4'
padding_digits_after: '0'
padding_digits_before: '0'
padding_type: 'NONE'
random_function: XKPasswd::basic_random_generator
random_increment: '4'
separator_character: '-'
word_length_max: '8'
word_length_min: '4'
*RANDOM NUMBER CACHE*
# in cache: 0
*PASSWORD STATISTICS*
Password length: between 19 & 35
Brute-Force permutations: between 2.29x10^33 & 2.85x10^61 (average 2.56x10^47)
Permutations (given dictionary & config): 5.74x10^19
Brute-Force Entropy (in bits): between 110 and 204 (average 157)
Entropy (given dictionary & config): 65bits
Passwords Generated: 0
$xkpasswd_instance->update_config({separator_character => '+'});
The function updates the config within an XKPasswd instance. A hashref with the config options to be changed must be passed. The function returns a reference to the instance to enable function chaining. The function will croak if the updated config would be invalid in some way. Note that if this happens the running config will not have been altered in any way.
By default this module does all of it's error notification via the functions carp()
, croak()
, and confess()
from the Carp
module. Optionally, all error messages can also be printed. To enable the printing of messages, set $XKPasswd::LOG_ERRORS
to a truthy value. All error messages will then be printed to the stream at $XKPasswd::LOG_STREAM
, which is set to STDERR
by default.
Ordinarily this module produces very little output, to enable more verbose output $XKPasswd::DEBUG
can be set to a truthy value. If this is set, all debug messages will be printed to the stream $XKPasswd::LOG_STREAM
.
This module produces output at three severity levels:
DEBUG
- this output is completely suppressed unless $XKPasswd::DEBUG
is set to a truthy value. If not suppressed debug messages are always printed to $XKPasswd::LOG_STREAM
(regardless of the value of $XKPasswd::LOG_ERRORS
).
WARNING
- warning messages are always thrown with carp()
, and also printed to $XKPasswd::LOG_STREAM
if $XKPasswd::LOG_ERRORS
evaluates to true.
ERROR
- error messages are usually thrown with croak()
, but will be thrown with confess()
if $XKPasswd::DEBUG
evaluates to true. If $XKPasswd::LOG_ERRORS
evaluates to true errors are also printed to $XKPasswd::LOG_STREAM
, including a stack trace if $XKPasswd::DEBUG
evaluates to true and the module Devel::StackTrace
is installed.
This module does not currently support configuration files, nor does it currently interact with the environment. It may do so in future versions.
This module uses the following standard Perl modules:
warnings
- http://search.cpan.org/perldoc?warnings =item *
English
- http://search.cpan.org/perldoc?English
Math::Round
- http://search.cpan.org/perldoc?Math%3A%3ARound
Math::BigInt
- http://search.cpan.org/perldoc?Math%3A%3ABigInt
The module can also optionally use the following non-standard Perl modules:
Devel::StackTrace
- http://search.cpan.org/perldoc?Devel%3A%3AStackTrace
Used for printing stack traces with error messages if $XKPasswd::DEBUG
and $XKPasswd::LOG_ERRORS
both evaluate to true. If the module is not installed the stack traces will be omitted from the log messages.
This module has no known incompatibilities.
There are no known bugs in this module.
Please report problems to Bart Busschots (mailto:bart@bartificer.net) Patches are welcome.
Copyright (c) 2014, Bart Busschots T/A Bartificer Web Solutions All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Bart Busschots (mailto:bart@bartificer.net)