1
Fork 0
mirror of https://github.com/Quackster/Havana.git synced 2025-07-02 20:57:47 +00:00

Move from Libsodium to native Java Argon2id hashing

This commit is contained in:
Quackster 2022-09-15 20:35:42 +10:00
parent 621b201a3b
commit 2fbc3d6b2c
8 changed files with 50 additions and 35 deletions

View file

@ -47,10 +47,14 @@ dependencies {
// https://mvnrepository.com/artifact/com.google.code.gson/gson
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.0'
// https://mvnrepository.com/artifact/org.springframework.security/spring-security-crypto
implementation group: 'org.springframework.security', name: 'spring-security-crypto', version: '5.7.3'
// https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on
implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.70'
implementation 'com.maxmind.geoip2:geoip2:2.12.0'
implementation 'com.github.bhlangonijr:chesslib:1.1.1'
implementation 'com.goterl:lazysodium-java:5.0.1'
implementation "net.java.dev.jna:jna:5.8.0"
}
// Create fat jar with libraries inside of it.

View file

@ -39,6 +39,7 @@ import org.alexdev.havana.util.config.writer.DefaultConfigWriter;
import org.alexdev.havana.util.config.writer.GameConfigWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder;
import java.io.IOException;
import java.net.UnknownHostException;
@ -353,4 +354,14 @@ public class Havana {
public static Gson getGson() {
return gson;
}
/**
* Get the Argon2 password encoder instance.
*
* @return
*/
public static Argon2PasswordEncoder getPasswordEncoder() {
var encoder =new Argon2PasswordEncoder(16, 32, 1, 65536, 2);
return encoder;
}
}

View file

@ -1,11 +1,9 @@
package org.alexdev.havana.dao.mysql;
import com.goterl.lazysodium.LazySodiumJava;
import com.goterl.lazysodium.SodiumJava;
import com.goterl.lazysodium.interfaces.PwHash;
import org.alexdev.havana.dao.Storage;
import org.alexdev.havana.game.player.Player;
import org.alexdev.havana.game.player.PlayerDetails;
import org.alexdev.havana.game.player.PlayerManager;
import org.alexdev.havana.util.DateUtil;
import java.nio.charset.StandardCharsets;
@ -15,7 +13,6 @@ import java.util.List;
import java.util.concurrent.TimeUnit;
public class PlayerDao {
public static final LazySodiumJava LIB_SODIUM = new LazySodiumJava(new SodiumJava());
private static String figureBlacklist1 = "hd-180-1.hr-100-61.ch-210-66.lg-270-82.sh-290-80";
public static void resetOnline() {
@ -353,13 +350,10 @@ public class PlayerDao {
resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
byte[] hashedPassword = (resultSet.getString("password") + '\0').getBytes(StandardCharsets.UTF_8);
byte[] pass = password.getBytes(StandardCharsets.UTF_8);
String databasePassword = resultSet.getString("password");
success = ((PwHash.Native) LIB_SODIUM).cryptoPwHashStrVerify(hashedPassword, pass, pass.length);
if (success) {
fill(playerDetails, resultSet);
if (PlayerManager.getInstance().passwordMatches(databasePassword, password)) {
success = true;
}
}
@ -1010,23 +1004,4 @@ public class PlayerDao {
row.getLong("totem_effect_expiry"), row.getLong("trade_ban_expiration"), row.getInt("favourite_group"),
row.getString("created_at"));
}
public static String createPassword(String password) throws Exception {
byte[] pw = password.getBytes();
byte[] outputHash = new byte[PwHash.STR_BYTES];
PwHash.Native pwHash = (PwHash.Native) PlayerDao.LIB_SODIUM;
boolean success = pwHash.cryptoPwHashStr(
outputHash,
pw,
pw.length,
PwHash.OPSLIMIT_INTERACTIVE,
PwHash.MEMLIMIT_INTERACTIVE
);
if (!success) {
throw new Exception("Password creation was a failure!");
}
return new String(outputHash).replace((char)0 + "", "");
}
}

View file

@ -6,6 +6,7 @@ import org.alexdev.havana.game.entity.Entity;
import org.alexdev.havana.game.entity.EntityType;
import org.alexdev.havana.game.player.Player;
import org.alexdev.havana.game.player.PlayerDetails;
import org.alexdev.havana.game.player.PlayerManager;
import org.alexdev.havana.game.player.PlayerRank;
import org.alexdev.havana.messages.outgoing.alerts.ALERT;
@ -40,7 +41,7 @@ public class RecoverAccountCommand extends Command {
}
player.send(new ALERT(targetUser.getName() + "'s password has been reset to: changeme123"));
PlayerDao.setPassword(targetUser.getId(), PlayerDao.createPassword("changeme123"));
PlayerDao.setPassword(targetUser.getId(), PlayerManager.getInstance().createPassword("changeme123"));
}
@Override

