use warnings;
use Carp;
-use parent qw/Exporter Authen::Passphrase Class::Accessor::Fast/;
+use parent qw/Exporter Authen::Passphrase/;
our @EXPORT = qw/crypto_scrypt/;
our @EXPORT_OK = @EXPORT;
-our $VERSION = '0.001';
+our $VERSION = '0.002';
use Data::Entropy::Algorithms qw/rand_bits/;
use Digest::SHA qw/sha256 hmac_sha256/;
require XSLoader;
XSLoader::load('Authen::Passphrase::Scrypt', $VERSION);
-__PACKAGE__->mk_accessors(qw/data logN r p salt hmac passphrase/);
+use Object::Tiny qw/data logN r p salt hmac passphrase/;
sub compute_hash {
my ($self, $passphrase) = @_;
sub new {
my ($class, @args) = @_;
- my $self = $class->SUPER::new(@args);
+ if ('HASH' eq ref $args[0]) { # we were given a hash
+ @args = %{$args[0]}
+ }
+ unshift @args, logN => 14, r => 16, p => 1; # default values
+ my %args = @args;
+ $args{salt} = rand_bits 256 unless exists $args{salt};
+ my $self = bless \%args, $class;
- $self->logN(14) unless defined $self->logN;
- $self->r(16) unless defined $self->r;
- $self->p(1) unless defined $self->p;
croak "passphrase not set" unless defined $self->passphrase;
- $self->salt(rand_bits 256) unless $self->salt;
my $data = "scrypt\x00" . pack 'CNNa32',
$self->logN, $self->r, $self->p, $self->salt;
$data .= truncated_sha256 $data;
- $self->data($data);
- $self->hmac(hmac_sha256 $self->data, truncate_hash $self->compute_hash($self->passphrase));
+ $self->{data} = $data;
+ $self->{hmac} = hmac_sha256 $self->data, truncate_hash $self->compute_hash($self->passphrase);
$self
}
unpack 'Z7CNNa32a16a32', $data;
croak 'Invalid Scrypt hash: should start with "scrypt"' unless $scrypt eq 'scrypt';
croak 'Invalid Scrypt hash: bad checksum', unless $cksum eq truncated_sha256 (substr $data, 0, 48);
- $class->SUPER::new({data => (substr $data, 0, 64), logN => $logN, r => $r, p => $p, salt => $salt, hmac => $hmac});
+ bless { data => (substr $data, 0, 64), logN => $logN, r => $r, p => $p, salt => $salt, hmac => $hmac }, $class;
}
sub match {
use Authen::Passphrase::Scrypt;
# Hash a password
- my $sc = Authen::Passphrase::Scrypt->new({
+ my $sc = Authen::Passphrase::Scrypt->new(
passphrase => 'correcthorsebatterystaple'
- });
+ );
my $hash = $sc->as_rfc2307;
say "The given password hashes to $hash";
say 'The password was "xkcd"' if $sc->match('xkcd');
# Advanced hashing
- my $sc = Authen::Passphrase::Scrypt->new({
+ my $sc = Authen::Passphrase::Scrypt->new(
passphrase => 'xkcd',
logN => 14, # General work factor
r => 16, # Memory work factor
p => 1, # CPU (parallellism) work factor
salt => 'SodiumChloride && sODIUMcHLORIDE', # Must be 32 bytes
- });
+ );
say 'The given password now hashes to ', $sc->as_rfc2307;
=head1 DESCRIPTION
=over
-=item Authen::Passphrase::Scrypt->B<new>(I<\%args>)
+=item Authen::Passphrase::Scrypt->B<new>(I<%args>)
Creates a new L<Authen::Passphrase::Scrypt> from a given passphrase
-and parameters. Use this to hash a passphrase. The arguments are:
+and parameters. Use this to hash a passphrase. This function takes
+either a key value list or a hashref. The arguments are:
=over
decrease logN and increase p; if scrypt uses too much CPU but not
enough memory, decrease logN and increase r.
+Note that C<< 2^logN >> must fit in 64 bits and C<< r * p < 2^30 >>.
+
=item $sc->B<as_rfc2307>
Returns the hash of the passphrase, in RFC2307 format. This is
otherwise.
=item Authen::Passphrase::Scrypt->from_crypt
+
=item $sc->as_crypt
These functions both croak. They are provided for compatibility with
=head1 COPYRIGHT AND LICENSE
-Copyright (C) 2017 by Marius Gavrilescu
+Copyright (C) 2017-2018 by Marius Gavrilescu
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.24.1 or,