Skip to content

Commit

Permalink
Update Bcrypt dependency and password hash service (#670)
Browse files Browse the repository at this point in the history
* Update bcrypt and password hashing

- update bcrypt dependency to
- make hashing strength configurable via JVM variable

* Fix HashService for very large passwords

- Use BCrypt version 2B
- Apply long password strategy when verifying them
- Add HashServiceTest
  • Loading branch information
Enet4 authored Oct 7, 2023
1 parent ef01f12 commit 67c7209
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 7 deletions.
2 changes: 1 addition & 1 deletion dicoogle/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@
<dependency>
<groupId>at.favre.lib</groupId>
<artifactId>bcrypt</artifactId>
<version>0.9.0</version>
<version>0.10.2</version>
</dependency>

<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,40 @@
*/
package pt.ua.dicoogle.server.users;

import org.slf4j.LoggerFactory;

import at.favre.lib.crypto.bcrypt.BCrypt;
import at.favre.lib.crypto.bcrypt.LongPasswordStrategies;
import at.favre.lib.crypto.bcrypt.LongPasswordStrategy;
import at.favre.lib.crypto.bcrypt.BCrypt.Version;

/**
* This class provides a password hashing service.
*/
public class HashService {

/**
* Hardcoded cost for the password hashing algorithm.
* The cost for the password hashing algorithm.
*
* Can be configured via JVM variable `dicoogle.user.hashStrength`.
* Default is 10.
*/
private static final int HASH_STRENGTH = 10;
private static final int HASH_STRENGTH;

static {
int strength;
try {
strength = Integer.parseInt(System.getProperty("dicoogle.user.hashStrength", "10"));
} catch (NumberFormatException e) {
LoggerFactory.getLogger(HashService.class)
.warn("Invalid value for dicoogle.user.hashStrength, using default value");
strength = 10;
}
HASH_STRENGTH = strength;
}

private static final LongPasswordStrategy LONG_PASSWORD_STRATEGY =
LongPasswordStrategies.hashSha512(BCrypt.Version.VERSION_2B);

/**
* Hash a password.
Expand All @@ -50,8 +72,7 @@ public static String hashPassword(String password) {
*/
public static String hashPassword(char[] password) {
try {
return BCrypt.with(LongPasswordStrategies.hashSha512(BCrypt.Version.VERSION_2B)).hashToString(HASH_STRENGTH,
password);
return BCrypt.with(Version.VERSION_2B, LONG_PASSWORD_STRATEGY).hashToString(HASH_STRENGTH, password);
} finally {
for (int i = 0; i < password.length; i++) {
password[i] = '\0';
Expand Down Expand Up @@ -80,13 +101,12 @@ public static boolean verifyPassword(String hash, String password) {
*/
public static boolean verifyPassword(String hash, char[] password) {
try {
BCrypt.Result result = BCrypt.verifyer().verify(password, hash);
BCrypt.Result result = BCrypt.verifyer(Version.VERSION_2B, LONG_PASSWORD_STRATEGY).verify(password, hash);
return result.verified;
} finally {
for (int i = 0; i < password.length; i++) {
password[i] = '\0';
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Copyright (C) 2014 Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
*
* This file is part of Dicoogle/dicoogle.
*
* Dicoogle/dicoogle is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dicoogle/dicoogle is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Dicoogle. If not, see <http://www.gnu.org/licenses/>.
*/

package pt.ua.dicoogle.server.users;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

public class HashServiceTest {

/** Hash service reliably accepts the same password,
* while rejecting different passwords.
*/
@Test
public void canValidatePasswords() {

String[] passwords = new String[] {"dicoogledicoogle", "IAmTest123456789", "áÀéìóÙãõçüºª",
"very long password here very long password here very long password here"};

for (String password : passwords) {
String hash = HashService.hashPassword(password);
assertTrue(HashService.verifyPassword(hash, password));

assertFalse(HashService.verifyPassword(hash, "wrongpasswordgoeshere123"));
}
}
}

0 comments on commit 67c7209

Please sign in to comment.