diff --git a/.travis.yml b/.travis.yml
index ba8dd103..301dfd72 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,12 +1,17 @@
-sudo: false
+sudo: required
addons:
apt:
packages:
- oracle-java8-installer
+ - git
language: java
jdk: oraclejdk8
+before_script:
+ - "sudo git clone https://www.github.com/P-H-C/phc-winner-argon2.git argon2-src"
+ - "cd argon2-src && sudo make && sudo make install && cd .."
+
script: mvn clean verify -B
notifications:
diff --git a/circle.yml b/circle.yml
index c9742f65..169726b8 100644
--- a/circle.yml
+++ b/circle.yml
@@ -1,6 +1,9 @@
machine:
java:
version: oraclejdk8
+dependencies:
+ pre:
+ - "sudo apt-get update; sudo apt-get install -y git; sudo git clone https://www.github.com/P-H-C/phc-winner-argon2.git argon2-src; cd argon2-src; sudo make; sudo make install"
general:
artifacts:
- "target/AuthMe-*.jar"
diff --git a/docs/hash_algorithms.md b/docs/hash_algorithms.md
index 45fa6594..00480c80 100644
--- a/docs/hash_algorithms.md
+++ b/docs/hash_algorithms.md
@@ -7,6 +7,7 @@ AuthMe supports the following hash algorithms for storing your passwords safely.
Algorithm | Recommendation | Hash length | ASCII | | Salt type | Length | Separate?
--------- | -------------- | ----------- | ----- | --- | --------- | ------ | ---------
+ARGON2 | Recommended | 96 | | | Text | 16 |
BCRYPT | Recommended | 60 | | | Text | |
BCRYPT2Y | Recommended | 60 | | | Text | 22 |
CRAZYCRYPT1 | Do not use | 128 | | | Username | |
diff --git a/pom.xml b/pom.xml
index e44421cc..7d7dc7a3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -192,6 +192,10 @@
de.rtner
fr.xephi.authme.libs.de.rtner
+
+ de.mkammerer
+ fr.xephi.authme.libs.de.mkammerer
+
javax.inject
fr.xephi.authme.libs.javax.inject
@@ -388,6 +392,13 @@
true
+
+
+ de.mkammerer
+ argon2-jvm-nolibs
+ 2.2
+
+
org.spigotmc
diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java
index 728b469b..532c8aeb 100644
--- a/src/main/java/fr/xephi/authme/AuthMe.java
+++ b/src/main/java/fr/xephi/authme/AuthMe.java
@@ -23,6 +23,8 @@ import fr.xephi.authme.listener.PlayerListener18;
import fr.xephi.authme.listener.PlayerListener19;
import fr.xephi.authme.listener.PlayerListener19Spigot;
import fr.xephi.authme.listener.ServerListener;
+import fr.xephi.authme.security.HashAlgorithm;
+import fr.xephi.authme.security.crypts.Argon2;
import fr.xephi.authme.security.crypts.Sha256;
import fr.xephi.authme.service.BackupService;
import fr.xephi.authme.service.BukkitService;
@@ -267,6 +269,13 @@ public class AuthMe extends JavaPlugin {
&& settings.getProperty(EmailSettings.SMTP_PORT) != 25) {
ConsoleLogger.warning("Note: You have set Email.useTls to false but this only affects mail over port 25");
}
+ // Check if argon2 library is present and can be loaded
+ if (settings.getProperty(SecuritySettings.PASSWORD_HASH).equals(HashAlgorithm.ARGON2)
+ && !Argon2.isLibraryLoaded()) {
+ ConsoleLogger.warning("WARNING!!! You use Argon2 Hash Algorithm method but we can't find the Argon2 "
+ + "library on your system! See https://github.com/AuthMe/AuthMeReloaded/wiki/Argon2-as-Password-Hash");
+ stopOrUnload();
+ }
}
/**
diff --git a/src/main/java/fr/xephi/authme/security/HashAlgorithm.java b/src/main/java/fr/xephi/authme/security/HashAlgorithm.java
index 9c9ff919..fb47f780 100644
--- a/src/main/java/fr/xephi/authme/security/HashAlgorithm.java
+++ b/src/main/java/fr/xephi/authme/security/HashAlgorithm.java
@@ -7,6 +7,7 @@ import fr.xephi.authme.security.crypts.EncryptionMethod;
*/
public enum HashAlgorithm {
+ ARGON2(fr.xephi.authme.security.crypts.Argon2.class),
BCRYPT(fr.xephi.authme.security.crypts.BCrypt.class),
BCRYPT2Y(fr.xephi.authme.security.crypts.BCrypt2y.class),
CRAZYCRYPT1(fr.xephi.authme.security.crypts.CrazyCrypt1.class),
diff --git a/src/main/java/fr/xephi/authme/security/crypts/Argon2.java b/src/main/java/fr/xephi/authme/security/crypts/Argon2.java
new file mode 100644
index 00000000..27b89027
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/security/crypts/Argon2.java
@@ -0,0 +1,48 @@
+package fr.xephi.authme.security.crypts;
+
+import de.mkammerer.argon2.Argon2Constants;
+import de.mkammerer.argon2.Argon2Factory;
+import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.security.crypts.description.HasSalt;
+import fr.xephi.authme.security.crypts.description.Recommendation;
+import fr.xephi.authme.security.crypts.description.SaltType;
+import fr.xephi.authme.security.crypts.description.Usage;
+
+@Recommendation(Usage.RECOMMENDED)
+@HasSalt(value = SaltType.TEXT, length = Argon2Constants.DEFAULT_SALT_LENGTH)
+// Note: Argon2 is actually a salted algorithm but salt generation is handled internally
+// and isn't exposed to the outside, so we treat it as an unsalted implementation
+public class Argon2 extends UnsaltedMethod {
+
+ private de.mkammerer.argon2.Argon2 argon2;
+
+ public Argon2() {
+ argon2 = Argon2Factory.create();
+ }
+
+ /**
+ * Checks if the argon2 library is available in java.library.path.
+ *
+ * @return true if the library is present, false otherwise
+ */
+ public static boolean isLibraryLoaded() {
+ try {
+ System.loadLibrary("argon2");
+ return true;
+ } catch (UnsatisfiedLinkError e) {
+ ConsoleLogger.logException(
+ "Cannot find argon2 library: https://github.com/AuthMe/AuthMeReloaded/wiki/Argon2-as-Password-Hash", e);
+ }
+ return false;
+ }
+
+ @Override
+ public String computeHash(String password) {
+ return argon2.hash(2, 65536, 1, password);
+ }
+
+ @Override
+ public boolean comparePassword(String password, HashedPassword hashedPassword, String name) {
+ return argon2.verify(hashedPassword.getHash(), password);
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java b/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java
index 0a32c558..73799516 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java
@@ -55,8 +55,9 @@ public final class SecuritySettings implements SettingsHolder {
@Comment({
"Possible values: SHA256, BCRYPT, BCRYPT2Y, PBKDF2, SALTEDSHA512,",
"MYBB, IPB3, PHPBB, PHPFUSION, SMF, XENFORO, XAUTH, JOOMLA, WBB3, WBB4, MD5VB,",
- "PBKDF2DJANGO, WORDPRESS, ROYALAUTH, CUSTOM (for developers only). See full list at",
- "https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/hash_algorithms.md"
+ "PBKDF2DJANGO, WORDPRESS, ROYALAUTH, ARGON2, CUSTOM (for developers only). See full list at",
+ "https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/hash_algorithms.md",
+ "If you use ARGON2, check that you have the argon2 c library on your system"
})
public static final Property PASSWORD_HASH =
newProperty(HashAlgorithm.class, "settings.security.passwordHash", HashAlgorithm.SHA256);
diff --git a/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java b/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java
index 5b835194..fc9fd0d6 100644
--- a/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java
+++ b/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java
@@ -2,6 +2,7 @@ package fr.xephi.authme.security;
import ch.jalu.injector.Injector;
import ch.jalu.injector.InjectorBuilder;
+import fr.xephi.authme.security.crypts.Argon2;
import fr.xephi.authme.security.crypts.EncryptionMethod;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.security.crypts.description.Recommendation;
@@ -61,6 +62,10 @@ public class HashAlgorithmIntegrationTest {
// given / when / then
for (HashAlgorithm algorithm : HashAlgorithm.values()) {
if (!HashAlgorithm.CUSTOM.equals(algorithm) && !HashAlgorithm.PLAINTEXT.equals(algorithm)) {
+ if (HashAlgorithm.ARGON2.equals(algorithm) && !Argon2.isLibraryLoaded()) {
+ System.out.println("[WARNING] Cannot find argon2 library, skipping integration test");
+ continue;
+ }
EncryptionMethod method = injector.createIfHasDependencies(algorithm.getClazz());
if (method == null) {
fail("Could not create '" + algorithm.getClazz() + "' - forgot to provide some class?");
diff --git a/src/test/java/fr/xephi/authme/security/crypts/Argon2Test.java b/src/test/java/fr/xephi/authme/security/crypts/Argon2Test.java
new file mode 100644
index 00000000..46b315d5
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/security/crypts/Argon2Test.java
@@ -0,0 +1,29 @@
+package fr.xephi.authme.security.crypts;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assume.assumeThat;
+
+/**
+ * Test for {@link Argon2}.
+ */
+public class Argon2Test extends AbstractEncryptionMethodTest {
+
+ private static final boolean IS_LIBRARY_LOADED = Argon2.isLibraryLoaded();
+
+ public Argon2Test() {
+ super(new Argon2(),
+ "$argon2i$v=19$m=65536,t=2,p=1$dOP8NiXsPTcMgzI4Z8Rbew$ShdowtoTEWTL5UTFz1UgQOigb9JOlm4ZxWPA6WbIeUw", // password
+ "$argon2i$v=19$m=65536,t=2,p=1$amZHbPfgc5peKd/4w1AI1g$Q2PUiOVw47TACijP57U0xf7QfiZ00HV4eFzMDA6yKRE", // PassWord1
+ "$argon2i$v=19$m=65536,t=2,p=1$58v7dWNn9/bpD00QLzSebw$7cMC7p0qceE3Mgf2yQp4X7c+UkO9oyJwQ7S6XTBubNs", // &^%te$t?Pw@_
+ "$argon2i$v=19$m=65536,t=2,p=1$93OSU71DgBOzpmhti7+6rQ$sSSI6QQQdoG9DlGwLjYz576kTek89nwr9CyNpy6bsL0"); // âË_3(íù*
+
+ assumeThat("Argon2 library is not loaded - skipping test",
+ IS_LIBRARY_LOADED, equalTo(true));
+ }
+
+ @Override
+ protected boolean testHashEqualityForSameSalt() {
+ // Argon2 has a salt but it is handled internally
+ return false;
+ }
+}