|
NAME"Crypt::HSXKPasswd" - A secure memorable password generator inspired by Steve Gibson's Passord Haystacks (<https://www.grc.com/haystack.htm>), and the famous XKCD password cartoon (<https://xkcd.com/936/>).VERSIONThis documentation refers to "Crypt::HSXKPasswd" version 3.6.SYNOPSISuse Crypt::HSXKPasswd; # # Functional Interface - a shortcut for generating single passwords # # generate a single password using the default word source, configuration, # and random number generator my $password = hsxkpasswd(); # the above call is simply a shortcut for the following my $password = Crypt::HSXKPasswd->new()->password(); # this function passes all arguments on to Crypt::HSXKPasswd->new() # so all the same customisations can be specified, e.g. specifying a # config preset: my $password = hsxkpasswd(preset => 'XKCD'); # # Object Oriented Interface - recommended for generating multiple passwords # # create a new instance with the default dictionary, config, and random # number generator my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(); # generate a single password my $password = $hsxkpasswd_instance->password(); # generate multiple passwords my @passwords = $hsxkpasswd_instance->passwords(10); DESCRIPTIONA 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 module that powers <https://www.xkpasswd.net>.PHILOSOPHYMore 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 symbols and digits to add security without making the passwords difficult to remember, read, type, and 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 PASSWORD GENERATION ALGORITHMThis module always uses a simple five-step algorithm to generate passwords, but each step can be customised, and many steps can be skipped completely.It's important to understand the algorithm before trying to create your own custom configurations for this module. The algorithm is broken in to the following steps:
You can visualise this process as follows: correct horse batter staple correct HORSE battery staple 25 correct HORSE battery staple 83 25*correct*HORSE*battery*staple*83 ++25*correct*HORSE*battery*staple*83++ Each of these steps can be customised in the following ways:
THE MATHSBefore examining the password strength of passwords generated with this module we need to lay out the relatively simple maths underlying it all.Maths Primer 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. The Entropy of HSXKPasswd Passwords 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 convert 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 HSXKPasswd object, and throws a warning if either the blind entropy falls below 78bits, or the seen entropy falls below 52 bits. SUBROUTINES/METHODSMODULE CONFIGURATIONIt is possible to tweak the module's behaviour in certain areas by updating the values contained within a set of module configuration keys. The values associated with these keys can be accessed and updated via the class function "module_config()".# get the current debug status my $debug_status = Crypt::HSXKPasswd->module_config('DEBUG'); # configure the module to suppress all entropy warnings Crypt::HSXKPasswd->module_config('ENTROPY_WARNINGS', 'NONE'); The following module configuration keys exist within the module:
CUSTOM DATA TYPESThis module uses a custom type library created with "Type::Library" for data validation. It is important to know this for two reasons - firstly, these custom types are mentioned in many error messages, and secondly these custom types are available for developers to use in their own code, either when utilising "Crypt::HSXKPasswd", or writing custom word sources by extending "Crypt::HSXKPasswd::Dictionary", or when writing custom random number generators by extending "Crypt::HSXKPasswd::RNG".Defined Types
Using the Custom Types The library of custom types is defined in the package "Crypt::HSXKPasswd::Types", and it is a standard "Type::Library" type library containing "Type::Tiny" type definitions. Useful Links:
To use the bare type definitions listed above, import the module as follows: use Crypt::HSXKPasswd::Types qw( :types ); Each type listed above will now be imported, and become available as a bare word. The "Type::Tiny" documentation provides a full list of available functions, but the examples below illustrate some of the more useful ones: $is_valid = Letter->check('e'); # $is_valid = 1 $is_valid = Letter->check('-'); # $is_valid = undef $err_msg = Letter->validate('e'); # $err_msg = undef $err_msg = Letter->validate('-'); # $err_msg = "'-' is not a Letter ... # ... (must be a string containing exactly one letter)" "Type::Library" automatically creates an "is_TypeName" function for each type defined in the library. These are not imported by default. To import them add the export tag ":is" to the "use" line. I would recommend the following "use" line: use Crypt::HSXKPasswd::Types qw( :types :is ); You can now do things like the following: $is_valid = is_Letter('e'); # $is_valid = 1 $is_valid = is_Letter('-'); # $is_valid = undef Each of the types listed above also contains a custom function using "Type::Tiny"'s new, and still officially experimental, "my_methods" feature. The custom function is called "my_english", and can be used to return an English description of the values considered valid by the type, e.g.: print Letter->my_english(); # prints: a string containing exactly one letter As well as the named types listed above, there are also anonymous types defined for each supported configuration key. These can be accessed using the function "Crypt::HSXKPasswd-"config_key_definitions()>. If declaring your own "Type::Tiny" types, you may also find the public subroutine "Crypt::HSXKPasswd::Types::var_to_string()" useful - it will turn anything passed as a scalar into a meaningful string, truncating any resulting strings longer than 72 characters in nice way. All the custom error messages in all the types defined in "Crypt::HSXKPasswd::Types" make use of this subroutine. CONFIGURATIONThe module builds passwords using the following process.First, a set of words are randomly chosen from the word source. Then, two pseudo-words made of one or more digits may added before and/or after the words from. Next, a separator character may be placed between all the words (including the groups of digits), and one or more occurrences of a padding symbol may be added front and/or back. You can envisage the process as follows: correct HORSE BATTERY staple 34 correct HORSE BATTERY staple 56 34-correct-HORSE-BATTERY-staple-56 !!34-correct-HORSE-BATTERY-staple-56!! Many aspects of this password generation process are configurable. You can control the length and number of words chosen, and what, if any, case transformations should be applied to those words, and how accented characters should be treated. How many, if any, digits should be added front and back. What symbol, if any, should be used as a separator. And finally how the password should be padded, if at all, and with what symbol. Passwords can be padded to a given length, or by a given number of symbols front and back. The symbols used as the separator and for padding can be explicitly specified, or the they can be randomly chosen from a given alphabet of possible symbols. Both symbols can be randomly chosen from the same alphabet, or from two separately specified alphabets. Every instance of an HSXKPasswd password generator stores its configuration as a set of name-value pairs, referred to as configuration keys throughout this documentation. Configurations can be specified either as a complete set of configuration keys with values that together form a valid configuration, as a named preset, or, as a named preset accompanied by a list of one or more configuration keys with new values to override those specified by the preset. The module contains a preset called "DEFAULT", and this preset is used if no configuration is specified. The function "default_config()" will return a copy of this configuration as a reference to a hashtable. For more details on how to specify configurations, see the documentation for the constructor (the function "new()") below. Password Generator Configuration Keys Below is a list of all the configuration keys that can be used to customise the password generation algorithm. Each configuration key is accompanied by a description of what aspect of the algorithm they control, and any validation rules that apply to the key. Note that some keys are always required, and that there are dependencies between keys. For examples, if you specify that the separator symbol should be chosen at random, you must also specify an alphabet from which the symbol should be randomly chosen.
The function "default_config()" returns a value of "CAPITALISE" for this key.
The function "default_config" return the value "RANDOM" for this key.
The function "default_config()" returns a value of "FIXED" for this key.
The function "default_config()" returns a value of "RANDOM" for this key.
PRESETSBelow is a list of all the presets defined by this module.This information can be accessed programatically using the functions "defined_presets()", "presets_to_string()", "preset_description()", and "preset_config()".
FUNCTIONAL INTERFACEAlthough 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: hsxkpasswd() my $password = hsxkpasswd(); This function call is equivalent to the following Object-Oriented code: my $password = Crypt::HSXKPasswd->new()->password(); This function passes all arguments it receives 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 will be re-loaded, and the entropy stats re-calculated each time the function is called. CONSTRUCTOR# create a new instance with the default dictionary, config, and random # number generator my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(); # the constructor takes optional named arguments, these can be used to # customise the word source, config, and random number source. # create an instance that uses the UNIX words file as the word source my $hsxkpasswd_instance = Crypt::HSXKPasswd->new( dictionary => Crypt::HSXKPasswd::Dictionary::System->new() ); # create an instance that uses an array reference as the word source my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(dictionary_list => $array_ref); # create an instance that uses a dictionary file as the word source my $hsxkpasswd_instance = Crypt::HSXKPasswd->new( dictionary_file => 'sample_dict_EN.txt' ); # the class Crypt::HSXKPasswd::Dictionary::Basic can be used to aggregate # multiple array refs and/or dictionary files into a single word source my $dictionary = Crypt::HSXKPasswd::Dictionary::Basic->new(); $dictionary->add_words('dict1.txt'); $dictionary->add_words('dict2.txt'); $dictionary->add_words($array_ref); my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(dictionary => $dictionary); # create an instance from the preset 'XKCD' my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(preset => 'XKCD'); # create an instance based on the preset 'XKCD' with one customisation my $hsxkpasswd_instance = Crypt::HSXKPasswd->new( preset => 'XKCD', preset_override => {separator_character => q{ }} ); # create an instance from a config based on a preset # but with many alterations my $config = Crypt::HSXKPasswd->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 $hsxkpasswd_instance = Crypt::HSXKPasswd->new(config => $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', } my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(config => $config); # create an instance from an entire custom config passed as a JSON string # a convenient way to use configs generated using the web interface at # https://xkpasswd.net my $config = <<'END_CONF'; { "num_words": 4, "word_length_min": 4, "word_length_max": 8, "case_transform": "RANDOM", "separator_character": " ", "padding_digits_before": 0, "padding_digits_after": 0, "padding_type": "NONE", } END_CONF my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(config_json => $config); # create an instance which uses /dev/urandom as the RNG # (only possible on Linux/Unix only systems) my $hsxkpasswd_instance = Crypt::HSXKPasswd->new( rng => Crypt::HSXKPasswd::RNG::DevUrandom->new(); ); # create an instance which uses Random.Org as the random number generator # NOTE - this should be used sparingly, and only by the paranoid. If you # abuse this RNG your IP will get blacklisted on Random.Org. You must pass # a valid email address to the constructor for # Crypt::HSXKPasswd::RNG::RandomDorOrg because Random.Org's usage # guidelines request that all invocations to their API contain a contact # email in the useragent header, and this module honours that request. my $hsxkpasswd_instance = Crypt::HSXKPasswd->new( rng => Crypt::HSXKPasswd::RNG::RandomDorOrg->new('your.email@addre.ss'); ); The constructor must be called via the package name. If called with no arguments the constructor will use an instance of "Crypt::HSXKPasswd::Dictionary::EN" as the word source, the preset "DEFAULT", and an instance of the class "Crypt::HSXKPasswd::RNG::Basic" to generate random numbers. The function accepts named arguments to allow for custom specification of the word source, config, and random number source. Specifying Custom Word Sources Three named arguments can be used to specify a word source, but only one should be specified at a time. If multiple are specified, the one with the highest priority will be used, and the rest ignored. The variables are listed below in descending order of priority:
Specifying Custom Password Generator Configurations Two primary named arguments can be used to specify the config the instance should use to generate passwords. Only one should be specified at a time. If multiple are specified, the one with the highest priority will be used, and the rest ignored. The variables are listed below in descending order of priority:
Specifying Custom Random Number Generators A custom RNG can be specified using the named argument "rng". The passed value must be an instance of a class that extends "Crypt::HSXKPasswd::RNG" and overrides the function "random_numbers()". INSTANCE METHODSNOTE - all instance methods must be invoked on a Crypt::HSXKPasswd object or they will croak.->config() my $config = $hsxkpasswd_instance->config(); # getter $hsxkpasswd_instance->config($config_hashref); # setter $hsxkpasswd_instance->config($config_json_string); # 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 config. If present, the argument must be either a hashref containing valid config keys and values, or a JSON string representing a hashref containing valid config keys and values. The function will croak if an invalid config is passed. ->config_as_json() my $config_json_string = $hsxkpasswd_instance->config_as_json(); This function returns the content of the instance's loaded config hashref as a JSON string. The output from this function can be loaded into the web interface at <https://xkpasswd.net> (using the load/save tab). ->config_as_string() my $config_string = $hsxkpasswd_instance->config_as_string(); This function returns the content of the instance's loaded config hashref as a scalar string. ->dictionary() my $dictionary_clone = $hsxkpasswd_instance->dictionary(); $hsxkpasswd_instance->dictionary($dictionary_instance); $hsxkpasswd_instance->dictionary($array_ref); $hsxkpasswd_instance->dictionary('sample_dict_EN.txt'); $hsxkpasswd_instance->dictionary('sample_dict_EN.txt', 'Latin1'); When called with no arguments this function returns a clone of the currently loaded dictionary which will be an instance of a class that extends "Crypt::HSXKPasswd::Dictionary". To load a new dictionary into an instance, call this function with arguments. The first argument argument can be an instance of a class that extends "Crypt::HSXKPasswd::Dictionary", a reference to an array of words, or the path to a dictionary file. If either an array reference or a file path are passed, they will be used to instantiate an instance of the class "Crypt::HSXKPasswd::Dictionary::Basic", and that new instance will then be loaded into the object. If a file path is passed, it will be assumed to be UTF-8 encoded. If not, an optional second argument can be passed to specify the file's encoding. ->password() my $password = $hsxkpasswd_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. ->passwords() my @passwords = $hsxkpasswd_instance->passwords(10); This function generates a number of passwords and returns them all as an array. The function uses "password()" to generate the passwords, and hence will croak if there is an error generating any of the requested passwords. ->passwords_json() my $json_string = $hsxkpasswd_instance->passwords_json(10); This function generates a number of passwords and returns them and the instance's entropy stats as a JSON string representing a hashref containing an array of passwords indexed by "passwords", and a hashref of entropy stats indexed by "stats". The stats hashref itself is indexed by: "password_entropy_blind", "password_permutations_blind", "password_entropy_blind_min", "password_entropy_blind_max", "password_permutations_blind_max", "password_entropy_seen" & "password_permutations_seen". The function uses "passwords()" to generate the passwords, and hence will croak if there is an error generating any of the requested passwords. ->rng() my $rng_instance = $hsxkpasswd_instance->rng(); $hsxkpasswd_instance->rng($rng_instance); When called with no arguments this function returns currently loaded Random Number Generator (RNG) which will be an instance of a class that extends "Crypt::HSXKPasswd::RNG". To load a new RNG into an instance, call this function with a single argument, an instance of a class that extends "Crypt::HSXKPasswd::RNG". ->stats() my %stats = $hsxkpasswd_instance->stats(); This function generates a hash containing stats about the instance indexed by the following keys:
->status() print $hsxkpasswd_instance->status(); Generates a string detailing the internal status of the instance. Below is a sample status string: *DICTIONARY* Source: Crypt::HSXKPasswd::Dictionary::EN # words: 1425 # words of valid length: 1194 (84%) *CONFIG* case_transform: 'ALTERNATE' num_words: '3' padding_character: 'RANDOM' padding_characters_after: '2' padding_characters_before: '2' padding_digits_after: '2' padding_digits_before: '2' padding_type: 'FIXED' separator_alphabet: ['!', '$', '%', '&', '*', '+', '-', '.', '/', ':', ';', '=', '?', '@', '^', '_', '|', '~'] separator_character: 'RANDOM' symbol_alphabet: ['!', '$', '%', '&', '*', '+', '-', '.', '/', ':', ';', '=', '?', '@', '^', '_', '|', '~'] word_length_max: '8' word_length_min: '4' *RANDOM NUMBER CACHE* Random Number Generator: Crypt::HSXKPasswd::RNG::Basic # in cache: 0 *PASSWORD STATISTICS* Password length: between 24 & 36 Permutations (brute-force): between 2.91x10^47 & 1.57x10^71 (average 2.14x10^59) Permutations (given dictionary & config): 5.51x10^15 Entropy (Brute-Force): between 157bits and 236bits (average 197bits) Entropy (given dictionary & config): 52bits # Random Numbers needed per-password: 9 Passwords Generated: 0 ->update_config() $hsxkpasswd_instance->update_config({separator_character => '+'}); The function updates the config within an HSXKPasswd 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. CLASS METHODSNOTE - All class methods must be invoked via the package name, or they will croak.clone_config() my $clone = Crypt::HSXKPasswd->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. config_key_definition() my %key_definition = Crypt::HSXKPasswd->config_key_definition($key_name); A function to return the definition for a config key. The definition is returned as a hash indexed by the following keys:
config_key_definitions() my %key_definitions = Crypt::HSXKPasswd->config_key_definitions(); A function to return definitions for all defined config keys as a hash indexed by config key names. Each definition is represented as a hash with the same keys as the hashes returned by the function "config_key_definition()". config_stats() my %stats = Crypt::HSXKPasswd->config_stats($config); my %stats = Crypt::HSXKPasswd->config_stats( $config, suppress_warnings => 1, ); 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:
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. Such warnings can be suppressed by passing an optional named argument "suppress_warnings" with the value 1. config_to_json() my $config_json_string = Crypt::HSXKPasswd->config_to_json($config); This function returns a JSON representation of the passed config hashref as a scalar string. The function must be passed a valid config hashref or it will croak. config_to_string() my $config_string = Crypt::HSXKPasswd->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. default_config() my $config = Crypt::HSXKPasswd->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 = Crypt::HSXKPasswd->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 = Crypt::HSXKPasswd->preset_config('DEFAULT'); my $config = Crypt::HSXKPasswd->preset_config('DEFAULT', {num_words => 3}); defined_config_keys() my @config_key_names = Crypt::HSXKPasswd->defined_config_keys(); This function returns the list of valid config key names as an array of strings. defined_presets() my @preset_names = Crypt::HSXKPasswd->defined_presets(); This function returns the list of defined preset names as an array of strings. distil_to_config_keys() my $dist_hashref = Crypt::HSXKPasswd->distil_to_config_keys($hashref); This function takes a hashref as an argument, and returns a deep clone of that hashref containing only valid config keys with valid values. By default the function silently drops keys that are not valid config keys, but issues a warning when dropping a key that is a valid config key, but contains an invalid value. The function can also issue warnings when dropping keys that are not valid config keys. The warnings can be controlled with a pair of optional named arguments that can be added as a second argument: # suppress all warnings my $dist_hashref = Crypt::HSXKPasswd->distil_to_config_keys( $hashref, suppress_warnings => 1, ); # emit warnings when dropping invalidly named keys my $dist_hashref = Crypt::HSXKPasswd->distil_to_config_keys( $hashref, warn_invalid_key_names => 1, ); distil_to_symbol_alphabet() my @unique_syms = Crypt::HSXKPasswd->distil_to_symbol_alphabet($arrayref); my @unique_syms = Crypt::HSXKPasswd->distil_to_symbol_alphabet( $arrayref, warn => 1, ); This function takes reference to an array of strings and returns a new array containing all the valid symbols from the referenced array. The valid symbols are de-duplicated before being returned. By default the function silently skips over strings that are not valid symbols. The function can be made issue warnings each time a string is skipped by passing a named argument "warn" with a value of 1 (0 can also be passed to explicitly disable warnings). distil_to_words() my @valid_unique_words = Crypt::HSXKPasswd->distil_to_words($arrayref); my @valid_unique_words = Crypt::HSXKPasswd->distil_to_words( $arrayref, warn => 1, ); This function takes reference to an array of strings and returns a new array containing all the valid words from the referenced array. The valid words are de-duplicated before being returned. By default the function silently skips over strings that are not valid words. The function can be made issue warnings each time a string is skipped by passing a named argument "warn" with a value of 1 (0 can also be passed to explicitly disable warnings). is_valid_config() # determine the validity my $is_ok = Crypt::HSXKPasswd->is_valid_config($config); # assert the validity - will croak if the config is invalid Crypt::HSXKPasswd->is_valid_config($config, croak => 1); This function must be passed a hashref to test as the first argument. The function returns 1 if the passed config is valid, and 0 otherwise. Optionally, a named argument "croak" can also be passed to control whether or not the function should croak if the config is invalid. The value of this named argument should be 1 or 0. When calling the function with "croak" set to 1, the message thrown by croak will explain why the config is invalid. use English qw( -no_match_vars ); eval{ Crypt::HSXKPasswd->is_valid_config($config, croak => 1); }or do{ print "ERROR - config is invalid because: $EVAL_ERROR\n"; } module_config() my $debug_val = Crypt::HSXKPasswd->module_config('DEBUG'); # getter Crypt::HSXKPasswd->module_config('DEBUG', 1); # setter This function is used to access or alter the value of one of the module configuration settings. The first function must always be a valid module configuration key name. If no second argument is provided, the value stored in the module configuration key will not be updated. To update the stored value, pass a new value as a second argument. Regardless of whether or not a second argument is passed, the value stored in the module configuration key is always returned. The function will croak if called with an invalid module configuration key name, or passed an invalid new value. For a list of the module configuration keys, see the MODULE CONFIGURATION section of this document. preset_config() my $config = Crypt::HSXKPasswd->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 accepts 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 = Crypt::HSXKPasswd->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. preset_definition() my %preset_def = Crypt::HSXKPasswd->preset_definition('XKCD'); This function returns a hash defining a preset. The hash contains an English description of the preset indexed be "description" and a config hashref indexed by "config". The function expects to be called with one argument, a valid preset name, but it can be called without arguments, in which case it will return the definition for the preset c<DEFAULT>. You can see all the defined presets in the PRESETS section of this document, and you can get a list of valid preset names programatically with the function "defined_presets()". preset_definitions() my %preset_defs = Crypt::HSXKPasswd->preset_definitions(); This function returns a hash of all defined presets indexed by preset name. Each preset definition is a hash as returned by "preset_definition()". This function does not take any arguments. presets_json() my $json_string = Crypt::HSXKPasswd->presets_json(); This function returns a JSON string representing all the defined configs, including their descriptions. The returned JSON string represents a hashref indexed by three keys: "defined_keys" contains an array of preset identifiers, "presets" contains the preset configs indexed by reset identifier, and "preset_descriptions" contains a hashref of descriptions indexed by preset identifiers. preset_description() my $description = Crypt::HSXKPasswd->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 accepts 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. presets_to_string() print Crypt::HSXKPasswd->presets_to_string(); This function returns a string containing a description of each defined preset and the configs associated with the presets. COMMANDLINE INTERFACEThe module ships with a commandline interface to this library, simply called "hsxkpasswd".This interface allows for the generation of multiple passwords at a time, the use of presets and preset overrides, the use of custom password generator configurations, the use of custom word sources, and the use of custom random number generators. Both preset overrides and password generator configurations must be specified in JSON format. Examples Generate a single password using all the default settings: hsxkpasswd Generate five passwords using the default settings: hsxkpasswd 5 Generate five passwords using the "XKCD" preset: hsxkpasswd -p XKCD 5 Generate five passwords using the "XKCD" preset with an overridden password generator configuration key: hsxkpasswd -p XKCD -o '{"separator_character" : "*"}' 5 Generate five passwords using a custom password generator configuration stored in a text file in JSON format: hsxkpasswd -c my_config.json Further Reading The examples above are just a sample of what the command can do, for complete documentation, run the command with the -h flag: hsxkpasswd -h If you are new to JSON, you may find the following links useful:
ENTROPY CHECKINGFor security reasons, this module's default behaviour is to warn (using "carp()") when ever the loaded combination of word source and configuration would result in low-entropy passwords. When the constructor is invoked, or when an instance's the word source or config are altered (using "dictionary()" or "config()"), the entropy is re-calculated and re-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 a brute-force attack. 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 word source and config settings used to generate the password. Entropy checking is controlled via three module configuration variables (which can be accessed and updated using the function "module_config()"):
Caveats 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. WORD SOURCES (DICTIONARIES)The abstract class "Crypt::HSXKPasswd::Dictionary" acts as a base class for sources of words for use by this module. Word sources should extend this base class and implement the function "word_list()", which should return an array of words.In order to produce secure passwords it's important to use a word source that contains a large selection of words with a good mix of different lengths of words. The module ships with a number of pre-defined word sources: "Crypt::HSXKPasswd::Dictionary::DE" A German word list based on the GPL-licensed German dictionary for WinEdit by Juergen Vierheilig. Note: This module is licensed under the GPL, not the BSD license used for the majority of this project. "Crypt::HSXKPasswd::Dictionary::EN" A default word list consisting of English words and place names. "Crypt::HSXKPasswd::Dictionary::ES" A Spanish word list based on the BSD-licensed Spanish dictionary for WinEdit by Juan L. Varona from the Universidad de La Rioja. "Crypt::HSXKPasswd::Dictionary::FR" A French word list based on the GPL-licensed French dictionary for WinEdit. Note: This module is licensed under GPL V2, not the BSD license used for the majority of this project. "Crypt::HSXKPasswd::Dictionary::IT" An Italian word list based on the free-for-non-commerical-use Italian dictionary for WinEdit by Karl Koeller. Note: This module is licensed under GPL V2, not the BSD license used for the majority of this project. "Crypt::HSXKPasswd::Dictionary::NL" A Dutch/Flemish word list based on the GPL-licensed Dutch dictionary for WinEdit. Note: This module is licensed under GPL V2, not the BSD license used for the majority of this project. "Crypt::HSXKPasswd::Dictionary::PT" A Portuguese word list based on the GPL-licensed Portuguese dictionary for WinEdit compiled by Bernhard Enders (building on work by Raimundo Santos Moura & Ricardo Ueda Karpischek). Note: This module is licensed under GPL V2.1, not the BSD license used for the majority of this project. "Crypt::HSXKPasswd::Dictionary::System" This class tries to find and use a Unix words file on the system. The constructor croaks if no system words file can be found. Usage my $word_source = Crypt::HSXKPasswd::Dictionary::System->new(); "Crypt::HSXKPasswd::Dictionary::Basic" This class can be initialised from a words file, or from an array ref containing words. Usage my $word_source = Crypt::HSXKPasswd::Dictionary::Basic->new('file_path'); my $word_source = Crypt::HSXKPasswd::Dictionary::Basic->new( 'file_path', 'Latin1' ); my $word_source = Crypt::HSXKPasswd::Dictionary::Basic->new($array_ref); 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. Files are assumed to be UTF-8 encoded, but an optional second argument can be passed specifying a different file encoding. 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). RANDOM NUMBER SOURCESIn order to minimise the number of non-standard modules this module requires, 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 random numbers. To facilitate both of these options, this module uses a cache of randomness, and provides an abstract Random Number Generator (RNG) class that can be extended.The module can use an instance of any class that extends "Crypt::HSXKPasswd::RNG" as it's source of randomness. Custom RNG classes must implement the method "random_numbers()" which will be invoked on an instance of the class and passed one argument, the number of random numbers required to generate a single password. The function must return an array of random numbers between 0 and 1. The number of random numbers returned is entirely up to the module to decide. The number required for a single password is passed purely as a guide. The function must always return at least one random number. The module ships with five standard RNGs (described below). By default, the module will try to use one of the following four RNGs, listed from most to least preferred, depending on what is available on the system:
If the constructor is called without specifying an RNG, and if the only available RNG is "Crypt::HSXKPasswd::RNG::Basic", a warning will be thrown suggesting installing "Math::Random::Secure" or "Data::Entropy::Algorithms". The module also ships with a fifth RNG, "Crypt::HSXKPasswd::RNG::RandomDotOrg", but this one must be explicitly used, the constructor will never used it by default. As its name suggests, this class uses <http://Random.Org/>'s HTTP API to generate random numbers. To explicitly use any particular RNG, create an instance of it, and either pass that instance to the constructor with the named argument "rng", or, set the RNG after instantiating the object using the "rng()" function. Crypt::HSXKPasswd::RNG::Math_Random_Secure my $rng = Crypt::HSXKPasswd::RNG::Math_Random_Secure->new(); This is the preferred RNG because it is both fast and secure, but, it requires the non-standard module "Math::Random::Secure" (<http://search.cpan.org/perldoc?Math%3A%3ARandom%3A%3ASecure>) be installed. Crypt::HSXKPasswd::RNG::Data_Entropy my $rng = Crypt::HSXKPasswd::RNG::Data_Entropy->new(); This RNG is secure, but it is quite slow (about six times slower than "Crypt::HSXKPasswd::RNG::Math_Random_Secure"), and it requires the non-standard module "Data::Entropy::Algorithms" (<http://search.cpan.org/perldoc?Data%3A%3AEntropy%3A%3AAlgorithms>) be installed. Crypt::HSXKPasswd::RNG::DevUrandom my $rng = Crypt::HSXKPasswd::RNG::DevUrandom->new(); This RNG is secure and relatively fast (faster than "Crypt::HSXKPasswd::RNG::Data_Entropy" but slower than "Crypt::HSXKPasswd::RNG::Math_Random_Secure"), but is only available on Linux/Unix systems with a "/dev/urandom" special file. Crypt::HSXKPasswd::RNG::Basic my $rng = Crypt::HSXKPasswd::RNG::Basic->new(); This RNG uses Perl's built-in "rand()" function as its source of randomness, and this is sub-optimal. The Perl docs warn that "rand()" is not a particularly good source of random numbers, and advises against its use for cryptography. This RNG provides a base-line, and should only be used if none of the better RNGs are available. While it is sub-optimal, it will still generate passwords with sufficient entropy in most situations. Ultimately, even using this imperfect RNG, this module will still produce passwords that are much better than those produced by the human imagination! Crypt::HSXKPasswd::RNG::RandomDotOrg my $rng = Crypt::HSXKPasswd::RNG::RandomDotOrg->new('my.address@my.dom'); my $rng = Crypt::HSXKPasswd::RNG::RandomDotOrg->new('my.address@my.dom', timeout => 180, num_passwords => 3, ); This RNG serves as a usable example of an RNG that queries a web service. As its name suggests, this class uses <http://Random.Org/>'s HTTP API to generate random numbers. In order to comply with Random.Org's client guidelines (<https://www.random.org/clients/>), this module requires that a valid email address be passed as the first argument. The client guidelines also request that clients use long timeouts, and batch their requests. They prefer to be asked for more number less frequently than less numbers more frequently. For this reason the class's default behaviour is to use a timeout of 180 seconds, and to request enough random numbers to generate three passwords at a time. These defaults can be overridden by passing named arguments to the constructor after the email address. The following named arguments are supported:
"num_passwords" and "num_absolute" should not be used together, but if they are, "num_absolute" use used, and "num_passwords" is ignored. This class requires a number of modules not used by any other classes under "Crypt::HSXKPasswd", and not listed in that module's requirements. If all of the following modules are not installed, the constructor will croak:
DIAGNOSTICSBy 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 a stream. To enable the printing of messages, set the "LOG_ERRORS" module configuration variable to 1. All error messages will then be printed to the stream defined by the module configuration variable "LOG_STREAM", which is set to "STDERR" by default.Ordinarily this module produces very little output. To enable more verbose output the module configuration variable "DEBUG" can be set to 1. Debug message are printed to the stream specified by the module variable "LOG_STREAM". This module produces output at three severity levels:
The value stored in a module configuration variable can be accessed and updated using the function "module_config()". CONFIGURATION AND ENVIRONMENTThis module does not currently support configuration files, nor does it currently interact with the environment. It may do so in future versions.DEPENDENCIESThis module requires the following Perl modules:
The module can also optionally use the following Perl modules:
INCOMPATIBILITIESThis module has no known incompatibilities.BUGS AND LIMITATIONSThere are no known bugs in this module.Please report any bugs you may find on the module's GitHub page: <https://github.com/bbusschots/xkpasswd.pm>. LICENCE AND COPYRIGHTCopyright (c) 2014-15, 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:
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. The following components of this package are covered by the more restrictive GPL V2 license <https://www.gnu.org/licenses/gpl-2.0.html>:
AUTHORBart Busschots (<mailto:bart@bartificer.net>)
Visit the GSP FreeBSD Man Page Interface. |