diff --git a/docs/hash_algorithms.md b/docs/hash_algorithms.md
index 8e066dc7..ef05a251 100644
--- a/docs/hash_algorithms.md
+++ b/docs/hash_algorithms.md
@@ -1,5 +1,5 @@
-
+
## Hash Algorithms
AuthMe supports the following hash algorithms for storing your passwords safely.
@@ -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 | | | None | |
BCRYPT | Recommended | 60 | | | Text | |
BCRYPT2Y | Recommended | 60 | | | Text | 22 |
CRAZYCRYPT1 | Do not use | 128 | | | Username | |
@@ -82,4 +83,4 @@ or bad.
---
-This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sat Mar 25 00:15:27 CET 2017
+This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Fri Apr 14 01:40:05 CEST 2017
diff --git a/pom.xml b/pom.xml
index c46ef85f..52115a89 100644
--- a/pom.xml
+++ b/pom.xml
@@ -264,6 +264,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
@@ -319,6 +323,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
@@ -537,6 +545,13 @@
1.1.2
+
+
+ de.mkammerer
+ argon2-jvm
+ 2.2
+
+
diff --git a/src/main/java/fr/xephi/authme/security/HashAlgorithm.java b/src/main/java/fr/xephi/authme/security/HashAlgorithm.java
index f12da678..909d2443 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..55ab3d8a
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/security/crypts/Argon2.java
@@ -0,0 +1,31 @@
+package fr.xephi.authme.security.crypts;
+
+import de.mkammerer.argon2.Argon2Constants;
+import de.mkammerer.argon2.Argon2Factory;
+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();
+ }
+
+ @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/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..0a46003c
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/security/crypts/Argon2Test.java
@@ -0,0 +1,21 @@
+package fr.xephi.authme.security.crypts;
+
+/**
+ * Test for {@link Argon2}.
+ */
+public class Argon2Test extends AbstractEncryptionMethodTest {
+
+ 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(íù*
+ }
+
+ @Override
+ protected boolean testHashEqualityForSameSalt() {
+ // Argon2 has a salt but it is handled internally
+ return false;
+ }
+}