Crypt-Passphrase-Scrypt
view release on metacpan or search on metacpan
lib/Crypt/Passphrase/Scrypt.pm view on Meta::CPAN
my $hash = scrypt_b64($password, $salt, 1 << $self->{cost}, $self->{block_size}, $self->{parallel}, $self->{output_size});
return sprintf '$scrypt$ln=%d,r=%d,p=%d$%s$%s', $self->{cost}, $self->{block_size}, $self->{parallel}, encode_base64($salt, ''), $hash;
} else {
my $encoded_salt = encode_crypt64($salt);
my $hash = scrypt_raw($password, $encoded_salt, 1 << $self->{cost}, $self->{block_size}, $self->{parallel}, $self->{output_size});
my $encoded_hash = encode_crypt64($hash);
my $cost = encode_crypt64_number($self->{cost}, 1);
my $block_size = encode_crypt64_number($self->{block_size}, 5);
my $parallel = encode_crypt64_number($self->{parallel}, 5);
my $header = join '', $cost, $block_size, $parallel, $encoded_salt;
return sprintf '$7$%s$%s', $header, $encoded_hash;
}
}
my $decode_regex = qr/ \A \$ scrypt \$ ln=(\d+),r=(\d+),p=(\d+) \$ ([^\$]+) \$ ([^\$]*) \z /x;
my $char64 = qr{[./0-9A-Za-z]};
my $regex7 = qr/ ^ \$7\$ ($char64) ($char64{5}) ($char64{5}) ([^\$]{22}) \$ ([^\$]*) /x;
sub needs_rehash {
my ($self, $hash) = @_;
if ($self->{format} eq 'passlib') {
my ($cost, $block_size, $parallel, $salt64, $hash64) = $hash =~ $decode_regex or return 1;
return !!1 if $cost != $self->{cost} or $block_size != $self->{block_size} or $parallel != $self->{parallel};
return !!1 if length decode_base64($salt64) != $self->{salt_size} or length decode_base64($hash64) != $self->{output_size};
} else {
my ($encoded_cost, $encoded_block_size, $encoded_parallel, $salt, $encoded_hash) = $hash =~ $regex7 or return 1;
my ($cost, $block_size, $parallel) = map { decode_crypt64_number($_) } $encoded_cost, $encoded_block_size, $encoded_parallel;
return !!1 if $cost != $self->{cost} or $block_size != $self->{block_size} or $parallel != $self->{parallel};
return !!1 if length decode_crypt64($salt) != $self->{salt_size} or length decode_crypt64($encoded_hash) != $self->{output_size};
}
return !!0;
}
sub crypt_subtypes {
return ('scrypt', '7');
}
sub verify_password {
my ($class, $password, $hash) = @_;
if (my ($cost, $block_size, $parallel, $salt64, $hash64) = $hash =~ $decode_regex) {
my $old_hash = decode_base64($hash64);
my $new_hash = scrypt_raw($password, decode_base64($salt64), 1 << $cost, $block_size, $parallel, length $old_hash);
return $class->secure_compare($new_hash, $old_hash);
}
elsif (my ($encoded_cost, $encoded_block_size, $encoded_parallel, $salt, $encoded_hash) = $hash =~ $regex7) {
my ($cost, $block_size, $parallel) = map { decode_crypt64_number($_) } $encoded_cost, $encoded_block_size, $encoded_parallel;
my $old_hash = decode_crypt64($encoded_hash);
my $new_hash = scrypt_raw($password, $salt, 1 << $cost, $block_size, $parallel, length $old_hash);
return $class->secure_compare($new_hash, $old_hash);
}
return !!0;
}
sub recode_hash {
my ($self, $hash) = @_;
return $hash if $self->{format} eq 'libcrypt';
if (my ($encoded_cost, $encoded_block_size, $encoded_parallel, $salt, $encoded_hash) = $hash =~ $regex7) {
my ($cost, $block_size, $parallel) = map { decode_crypt64_number($_) } $encoded_cost, $encoded_block_size, $encoded_parallel;
my $decoded = decode_crypt64($encoded_hash);
my $recoded_hash = encode_base64($decoded, '');
return sprintf '$scrypt$ln=%d,r=%d,p=%d$%s$%s', $cost, $block_size, $parallel, encode_base64($salt, ''), $recoded_hash;
}
return $hash;
}
1;
#ABSTRACT: A scrypt encoder for Crypt::Passphrase
__END__
=pod
=encoding UTF-8
=head1 NAME
Crypt::Passphrase::Scrypt - A scrypt encoder for Crypt::Passphrase
=head1 VERSION
version 0.005
=head1 DESCRIPTION
This class implements an scrypt encoder for Crypt::Passphrase. If one wants a memory-hard password scheme Argon2 is recommended instead.
=head2 Configuration.
It takes the following arguments
=over 4
=item * format
This module supports formats: B<passlib> (C<$scrypt$>) and B<libcrypt> (C<$7>), with the former being the default.
=item * cost
This is the cost factor that is used to hash passwords, it scales exponentially. It currently defaults to B<16>, but this may change in any future version. Note that unlike many hash algorithms, increasing the rounds value will increase both the time...
=item * block_size
This defaults to B<8>.
=item * parallelism
The number of threads used for the hash. This defaults to B<1>, but this number may change in any future version.
=item * output_size
The size of a hashed value. This defaults to B<32> bytes.
=item * salt_size
The size of the salt. This defaults to B<16> bytes, which should be more than enough for any use-case.
=back
Note that some defaults are likely to change at some point in the future, as computers get progressively more powerful and cryptoanalysis gets more advanced.
( run in 1.429 second using v1.01-cache-2.11-cpan-d7f47b0818f )