File: TimeEstimate.pm

package info (click to toggle)
libdata-password-zxcvbn-perl 1.1.2-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 3,564 kB
  • sloc: perl: 100,726; makefile: 9
file content (240 lines) | stat: -rw-r--r-- 5,315 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
package Data::Password::zxcvbn::TimeEstimate;
use strict;
use warnings;
use Exporter 'import';
our @EXPORT_OK=qw(estimate_attack_times guesses_to_score display_time);
our $VERSION = '1.1.2'; # VERSION
# ABSTRACT: functions to estimate cracking times


sub estimate_attack_times {
    my ($guesses) = @_;
    my %crack_times_seconds = (
        online_throttling_100_per_hour => $guesses / (100.0 / 3600.0),
        online_no_throttling_10_per_second => $guesses / 10.0,
        offline_slow_hashing_1e4_per_second => $guesses / 1e4,
        offline_fast_hashing_1e10_per_second => $guesses / 1e10,
    );

    my %crack_times_display = map {
        $_ => display_time($crack_times_seconds{$_})
    } keys %crack_times_seconds;

    return {
        crack_times_seconds => \%crack_times_seconds,
        crack_times_display => \%crack_times_display,
    };
}


# the +5 are apparently there to avoid fencepost errors
my @score_scales = (
    1e3+5, # risky password: "too guessable"

    1e6+5, # modest protection from throttled online attacks: "very guessable"

    1e8+5, # modest protection from unthrottled online attacks:
           # "somewhat guessable"

    1e10+5, # modest protection from offline attacks: "safely
            # unguessable" assuming a salted, slow hash function like
            # bcrypt, scrypt, PBKDF2, argon, etc

    # else: strong protection from offline attacks under same
    # scenario: "very unguessable"
);
sub guesses_to_score {
    my ($guesses) = @_;

    for my $score (0..$#score_scales) {
        if ($guesses < $score_scales[$score]) {
            return $score
        }
    }

    return scalar @score_scales;
}


my @display_scales = (
    # if it's less than this, use this name
    # (otherwise divide by the number, and carry on)
    [ 60 => 'second' ],
    [ 60 => 'minute' ],
    [ 24 => 'hour' ],
    [ 30 => 'day' ],
    [ 12 => 'month' ],
    [ 100 => 'year' ],
);

sub display_time {
    my ($time) = @_;
    return ['less than a second']
        if $time < 1;

    for my $scale (@display_scales) {
        if ($time < $scale->[0]) {
            return [ "[quant,_1,$scale->[1]]", int($time) ];
        }
        $time /= $scale->[0];
    }

    return ['centuries'];
}

1;

__END__

=pod

=encoding UTF-8

=for :stopwords PBKDF2 scrypt bcrypt un

=head1 NAME

Data::Password::zxcvbn::TimeEstimate - functions to estimate cracking times

=head1 VERSION

version 1.1.2

=head1 SYNOPSIS

  use Data::Password::zxcvbn::TimeEstimate qw(estimate_attack_times);
  my $estimates = estimate_attack_times($number_of_guesses);

=head1 DESCRIPTION

This module provides functions for back-of-the-envelope crack time
estimations, in seconds, based on a few scenarios.

=head1 FUNCTIONS

=head2 C<estimate_attack_times>

  my $estimates = estimate_attack_times($number_of_guesses);

Returns a hashref with two keys:

=over 4

=item *

C<crack_times_seconds>

hashref of back-of-the-envelope crack time estimations, in seconds,
based on a few scenarios:

=over 4

=item *

C<online_throttling_100_per_hour>

online attack on a service that rate-limits authentication attempts

=item *

C<online_no_throttling_10_per_second>

online attack on a service that doesn't rate-limit, or where an
attacker has outsmarted rate-limiting.

=item *

C<offline_slow_hashing_1e4_per_second>

offline attack. assumes multiple attackers, proper user-unique
salting, and a slow hash function with moderate work factor, such as
bcrypt, scrypt, PBKDF2.

=item *

C<offline_fast_hashing_1e10_per_second>

offline attack with user-unique salting but a fast hash function like
SHA-1, SHA-256 or MD5. A wide range of reasonable numbers anywhere
from one billion - one trillion guesses per second, depending on
number of cores and machines; ball-parking at 10B/sec.

=back

=item *

C<crack_times_display>

same keys as C<crack_times_seconds>, but more useful for display: the
values are arrayrefs C<["english string",$value]> that can be passed
to I18N libraries like L<< C<Locale::Maketext> >> to get localised
versions with proper plurals

=back

=head2 C<guesses_to_score>

 my $score = guesses_to_score($number_of_guesses);

Returns an integer from 0-4 (useful for implementing a strength bar):

=over 4

=item *

C<0>

too guessable: risky password. (C<< guesses < 10e3 >>)

=item *

C<1>

very guessable: protection from throttled online attacks. (C<< guesses
< 10e6 >>)

=item *

C<2>

somewhat guessable: protection from un-throttled online attacks. (C<<
guesses < 10e8 >>)

=item *

C<3>

safely un-guessable: moderate protection from offline slow-hash
scenario. (C<< guesses < 10e10 >>)

=item *

C<4>

very un-guessable: strong protection from offline slow-hash
scenario. (C<< guesses >= 10e10 >>)

=back

=head2 C<display_time>

  my ($string,@values) = @{ display_time($time) };
  print My::Localise->get_handle->maketext($string,@values);

Given a C<$time> in seconds, returns an arrayref suitable for
L<< C<Locale::Maketext> >>, like:

 [ 'quant,_1,day', 23 ]

=head1 AUTHOR

Gianni Ceccarelli <gianni.ceccarelli@broadbean.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2022 by BroadBean UK, a CareerBuilder Company.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut