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
|
#!perl
use strict;
use warnings;
use Time::HiRes 'time';
use Crypt::Argon2;
sub prompt {
my ($mess, $def) = @_;
my $dispdef = defined $def ? ("[$def] " ) : '';
local $| = 1;
print "$mess ", $dispdef;
my $ans = <STDIN>;
chomp $ans;
if (not defined $ans or not length $ans) {
$ans = defined $def ? $def : '';
}
return $ans;
}
my %encoder = (
argon2id => \&Crypt::Argon2::argon2id_raw,
argon2i => \&Crypt::Argon2::argon2i_raw,
argon2d => \&Crypt::Argon2::argon2d_raw,
);
my $type = prompt('What type of hash?', 'argon2id');
my $encoder = $encoder{$type} or die "Invalid type $type";
my $threads = prompt('How many threads may it use', 1);
die "Invalid number '$threads'" unless $threads > 0;
my $mem_cost = prompt('How much memory may it use (e.g. 32M)');
die "Invalid memory usage '$mem_cost'" unless $mem_cost =~ / ^ \d+ [hMG] $ /x;
my $max_time = prompt('How much time may argon2 take? (in milliseconds)');
die 'No time given' unless $max_time > 0;
my $begin = time;
$encoder->("correct horse battery staple", scalar("\x00" x 16), 100, $mem_cost, $threads, 16);
my $end = time;
my $time_per_round = ($end - $begin) * 10;
my $time_cost = int($max_time / $time_per_round);
die "Can't compute a hash in the given time (took $time_per_round milliseconds)" if $time_cost == 0;
die "Unsafe parameters were computed" if $type eq 'argon2i' && $time_cost < 3;
print <<"END";
type = $type
threads = $threads
mem_cost = $mem_cost
time_cost = $time_cost
END
# PODNAME: argon2-calibrate
# ABSTRACT: a script to find the appropriate argon2 parameters
__END__
=pod
=encoding UTF-8
=head1 NAME
argon2-calibrate - a script to find the appropriate argon2 parameters
=head1 VERSION
version 0.030
=head1 DESCRIPTION
This program implements the following procedure, as recommended by the argon2 authors:
=over 4
=item 1. Select the type C<y>. If you do not know the difference between them, choose Argon2id.
=item 2. Figure out the maximum number of threads C<h> that can be initiated by each call to Argon2. This is the C<parallelism> argument.
=item 3. Figure out the maximum amount of memory C<m> that each call can a afford.
=item 4. Figure out the maximum amount C<x> of time (in seconds) that each call can a afford.
=item 5. Select the salt length. 16 bytes is suffient for all applications, but can be reduced to 8 bytes in the case of space constraints.
=item 6. Select the tag (output) size. 16 bytes is suffient for most applications, including key derivation.
=item 7. Run the scheme of type C<y>, memory C<m> and C<h> lanes and threads, using different number of passes C<t>. Figure out the maximum C<t> such that the running time does not exceed C<x>. If it exceeds C<x> even for C<t = 1>, reduce C<m> accordingly. If using Argon2i, t must be at least 3.
=item 8. Hash all the passwords with the just determined values C<m>, C<h>, and C<t>.
=back
=head1 AUTHOR
Leon Timmermans <leont@cpan.org>
=head1 COPYRIGHT AND LICENSE
This software is Copyright (c) 2013 by Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, Samuel Neves, Thomas Pornin and Leon Timmermans.
This is free software, licensed under:
The Apache License, Version 2.0, January 2004
=cut
|