mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-12-20 15:47:38 +01:00
Merge branch 'master' of https://github.com/AuthMe-Team/AuthMeReloaded into 411-forced-commands
This commit is contained in:
commit
2bd5fcde3c
@ -1,5 +1,5 @@
|
||||
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
|
||||
<!-- File auto-generated on Sat Oct 01 23:42:20 CEST 2016. See hashmethods/hash_algorithms.tpl.md -->
|
||||
<!-- File auto-generated on Fri Nov 25 15:48:35 CET 2016. See docs/hashmethods/hash_algorithms.tpl.md -->
|
||||
|
||||
## Hash Algorithms
|
||||
AuthMe supports the following hash algorithms for storing your passwords safely.
|
||||
@ -13,11 +13,11 @@ CRAZYCRYPT1 | Do not use | 128 | | | Username | |
|
||||
DOUBLEMD5 | Do not use | 32 | | | None | |
|
||||
IPB3 | Acceptable | 32 | | | Text | 5 | Y
|
||||
IPB4 | Does not work | 60 | | | Text | 22 | Y
|
||||
JOOMLA | Recommended | 65 | | | Text | 32 |
|
||||
JOOMLA | Acceptable | 65 | | | Text | 32 |
|
||||
MD5 | Do not use | 32 | | | None | |
|
||||
MD5VB | Acceptable | 56 | | | Text | 16 |
|
||||
MYBB | Acceptable | 32 | | | Text | 8 | Y
|
||||
PBKDF2 | Does not work | 332 | | | Text | 12 |
|
||||
PBKDF2 | Recommended | 165 | | | Text | 16 |
|
||||
PBKDF2DJANGO | Acceptable | 77 | Y | | Text | 12 |
|
||||
PHPBB | Acceptable | 34 | | | Text | 16 |
|
||||
PHPFUSION | Do not use | 64 | Y | | | | Y
|
||||
@ -82,4 +82,4 @@ or bad.
|
||||
|
||||
---
|
||||
|
||||
This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sat Oct 01 23:42:20 CEST 2016
|
||||
This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Fri Nov 25 15:48:35 CET 2016
|
||||
|
15
pom.xml
15
pom.xml
@ -268,6 +268,10 @@
|
||||
<pattern>net.ricecode.similarity</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.ricecode.similarity</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>de.rtner</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.de.rtner</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>javax.inject</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.javax.inject</shadedPattern>
|
||||
@ -319,6 +323,10 @@
|
||||
<pattern>net.ricecode.similarity</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.ricecode.similarity</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>de.rtner</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.de.rtner</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>javax.inject</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.javax.inject</shadedPattern>
|
||||
@ -524,6 +532,13 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- PBKDF2 implementation -->
|
||||
<dependency>
|
||||
<groupId>de.rtner</groupId>
|
||||
<artifactId>PBKDF2</artifactId>
|
||||
<version>1.1.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spigot API, http://www.spigotmc.org/ or http://bukkit.org/ -->
|
||||
<!-- Moved in profiles! -->
|
||||
|
||||
|
@ -109,7 +109,6 @@ abstract class AuthMeController {
|
||||
* @return string|null the hash, or null if unavailable (e.g. username doesn't exist)
|
||||
*/
|
||||
private function getHashFromDatabase($username) {
|
||||
// Add here your database host, username, password and database name
|
||||
$mysqli = $this->getAuthmeMySqli();
|
||||
if ($mysqli !== null) {
|
||||
$stmt = $mysqli->prepare('SELECT password FROM ' . self::AUTHME_TABLE . ' WHERE username = ?');
|
||||
|
53
samples/website_integration/Pbkdf2.php
Normal file
53
samples/website_integration/Pbkdf2.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/***********************************************************
|
||||
* AuthMe website integration logic for PBKDF2 *
|
||||
* ------------------------------------------------------- *
|
||||
* See AuthMeController for details. *
|
||||
* *
|
||||
* Source: https://github.com/AuthMe-Team/AuthMeReloaded/ *
|
||||
***********************************************************/
|
||||
class Pbkdf2 extends AuthMeController {
|
||||
|
||||
/** @var string[] range of characters for salt generation */
|
||||
private $CHARS;
|
||||
|
||||
const SALT_LENGTH = 16;
|
||||
const NUMBER_OF_ITERATIONS = 10000;
|
||||
|
||||
public function __construct() {
|
||||
$this->CHARS = self::initCharRange();
|
||||
}
|
||||
|
||||
protected function isValidPassword($password, $hash) {
|
||||
// hash := pbkdf2_sha256$iterations$salt$hash
|
||||
$parts = explode('$', $hash);
|
||||
return count($parts) === 4 && $hash === $this->computeHash($parts[1], $parts[2], $password);
|
||||
}
|
||||
|
||||
protected function hash($password) {
|
||||
$salt = $this->generateSalt();
|
||||
return $this->computeHash(self::NUMBER_OF_ITERATIONS, $salt, $password);
|
||||
}
|
||||
|
||||
private function computeHash($iterations, $salt, $password) {
|
||||
return 'pbkdf2_sha256$' . self::NUMBER_OF_ITERATIONS . '$' . $salt
|
||||
. '$' . hash_pbkdf2('sha256', $password, $salt, self::NUMBER_OF_ITERATIONS, 64, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string randomly generated salt
|
||||
*/
|
||||
private function generateSalt() {
|
||||
$maxCharIndex = count($this->CHARS) - 1;
|
||||
$salt = '';
|
||||
for ($i = 0; $i < self::SALT_LENGTH; ++$i) {
|
||||
$salt .= $this->CHARS[mt_rand(0, $maxCharIndex)];
|
||||
}
|
||||
return $salt;
|
||||
}
|
||||
|
||||
private static function initCharRange() {
|
||||
return array_merge(range('0', '9'), range('a', 'f'));
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@ class Sha256 extends AuthMeController {
|
||||
const SALT_LENGTH = 16;
|
||||
|
||||
public function __construct() {
|
||||
$this->CHARS = self::initRandomChars();
|
||||
$this->CHARS = self::initCharRange();
|
||||
}
|
||||
|
||||
protected function isValidPassword($password, $hash) {
|
||||
@ -41,7 +41,7 @@ class Sha256 extends AuthMeController {
|
||||
return $salt;
|
||||
}
|
||||
|
||||
private static function initRandomChars() {
|
||||
private static function initCharRange() {
|
||||
return array_merge(range('0', '9'), range('a', 'f'));
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ import fr.xephi.authme.settings.properties.PluginSettings;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.inject.Inject;
|
||||
import java.util.Arrays;
|
||||
|
||||
@ -115,6 +116,7 @@ public class AuthGroupHandler implements Reloadable {
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostConstruct
|
||||
public void reload() {
|
||||
unloggedInGroup = settings.getProperty(SecuritySettings.UNLOGGEDIN_GROUP);
|
||||
unregisteredGroup = settings.getProperty(HooksSettings.UNREGISTERED_GROUP);
|
||||
|
@ -3,8 +3,7 @@ package fr.xephi.authme.security;
|
||||
import fr.xephi.authme.security.crypts.EncryptionMethod;
|
||||
|
||||
/**
|
||||
* The list of hash algorithms supported by AuthMe. The linked {@link EncryptionMethod} implementation
|
||||
* must be able to be instantiated with the default constructor.
|
||||
* Hash algorithms supported by AuthMe.
|
||||
*/
|
||||
public enum HashAlgorithm {
|
||||
|
||||
@ -18,8 +17,8 @@ public enum HashAlgorithm {
|
||||
MD5(fr.xephi.authme.security.crypts.MD5.class),
|
||||
MD5VB(fr.xephi.authme.security.crypts.MD5VB.class),
|
||||
MYBB(fr.xephi.authme.security.crypts.MYBB.class),
|
||||
PBKDF2(fr.xephi.authme.security.crypts.CryptPBKDF2.class),
|
||||
PBKDF2DJANGO(fr.xephi.authme.security.crypts.CryptPBKDF2Django.class),
|
||||
PBKDF2(fr.xephi.authme.security.crypts.Pbkdf2.class),
|
||||
PBKDF2DJANGO(fr.xephi.authme.security.crypts.Pbkdf2Django.class),
|
||||
PHPBB(fr.xephi.authme.security.crypts.PHPBB.class),
|
||||
PHPFUSION(fr.xephi.authme.security.crypts.PHPFUSION.class),
|
||||
@Deprecated
|
||||
|
@ -1,40 +0,0 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
import fr.xephi.authme.security.pbkdf2.PBKDF2Engine;
|
||||
import fr.xephi.authme.security.pbkdf2.PBKDF2Parameters;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@Recommendation(Usage.DOES_NOT_WORK)
|
||||
public class CryptPBKDF2 extends HexSaltedMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
String result = "pbkdf2_sha256$10000$" + salt + "$";
|
||||
PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 10000);
|
||||
PBKDF2Engine engine = new PBKDF2Engine(params);
|
||||
|
||||
return result + Arrays.toString(engine.deriveKey(password, 64));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String password, HashedPassword hashedPassword, String unusedName) {
|
||||
String[] line = hashedPassword.getHash().split("\\$");
|
||||
if (line.length != 4) {
|
||||
return false;
|
||||
}
|
||||
String salt = line[2];
|
||||
String derivedKey = line[3];
|
||||
PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 10000, derivedKey.getBytes());
|
||||
PBKDF2Engine engine = new PBKDF2Engine(params);
|
||||
return engine.verifyKey(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSaltLength() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
}
|
@ -4,7 +4,7 @@ import fr.xephi.authme.security.HashUtils;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
@Recommendation(Usage.RECOMMENDED)
|
||||
@Recommendation(Usage.ACCEPTABLE)
|
||||
public class JOOMLA extends HexSaltedMethod {
|
||||
|
||||
@Override
|
||||
|
60
src/main/java/fr/xephi/authme/security/crypts/Pbkdf2.java
Normal file
60
src/main/java/fr/xephi/authme/security/crypts/Pbkdf2.java
Normal file
@ -0,0 +1,60 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import de.rtner.misc.BinTools;
|
||||
import de.rtner.security.auth.spi.PBKDF2Engine;
|
||||
import de.rtner.security.auth.spi.PBKDF2Parameters;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@Recommendation(Usage.RECOMMENDED)
|
||||
public class Pbkdf2 extends HexSaltedMethod {
|
||||
|
||||
private static final int DEFAULT_ROUNDS = 10_000;
|
||||
private int numberOfRounds;
|
||||
|
||||
@Inject
|
||||
Pbkdf2(Settings settings) {
|
||||
int configuredRounds = settings.getProperty(SecuritySettings.PBKDF2_NUMBER_OF_ROUNDS);
|
||||
this.numberOfRounds = configuredRounds > 0 ? configuredRounds : DEFAULT_ROUNDS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
String result = "pbkdf2_sha256$" + numberOfRounds + "$" + salt + "$";
|
||||
PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "UTF-8", salt.getBytes(), numberOfRounds);
|
||||
PBKDF2Engine engine = new PBKDF2Engine(params);
|
||||
|
||||
return result + BinTools.bin2hex(engine.deriveKey(password, 64));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String password, HashedPassword hashedPassword, String unusedName) {
|
||||
String[] line = hashedPassword.getHash().split("\\$");
|
||||
if (line.length != 4) {
|
||||
return false;
|
||||
}
|
||||
int iterations;
|
||||
try {
|
||||
iterations = Integer.parseInt(line[1]);
|
||||
} catch (NumberFormatException e) {
|
||||
ConsoleLogger.logException("Cannot read number of rounds for Pbkdf2", e);
|
||||
return false;
|
||||
}
|
||||
String salt = line[2];
|
||||
byte[] derivedKey = BinTools.hex2bin(line[3]);
|
||||
PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "UTF-8", salt.getBytes(), iterations, derivedKey);
|
||||
PBKDF2Engine engine = new PBKDF2Engine(params);
|
||||
return engine.verifyKey(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSaltLength() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
}
|
@ -1,15 +1,14 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import de.rtner.security.auth.spi.PBKDF2Engine;
|
||||
import de.rtner.security.auth.spi.PBKDF2Parameters;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.security.crypts.description.AsciiRestricted;
|
||||
import fr.xephi.authme.security.pbkdf2.PBKDF2Engine;
|
||||
import fr.xephi.authme.security.pbkdf2.PBKDF2Parameters;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
@AsciiRestricted
|
||||
public class CryptPBKDF2Django extends HexSaltedMethod {
|
||||
public class Pbkdf2Django extends HexSaltedMethod {
|
||||
|
||||
private static final int DEFAULT_ITERATIONS = 24000;
|
||||
|
||||
@ -19,7 +18,7 @@ public class CryptPBKDF2Django extends HexSaltedMethod {
|
||||
PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), DEFAULT_ITERATIONS);
|
||||
PBKDF2Engine engine = new PBKDF2Engine(params);
|
||||
|
||||
return result + String.valueOf(DatatypeConverter.printBase64Binary(engine.deriveKey(password, 32)));
|
||||
return result + DatatypeConverter.printBase64Binary(engine.deriveKey(password, 32));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -32,8 +31,7 @@ public class CryptPBKDF2Django extends HexSaltedMethod {
|
||||
try {
|
||||
iterations = Integer.parseInt(line[1]);
|
||||
} catch (NumberFormatException e) {
|
||||
ConsoleLogger.warning("Could not read number of rounds for CryptPBKDF2Django:"
|
||||
+ StringUtils.formatException(e));
|
||||
ConsoleLogger.logException("Could not read number of rounds for Pbkdf2Django:", e);
|
||||
return false;
|
||||
}
|
||||
String salt = line[2];
|
@ -1,114 +0,0 @@
|
||||
package fr.xephi.authme.security.pbkdf2;
|
||||
|
||||
/*
|
||||
* Free auxiliary functions. Copyright 2007, 2014, Matthias Gärtner
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This software 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this software; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Free auxiliary functions
|
||||
*
|
||||
* @author Matthias Gärtner
|
||||
*/
|
||||
public class BinTools {
|
||||
public static final String hex = "0123456789ABCDEF";
|
||||
|
||||
/**
|
||||
* Simple binary-to-hexadecimal conversion.
|
||||
*
|
||||
* @param b
|
||||
* Input bytes. May be <code>null</code>.
|
||||
* @return Hexadecimal representation of b. Uppercase A-F, two characters
|
||||
* per byte. Empty string on <code>null</code> input.
|
||||
*/
|
||||
public static String bin2hex(final byte[] b) {
|
||||
if (b == null) {
|
||||
return "";
|
||||
}
|
||||
StringBuffer sb = new StringBuffer(2 * b.length);
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
int v = (256 + b[i]) % 256;
|
||||
sb.append(hex.charAt((v / 16) & 15));
|
||||
sb.append(hex.charAt((v % 16) & 15));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hex string to array of bytes.
|
||||
*
|
||||
* @param s
|
||||
* String containing hexadecimal digits. May be <code>null</code>
|
||||
* . On odd length leading zero will be assumed.
|
||||
* @return Array on bytes, non-<code>null</code>.
|
||||
* @throws IllegalArgumentException
|
||||
* when string contains non-hex character
|
||||
*/
|
||||
public static byte[] hex2bin(final String s) {
|
||||
String m = s;
|
||||
if (s == null) {
|
||||
// Allow empty input string.
|
||||
m = "";
|
||||
} else if (s.length() % 2 != 0) {
|
||||
// Assume leading zero for odd string length
|
||||
m = "0" + s;
|
||||
}
|
||||
byte r[] = new byte[m.length() / 2];
|
||||
for (int i = 0, n = 0; i < m.length(); n++) {
|
||||
char h = m.charAt(i++);
|
||||
char l = m.charAt(i++);
|
||||
r[n] = (byte) (hex2bin(h) * 16 + hex2bin(l));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hex digit to numerical value.
|
||||
*
|
||||
* @param c
|
||||
* 0-9, a-f, A-F allowd.
|
||||
* @return 0-15
|
||||
* @throws IllegalArgumentException
|
||||
* on non-hex character
|
||||
*/
|
||||
public static int hex2bin(char c) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
return (c - '0');
|
||||
}
|
||||
if (c >= 'A' && c <= 'F') {
|
||||
return (c - 'A' + 10);
|
||||
}
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
return (c - 'a' + 10);
|
||||
}
|
||||
throw new IllegalArgumentException("Input string may only contain hex digits, but found '" + c + "'");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
byte b[] = new byte[256];
|
||||
byte bb = 0;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
b[i] = bb++;
|
||||
}
|
||||
String s = bin2hex(b);
|
||||
byte c[] = hex2bin(s);
|
||||
String t = bin2hex(c);
|
||||
if (!s.equals(t)) {
|
||||
throw new AssertionError("Mismatch");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
package fr.xephi.authme.security.pbkdf2;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Default PRF implementation based on standard javax.crypt.Mac mechanisms.
|
||||
* </p>
|
||||
* <p>
|
||||
* A free Java implementation of Password Based Key Derivation Function 2 as
|
||||
* defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
|
||||
* </p>
|
||||
* <p>
|
||||
* This library is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 2.1 of the License, or (at your option)
|
||||
* any later version.
|
||||
* </p>
|
||||
* <p>
|
||||
* This library 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 Lesser General Public License for more
|
||||
* details.
|
||||
* </p>
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
* </p>
|
||||
* <p>
|
||||
* For Details, see <a
|
||||
* href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
||||
* >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
|
||||
* </p>
|
||||
*
|
||||
* @author Matthias Gärtner
|
||||
* @version 1.0
|
||||
*/
|
||||
public class MacBasedPRF implements PRF {
|
||||
|
||||
protected Mac mac;
|
||||
|
||||
protected int hLen;
|
||||
|
||||
protected final String macAlgorithm;
|
||||
|
||||
/**
|
||||
* Create Mac-based Pseudo Random Function.
|
||||
*
|
||||
* @param macAlgorithm Mac algorithm to use, i.e. HMacSHA1 or HMacMD5.
|
||||
*/
|
||||
public MacBasedPRF(String macAlgorithm) {
|
||||
this.macAlgorithm = macAlgorithm;
|
||||
try {
|
||||
mac = Mac.getInstance(macAlgorithm);
|
||||
hLen = mac.getMacLength();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public MacBasedPRF(String macAlgorithm, String provider) {
|
||||
this.macAlgorithm = macAlgorithm;
|
||||
try {
|
||||
mac = Mac.getInstance(macAlgorithm, provider);
|
||||
hLen = mac.getMacLength();
|
||||
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] doFinal(byte[] M) {
|
||||
byte[] r = mac.doFinal(M);
|
||||
return r;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHLen() {
|
||||
return hLen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(byte[] P) {
|
||||
try {
|
||||
mac.init(new SecretKeySpec(P, macAlgorithm));
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
package fr.xephi.authme.security.pbkdf2;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A free Java implementation of Password Based Key Derivation Function 2 as
|
||||
* defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
|
||||
* </p>
|
||||
* <p>
|
||||
* This library is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 2.1 of the License, or (at your option)
|
||||
* any later version.
|
||||
* </p>
|
||||
* <p>
|
||||
* This library 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 Lesser General Public License for more
|
||||
* details.
|
||||
* </p>
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
* </p>
|
||||
* <p>
|
||||
* For Details, see <a
|
||||
* href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
||||
* >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
|
||||
* </p>
|
||||
*
|
||||
* @author Matthias Gärtner
|
||||
* @version 1.0
|
||||
*/
|
||||
public interface PBKDF2 {
|
||||
|
||||
/**
|
||||
* Convert String-based input to internal byte array, then invoke PBKDF2.
|
||||
* Desired key length defaults to Pseudo Random Function block size.
|
||||
*
|
||||
* @param inputPassword Candidate password to compute the derived key for.
|
||||
*
|
||||
* @return internal byte array
|
||||
*/
|
||||
byte[] deriveKey(String inputPassword);
|
||||
|
||||
/**
|
||||
* Convert String-based input to internal byte array, then invoke PBKDF2.
|
||||
*
|
||||
* @param inputPassword Candidate password to compute the derived key for.
|
||||
* @param dkLen Specify desired key length
|
||||
*
|
||||
* @return internal byte array
|
||||
*/
|
||||
byte[] deriveKey(String inputPassword, int dkLen);
|
||||
|
||||
/**
|
||||
* Convert String-based input to internal byte arrays, then invoke PBKDF2
|
||||
* and verify result against the reference data that is supplied in the
|
||||
* PBKDF2Parameters.
|
||||
*
|
||||
* @param inputPassword Candidate password to compute the derived key for.
|
||||
*
|
||||
* @return <code>true</code> password match; <code>false</code> incorrect
|
||||
* password
|
||||
*/
|
||||
boolean verifyKey(String inputPassword);
|
||||
|
||||
/**
|
||||
* Allow reading of configured parameters.
|
||||
*
|
||||
* @return Currently set parameters.
|
||||
*/
|
||||
PBKDF2Parameters getParameters();
|
||||
|
||||
/**
|
||||
* Allow setting of configured parameters.
|
||||
*
|
||||
* @param parameters PBKDF2Parameters
|
||||
*/
|
||||
void setParameters(PBKDF2Parameters parameters);
|
||||
|
||||
/**
|
||||
* Get currently set Pseudo Random Function.
|
||||
*
|
||||
* @return Currently set Pseudo Random Function
|
||||
*/
|
||||
PRF getPseudoRandomFunction();
|
||||
|
||||
/**
|
||||
* Set the Pseudo Random Function to use. Note that deriveKeys/getPRF does
|
||||
* init this object using the supplied candidate password. If this is
|
||||
* undesired, one has to override getPRF.
|
||||
*
|
||||
* @param prf Pseudo Random Function to set.
|
||||
*/
|
||||
void setPseudoRandomFunction(PRF prf);
|
||||
}
|
@ -1,346 +0,0 @@
|
||||
package fr.xephi.authme.security.pbkdf2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Request for Comments: 2898 PKCS #5: Password-Based Cryptography Specification
|
||||
* </p><p>
|
||||
* Version 2.0
|
||||
* </p>
|
||||
* <p>
|
||||
* PBKDF2 (P, S, c, dkLen)
|
||||
* </p>
|
||||
* Options:
|
||||
* <ul>
|
||||
* <li>PRF underlying pseudorandom function (hLen denotes the length in octets
|
||||
* of the pseudorandom function output). PRF is pluggable.</li>
|
||||
* </ul>
|
||||
* Input:
|
||||
* <ul>
|
||||
* <li>P password, an octet string</li>
|
||||
* <li>S salt, an octet string</li>
|
||||
* <li>c iteration count, a positive integer</li>
|
||||
* <li>dkLen intended length in octets of the derived key, a positive integer,
|
||||
* at most (2^32 - 1) * hLen</li>
|
||||
* </ul>
|
||||
* Output:
|
||||
* <ul>
|
||||
* <li>DK derived key, a dkLen-octet string</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* A free Java implementation of Password Based Key Derivation Function 2 as
|
||||
* defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
|
||||
* </p>
|
||||
* <p>
|
||||
* This library is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 2.1 of the License, or (at your option)
|
||||
* any later version.
|
||||
* </p>
|
||||
* <p>
|
||||
* This library 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 Lesser General Public License for more
|
||||
* details.
|
||||
* </p>
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
* </p>
|
||||
* <p>
|
||||
* For Details, see
|
||||
* <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html" >http://www.
|
||||
* gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
|
||||
* </p>
|
||||
*
|
||||
* @author Matthias Gärtner
|
||||
* @version 1.0
|
||||
* @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898</a>
|
||||
*/
|
||||
public class PBKDF2Engine implements PBKDF2 {
|
||||
|
||||
protected PBKDF2Parameters parameters;
|
||||
|
||||
protected PRF prf;
|
||||
|
||||
/**
|
||||
* Constructor for PBKDF2 implementation object. PBKDF2 parameters must be
|
||||
* passed later.
|
||||
*/
|
||||
public PBKDF2Engine() {
|
||||
this.parameters = null;
|
||||
prf = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for PBKDF2 implementation object. PBKDF2 parameters are
|
||||
* passed so that this implementation knows iteration count, method to use
|
||||
* and String encoding.
|
||||
*
|
||||
* @param parameters Data holder for iteration count, method to use et cetera.
|
||||
*/
|
||||
public PBKDF2Engine(PBKDF2Parameters parameters) {
|
||||
this.parameters = parameters;
|
||||
prf = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for PBKDF2 implementation object. PBKDF2 parameters are
|
||||
* passed so that this implementation knows iteration count, method to use
|
||||
* and String encoding.
|
||||
*
|
||||
* @param parameters Data holder for iteration count, method to use et cetera.
|
||||
* @param prf Supply customer Pseudo Random Function.
|
||||
*/
|
||||
public PBKDF2Engine(PBKDF2Parameters parameters, PRF prf) {
|
||||
this.parameters = parameters;
|
||||
this.prf = prf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience client function. Convert supplied password with random 8-byte
|
||||
* salt and 1000 iterations using HMacSHA1. Assume that password is in
|
||||
* ISO-8559-1 encoding. Output result as
|
||||
* "Salt:iteration-count:PBKDF2" with binary data in hexadecimal
|
||||
* encoding.
|
||||
* <p>
|
||||
* Example: Password "password" (without the quotes) leads to
|
||||
* 48290A0B96C426C3:1000:973899B1D4AFEB3ED371060D0797E0EE0142BD04
|
||||
* </p>
|
||||
* @param args Supply the password as argument.
|
||||
*
|
||||
* @throws IOException an ioexception occured
|
||||
* @throws NoSuchAlgorithmException a NoSuchAlgorithmException occured
|
||||
*/
|
||||
public static void main(String[] args)
|
||||
throws IOException, NoSuchAlgorithmException {
|
||||
String password = "password";
|
||||
String candidate = null;
|
||||
PBKDF2Formatter formatter = new PBKDF2HexFormatter();
|
||||
|
||||
if (args.length >= 1) {
|
||||
password = args[0];
|
||||
}
|
||||
if (args.length >= 2) {
|
||||
candidate = args[1];
|
||||
}
|
||||
if (candidate == null) {
|
||||
// Creation mode
|
||||
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
|
||||
byte[] salt = new byte[8];
|
||||
sr.nextBytes(salt);
|
||||
int iterations = 1000;
|
||||
PBKDF2Parameters p = new PBKDF2Parameters("HmacSHA1", "ISO-8859-1", salt, iterations);
|
||||
PBKDF2Engine e = new PBKDF2Engine(p);
|
||||
p.setDerivedKey(e.deriveKey(password));
|
||||
candidate = formatter.toString(p);
|
||||
} else {
|
||||
// Verification mode
|
||||
PBKDF2Parameters p = new PBKDF2Parameters();
|
||||
p.setHashAlgorithm("HmacSHA1");
|
||||
p.setHashCharset("ISO-8859-1");
|
||||
if (formatter.fromString(p, candidate)) {
|
||||
throw new IllegalArgumentException("Candidate data does not have correct format (\"" + candidate + "\")");
|
||||
}
|
||||
PBKDF2Engine e = new PBKDF2Engine(p);
|
||||
boolean verifyOK = e.verifyKey(password);
|
||||
System.exit(verifyOK ? 0 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] deriveKey(String inputPassword) {
|
||||
return deriveKey(inputPassword, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] deriveKey(String inputPassword, int dkLen) {
|
||||
byte[] r = null;
|
||||
byte[] P = null;
|
||||
String charset = parameters.getHashCharset();
|
||||
if (inputPassword == null) {
|
||||
inputPassword = "";
|
||||
}
|
||||
try {
|
||||
if (charset == null) {
|
||||
P = inputPassword.getBytes();
|
||||
} else {
|
||||
P = inputPassword.getBytes(charset);
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
assertPRF(P);
|
||||
if (dkLen == 0) {
|
||||
dkLen = prf.getHLen();
|
||||
}
|
||||
r = PBKDF2(prf, parameters.getSalt(), parameters.getIterationCount(), dkLen);
|
||||
return r;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verifyKey(String inputPassword) {
|
||||
byte[] referenceKey = getParameters().getDerivedKey();
|
||||
if (referenceKey == null || referenceKey.length == 0) {
|
||||
return false;
|
||||
}
|
||||
byte[] inputKey = deriveKey(inputPassword, referenceKey.length);
|
||||
|
||||
if (inputKey == null || inputKey.length != referenceKey.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < inputKey.length; i++) {
|
||||
if (inputKey[i] != referenceKey[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method. Default implementation is (H)MAC-based. To be overridden
|
||||
* in derived classes.
|
||||
*
|
||||
* @param P User-supplied candidate password as array of bytes.
|
||||
*/
|
||||
protected void assertPRF(byte[] P) {
|
||||
if (prf == null) {
|
||||
prf = new MacBasedPRF(parameters.getHashAlgorithm());
|
||||
}
|
||||
prf.init(P);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PRF getPseudoRandomFunction() {
|
||||
return prf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPseudoRandomFunction(PRF prf) {
|
||||
this.prf = prf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Core Password Based Key Derivation Function 2.
|
||||
*
|
||||
* @param prf Pseudo Random Function (i.e. HmacSHA1)
|
||||
* @param S Salt as array of bytes. <code>null</code> means no salt.
|
||||
* @param c Iteration count (see RFC 2898 4.2)
|
||||
* @param dkLen desired length of derived key.
|
||||
*
|
||||
* @return internal byte array * @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2</a>
|
||||
*/
|
||||
protected byte[] PBKDF2(PRF prf, byte[] S, int c, int dkLen) {
|
||||
if (S == null) {
|
||||
S = new byte[0];
|
||||
}
|
||||
int hLen = prf.getHLen();
|
||||
int l = ceil(dkLen, hLen);
|
||||
int r = dkLen - (l - 1) * hLen;
|
||||
byte T[] = new byte[l * hLen];
|
||||
int ti_offset = 0;
|
||||
for (int i = 1; i <= l; i++) {
|
||||
_F(T, ti_offset, prf, S, c, i);
|
||||
ti_offset += hLen;
|
||||
}
|
||||
if (r < hLen) {
|
||||
// Incomplete last block
|
||||
byte DK[] = new byte[dkLen];
|
||||
System.arraycopy(T, 0, DK, 0, dkLen);
|
||||
return DK;
|
||||
}
|
||||
return T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Integer division with ceiling function.
|
||||
*
|
||||
* @param a Integer
|
||||
* @param b Integer
|
||||
*
|
||||
* @return ceil(a/b) * @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2 Step
|
||||
* 2.</a>
|
||||
*/
|
||||
protected int ceil(int a, int b) {
|
||||
int m = 0;
|
||||
if (a % b > 0) {
|
||||
m = 1;
|
||||
}
|
||||
return a / b + m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function F.
|
||||
*
|
||||
* @param dest Destination byte buffer
|
||||
* @param offset Offset into destination byte buffer
|
||||
* @param prf Pseudo Random Function
|
||||
* @param S Salt as array of bytes
|
||||
* @param c Iteration count
|
||||
* @param blockIndex Integer
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2 Step
|
||||
* 3.</a>
|
||||
*/
|
||||
protected void _F(byte[] dest, int offset, PRF prf, byte[] S, int c,
|
||||
int blockIndex) {
|
||||
int hLen = prf.getHLen();
|
||||
byte U_r[] = new byte[hLen];
|
||||
|
||||
// U0 = S || INT (i);
|
||||
byte U_i[] = new byte[S.length + 4];
|
||||
System.arraycopy(S, 0, U_i, 0, S.length);
|
||||
INT(U_i, S.length, blockIndex);
|
||||
|
||||
for (int i = 0; i < c; i++) {
|
||||
U_i = prf.doFinal(U_i);
|
||||
xor(U_r, U_i);
|
||||
}
|
||||
System.arraycopy(U_r, 0, dest, offset, hLen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Block-Xor. Xor source bytes into destination byte buffer. Destination
|
||||
* buffer must be same length or less than source buffer.
|
||||
*
|
||||
* @param dest byte array
|
||||
* @param src byte array
|
||||
*/
|
||||
protected void xor(byte[] dest, byte[] src) {
|
||||
for (int i = 0; i < dest.length; i++) {
|
||||
dest[i] ^= src[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Four-octet encoding of the integer i, most significant octet first.
|
||||
*
|
||||
* @param dest byte array
|
||||
* @param offset Integer
|
||||
* @param i Integer
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2 Step
|
||||
* 3.</a>
|
||||
*/
|
||||
protected void INT(byte[] dest, int offset, int i) {
|
||||
dest[offset] = (byte) (i / (256 * 256 * 256));
|
||||
dest[offset + 1] = (byte) (i / (256 * 256));
|
||||
dest[offset + 2] = (byte) (i / (256));
|
||||
dest[offset + 3] = (byte) (i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PBKDF2Parameters getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameters(PBKDF2Parameters parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package fr.xephi.authme.security.pbkdf2;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A free Java implementation of Password Based Key Derivation Function 2 as
|
||||
* defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
|
||||
* </p>
|
||||
* <p>
|
||||
* This library is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 2.1 of the License, or (at your option)
|
||||
* any later version.
|
||||
* </p>
|
||||
* <p>
|
||||
* This library 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 Lesser General Public License for more
|
||||
* details.
|
||||
* </p>
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
* </p>
|
||||
* <p>
|
||||
* For Details, see <a
|
||||
* href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
||||
* >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
|
||||
* </p>
|
||||
*
|
||||
* @author Matthias Gärtner
|
||||
* @version 1.0
|
||||
*/
|
||||
public interface PBKDF2Formatter {
|
||||
|
||||
/**
|
||||
* Convert parameters to String.
|
||||
*
|
||||
* @param p Parameters object to output.
|
||||
*
|
||||
* @return String representation
|
||||
*/
|
||||
String toString(PBKDF2Parameters p);
|
||||
|
||||
/**
|
||||
* Convert String to parameters. Depending on actual implementation, it may
|
||||
* be required to set further fields externally.
|
||||
*
|
||||
* @param s String representation of parameters to decode.
|
||||
* @param p PBKDF2Parameters
|
||||
*
|
||||
* @return <code>false</code> syntax OK, <code>true</code> some syntax
|
||||
* issue.
|
||||
*/
|
||||
boolean fromString(PBKDF2Parameters p, String s);
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
package fr.xephi.authme.security.pbkdf2;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A free Java implementation of Password Based Key Derivation Function 2 as
|
||||
* defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
|
||||
* </p>
|
||||
* <p>
|
||||
* This library is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 2.1 of the License, or (at your option)
|
||||
* any later version.
|
||||
* </p>
|
||||
* <p>
|
||||
* This library 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 Lesser General Public License for more
|
||||
* details.
|
||||
* </p>
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
* </p>
|
||||
* <p>
|
||||
* For Details, see <a
|
||||
* href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
||||
* >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
|
||||
* </p>
|
||||
*
|
||||
* @author Matthias Gärtner
|
||||
* @version 1.0
|
||||
*/
|
||||
public class PBKDF2HexFormatter implements PBKDF2Formatter {
|
||||
|
||||
@Override
|
||||
public boolean fromString(PBKDF2Parameters p, String s) {
|
||||
if (p == null || s == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String[] p123 = s.split(":");
|
||||
if (p123.length != 3) {
|
||||
return true;
|
||||
}
|
||||
|
||||
byte salt[] = BinTools.hex2bin(p123[0]);
|
||||
int iterationCount = Integer.parseInt(p123[1]);
|
||||
byte bDK[] = BinTools.hex2bin(p123[2]);
|
||||
|
||||
p.setSalt(salt);
|
||||
p.setIterationCount(iterationCount);
|
||||
p.setDerivedKey(bDK);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(PBKDF2Parameters p) {
|
||||
String s = BinTools.bin2hex(p.getSalt()) + ":" + String.valueOf(p.getIterationCount()) + ":" + BinTools.bin2hex(p.getDerivedKey());
|
||||
return s;
|
||||
}
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
package fr.xephi.authme.security.pbkdf2;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Parameter data holder for PBKDF2 configuration.
|
||||
* </p>
|
||||
* <p>
|
||||
* A free Java implementation of Password Based Key Derivation Function 2 as
|
||||
* defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
|
||||
* </p>
|
||||
* <p>
|
||||
* This library is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 2.1 of the License, or (at your option)
|
||||
* any later version.
|
||||
* </p>
|
||||
* <p>
|
||||
* This library 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 Lesser General Public License for more
|
||||
* details.
|
||||
* </p>
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
* </p>
|
||||
* <p>
|
||||
* For Details, see <a
|
||||
* href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
||||
* >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
|
||||
* </p>
|
||||
*
|
||||
* @author Matthias Gärtner
|
||||
* @version 1.0
|
||||
*/
|
||||
public class PBKDF2Parameters {
|
||||
|
||||
protected byte[] salt;
|
||||
|
||||
protected int iterationCount;
|
||||
|
||||
protected String hashAlgorithm;
|
||||
|
||||
protected String hashCharset;
|
||||
|
||||
/**
|
||||
* The derived key is actually only a convenience to store a reference
|
||||
* derived key. It is not used during computation.
|
||||
*/
|
||||
protected byte[] derivedKey;
|
||||
|
||||
/**
|
||||
* Constructor. Defaults to <code>null</code> for byte arrays, UTF-8 as
|
||||
* character set and 1000 for iteration count.
|
||||
*/
|
||||
public PBKDF2Parameters() {
|
||||
this.hashAlgorithm = null;
|
||||
this.hashCharset = "UTF-8";
|
||||
this.salt = null;
|
||||
this.iterationCount = 1000;
|
||||
this.derivedKey = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param hashAlgorithm for example HMacSHA1 or HMacMD5
|
||||
* @param hashCharset for example UTF-8
|
||||
* @param salt Salt as byte array, may be <code>null</code> (not recommended)
|
||||
* @param iterationCount Number of iterations to execute. Recommended value 1000.
|
||||
*/
|
||||
public PBKDF2Parameters(String hashAlgorithm, String hashCharset,
|
||||
byte[] salt, int iterationCount) {
|
||||
this.hashAlgorithm = hashAlgorithm;
|
||||
this.hashCharset = hashCharset;
|
||||
this.salt = salt;
|
||||
this.iterationCount = iterationCount;
|
||||
this.derivedKey = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param hashAlgorithm for example HMacSHA1 or HMacMD5
|
||||
* @param hashCharset for example UTF-8
|
||||
* @param salt Salt as byte array, may be <code>null</code> (not recommended)
|
||||
* @param iterationCount Number of iterations to execute. Recommended value 1000.
|
||||
* @param derivedKey Convenience data holder, not used during computation.
|
||||
*/
|
||||
public PBKDF2Parameters(String hashAlgorithm, String hashCharset,
|
||||
byte[] salt, int iterationCount, byte[] derivedKey) {
|
||||
this.hashAlgorithm = hashAlgorithm;
|
||||
this.hashCharset = hashCharset;
|
||||
this.salt = salt;
|
||||
this.iterationCount = iterationCount;
|
||||
this.derivedKey = derivedKey;
|
||||
}
|
||||
|
||||
public int getIterationCount() {
|
||||
return iterationCount;
|
||||
}
|
||||
|
||||
public void setIterationCount(int iterationCount) {
|
||||
this.iterationCount = iterationCount;
|
||||
}
|
||||
|
||||
public byte[] getSalt() {
|
||||
return salt;
|
||||
}
|
||||
|
||||
public void setSalt(byte[] salt) {
|
||||
this.salt = salt;
|
||||
}
|
||||
|
||||
public byte[] getDerivedKey() {
|
||||
return derivedKey;
|
||||
}
|
||||
|
||||
public void setDerivedKey(byte[] derivedKey) {
|
||||
this.derivedKey = derivedKey;
|
||||
}
|
||||
|
||||
public String getHashAlgorithm() {
|
||||
return hashAlgorithm;
|
||||
}
|
||||
|
||||
public void setHashAlgorithm(String hashAlgorithm) {
|
||||
this.hashAlgorithm = hashAlgorithm;
|
||||
}
|
||||
|
||||
public String getHashCharset() {
|
||||
return hashCharset;
|
||||
}
|
||||
|
||||
public void setHashCharset(String hashCharset) {
|
||||
this.hashCharset = hashCharset;
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
package fr.xephi.authme.security.pbkdf2;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A free Java implementation of Password Based Key Derivation Function 2 as
|
||||
* defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
|
||||
* </p>
|
||||
* <p>
|
||||
* This library is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 2.1 of the License, or (at your option)
|
||||
* any later version.
|
||||
* </p>
|
||||
* <p>
|
||||
* This library 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 Lesser General Public License for more
|
||||
* details.
|
||||
* </p>
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
* </p>
|
||||
* <p>
|
||||
* For Details, see <a
|
||||
* href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
||||
* >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
|
||||
* </p>
|
||||
*
|
||||
* @author Matthias Gärtner
|
||||
* @version 1.0
|
||||
*/
|
||||
public interface PRF {
|
||||
|
||||
/**
|
||||
* Initialize this instance with the user-supplied password.
|
||||
*
|
||||
* @param P The password supplied as array of bytes. It is the caller's
|
||||
* task to convert String passwords to bytes as appropriate.
|
||||
*/
|
||||
void init(byte[] P);
|
||||
|
||||
/**
|
||||
* Pseudo Random Function
|
||||
*
|
||||
* @param M Input data/message etc. Together with any data supplied during
|
||||
* initilization.
|
||||
*
|
||||
* @return Random bytes of hLen length.
|
||||
*/
|
||||
byte[] doFinal(byte[] M);
|
||||
|
||||
/**
|
||||
* Query block size of underlying algorithm/mechanism.
|
||||
*
|
||||
* @return block size
|
||||
*/
|
||||
int getHLen();
|
||||
}
|
@ -64,9 +64,10 @@ public class SecuritySettings implements SettingsHolder {
|
||||
newProperty("settings.security.unLoggedinGroup", "unLoggedinGroup");
|
||||
|
||||
@Comment({
|
||||
"Possible values: MD5, SHA1, SHA256, WHIRLPOOL, XAUTH, MD5VB, PHPBB,",
|
||||
"MYBB, IPB3, PHPFUSION, SMF, XENFORO, SALTED2MD5, JOOMLA, BCRYPT, WBB3, SHA512,",
|
||||
"DOUBLEMD5, PBKDF2, PBKDF2DJANGO, WORDPRESS, ROYALAUTH, CUSTOM (for developers only)"
|
||||
"Possible values: SHA256, BCRYPT, BCRYPT2Y, PBKDF2, SALTEDSHA512, WHIRLPOOL,",
|
||||
"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"
|
||||
})
|
||||
public static final Property<HashAlgorithm> PASSWORD_HASH =
|
||||
newProperty(HashAlgorithm.class, "settings.security.passwordHash", HashAlgorithm.SHA256);
|
||||
@ -85,6 +86,10 @@ public class SecuritySettings implements SettingsHolder {
|
||||
public static final Property<List<String>> LEGACY_HASHES =
|
||||
new EnumSetProperty<>(HashAlgorithm.class, "settings.security.legacyHashes");
|
||||
|
||||
@Comment("Number of rounds to use if passwordHash is set to PBKDF2. Default is 10000")
|
||||
public static final Property<Integer> PBKDF2_NUMBER_OF_ROUNDS =
|
||||
newProperty("settings.security.pbkdf2Rounds", 10000);
|
||||
|
||||
@Comment({"Prevent unsafe passwords from being used; put them in lowercase!",
|
||||
"You should always set 'help' as unsafePassword due to possible conflicts.",
|
||||
"unsafePasswords:",
|
||||
|
@ -71,7 +71,7 @@ kick_antibot: '¡El modo de protección AntiBot está habilitado! Tienes que esp
|
||||
email_exists: '&c¡El correo de recuperación ya ha sido enviado! Puedes descartarlo y enviar uno nuevo utilizando el siguiente comando:'
|
||||
password_error_nick: '&cNo puedes utilizar tu nombre como contraseña, por favor elige otra...'
|
||||
accounts_owned_other: 'El jugador %name tiene %count cuentas:'
|
||||
incomplete_email_settings: 'Error: no todos los ajustes necesario se han configurado para enviar correos. Por favor, contacta con un administrador.'
|
||||
incomplete_email_settings: 'Error: no todos los ajustes necesarios se han configurado para enviar correos. Por favor, contacta con un administrador.'
|
||||
recovery_code_sent: 'El código de recuperación para recuperar tu contraseña se ha enviado a tu correo.'
|
||||
invalid_name_case: 'Solo puedes unirte mediante el nombre de usuario %valid, no %invalid.'
|
||||
email_show: '&2Tu dirección de E-Mail actual es: &f%email'
|
||||
|
@ -32,6 +32,7 @@ public class HashAlgorithmIntegrationTest {
|
||||
Settings settings = mock(Settings.class);
|
||||
given(settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND)).willReturn(8);
|
||||
given(settings.getProperty(SecuritySettings.DOUBLE_MD5_SALT_LENGTH)).willReturn(16);
|
||||
given(settings.getProperty(SecuritySettings.PBKDF2_NUMBER_OF_ROUNDS)).willReturn(10_000);
|
||||
injector = new InjectorBuilder().addDefaultHandlers("fr.xephi.authme").create();
|
||||
injector.register(Settings.class, settings);
|
||||
}
|
||||
|
@ -2,7 +2,9 @@ package fr.xephi.authme.security.crypts;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import fr.xephi.authme.TestHelper;
|
||||
import fr.xephi.authme.security.crypts.description.AsciiRestricted;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
@ -100,6 +102,11 @@ public abstract class AbstractEncryptionMethodTest {
|
||||
GIVEN_PASSWORDS[3], result3);
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setupLogger() {
|
||||
TestHelper.setupLogger();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGivenPasswords() {
|
||||
// Start with the 2nd to last password if we skip long tests
|
||||
|
@ -1,9 +1,7 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.TestHelper;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.HooksSettings;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@ -13,11 +11,6 @@ import static org.mockito.Mockito.mock;
|
||||
*/
|
||||
public class BcryptTest extends AbstractEncryptionMethodTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void initializeLogger() {
|
||||
TestHelper.setupLogger();
|
||||
}
|
||||
|
||||
public BcryptTest() {
|
||||
super(new BCRYPT(mockSettings()),
|
||||
"$2a$10$6iATmYgwJVc3YONhVcZFve3Cfb5GnwvKhJ20r.hMjmcNkIT9.Uh9K", // password
|
||||
|
@ -1,20 +0,0 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import org.junit.Ignore;
|
||||
|
||||
/**
|
||||
* Test for {@link CryptPBKDF2}.
|
||||
*/
|
||||
@Ignore
|
||||
// TODO #685: This algorithm seems broken
|
||||
public class CryptPBKDF2Test extends AbstractEncryptionMethodTest {
|
||||
|
||||
public CryptPBKDF2Test() {
|
||||
super(new CryptPBKDF2(),
|
||||
"pbkdf2_sha256$10000$dd9b1cd071f2$[82, -69, -58, -51, 101, 105, 61, -48, -49, 25, 50, -126, 115, 36, 16, -94, 4, 84, -94, 13, -115, -12, 94, -27, 94, -103, 115, -31, -56, -18, 8, 77, 36, 78, -61, 105, -7, -114, 41, 3, 48, 122, 27, 1, 56, 76, 126, 68, -120, 127, -95, 119, -7, 100, -87, -128, -77, 83, -118, 28, 43, 84, 73, 103]", // password
|
||||
"pbkdf2_sha256$10000$4b3b650288cd$[99, 25, 45, 22, -66, -109, -109, 30, 117, 77, 22, 63, -36, -126, -116, -66, 35, 109, -33, -4, -112, 53, 48, 33, -20, 107, -100, -37, -89, 59, -29, -83, 57, -123, -40, 11, 98, 32, -74, 77, 107, -76, 95, -9, 110, -92, -31, -2, -18, 115, 43, -27, 16, 36, 75, -56, -11, 58, -62, 21, 0, 37, -59, -82]", // PassWord1
|
||||
"pbkdf2_sha256$10000$035205f5ab39$[-121, -15, 97, 35, -105, -57, -49, -60, -58, -106, 101, 78, -103, 2, -116, -120, 0, 106, -107, 10, 78, -97, 111, 98, -15, 40, -53, 84, 120, -86, 116, 12, -60, 19, 105, 1, 71, 99, 4, 43, -4, -36, 35, -110, 59, 73, -20, -8, 46, 102, 51, 84, 54, -92, -41, -84, 28, 36, 37, 26, 90, -6, -49, 70]", // &^%te$t?Pw@_
|
||||
"pbkdf2_sha256$10000$ca72ded579e9$[-81, 76, -103, 78, 68, -10, -58, -88, -57, 88, -38, 108, 115, -86, 13, -84, 80, 69, 48, 15, 105, 25, -2, 123, 9, 97, 23, -96, 95, -64, -56, 59, -124, 116, 36, 10, 96, -12, -76, -121, -51, 76, -96, -27, 84, 66, 85, 75, 95, -97, -60, -98, -41, -32, -58, 39, 82, -19, -25, 98, -15, -68, 59, -48]"); // âË_3(íù*
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +1,10 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.TestHelper;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
/**
|
||||
* Test for {@link IPB4}.
|
||||
*/
|
||||
public class IPB4Test extends AbstractEncryptionMethodTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpSettings() {
|
||||
TestHelper.setupLogger();
|
||||
}
|
||||
|
||||
public IPB4Test() {
|
||||
super(new IPB4(),
|
||||
new HashedPassword("$2a$13$leEvXu77OIwPwNvtZIJvaeAx8EItGHuR3nIlq8416g0gXeJaQdrr2", "leEvXu77OIwPwNvtZIJval"), //password
|
||||
|
@ -1,20 +1,12 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.TestHelper;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
/**
|
||||
* Test for {@link CryptPBKDF2Django}.
|
||||
* Test for {@link Pbkdf2Django}.
|
||||
*/
|
||||
public class CryptPBKDF2DjangoTest extends AbstractEncryptionMethodTest {
|
||||
public class Pbkdf2DjangoTest extends AbstractEncryptionMethodTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void setupLogger() {
|
||||
TestHelper.setupLogger();
|
||||
}
|
||||
|
||||
public CryptPBKDF2DjangoTest() {
|
||||
super(new CryptPBKDF2Django(),
|
||||
public Pbkdf2DjangoTest() {
|
||||
super(new Pbkdf2Django(),
|
||||
"pbkdf2_sha256$15000$50a7ff2d7e00$t7Qx2CfzMhGEbyCa3Wk5nJvNjj3N+FdxhpwJDerl4Fs=", // password
|
||||
"pbkdf2_sha256$15000$f9d8a58f3fe2$oMqmMGuJetdubW0cpubmT8CltQLjHT+L2GuwKsaWLx8=", // PassWord1
|
||||
"pbkdf2_sha256$15000$1170bc7a31f5$Ex/2aQsXm4kogLIYARpUPn04ccK5LYYjyVPpl32ALjE=", // &^%te$t?Pw@_
|
@ -0,0 +1,44 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Test for {@link Pbkdf2}.
|
||||
*/
|
||||
public class Pbkdf2Test extends AbstractEncryptionMethodTest {
|
||||
|
||||
public Pbkdf2Test() {
|
||||
super(new Pbkdf2(mockSettings()),
|
||||
"pbkdf2_sha256$10000$b25801311edf$093E38B16DFF13FCE5CD64D5D888EE6E0376A3E572FE5DA6749515EA0F384413223A21C464B0BE899E64084D1FFEFD44F2AC768453C87F41B42CC6954C416900", // password
|
||||
"pbkdf2_sha256$10000$fe705da06c57$A41527BD58FED9C9E6F452FC1BA8B0C4C4224ECC63E37F71EB1A0865D2AB81BBFEBCA9B7B6A6E8AEF4717B43F8EB6FB4EDEFFBB399D9D991EF7E23013595BAF0", // PassWord1
|
||||
"pbkdf2_sha256$10000$05603593cdda$1D30D1D90D826C866755969F06C312E21CC3E8DA0B777E2C764700E4E1FD890B731FAF44753D68F3FC025D3EAA709E800FBF2AF61DB23464311FCE7D35353A30", // &^%te$t?Pw@_
|
||||
"pbkdf2_sha256$10000$fb944d66d754$F7E3BF8CB07CE3B3C8C5C534F803252F7B4FD58832E33BA62BA46CA06F23BAE12BE03A9CB5874BCFD4469E42972406F920E59F002247B23C22A8CF3D0E7BFFE0"); // âË_3(íù*
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDetectMatchForHashWithOtherRoundNumber() {
|
||||
// given
|
||||
Pbkdf2 pbkdf2 = new Pbkdf2(mockSettings());
|
||||
String hash = "pbkdf2_sha256$4128$3469b0d48b702046$DC8A54351008C6054E12FB19E0BF8A4EA6D4165E0EDC97A1ECD15231037C382DE5BF85D07D5BC9D1ADF9BBFE4CE257C6059FB1B9FF65DB69D8B205F064BE0DA9";
|
||||
String clearText = "PassWord1";
|
||||
|
||||
// when
|
||||
boolean isMatch = pbkdf2.comparePassword(clearText, new HashedPassword(hash), "");
|
||||
|
||||
// then
|
||||
assertThat(isMatch, equalTo(true));
|
||||
}
|
||||
|
||||
private static Settings mockSettings() {
|
||||
Settings settings = mock(Settings.class);
|
||||
given(settings.getProperty(SecuritySettings.PBKDF2_NUMBER_OF_ROUNDS)).willReturn(4128);
|
||||
return settings;
|
||||
}
|
||||
}
|
@ -1,18 +1,10 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.TestHelper;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
/**
|
||||
* Test for {@link XFBCRYPT}.
|
||||
*/
|
||||
public class XFBCRYPTTest extends AbstractEncryptionMethodTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
TestHelper.setupLogger();
|
||||
}
|
||||
|
||||
public XFBCRYPTTest() {
|
||||
super(new XFBCRYPT(),
|
||||
"$2a$10$UtuON/ZG.x8EWG/zQbryB.BHfQVrfxk3H7qykzP.UJQ8YiLjZyfqq", // password
|
||||
|
Loading…
Reference in New Issue
Block a user