View file

@ -1,5 +1,6 @@
package org.alexdev.havana.game.player;
import org.alexdev.havana.Havana;
import org.alexdev.havana.dao.mysql.PlayerDao;
import org.alexdev.havana.game.GameScheduler;
import org.alexdev.havana.game.player.statistics.PlayerStatistic;
@ -283,6 +284,26 @@ public class PlayerManager {
return activePlayers;
}
/**
* Create password hash
*
* @param password password to hash
* @return hashed password
* @throws Exception
*/
public String createPassword(String password) {
return Havana.getPasswordEncoder().encode(password);
}
/**
* Get whether the hash matches the entered password.
*
* @return true, if success
*/
public boolean passwordMatches(String databasePassword, String enteredPassword) {
return Havana.getPasswordEncoder().matches(enteredPassword, databasePassword);
}
/**
* Get daily player peak
*

View file

@ -9,6 +9,7 @@ import org.alexdev.havana.dao.mysql.PlayerStatisticsDao;
import org.alexdev.havana.dao.mysql.WardrobeDao;
import org.alexdev.havana.game.misc.figure.FigureManager;
import org.alexdev.havana.game.player.PlayerDetails;
import org.alexdev.havana.game.player.PlayerManager;
import org.alexdev.havana.game.player.Wardrobe;
import org.alexdev.havana.game.player.statistics.PlayerStatistic;
import org.alexdev.havana.game.player.statistics.PlayerStatisticManager;
@ -229,7 +230,7 @@ public class ProfileController {
webConnection.session().set("alertMessage", "Your password has been changed successfully. You will need to login again.");
webConnection.session().set("alertColour", "green");
PlayerDao.setPassword(playerDetails.getId(), PlayerDao.createPassword(newPassword));
PlayerDao.setPassword(playerDetails.getId(), PlayerManager.getInstance().createPassword(newPassword));
logout = true;
}
}

View file

@ -4,6 +4,7 @@ import org.alexdev.duckhttpd.server.connection.WebConnection;
import org.alexdev.havana.dao.mysql.PlayerDao;
import org.alexdev.havana.dao.mysql.PlayerStatisticsDao;
import org.alexdev.havana.game.player.PlayerDetails;
import org.alexdev.havana.game.player.PlayerManager;
import org.alexdev.havana.game.player.statistics.PlayerStatistic;
import org.alexdev.havana.util.DateUtil;
import org.alexdev.havana.util.config.GameConfiguration;
@ -137,7 +138,7 @@ public class RecoveryController {
webConnection.session().set("alertMessage", "Your password has been changed successfully.");
webConnection.session().set("alertColour", "green");
PlayerDao.setPassword(userId, PlayerDao.createPassword(newPassword));
PlayerDao.setPassword(userId, PlayerManager.getInstance().createPassword(newPassword));
EmailDao.removeRecoveryCode(userId);
}
}

View file

@ -9,6 +9,7 @@ import org.alexdev.havana.dao.mysql.PlayerDao;
import org.alexdev.havana.dao.mysql.PlayerStatisticsDao;
import org.alexdev.havana.dao.mysql.ReferredDao;
import org.alexdev.havana.game.misc.figure.FigureManager;
import org.alexdev.havana.game.player.PlayerManager;
import org.alexdev.havana.util.DateUtil;
import org.alexdev.havana.util.FigureUtil;
import org.alexdev.havana.util.config.GameConfiguration;
@ -158,7 +159,7 @@ public class RegisterController {
return;
}
String hashedPassword = PlayerDao.createPassword(webConnection.session().getString("registerPassword"));
String hashedPassword = PlayerManager.getInstance().createPassword(webConnection.session().getString("registerPassword"));
int userId = RegisterDao.newUser(
webConnection.session().getString("registerUsername"),
hashedPassword,