summaryrefslogtreecommitdiff
path: root/lib/VNDB/Util/Auth.pm
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2014-10-15 14:20:56 +0200
committerYorhel <git@yorhel.nl>2014-10-15 14:20:56 +0200
commit6e0a0e1d00e11da9b4eab2163e19314f752b05b5 (patch)
treea65e4b62d81d395c9988f7045b4e83deec8b2485 /lib/VNDB/Util/Auth.pm
parent13e967810a8b336164d22167bb047ad1dbb5a836 (diff)
Use scrypt for new password hashes
I increased the N parameter to approximate about 500ms to generate the hash. This is quite a paranoid setting for a website, but login attempts are throttled so there's not much of a DoS factor. (Alright, password changing feature isn't throttled so the DoS factor still exists. But really, there's some pages with longer page generation times anyway.) I did lower the size of the salt a bit (Crypt::ScryptKDF uses 256 bits by default), because 64 bits of randomness should have low enough chance of collision with only ~100k users (even with a million users, seriously).
Diffstat (limited to 'lib/VNDB/Util/Auth.pm')
-rw-r--r--lib/VNDB/Util/Auth.pm30
1 files changed, 27 insertions, 3 deletions
diff --git a/lib/VNDB/Util/Auth.pm b/lib/VNDB/Util/Auth.pm
index 2fd06828..5228b6eb 100644
--- a/lib/VNDB/Util/Auth.pm
+++ b/lib/VNDB/Util/Auth.pm
@@ -7,6 +7,7 @@ use warnings;
use Exporter 'import';
use Digest::SHA qw|sha1 sha1_hex sha256|;
use Crypt::URandom 'urandom';
+use Crypt::ScryptKDF 'scrypt_raw';
use Encode 'encode_utf8';
use TUWF ':html';
use VNDB::Func;
@@ -107,9 +108,21 @@ sub _authCheck {
return 0 if !$user || length($user) > 15 || length($user) < 2 || !$pass;
my $d = $self->dbUserGet(username => $user, what => 'extended notifycount')->[0];
- return 0 if !$d->{id} || length $d->{passwd} != 41;
+ return 0 if !$d->{id};
- if($self->authPreparePass($pass, substr $d->{passwd}, 0, 9) eq $d->{passwd}) {
+ # Old-style hashes
+ if(length $d->{passwd} == 41) {
+ return 0 if _authPreparePassSha256($self, $pass, substr $d->{passwd}, 0, 9) ne $d->{passwd};
+ $self->{_auth} = $d;
+ # Update database with new hash format, now that we have the plain text password
+ $self->dbUserEdit($d->{id}, passwd => $self->authPreparePass($pass));
+ return 1;
+ }
+
+ # New scrypt hashes
+ if(length $d->{passwd} == 46) {
+ my($N, $r, $p, $salt) = unpack 'NCCa8', $d->{passwd};
+ return 0 if $self->authPreparePass($pass, $salt, $N, $r, $p) ne $d->{passwd};
$self->{_auth} = $d;
return 1;
}
@@ -119,9 +132,20 @@ sub _authCheck {
# Prepares a plaintext password for database storage
-# Arguments: pass, optionally salt
+# Arguments: pass, optionally: salt, N, r, p
# Returns: encrypted password (as a binary string)
sub authPreparePass {
+ my($self, $pass, $salt, $N, $r, $p) = @_;
+ ($N, $r, $p) = @{$self->{scrypt_args}} if !$N;
+ $salt ||= urandom(8);
+ return pack 'NCCa8a*', $N, $r, $p, $salt, scrypt_raw($pass, $self->{scrypt_salt} . $salt, $N, $r, $p, 32);
+}
+
+
+# Same as authPreparePass, but for the old sha256 hash.
+# Arguments: pass, optionally salt
+# Returns: encrypted password (as a binary string)
+sub _authPreparePassSha256 {
my($self, $pass, $salt) = @_;
$salt ||= encode_utf8(randomascii(9));
return $salt.sha256($self->{global_salt} . encode_utf8($pass) . $salt);