Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a utf8Crypt method to handle UTF-8 encoded password hashing. #22

Open
wants to merge 1 commit into
base: WideCharInPasswords
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 3 additions & 10 deletions lib/WeBWorK/Authen.pm
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ use Scalar::Util qw(weaken);
use Mojo::Util qw(b64_encode b64_decode);

use WeBWorK::Debug;
use WeBWorK::Utils qw(x runtime_use);
use WeBWorK::Utils qw(x runtime_use utf8Crypt);
use WeBWorK::Utils::Logs qw(writeCourseLog);
use WeBWorK::Utils::TOTP;
use WeBWorK::Localize;
Expand Down Expand Up @@ -633,15 +633,8 @@ sub checkPassword {
my $Password = $db->getPassword($userID);
if (defined $Password) {
# Check against the password in the database.
my $possibleCryptPassword = '';
# Wrap crypt in an eval to catch any "Wide character in crypt" errors.
# If crypt fails due to a wide character, encode to UTF-8 before calling crypt.
eval { $possibleCryptPassword = crypt $possibleClearPassword, $Password->password; };
if ($@ && $@ =~ /Wide char/) {
$possibleCryptPassword = crypt Encode::encode_utf8($possibleClearPassword), $Password->password;
}

my $dbPassword = $Password->password;
my $possibleCryptPassword = utf8Crypt($possibleClearPassword, $Password->password);
my $dbPassword = $Password->password;
# This next line explicitly insures that blank or null passwords from the database can never succeed in matching
# an entered password. This also rejects cases when the database has a crypted password which matches a
# submitted all white-space or null password by requiring that the $possibleClearPassword contain some non-space
Expand Down
13 changes: 2 additions & 11 deletions lib/WeBWorK/ContentGenerator/Options.pm
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ WeBWorK::ContentGenerator::Options - Change user options.

=cut

use WeBWorK::Utils qw(cryptPassword);
use WeBWorK::Utils qw(cryptPassword utf8Crypt);
use WeBWorK::Localize;

sub page_title ($c) {
Expand Down Expand Up @@ -56,16 +56,7 @@ sub initialize ($c) {
$userID ne $effectiveUserID ? eval { $db->getPassword($c->{effectiveUser}->user_id) } : $password;

# Check that either password is not defined or if it is defined then we have the right one.
my $cryptedCurrP;
if (defined $password) {
# Wrap crypt in an eval to catch any "Wide character in crypt" errors.
# If crypt fails due to a wide character, encode to UTF-8 before calling crypt.
eval { $cryptedCurrP = crypt($currP // '', $password->password); };
if ($@ && $@ =~ /Wide char/) {
$cryptedCurrP = crypt(Encode::encode_utf8($currP), $password->password);
}
}
if (!defined $password || $cryptedCurrP eq $password->password) {
if (!defined $password || utf8Crypt($currP // '', $password->password) eq $password->password) {
my $e_user_name = $c->{effectiveUser}->first_name . ' ' . $c->{effectiveUser}->last_name;
if ($newP eq $confirmP) {
if (!defined $effectiveUserPassword) {
Expand Down
22 changes: 17 additions & 5 deletions lib/WeBWorK/Utils.pm
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ our @EXPORT_OK = qw(
max
wwRound
cryptPassword
utf8Crypt
undefstr
sortByName
sortAchievements
Expand Down Expand Up @@ -151,14 +152,15 @@ sub cryptPassword ($clearPassword) {
$salt .= ('.', '/', '0' .. '9', 'A' .. 'Z', 'a' .. 'z')[ rand 64 ];
}

return utf8Crypt(trim_spaces($clearPassword), $salt);
}

sub utf8Crypt ($clearPassword, $hash) {
# Wrap crypt in an eval to catch any "Wide character in crypt" errors.
# If crypt fails due to a wide character, encode to UTF-8 before calling crypt.
my $cryptedPassword = '';
eval { $cryptedPassword = crypt(trim_spaces($clearPassword), $salt); };
if ($@ && $@ =~ /Wide char/) {
$cryptedPassword = crypt(Encode::encode_utf8(trim_spaces($clearPassword)), $salt);
}

eval { $cryptedPassword = crypt($clearPassword, $hash); };
$cryptedPassword = crypt(encode('UTF-8', $clearPassword), $hash) if $@ && $@ =~ /Wide char/;
return $cryptedPassword;
}

Expand Down Expand Up @@ -621,6 +623,16 @@ Usage: C<cryptPassword($clearPassword)>
Returns the crypted form of C<$clearPassword> using a random 16 character
salt.

=head2 utf8Crypt

Usage: C<utf8Crypt($clearPassword, $hash)>

Attempts to call C<crypt> on C<$clearPassword>. If that fails, then C<crypt> is
called on the UTF-8 encoded version of C<$clearPassword>.

Note that C<$hash> can be a salt or a password hash generated by a previous call
of this method with a salt..

=head2 undefstr

Usage: C<undefstr($default, @values)>
Expand Down