1package Crypt::HSXKPasswd;
2
3# import required modules
4use strict;
5use warnings;
6use Carp; # for nicer 'exception' handling for users of the module
7use Fatal qw( :void open close binmode ); # make builtins throw exceptions on failure
8use English qw( -no_match_vars ); # for more readable code
9use Scalar::Util qw( blessed ); # for checking if a reference is blessed
10use Math::Round; # for round()
11use Math::BigInt; # for the massive numbers needed to store the permutations
12use Clone qw( clone ); # for cloning nested data structures - exports clone()
13use Readonly; # for truly constant constants
14use JSON; # for dealing with JSON strings
15use List::MoreUtils qw( uniq ); # for array deduplication
16use Type::Tiny; # for generating anonymous type constraints when needed
17use Type::Params qw( compile multisig ); # for parameter validation with Type::Tiny objects
18use Types::Standard qw( slurpy :types ); # for basic type checking (Int Str etc.)
19use Crypt::HSXKPasswd::Types qw( :types ); # for custom type checking
20use Crypt::HSXKPasswd::Helper; # exports utility functions like _error & _warn
21use Crypt::HSXKPasswd::Dictionary::Basic;
22use Crypt::HSXKPasswd::RNG::Math_Random_Secure;
23use Crypt::HSXKPasswd::RNG::Data_Entropy;
24use Crypt::HSXKPasswd::RNG::DevUrandom;
25use Crypt::HSXKPasswd::RNG::Basic;
26
27# set things up for using UTF-8
28use 5.016; # min Perl for good UTF-8 support, implies feature 'unicode_strings'
29use Encode qw( encode decode );
30use Text::Unidecode; # for stripping accents from accented characters
31use utf8;
32binmode STDOUT, ':encoding(UTF-8)';
33
34# import (or not) optional modules
35eval{
36    # the default dicrionary may not have been geneated using the Util module
37    require Crypt::HSXKPasswd::Dictionary::EN;
38}or do{
39    carp('WARNING - failed to load Crypt::HSXKPasswd::Dictionary::EN');
40};
41
42## no critic (ProhibitAutomaticExportation);
43use base qw( Exporter );
44our @EXPORT = qw( hsxkpasswd );
45## use critic
46
47# Copyright (c) 2015, Bart Busschots T/A Bartificer Web Solutions All rights
48# reserved.
49#
50# Code released under the FreeBSD license (included in the POD at the bottom of
51# this file)
52
53#==============================================================================
54# Code
55#==============================================================================
56
57#
58# === Constants and Package Variables =========================================#
59#
60
61# version info
62use version; our $VERSION = qv('3.6');
63
64# entropy control variables
65my $_ENTROPY_MIN_BLIND = 78; # 78 bits - equivalent to 12 alpha numeric characters with mixed case and symbols
66my $_ENTROPY_MIN_SEEN = 52; # 52 bits - equivalent to 8 alpha numeric characters with mixed case and symbols
67my $_ENTROPY_WARNINGS = 'ALL'; # valid values are 'ALL', 'BLIND', or 'NONE' (invalid values treated like 'ALL')
68
69# utility constants
70Readonly my $_CLASS => __PACKAGE__;
71Readonly my $_TYPES_CLASS => 'Crypt::HSXKPasswd::Types';
72Readonly my $_DICTIONARY_BASE_CLASS => 'Crypt::HSXKPasswd::Dictionary';
73Readonly my $_RNG_BASE_CLASS => 'Crypt::HSXKPasswd::RNG';
74
75#
76# Constructor -----------------------------------------------------------------
77#
78
79#####-SUB-######################################################################
80# Type       : CONSTRUCTOR (CLASS)
81# Purpose    : Instantiate an object of type XKPasswd
82# Returns    : An object of type XKPasswd
83# Arguments  : This function accepts the following named arguments - all
84#              optional:
85#              dictionary - an object that inherits from
86#                  Crypt::HSXKPasswd::Dictionary
87#              dictionary_list - an array ref of words to use as a dictionary.
88#              dictionary_file - the path to a dictionary file.
89#              dictionary_file_encoding - the encoding to use when loading the
90#                  dictionary file, defaults to UTF-8.
91#              preset - the preset to use
92#              preset_overrides - a hashref of config options to override.
93#                  Ignored unless preset is set, and in use.
94#              config - a config hashref.
95#              config_json - a config as a JSON string (requires that the JSON
96#                  module be installed)
97#              rng - an object that inherits from Crypt::HSXKPasswd::RNG
98# Throws     : Croaks if the function is called in an invalid way, called with
99#              invalid args, or called with a JSON string when JSON is not
100#              installed.
101# Notes      : The order of preference for word sources is dictionary, then
102#              dictionary_list, then dictionary_file. If none are specified,
103#              then an instance of Crypt::HSXKPasswd::Dictionary::EN will be
104#              used.
105#              The order of preference for the configuration source is config
106#              then config_json, then preset. If no configuration source is
107#              specified, then the preset 'DEFAULT' is used.
108#              If no RNG is passed, _best_available_rng() will be used to
109#              instantiate and instance of the most secure RNG usable on the
110#              system.
111# See Also   : For valid configuarion options see POD documentation below
112sub new{
113    my @args = @_;
114    my $class = shift @args;
115    _force_class($class);
116
117    # validate args
118    state $args_check = compile(slurpy Dict[
119        dictionary => Optional[InstanceOf[$_DICTIONARY_BASE_CLASS]],
120        dictionary_list => Optional[ArrayRef[Str]],
121        dictionary_file => Optional[Str],
122        dictionary_file_encoding => Optional[Str],
123        config => Optional[Config],
124        config_json => Optional[Str],
125        preset => Optional[PresetName],
126        preset_overrides => Optional[ConfigOverride],
127        rng => Optional[InstanceOf[$_RNG_BASE_CLASS]],
128    ]);
129    my ($options) = $args_check->(@args);
130
131    # set defaults
132    $options->{dictionary_file_encoding} = 'UTF-8' unless $options->{dictionary_file_encoding};
133
134
135    # before going any further, check the presets and key definitions if debugging (doing later may cause an error before we test)
136    if($_CLASS->module_config('DEBUG')){
137        $_CLASS->_check_config_key_definitions();
138        $_CLASS->_check_preset_definitions();
139    }
140
141    # process the word source
142    my $dictionary;
143    if($options->{dictionary}){
144        $dictionary = $options->{dictionary};
145    }elsif($options->{dictionary_list}){
146        $dictionary = Crypt::HSXKPasswd::Dictionary::Basic->new($options->{dictionary_list});
147    }elsif($options->{dictionary_file}){
148        $dictionary = Crypt::HSXKPasswd::Dictionary::Basic->new($options->{dictionary_file}, $options->{dictionary_file_encoding});
149    }else{
150        $dictionary = Crypt::HSXKPasswd::Dictionary::EN->new();
151    }
152
153    # process the config source
154    my $config = {};
155    if($options->{config}){
156        $config = $options->{config};
157    }elsif($options->{config_json}){
158        $config = $options->{config_json}; # pass the string on, config() will deal with it
159    }elsif($options->{preset}){
160        $config = $_CLASS->preset_config($options->{preset}, $options->{preset_overrides});
161    }else{
162        $config = $_CLASS->default_config();
163    }
164
165    # process the random number source
166    my $rng = {};
167    if($options->{rng}){
168        $rng = $options->{rng};
169    }else{
170        $rng = $_CLASS->_best_available_rng();
171    }
172
173    # initialise the object
174    my $instance = {
175        # 'public' instance variables (none so far)
176        # 'PRIVATE' internal variables
177        _CONFIG => {},
178        _DICTIONARY_SOURCE => {}, # the dictionary object to source words from
179        _RNG => {}, # the random number generator
180        _CACHE_DICTIONARY_FULL => [], # a cache of all words found in the dictionary file
181        _CACHE_DICTIONARY_LIMITED => [], # a cache of all the words found in the dictionary file that meet the length criteria
182        _CACHE_CONTAINS_ACCENTS => 0, # a cache of whether or not the filtered word list contains words with accented letters
183        _CACHE_ENTROPYSTATS => {}, # a cache of the entropy stats for the current combination of dictionary and config
184        _CACHE_RANDOM => [], # a cache of random numbers (as floating points between 0 and 1)
185        _PASSWORD_COUNTER => 0, # the number of passwords this instance has generated
186    };
187    bless $instance, $class;
188
189    # load the config - will croak on invalid config
190    $instance->config($config);
191
192    # load the dictionary (can't be done until the config is loaded)
193    $instance->dictionary($dictionary);
194
195    # load the rng
196    $instance->rng($rng);
197
198    # if debugging, print status
199    _debug("instantiated $_CLASS object with the following details:\n".$instance->status());
200
201    # return the initialised object
202    return $instance;
203}
204
205#
206# Public Class (Static) functions ---------------------------------------------
207#
208
209#####-SUB-######################################################################
210# Type       : CLASS
211# Purpose    : Return or update a module config variable
212# Returns    : The value of the specified module config variable
213# Arguments  : 1) the name of the module config variable
214#              2) OPTIONAL - a new value for the module config variable
215# Throws     : Croaks on invalid invocation, or invalid args
216# Notes      :
217# See Also   :
218sub module_config{
219    my @args = @_;
220    my $class = shift @args;
221    _force_class($class);
222
223    # validate args
224    state $args_check = compile(
225        NonEmptyString->plus_coercions(Str, q{uc $_}), ## no critic (RequireInterpolationOfMetachars)
226        Optional[Maybe[Value]],
227    );
228    my ($config_key, $new_value) = $args_check->(@args);
229
230
231    # figure out which variable we are accessing
232    ## no critic (ProhibitCascadingIfElse);
233    if($config_key eq 'LOG_STREAM'){
234        # check if we are a setter
235        if(defined $new_value){
236            # make sure the new value is valid
237            FileHandle->check($new_value) || _error(FileHandle->get_message($new_value));
238
239            # save the new value
240            $Crypt::HSXKPasswd::Helper::_LOG_STREAM = $new_value; ## no critic (ProtectPrivateVars)
241        }
242
243        #return the value
244        return $Crypt::HSXKPasswd::Helper::_LOG_STREAM; ## no critic (ProtectPrivateVars)
245    }
246    elsif($config_key eq 'LOG_ERRORS'){
247        # check if we are a setter
248        if(defined $new_value){
249            # make sure the new value is valid
250            TrueFalse->check($new_value) || _error(TrueFalse->get_message($new_value));
251
252            # save the new value
253            $Crypt::HSXKPasswd::Helper::_LOG_ERRORS = $new_value; ## no critic (ProtectPrivateVars)
254        }
255
256        #return the value
257        return $Crypt::HSXKPasswd::Helper::_LOG_ERRORS; ## no critic (ProtectPrivateVars)
258    }
259    elsif($config_key eq 'DEBUG'){
260        # check if we are a setter
261        if(defined $new_value){
262            # make sure the new value is valid
263            TrueFalse->check($new_value) || _error(TrueFalse->get_message($new_value));
264
265            # save the new value
266            $Crypt::HSXKPasswd::Helper::_DEBUG = $new_value; ## no critic (ProtectPrivateVars)
267        }
268
269        #return the value
270        return $Crypt::HSXKPasswd::Helper::_DEBUG; ## no critic (ProtectPrivateVars)
271    }elsif($config_key eq 'ENTROPY_MIN_BLIND'){
272        # check if we are a setter
273        if(defined $new_value){
274            # make sure the new value is valid
275            PositiveInteger->check($new_value) || _error(PositiveInteger->get_message($new_value));
276
277            # save the new value
278            $_ENTROPY_MIN_BLIND = $new_value;
279        }
280
281        #return the value
282        return $_ENTROPY_MIN_BLIND;
283    }elsif($config_key eq 'ENTROPY_MIN_SEEN'){
284        # check if we are a setter
285        if(defined $new_value){
286            # make sure the new value is valid
287            PositiveInteger->check($new_value) || _error(PositiveInteger->get_message($new_value));
288
289            # save the new value
290            $_ENTROPY_MIN_SEEN = $new_value;
291        }
292
293        #return the value
294        return $_ENTROPY_MIN_SEEN;
295    }elsif($config_key eq 'ENTROPY_WARNINGS'){
296        # check if we are a setter
297        if(defined $new_value){
298            # make sure the new value is valid
299            EntropyWarningLevel->check($new_value) || _error(EntropyWarningLevel->get_message($new_value));
300
301            # save the new value
302            $_ENTROPY_WARNINGS = $new_value;
303        }
304
305        #return the value
306        return $_ENTROPY_WARNINGS;
307    }else{
308        # the config key was invalid
309        _error(qq{no package variable '$config_key'});
310    }
311    ## use critic
312
313    # It's not possible to get here, so return 1 to keep PerlCritic happy
314    return 1;
315}
316
317#####-SUB-######################################################################
318# Type       : CLASS
319# Purpose    : Get a list of defined config keys.
320# Returns    : An array of strings.
321# Arguments  : NONE
322# Throws     : NOTHING
323# Notes      :
324# See Also   :
325sub defined_config_keys{
326    # gather and return the list of config key names
327    return (sort keys %{$_TYPES_CLASS->_config_keys()});
328}
329
330#####-SUB-######################################################################
331# Type       : CLASS
332# Purpose    : Return the specification for a given config key.
333# Returns    : A hash indexed by 'required', 'type', and 'expects'.
334# Arguments  : 1) a valid config key name
335# Throws     : Croaks on invalid invocation and args
336# Notes      :
337# See Also   :
338sub config_key_definition{
339    my @args = @_;
340    my $class = shift @args;
341    _force_class($class);
342
343    # validate args
344    state $args_check = compile(ConfigKeyName);
345    my ($key) = $args_check->(@args);
346
347    # get a referece to the keys hashref from the Types class
348    my $defined_keys = $_TYPES_CLASS->_config_keys();
349
350    # assemble the hash
351    my %definition = (
352        required => $defined_keys->{$key}->{required},
353        type => $defined_keys->{$key}->{type},
354        expects => $defined_keys->{$key}->{expects},
355    );
356
357    # return the hash
358    return %definition;
359}
360
361#####-SUB-######################################################################
362# Type       : CLASS
363# Purpose    : Return a hash of all key definitions indexed by key name.
364# Returns    : A hash of key defintions as returned by config_key_definition().
365# Arguments  : NONE
366# Throws     : NOTHING
367# Notes      :
368# See Also   : config_key_definition()
369sub config_key_definitions{
370    # gather the definitions
371    my %definitions = ();
372    foreach my $key ($_CLASS->defined_config_keys()){
373        $definitions{$key} = $_CLASS->config_key_definition($key);
374    }
375
376    # return the definitions
377    return %definitions;
378}
379
380#####-SUB-######################################################################
381# Type       : CLASS
382# Purpose    : generate a config hashref populated with the default values
383# Returns    : a hashref
384# Arguments  : 1. OPTIONAL - a hashref with config keys to over-ride when
385#                 assembling the config
386# Throws     : Croaks if invoked in an invalid way. If passed overrides also
387#              Croaks if the resulting config is invalid, and Carps if passed
388#              on each invalid key passed in the overrides hashref.
389# Notes      :
390# See Also   :
391sub default_config{
392    my @args = @_;
393    my $class = shift @args;
394    _force_class($class);
395
396    # validate args
397    state $args_check = compile(Optional[ConfigOverride]);
398    my ($overrides) = $args_check->(@args);
399
400    # build and return a default config
401    return $_CLASS->preset_config('DEFAULT', $overrides);
402}
403
404#####-SUB-######################################################################
405# Type       : CLASS
406# Purpose    : Return the specification for a given preset.
407# Returns    : A hash indexed by 'description', and 'config'.
408# Arguments  : 1) OPTIONAL - a valid preset name, defaults to 'DEFAULT'
409# Throws     : Croaks on invalid invocation and args
410# Notes      :
411# See Also   :
412sub preset_definition{
413    my @args = @_;
414    my $class = shift @args;
415    _force_class($class);
416
417    # validate args
418    state $args_check = compile(Optional[Maybe[PresetName]]);
419    my ($preset_name) = $args_check->(@args);
420
421    # set defaults
422    $preset_name = 'DEFAULT' unless $preset_name;
423
424    # get a referece to the presets hashref from the Types class
425    my $preset_defs = $_TYPES_CLASS->_presets();
426
427    # assemble the hash
428    my %definition = (
429        description => $preset_defs->{$preset_name}->{description},
430        config => $preset_defs->{$preset_name}->{config},
431    );
432
433    # return the hash
434    return %definition;
435}
436
437#####-SUB-######################################################################
438# Type       : CLASS
439# Purpose    : Return a hash of all preset definitions indexed by name.
440# Returns    : A hash of preset defintions as returned by preset_definition().
441# Arguments  : NONE
442# Throws     : NOTHING
443# Notes      :
444# See Also   : preset_definition()
445sub preset_definitions{
446    # gather the definitions
447    my %definitions = ();
448    foreach my $name ($_CLASS->defined_presets()){
449        $definitions{$name} = $_CLASS->preset_definition($name);
450    }
451
452    # return the definitions
453    return %definitions;
454}
455
456#####-SUB-######################################################################
457# Type       : CLASS
458# Purpose    : generate a config hashref populated using a preset
459# Returns    : a hashref
460# Arguments  : 1. OPTIONAL - The name of the preset to assemble the config for
461#                 as a scalar. If no name is passed, the preset 'DEFAULT' is
462#                 used
463#              2. OPTIONAL - a hashref with config keys to over-ride when
464#                 assembling the config
465# Throws     : Croaks if invoked in an invalid way. If passed overrides also
466#              Croaks if the resulting config is invalid, and Carps if passed
467#              on each invalid key passed in the overrides hashref.
468# Notes      :
469# See Also   :
470sub preset_config{
471    my @args = @_;
472    my $class = shift @args;
473    _force_class($class);
474
475    # validate args
476    state $args_check = compile(Optional[PresetName], Optional[Maybe[ConfigOverride]]);
477    my ($preset_name, $overrides) = $args_check->(@args);
478
479    # default the preset name to 'DEFAULT'
480    $preset_name = 'DEFAULT' unless $preset_name;
481
482    # get a reference to the Presets hashref from the Types class
483    my $preset_defs = $_TYPES_CLASS->_presets();
484
485    # start by loading the preset
486    my $config = $_CLASS->clone_config($preset_defs->{$preset_name}->{config});
487
488    # if overrides were passed, apply them and validate
489    if(defined $overrides){
490        # save the keys into the config
491        foreach my $key (keys %{$overrides}){
492            $config->{$key} = $overrides->{$key};
493        }
494        # validate the resulting config
495        unless(Config->check($config)){
496            _error('The preset combined with the specified overrides produces an invalid config: '.Config->get_message($config));
497        }
498    }
499
500    # return the config
501    return $config;
502}
503
504#####-SUB-######################################################################
505# Type       : CLASS
506# Purpose    : Resturn the presets defined in the Crypt::HSXKPasswd module as a
507#              JSON string
508# Returns    : A JSON String as a scalar. The JSON string represets a hashref
509#              with three keys  - 'defined_keys' contains an array of preset
510#              identifiers, 'presets' contains the preset configs indexed by
511#              preset identifier, and 'preset_descriptions' contains the a
512#              hashref of descriptions indexed by preset identifiers
513# Arguments  : NONE
514# Throws     : If there is a problem converting the objects to JSON.
515# Notes      :
516# See Also   :
517sub presets_json{
518    # assemble an object containing the presets with any keys that can't be
519    #  converted to JSON removed
520    my @defined_presets = $_CLASS->defined_presets();
521    my $sanitised_presets = {};
522    my $preset_descriptions = {};
523    foreach my $preset_name (@defined_presets){
524        $sanitised_presets->{$preset_name} = $_CLASS->preset_config($preset_name);
525        $preset_descriptions->{$preset_name} = $_CLASS->preset_description($preset_name);
526    }
527    my $return_object = {
528        defined_presets => [@defined_presets],
529        presets => $sanitised_presets,
530        preset_descriptions => $preset_descriptions,
531    };
532
533    # try convert the object to a JSON string
534    my $json_string = q{};
535    eval{
536        $json_string = JSON->new()->encode($return_object);
537        1; # ensure truthy evaluation on succesful execution
538    }or do{
539        _error("failed to render presets as JSON string with error: $EVAL_ERROR");
540    };
541
542    # return the JSON string
543    return $json_string;
544}
545
546#####-SUB-######################################################################
547# Type       : CLASS
548# Purpose    : Clone a config hashref
549# Returns    : a hashref
550# Arguments  : 1. the config hashref to clone
551# Throws     : Croaks if called in an invalid way, or with an invalid config.
552# Notes      : This function needs to be updated each time a new non-scalar
553#              valid config key is added to the library.
554# See Also   :
555sub clone_config{
556    my @args = @_;
557    my $class = shift @args;
558    _force_class($class);
559
560    # validate args
561    state $args_check = compile(Config);
562    my ($config) = $args_check->(@args);
563
564    return clone($config);
565}
566
567#####-SUB-######################################################################
568# Type       : CLASS
569# Purpose    : Remove all keys from a hashref that are not valid config keys
570# Returns    : A reference to a hashref
571# Arguments  : 1) a hashref
572#              2) OPTIONAL - a list of named arguments:
573#                 'warn_invalid_key_names' - must be either 1 or 0. If 1,
574#                     warnings will be issued for any keys containined in the
575#                     test hash that are not valid config keys.
576#                     'suppress_warnings' takes precedence over this argument.
577#                 'suppress_warnings' - must be either 1 or 0. If 1, no warnings
578#                     will be printed when dropping valid keys with invalid
579#                     values, or invalid keys.
580# Throws     : Croaks on invalid args. Unless configured not to, will warn if
581#              a valid key with an invalid value is encountered.
582# Notes      :
583# See Also   :
584sub distil_to_config_keys{
585    my @args = @_;
586    my $class = shift @args;
587    _force_class($class);
588
589    # validate args
590    state $args_check = compile(HashRef,
591        slurpy Dict[
592            suppress_warnings => Optional[TrueFalse],
593            warn_invalid_key_names => Optional[TrueFalse],
594        ],
595    );
596    my ($hashref, $options) = $args_check->(@args);
597
598    # get a list of all the defined keys
599    my @defined_keys = $_CLASS->defined_config_keys();
600
601    # if warnings are not suppressed, and if extra warnings are asked for, check for invalid keys
602    if(!$options->{suppress_warnings} && $options->{warn_invalid_key_names}){
603        # build a lookup table to quickly test if a key exists
604        my %defined_keys_lookup = ();
605        foreach my $key (@defined_keys){
606            $defined_keys_lookup{$key} = 1;
607        }
608
609        # check each key in the test hash against the lookup table
610        foreach my $test_key (sort keys %{$hashref}){
611            unless($defined_keys_lookup{$test_key}){
612                _warn(qq{distilling out undefined config key '$test_key'});
613            }
614        }
615    }
616
617    # start with a new blank hashref, and copy across only the valid keys
618    my $distilled = {};
619    foreach my $key (@defined_keys){
620        if(defined $hashref->{$key}){
621            if(ConfigKeyAssignment->check({$key => $hashref->{$key}})){
622                $distilled->{$key} = clone($hashref->{$key});
623            }else{
624                _warn("distilling out valid config key '$key' because of invalid value: ".ConfigKeyAssignment->get_message({$key => $hashref->{$key}})) unless $options->{suppress_warnings};
625            }
626        }
627    }
628    _debug('hashref distilled down from '.(scalar keys %{$hashref}).' to '.(scalar keys %{$distilled}).' keys');
629
630    # return the distilled hashref
631    return $distilled;
632}
633
634#####-SUB-######################################################################
635# Type       : CLASS
636# Purpose    : Distil an array of strings down to a de-duplicated array of only
637#              symbols.
638# Returns    : An array of strings
639# Arguments  : 1) A reference to an array of strings
640#              2) OPTIONAL - a named argument warn with a value of 0 or 1. If 1
641#                 is passed, warnings will be issued each time an invalid string
642#                 is skipped over.
643# Throws     : Croaks on invalid invocation or args, and warns on request when
644#              skipping words.
645# Notes      :
646# See Also   :
647sub distil_to_symbol_alphabet{
648    my @args = @_;
649    my $class = shift @args;
650    _force_class($class);
651
652    # validate args
653    state $args_check = compile(ArrayRef[Str], slurpy Dict[warn => Optional[TrueFalse]]);
654    my ($array_ref, $options) = $args_check->(@args);
655    my $warn = $options->{warn} || 0;
656
657    # loop through the array and copy all valid synbols to a new array
658    my @valid_symbols = ();
659    foreach my $potential_symbol (@{$array_ref}){
660        if(Symbol->check($potential_symbol)){
661            push @valid_symbols, $potential_symbol;
662        }else{
663            if($warn || _do_debug()){
664                my $msg = 'skipping invalid symbol: '.Symbol->get_message($potential_symbol);
665                if($warn){
666                    _warn($msg);
667                }else{
668                    _debug($msg);
669                }
670            }
671        }
672    }
673
674    # de-dupe the valid symbols
675    my @final_alphabet = uniq(@valid_symbols);
676
677    # return the valid symbols
678    return @final_alphabet;
679}
680
681#####-SUB-######################################################################
682# Type       : CLASS
683# Purpose    : Distil an array of strings down to a de-duplicated array of only
684#              the valid words.
685# Returns    : An array of words
686# Arguments  : 1) A reference to an array of strings
687#              2) OPTIONAL - a named argument warn with a value of 0 or 1. If 1
688#                 is passed, warnings will be issued each time an invalid string
689#                 is skipped over.
690# Throws     : Croaks on invalid invocation or args, and warns on request when
691#              skipping words.
692# Notes      :
693# See Also   :
694sub distil_to_words{
695    my @args = @_;
696    my $class = shift @args;
697    _force_class($class);
698
699    # just pass everything through to the dictionary class
700    return $_DICTIONARY_BASE_CLASS->distil_to_words(@args);
701}
702
703#####-SUB-######################################################################
704# Type       : CLASS
705# Purpose    : validate a config hashref
706# Returns    : 1 if the config is valid, 0 otherwise
707# Arguments  : 1. a hashref to validate
708#              2. OPTIONAL - a named argument croak with a value of 1 or 1
709# Throws     : Croaks on invalid args, or on error if second arg is truthy
710# Notes      : This function needs to be updated each time a new valid config
711#              key is added to the library.
712# See Also   :
713sub is_valid_config{
714    my @args = @_;
715    my $class = shift @args;
716    _force_class($class);
717
718    # validate args
719    state $args_check = compile(Item, slurpy Dict[croak => Optional[TrueFalse]]);
720    my ($config, $options) = $args_check->(@args);
721
722    # validate the config
723    my $is_valid = Config->check($config) || 0;
724
725    # croak if appropriate
726    if(!$is_valid && $options->{croak}){
727        _error(Config->get_message($config));
728    }
729
730    # return the result of the validation
731    return $is_valid;
732}
733
734#####-SUB-######################################################################
735# Type       : CLASS
736# Purpose    : Convert a config hashref to a JSON String
737# Returns    : A scalar
738# Arguments  : 1. A config hashref
739# Throws     : Croaks on invalid invocation, invalid args, or if the JSON module
740#              is not available
741# Notes      :
742# See Also   :
743sub config_to_json{
744    my @args = @_;
745    my $class = shift @args;
746    _force_class($class);
747
748    # validate args
749    state $args_check = compile(Config);
750    my ($config) = $args_check->(@args);
751
752    # try render the config to a JSON string
753    my $ans = q{};
754    eval{
755        $ans = encode_json($config);
756        1; # ensure a thurthy evaluation on successful execution
757    }or do{
758        _error("Failed to convert config to JSON stirng with error: $EVAL_ERROR");
759    };
760
761    # return the string
762    return $ans;
763}
764
765#####-SUB-######################################################################
766# Type       : CLASS
767# Purpose    : Convert a config hashref to a String
768# Returns    : A scalar
769# Arguments  : 1. A config hashref
770# Throws     : Croaks on invalid invocation or with invalid args. Carps if there
771#              are problems with the config hashref.
772# Notes      :
773# See Also   :
774sub config_to_string{
775    my @args = @_;
776    my $class = shift @args;
777    _force_class($class);
778
779    # validate args
780    state $args_check = compile(Config);
781    my ($config) = $args_check->(@args);
782
783    # get a reference to the key definitions from the types class
784    my $defined_keys = $_TYPES_CLASS->_config_keys();
785
786    # assemble the string to return
787    my $ans = q{};
788    CONFIG_KEY:
789    foreach my $key (sort keys %{$defined_keys}){
790        # skip undefined keys
791        next CONFIG_KEY unless defined $config->{$key};
792
793        # process the key
794        if(ref $config->{$key} eq q{}){
795            # the key is a scalar
796            $ans .= $key.q{: '}.$config->{$key}.qq{'\n};
797        }elsif(ref $config->{$key} eq 'ARRAY'){
798            # the key is an array ref
799            $ans .= "$key: [";
800            my @parts = ();
801            foreach my $subval (sort @{$config->{$key}}){
802                push @parts, "'$subval'";
803            }
804            $ans .= join q{, }, @parts;
805            $ans .= "]\n";
806        }elsif(ref $config->{$key} eq 'HASH'){
807            $ans .= "$key: {";
808            my @parts = ();
809            foreach my $subkey (sort keys %{$config->{$key}}){
810                push @parts, "$subkey: '$config->{$key}->{$subkey}'";
811            }
812            $ans .= join q{, }, @parts;
813            $ans .= "}\n";
814        }else{
815            # this should never happen, but just in case, throw a warning
816            _warn("the data for the key '$key' is of an un-expected type (".(ref $config->{$key}).') - skipping key');
817        }
818    }
819
820    # return the string
821    return $ans;
822}
823
824#####-SUB-######################################################################
825# Type       : CLASS
826# Purpose    : Return the description for a given preset
827# Returns    : A scalar string
828# Arguments  : 1. OPTIONAL - the name of the preset to get the description for,
829#                 if no name is passed 'DEFAULT' is assumed
830# Throws     : Croaks on invalid invocation or invalid args
831# Notes      :
832# See Also   :
833sub preset_description{
834    my @args = @_;
835    my $class = shift @args;
836    _force_class($class);
837
838    # validate args
839    state $args_check = compile(Optional[Maybe[PresetName]]);
840    my ($preset) = $args_check->(@args);
841
842    # set defaults
843    $preset = 'DEFAULT' unless $preset;
844
845    # get a reference to the preset definitions from the Types class
846    my $preset_defs = $_TYPES_CLASS->_presets();
847
848    # return the description by loading the preset
849    return $preset_defs->{$preset}->{description};
850}
851
852
853#####-SUB-######################################################################
854# Type       : CLASS
855# Purpose    : Return a list of all valid preset names
856# Returns    : An array of preset names as scalars
857# Arguments  : NONE
858# Throws     : NOTHING
859# Notes      :
860# See Also   :
861sub defined_presets{
862    # return the preset names
863    my @preset_names = sort keys %{$_TYPES_CLASS->_presets()};
864    return @preset_names;
865}
866
867#####-SUB-######################################################################
868# Type       : CLASS
869# Purpose    : Render the defined presets as a string
870# Returns    : A scalar
871# Arguments  : NONE
872# Throws     : NOTHING
873# Notes      :
874# See Also   :
875sub presets_to_string{
876    # get a reference to the preset definitions from th Types class
877    my $preset_defs = $_TYPES_CLASS->_presets();
878
879    # loop through each preset and assemble the result
880    my $ans = q{};
881    my @preset_names = $_CLASS->defined_presets();
882    foreach my $preset (@preset_names){
883        $ans .= $preset."\n===\n";
884        $ans .= $preset_defs->{$preset}->{description}."\n";
885        $ans .= "\nConfig:\n---\n";
886        $ans .= $_CLASS->config_to_string($preset_defs->{$preset}->{config});
887        $ans .= "\nStatistics:\n---\n";
888        my %stats = $_CLASS->config_stats($preset_defs->{$preset}->{config});
889        if($stats{length_min} == $stats{length_max}){
890            $ans .= "Length (fixed): $stats{length_min} characters\n";
891        }else{
892            $ans .= "Length (variable): between $stats{length_min} & $stats{length_max} characters\n";
893        }
894        $ans .= "Random Numbers Needed Per-Password: $stats{random_numbers_required}\n";
895        $ans .= "\n";
896    }
897
898    # return the string
899    return $ans;
900}
901
902#####-SUB-#####################################################################
903# Type       : CLASS
904# Purpose    : Calculate the number of random numbers needed to genereate a
905#              single password with a given config.
906# Returns    : An integer
907# Arguments  : 1) a valid config hashref
908# Throws     : Croaks in invalid invocation, or invalid args
909# Notes      :
910# See Also   :
911sub config_random_numbers_required{
912    my @args = @_;
913    my $class = shift @args;
914    _force_class($class);
915
916    # validate args
917    state $args_check = compile(Config);
918    my ($config) = $args_check->(@args);
919
920    # calculate the number of random numbers needed to generate the password
921    my $num_rand = 0;
922    $num_rand += $config->{num_words};
923    if($config->{case_transform} eq 'RANDOM'){
924        $num_rand += $config->{num_words};
925    }
926    if($config->{separator_character} eq 'RANDOM'){
927        $num_rand++;
928    }
929    if(defined $config->{padding_character} && $config->{padding_character} eq 'RANDOM'){
930        $num_rand++;
931    }
932    $num_rand += $config->{padding_digits_before};
933    $num_rand += $config->{padding_digits_after};
934
935    # return the number
936    return $num_rand;
937}
938
939#####-SUB-######################################################################
940# Type       : CLASS
941# Purpose    : Calculate statistics for a given configutration hashref.
942# Returns    : A hash of statistics indexed by the following keys:
943#              * 'length_min' - the minimum possible length of a password
944#                generated by the given config
945#              * 'length_max' - the maximum possible length of a password
946#                generated by the given config
947#              * 'random_numbers_required' - the number of random numbers needed
948#                to generate a single password using the given config
949# Arguments  : 1. A valid config hashref
950#              2. OPTONAL - a named argument 'suppress_warnings' to indicate that
951#                 no warnings should be issued if the config is such that there
952#                 are uncertainties in the calculation.
953# Throws     : Croaks on invalid invocation or args, carps if multi-character
954#              substitutions are in use when not using adapive padding
955# Notes      : This function ignores character replacements, if one or more
956#              multi-character replacements are used when padding is not set
957#              to adaptive, this function will return an invalid max length.
958# See Also   :
959sub config_stats{
960    my @args = @_;
961    my $class = shift @args;
962    _force_class($class);
963
964    # validate args
965    state $args_check = compile(Config, slurpy Dict[suppress_warnings => Optional[TrueFalse]]);
966    my ($config, $options) = $args_check->(@args);
967    my $suppres_warnings = $options->{suppress_warnings} || 0;
968
969    # calculate the lengths
970    my $len_min = 0;
971    my $len_max = 0;
972    if($config->{padding_type} eq 'ADAPTIVE'){
973        $len_min = $len_max = $config->{pad_to_length};
974    }else{
975        # calcualte the length of everything but the words themselves
976        my $len_base = 0;
977        if($config->{padding_type} eq 'FIXED'){
978            $len_base += $config->{padding_characters_before};
979            $len_base += $config->{padding_characters_after};
980        }
981        if($config->{padding_digits_before} > 0){
982            $len_base += $config->{padding_digits_before};
983            if($config->{separator_character} ne 'NONE'){
984                $len_base++;
985            }
986        }
987        if($config->{padding_digits_after} > 0){
988            $len_base += $config->{padding_digits_after};
989            if($config->{separator_character} ne 'NONE'){
990                $len_base++;
991            }
992        }
993        if($config->{separator_character} ne 'NONE'){
994            $len_base += $config->{num_words} - 1;
995        }
996
997        # maximise and minimise the word lengths to calculate the final answers
998        $len_min = $len_base + ($config->{num_words} * $config->{word_length_min});
999        $len_max = $len_base + ($config->{num_words} * $config->{word_length_max});
1000    }
1001
1002    # calculate the number of random numbers needed to generate the password
1003    my $num_rand = $_CLASS->config_random_numbers_required($config);
1004
1005    # detect whether or not we need to carp about multi-character replacements
1006    if($config->{padding_type} ne 'ADAPTIVE' && !$suppres_warnings){
1007        if(defined $config->{character_substitutions}){
1008            CHAR_SUB:
1009            foreach my $char (keys %{$config->{character_substitutions}}){
1010                if(length $config->{character_substitutions}->{$char} > 1){
1011                    _warn('maximum length may be underestimated. The loaded config contains at least one character substitution which replaces a single character with multiple characters.');
1012                    last CHAR_SUB;
1013                }
1014            }
1015        }
1016    }
1017
1018    # assemble the result and return
1019    my $stats = {
1020        length_min => $len_min,
1021        length_max => $len_max,
1022        random_numbers_required => $num_rand,
1023    };
1024    return %{$stats};
1025}
1026
1027#
1028# --- Public Instance functions -----------------------------------------------
1029#
1030
1031#####-SUB-#####################################################################
1032# Type       : INSTANCE
1033# Purpose    : Get the currently loaded dictionary object, or, load a new
1034#              dictionary
1035# Returns    : An clone of the loaded dictionary object, or, a reference to the
1036#              instance (to enable function chaining) if called as a setter
1037# Arguments  : 1. OPTIONAL - the source for the dictionary, can be:
1038#                 The path to a dictionary file
1039#                     -OR-
1040#                 A reference to an array of words
1041#                     -OR-
1042#                 An instance of a sub-class of Crypt::HSXKPasswd::Dictionary
1043#              2. OPTIONAL - the encoding to import the file with. The default
1044#                 is UTF-8 (ignored if the first argument is not a file path).
1045# Throws     : Croaks on invalid invocation, or, if there is a problem loading
1046#              a dictionary file. While debugging, also warns when skipping
1047#              invalid words.
1048# Notes      :
1049# See Also   : For description of dictionary file format, see POD documentation
1050#              below
1051sub dictionary{
1052    my @args = @_;
1053    my $self = shift @args;
1054    _force_instance($self);
1055
1056    # validate args
1057    state $args_check = multisig(
1058        [],
1059        [NonEmptyString, Optional[Maybe[NonEmptyString]]],
1060        [InstanceOf[$_DICTIONARY_BASE_CLASS]],
1061        [ArrayRef[Str]],
1062    );
1063    my ($dictionary_source, $encoding) = $args_check->(@args);
1064
1065    # set defaults
1066    $encoding = 'UTF-8' unless $encoding;
1067
1068    # if we're a getter, just get and return
1069    unless(defined $dictionary_source){
1070        return $self->{_DICTIONARY_SOURCE}->clone();
1071    }
1072
1073    # OK, so we're a setter - carry on!
1074
1075    # croak if we are called before the config has been loaded into the instance
1076    unless(defined $self->{_CONFIG}->{word_length_min} && $self->{_CONFIG}->{word_length_max}){
1077        _error('failed to load word source - config has not been loaded yet');
1078    }
1079
1080    # get a dictionary instance
1081    my $new_dict;
1082    if(blessed($dictionary_source) && $dictionary_source->isa($_DICTIONARY_BASE_CLASS)){
1083        $new_dict = $dictionary_source;
1084    }elsif(ref $dictionary_source eq q{} || ref $dictionary_source eq 'ARRAY'){
1085        $new_dict = Crypt::HSXKPasswd::Dictionary::Basic->new($dictionary_source, $encoding); # could throw an error
1086    }else{
1087        _error('invalid word source - must be a dictionary object, hashref, or file path');
1088    }
1089
1090    # load and sanitise the words from the word source
1091    my @cache_full = $_CLASS->distil_to_words(\@{$new_dict->word_list()});
1092
1093    # generate the cache of appropriate-length words - croaks if too few words left after filtering
1094    my @cache_limited = $_CLASS->_filter_word_list(
1095        \@cache_full,
1096        $self->{_CONFIG}->{word_length_min},
1097        $self->{_CONFIG}->{word_length_max},
1098        allow_accents => $self->{_CONFIG}->{allow_accents},
1099    );
1100
1101    # if we got here all is well, so save the new path and caches into the object
1102    $self->{_DICTIONARY_SOURCE} = $new_dict;
1103    $self->{_CACHE_DICTIONARY_FULL} = [@cache_full];
1104    $self->{_CACHE_DICTIONARY_LIMITED} = [@cache_limited];
1105    if($self->{_CONFIG}->{allow_accents}){
1106        $self->{_CACHE_CONTAINS_ACCENTS} = $_CLASS->_contains_accented_letters(\@cache_limited);
1107    }else{
1108        $self->{_CACHE_CONTAINS_ACCENTS} = 0;
1109    }
1110
1111    # update the instance's entropy cache
1112    $self->_update_entropystats_cache();
1113
1114    # return a reference to self
1115    return $self;
1116}
1117
1118#####-SUB-######################################################################
1119# Type       : INSTANCE
1120# Purpose    : Get a clone of the current config from an instance, or load a
1121#              new config into the instance.
1122# Returns    : A config hashref if called with no arguments, or, the instance
1123#              if called with a hashref (to facilitate function chaining)
1124# Arguments  : 1. OPTIONAL - a configuration to load as:
1125#                 A config hashref
1126#                     -OR-
1127#                 A JSON string representing a config hashref
1128# Throws     : Croaks if the function is called in an invalid way, with invalid
1129#              arguments, or with an invalid config.
1130# Notes      : Passing a JSON string will cause the function to croak if perl's
1131#              JSON module is not installed.
1132# See Also   : For valid configuarion options see POD documentation below
1133sub config{
1134    my @args = @_;
1135    my $self = shift @args;
1136    _force_instance($self);
1137
1138    # validate args
1139    state $args_check = multisig(
1140        [],
1141        [Config],
1142        [NonEmptyString],
1143    );
1144    my ($config_raw) = $args_check->(@args);
1145
1146    # if we're a getter, just get and return
1147    unless(defined $config_raw){
1148        return $self->_clone_config();
1149    }
1150
1151    # OK - so we're a setter - carry on!
1152
1153    # see what kind of argument we were passed, and behave appropriately
1154    my $config = {};
1155    if(ref $config_raw eq 'HASH'){
1156        # we  received a hashref, so just and pass it on
1157        $config = $config_raw;
1158    }elsif(ref $config_raw eq q{}){
1159        # we received as string, so treat it as JSON
1160
1161        # try parse the received string as JSON
1162        my $config_from_json = {};
1163        eval{
1164            $config_from_json = decode_json($config_raw);
1165            1; # ensure truthy evaluation on successful execution
1166        }or do{
1167            _error("Failed to parse JSON config string with error: $EVAL_ERROR");
1168        };
1169
1170        # strip out any extraneous keys found
1171        $config = $_CLASS->distil_to_config_keys($config_from_json);
1172
1173        # validate the generated config
1174        unless(Config->check($config)){
1175            _error('Config extracted from JSON string is not valid: '.Config->get_message($config));
1176        }
1177    }else{
1178        _error('the config passed must be a hashref or a JSON string');
1179    }
1180
1181    # distil the alphabets in the new config
1182    $_CLASS->_distil_alphabets_inplace($config);
1183
1184    # save a clone of the passed config into the instance
1185    $self->{_CONFIG} = $_CLASS->clone_config($config);
1186
1187    # update the instance's entropy cache
1188    $self->_update_entropystats_cache();
1189
1190    # return a reference to self to facilitate function chaining
1191    return $self;
1192}
1193
1194#####-SUB-#####################################################################
1195# Type       : INSTANCE
1196# Purpose    : Return the config of the currently running instance as a JSON
1197#              string.
1198# Returns    : A scalar.
1199# Arguments  : NONE
1200# Throws     : Croaks if invoked in an invalid way. Carps if it meets a key of a
1201#              type not accounted for in the code.
1202# Notes      : This function will carp if the JSON module is not available
1203# See Also   :
1204sub config_as_json{
1205    my $self = shift;
1206    _force_instance($self);
1207
1208    # assemble and return the JSON string
1209    return $_CLASS->config_to_json($self->{_CONFIG}); # will croak without JSON
1210}
1211
1212#####-SUB-#####################################################################
1213# Type       : INSTANCE
1214# Purpose    : Return the config of the currently running instance as a string.
1215# Returns    : A scalar.
1216# Arguments  : NONE
1217# Throws     : Croaks if invoked in an invalid way. Carps if it meets a key of a
1218#              type not accounted for in the code.
1219# Notes      :
1220# See Also   :
1221sub config_as_string{
1222    my $self = shift;
1223    _force_instance($self);
1224
1225    # assemble and return the string
1226    return $_CLASS->config_to_string($self->{_CONFIG});
1227}
1228
1229#####-SUB-######################################################################
1230# Type       : INSTANCE
1231# Purpose    : Alter the running config with new values.
1232# Returns    : A reference to the instalce itself to enable function chaining.
1233# Arguments  : 1. a hashref containing config keys and values.
1234# Throws     : Croaks on invalid invocaiton, invalid args, and, if the resulting
1235#              new config is in some way invalid.
1236# Notes      : Invalid keys in the new keys hashref will be silently ignored.
1237# See Also   :
1238sub update_config{
1239    my @args = @_;
1240    my $self = shift @args;
1241    _force_instance($self);
1242
1243    # validate args
1244    state $args_check = compile(ConfigOverride);
1245    my ($new_keys) = $args_check->(@args);
1246
1247    # clone the current config as a starting point for the new config
1248    my $new_config = $self->_clone_config();
1249
1250    # get a reference to the key definitions from the types class
1251    my $defined_keys = $_TYPES_CLASS->_config_keys();
1252
1253    # merge the new values into the config
1254    my $num_keys_updated = 0;
1255    CONFIG_KEY:
1256    foreach my $key ($_CLASS->defined_config_keys()){
1257        # skip the key if it's not present in the list of new keys
1258        next CONFIG_KEY unless defined $new_keys->{$key};
1259
1260        # update the key in the new config
1261        $new_config->{$key} = $new_keys->{$key};
1262        $num_keys_updated++;
1263        _debug("updated $key to new value");
1264    }
1265    _debug("updated $num_keys_updated keys");
1266
1267    # distil the alphabets in the merged config
1268    $_CLASS->_distil_alphabets_inplace($new_config);
1269
1270    # validate the merged config
1271    unless(Config->check($new_config)){
1272        _error('the updated config is not valid: '.Config->get_message($new_config));
1273    }
1274
1275    # re-calculate the dictionary cache if needed
1276    my @cache_all = @{$self->{_CACHE_DICTIONARY_FULL}};
1277    my @cache_limited = @{$self->{_CACHE_DICTIONARY_LIMITED}};
1278    if($new_config->{word_length_min} ne $self->{_CONFIG}->{word_length_min} || $new_config->{word_length_max} ne $self->{_CONFIG}->{word_length_max}){
1279        # re-build the cache of valid words - throws an error if too few words are returned
1280        @cache_limited = $_CLASS->_filter_word_list(\@cache_all, $new_config->{word_length_min}, $new_config->{word_length_max}, $new_config->{allow_accents});
1281    }
1282
1283    # if we got here, all is well with the new config, so add it and the caches to the instance
1284    $self->{_CONFIG} = $new_config;
1285    $self->{_CACHE_DICTIONARY_LIMITED} = [@cache_limited];
1286
1287    # update the instance's entropy cache
1288    $self->_update_entropystats_cache();
1289
1290    # return a reference to self
1291    return $self;
1292}
1293
1294#####-SUB-#####################################################################
1295# Type       : INSTANCE
1296# Purpose    : Get the currently loaded RNG object, or, load a new RNG
1297# Returns    : An instance to the loaded RNG object, or, a reference to the
1298#              instance (to enable function chaining) if called as a setter
1299# Arguments  : 1. OPTIONAL - an object that is a Crypt::HSXKPasswd::RNG
1300# Throws     : Croaks on invalid invocation, or invalid args
1301# Notes      :
1302# See Also   :
1303sub rng{
1304    my @args = @_;
1305    my $self = shift @args;
1306    _force_instance($self);
1307
1308    # validate args
1309    state $args_check = multisig(
1310        [],
1311        [InstanceOf[$_RNG_BASE_CLASS]],
1312    );
1313    my ($rng) = $args_check->(@args);
1314
1315    # if we're a getter, just get and return
1316    unless(defined $rng){
1317        return $self->{_RNG};
1318    }
1319
1320    # OK - so we're a getter - carry on!
1321
1322    # set the RNG
1323    $self->{_RNG} = $rng;
1324
1325    # empty the random cache
1326    $self->{_CACHE_RANDOM} = [];
1327
1328    # return a reference to self
1329    return $self;
1330}
1331
1332#####-SUB-######################################################################
1333# Type       : INSTANCE
1334# Purpose    : Return the status of the internal caches within the instnace.
1335# Returns    : A string
1336# Arguments  : NONE
1337# Throws     : Croaks in invalid invocation
1338# Notes      :
1339# See Also   :
1340sub caches_state{
1341    my $self = shift;
1342    _force_instance($self);
1343
1344    # generate the string
1345    my $ans = q{};
1346    $ans .= 'Loaded Words: '.(scalar @{$self->{_CACHE_DICTIONARY_LIMITED}}).' (out of '.(scalar @{$self->{_CACHE_DICTIONARY_FULL}}).' loaded from the file)'.qq{\n};
1347    $ans .= 'Cached Random Numbers: '.(scalar @{$self->{_CACHE_RANDOM}}).qq{\n};
1348
1349    # return it
1350    return $ans;
1351}
1352
1353#####-SUB-######################################################################
1354# Type       : INSTANCE
1355# Purpose    : Generaete a random password based on the object's loaded config
1356# Returns    : a passowrd as a scalar
1357# Arguments  : NONE
1358# Throws     : Croaks on invalid invocation or on error generating the password
1359# Notes      :
1360# See Also   :
1361sub password{
1362    my $self = shift;
1363    _force_instance($self);
1364
1365    #
1366    # Generate the password
1367    #
1368    my $password = q{};
1369    eval{
1370        #
1371        # start by generating the needed parts of the password
1372        #
1373        _debug('starting to generate random words');
1374        my @words = $self->_random_words();
1375        _debug('got random words='.(join q{, }, @words));
1376        $self->_transform_case(\@words);
1377        $self->_substitute_characters(\@words); # TO DO
1378        my $separator = $self->_separator();
1379        _debug("got separator=$separator");
1380        my $pad_char = $self->_padding_char($separator);
1381        _debug("got pad_char=$pad_char");
1382
1383        #
1384        # Then assemble the finished password
1385        #
1386
1387        # start with the words and the separator
1388        $password = join $separator, @words;
1389        _debug("assembled base password: $password");
1390
1391        # next add the numbers front and back
1392        if($self->{_CONFIG}->{padding_digits_before} > 0){
1393            $password = $self->_random_digits($self->{_CONFIG}->{padding_digits_before}).$separator.$password;
1394        }
1395        if($self->{_CONFIG}->{padding_digits_after} > 0){
1396            $password = $password.$separator.$self->_random_digits($self->{_CONFIG}->{padding_digits_after});
1397        }
1398        _debug("added random digits (as configured): $password");
1399
1400
1401        # then finally add the padding characters
1402        if($self->{_CONFIG}->{padding_type} eq 'FIXED'){
1403            # simple fixed padding
1404            if($self->{_CONFIG}->{padding_characters_before} > 0){
1405                foreach my $c (1..$self->{_CONFIG}->{padding_characters_before}){
1406                    $password = $pad_char.$password;
1407                }
1408            }
1409            if($self->{_CONFIG}->{padding_characters_after} > 0){
1410                foreach my $c (1..$self->{_CONFIG}->{padding_characters_after}){
1411                    $password .= $pad_char;
1412                }
1413            }
1414        }elsif($self->{_CONFIG}->{padding_type} eq 'ADAPTIVE'){
1415            # adaptive padding
1416            my $pwlen = length $password;
1417            if($pwlen < $self->{_CONFIG}->{pad_to_length}){
1418                # if the password is shorter than the target length, padd it out
1419                while((length $password) < $self->{_CONFIG}->{pad_to_length}){
1420                    $password .= $pad_char;
1421                }
1422            }elsif($pwlen > $self->{_CONFIG}->{pad_to_length}){
1423                # if the password is too long, trim it
1424                $password = substr $password, 0, $self->{_CONFIG}->{pad_to_length};
1425            }
1426        }
1427        _debug("added padding (as configured): $password");
1428        1; # ensure true evaluation on successful execution
1429    }or do{
1430        _error("Failed to generate password with the following error: $EVAL_ERROR");
1431    };
1432
1433    # increment the passwords generated counter
1434    $self->{_PASSWORD_COUNTER}++;
1435
1436    # return the finished password
1437    return $password;
1438}
1439
1440#####-SUB-######################################################################
1441# Type       : INSTANCE
1442# Purpose    : Generate multiple passwords
1443# Returns    : An array of passwords as scalars
1444# Arguments  : 1. the number of passwords to generate as a scalar
1445# Throws     : Croaks on invalid invocation or invalid args
1446# Notes      :
1447# See Also   :
1448sub passwords{
1449    my @args = @_;
1450    my $self = shift @args;
1451    _force_instance($self);
1452
1453    # validate args
1454    state $args_check = compile(NonZeroPositiveInteger);
1455    my ($num_pws) = $args_check->(@args);
1456
1457    # generate the needed passwords
1458    my @passwords = ();
1459    my $num_to_do = $num_pws;
1460    while($num_to_do > 0){
1461        push @passwords, $self->password(); # could croak
1462        $num_to_do--;
1463    }
1464
1465    # return the passwords
1466    return @passwords;
1467}
1468
1469#####-SUB-######################################################################
1470# Type       : INSTANCE
1471# Purpose    : Generate n passwords and return them, and the entropy stats as a
1472#              JSON string.
1473# Returns    : A JSON string as a scalar representing a hashref contianing an
1474#              array of passwords indexed by 'passwords', and a hashref of
1475#              entropy stats indexed by 'stats'. The stats hashref itself is
1476#              indexed by: 'password_entropy_blind',
1477#              'password_permutations_blind', 'password_entropy_blind_min',
1478#              'password_entropy_blind_max', 'password_permutations_blind_max',
1479#              'password_entropy_seen' & 'password_permutations_seen'
1480# Arguments  : 1. the number of passwords to generate
1481# Throws     : Croaks on invalid invocation, invalid args, if there is a
1482#              problem generating the passwords, statistics, or converting the
1483#              results to a JSON string, or if the JSON module is not
1484#              available.
1485# Notes      :
1486# See Also   :
1487sub passwords_json{
1488    my @args = @_;
1489    my $self = shift @args;
1490    _force_instance($self);
1491
1492    # validate args
1493    state $args_check = compile(NonZeroPositiveInteger);
1494    my ($num_pws) = $args_check->(@args);
1495
1496    # try generate the passwords and stats - could croak
1497    my @passwords = $self->passwords($num_pws);
1498    my %stats = $self->stats();
1499
1500    # generate the hashref containing the results
1501    my $response_obj = {
1502        passwords => [@passwords],
1503        stats => {
1504            password_entropy_blind => $stats{password_entropy_blind},
1505            password_permutations_blind => $_CLASS->_render_bigint($stats{password_permutations_blind}),
1506            password_entropy_blind_min => $stats{password_entropy_blind_min},
1507            password_permutations_blind_min => $_CLASS->_render_bigint($stats{password_permutations_blind_min}),
1508            password_entropy_blind_max => $stats{password_entropy_blind_max},
1509            password_permutations_blind_max => $_CLASS->_render_bigint($stats{password_permutations_blind_max}),
1510            password_entropy_seen => $stats{password_entropy_seen},
1511            password_permutations_seen => $_CLASS->_render_bigint($stats{password_permutations_seen}),
1512        },
1513    };
1514
1515    # try generate the JSON string to return
1516    my $json_string = q{};
1517    eval{
1518        $json_string = JSON->new()->encode($response_obj);
1519        1; # ensure truthy evaluation on succesful execution
1520    }or do{
1521        _error("Failed to render hashref as JSON string with error: $EVAL_ERROR");
1522    };
1523
1524    # return the JSON string
1525    return $json_string;
1526}
1527
1528#####-SUB-######################################################################
1529# Type       : INSTANCE
1530# Purpose    : Return statistics about the instance
1531# Returns    : A hash of statistics indexed by the following keys:
1532#              * 'dictionary_source' - the source of the word list
1533#              * 'dictionary_words_total' - the total number of words loaded
1534#                from the dictionary file
1535#              * 'dictionary_words_filtered' - the number of words loaded from
1536#                the dictionary file that meet the lenght criteria set in the
1537#                loaded config
1538#              * 'dictionary_words_percent_available' - the percentage of the
1539#                total dictionary that is avialable for use with the loaded
1540#                config
1541#              * 'dictionary_filter_length_min' - the minimum length world
1542#                permitted by the filter
1543#              * 'dictionary_filter_length_max' - the maximum length world
1544#                permitted by the filter
1545#              * 'dictionary_contains_accents' - whether or not the filtered
1546#                list contains accented letters
1547#              * 'password_entropy_blind_min' - the entropy of the shortest
1548#                password this config can generate from the point of view of a
1549#                brute-force attacker in bits
1550#              * 'password_entropy_blind_max' - the entropy of the longest
1551#                password this config can generate from the point of view of a
1552#                brute-force attacker in bits
1553#              * 'password_entropy_blind' - the entropy of the average length
1554#                of password generated by this configuration from the point of
1555#                view of a brute-force attacker in bits
1556#              * 'password_entropy_seen' - the true entropy of passwords
1557#                generated by this instance assuming the dictionary and config
1558#                are known to the attacker in bits
1559#              * 'password_length_min' - the minimum length of passwords
1560#                generated with this instance's config
1561#              * 'password_length_max' - the maximum length of passwords
1562#                generated with this instance's config
1563#              * 'password_permutations_blind_min' - the number of permutations
1564#                a brute-froce attacker would have to try to be sure of success
1565#                on the shortest possible passwords geneated by this instance
1566#                as a Math::BigInt object
1567#              * 'password_permutations_blind_max' - the number of permutations
1568#                a brute-froce attacker would have to try to be sure of success
1569#                on the longest possible passwords geneated by this instance as
1570#                a Math::BigInt object
1571#              * 'password_permutations_blind' - the number of permutations
1572#                a brute-froce attacker would have to try to be sure of success
1573#                on the average length password geneated by this instance as a
1574#                Math::BigInt object
1575#              * 'password_permutations_seen' - the number of permutations an
1576#                attacker with a copy of the dictionary and config would need to
1577#                try to be sure of cracking a password generated by this
1578#                instance as a Math::BigInt object
1579#              * 'password_random_numbers_required' - the number of random
1580#                numbers needed to generate a single password using the loaded
1581#                config
1582#              * 'passwords_generated' - the number of passwords this instance
1583#                has generated
1584#              * 'randomnumbers_cached' - the number of random numbers
1585#                currently cached within the instance
1586#              * 'randomnumbers_cache_increment' - the number of random numbers
1587#                generated at once to re-plenish the cache when it's empty
1588#              * 'randomnumbers_source' - the name of the class used to
1589#                generate random numbers
1590# Arguments  : NONE
1591# Throws     : Croaks on invalid invocation
1592# Notes      :
1593# See Also   :
1594sub stats{
1595    my $self = shift;
1596    _force_instance($self);
1597
1598    # create a hash to assemble all the stats into
1599    my %stats = ();
1600
1601    # deal with the config-specific stats
1602    my %config_stats = $_CLASS->config_stats($self->{_CONFIG});
1603    $stats{password_length_min} = $config_stats{length_min};
1604    $stats{password_length_max} = $config_stats{length_max};
1605    $stats{password_random_numbers_required} = $config_stats{random_numbers_required};
1606
1607    # deal with the dictionary file
1608    my %dict_stats = $self->_calcualte_dictionary_stats();
1609    $stats{dictionary_source} = $dict_stats{source};
1610    $stats{dictionary_words_total} = $dict_stats{num_words_total};
1611    $stats{dictionary_words_filtered} = $dict_stats{num_words_filtered};
1612    $stats{dictionary_words_percent_available} = $dict_stats{percent_words_available};
1613    $stats{dictionary_filter_length_min} = $dict_stats{filter_length_min};
1614    $stats{dictionary_filter_length_max} = $dict_stats{filter_length_max};
1615    $stats{dictionary_contains_accents} = $dict_stats{contains_accents};
1616
1617    # deal with the entropy stats
1618    $stats{password_entropy_blind_min} = $self->{_CACHE_ENTROPYSTATS}->{entropy_blind_min};
1619    $stats{password_entropy_blind_max} = $self->{_CACHE_ENTROPYSTATS}->{entropy_blind_max};
1620    $stats{password_entropy_blind} = $self->{_CACHE_ENTROPYSTATS}->{entropy_blind};
1621    $stats{password_entropy_seen} = $self->{_CACHE_ENTROPYSTATS}->{entropy_seen};
1622    $stats{password_permutations_blind_min} = $self->{_CACHE_ENTROPYSTATS}->{permutations_blind_min};
1623    $stats{password_permutations_blind_max} = $self->{_CACHE_ENTROPYSTATS}->{permutations_blind_max};
1624    $stats{password_permutations_blind} = $self->{_CACHE_ENTROPYSTATS}->{permutations_blind};
1625    $stats{password_permutations_seen} = $self->{_CACHE_ENTROPYSTATS}->{permutations_seen};
1626
1627    # deal with password counter
1628    $stats{passwords_generated} = $self->{_PASSWORD_COUNTER};
1629
1630    # deal with the random number generator
1631    $stats{randomnumbers_cached} = scalar @{$self->{_CACHE_RANDOM}};
1632    $stats{randomnumbers_source} = blessed($self->{_RNG});
1633
1634    # return the stats
1635    return %stats;
1636}
1637
1638#####-SUB-######################################################################
1639# Type       : INSTANCE
1640# Purpose    : Represent the current state of the instance as a string.
1641# Returns    : Returns a multi-line string as as scalar containing details of the
1642#              loaded dictionary file, config, and caches
1643# Arguments  : NONE
1644# Throws     : Croaks on invalid invocation
1645# Notes      :
1646# See Also   :
1647sub status{
1648    my $self = shift;
1649    _force_instance($self);
1650
1651    # assemble the response
1652    my %stats = $self->stats();
1653    my $status = q{};
1654
1655    # the dictionary
1656    $status .= "*DICTIONARY*\n";
1657    $status .= "Source: $stats{dictionary_source}\n";
1658    $status .= "# words: $stats{dictionary_words_total}\n";
1659    $status .= "# words of valid length: $stats{dictionary_words_filtered} ($stats{dictionary_words_percent_available}%)\n";
1660    $status .= 'Contains Accented Characters: '.($stats{dictionary_contains_accents} ? 'YES' : 'NO')."\n";
1661
1662    # the config
1663    $status .= "\n*CONFIG*\n";
1664    $status .= $self->config_as_string();
1665
1666    # the random number cache
1667    $status .= "\n*RANDOM NUMBER CACHE*\n";
1668    $status .= "Random Number Generator: $stats{randomnumbers_source}\n";
1669    $status .= "# in cache: $stats{randomnumbers_cached}\n";
1670
1671    # password statistics
1672    $status .= "\n*PASSWORD STATISTICS*\n";
1673    if($stats{password_length_min} == $stats{password_length_max}){
1674        $status .= "Password length: $stats{password_length_max}\n";
1675        $status .= 'Permutations (brute-force): '.$_CLASS->_render_bigint($stats{password_permutations_blind_max})."\n";
1676    }else{
1677        $status .= "Password length: between $stats{password_length_min} & $stats{password_length_max}\n";
1678        $status .= 'Permutations (brute-force): between '.$_CLASS->_render_bigint($stats{password_permutations_blind_min}).q{ & }.$_CLASS->_render_bigint($stats{password_permutations_blind_max}).q{ (average }.$_CLASS->_render_bigint($stats{password_permutations_blind}).")\n";
1679    }
1680    $status .= 'Permutations (given dictionary & config): '.$_CLASS->_render_bigint($stats{password_permutations_seen})."\n";
1681    if($stats{password_length_min} == $stats{password_length_max}){
1682        $status .= "Entropy (brute-force): $stats{password_entropy_blind_max}bits\n";
1683    }else{
1684        $status .= "Entropy (Brute-Force): between $stats{password_entropy_blind_min}bits and $stats{password_entropy_blind_max}bits (average $stats{password_entropy_blind}bits)\n";
1685    }
1686    $status .= "Entropy (given dictionary & config): $stats{password_entropy_seen}bits\n";
1687    $status .= "# Random Numbers needed per-password: $stats{password_random_numbers_required}\n";
1688    $status .= "Passwords Generated: $stats{passwords_generated}\n";
1689
1690    # debug-only
1691    if($_Types_CLASS::_DEBUG){ ## no critic (ProtectPrivateVars)
1692        $status .= "\n*DEBUG INFO*\n";
1693        if($_Types_CLASS::_CAN_STACK_TRACE){ ## no critic (ProtectPrivateVars)
1694            $status .= "Devel::StackTrace IS installed\n";
1695        }else{
1696            $status .= "Devel::StackTrace is NOT installed\n";
1697        }
1698    }
1699
1700    # return the status
1701    return $status;
1702}
1703
1704#
1705# Regular Subs-----------------------------------------------------------------
1706#
1707
1708#####-SUB-######################################################################
1709# Type       : SUBROUTINE
1710# Purpose    : A functional interface to this library (exported)
1711# Returns    : A random password as a scalar
1712# Arguments  : See the constructor
1713# Throws     : Croaks on error
1714# Notes      : See the Constructor
1715# See Also   : For valid configuarion options see POD documentation below
1716sub hsxkpasswd{
1717    my @constructor_args = @_;
1718
1719    # try initialise an xkpasswd object
1720    my $hsxkpasswd;
1721    eval{
1722        $hsxkpasswd = $_CLASS->new(@constructor_args);
1723        1; # ensure truthy evaliation on successful execution
1724    } or do {
1725        _error("Failed to generate password with the following error: $EVAL_ERROR");
1726    };
1727
1728    # genereate and return a password - could croak
1729    return $hsxkpasswd->password();
1730}
1731
1732#
1733# 'Private' functions ---------------------------------------------------------
1734#
1735
1736#####-SUB-######################################################################
1737# Type       : INSTANCE ('PRIVATE')
1738# Purpose    : Clone the instance's config hashref
1739# Returns    : a hashref
1740# Arguments  : NONE
1741# Throws     : Croaks if called in an invalid way
1742# Notes      :
1743# See Also   :
1744sub _clone_config{
1745    my $self = shift;
1746    _force_instance($self);
1747
1748    # build the clone
1749    my $clone = $_CLASS->clone_config($self->{_CONFIG});
1750
1751    # if, and only if, debugging, validate the cloned config so errors in the
1752    # cloning code will trigger an exception
1753    if($self->{debug}){
1754        Config->check($clone) || _error('cloning error - clone is invalid: '.Config->get_message($clone));
1755    }
1756
1757    # return the clone
1758    return $clone;
1759}
1760
1761#####-SUB-######################################################################
1762# Type       : CLASS
1763# Purpose    : Distil all alphabets in a config hashref
1764# Returns    : always returns 1 (to keep perlcritic happy)
1765# Arguments  : 1) a config hashref
1766# Throws     : Croaks on invalid invocation or args
1767# Notes      :
1768# See Also   :
1769sub _distil_alphabets_inplace{
1770    my @args = @_;
1771    my $class = shift @args;
1772    _force_class($class);
1773
1774    # validate args
1775    state $args_check = compile(Config);
1776    my ($config) = $args_check->(@args);
1777
1778    # distil all three possible alphabet keys, if pressent
1779    if($config->{symbol_alphabet}){
1780        $config->{symbol_alphabet} = [$_CLASS->distil_to_symbol_alphabet($config->{symbol_alphabet})];
1781    }
1782    if($config->{padding_alphabet}){
1783        $config->{padding_alphabet} = [$_CLASS->distil_to_symbol_alphabet($config->{padding_alphabet})];
1784    }
1785    if($config->{separator_alphabet}){
1786        $config->{separator_alphabet} = [$_CLASS->distil_to_symbol_alphabet($config->{separator_alphabet})];
1787    }
1788
1789    # an explicit return
1790    return 1;
1791}
1792
1793#####-SUB-######################################################################
1794# Type       : CLASS (PRIVATE)
1795# Purpose    : Filter a word list based on word length
1796# Returns    : An array of words as scalars.
1797# Arguments  : 1. a reference to the array of words to filter.
1798#              2. the minimum allowed word length
1799#              3. the maximum allowed word length
1800#              4. OPTIONAL - named argument allow_accents with a value of 0 or
1801#                 1. If 1 is passed, accents will not be stripped from words,
1802#                 otherwise they will.
1803# Throws     : Croaks on invalid invocation, or if too few matching words found.
1804# Notes      : Unless the fourth argument is a truthy value, accents will be
1805#              stripped from the words.
1806# See Also   :
1807sub _filter_word_list{
1808    my @args = @_;
1809    my $class = shift @args;
1810    _force_class($class);
1811
1812    # validate args
1813    state $args_check = compile(
1814        ArrayRef[Str],
1815        WordLength,
1816        WordLength,
1817        slurpy Dict[allow_accents => Optional[TrueFalse]]
1818    );
1819    my ($word_list_ref, $min_len, $max_len, $options) = $args_check->(@args);
1820    my $allow_accents = $options->{allow_accents} || 0;
1821    unless($max_len >= $min_len){
1822        _error("minimum length (recived $min_len) cannot be greater than maximum length (received $max_len)");
1823    }
1824
1825    #build the array of words of appropriate length
1826    my @ans = ();
1827    WORD:
1828    foreach my $word (@{$word_list_ref}){
1829        # calcualte the grapheme length
1830        my $grapheme_length = $_CLASS->_grapheme_length($word);
1831
1832        # skip words shorter than the minimum
1833        next WORD if $grapheme_length < $min_len;
1834
1835        # skip words longer than the maximum
1836        next WORD if $grapheme_length > $max_len;
1837
1838        # strip accents unless they are explicitly allowed by the config
1839        unless($allow_accents){
1840            $word = unidecode($word);
1841        }
1842
1843        # store the word in the filtered list
1844        push @ans, $word;
1845    }
1846
1847    # return the list
1848    return @ans;
1849}
1850
1851#####-SUB-######################################################################
1852# Type       : CLASS (PRIVATE)
1853# Purpose    : Determine whether a word list contains accented characters
1854# Returns    : 1 if the word list does contain accented characters, and 0 if it
1855#              does not.
1856# Arguments  : 1. A reference to an array of words to test
1857# Throws     : NOTHING
1858# Notes      :
1859# See Also   :
1860sub _contains_accented_letters{
1861    my @args = @_;
1862    my $class = shift @args;
1863    _force_class($class);
1864
1865    # validate args
1866    state $args_check = compile(ArrayRef[Str]);
1867    my ($word_list_ref) = $args_check->(@args);
1868
1869    # assume no accented characters, test until 1 is found
1870    my $accent_found = 0;
1871    WORD:
1872    foreach my $word (@{$word_list_ref}){
1873        # check for accents by stripping accents and comparing to original
1874        my $word_accents_stripped = unidecode($word);
1875        unless($word eq $word_accents_stripped){
1876            $accent_found = 1;
1877            last WORD;
1878        }
1879    }
1880
1881    # return the list
1882    return $accent_found;
1883}
1884
1885#####-SUB-######################################################################
1886# Type       : INSTANCE (PRIVATE)
1887# Purpose    : Generate a random integer greater than 0 and less than a given
1888#              maximum value.
1889# Returns    : A random integer as a scalar.
1890# Arguments  : 1. the min value for the random number (as a positive integer)
1891# Throws     : Croaks if invoked in an invalid way, with invalid args, of if
1892#              there is a problem generating random numbers (should the cache)
1893#              be empty.
1894# Notes      : The random cache is used as the source for the randomness. If the
1895#              random pool is empty, this function will replenish it.
1896# See Also   :
1897sub _random_int{
1898    my @args = @_;
1899    my $self = shift @args;
1900    _force_instance($self);
1901
1902    # validate args
1903    state $args_check = compile(NonZeroPositiveInteger);
1904    my ($max) = $args_check->(@args);
1905
1906    # calculate the random number
1907    my $ans = ($self->_rand() * 1_000_000) % $max;
1908
1909    # return it
1910    _debug("returning $ans (max=$max)");
1911    return $ans;
1912}
1913
1914#####-SUB-######################################################################
1915# Type       : INSTANCE (PRIVATE)
1916# Purpose    : Generate a number of random integers.
1917# Returns    : A scalar containing a number of random integers.
1918# Arguments  : 1. The number of random integers to generate
1919# Throws     : Croaks on invalid invocation, or if there is a problem generating
1920#              the needed randomness.
1921# Notes      :
1922# See Also   :
1923sub _random_digits{
1924    my @args = @_;
1925    my $self = shift @args;
1926    _force_instance($self);
1927
1928    # validate args
1929    state $args_check = compile(NonZeroPositiveInteger);
1930    my ($num) = $args_check->(@args);
1931
1932    # assemble the response
1933    my $ans = q{};
1934    foreach my $n (1..$num){
1935        $ans .= $self->_random_int(10);
1936    }
1937
1938    # return the response
1939    return $ans;
1940}
1941
1942#####-SUB-######################################################################
1943# Type       : INSTANCE (PRIVATE)
1944# Purpose    : Return the next random number in the cache, and if needed,
1945#              replenish it.
1946# Returns    : A decimal number between 0 and 1
1947# Arguments  : NONE
1948# Throws     : Croaks if invoked in an invalid way, or if there is problem
1949#              replenishing the random cache.
1950# Notes      :
1951# See Also   :
1952sub _rand{
1953    my $self = shift;
1954    _force_instance($self);
1955
1956    # get the next random number from the cache
1957    my $num = shift @{$self->{_CACHE_RANDOM}};
1958    if(!defined $num){
1959        # the cache was empty - so try top up the random cache - could croak
1960        _debug('random cache empty - attempting to replenish');
1961        $self->_increment_random_cache();
1962
1963        # try shift again
1964        $num = shift @{$self->{_CACHE_RANDOM}};
1965    }
1966
1967    # make sure we got a valid random number
1968    unless(defined $num && $num =~ m/^\d+([.]\d+)?$/sx && $num >= 0 && $num <= 1){
1969        _error('found invalid entry in random cache');
1970    }
1971
1972    # return the random number
1973    _debug("returning $num (".(scalar @{$self->{_CACHE_RANDOM}}).' remaining in cache)');
1974    return $num;
1975}
1976
1977#####-SUB-######################################################################
1978# Type       : INSTANCE (PRIVATE)
1979# Purpose    : Append random numbers to the cache.
1980# Returns    : Always returns 1.
1981# Arguments  : NONE
1982# Throws     : Croaks if incorrectly invoked or if the random generating
1983#              function fails to produce random numbers.
1984# Notes      :
1985# See Also   :
1986sub _increment_random_cache{
1987    my $self = shift;
1988    _force_instance($self);
1989
1990    # genereate the random numbers
1991    my @random_numbers = $self->{_RNG}->random_numbers($_CLASS->config_random_numbers_required($self->{_CONFIG}));
1992    _debug('generated '.(scalar @random_numbers).' random numbers ('.(join q{, }, @random_numbers).')');
1993
1994    # validate them
1995    unless(scalar @random_numbers){
1996        _error('random function did not return any random numbers');
1997    }
1998    foreach my $num (@random_numbers){
1999        unless($num =~ m/^1|(0([.]\d+)?)$/sx){
2000            _error("random function returned and invalid value ($num)");
2001        }
2002    }
2003
2004    # add them to the cache
2005    foreach my $num (@random_numbers){
2006        push @{$self->{_CACHE_RANDOM}}, $num;
2007    }
2008
2009    # always return 1 (to keep PerlCritic happy)
2010    return 1;
2011}
2012
2013#####-SUB-######################################################################
2014# Type       : INSTANCE (PRIVATE)
2015# Purpose    : Get the required number of random words from the loaded words
2016#              file
2017# Returns    : An array of words
2018# Arguments  : NONE
2019# Throws     : Croaks on invalid invocation or error generating random numbers
2020# Notes      : The number of words generated is determined by the num_words
2021#              config key.
2022# See Also   :
2023sub _random_words{
2024    my $self = shift;
2025    _force_instance($self);
2026
2027    # get the random words
2028    my @ans = ();
2029    _debug('about to generate '.$self->{_CONFIG}->{num_words}.' words');
2030    while ((scalar @ans) < $self->{_CONFIG}->{num_words}){
2031        my $word = $self->{_CACHE_DICTIONARY_LIMITED}->[$self->_random_int(scalar @{$self->{_CACHE_DICTIONARY_LIMITED}})];
2032        _debug("generate word=$word");
2033        push @ans, $word;
2034    }
2035
2036    # return the list of random words
2037    _debug('returning '.(scalar @ans).' words');
2038    return @ans;
2039}
2040
2041#####-SUB-######################################################################
2042# Type       : INSTANCE (PRIVATE)
2043# Purpose    : Get the separator character to use based on the loaded config.
2044# Returns    : A scalar containing the separator, which could be an empty string.
2045# Arguments  : NONE
2046# Throws     : Croaks on invalid invocation, or if there is a problem generating
2047#              any needed random numbers.
2048# Notes      : The character returned is controlled by the config variable
2049#              separator_character
2050# See Also   :
2051sub _separator{
2052    my $self = shift;
2053    _force_instance($self);
2054
2055    # figure out the separator character
2056    my $sep = $self->{_CONFIG}->{separator_character};
2057    if ($sep eq 'NONE'){
2058        $sep = q{};
2059    }elsif($sep eq 'RANDOM'){
2060        if(defined $self->{_CONFIG}->{separator_alphabet}){
2061            $sep = $self->{_CONFIG}->{separator_alphabet}->[$self->_random_int(scalar @{$self->{_CONFIG}->{separator_alphabet}})];
2062        }else{
2063            $sep = $self->{_CONFIG}->{symbol_alphabet}->[$self->_random_int(scalar @{$self->{_CONFIG}->{symbol_alphabet}})];
2064        }
2065    }
2066
2067    # return the separator character
2068    return $sep
2069}
2070
2071#####-SUB-######################################################################
2072# Type       : INSTANCE (PRIVATE)
2073# Purpose    : Return the padding character based on the loaded config.
2074# Returns    : A scalar containing the padding character, which could be an
2075#              empty string.
2076# Arguments  : 1. the separator character being used to generate the password
2077# Throws     : Croaks on invalid invocation, or if there is a problem geneating
2078#              any needed random numbers.
2079# Notes      : The character returned is determined by a combination of the
2080#              padding_type & padding_character config variables.
2081# See Also   :
2082sub _padding_char{
2083    my $self = shift;
2084    my $sep = shift;
2085
2086
2087    # validate args - doing it the old-fassioned way because the separator will
2088    # be an empty string if the separator is set to 'NONE'
2089    _force_instance($self);
2090    if($sep){
2091        unless(Symbol->check($sep)){
2092            _error('first argument must be an empty string or a valid Symbol');
2093        }
2094    }
2095
2096    # if there is no padding character needed, return an empty string
2097    if($self->{_CONFIG}->{padding_type} eq 'NONE'){
2098        return q{};
2099    }
2100
2101    # if we got here we do need a character, so generate one as appropriate
2102    my $padc = $self->{_CONFIG}->{padding_character};
2103    if($padc eq 'SEPARATOR'){
2104        $padc = $sep;
2105    }elsif($padc eq 'RANDOM'){
2106        if(defined $self->{_CONFIG}->{padding_alphabet}){
2107            $padc = $self->{_CONFIG}->{padding_alphabet}->[$self->_random_int(scalar @{$self->{_CONFIG}->{padding_alphabet}})];
2108        }else{
2109            $padc = $self->{_CONFIG}->{symbol_alphabet}->[$self->_random_int(scalar @{$self->{_CONFIG}->{symbol_alphabet}})];
2110        }
2111    }
2112
2113    # return the padding character
2114    return $padc;
2115}
2116
2117#####-SUB-######################################################################
2118# Type       : INSTANCE (PRIVATE)
2119# Purpose    : Apply the case transform (if any) specified in the loaded config.
2120# Returns    : Always returns 1 (to keep PerlCritic happy)
2121# Arguments  : 1. A reference to the array contianing the words to be
2122#                 transformed.
2123# Throws     : Croaks on invalid invocation or if there is a problem generating
2124#              any needed random numbers.
2125# Notes      : The transformations applied are controlled by the case_transform
2126#              config variable.
2127# See Also   :
2128sub _transform_case{
2129    my @args = @_;
2130    my $self = shift @args;
2131    _force_instance($self);
2132
2133    # validate args
2134    state $args_check = compile(ArrayRef[Str]);
2135    my ($words_ref) = $args_check->(@args);
2136
2137    # if the transform is set to nothing, then just return
2138    if($self->{_CONFIG}->{case_transform} eq 'NONE'){
2139        return 1;
2140    }
2141
2142    # apply the appropriate transform
2143    ## no critic (ProhibitCascadingIfElse);
2144    if($self->{_CONFIG}->{case_transform} eq 'UPPER'){
2145        foreach my $i (0..((scalar @{$words_ref}) - 1)){
2146            $words_ref->[$i] = uc $words_ref->[$i];
2147        }
2148    }elsif($self->{_CONFIG}->{case_transform} eq 'LOWER'){
2149        foreach my $i (0..((scalar @{$words_ref}) - 1)){
2150            $words_ref->[$i] = lc $words_ref->[$i];
2151        }
2152    }elsif($self->{_CONFIG}->{case_transform} eq 'CAPITALISE'){
2153        foreach my $i (0..((scalar @{$words_ref}) - 1)){
2154            $words_ref->[$i] = ucfirst lc $words_ref->[$i];
2155        }
2156    }elsif($self->{_CONFIG}->{case_transform} eq 'INVERT'){
2157        foreach my $i (0..((scalar @{$words_ref}) - 1)){
2158            $words_ref->[$i] = lcfirst uc $words_ref->[$i];
2159        }
2160    }elsif($self->{_CONFIG}->{case_transform} eq 'ALTERNATE'){
2161        # randomly decide whether to capitalise on odd or even
2162        my $rand_bias = ($self->_random_int(2) % 2 == 0) ? 1 : 0;
2163        foreach my $i (0..((scalar @{$words_ref}) - 1)){
2164            my $word = $words_ref->[$i];
2165            if(($i + $rand_bias) % 2 == 0){
2166                $word = lc $word;
2167            }else{
2168                $word = uc $word;
2169            }
2170            $words_ref->[$i] = $word;
2171        }
2172    }elsif($self->{_CONFIG}->{case_transform} eq 'RANDOM'){
2173        foreach my $i (0..((scalar @{$words_ref}) - 1)){
2174            my $word = $words_ref->[$i];
2175            if($self->_random_int(2) % 2 == 0){
2176                $word = uc $word;
2177            }else{
2178                $word = lc $word;
2179            }
2180            $words_ref->[$i] = $word;
2181        }
2182    }
2183    ## use critic
2184
2185    return 1; # just to to keep PerlCritic happy
2186}
2187
2188#####-SUB-######################################################################
2189# Type       : INSTANCE (PRIVATE)
2190# Purpose    : Apply any case transforms specified in the loaded config.
2191# Returns    : Always returns 1 (to keep PerlCritic happy)
2192# Arguments  : 1. a reference to an array containing the words that will make up
2193#                 the password.
2194# Throws     : Croaks on invalid invocation or invalid args.
2195# Notes      : The substitutions that will be applied are specified in the
2196#              character_substitutions config variable.
2197# See Also   :
2198sub _substitute_characters{
2199    my @args = @_;
2200    my $self = shift @args;
2201    _force_instance($self);
2202
2203    # validate args
2204    state $args_check = compile(ArrayRef[Str]);
2205    my ($words_ref) = $args_check->(@args);
2206
2207    # if no substitutions are defined, do nothing
2208    unless(defined $self->{_CONFIG}->{character_substitutions} && (scalar keys %{$self->{_CONFIG}->{character_substitutions}})){
2209        return 1;
2210    }
2211
2212    # If we got here, go ahead and apply the substitutions
2213    foreach my $i (0..((scalar @{$words_ref}) - 1)){
2214        my $word = $words_ref->[$i];
2215        foreach my $char (keys %{$self->{_CONFIG}->{character_substitutions}}){
2216            my $sub = $self->{_CONFIG}->{character_substitutions}->{$char};
2217            $word =~ s/$char/$sub/sxg;
2218        }
2219        $words_ref->[$i] = $word;
2220    }
2221
2222    # always return 1 to keep PerlCritic happy
2223    return 1;
2224}
2225
2226#####-SUB-######################################################################
2227# Type       : CLASS (PRIVATE)
2228# Purpose    : Perform sanity checks on all the config key definitions
2229# Returns    : Always returns 1 (to keep PerlCritic happy)
2230# Arguments  : NONE
2231# Throws     : Croaks if there is a problem with a key definition.
2232# Notes      : The function is designed to be called from the constructor when
2233#              in debug mode, so it prints information on what it's doing
2234#              to STDERR.
2235# See Also   :
2236sub _check_config_key_definitions{
2237    # get a reference to the config key definitions form the Types class
2238    my $key_definitions = $_TYPES_CLASS->_config_keys();
2239
2240    # loop through each key definition and do some sanity checks
2241    my $num_problems = 0;
2242    foreach my $key_name ($_CLASS->defined_config_keys()){
2243        _debug("checking config key '$key_name'");
2244        unless(ConfigKeyDefinition->check($key_definitions->{$key_name})){
2245            _warn(ConfigKeyDefinition->get_message($key_definitions->{$key_name}));
2246            $num_problems++;
2247        }
2248    }
2249    if($num_problems == 0){
2250        _debug('all config key definitions OK');
2251    }else{
2252        _error("there are errors in $num_problems config key definitions - fix these before continuing");
2253    }
2254
2255    # to keep perlcritic happy
2256    return 1;
2257}
2258
2259#####-SUB-######################################################################
2260# Type       : CLASS (PRIVATE)
2261# Purpose    : Perform sanity checks on all defined presets
2262# Returns    : Always returns 1 (to keep perlcritic happy)
2263# Arguments  : NONE
2264# Throws     : Croaks if there is a problem with a preset.
2265# Notes      : The function is designed to be called from the constructor when
2266#              in debug mode, so it prints information on what it's doing
2267#              to STDERR.
2268# See Also   :
2269sub _check_preset_definitions{
2270    # get a reference to the preset definitions from the types class
2271    my $preset_defs = $_TYPES_CLASS->_presets();
2272
2273    # loop through all presets and perform sanity checks
2274    my $num_problems = 0;
2275    foreach my $preset_name (sort keys %{$preset_defs}){
2276        _debug("checking preset '$preset_name'");
2277        unless(PresetDefinition->check($preset_defs->{$preset_name})){
2278            _warn(PresetDefinition->get_message($preset_defs->{$preset_name}));
2279            $num_problems++;
2280        }
2281    }
2282    if($num_problems == 0){
2283        _debug('all presets OK');
2284    }else{
2285        _error("there are errors in $num_problems presets - fix these before continuing");
2286    }
2287
2288    # to keep perlcritic happy
2289    return 1;
2290}
2291
2292#####-SUB-######################################################################
2293# Type       : CLASS (PRIVATE)
2294# Purpose    : Create an RNG object that is as secure as possible.
2295# Returns    : An instance of a class that extends Crypt::HSXKPasswd::RNG.
2296# Arguments  : NONE
2297# Throws     : This function issues a warning if it has to fall back to
2298#              Crypt::HSXKPasswd::RNG::Basic.
2299# Notes      : This function works its way through the constructurs for the
2300#              following RNG classes in the following order, returing the first
2301#              successfully instantiate object:
2302#              1) Crypt::HSXKPasswd::RNG::Math_Random_Secure (using
2303#                 Math::Random::Secure)
2304#              2) Crypt::HSXKPasswd::RNG::Data_Entropy (using
2305#                 Data::Entropy::Algorithms)
2306#              3) Crypt::HSXKPasswd::RNG::DevUrandom (reads from /dev/urandom)
2307#              4) Crypt::HSXKPasswd::RNG::Basic (using Perl's built-in rand())
2308#              This ordering is based on security and speed - all but Basic are
2309#              good from a secutrity point of view, but Math::Random::Secure is
2310#              over six times faster than Data::Entropy::Algorithms, so it is
2311#              reduced to second place. Speed tested wth the commands:
2312#              time perl -MMath::Random::Secure -e "foreach my \$n (0..1000000){Math::Random::Secure::rand();}"
2313#              time perl -MData::Entropy::Algorithms -e "foreach my \$n (0..1000000){Data::Entropy::Algorithms::rand();}"
2314# See Also   :
2315sub _best_available_rng{
2316    # try the good entropy sources in order
2317    my $rng;
2318    eval{
2319        $rng = Crypt::HSXKPasswd::RNG::Math_Random_Secure->new(); # will return a truthy value on success
2320    }or do{
2321        _debug("Failed to instantiate a Crypt::HSXKPasswd::RNG::Math_Random_Secure object with error: $EVAL_ERROR");
2322    };
2323    return $rng if $rng;
2324    eval{
2325        $rng = Crypt::HSXKPasswd::RNG::Data_Entropy->new(); # will return a truthy value on success
2326    }or do{
2327        _debug("Failed to instantiate a Crypt::HSXKPasswd::RNG::Data_Entropy object with error: $EVAL_ERROR");
2328    };
2329    return $rng if $rng;
2330    eval{
2331        $rng = Crypt::HSXKPasswd::RNG::DevUrandom->new(); # will return a truthy value on success
2332    }or do{
2333        _debug("Failed to instantiate a Crypt::HSXKPasswd::RNG::DevUrandom object with error: $EVAL_ERROR");
2334    };
2335    return $rng if $rng;
2336
2337    # if we got here, no secure RNGs were avaialable, so warn, then return an instance of the basic RNG
2338    _warn(q{using Perl's built-in rand() function for random number generation. This is secure enough for most users, but you can get more secure random numbers by installing Math::Random::Secure or Data::Entropy::Algorithms});
2339    return Crypt::HSXKPasswd::RNG::Basic->new();
2340}
2341
2342#####-SUB-######################################################################
2343# Type       : INSTANCE (PRIVATE)
2344# Purpose    : Gather entropy stats for the combination of the loaded config
2345#              and dictionary.
2346# Returns    : A hash of stats indexed by:
2347#              * 'permutations_blind_min' - the number of permutations to be
2348#                tested by an attacker with no knowledge of the dictionary file
2349#                used, or the config used, assuming the minimum possible
2350#                password length from the given config (as BigInt)
2351#              * 'permutations_blind_max' - the number of permutations to be
2352#                tested by an attacker with no knowledge of the dictionary file
2353#                used, or the cofig file used, assuming the maximum possible
2354#                password length fom the given config (as BigInt)
2355#              * 'permutations_blind' - the number of permutations for the
2356#                average password length for the given config (as BigInt)
2357#              * 'permutations_seen' - the number of permutations to be tested
2358#                by an attacker with full knowledge of the dictionary file and
2359#                configuration used (as BigInt)
2360#              * 'entropy_blind_min' - permutations_blind_min converted to bits
2361#              * 'entropy_blind_max' - permutations_blind_max converted to bits
2362#              * 'entropy_blind' - permutations_blind converted to bits
2363#              * 'entropy_seen' - permutations_seen converted to bits
2364# Arguments  : NONE
2365# Throws     : Croaks on invalid invocation
2366# Notes      : This function uses config_stats() to determined the longest and
2367#              shortest password lengths, so the caveat that function has
2368#              when it comes to multi-character substitutions applies here too.
2369#              This function assumes no accented characters (at least for now).
2370#              For the blind calculations, if any single symbol is present, a
2371#              search-space of 33 symbols is assumed (same as password
2372#              haystacks page)
2373# See Also   : config_stats()
2374sub _calculate_entropy_stats{
2375    my $self = shift;
2376    _force_instance($self);
2377
2378    my %ans = ();
2379
2380    # get the password length details for the config
2381    my %config_stats = $_CLASS->config_stats($self->{_CONFIG}, suppress_warnings => 1);
2382    my $b_length_min = Math::BigInt->new($config_stats{length_min});
2383    my $b_length_max = Math::BigInt->new($config_stats{length_max});
2384
2385    # calculate the blind permutations - (based purely on length and alphabet)
2386    my $alphabet_count = 26; # all passwords have at least one case of letters
2387    if($self->{_CONFIG}->{case_transform} =~ m/^(ALTERNATE)|(CAPITALISE)|(INVERT)|(RANDOM)$/sx){
2388        $alphabet_count += 26; # these configs guarantee a mix of cases
2389    }
2390    if($self->{_CONFIG}->{padding_digits_before} > 0 || $self->{_CONFIG}->{padding_digits_after} > 0){
2391        $alphabet_count += 10; # these configs guarantee digits in the mix
2392    }
2393    if($self->_passwords_will_contain_symbol() || $self->{_CACHE_CONTAINS_ACCENTS}){
2394        $alphabet_count += 33; # the config almost certainly includes a symbol, so add 33 to the alphabet (like password haystacks does)
2395    }
2396    my $b_alphabet_count = Math::BigInt->new($alphabet_count);
2397    my $length_avg = round(($config_stats{length_min} + $config_stats{length_max})/2);
2398    $ans{permutations_blind_min} = $b_alphabet_count->copy()->bpow($b_length_min); #$alphabet_count ** $length_min;
2399    _debug('got permutations_blind_min='.$ans{permutations_blind_min});
2400    $ans{permutations_blind_max} = $b_alphabet_count->copy()->bpow($b_length_max); #$alphabet_count ** $length_max;
2401    _debug('got permutations_blind_max='.$ans{permutations_blind_max});
2402    $ans{permutations_blind} = $b_alphabet_count->copy()->bpow(Math::BigInt->new($length_avg)); #$alphabet_count ** $length_avg;
2403    _debug('got permutations_blind='.$ans{permutations_blind});
2404
2405    # calculate the seen permutations
2406    my $num_words = scalar @{$self->{_CACHE_DICTIONARY_LIMITED}};
2407    my $b_num_words = Math::BigInt->new($num_words);
2408    my $b_seen_perms = Math::BigInt->new('0');
2409    # start with the permutations from the chosen words
2410    $b_seen_perms->badd($b_num_words->copy()->bpow(Math::BigInt->new($self->{_CONFIG}->{num_words}))); # += $num_words ** $self->{_CONFIG}->{num_words};
2411    # then add the extra randomness from the case transformations (if any)
2412    if($self->{_CONFIG}->{case_transform} eq 'RANDOM'){
2413        # multiply by two for each word
2414        for my $n (1..$self->{_CONFIG}->{num_words}){
2415            $b_seen_perms->bmul(Math::BigInt->new(2));
2416        }
2417    }elsif($self->{_CONFIG}->{case_transform} eq 'ALTERNATE'){
2418        # multiply by two for the one random decision about whether or capitalise the odd or even words
2419        $b_seen_perms->bmul(Math::BigInt->new(2));
2420    }
2421    # multiply in the permutations from the separator (if any - i.e. if it's randomly chosen)
2422    if($self->{_CONFIG}->{separator_character} eq 'RANDOM'){
2423        if(defined $self->{_CONFIG}->{separator_alphabet}){
2424            $b_seen_perms->bmul(Math::BigInt->new(scalar @{$self->{_CONFIG}->{separator_alphabet}}));
2425        }else{
2426            $b_seen_perms->bmul(Math::BigInt->new(scalar @{$self->{_CONFIG}->{symbol_alphabet}}));
2427        }
2428    }
2429    # multiply in the permutations from the padding character (if any - i.e. if it's randomly chosen)
2430    if($self->{_CONFIG}->{padding_type} ne 'NONE' && $self->{_CONFIG}->{padding_character} eq 'RANDOM'){
2431        if(defined $self->{_CONFIG}->{padding_alphabet}){
2432            $b_seen_perms->bmul(Math::BigInt->new(scalar @{$self->{_CONFIG}->{padding_alphabet}}));
2433        }else{
2434            $b_seen_perms->bmul(Math::BigInt->new(scalar @{$self->{_CONFIG}->{symbol_alphabet}}));
2435        }
2436    }
2437    # multiply in the permutations from the padding digits (if any)
2438    my $num_padding_digits = $self->{_CONFIG}->{padding_digits_before} + $self->{_CONFIG}->{padding_digits_after};
2439    while($num_padding_digits > 0){
2440        $b_seen_perms->bmul(Math::BigInt->new('10'));
2441        $num_padding_digits--;
2442    }
2443    $ans{permutations_seen} = $b_seen_perms;
2444    _debug('got permutations_seen='.$ans{permutations_seen});
2445
2446    # calculate the entropy values based on the permutations
2447    $ans{entropy_blind_min} = $ans{permutations_blind_min}->copy()->blog(2)->numify();
2448    _debug('got entropy_blind_min='.$ans{entropy_blind_min});
2449    $ans{entropy_blind_max} = $ans{permutations_blind_max}->copy()->blog(2)->numify();
2450    _debug('got entropy_blind_max='.$ans{entropy_blind_max});
2451    $ans{entropy_blind} = $ans{permutations_blind}->copy()->blog(2)->numify();
2452    _debug('got entropy_blind='.$ans{entropy_blind});
2453    $ans{entropy_seen} = $ans{permutations_seen}->copy()->blog(2)->numify();
2454    _debug('got entropy_seen='.$ans{entropy_seen});
2455
2456    # return the stats
2457    return %ans;
2458}
2459
2460#####-SUB-######################################################################
2461# Type       : INSTANCE (PRIVATE)
2462# Purpose    : Calculate statistics on the loaded dictionary file
2463# Returns    : A hash of statistics indexed by:
2464#              * 'source' - the source for the word list
2465#              * 'filter_length_min' - the minimum allowed word length
2466#              * 'filter_length_max' - the maximum allowed word length
2467#              * 'num_words_total' - the number of words in the un-filtered
2468#                dictionary file
2469#              * 'num_words_filtered' - the number of words after filtering on
2470#                size limitations
2471#              * 'percent_words_available' - the percentage of the un-filtered
2472#                words remaining in the filtered words list
2473#              * 'contains_accents' - whether or not the filtered word list
2474#                contains accented letter
2475# Arguments  : NONE
2476# Throws     : Croaks on invalid invocation
2477# Notes      :
2478# See Also   :
2479sub _calcualte_dictionary_stats{
2480    my $self = shift;
2481    _force_instance($self);
2482
2483    # create a hash to aggregate the stats into
2484    my %ans = ();
2485
2486    # deal with agregate numbers first
2487    $ans{source} = $self->{_DICTIONARY_SOURCE}->source();
2488    $ans{num_words_total} = scalar @{$self->{_CACHE_DICTIONARY_FULL}};
2489    $ans{num_words_filtered} = scalar @{$self->{_CACHE_DICTIONARY_LIMITED}};
2490    $ans{percent_words_available} = round(($ans{num_words_filtered}/$ans{num_words_total}) * 100);
2491    $ans{filter_length_min} = $self->{_CONFIG}->{word_length_min};
2492    $ans{filter_length_max} = $self->{_CONFIG}->{word_length_max};
2493    $ans{contains_accents} = $self->{_CACHE_CONTAINS_ACCENTS};
2494
2495    # return the stats
2496    return %ans;
2497}
2498
2499#####-SUB-######################################################################
2500# Type       : INSTANCE (PRIVATE)
2501# Purpose    : A function to check if passwords genereated with the loaded
2502#              config would contian a symbol
2503# Returns    : 1 if the config will produce passwords with a symbol, or 0
2504#              otherwise
2505# Arguments  : NONE
2506# Throws     : Croaks on invalid invocation
2507# Notes      : This function is used by _calculate_entropy_stats() to figure out
2508#              whether or not there are symbols in the alphabet when calculating
2509#              the brute-force entropy.
2510# See Also   : _calculate_entropy_stats()
2511sub _passwords_will_contain_symbol{
2512    my $self = shift;
2513    _force_instance($self);
2514
2515    # assume no symbol, if we find one, set to 1
2516    my $symbol_used = 0;
2517
2518    ## no critic (ProhibitEnumeratedClasses);
2519    # first check the padding
2520    if($self->{_CONFIG}->{padding_type} ne 'NONE'){
2521        if($self->{_CONFIG}->{padding_character} eq 'RANDOM'){
2522            if(defined $self->{_CONFIG}->{padding_alphabet}){
2523                my $all_pad_chars = join q{}, @{$self->{_CONFIG}->{padding_alphabet}};
2524                if($all_pad_chars =~ m/[^0-9a-zA-Z]/sx){ # if we have just one non-word character
2525                    $symbol_used = 1;
2526                }
2527            }else{
2528                my $all_pad_chars = join q{}, @{$self->{_CONFIG}->{symbol_alphabet}};
2529                if($all_pad_chars =~ m/[^0-9a-zA-Z]/sx){ # if we have just one non-word character
2530                    $symbol_used = 1;
2531                }
2532            }
2533        }else{
2534            if($self->{_CONFIG}->{padding_character} =~ m/[^0-9a-zA-Z]/sx){ # the padding character is not a word character
2535                $symbol_used = 1;
2536            }
2537        }
2538    }
2539
2540    # then check the separator
2541    if($self->{_CONFIG}->{separator_character} ne 'NONE'){
2542        if($self->{_CONFIG}->{separator_character} eq 'RANDOM'){
2543            if(defined $self->{_CONFIG}->{separator_alphabet}){
2544                my $all_sep_chars = join q{}, @{$self->{_CONFIG}->{separator_alphabet}};
2545                if($all_sep_chars =~ m/[^0-9a-zA-Z]/sx){ # if we have just one non-word character
2546                    $symbol_used = 1;
2547                }
2548            }else{
2549                my $all_sep_chars = join q{}, @{$self->{_CONFIG}->{symbol_alphabet}};
2550                if($all_sep_chars =~ m/[^0-9a-zA-Z]/sx){ # if we have just one non-word character
2551                    $symbol_used = 1;
2552                }
2553            }
2554        }else{
2555            if($self->{_CONFIG}->{separator_character} =~ m/[^0-9a-zA-Z]/sx){ # the separator is not a word character
2556                $symbol_used = 1;
2557            }
2558        }
2559    }
2560    ## use critic
2561
2562    # return
2563    return $symbol_used;
2564}
2565
2566#####-SUB-######################################################################
2567# Type       : INSTANCE (PRIVATE)
2568# Purpose    : Update the entropy stats cache (and warn of low entropy if
2569#              appropriate)
2570# Returns    : always returns 1 (to keep perlcritic happy)
2571# Arguments  : NONE
2572# Throws     : Croaks on invalid invocation
2573# Notes      : This function should only be called from config() or dictionary().
2574#              The entropy is calculated with _calculate_entropy_stats(), and a
2575#              reference to the hash returned from that function is stored in
2576#              $self->{_CACHE_ENTROPYSTATS}.
2577# See Also   : _calculate_entropy_stats(), config() & dictionary()
2578sub _update_entropystats_cache{
2579    my $self = shift;
2580    _force_instance($self);
2581
2582    # do nothing if the dictionary has not been loaded yet (should only happen while the constructor is building an instance)
2583    return 1 unless($self->{_DICTIONARY_SOURCE} && blessed($self->{_DICTIONARY_SOURCE}) && $self->{_DICTIONARY_SOURCE}->isa($_DICTIONARY_BASE_CLASS));
2584
2585    # calculate and store the entropy stats
2586    my %stats = $self->_calculate_entropy_stats();
2587    $self->{_CACHE_ENTROPYSTATS} = \%stats;
2588
2589    # warn if we need to
2590    unless(uc $_ENTROPY_WARNINGS eq 'NONE'){
2591        # blind warnings are always needed if the level is not 'NONE'
2592        if($self->{_CACHE_ENTROPYSTATS}->{entropy_blind_min} < $_ENTROPY_MIN_BLIND){
2593            _warn('for brute force attacks, the combination of the loaded config and dictionary produces an entropy of '.$self->{_CACHE_ENTROPYSTATS}->{entropy_blind_min}.'bits, below the minimum recommended '.$_ENTROPY_MIN_BLIND.'bits');
2594        }
2595
2596        # seen warnings if the cut-off is not 'BLIND'
2597        unless(uc $_ENTROPY_WARNINGS eq 'BLIND'){
2598            if($self->{_CACHE_ENTROPYSTATS}->{entropy_seen} < $_ENTROPY_MIN_SEEN){
2599                _warn('for attacks assuming full knowledge, the combination of the loaded config and dictionary produces an entropy of '.$self->{_CACHE_ENTROPYSTATS}->{entropy_seen}.'bits, below the minimum recommended '.$_ENTROPY_MIN_SEEN.'bits');
2600            }
2601        }
2602    }
2603
2604    # to keep perl critic happy
2605    return 1;
2606}
2607
2608#####-SUB-######################################################################
2609# Type       : CLASS (PRIVATE)
2610# Purpose    : To nicely print a Math::BigInt object
2611# Returns    : a string representing the object's value in scientific notation
2612#              with 1 digit before the decimal and 2 after
2613# Arguments  : 1. a Math::BigInt object
2614# Throws     : Croaks on invalid invocation or args
2615# Notes      :
2616# See Also   :
2617sub _render_bigint{
2618    my @args = @_;
2619    my $class = shift @args;
2620    _force_class($class);
2621
2622    # validate args
2623    state $args_check = compile(InstanceOf['Math::BigInt']);
2624    my ($bigint) = $args_check->(@args);
2625
2626    # convert the bigint to an array of characters
2627    my @chars = split //sx, "$bigint";
2628
2629    # render nicely
2630    if(scalar @chars < 3){
2631        return q{}.join q{}, @chars;
2632    }
2633    # start with the three most signifficant digits (as a decimal)
2634    my $ans = q{}.$chars[0].q{.}.$chars[1].$chars[2];
2635    # then add the scientific notation bit
2636    $ans .= 'x10^'.(scalar @chars - 1);
2637
2638    # return the result
2639    return $ans;
2640}
2641
2642#####-SUB-######################################################################
2643# Type       : CLASS (PRIVATE)
2644# Purpose    : Get the so-called 'grapheme length' of a unicode string, that is
2645#              to say, the length of a word where a letter with an accent counts
2646#              as a single letter.
2647# Returns    : An integer
2648# Arguments  : 1) the string to get the length of
2649# Throws     : Croaks on invalid invocation and invalid args
2650# Notes      : Perl, by default, will consider accented letters as having a
2651#              length of two. This function uses a very common algorythm
2652#              recommended all over the internet, including in the Perl Unicode
2653#              cookbook: http://search.cpan.org/~shay/perl-5.20.2/pod/perlunicook.pod
2654#              Before resorting to this technique, I tried to use the
2655#              grapheme_length function from Unicode::Util, but it proved
2656#              unacceptably slow.
2657# See Also   :
2658sub _grapheme_length{
2659    my @args = @_;
2660    my $class = shift @args;
2661    _force_class($class);
2662
2663    # validate args
2664    state $args_check = compile(Str);
2665    my ($string) = $args_check->(@args);
2666
2667    # do the calculation
2668    my $grapheme_length = 0;
2669    while($string =~ /\X/gsx){$grapheme_length++};
2670
2671    # return the result
2672    return $grapheme_length;
2673}
2674
26751; # because Perl is just a little bit odd :)
2676__END__
2677
2678#==============================================================================
2679# User Documentation
2680#==============================================================================
2681
2682=head1 NAME
2683
2684C<Crypt::HSXKPasswd> - A secure memorable password generator inspired by Steve
2685Gibson's Passord Haystacks (L<https://www.grc.com/haystack.htm>), and the
2686famous XKCD password cartoon (L<https://xkcd.com/936/>).
2687
2688=head1 VERSION
2689
2690This documentation refers to C<Crypt::HSXKPasswd> version 3.6.
2691
2692=head1 SYNOPSIS
2693
2694    use Crypt::HSXKPasswd;
2695
2696    #
2697    # Functional Interface - a shortcut for generating single passwords
2698    #
2699
2700    # generate a single password using the default word source, configuration,
2701    # and random number generator
2702    my $password = hsxkpasswd();
2703
2704    # the above call is simply a shortcut for the following
2705    my $password = Crypt::HSXKPasswd->new()->password();
2706
2707    # this function passes all arguments on to Crypt::HSXKPasswd->new()
2708    # so all the same customisations can be specified, e.g. specifying a
2709    # config preset:
2710    my $password = hsxkpasswd(preset => 'XKCD');
2711
2712    #
2713    # Object Oriented Interface - recommended for generating multiple passwords
2714    #
2715
2716    # create a new instance with the default dictionary, config, and random
2717    # number generator
2718    my $hsxkpasswd_instance = Crypt::HSXKPasswd->new();
2719
2720    # generate a single password
2721    my $password = $hsxkpasswd_instance->password();
2722
2723    # generate multiple passwords
2724    my @passwords = $hsxkpasswd_instance->passwords(10);
2725
2726=head1 DESCRIPTION
2727
2728A secure memorable password generator inspired by the wonderful XKCD webcomic
2729at L<http://www.xkcd.com/> and Steve Gibson's Password Haystacks page at
2730L<https://www.grc.com/haystack.htm>. This is the Perl module that powers
2731L<https://www.xkpasswd.net>.
2732
2733=head2 PHILOSOPHY
2734
2735More and more of the things we do on our computer require passwords, and at the
2736same time it seems we hear about organisations or sites losing user database on
2737every day that ends in a I<y>. If we re-use our passwords we expose ourself to
2738an ever greater risk, but we need more passwords than we can possibly remember
2739or invent. Coming up with one good password is easy, but coming up with one
2740good password a week is a lot harder, let alone one a day!
2741
2742Obviously we need some technological help. We need our computers to help us
2743generate robust password and store them securely. There are many great password
2744managers out there to help us securely store and sync our passwords, including
2745commercial offerings and open-source projects. Many of these managers also offer
2746to generate random passwords for us, usually in the form of a random string of
2747meaningless letters numbers and symbols. These kinds of nonsense passwords are
2748certainly secure, but they are often impractical.
2749
2750Regardless of how good your chosen password manager is, there will always be
2751times when you need to type in your passwords, and that's when random gibberish
2752passwords become a real pain point. As annoying as it is to have to glance over
2753and back at a small cellphone screen to manually type a gibberish password into
2754a computer, that's nothing compared to the annoyance of trying to communicate
2755such a password to a family member, friend, colleague or customer over the phone.
2756
2757Surely it would be better to have passwords that are still truly random in the
2758way humans can't be, but are also human-friendly in the way random gibberish
2759never will be? This is the problem this module aims to solve.
2760
2761Rather than randomly choosing many letters, digits, and symbols from a fairly
2762small alphabet of possible characters, this library chooses a small number of
2763words from a large I<alphabet> of possible words as the basis for passwords.
2764Words are easy to remember, easy to read from a screen, easy to type, and easy
2765to communicate over the telephone.
2766
2767This module uses words to make up the bulk of the passwords it generates, but
2768it also adds carefully placed symbols and digits to add security without making
2769the passwords difficult to remember, read, type, and speak.
2770
2771In shot, this module is for people who prefer passwords that look like this:
2772
2773    !15.play.MAJOR.fresh.FLAT.23!
2774
2775to passwords that look like this:
2776
2777    eB8.GJXa@TuM
2778
2779=head2 PASSWORD GENERATION ALGORITHM
2780
2781This module always uses a simple five-step algorithm to generate passwords, but
2782each step can be customised, and many steps can be skipped completely.
2783
2784It's important to understand the algorithm before trying to create your own
2785custom configurations for this module.
2786
2787The algorithm is broken in to the following steps:
2788
2789=over 4
2790
2791=item 1
2792
2793Pick random words from the dictionary.
2794
2795=item 2
2796
2797Apply transformations to the words.
2798
2799=item 3
2800
2801Create pseudo-words made up for randomly chosen digits and add them as the first
2802and last words.
2803
2804=item 4
2805
2806Insert a copy of the same symbol between each of the words and pseudo-words.
2807This symbol is referred to as the I<separator character>.
2808
2809=item 5
2810
2811Pad the password with multiple instances of the same symbol front and/or back.
2812This symbol is referred to as the I<padding character>.
2813
2814=back
2815
2816You can visualise this process as follows:
2817
2818    correct horse batter staple
2819    correct HORSE battery staple
2820    25 correct HORSE battery staple 83
2821    25*correct*HORSE*battery*staple*83
2822    ++25*correct*HORSE*battery*staple*83++
2823
2824Each of these steps can be customised in the following ways:
2825
2826=over 4
2827
2828=item 1
2829
2830The number of words to be used, and the minimum and maximum lengths of the words
2831can be configured.
2832
2833=item 2
2834
2835The case of the words can be modified in a number of ways, including randomly
2836choosing the case for each word.
2837
2838It is also possible to specify so-called I<133t-style> character substitutions,
2839e.g. replacing all occurrences of the letter C<e> with the digit C<3>, or all
2840occurrences of the letter C<s> with the symbol C<$>.
2841
2842=item 3
2843
2844The number of digits to add as pseudo words to the front and back of the
2845password can be configured. A length of zero can be specified for both to
2846generate passwords without any randomly chosen digits.
2847
2848=item 4
2849
2850The separator character can be specified directly, or it can be randomly chosen
2851from a list of symbols. It is also possible to specify that no separator should
2852be used.
2853
2854=item 5
2855
2856The padding character can also be specified directly, or remotely chosen from a
2857list of possible symbols. Padding can also be disabled completely. If padding is
2858to be used it can be applied in two modes - fixed, and adaptive.
2859
2860With fixed padding a specified number of copies of the separator character are
2861added to the front and back of the password. The fixed padding does not have to
2862be symmetric.
2863
2864With adaptive padding the required number of copies of the separator character
2865are added to the back of the password until it reaches a specified length.
2866
2867=back
2868
2869=head2 THE MATHS
2870
2871Before examining the password strength of passwords generated with this module
2872we need to lay out the relatively simple maths underlying it all.
2873
2874=head3 Maths Primer
2875
2876A coin could be used as a very simple password generator. Each character in
2877the password would be the result of a single coin toss. If the coin lands
2878heads up, we add a C<H> to our password, if it lands tails up, we add a C<T>.
2879
2880If you made a one-letter password in this way there would only be two
2881possibilities, C<H>, or C<T>, or two permutations. If you made a two-letter
2882password in this way there would be four possible combinations, or
2883permutations, C<HH>, C<HT>, C<TH>, and C<TT>. If you made a three-character
2884password in this way there would be 16 permutations, a five character one
2885would have 32 permutations, and so forth.
2886
2887So, for a coin toss, which has two possible values for each character, the
2888formula for the number of permutations C<P> for a given length of password C<L>
2889is:
2890
2891    P = 2^L
2892
2893Or, two to the power of the length of the password.
2894
2895If we now swapped our coin for a dice, we would go from two possible values
2896per letter, to six possible values per letter. For one dice roll there would
2897be six permutations, for two there would be 36, for three there would be 108
2898and so on.
2899
2900This means that for a dice, the number of permutations can be calculated with
2901the formula:
2902
2903    P = 6^L
2904
2905When talking about passwords, the set of possible symbols used for each
2906character in the password is referred to as the password's I<alphabet>. So,
2907for the coin toss the alphabet was just C<H> and C<T>, and for the dice it
2908was C<1>, C<2>, C<3>, C<4>, C<5>, and C<6>. The actual characters used in
2909the alphabet make no difference to the strength of the password, all that
2910matters is the size of the alphabet, which we'll call C<A>.
2911
2912As you can probably infer from the two examples above, the formula for the
2913number of possible permutations C<P> for a password of length C<L> created from
2914an alphabet of size C<A> is:
2915
2916    P = A^L
2917
2918In the real world our passwords are generally made up of a mix of letters,
2919digits, and symbols. If we use mixed case that gives us 52 letters alone,
2920then add in the ten digits from C<0> to C<9> and we're already up to 62
2921possible characters before we even start on the array of symbols and
2922punctuation characters on our keyboards. It's generally accepted that if you
2923include symbols and punctuation, there are 95 characters available for use in
2924randomly generated passwords. Hence, in the real-world, the value for C<A> is
2925assumed to be 95. When you start raising a number as big as 95 to even low
2926powers the number of permutations quickly rises.
2927
2928A two character password with alphabet of 95 has 9025 permutations, increasing
2929the length to three characters brings that up to 857,375, and so on. These
2930numbers very quickly become too big to handle. For just an 8 character password
2931we are talking about 6,634,204,312,890,625 permutations, which is a number
2932so big most people couldn't say it (what do you call something a thousand times
2933bigger than a trillion?).
2934
2935Because the numbers get so astronomically big so quickly, computer scientists
2936use bits of entropy to measure password strength rather than the number of
2937permutations. The formula to turn permutations into bits of entropy C<E> is very
2938simple:
2939
2940    E = Log(2)P
2941
2942In other words, the entropy is the log to base two of the permutations. For our
2943eight character example that equates to about 52 bits.
2944
2945There are two approaches to increasing the number of permutations, and hence
2946the entropy, you can choose more characters, or, you can make the alphabet you
2947are choosing from bigger.
2948
2949=head3 The Entropy of HSXKPasswd Passwords
2950
2951Exactly how much entropy does a password need? That's the subject of much
2952debate, and the answer ultimately depends on the value of the assets being
2953protected by the password.
2954
2955Two common recommendations you hear are 8 characters containing a mix of upper
2956and lower case letters, digits, and symbols, or 12 characters with the same
2957composition. These evaluation to approximately 52 bits of entropy and 78 bits
2958of entropy respectively.
2959
2960When evaluating the entropy of passwords generated by this module, it has to be
2961done from two points of view for the answer to be meaningful. Firstly, a
2962best-case scenario - the attacker has absolutely no knowledge of how the
2963password was generated, and hence must mount a brute-force attack. Then,
2964secondly from the point of view of an attacker with full knowledge of how the
2965password was generated. Not just the knowledge that this module was used, but
2966a copy of the dictionary file used, and, a copy of the configuration settings
2967used.
2968
2969For the purpose of this documentation, the entropy in the first scenario, the
2970brute force attack, will be referred to as the blind entropy, and the entropy
2971in the second scenario the seen entropy.
2972
2973The blind entropy is solely determined by the configuration settings, the seen
2974entropy depends on both the settings and the dictionary file used.
2975
2976Calculating the bind entropy C<Eb> is quite straightforward, we just need to
2977know the size of the alphabet resulting from the configuration C<A>, and the
2978minimum length of passwords generated with the configuration C<L>, and plug
2979those values into this formula:
2980
2981    Eb = Log(2)(A^L)
2982
2983Calculating C<A> simply involves determining whether or not the configuration
2984results in a mix of letter cases (26 or 52 characters), the inclusion of at
2985least one symbol (if any one is present, assume the industry standard of a 33
2986character search space), and the inclusion of at least one digit
2987(10 character). This will result in a value between 26 and 95.
2988
2989Calculating C<L> is also straightforward. The one minor complication is that
2990some configurations result in a variable length password. In this case,
2991assume the shortest possible length the configuration could produce.
2992
2993The example password from the L</PHILOSOPHY> section
2994(C<!15.play.MAJOR.fresh.FLAT.23!>) was generated using the preset C<WEB32>.
2995This preset uses four words of between four and five letters long, with the
2996case of each word randomly set to all lower or all upper as the
2997basis for the password, it then chooses two pairs of random digits as extra
2998words to go front and back, before separating each word with a copy of a
2999randomly chosen symbol, and padding the front and back of the password with
3000a copy of a different randomly chosen symbol. This results in passwords that
3001contain a mix of cases, digits, and symbols, and are between 27 and 31
3002characters long. If we add these values into the formula we find that the
3003blind entropy for passwords created with this preset is:
3004
3005    Eb = Log(2)(95^27) = 163 bits
3006
3007This is spectacularly secure! And, this is the most likely kind of attack for
3008a password to face. However, to have confidence in the password we must also
3009now calculate the entropy when the attacker knows everything about how the
3010password was generated.
3011
3012We will calculate the entropy resulting from the same C<WEB32> config being
3013used to generate a password using the sample library file that ships with
3014the module.
3015
3016The number of permutations the attacker needs to check is purely the product
3017of possibly results for each random choice made during the assembly of the
3018password.
3019
3020Lets start with the words that will form the core of the password. The
3021configuration chooses four words of between four and five letters long from
3022the dictionary, and then randomises their case, effectively making it a
3023choice from twice as many words (each word in each case).
3024
3025The sample dictionary file contains 698 words of the configured length, which
3026doubles to 1396. Choosing four words from that very large alphabet gives a
3027starting point of C<1396^4>, or 3,797,883,801,856 permutations.
3028
3029Next we need to calculate the permutations for the separator character. The
3030configuration specifies just nine permitted characters, and we choose just one,
3031so that equates to 9 permutations.
3032
3033Similarly, the padding character on the end is chosen from 13 permitted symbols
3034giving 13 more permutations.
3035
3036Finally, there are four randomly chosen digits, giving C<10^4>, or 10,000
3037permutations.
3038
3039The total number of permutations is the product of all these permutations:
3040
3041    Pseen = 3,797,883,801,856 * 9 * 13 * 10,000 = 2.77x10^17
3042
3043Finally, we convert this to entropy by taking the base 2 log:
3044
3045    Eseen = Log(2)2.77x10^17 = ~57bits
3046
3047What this means is that most probably, passwords generated with this preset
3048using the sample dictionary file are spectacularly more secure than even
304912 randomly chosen characters, and, that in the very unlikely event that an
3050attackers knows absolutely everything about how the password was generated,
3051it is still significantly more secure than 8 randomly chosen characters.
3052
3053Because the exact strength of the passwords produced by this module depend on
3054the configuration and dictionary file used, the constructor does the above
3055math when creating an HSXKPasswd object, and throws a warning if either the
3056blind entropy falls below 78bits, or the seen entropy falls below 52 bits.
3057
3058=head1 SUBROUTINES/METHODS
3059
3060=head2 MODULE CONFIGURATION
3061
3062It is possible to tweak the module's behaviour in certain areas by updating the
3063values contained within a set of module configuration keys. The values
3064associated with these keys can be accessed and updated via the class function
3065C<module_config()>.
3066
3067    # get the current debug status
3068    my $debug_status = Crypt::HSXKPasswd->module_config('DEBUG');
3069
3070    # configure the module to suppress all entropy warnings
3071    Crypt::HSXKPasswd->module_config('ENTROPY_WARNINGS', 'NONE');
3072
3073The following module configuration keys exist within the module:
3074
3075=over 4
3076
3077=item *
3078
3079C<DEBUG> - A True/False value denoting whether or not the module should print
3080debug messages. The default is not to print debug messages.
3081
3082For more details see the DIAGNOSTICS section of this document.
3083
3084=item *
3085
3086C<LOG_ERRORS> - A True/False value denoting whether or not errors should be
3087logged. The default is not to log.
3088
3089For more details see the DIAGNOSTICS section of this document.
3090
3091=item *
3092
3093C<LOG_STREAM> - the stream to which debug messages should be printed if
3094debugging is enabled, and log messages should be printed when error logging is
3095enabled. The default is to print to C<STDERR>.
3096
3097For more details see the DIAGNOSTICS section of this document.
3098
3099=item *
3100
3101C<ENTROPY_MIN_BLIND> - the minimum allowable entropy against brute force attacks
3102in bits. The default is 78 bits.
3103
3104For more details see the ENTROPY CHECKING section of this document.
3105
3106=item *
3107
3108C<ENTROPY_MIN_SEEN> - the minimum allowable entropy against an attacker with
3109full knowledge. The default is 52 bits.
3110
3111For more details see the ENTROPY CHECKING section of this document.
3112
3113=item *
3114
3115C<ENTROPY_WARNINGS> - control the emission of entropy warnings. The value must
3116be one of C<ALL>, C<BLIND>, or C<NONE>. The default value is C<ALL>.
3117
3118For more details see the ENTROPY CHECKING section of this document.
3119
3120=back
3121
3122=head2 CUSTOM DATA TYPES
3123
3124This module uses a custom type library created with C<Type::Library> for data
3125validation. It is important to know this for two reasons - firstly, these
3126custom types are mentioned in many error messages, and secondly these custom
3127types are available for developers to use in their own code, either when
3128utilising C<Crypt::HSXKPasswd>, or writing custom word sources by extending
3129C<Crypt::HSXKPasswd::Dictionary>, or when writing custom random number
3130generators by extending C<Crypt::HSXKPasswd::RNG>.
3131
3132=head3 Defined Types
3133
3134=over 4
3135
3136=item *
3137
3138C<NonEmptyString> - a string containing at least one character.
3139
3140=item *
3141
3142C<PositiveInteger> - a whole number greater than or equal to zero.
3143
3144=item *
3145
3146C<NonZeroPositiveInteger> - a whole number greater than zero.
3147
3148=item *
3149
3150C<TrueFalse> - a reasonable boolean value, specifically, C<undef>, and empty
3151string, or 0 to indicate false, and a 1 to indicate true.
3152
3153=item *
3154
3155C<PerlPackageName> - string representing a valid Perl package name like
3156C<Crypt::HSXKPasswd::Dictionary::NL>.
3157
3158=item *
3159
3160C<Letter> - a string containing a single letter. Because this module is
3161Unicode-aware, it should be noted that a letter is defined as a single Unicode
3162grapheme with the Unicode property C<Letter>. What this means is that accented
3163letters like C<E<eacute>> are considered valid, as are ligatures like
3164C<E<aelig>>.
3165
3166=item *
3167
3168C<Symbol> - a string containing a single non-letter character. Because this
3169module is Unicode-aware, should be noted that a non-letter character is defined
3170as a single Unicode grapheme that does not have the Unicode property C<Letter>.
3171What this means is that neither letters, accented characters, nor ligatures can
3172be used as symbols, but just about every other Unicode character can, including
3173punctuation symbols, mathematical symbols, and even emoji!
3174
3175=item *
3176
3177C<Word> - a string containing only letters (as defined by the type C<Letter>),
3178and at least four long.
3179
3180=item *
3181
3182C<SymbolAlphabet> - a symbol alphabet is a reference to an array that contains
3183at least two distinct symbols (as defined by the type C<Symbol>), and no values
3184that are not symbols.
3185
3186=item *
3187
3188C<WordLength> - a valid value when specifying the length of a word,
3189specifically, a whole number greater than or equal to four.
3190
3191=item *
3192
3193C<ConfigKeyDefinition> - a valid configuration key definition. A reference to a
3194hash  mapping C<required> to a true/false value, C<expects> to a non-empty
3195string, and C<type> to a C<Type::Tiny> object.
3196
3197=item *
3198
3199C<ConfigKeyName> - a valid configuration key name, see the CONFIGURATION section
3200of this document for a description of each configuration key supported by this
3201module. You can get a list of valid configuration key names programatically by
3202calling the function C<Crypt::HSXKPasswd->defined_config_keys()>.
3203
3204=item *
3205
3206C<ConfigKeyAssignment> - a mapping between a valid configuration key name and a
3207valid value for that configuration key.
3208
3209=item *
3210
3211C<ConfigOverride> - a reference to hash containing one or more configuration key
3212assignments as defined by the type C<ConfigKeyAssignment>.
3213
3214=item *
3215
3216C<Config> - a reference to a hash that contains a complete and valid set of
3217mappings between configuration key names and values. For a config to be
3218considered valid it must contain only valid valid configuration key assignments
3219as defined by the type C<ConfigKeyAssignment>, must contain a configuration key
3220assignment for each required configuration key and all interdependencies between
3221the specified configuration key assignments must be fulfilled.
3222
3223See the CONFIG section of this document for a detailed description of each of
3224the defined configuration keys and their various interdependencies.
3225
3226=item *
3227
3228C<PresetDefinition> - a valid preset definition. A reference to a hash  mapping
3229C<description> to a non-empty string, and C<config> to a valid Config.
3230
3231=item *
3232
3233C<PresetName> - a valid preset name, see the PRESETS section of this document
3234for a description of each preset supported by this module. You can get a list of
3235valid preset names programatically by calling the function
3236C<Crypt::HSXKPasswd->defined_presets()>.
3237
3238=back
3239
3240=head3 Using the Custom Types
3241
3242The library of custom types is defined in the package
3243C<Crypt::HSXKPasswd::Types>, and it is a standard C<Type::Library> type library
3244containing C<Type::Tiny> type definitions.
3245
3246Useful Links:
3247
3248=over 4
3249
3250=item *
3251
3252The documentation for C<Type::Tiny> -
3253L<http://search.cpan.org/perldoc?Type%3A%3ATiny>
3254
3255=item *
3256
3257The documentation for C<Type::Library> -
3258L<http://search.cpan.org/perldoc?Type%3A%3ALibrary>
3259
3260=back
3261
3262To use the bare type definitions listed above, import the module as follows:
3263
3264    use Crypt::HSXKPasswd::Types qw( :types );
3265
3266Each type listed above will now be imported, and become available as a bare
3267word. The C<Type::Tiny> documentation provides a full list of available
3268functions, but the examples below illustrate some of the more useful ones:
3269
3270    $is_valid = Letter->check('e'); # $is_valid = 1
3271    $is_valid = Letter->check('-'); # $is_valid = undef
3272    $err_msg = Letter->validate('e'); # $err_msg = undef
3273    $err_msg = Letter->validate('-'); # $err_msg = "'-' is not a Letter ...
3274                    # ... (must be a string containing exactly one letter)"
3275
3276C<Type::Library> automatically creates an C<is_TypeName> function for each type
3277defined in the library. These are not imported by default. To import them add
3278the export tag C<:is> to the C<use> line. I would recommend the following C<use>
3279line:
3280
3281    use Crypt::HSXKPasswd::Types qw( :types :is );
3282
3283You can now do things like the following:
3284
3285    $is_valid = is_Letter('e'); # $is_valid = 1
3286    $is_valid = is_Letter('-'); # $is_valid = undef
3287
3288Each of the types listed above also contains a custom function using
3289C<Type::Tiny>'s new, and still officially experimental, C<my_methods> feature.
3290The custom function is called C<my_english>, and can be used to return an
3291English description of the values considered valid by the type, e.g.:
3292
3293    print Letter->my_english(); # prints: a string containing exactly one letter
3294
3295As well as the named types listed above, there are also anonymous types defined
3296for each supported configuration key. These can be accessed using the function
3297C<Crypt::HSXKPasswd->config_key_definitions()>.
3298
3299If declaring your own C<Type::Tiny> types, you may also find the public
3300subroutine C<Crypt::HSXKPasswd::Types::var_to_string()> useful - it will turn
3301anything passed as a scalar into a meaningful string, truncating any resulting
3302strings longer than 72 characters in nice way. All the custom error messages in
3303all the types defined in C<Crypt::HSXKPasswd::Types> make use of this
3304subroutine.
3305
3306=head2 CONFIGURATION
3307
3308The module builds passwords using the following process.
3309
3310First, a set of words are randomly chosen from the word source. Then, two
3311pseudo-words made of one or more digits may added before and/or after the words
3312from. Next, a separator character may be placed between all the words
3313(including the groups of digits), and one or more occurrences of a padding
3314symbol may be added front and/or back.
3315
3316You can envisage the process as follows:
3317
3318    correct HORSE BATTERY staple
3319    34 correct HORSE BATTERY staple 56
3320    34-correct-HORSE-BATTERY-staple-56
3321    !!34-correct-HORSE-BATTERY-staple-56!!
3322
3323Many aspects of this password generation process are configurable. You can
3324control the length and number of words chosen, and what, if any, case
3325transformations should be applied to those words, and how accented characters
3326should be treated. How many, if any, digits should be added front and back.
3327What symbol, if any, should be used as a separator. And finally how the
3328password should be padded, if at all, and with what symbol. Passwords can be
3329padded to a given length, or by a given number of symbols front and back.
3330
3331The symbols used as the separator and for padding can be explicitly specified,
3332or the they can be randomly chosen from a given alphabet of possible symbols.
3333Both symbols can be randomly chosen from the same alphabet, or from two
3334separately specified alphabets.
3335
3336Every instance of an HSXKPasswd password generator stores its configuration as
3337a set of name-value pairs, referred to as I<configuration keys> throughout this
3338documentation.
3339
3340Configurations can be specified either as a complete set of configuration keys
3341with values that together form a valid configuration, as a named preset, or, as
3342a named preset accompanied by a list of one or more configuration keys
3343with new values to override those specified by the preset.
3344
3345The module contains a preset called C<DEFAULT>, and this preset is used if no
3346configuration is specified. The function C<default_config()> will return a copy
3347of this configuration as a reference to a hashtable.
3348
3349For more details on how to specify configurations, see the documentation for
3350the constructor (the function C<new()>) below.
3351
3352=head3 Password Generator Configuration Keys
3353
3354Below is a list of all the configuration keys that can be used to customise the
3355password generation algorithm. Each configuration key is accompanied by a
3356description of what aspect of the algorithm they control, and any validation
3357rules that apply to the key.
3358
3359Note that some keys are always required, and that there are dependencies
3360between keys. For examples, if you specify that the separator symbol should be
3361chosen at random, you must also specify an alphabet from which the symbol should
3362be randomly chosen.
3363
3364=over 4
3365
3366=item *
3367
3368C<allow_accents> (optional) - if not specified, or if a falsy value is
3369specified, accents will be removed from letters in the generated passwords.
3370E.g. C<E<eacute>> becomes C<e>. If a truthy value is specified, accents will
3371be preserved, and appear in the generated passwords.
3372
3373=item *
3374
3375C<case_transform> (required) - the transformations, if any, that should be
3376applied to the words that appear in the generated passwords. The value specified
3377must be one of the following:
3378
3379=over 4
3380
3381=item *
3382
3383C<ALTERNATE> - each alternate word will be converted to all upper case and
3384all lower case. The case of the first word is chosen at random.
3385
3386=item *
3387
3388C<CAPITALISE> - the first letter in every word will be converted to upper case,
3389all other letters will be converted to lower case.
3390
3391=item *
3392
3393C<INVERT> - the first letter in every word will be converted to lower case,
3394all other letters will be converted to upper case.
3395
3396=item *
3397
3398C<LOWER> - all letters in all the words will be converted to lower case. B<Use
3399of this option is strongly discouraged for security reasons.>
3400
3401=item *
3402
3403C<NONE> - the case of the letters that make up the words will not be altered
3404from how they were specified in the original word source.
3405
3406=item *
3407
3408C<RANDOM> - each word will be randomly converted to all upper case or all lower
3409case.
3410
3411=item *
3412
3413C<UPPER> - all letters in all the words will be converted to upper case. B<Use
3414of this option is strongly discouraged for security reasons.>
3415
3416=back
3417
3418The function C<default_config()> returns a value of C<CAPITALISE> for this key.
3419
3420=item *
3421
3422C<character_substitutions> (optional) - a reference to a hashtable containing
3423containing zero or more character substitutions to be applied to the randomly
3424chosen words when generating passwords. The keys in the hashtable must be
3425single letters. The substitutions can contain multiple characters. Specifying
3426one or more substitutions with a length greater than one could lead to
3427passwords being longer than expected, and to entropy calculations being under
3428estimated. The module will issue a warning when such a config is loaded.
3429
3430=item *
3431
3432C<num_words> (required) - the number of words to randomly choose from the word
3433source as the basis for the generated passwords.
3434
3435The function C<default_config()> returns a value of C<3> for this key.
3436
3437=item *
3438
3439C<pad_to_length> (conditionally required) - the length generated passwords must
3440be padded to when using adaptive padding, i.e. when C<padding_type> is set to
3441C<ADAPTIVE>). The value must be an integer greater than or equal to 12. Lengths
3442of less than 12 are not permitted for security reasons.
3443
3444=item *
3445
3446C<padding_alphabet> (optional) - this key is ignored unless the configuration
3447specifies that the padding character should be randomly chosen, i.e. unless
3448C<padding_character> is set to C<RANDOM>.
3449
3450When the padding character is set to be randomly chosen, the module will check
3451for the presence of this key. If it is specified, the padding character will
3452be randomly chosen from the set of symbols defined by this key. If this key is
3453not set, the module will use the set of symbols specified by the key
3454C<symbol_alphabet>. If neither this key nor C<symbol_alphabet> are specified,
3455then the configuration will be considered invalid.
3456
3457If specified, this key must be a reference to an array of single-character
3458strings.
3459
3460=item *
3461
3462C<padding_character> (conditionally required) - this key is unless the key
3463C<padding_type> is set to C<NONE>. It specifies the padding symbol to be used
3464when generating passwords.
3465
3466If specified, they key's value must be a single character string, or one of the
3467following special values:
3468
3469=over 4
3470
3471=item *
3472
3473C<RANDOM> - the character should be randomly chosen from the set of characters
3474specified by the key C<padding_alphabet> or C<symbol_alphabet>. If specified,
3475C<padding_alphabet> takes precedence over C<symbol_alphabet>. If this value
3476is specified for C<padding_character>, and neither C<padding_alphabet> nor
3477C<symbol_alphabet> are specified, the configuration will be considered invalid.
3478
3479=item *
3480
3481C<SEPARATOR> - pad the password with the same symbol that is used to separate
3482the words. The key C<padding_character> cannot be set to C<SEPARATOR> when the
3483key C<separator_character> is set to C<NONE>.
3484
3485
3486=back
3487
3488
3489The function C<default_config> return the value C<RANDOM> for this key.
3490
3491=item *
3492
3493C<padding_characters_before> & C<padding_characters_after> (conditionally
3494required) - both of these keys are required if the key C<padding_type> is set
3495to C<FIXED>.
3496
3497These keys specify the number of padding symbols that should be added to the
3498front and back of the password.
3499
3500Both keys require that the specified value be an integer greater than or equal
3501to zero.
3502
3503The function C<default_config()> returns a value of C<2> for both of these
3504keys.
3505
3506=item *
3507
3508C<padding_digits_before> & C<padding_digits_after> (required) - the number of
3509random digits to include before and after the randomly chosen words when
3510generating passwords.
3511
3512Both keys require that the specified value be an integer greater than or equal
3513to zero.
3514
3515The function C<default_config()> returns a value of C<2> for both of these
3516keys.
3517
3518=item *
3519
3520C<padding_type> (required) - the way in which padding symbols should be added
3521when generating passwords.
3522
3523Only the following values are valid for this key:
3524
3525=over 4
3526
3527=item *
3528
3529C<NONE> - do not add any padding symbols when generating passwords.
3530
3531=item *
3532
3533C<FIXED> - add an exactly specified number of copies of the padding symbol to
3534the front and back of generated passwords.
3535
3536When they key C<padding_type> is set to C<FIXED>, the three keys
3537C<padding_character>, C<padding_characters_before> &
3538C<padding_characters_after> become required.
3539
3540=item *
3541
3542C<ADAPTIVE> - add no copies of the padding symbol will be added to the front
3543of the generated passwords, and copies of the padding character will be added
3544to the end of the generated passwords until the total length of the password is
3545equal to the value specified for the key C<pad_to_length>.
3546
3547Note that If the password is longer than the value specified by the key
3548C<pad_to_length> before any copies of the padding symbol are added, the
3549password will be truncated to the length specified by the key C<pad_to_length>.
3550
3551When they key C<padding_type> is set to C<ADAPTIVE>, the three keys
3552C<padding_character>, C<padding_characters_before> &
3553C<padding_characters_after> become required.
3554
3555=back
3556
3557The function C<default_config()> returns a value of C<FIXED> for this key.
3558
3559=item *
3560
3561C<separator_alphabet> (optional) - this key is ignored unless the configuration
3562specifies that the separator character should be randomly chosen, i.e. unless
3563C<separator_character> is set to C<RANDOM>.
3564
3565When the separator character is set to be randomly chosen, the module will
3566check for the presence of this key. If it is specified, the separator character
3567will be randomly chosen from the set of symbols defined by this key. If this
3568key is not set, the module will use the set of symbols specified by the key
3569C<symbol_alphabet>. If neither this key nor C<symbol_alphabet> are specified,
3570then the configuration will be considered invalid.
3571
3572If specified, this key must be a reference to an array of single-character
3573strings.
3574
3575=item *
3576
3577C<separator_character> (required) - the symbol to use to separate the words
3578when generating passwords.
3579
3580The value specified for this key must be a single-character string, or one of
3581the following special values:
3582
3583=over 4
3584
3585=item *
3586
3587C<NONE> - no separator character will be used. I.e. the words, and the groups
3588of digits before and after the words, if any, will be directly joined together.
3589
3590C<RANDOM> - a single character will be randomly chosen from the list of symbols
3591specified by one of the keys C<separator_alphabet> or C<symbol_alphabet>. If
3592both keys are set, C<separator_alphabet> takes precedence.
3593
3594=back
3595
3596The function C<default_config()> returns a value of C<RANDOM> for this key.
3597
3598=item *
3599
3600C<symbol_alphabet> (optional) - this key specifies a default alphabet of
3601symbols that can be used when either or both the separator character and the
3602padding character are set to be chosen at random. I.e. when either or both of
3603the keys C<separator_character> and C<padding_character> are set to C<RANDOM>.
3604
3605Note that the keys C<separator_alphabet> and C<padding_alphabet> take
3606precedence over this key if specified.
3607
3608The value specified for this key must be a reference to an array of
3609single-character strings.
3610
3611The function C<default_config()> returns a value of
3612C<['!', '@', '$', '%', '^', '&', '*', '-', '_',
3613'+', '=', ':', '|', '~', '?', '/', '.', ';']>
3614for this key.
3615
3616=item *
3617
3618C<word_length_min> & C<word_length_max> (required) - the minimum and maximum
3619length of the words that will form the basis of the generated passwords.
3620
3621The values specified for both keys must be integers greater than three, and
3622the value specified for C<word_length_max> must be greater than or equal to
3623the value specified for C<word_length_min>.
3624
3625The function C<default_config()> returns values of C<4> and C<8> for these keys.
3626
3627=back
3628
3629=head2 PRESETS
3630
3631Below is a list of all the presets defined by this module.
3632
3633This information can be accessed programatically using the functions
3634C<defined_presets()>, C<presets_to_string()>, C<preset_description()>, and
3635C<preset_config()>.
3636
3637=over 4
3638
3639=item *
3640
3641C<APPLEID> - a preset respecting the many prerequisites Apple places on Apple
3642ID passwords. Apple's official password policy cam be found at the following
3643URL: L<http://support.apple.com/kb/ht4232>. Note that Apple's knowledge base
3644article omits to mention that passwords can't be longer than 32 characters.
3645This preset is also configured to use only characters that are easy to type on
3646the standard iOS keyboard, i.e. those appearing on the letters keyboard
3647(C<ABC>) or the numbers keyboard C<.?123>, and not those on the harder to reach
3648symbols keyboard C<#+=>.
3649
3650Sample Password:
3651
3652    -25,favor,MANY,BEAR,53-
3653
3654Preset Definition:
3655
3656    {
3657        padding_alphabet => [qw{- : . ! ? @ &}],
3658        separator_alphabet => [qw{- : . @}, q{,}, q{ }],
3659        word_length_min => 4,
3660        word_length_max => 7,
3661        num_words => 3,
3662        separator_character => 'RANDOM',
3663        padding_digits_before => 2,
3664        padding_digits_after => 2,
3665        padding_type => 'FIXED',
3666        padding_character => 'RANDOM',
3667        padding_characters_before => 1,
3668        padding_characters_after => 1,
3669        case_transform => 'RANDOM',
3670        allow_accents => 0,
3671    }
3672
3673=item *
3674
3675C<DEFAULT> - the default configuration.
3676
3677Sample Password:
3678
3679    ~~12:settle:SUCCEED:summer:48~~
3680
3681Preset Definition:
3682
3683    {
3684        symbol_alphabet => [qw{! @ $ % ^ & * - _ + = : | ~ ? / . ;}],
3685        word_length_min => 4,
3686        word_length_max => 8,
3687        num_words => 3,
3688        separator_character => 'RANDOM',
3689        padding_digits_before => 2,
3690        padding_digits_after => 2,
3691        padding_type => 'FIXED',
3692        padding_character => 'RANDOM',
3693        padding_characters_before => 2,
3694        padding_characters_after => 2,
3695        case_transform => 'ALTERNATE',
3696        allow_accents => 0,
3697    }
3698
3699=item *
3700
3701C<NTLM> - a preset for 14 character NTMLv1 (NTLM Version 1) passwords. B<ONLY
3702USE THIS PRESET IF YOU MUST!> The 14 character limit does not allow for
3703sufficient entropy in scenarios where the attacker knows the dictionary and
3704config used to generate the password. Use of this preset will generate a low
3705entropy warning.
3706
3707Sample Password:
3708
3709    0=mAYAN=sCART@
3710
3711Preset Definition:
3712
3713    {
3714        padding_alphabet => [qw{! @ $ % ^ & * + = : | ~ ?}],
3715        separator_alphabet => [qw{- + = . * _ | ~}, q{,}],
3716        word_length_min => 5,
3717        word_length_max => 5,
3718        num_words => 2,
3719        separator_character => 'RANDOM',
3720        padding_digits_before => 1,
3721        padding_digits_after => 0,
3722        padding_type => 'FIXED',
3723        padding_character => 'RANDOM',
3724        padding_characters_before => 0,
3725        padding_characters_after => 1,
3726        case_transform => 'INVERT',
3727        allow_accents => 0,
3728    }
3729
3730=item *
3731
3732C<SECURITYQ> - a preset for creating fake answers to security questions. This
3733preset generates long nonsense sentences ending in C<.> C<!> or C<?>.
3734
3735Sample 'Password':
3736
3737    Wales outside full month minutes gentle?
3738
3739Preset Definition:
3740
3741    {
3742        word_length_min => 4,
3743        word_length_max => 8,
3744        num_words => 6,
3745        separator_character => q{ },
3746        padding_digits_before => 0,
3747        padding_digits_after => 0,
3748        padding_type => 'FIXED',
3749        padding_character => 'RANDOM',
3750        padding_alphabet => [qw{. ! ?}],
3751        padding_characters_before => 0,
3752        padding_characters_after => 1,
3753        case_transform => 'NONE',
3754        allow_accents => 0,
3755    }
3756
3757=item *
3758
3759C<WEB16> - a preset for websites that don't allow passwords to be longer than
376016 characters. B<ONLY USE THIS PRESET IF YOU MUST!> The 14 character limit does
3761not allow for sufficient entropy in scenarios where the attacker knows the
3762dictionary and config used to generate the password. Use of this preset will
3763generate a low entropy warning.
3764
3765Sample Password:
3766
3767    tube+NICE+iron+02
3768
3769Preset Definition:
3770
3771    {
3772        symbol_alphabet => [qw{! @ $ % ^ & * - _ + = : | ~ ? / . ;}],
3773        word_length_min => 4,
3774        word_length_max => 4,
3775        num_words => 3,
3776        separator_character => 'RANDOM',
3777        padding_digits_before => 0,
3778        padding_digits_after => 2,
3779        padding_type => 'NONE',
3780        case_transform => 'RANDOM',
3781        allow_accents => 0,
3782    }
3783
3784=item *
3785
3786C<WEB32> - a preset for websites that don't allow passwords to be longer than
378732 characters.
3788
3789Sample Password:
3790
3791    +93-took-CASE-money-AHEAD-31+
3792
3793Preset Definition:
3794
3795    {
3796        padding_alphabet => [qw{! @ $ % ^ & * + = : | ~ ?}],
3797        separator_alphabet => [qw{- + = . * _ | ~}, q{,}],
3798        word_length_min => 4,
3799        word_length_max => 5,
3800        num_words => 4,
3801        separator_character => 'RANDOM',
3802        padding_digits_before => 2,
3803        padding_digits_after => 2,
3804        padding_type => 'FIXED',
3805        padding_character => 'RANDOM',
3806        padding_characters_before => 1,
3807        padding_characters_after => 1,
3808        case_transform => 'ALTERNATE',
3809        allow_accents => 0,
3810    }
3811
3812=item *
3813
3814C<WIFI> - a preset for generating 63 character long WPA2 keys (most routers
3815allow 64 characters, but some only allow 63, hence the somewhat unexpected
3816length).
3817
3818Sample Password:
3819
3820    2736_ITSELF_PARTIAL_QUICKLY_SCOTLAND_wild_people_7441!!!!!!!!!!
3821
3822Preset Definition:
3823
3824    {
3825        padding_alphabet => [qw{! @ $ % ^ & * + = : | ~ ?}],
3826        separator_alphabet => [qw{- + = . * _ | ~}, q{,}],
3827        word_length_min => 4,
3828        word_length_max => 8,
3829        num_words => 6,
3830        separator_character => 'RANDOM',
3831        padding_digits_before => 4,
3832        padding_digits_after => 4,
3833        padding_type => 'ADAPTIVE',
3834        padding_character => 'RANDOM',
3835        pad_to_length => 63,
3836        case_transform => 'RANDOM',
3837        allow_accents => 0,
3838    }
3839
3840=item *
3841
3842C<XKCD> - a preset inspired by the original XKCD comic
3843(L<http://xkcd.com/936/>), but with some alterations to provide sufficient
3844entropy to avoid low entropy warnings.
3845
3846Sample Password:
3847
3848    quiet-children-OCTOBER-today-HOPE
3849
3850Preset Definition:
3851
3852    {
3853        word_length_min => 4,
3854        word_length_max => 8,
3855        num_words => 5,
3856        separator_character => q{-},
3857        padding_digits_before => 0,
3858        padding_digits_after => 0,
3859        padding_type => 'NONE',
3860        case_transform => 'RANDOM',
3861        allow_accents => 0,
3862    }
3863
3864=back
3865
3866=head2 FUNCTIONAL INTERFACE
3867
3868Although the package was primarily designed to be used in an object-oriented
3869way, there is a functional interface too. The functional interface initialises
3870an object internally and then uses that object to generate a single password.
3871If you only need one password, this is no less efficient than the
3872object-oriented interface, however, if you are generating multiple passwords it
3873is much less efficient.
3874
3875There is only a single function exported by the module:
3876
3877=head3 hsxkpasswd()
3878
3879    my $password = hsxkpasswd();
3880
3881This function call is equivalent to the following Object-Oriented code:
3882
3883    my $password =  Crypt::HSXKPasswd->new()->password();
3884
3885This function passes all arguments it receives through to the constructor, so all
3886arguments that are valid in C<new()> are valid here.
3887
3888This function Croaks if there is a problem generating the password.
3889
3890Note that it is inefficient to use this function to generate multiple passwords
3891because the dictionary will be re-loaded, and the entropy stats re-calculated
3892each time the function is called.
3893
3894=head2 CONSTRUCTOR
3895
3896    # create a new instance with the default dictionary, config, and random
3897    # number generator
3898    my $hsxkpasswd_instance = Crypt::HSXKPasswd->new();
3899
3900    # the constructor takes optional named arguments, these can be used to
3901    # customise the word source, config, and random number source.
3902
3903    # create an instance that uses the UNIX words file as the word source
3904    my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(
3905        dictionary => Crypt::HSXKPasswd::Dictionary::System->new()
3906    );
3907
3908    # create an instance that uses an array reference as the word source
3909    my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(dictionary_list => $array_ref);
3910
3911    # create an instance that uses a dictionary file as the word source
3912    my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(
3913        dictionary_file => 'sample_dict_EN.txt'
3914    );
3915
3916    # the class Crypt::HSXKPasswd::Dictionary::Basic can be used to aggregate
3917    # multiple array refs and/or dictionary files into a single word source
3918    my $dictionary = Crypt::HSXKPasswd::Dictionary::Basic->new();
3919    $dictionary->add_words('dict1.txt');
3920    $dictionary->add_words('dict2.txt');
3921    $dictionary->add_words($array_ref);
3922    my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(dictionary => $dictionary);
3923
3924    # create an instance from the preset 'XKCD'
3925    my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(preset => 'XKCD');
3926
3927    # create an instance based on the preset 'XKCD' with one customisation
3928    my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(
3929        preset => 'XKCD',
3930        preset_override => {separator_character => q{ }}
3931    );
3932
3933    # create an instance from a config based on a preset
3934    # but with many alterations
3935    my $config = Crypt::HSXKPasswd->preset_config('XKCD');
3936    $config->{separator_character} = q{ };
3937    $config->{case_transform} = 'INVERT';
3938    $config->{padding_type} = "FIXED";
3939    $config->{padding_characters_before} = 1;
3940    $config->{padding_characters_after} = 1;
3941    $config->{padding_character} = '*';
3942    my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(config => $config);
3943
3944    # create an instance from an entirely custom configuration
3945    my $config = {
3946        padding_alphabet => [qw{! @ $ % ^ & * + = : ~ ?}],
3947        separator_alphabet => [qw{- + = . _ | ~}],
3948        word_length_min => 6,
3949        word_length_max => 6,
3950        num_words => 3,
3951        separator_character => 'RANDOM',
3952        padding_digits_before => 2,
3953        padding_digits_after => 2,
3954        padding_type => 'FIXED',
3955        padding_character => 'RANDOM',
3956        padding_characters_before => 2,
3957        padding_characters_after => 2,
3958        case_transform => 'CAPITALISE',
3959    }
3960    my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(config => $config);
3961
3962    # create an instance from an entire custom config passed as a JSON string
3963    # a convenient way to use configs generated using the web interface at
3964    # https://xkpasswd.net
3965    my $config = <<'END_CONF';
3966    {
3967     "num_words": 4,
3968     "word_length_min": 4,
3969     "word_length_max": 8,
3970     "case_transform": "RANDOM",
3971     "separator_character": " ",
3972     "padding_digits_before": 0,
3973     "padding_digits_after": 0,
3974     "padding_type": "NONE",
3975    }
3976    END_CONF
3977    my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(config_json => $config);
3978
3979    # create an instance which uses /dev/urandom as the RNG
3980    # (only possible on Linux/Unix only systems)
3981    my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(
3982        rng => Crypt::HSXKPasswd::RNG::DevUrandom->new();
3983    );
3984
3985    # create an instance which uses Random.Org as the random number generator
3986    # NOTE - this should be used sparingly, and only by the paranoid. If you
3987    # abuse this RNG your IP will get blacklisted on Random.Org. You must pass
3988    # a valid email address to the constructor for
3989    # Crypt::HSXKPasswd::RNG::RandomDorOrg because Random.Org's usage
3990    # guidelines request that all invocations to their API contain a contact
3991    # email in the useragent header, and this module honours that request.
3992    my $hsxkpasswd_instance = Crypt::HSXKPasswd->new(
3993        rng => Crypt::HSXKPasswd::RNG::RandomDorOrg->new('your.email@addre.ss');
3994    );
3995
3996The constructor must be called via the package name.
3997
3998If called with no arguments the constructor will use an instance of
3999C<Crypt::HSXKPasswd::Dictionary::EN> as the word source, the preset C<DEFAULT>,
4000and an instance of the class C<Crypt::HSXKPasswd::RNG::Basic> to generate random
4001numbers.
4002
4003The function accepts named arguments to allow for custom specification of the
4004word source, config, and random number source.
4005
4006=head3 Specifying Custom Word Sources
4007
4008Three named arguments can be used to specify a word source, but only one should
4009be specified at a time. If multiple are specified, the one with the highest
4010priority will be used, and the rest ignored. The variables are listed below in
4011descending order of priority:
4012
4013=over 4
4014
4015=item *
4016
4017C<dictionary> - an instance of a class that extends
4018C<Crypt::HSXKPasswd::Dictionary>.
4019
4020=item *
4021
4022C<dictionary_list> - a reference to an array containing words as scalars.
4023
4024=item *
4025
4026C<dictionary_file> - the path to a dictionary file. Dictionary files should
4027contain one word per. Lines starting with a # symbol will be ignored. It is
4028assumed files will be UTF-8 encoded. If not, a second named argument,
4029C<dictionary_file_encoding>, can be used to specify another encoding.
4030
4031=back
4032
4033=head3 Specifying Custom Password Generator Configurations
4034
4035Two primary named arguments can be used to specify the config the instance
4036should use to generate passwords. Only one should be specified at a time. If
4037multiple are specified, the one with the highest priority will be used, and the
4038rest ignored. The variables are listed below in descending order of priority:
4039
4040=over 4
4041
4042=item *
4043
4044C<config> - a valid config hashref.
4045
4046=item *
4047
4048C<config_json> - a JSON string representing a valid config hashref.
4049
4050This named argument provides a convenient way to use configs generated using
4051the web interface at L<https://xkpasswd.net/>. The Save/Load tab in that
4052interface saves and loads configs in JSON format.
4053
4054=item *
4055
4056C<preset> - a valid preset name. If this variable is used, then any desired
4057config overrides can be passed as a hashref using the variable
4058C<preset_overrides>.
4059
4060=back
4061
4062=head3 Specifying Custom Random Number Generators
4063
4064A custom RNG can be specified using the named argument C<rng>. The passed value
4065must be an instance of a class that extends C<Crypt::HSXKPasswd::RNG> and
4066overrides the function C<random_numbers()>.
4067
4068=head2 INSTANCE METHODS
4069
4070B<NOTE> - all instance methods must be invoked on a Crypt::HSXKPasswd object or
4071they will croak.
4072
4073=head3 ->config()
4074
4075    my $config = $hsxkpasswd_instance->config(); # getter
4076    $hsxkpasswd_instance->config($config_hashref); # setter
4077    $hsxkpasswd_instance->config($config_json_string); # setter
4078
4079When called with no arguments the function returns a clone of the instance's
4080config hashref.
4081
4082When called with a single argument the function sets the config of the instance
4083to a clone of the passed config. If present, the argument must be either a
4084hashref containing valid config keys and values, or a JSON string representing
4085a hashref containing valid config keys and values.
4086
4087The function will croak if an invalid config is passed.
4088
4089=head3 ->config_as_json()
4090
4091    my $config_json_string = $hsxkpasswd_instance->config_as_json();
4092
4093This function returns the content of the instance's loaded config hashref as a
4094JSON string.
4095
4096The output from this function can be loaded into the web interface at
4097L<https://xkpasswd.net> (using the load/save tab).
4098
4099=head3 ->config_as_string()
4100
4101    my $config_string = $hsxkpasswd_instance->config_as_string();
4102
4103This function returns the content of the instance's loaded config hashref as a
4104scalar string.
4105
4106=head3 ->dictionary()
4107
4108    my $dictionary_clone = $hsxkpasswd_instance->dictionary();
4109    $hsxkpasswd_instance->dictionary($dictionary_instance);
4110    $hsxkpasswd_instance->dictionary($array_ref);
4111    $hsxkpasswd_instance->dictionary('sample_dict_EN.txt');
4112    $hsxkpasswd_instance->dictionary('sample_dict_EN.txt', 'Latin1');
4113
4114When called with no arguments this function returns a clone of the currently
4115loaded dictionary which will be an instance of a class that extends
4116C<Crypt::HSXKPasswd::Dictionary>.
4117
4118To load a new dictionary into an instance, call this function with arguments.
4119The first argument argument can be an instance of a class that extends
4120C<Crypt::HSXKPasswd::Dictionary>, a reference to an array of words, or the
4121path to a dictionary file. If either an array reference or a file path are
4122passed, they will be used to instantiate an instance of the class
4123C<Crypt::HSXKPasswd::Dictionary::Basic>, and that new instance will then be
4124loaded into the object. If a file path is passed, it will be assumed to be
4125UTF-8 encoded. If not, an optional second argument can be passed to specify the
4126file's encoding.
4127
4128=head3 ->password()
4129
4130    my $password = $hsxkpasswd_instance->password();
4131
4132This function generates a random password based on the instance's loaded config
4133and returns it as a scalar. The function takes no arguments.
4134
4135The function croaks if there is an error generating the password. The most
4136likely cause of and error is the random number generation, particularly if the
4137loaded random generation function relies on a cloud service or a non-standard
4138library.
4139
4140=head3 ->passwords()
4141
4142    my @passwords = $hsxkpasswd_instance->passwords(10);
4143
4144This function generates a number of passwords and returns them all as an array.
4145
4146The function uses C<password()> to generate the passwords, and hence will
4147croak if there is an error generating any of the requested passwords.
4148
4149=head3 ->passwords_json()
4150
4151    my $json_string = $hsxkpasswd_instance->passwords_json(10);
4152
4153This function generates a number of passwords and returns them and the
4154instance's entropy stats as a JSON string representing a hashref containing an
4155array of passwords indexed by C<passwords>, and a hashref of entropy stats
4156indexed by C<stats>. The stats hashref itself is indexed by:
4157C<password_entropy_blind>, C<password_permutations_blind>,
4158C<password_entropy_blind_min>, C<password_entropy_blind_max>,
4159C<password_permutations_blind_max>, C<password_entropy_seen> &
4160C<password_permutations_seen>.
4161
4162The function uses C<passwords()> to generate the passwords, and hence will
4163croak if there is an error generating any of the requested passwords.
4164
4165=head3 ->rng()
4166
4167    my $rng_instance = $hsxkpasswd_instance->rng();
4168    $hsxkpasswd_instance->rng($rng_instance);
4169
4170When called with no arguments this function returns currently loaded Random
4171Number Generator (RNG) which will be an instance of a class that extends
4172C<Crypt::HSXKPasswd::RNG>.
4173
4174To load a new RNG into an instance, call this function with a single
4175argument, an instance of a class that extends
4176C<Crypt::HSXKPasswd::RNG>.
4177
4178=head3 ->stats()
4179
4180    my %stats = $hsxkpasswd_instance->stats();
4181
4182This function generates a hash containing stats about the instance indexed by
4183the following keys:
4184
4185=over 4
4186
4187=item *
4188
4189C<dictionary_contains_accents> - 1 if the filtered word list contains accented
4190letters, 0 otherwise.
4191
4192=item *
4193
4194C<dictionary_filter_length_min> & C<dictionary_filter_length_max> - the minimum
4195and maximum word lengths allowed by the dictionary filter (defined by config
4196keys C<word_length_min> and C<word_length_max>)
4197
4198=item *
4199
4200C<dictionary_source> - the source of the word list loaded into the instance.
4201
4202=item *
4203
4204C<dictionary_words_filtered> - the number of words loaded from the dictionary
4205file that meet the criteria defined by the loaded config.
4206
4207=item *
4208
4209C<dictionary_words_percent_available> - the percentage of the words in the
4210dictionary file that are available for use with the loaded config.
4211
4212=item *
4213
4214C<dictionary_words_total> - the total number of words loaded from the
4215dictionary file.
4216
4217=item *
4218
4219C<password_entropy_blind_min> - the entropy (in bits) of the shortest password
4220the loaded config can generate from the point of view of a brute-force
4221attacker.
4222
4223=item *
4224
4225C<password_entropy_blind_max> - the entropy (in bits) of the longest password
4226the loaded config can generate from the point of view of a brute-force
4227attacker.
4228
4229=item *
4230
4231C<password_entropy_blind> - the entropy (in bits) of the average length
4232of passwords the loaded config can generate from the point of view of a
4233brute-force attacker.
4234
4235=item *
4236
4237C<password_entropy_seen> - the  entropy (in bits) of passwords generated by the
4238instance assuming the dictionary and config are known to the attacker.
4239
4240=item *
4241
4242C<password_length_min> - the minimum length of passwords generated by the
4243loaded config.
4244
4245=item *
4246
4247C<password_length_max> - the maximum length of passwords generated by the
4248loaded config.
4249
4250=item *
4251
4252C<password_permutations_blind_min> - the number of permutations a brute-force
4253attacker would have to try to be sure of cracking the shortest possible
4254passwords generated by this instance. Because this number can be very big, it's
4255returned as a C<Math::BigInt> object.
4256
4257=item *
4258
4259C<password_permutations_blind_max> - the number of permutations a brute-force
4260attacker would have to try to be sure of cracking the longest possible
4261passwords generated by this instance. Because this number can be very big, it's
4262returned as a C<Math::BigInt> object.
4263
4264=item *
4265
4266C<password_permutations_blind> - the number of permutations a brute-force
4267attacker would have to try to be sure of cracking an average length password
4268generated by this instance. Because this number can be very big, it's returned
4269as a C<Math::BigInt> object.
4270
4271=item *
4272
4273C<password_permutations_seen> - the number of permutations an attacker with a
4274copy of the dictionary and config would need to try to be sure of cracking a
4275password generated by this instance. Because this number can be very big, it's
4276returned as a C<Math::BigInt> object.
4277
4278=item *
4279
4280C<passwords_generated> - the number of passwords this instance has generated.
4281
4282=item *
4283
4284C<password_random_numbers_required> - the number of random numbers needed to
4285generate a single password using the loaded config.
4286
4287=item *
4288
4289C<randomnumbers_cached> - the number of random numbers currently cached within
4290the instance.
4291
4292=item *
4293
4294C<randomnumbers_cache_increment> - the number of random numbers generated at
4295once to replenish the cache when it's empty.
4296
4297=item *
4298
4299C<randomnumbers_source> - the class used by the instance to generate random
4300numbers.
4301
4302=back
4303
4304=head3 ->status()
4305
4306    print $hsxkpasswd_instance->status();
4307
4308Generates a string detailing the internal status of the instance. Below is a
4309sample status string:
4310
4311    *DICTIONARY*
4312    Source: Crypt::HSXKPasswd::Dictionary::EN
4313    # words: 1425
4314    # words of valid length: 1194 (84%)
4315
4316    *CONFIG*
4317    case_transform: 'ALTERNATE'
4318    num_words: '3'
4319    padding_character: 'RANDOM'
4320    padding_characters_after: '2'
4321    padding_characters_before: '2'
4322    padding_digits_after: '2'
4323    padding_digits_before: '2'
4324    padding_type: 'FIXED'
4325    separator_alphabet: ['!', '$', '%', '&', '*', '+', '-', '.', '/', ':', ';', '=', '?', '@', '^', '_', '|', '~']
4326    separator_character: 'RANDOM'
4327    symbol_alphabet: ['!', '$', '%', '&', '*', '+', '-', '.', '/', ':', ';', '=', '?', '@', '^', '_', '|', '~']
4328    word_length_max: '8'
4329    word_length_min: '4'
4330
4331    *RANDOM NUMBER CACHE*
4332    Random Number Generator: Crypt::HSXKPasswd::RNG::Basic
4333    # in cache: 0
4334
4335    *PASSWORD STATISTICS*
4336    Password length: between 24 & 36
4337    Permutations (brute-force): between 2.91x10^47 & 1.57x10^71 (average 2.14x10^59)
4338    Permutations (given dictionary & config): 5.51x10^15
4339    Entropy (Brute-Force): between 157bits and 236bits (average 197bits)
4340    Entropy (given dictionary & config): 52bits
4341    # Random Numbers needed per-password: 9
4342    Passwords Generated: 0
4343
4344=head3 ->update_config()
4345
4346    $hsxkpasswd_instance->update_config({separator_character => '+'});
4347
4348The function updates the config within an HSXKPasswd instance. A hashref with
4349the config options to be changed must be passed. The function returns a
4350reference to the instance to enable function chaining. The function will croak
4351if the updated config would be invalid in some way. Note that if this happens
4352the running config will not have been altered in any way.
4353
4354=head2 CLASS METHODS
4355
4356B<NOTE> - All class methods must be invoked via the package name, or they will
4357croak.
4358
4359=head3 clone_config()
4360
4361    my $clone = Crypt::HSXKPasswd->clone_config($config);
4362
4363This function must be passed a valid config hashref as the first argument or it
4364will croak. The function returns a hashref.
4365
4366=head3 config_key_definition()
4367
4368    my %key_definition = Crypt::HSXKPasswd->config_key_definition($key_name);
4369
4370A function to return the definition for a config key. The definition is returned
4371as a hash indexed by the following keys:
4372
4373=over 4
4374
4375=item *
4376
4377C<required> - 1 if the key is a required key, and 0 otherwise.
4378
4379=item *
4380
4381C<type> - a C<Type::Tiny> object representing the valid data type for the key.
4382
4383=item *
4384
4385C<expects> - an English description of valid values for the key.
4386
4387=back
4388
4389=head3 config_key_definitions()
4390
4391    my %key_definitions = Crypt::HSXKPasswd->config_key_definitions();
4392
4393A function to return definitions for all defined config keys as a hash indexed
4394by config key names. Each definition is represented as a hash with the same keys
4395as the hashes returned by the function C<config_key_definition()>.
4396
4397=head3 config_stats()
4398
4399    my %stats = Crypt::HSXKPasswd->config_stats($config);
4400    my %stats = Crypt::HSXKPasswd->config_stats(
4401        $config,
4402        suppress_warnings => 1,
4403    );
4404
4405This function requires one argument, a valid config hashref. It returns a hash
4406of statistics about a given configuration. The hash is indexed by the
4407following:
4408
4409=over 4
4410
4411=item *
4412
4413C<length_min> - the minimum length a password generated with the given
4414config could be.
4415
4416=item *
4417
4418C<length_max> - the maximum length a password generated with the given
4419config could be. (see caveat below)
4420
4421=item *
4422
4423C<random_numbers_required> - the amount of random numbers needed to generate a
4424password using the given config.
4425
4426=back
4427
4428There is one scenario in which the calculated maximum length will not be
4429reliably accurate, and that's when a character substitution with a length
4430greater than 1 is specified, and C<padding_type> is not set to C<ADAPTIVE>. If
4431the config passed contains such a character substitution, the length will be
4432calculated ignoring the possibility that one or more extra characters could
4433be introduced depending on how many, if any, of the long substitutions get
4434triggered by the randomly chosen words. If this happens the function will also
4435carp with a warning. Such warnings can be suppressed by passing an optional
4436named argument C<suppress_warnings> with the value C<1>.
4437
4438=head3 config_to_json()
4439
4440    my $config_json_string = Crypt::HSXKPasswd->config_to_json($config);
4441
4442This function returns a JSON representation of the passed config hashref as a
4443scalar string.
4444
4445The function must be passed a valid config hashref or it will
4446croak.
4447
4448=head3 config_to_string()
4449
4450    my $config_string = Crypt::HSXKPasswd->config_to_string($config);
4451
4452This function returns the content of the passed config hashref as a scalar
4453string. The function must be passed a valid config hashref or it will croak.
4454
4455=head3 default_config()
4456
4457    my $config = Crypt::HSXKPasswd->default_config();
4458
4459This function returns a hashref containing a config with default values.
4460
4461This function can optionally be called with a single argument, a hashref
4462containing keys with values to override the defaults with.
4463
4464    my $config = Crypt::HSXKPasswd->default_config({num_words => 3});
4465
4466When overrides are present, the function will carp if an invalid key or value
4467is passed, and croak if the resulting merged config is invalid.
4468
4469This function is a shortcut for C<preset_config()>, and the two examples above
4470are equivalent to the following:
4471
4472    my $config = Crypt::HSXKPasswd->preset_config('DEFAULT');
4473    my $config = Crypt::HSXKPasswd->preset_config('DEFAULT', {num_words => 3});
4474
4475=head3 defined_config_keys()
4476
4477    my @config_key_names = Crypt::HSXKPasswd->defined_config_keys();
4478
4479This function returns the list of valid config key names as an array of strings.
4480
4481=head3 defined_presets()
4482
4483    my @preset_names = Crypt::HSXKPasswd->defined_presets();
4484
4485This function returns the list of defined preset names as an array of strings.
4486
4487=head3 distil_to_config_keys()
4488
4489    my $dist_hashref = Crypt::HSXKPasswd->distil_to_config_keys($hashref);
4490
4491This function takes a hashref as an argument, and returns a deep clone of that
4492hashref containing only valid config keys with valid values.
4493
4494By default the function silently drops keys that are not valid config keys, but
4495issues a warning when dropping a key that is a valid config key, but contains an
4496invalid value. The function can also issue warnings when dropping keys that are
4497not valid config keys.
4498
4499The warnings can be controlled with a pair of optional named arguments that can
4500be added as a second argument:
4501
4502    # suppress all warnings
4503    my $dist_hashref = Crypt::HSXKPasswd->distil_to_config_keys(
4504        $hashref,
4505        suppress_warnings => 1,
4506    );
4507
4508    # emit warnings when dropping invalidly named keys
4509    my $dist_hashref = Crypt::HSXKPasswd->distil_to_config_keys(
4510        $hashref,
4511        warn_invalid_key_names => 1,
4512    );
4513
4514=head3 distil_to_symbol_alphabet()
4515
4516    my @unique_syms = Crypt::HSXKPasswd->distil_to_symbol_alphabet($arrayref);
4517    my @unique_syms = Crypt::HSXKPasswd->distil_to_symbol_alphabet(
4518        $arrayref,
4519        warn => 1,
4520    );
4521
4522This function takes reference to an array of strings and returns a new array
4523containing all the valid symbols from the referenced array. The valid symbols
4524are de-duplicated before being returned.
4525
4526By default the function silently skips over strings that are not valid symbols.
4527The function can be made issue warnings each time a string is skipped by passing
4528a named argument C<warn> with a value of C<1> (C<0> can also be passed to
4529explicitly disable warnings).
4530
4531=head3 distil_to_words()
4532
4533    my @valid_unique_words = Crypt::HSXKPasswd->distil_to_words($arrayref);
4534    my @valid_unique_words = Crypt::HSXKPasswd->distil_to_words(
4535        $arrayref,
4536        warn => 1,
4537    );
4538
4539This function takes reference to an array of strings and returns a new array
4540containing all the valid words from the referenced array. The valid words are
4541de-duplicated before being returned.
4542
4543By default the function silently skips over strings that are not valid words.
4544The function can be made issue warnings each time a string is skipped by passing
4545a named argument C<warn> with a value of C<1> (C<0> can also be passed to
4546explicitly disable warnings).
4547
4548=head3 is_valid_config()
4549
4550    # determine the validity
4551    my $is_ok = Crypt::HSXKPasswd->is_valid_config($config);
4552
4553    # assert the validity - will croak if the config is invalid
4554    Crypt::HSXKPasswd->is_valid_config($config, croak => 1);
4555
4556This function must be passed a hashref to test as the first argument. The
4557function returns 1 if the passed config is valid, and 0 otherwise.
4558
4559Optionally, a named argument C<croak> can also be passed to control whether or
4560not the function should croak if the config is invalid. The value of this named
4561argument should be C<1> or C<0>.
4562
4563When calling the function with C<croak> set to C<1>, the message thrown by croak
4564will explain why the config is invalid.
4565
4566    use English qw( -no_match_vars );
4567    eval{
4568        Crypt::HSXKPasswd->is_valid_config($config, croak => 1);
4569    }or do{
4570        print "ERROR - config is invalid because: $EVAL_ERROR\n";
4571    }
4572
4573=head3 module_config()
4574
4575    my $debug_val = Crypt::HSXKPasswd->module_config('DEBUG'); # getter
4576    Crypt::HSXKPasswd->module_config('DEBUG', 1); # setter
4577
4578This function is used to access or alter the value of one of the module
4579configuration settings. The first function must always be a valid module
4580configuration key name. If no second argument is provided, the value stored
4581in the module configuration key will not be updated. To update the stored value,
4582pass a new value as a second argument. Regardless of whether or not a second
4583argument is passed, the value stored in the module configuration key is always
4584returned.
4585
4586The function will croak if called with an invalid module configuration key name,
4587or passed an invalid new value.
4588
4589For a list of the module configuration keys, see the MODULE CONFIGURATION
4590section of this document.
4591
4592=head3 preset_config()
4593
4594    my $config = Crypt::HSXKPasswd->preset_config('XKCD');
4595
4596This function returns the config hashref for a given preset. See above for the
4597list of available presets.
4598
4599The first argument this function accepts is the name of the desired preset as a
4600scalar. If an invalid name is passed, the function will carp. If no preset is
4601passed the preset C<DEFAULT> is assumed.
4602
4603This function can optionally accept a second argument, a hashref
4604containing keys with values to override the defaults with.
4605
4606    my $config = Crypt::HSXKPasswd->preset_config(
4607        'XKCD',
4608        {case_transform => 'INVERT'}
4609    );
4610
4611When overrides are present, the function will carp if an invalid key or value is
4612passed, and croak if the resulting merged config is invalid.
4613
4614=head3 preset_definition()
4615
4616    my %preset_def = Crypt::HSXKPasswd->preset_definition('XKCD');
4617
4618This function returns a hash defining a preset. The hash contains
4619an English description of the preset indexed be C<description> and
4620a config hashref indexed by C<config>.
4621
4622The function expects to be called with one argument, a valid preset name, but it
4623can be called without arguments, in which case it will return the definition for
4624the preset c<DEFAULT>.
4625
4626You can see all the defined presets in the PRESETS section of this document, and
4627you can get a list of valid preset names programatically with the function
4628C<defined_presets()>.
4629
4630=head3 preset_definitions()
4631
4632    my %preset_defs = Crypt::HSXKPasswd->preset_definitions();
4633
4634This function returns a hash of all defined presets indexed by preset name. Each
4635preset definition is a hash as returned by C<preset_definition()>.
4636
4637This function does not take any arguments.
4638
4639=head3 presets_json()
4640
4641    my $json_string = Crypt::HSXKPasswd->presets_json();
4642
4643This function returns a JSON string representing all the defined configs,
4644including their descriptions.
4645
4646The returned JSON string represents a hashref indexed by three keys:
4647C<defined_keys> contains an array of preset identifiers, C<presets> contains the
4648preset configs indexed by reset identifier, and C<preset_descriptions> contains
4649a hashref of descriptions indexed by preset identifiers.
4650
4651=head3 preset_description()
4652
4653    my $description = Crypt::HSXKPasswd->preset_description('XKCD');
4654
4655This function returns the description for a given preset. See above for the
4656list of available presets.
4657
4658The first argument this function accepts is the name of the desired preset as a
4659scalar. If an invalid name is passed, the function will carp. If no preset is
4660passed the preset C<DEFAULT> is assumed.
4661
4662=head3 presets_to_string()
4663
4664    print Crypt::HSXKPasswd->presets_to_string();
4665
4666This function returns a string containing a description of each defined preset
4667and the configs associated with the presets.
4668
4669=head2 COMMANDLINE INTERFACE
4670
4671The module ships with a commandline interface to this library, simply called
4672C<hsxkpasswd>.
4673
4674This interface allows for the generation of multiple passwords at a time, the
4675use of presets and preset overrides, the use of custom password generator
4676configurations, the use of custom word sources, and the use of custom random
4677number generators.
4678
4679Both preset overrides and password generator configurations must be specified
4680in JSON format.
4681
4682=head3 Examples
4683
4684Generate a single password using all the default settings:
4685
4686    hsxkpasswd
4687
4688Generate five passwords using the default settings:
4689
4690    hsxkpasswd 5
4691
4692Generate five passwords using the C<XKCD> preset:
4693
4694    hsxkpasswd -p XKCD 5
4695
4696Generate five passwords using the C<XKCD> preset with an overridden password
4697generator configuration key:
4698
4699    hsxkpasswd -p XKCD -o '{"separator_character" : "*"}' 5
4700
4701Generate five passwords using a custom password generator configuration stored
4702in a text file in JSON format:
4703
4704    hsxkpasswd -c my_config.json
4705
4706=head3 Further Reading
4707
4708The examples above are just a sample of what the command can do, for complete
4709documentation, run the command with the -h flag:
4710
4711    hsxkpasswd -h
4712
4713If you are new to JSON, you may find the following links useful:
4714
4715=over 4
4716
4717=item *
4718
4719JSON on Wikipedia - L<http://en.wikipedia.org/wiki/JSON>
4720
4721=item *
4722
4723A free online JSON validator - L<http://jsonformatter.curiousconcept.com>
4724
4725=item *
4726
4727A JSON tutorial from W3Schools - L<http://www.w3schools.com/json/>
4728
4729=back
4730
4731=head2 ENTROPY CHECKING
4732
4733For security reasons, this module's default behaviour is to warn (using
4734C<carp()>) when ever the loaded combination of word source and configuration
4735would result in low-entropy passwords. When the constructor is invoked, or when
4736an instance's the word source or config are altered (using C<dictionary()> or
4737C<config()>), the entropy is re-calculated and re-checked against the defined
4738minima.
4739
4740Entropy is calculated and checked for two scenarios. Firstly, for the best-case
4741scenario, when an attacker has no prior knowledge about the password, and must
4742resort to a brute-force attack. And secondly, for the worst-case scenario, when
4743the attacker is assumed to know that this module was used to generate the
4744password, and, that the attacker has a copy of the word source and config
4745settings used to generate the password.
4746
4747Entropy checking is controlled via three module configuration variables (which
4748can be accessed and updated using the function C<module_config()>):
4749
4750=over 4
4751
4752=item *
4753
4754C<ENTROPY_MIN_BLIND> - the minimum acceptable entropy in bits for a brute-force
4755attack. The default value is 78bits, the equivalent to a 12 character password
4756consisting of mixed-case letters, digits, and symbols.
4757
4758=item *
4759
4760C<ENTROPY_MIN_SEEN> - the minimum acceptable entropy in bits for a worst-case
4761scenario (where the word source and config are known). The default value is
476252bits, equivalent to an 8 character password consisting of mixed-case letters,
4763digits, and symbols.
4764
4765=item *
4766
4767C<ENTROPY_WARNINGS> - this variable can be used to control the emission of
4768entropy warnings. The following values are valid:
4769
4770=over 4
4771
4772=item *
4773
4774C<ALL> - all entropy warnings are emitted. This is the default value.
4775
4776=item *
4777
4778C<BLIND> - only warnings for the best-case scenario are emitted. I.e. warnings
4779for the worst-case scenario (attacker has full knowledge) are suppressed.
4780
4781=item *
4782
4783C<NONE> - all entropy warnings are suppressed.
4784
4785=back
4786
4787=back
4788
4789=head3 Caveats
4790
4791The entropy calculations make some assumptions which may in some cases lead to
4792the results being inaccurate. In general, an attempt has been made to always
4793round down, meaning that in reality the entropy of the produced passwords may
4794be higher than the values calculated by the package.
4795
4796When calculating the entropy for brute force attacks on configurations that can
4797result in variable length passwords, the shortest possible password is assumed.
4798
4799When calculating the entropy for brute force attacks on configurations that
4800contain at least one symbol, it is assumed that an attacker would have to
4801brute-force-check 33 symbols. This is the same value used by Steve Gibson's
4802I<Password Haystacks> calculator (L<https://www.grc.com/haystack.htm>).
4803
4804When calculating the entropy for worst-case attacks on configurations that
4805contain symbol substitutions where the replacement is more than 1 character
4806long the possible extra length is ignored.
4807
4808=head2 WORD SOURCES (DICTIONARIES)
4809
4810The abstract class C<Crypt::HSXKPasswd::Dictionary> acts as a base class for
4811sources of words for use by this module. Word sources should extend this base
4812class and implement the function C<word_list()>, which should return an array
4813of words.
4814
4815In order to produce secure passwords it's important to use a word source that
4816contains a large selection of words with a good mix of different lengths of
4817words.
4818
4819The module ships with a number of pre-defined word sources:
4820
4821=head3 C<Crypt::HSXKPasswd::Dictionary::DE>
4822
4823A German word list based on the GPL-licensed German dictionary for WinEdit by
4824Juergen Vierheilig.
4825
4826B<Note:> This module is licensed under the GPL, not the BSD license used for the
4827majority of this project.
4828
4829=head3 C<Crypt::HSXKPasswd::Dictionary::EN>
4830
4831A default word list consisting of English words and place names.
4832
4833=head3 C<Crypt::HSXKPasswd::Dictionary::ES>
4834
4835A Spanish word list based on the BSD-licensed Spanish dictionary for WinEdit by
4836Juan L. Varona from the Universidad de La Rioja.
4837
4838=head3 C<Crypt::HSXKPasswd::Dictionary::FR>
4839
4840A French word list based on the GPL-licensed French dictionary for WinEdit.
4841
4842B<Note:> This module is licensed under GPL V2, not the BSD license used for the
4843majority of this project.
4844
4845=head3 C<Crypt::HSXKPasswd::Dictionary::IT>
4846
4847An Italian word list based on the free-for-non-commerical-use Italian dictionary
4848for WinEdit by Karl Koeller.
4849
4850B<Note:> This module is licensed under GPL V2, not the BSD license used for the
4851majority of this project.
4852
4853=head3 C<Crypt::HSXKPasswd::Dictionary::NL>
4854
4855A Dutch/Flemish word list based on the GPL-licensed Dutch dictionary for WinEdit.
4856
4857B<Note:> This module is licensed under GPL V2, not the BSD license used for the
4858majority of this project.
4859
4860=head3 C<Crypt::HSXKPasswd::Dictionary::PT>
4861
4862A Portuguese word list based on the GPL-licensed Portuguese dictionary for
4863WinEdit compiled by Bernhard Enders (building on work by Raimundo Santos Moura &
4864Ricardo Ueda Karpischek).
4865
4866B<Note:> This module is licensed under GPL V2.1, not the BSD license used for
4867the majority of this project.
4868
4869=head3 C<Crypt::HSXKPasswd::Dictionary::System>
4870
4871This class tries to find and use a Unix words file on the system.
4872
4873The constructor croaks if no system words file can be found.
4874
4875=head4 Usage
4876
4877    my $word_source = Crypt::HSXKPasswd::Dictionary::System->new();
4878
4879=head3 C<Crypt::HSXKPasswd::Dictionary::Basic>
4880
4881This class can be initialised from a words file, or from an array ref
4882containing words.
4883
4884=head4 Usage
4885
4886    my $word_source = Crypt::HSXKPasswd::Dictionary::Basic->new('file_path');
4887    my $word_source = Crypt::HSXKPasswd::Dictionary::Basic->new(
4888        'file_path',
4889        'Latin1'
4890    );
4891    my $word_source = Crypt::HSXKPasswd::Dictionary::Basic->new($array_ref);
4892
4893
4894The rules for the formatting of dictionary files are simple. Dictionary
4895files must contain one word per line. Words shorter than four letters will be
4896ignored, as will all lines starting with the # symbol. Files are assumed to be
4897UTF-8 encoded, but an optional second argument can be passed specifying a
4898different file encoding.
4899
4900This format is the same as that of the standard Unix Words file, usually found
4901at C</usr/share/dict/words> on Unix and Linux operating systems (including OS
4902X).
4903
4904=head2 RANDOM NUMBER SOURCES
4905
4906In order to minimise the number of non-standard modules this module requires,
4907the default source of randomness is Perl's built-in C<rand()> function. This
4908provides a reasonable level of randomness, and should suffice for most users,
4909however, some users will prefer to make use of one of the many advanced
4910randomisation modules in CPAN, or, reach out to a web service like
4911L<http://random.org> for their random numbers. To facilitate both of these
4912options, this module uses a cache of randomness, and provides an abstract
4913Random Number Generator (RNG) class that can be extended.
4914
4915The module can use an instance of any class that extends
4916C<Crypt::HSXKPasswd::RNG> as it's source of randomness. Custom RNG classes
4917must implement the method C<random_numbers()> which will be invoked on an
4918instance of the class and passed one argument, the number of random numbers
4919required to generate a single password. The function must return an array
4920of random numbers between 0 and 1. The number of random numbers returned is
4921entirely up to the module to decide. The number required for a single password
4922is passed purely as a guide. The function must always return at least one
4923random number.
4924
4925The module ships with five standard RNGs (described below).
4926
4927By default, the module will try to use one of the following four RNGs, listed
4928from most to least preferred, depending on what is available on the system:
4929
4930=over 4
4931
4932=item 1
4933
4934C<Crypt::HSXKPasswd::RNG::Math_Random_Secure> (only available if
4935C<Math::Random::Secure> is installed on the system).
4936
4937=item 2
4938
4939C<Crypt::HSXKPasswd::RNG::Data_Entropy> (only available if
4940C<Data::Entropy::Algorithms> is installed on the system).
4941
4942=item 3
4943
4944C<Crypt::HSXKPasswd::RNG::DevUrandom> (only available on Linux/Unix systems
4945with a C</dev/urandom>).
4946
4947=item 4
4948
4949C<Crypt::HSXKPasswd::RNG::Basic> (available on all systems because it uses
4950Perl's built-in C<rand()> function).
4951
4952=back
4953
4954If the constructor is called without specifying an RNG, and if the only
4955available RNG is C<Crypt::HSXKPasswd::RNG::Basic>, a warning will be thrown
4956suggesting installing C<Math::Random::Secure> or C<Data::Entropy::Algorithms>.
4957
4958The module also ships with a fifth RNG, C<Crypt::HSXKPasswd::RNG::RandomDotOrg>,
4959but this one must be explicitly used, the constructor will never used it by
4960default. As its name suggests, this class uses L<http://Random.Org/>'s HTTP API
4961to generate random numbers.
4962
4963To explicitly use any particular RNG, create an instance of it, and either pass
4964that instance to the constructor with the named argument C<rng>, or, set the RNG
4965after instantiating the object using the C<rng()> function.
4966
4967=head3 Crypt::HSXKPasswd::RNG::Math_Random_Secure
4968
4969    my $rng = Crypt::HSXKPasswd::RNG::Math_Random_Secure->new();
4970
4971This is the preferred RNG because it is both fast and secure, but, it requires
4972the non-standard module C<Math::Random::Secure>
4973(L<http://search.cpan.org/perldoc?Math%3A%3ARandom%3A%3ASecure>) be installed.
4974
4975=head3 Crypt::HSXKPasswd::RNG::Data_Entropy
4976
4977    my $rng = Crypt::HSXKPasswd::RNG::Data_Entropy->new();
4978
4979This RNG is secure, but it is quite slow (about six times slower than
4980C<Crypt::HSXKPasswd::RNG::Math_Random_Secure>), and it requires
4981the non-standard module C<Data::Entropy::Algorithms>
4982(L<http://search.cpan.org/perldoc?Data%3A%3AEntropy%3A%3AAlgorithms>) be
4983installed.
4984
4985=head3 Crypt::HSXKPasswd::RNG::DevUrandom
4986
4987    my $rng = Crypt::HSXKPasswd::RNG::DevUrandom->new();
4988
4989This RNG is secure and relatively fast (faster than
4990C<Crypt::HSXKPasswd::RNG::Data_Entropy> but slower than
4991C<Crypt::HSXKPasswd::RNG::Math_Random_Secure>), but is only available on
4992Linux/Unix systems with a C</dev/urandom> special file.
4993
4994=head3 Crypt::HSXKPasswd::RNG::Basic
4995
4996    my $rng = Crypt::HSXKPasswd::RNG::Basic->new();
4997
4998This RNG uses Perl's built-in C<rand()> function as its source of randomness,
4999and this is sub-optimal. The Perl docs warn that C<rand()> is not a particularly
5000good source of random numbers, and advises against its use for cryptography.
5001
5002This RNG provides a base-line, and should only be used if none of the better
5003RNGs are available. While it is sub-optimal, it will still generate passwords
5004with sufficient entropy in most situations. Ultimately, even using this
5005imperfect RNG, this module will still produce passwords that are much better
5006than those produced by the human imagination!
5007
5008=head3 Crypt::HSXKPasswd::RNG::RandomDotOrg
5009
5010    my $rng = Crypt::HSXKPasswd::RNG::RandomDotOrg->new('my.address@my.dom');
5011    my $rng = Crypt::HSXKPasswd::RNG::RandomDotOrg->new('my.address@my.dom',
5012        timeout => 180,
5013        num_passwords => 3,
5014    );
5015
5016This RNG serves as a usable example of an RNG that queries a web service. As its
5017name suggests, this class uses L<http://Random.Org/>'s HTTP API to generate
5018random numbers.
5019
5020In order to comply with Random.Org's client guidelines
5021(L<https://www.random.org/clients/>), this module requires that a valid email
5022address be passed as the first argument.
5023
5024The client guidelines also request that clients use long timeouts, and batch
5025their requests. They prefer to be asked for more number less frequently than
5026less numbers more frequently. For this reason the class's default behaviour is
5027to use a timeout of 180 seconds, and to request enough random numbers to
5028generate three passwords at a time.
5029
5030These defaults can be overridden by passing named arguments to the constructor
5031after the email address. The following named arguments are supported:
5032
5033=over 4
5034
5035=item *
5036
5037C<timeout> - the timeout to use when making HTTP requests to Random.Org in
5038seconds (the default is 180).
5039
5040=item *
5041
5042C<num_passwords> - the number of password generations to fetch random numbers
5043for per request from Random.org. This value is in effect a multiplier for the
5044value passed to the C<random_numbers()> function by C<Crypt::HSXKPasswd>.
5045
5046C<num_absolute> - the absolute number of random numbers to fetch per request
5047to Random.Org. This argument takes precedence over C<num_passwords>.
5048
5049=back
5050
5051C<num_passwords> and C<num_absolute> should not be used together, but if they
5052are, C<num_absolute> use used, and C<num_passwords> is ignored.
5053
5054This class  requires a number of modules not used by any other classes under
5055C<Crypt::HSXKPasswd>, and not listed in that module's requirements. If all of
5056the following modules are not installed, the constructor will croak:
5057
5058=over 4
5059
5060=item *
5061
5062C<Email::Valid>
5063
5064=item *
5065
5066C<LWP::UserAgent>
5067
5068=item *
5069
5070C<Mozilla::CA>
5071
5072=item *
5073
5074C<URI>
5075
5076=back
5077
5078=head1 DIAGNOSTICS
5079
5080By default this module does all of it's error notification via the functions
5081C<carp()>, C<croak()>, and C<confess()> from the C<Carp> module. Optionally,
5082all error messages can also be printed to a stream. To enable the printing of
5083messages, set the  C<LOG_ERRORS> module configuration variable to C<1>. All
5084error messages will then be printed to the stream defined by the module
5085configuration variable C<LOG_STREAM>, which is set to C<STDERR> by default.
5086
5087Ordinarily this module produces very little output. To enable more verbose
5088output the module configuration variable C<DEBUG> can be set to C<1>. Debug
5089message are printed to the stream specified by the module variable
5090C<LOG_STREAM>.
5091
5092This module produces output at three severity levels:
5093
5094=over 4
5095
5096=item *
5097
5098C<DEBUG> - this output is completely suppressed unless the module configuration
5099variable C<DEBUG> is set to C<1>. All debug messages are printed to the stream
5100defined in the module configuration variable C<LOG_STREAM> (regardless of the
5101the value of the module configuration variable C<LOG_ERRORS>).
5102
5103=item *
5104
5105C<WARNING> - warning messages are always thrown with C<carp()>, and also printed
5106to the stream specified by the module configuration variable C<LOG_STREAM> if
5107the module configuration variable C<LOG_ERRORS> is set to C<1>.
5108
5109=item *
5110
5111C<ERROR> - error messages are usually thrown with C<croak()>, but will be thrown
5112with C<confess()> if the module configuration variable C<DEBUG> is set to C<1>.
5113If the module configuration variable C<LOG_ERRORS> is set to C<1> errors are
5114also printed to the stream defined by the module configuration variable
5115C<LOG_STREAM>, including a stack trace if the module configuration variable
5116C<DEBUG> is set to C<1> and the module C<Devel::StackTrace> is installed.
5117
5118=back
5119
5120The value stored in a module configuration variable can be accessed and updated
5121using the function C<module_config()>.
5122
5123=head1 CONFIGURATION AND ENVIRONMENT
5124
5125This module does not currently support configuration files, nor does it
5126currently interact with the environment. It may do so in future versions.
5127
5128=head1 DEPENDENCIES
5129
5130This module requires the following Perl modules:
5131
5132=over 4
5133
5134=item *
5135
5136C<Carp> - L<http://search.cpan.org/perldoc?Carp>
5137
5138=item *
5139
5140C<Clone> - L<http://search.cpan.org/perldoc?Clone>
5141
5142=item *
5143
5144C<DateTime> - L<http://search.cpan.org/perldoc?DateTime>
5145
5146=item *
5147
5148C<English> - L<http://search.cpan.org/perldoc?English>
5149
5150=item *
5151
5152C<Fatal> - L<http://search.cpan.org/perldoc?Fatal>
5153
5154=item *
5155
5156C<File::HomeDir> - L<http://search.cpan.org/perldoc?File%3A%3AHomeDir>
5157
5158=item *
5159
5160C<Getopt::Long> - L<http://search.cpan.org/perldoc?Getopt%3A%3ALong>
5161
5162=item *
5163
5164C<JSON> - L<http://search.cpan.org/perldoc?JSON>
5165
5166=item *
5167
5168C<List::MoreUtils> - L<http://search.cpan.org/perldoc?List%3A%3AMoreUtils>
5169
5170=item *
5171
5172C<Math::BigInt> - L<http://search.cpan.org/perldoc?Math%3A%3ABigInt>
5173
5174=item *
5175
5176C<Math::Round> - L<http://search.cpan.org/perldoc?Math%3A%3ARound>
5177
5178=item *
5179
5180C<Module::Load> - L<http://search.cpan.org/perldoc?Module%3A%3ALoad>
5181
5182=item *
5183
5184C<Pod::Usage> - L<http://search.cpan.org/perldoc?Pod%3A%3AUsage>
5185
5186=item *
5187
5188C<Readonly> - L<http://search.cpan.org/perldoc?Readonly>
5189
5190=item *
5191
5192C<Scalar::Util> - L<http://search.cpan.org/perldoc?Scalar%3A%3AUtil>
5193
5194=item *
5195
5196C<strict> - L<http://search.cpan.org/perldoc?strict>
5197
5198=item *
5199
5200C<Text::Unidecode> - L<http://search.cpan.org/perldoc?Text%3A%3AUnidecode>
5201
5202=item *
5203
5204C<Type::Library> - L<http://search.cpan.org/perldoc?Type%3A%3ALibrary>
5205
5206=item *
5207
5208C<Type::Params> - L<http://search.cpan.org/perldoc?Type%3A%3AParams>
5209
5210=item *
5211
5212C<Type::Tiny> - L<http://search.cpan.org/perldoc?Type%3A%3ATiny>
5213
5214=item *
5215
5216C<Types::Standard> - L<http://search.cpan.org/perldoc?Types%3A%3AStandard>
5217
5218=item *
5219
5220C<warnings> - L<http://search.cpan.org/perldoc?warnings>
5221
5222=back
5223
5224The module can also optionally use the following Perl modules:
5225
5226=over 4
5227
5228=item *
5229
5230C<Data::Entropy::Algorithms> - L<http://search.cpan.org/perldoc?Data%3A%3AEntropy%3A%3AAlgorithms>
5231
5232Used by the RNG class C<Crypt::HSXKPasswd::RNG::Data_Entropy>.
5233
5234=item *
5235
5236C<Devel::StackTrace> - L<http://search.cpan.org/perldoc?Devel%3A%3AStackTrace>
5237
5238Used for printing stack traces with error messages if
5239C<$XKPasswd::DEBUG> and C<$XKPasswd::LOG_ERRORS> both evaluate to true. If the
5240module is not installed the stack traces will be omitted from the log messages.
5241
5242=item *
5243
5244C<Email::Valid> - L<http://search.cpan.org/perldoc?Email%3A%3AValid>
5245
5246Used by the Random.Org RNG class C<Crypt::HSXKPasswd::RNG::RandomDotOrg>.
5247
5248=item *
5249
5250C<LWP::UserAgent> - L<http://search.cpan.org/perldoc?LWP%3A%3AUserAgent>
5251
5252Used by the Random.Org RNG class C<Crypt::HSXKPasswd::RNG::RandomDotOrg>.
5253
5254=item *
5255
5256C<Math::Random::Secure> - L<http://search.cpan.org/perldoc?Math%3A%3ARandom%3A%3ASecure>
5257
5258Used by the RNG class C<Crypt::HSXKPasswd::RNG::Math_Random_Secure>.
5259
5260=item *
5261
5262C<Mozilla::CA> - L<http://search.cpan.org/perldoc?Mozilla%3A%3ACA>
5263
5264Indirectly required by the Random.Org RNG class
5265C<Crypt::HSXKPasswd::RNG::RandomDotOrg> because without it C<LWP::UserAgent>
5266can't use HTTPS, and the Random.Org API uses HTTPS.
5267
5268=item *
5269
5270C<URI> - L<http://search.cpan.org/perldoc?URI>
5271
5272Used by the Random.Org RNG class C<Crypt::HSXKPasswd::RNG::RandomDotOrg>.
5273
5274=back
5275
5276=head1 INCOMPATIBILITIES
5277
5278This module has no known incompatibilities.
5279
5280=head1 BUGS AND LIMITATIONS
5281
5282There are no known bugs in this module.
5283
5284Please report any bugs you may find on the module's GitHub page:
5285L<https://github.com/bbusschots/xkpasswd.pm>.
5286
5287=head1 LICENCE AND COPYRIGHT
5288
5289Copyright (c) 2014-15, Bart Busschots T/A Bartificer Web Solutions
5290All rights reserved.
5291
5292Redistribution and use in source and binary forms, with or without
5293modification, are permitted provided that the following conditions are met:
5294
5295=over 4
5296
5297=item 1.
5298
5299Redistributions of source code must retain the above copyright notice, this
5300list of conditions and the following disclaimer.
5301
5302=item 2.
5303
5304Redistributions in binary form must reproduce the above copyright notice,
5305this list of conditions and the following disclaimer in the documentation
5306and/or other materials provided with the distribution.
5307
5308=back
5309
5310THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
5311ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
5312WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
5313DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
5314ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
5315(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
5316LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
5317ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5318(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
5319SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5320
5321The following components of this package are covered by the more restrictive
5322GPL V2 license L<https://www.gnu.org/licenses/gpl-2.0.html>:
5323
5324=over 4
5325
5326=item *
5327
5328The C<share/sample_dict_DE.txt> text file.
5329
5330=item *
5331
5332The C<Crypt::HSXKPasswd::Dictionary::DE> Perl module.
5333
5334=item *
5335
5336The C<share/sample_dict_FR.txt> text file.
5337
5338=item *
5339
5340The C<Crypt::HSXKPasswd::Dictionary::FR> Perl module.
5341
5342=item *
5343
5344The C<share/sample_dict_IT.txt> text file.
5345
5346=item *
5347
5348The C<Crypt::HSXKPasswd::Dictionary::IT> Perl module.
5349
5350=item *
5351
5352The C<share/sample_dict_NL.txt> text file.
5353
5354=item *
5355
5356The C<Crypt::HSXKPasswd::Dictionary::NL> Perl module.
5357
5358=item *
5359
5360The C<share/sample_dict_PT.txt> text file.
5361
5362=item *
5363
5364The C<Crypt::HSXKPasswd::Dictionary::PT> Perl module.
5365
5366=back
5367
5368=head1 AUTHOR
5369
5370Bart Busschots (L<mailto:bart@bartificer.net>)