mirror of
https://github.com/elastic/elasticsearch.git
synced 2025-06-28 09:28:55 -04:00
Introduce an additional hasher (PBKDF2_STRETCH) (#65328)
* Introduce an additional hasher that is PBKDF2 but pads the input to > 14 chars before hashing to comply with FIPS Approve Only mode * Introduce an additional hasher that is PBKDF2 but pads the input to > 14 chars before hashing to comply with FIPS Approve Only mode * Addressing the PR feedback adding doc changes * Renaming the hash function + rephrasing the doc descriptions * Removing leftover from the doc * Return HexCharArray instead of Base64 encoding and avoid intermediate String Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
0f7bbed37e
commit
c758dc7f4a
5 changed files with 271 additions and 63 deletions
|
@ -12,32 +12,53 @@ hashing algorithm by setting the <<static-cluster-setting,static>>
|
|||
[[cache-hash-algo]]
|
||||
.Cache hash algorithms
|
||||
|=======================
|
||||
| Algorithm | | | Description
|
||||
| `ssha256` | | | Uses a salted `sha-256` algorithm (default).
|
||||
| `md5` | | | Uses `MD5` algorithm.
|
||||
| `sha1` | | | Uses `SHA1` algorithm.
|
||||
| `bcrypt` | | | Uses `bcrypt` algorithm with salt generated in 1024 rounds.
|
||||
| `bcrypt4` | | | Uses `bcrypt` algorithm with salt generated in 16 rounds.
|
||||
| `bcrypt5` | | | Uses `bcrypt` algorithm with salt generated in 32 rounds.
|
||||
| `bcrypt6` | | | Uses `bcrypt` algorithm with salt generated in 64 rounds.
|
||||
| `bcrypt7` | | | Uses `bcrypt` algorithm with salt generated in 128 rounds.
|
||||
| `bcrypt8` | | | Uses `bcrypt` algorithm with salt generated in 256 rounds.
|
||||
| `bcrypt9` | | | Uses `bcrypt` algorithm with salt generated in 512 rounds.
|
||||
| `pbkdf2` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
| Algorithm | | | Description
|
||||
| `ssha256` | | | Uses a salted `sha-256` algorithm (default).
|
||||
| `md5` | | | Uses `MD5` algorithm.
|
||||
| `sha1` | | | Uses `SHA1` algorithm.
|
||||
| `bcrypt` | | | Uses `bcrypt` algorithm with salt generated in 1024 rounds.
|
||||
| `bcrypt4` | | | Uses `bcrypt` algorithm with salt generated in 16 rounds.
|
||||
| `bcrypt5` | | | Uses `bcrypt` algorithm with salt generated in 32 rounds.
|
||||
| `bcrypt6` | | | Uses `bcrypt` algorithm with salt generated in 64 rounds.
|
||||
| `bcrypt7` | | | Uses `bcrypt` algorithm with salt generated in 128 rounds.
|
||||
| `bcrypt8` | | | Uses `bcrypt` algorithm with salt generated in 256 rounds.
|
||||
| `bcrypt9` | | | Uses `bcrypt` algorithm with salt generated in 512 rounds.
|
||||
| `pbkdf2` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 10000 iterations.
|
||||
| `pbkdf2_1000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
| `pbkdf2_1000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 1000 iterations.
|
||||
| `pbkdf2_10000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
| `pbkdf2_10000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 10000 iterations.
|
||||
| `pbkdf2_50000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
| `pbkdf2_50000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 50000 iterations.
|
||||
| `pbkdf2_100000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
| `pbkdf2_100000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 100000 iterations.
|
||||
| `pbkdf2_500000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
| `pbkdf2_500000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 500000 iterations.
|
||||
| `pbkdf2_1000000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
| `pbkdf2_1000000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 1000000 iterations.
|
||||
| `noop`,`clear_text` | | | Doesn't hash the credentials and keeps it in clear text in
|
||||
| `pbkdf2_stretch` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 10000 iterations, after hashing the
|
||||
initial input with SHA512 first.
|
||||
| `pbkdf2_stretch_1000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 1000 iterations, after hashing the
|
||||
initial input with SHA512 first.
|
||||
| `pbkdf2_stretch_10000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 10000 iterations, after hashing the
|
||||
initial input with SHA512 first.
|
||||
| `pbkdf2_stretch_50000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 50000 iterations, after hashing the
|
||||
initial input with SHA512 first.
|
||||
| `pbkdf2_stretch_100000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 100000 iterations, after hashing the
|
||||
initial input with SHA512 first.
|
||||
| `pbkdf2_stretch_500000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 500000 iterations, after hashing the
|
||||
initial input with SHA512 first.
|
||||
| `pbkdf2_stretch_1000000`| | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 1000000 iterations, after hashing the
|
||||
initial input with SHA512 first.
|
||||
| `noop`,`clear_text` | | | Doesn't hash the credentials and keeps it in clear text in
|
||||
memory. CAUTION: keeping clear text is considered insecure
|
||||
and can be compromised at the OS level (for example through
|
||||
memory dumps and using `ptrace`).
|
||||
|
@ -52,34 +73,55 @@ following:
|
|||
[[password-hashing-algorithms]]
|
||||
.Password hashing algorithms
|
||||
|=======================
|
||||
| Algorithm | | | Description
|
||||
| Algorithm | | | Description
|
||||
|
||||
| `bcrypt` | | | Uses `bcrypt` algorithm with salt generated in 1024 rounds. (default)
|
||||
| `bcrypt4` | | | Uses `bcrypt` algorithm with salt generated in 16 rounds.
|
||||
| `bcrypt5` | | | Uses `bcrypt` algorithm with salt generated in 32 rounds.
|
||||
| `bcrypt6` | | | Uses `bcrypt` algorithm with salt generated in 64 rounds.
|
||||
| `bcrypt7` | | | Uses `bcrypt` algorithm with salt generated in 128 rounds.
|
||||
| `bcrypt8` | | | Uses `bcrypt` algorithm with salt generated in 256 rounds.
|
||||
| `bcrypt9` | | | Uses `bcrypt` algorithm with salt generated in 512 rounds.
|
||||
| `bcrypt10` | | | Uses `bcrypt` algorithm with salt generated in 1024 rounds.
|
||||
| `bcrypt11` | | | Uses `bcrypt` algorithm with salt generated in 2048 rounds.
|
||||
| `bcrypt12` | | | Uses `bcrypt` algorithm with salt generated in 4096 rounds.
|
||||
| `bcrypt13` | | | Uses `bcrypt` algorithm with salt generated in 8192 rounds.
|
||||
| `bcrypt14` | | | Uses `bcrypt` algorithm with salt generated in 16384 rounds.
|
||||
| `pbkdf2` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
| `bcrypt` | | | Uses `bcrypt` algorithm with salt generated in 1024 rounds. (default)
|
||||
| `bcrypt4` | | | Uses `bcrypt` algorithm with salt generated in 16 rounds.
|
||||
| `bcrypt5` | | | Uses `bcrypt` algorithm with salt generated in 32 rounds.
|
||||
| `bcrypt6` | | | Uses `bcrypt` algorithm with salt generated in 64 rounds.
|
||||
| `bcrypt7` | | | Uses `bcrypt` algorithm with salt generated in 128 rounds.
|
||||
| `bcrypt8` | | | Uses `bcrypt` algorithm with salt generated in 256 rounds.
|
||||
| `bcrypt9` | | | Uses `bcrypt` algorithm with salt generated in 512 rounds.
|
||||
| `bcrypt10` | | | Uses `bcrypt` algorithm with salt generated in 1024 rounds.
|
||||
| `bcrypt11` | | | Uses `bcrypt` algorithm with salt generated in 2048 rounds.
|
||||
| `bcrypt12` | | | Uses `bcrypt` algorithm with salt generated in 4096 rounds.
|
||||
| `bcrypt13` | | | Uses `bcrypt` algorithm with salt generated in 8192 rounds.
|
||||
| `bcrypt14` | | | Uses `bcrypt` algorithm with salt generated in 16384 rounds.
|
||||
| `pbkdf2` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 10000 iterations.
|
||||
| `pbkdf2_1000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
| `pbkdf2_1000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 1000 iterations.
|
||||
| `pbkdf2_10000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
| `pbkdf2_10000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 10000 iterations.
|
||||
| `pbkdf2_50000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
| `pbkdf2_50000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 50000 iterations.
|
||||
| `pbkdf2_100000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
| `pbkdf2_100000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 100000 iterations.
|
||||
| `pbkdf2_500000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
| `pbkdf2_500000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 500000 iterations.
|
||||
| `pbkdf2_1000000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
| `pbkdf2_1000000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 1000000 iterations.
|
||||
| `pbkdf2_stretch` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 10000 iterations, after hashing the
|
||||
initial input with SHA512 first.
|
||||
| `pbkdf2_stretch_1000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 1000 iterations, after hashing the
|
||||
initial input with SHA512 first.
|
||||
| `pbkdf2_stretch_10000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 10000 iterations, after hashing the
|
||||
initial input with SHA512 first.
|
||||
| `pbkdf2_stretch_50000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 50000 iterations, after hashing the
|
||||
initial input with SHA512 first.
|
||||
| `pbkdf2_stretch_100000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 100000 iterations, after hashing the
|
||||
initial input with SHA512 first.
|
||||
| `pbkdf2_stretch_500000` | | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 500000 iterations, after hashing the
|
||||
initial input with SHA512 first.
|
||||
| `pbkdf2_stretch_1000000`| | | Uses `PBKDF2` key derivation function with `HMAC-SHA512` as a
|
||||
pseudorandom function using 1000000 iterations, after hashing the
|
||||
initial input with SHA512 first.
|
||||
|=======================
|
||||
|
||||
|
||||
|
|
|
@ -25,8 +25,8 @@ import java.util.Objects;
|
|||
|
||||
/**
|
||||
* This MessageDigests class provides convenience methods for obtaining
|
||||
* thread local {@link MessageDigest} instances for MD5, SHA-1, and
|
||||
* SHA-256 message digests.
|
||||
* thread local {@link MessageDigest} instances for MD5, SHA-1, SHA-256 and
|
||||
* SHA-512 message digests.
|
||||
*/
|
||||
public final class MessageDigests {
|
||||
|
||||
|
@ -43,6 +43,7 @@ public final class MessageDigests {
|
|||
private static final ThreadLocal<MessageDigest> MD5_DIGEST = createThreadLocalMessageDigest("MD5");
|
||||
private static final ThreadLocal<MessageDigest> SHA_1_DIGEST = createThreadLocalMessageDigest("SHA-1");
|
||||
private static final ThreadLocal<MessageDigest> SHA_256_DIGEST = createThreadLocalMessageDigest("SHA-256");
|
||||
private static final ThreadLocal<MessageDigest> SHA_512_DIGEST = createThreadLocalMessageDigest("SHA-512");
|
||||
|
||||
/**
|
||||
* Returns a {@link MessageDigest} instance for MD5 digests; note
|
||||
|
@ -80,6 +81,18 @@ public final class MessageDigests {
|
|||
return get(SHA_256_DIGEST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link MessageDigest} instance for SHA-512 digests;
|
||||
* note that the instance returned is thread local and must not be
|
||||
* shared amongst threads.
|
||||
*
|
||||
* @return a thread local {@link MessageDigest} instance that
|
||||
* provides SHA-512 message digest functionality.
|
||||
*/
|
||||
public static MessageDigest sha512() {
|
||||
return get(SHA_512_DIGEST);
|
||||
}
|
||||
|
||||
private static MessageDigest get(ThreadLocal<MessageDigest> messageDigest) {
|
||||
MessageDigest instance = messageDigest.get();
|
||||
instance.reset();
|
||||
|
|
|
@ -185,12 +185,12 @@ public enum Hasher {
|
|||
PBKDF2() {
|
||||
@Override
|
||||
public char[] hash(SecureString data) {
|
||||
return getPbkdf2Hash(data, PBKDF2_DEFAULT_COST);
|
||||
return getPbkdf2Hash(data, PBKDF2_DEFAULT_COST, PBKDF2_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(SecureString data, char[] hash) {
|
||||
return verifyPbkdf2Hash(data, hash);
|
||||
return verifyPbkdf2Hash(data, hash, PBKDF2_PREFIX);
|
||||
}
|
||||
|
||||
},
|
||||
|
@ -198,12 +198,12 @@ public enum Hasher {
|
|||
PBKDF2_1000() {
|
||||
@Override
|
||||
public char[] hash(SecureString data) {
|
||||
return getPbkdf2Hash(data, 1000);
|
||||
return getPbkdf2Hash(data, 1000, PBKDF2_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(SecureString data, char[] hash) {
|
||||
return verifyPbkdf2Hash(data, hash);
|
||||
return verifyPbkdf2Hash(data, hash, PBKDF2_PREFIX);
|
||||
}
|
||||
|
||||
},
|
||||
|
@ -211,12 +211,12 @@ public enum Hasher {
|
|||
PBKDF2_10000() {
|
||||
@Override
|
||||
public char[] hash(SecureString data) {
|
||||
return getPbkdf2Hash(data, 10000);
|
||||
return getPbkdf2Hash(data, 10000, PBKDF2_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(SecureString data, char[] hash) {
|
||||
return verifyPbkdf2Hash(data, hash);
|
||||
return verifyPbkdf2Hash(data, hash, PBKDF2_PREFIX);
|
||||
}
|
||||
|
||||
},
|
||||
|
@ -224,12 +224,12 @@ public enum Hasher {
|
|||
PBKDF2_50000() {
|
||||
@Override
|
||||
public char[] hash(SecureString data) {
|
||||
return getPbkdf2Hash(data, 50000);
|
||||
return getPbkdf2Hash(data, 50000, PBKDF2_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(SecureString data, char[] hash) {
|
||||
return verifyPbkdf2Hash(data, hash);
|
||||
return verifyPbkdf2Hash(data, hash, PBKDF2_PREFIX);
|
||||
}
|
||||
|
||||
},
|
||||
|
@ -237,12 +237,12 @@ public enum Hasher {
|
|||
PBKDF2_100000() {
|
||||
@Override
|
||||
public char[] hash(SecureString data) {
|
||||
return getPbkdf2Hash(data, 100000);
|
||||
return getPbkdf2Hash(data, 100000, PBKDF2_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(SecureString data, char[] hash) {
|
||||
return verifyPbkdf2Hash(data, hash);
|
||||
return verifyPbkdf2Hash(data, hash, PBKDF2_PREFIX);
|
||||
}
|
||||
|
||||
},
|
||||
|
@ -250,12 +250,12 @@ public enum Hasher {
|
|||
PBKDF2_500000() {
|
||||
@Override
|
||||
public char[] hash(SecureString data) {
|
||||
return getPbkdf2Hash(data, 500000);
|
||||
return getPbkdf2Hash(data, 500000, PBKDF2_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(SecureString data, char[] hash) {
|
||||
return verifyPbkdf2Hash(data, hash);
|
||||
return verifyPbkdf2Hash(data, hash, PBKDF2_PREFIX);
|
||||
}
|
||||
|
||||
},
|
||||
|
@ -263,12 +263,103 @@ public enum Hasher {
|
|||
PBKDF2_1000000() {
|
||||
@Override
|
||||
public char[] hash(SecureString data) {
|
||||
return getPbkdf2Hash(data, 1000000);
|
||||
return getPbkdf2Hash(data, 1000000, PBKDF2_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(SecureString data, char[] hash) {
|
||||
return verifyPbkdf2Hash(data, hash);
|
||||
return verifyPbkdf2Hash(data, hash, PBKDF2_PREFIX);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
PBKDF2_STRETCH() {
|
||||
@Override
|
||||
public char[] hash(SecureString data) {
|
||||
return getPbkdf2Hash(new SecureString(hashSha512(data)), PBKDF2_DEFAULT_COST, PBKDF2_STRETCH_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(SecureString data, char[] hash) {
|
||||
return verifyPbkdf2Hash(new SecureString(hashSha512(data)), hash, PBKDF2_STRETCH_PREFIX);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
PBKDF2_STRETCH_1000() {
|
||||
@Override
|
||||
public char[] hash(SecureString data) {
|
||||
return getPbkdf2Hash(new SecureString(hashSha512(data)), 1000, PBKDF2_STRETCH_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(SecureString data, char[] hash) {
|
||||
return verifyPbkdf2Hash(new SecureString(hashSha512(data)), hash, PBKDF2_STRETCH_PREFIX);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
PBKDF2_STRETCH_10000() {
|
||||
@Override
|
||||
public char[] hash(SecureString data) {
|
||||
return getPbkdf2Hash(new SecureString(hashSha512(data)), 10000, PBKDF2_STRETCH_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(SecureString data, char[] hash) {
|
||||
return verifyPbkdf2Hash(new SecureString(hashSha512(data)), hash, PBKDF2_STRETCH_PREFIX);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
PBKDF2_STRETCH_50000() {
|
||||
@Override
|
||||
public char[] hash(SecureString data) {
|
||||
return getPbkdf2Hash(new SecureString(hashSha512(data)), 50000, PBKDF2_STRETCH_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(SecureString data, char[] hash) {
|
||||
return verifyPbkdf2Hash(new SecureString(hashSha512(data)), hash, PBKDF2_STRETCH_PREFIX);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
PBKDF2_STRETCH_100000() {
|
||||
@Override
|
||||
public char[] hash(SecureString data) {
|
||||
return getPbkdf2Hash(new SecureString(hashSha512(data)), 100000, PBKDF2_STRETCH_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(SecureString data, char[] hash) {
|
||||
return verifyPbkdf2Hash(new SecureString(hashSha512(data)), hash, PBKDF2_STRETCH_PREFIX);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
PBKDF2_STRETCH_500000() {
|
||||
@Override
|
||||
public char[] hash(SecureString data) {
|
||||
return getPbkdf2Hash(new SecureString(hashSha512(data)), 500000, PBKDF2_STRETCH_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(SecureString data, char[] hash) {
|
||||
return verifyPbkdf2Hash(new SecureString(hashSha512(data)), hash, PBKDF2_STRETCH_PREFIX);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
PBKDF2_STRETCH_1000000() {
|
||||
@Override
|
||||
public char[] hash(SecureString data) {
|
||||
return getPbkdf2Hash(new SecureString(hashSha512(data)), 1000000, PBKDF2_STRETCH_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(SecureString data, char[] hash) {
|
||||
return verifyPbkdf2Hash(new SecureString(hashSha512(data)), hash, PBKDF2_STRETCH_PREFIX);
|
||||
}
|
||||
|
||||
},
|
||||
|
@ -388,6 +479,7 @@ public enum Hasher {
|
|||
private static final String MD5_PREFIX = "{MD5}";
|
||||
private static final String SSHA256_PREFIX = "{SSHA256}";
|
||||
private static final String PBKDF2_PREFIX = "{PBKDF2}";
|
||||
private static final String PBKDF2_STRETCH_PREFIX = "{PBKDF2_STRETCH}";
|
||||
private static final int PBKDF2_DEFAULT_COST = 10000;
|
||||
private static final int PBKDF2_KEY_LENGTH = 256;
|
||||
private static final int BCRYPT_DEFAULT_COST = 10;
|
||||
|
@ -442,6 +534,20 @@ public enum Hasher {
|
|||
return PBKDF2_500000;
|
||||
case "pbkdf2_1000000":
|
||||
return PBKDF2_1000000;
|
||||
case "pbkdf2_stretch":
|
||||
return PBKDF2_STRETCH;
|
||||
case "pbkdf2_stretch_1000":
|
||||
return PBKDF2_STRETCH_1000;
|
||||
case "pbkdf2_stretch_10000":
|
||||
return PBKDF2_STRETCH_10000;
|
||||
case "pbkdf2_stretch_50000":
|
||||
return PBKDF2_STRETCH_50000;
|
||||
case "pbkdf2_stretch_100000":
|
||||
return PBKDF2_STRETCH_100000;
|
||||
case "pbkdf2_stretch_500000":
|
||||
return PBKDF2_STRETCH_500000;
|
||||
case "pbkdf2_stretch_1000000":
|
||||
return PBKDF2_STRETCH_1000000;
|
||||
case "sha1":
|
||||
return SHA1;
|
||||
case "md5":
|
||||
|
@ -468,6 +574,9 @@ public enum Hasher {
|
|||
if (CharArrays.charsBeginsWith(BCRYPT_PREFIX, hash)) {
|
||||
int cost = Integer.parseInt(new String(Arrays.copyOfRange(hash, BCRYPT_PREFIX.length(), hash.length - 54)));
|
||||
return cost == BCRYPT_DEFAULT_COST ? Hasher.BCRYPT : resolve("bcrypt" + cost);
|
||||
} else if (CharArrays.charsBeginsWith(PBKDF2_STRETCH_PREFIX, hash)) {
|
||||
int cost = Integer.parseInt(new String(Arrays.copyOfRange(hash, PBKDF2_STRETCH_PREFIX.length(), hash.length - 90)));
|
||||
return cost == PBKDF2_DEFAULT_COST ? Hasher.PBKDF2_STRETCH : resolve("pbkdf2_stretch_" + cost);
|
||||
} else if (CharArrays.charsBeginsWith(PBKDF2_PREFIX, hash)) {
|
||||
int cost = Integer.parseInt(new String(Arrays.copyOfRange(hash, PBKDF2_PREFIX.length(), hash.length - 90)));
|
||||
return cost == PBKDF2_DEFAULT_COST ? Hasher.PBKDF2 : resolve("pbkdf2_" + cost);
|
||||
|
@ -497,12 +606,12 @@ public enum Hasher {
|
|||
return hasher.verify(data, hash);
|
||||
}
|
||||
|
||||
private static char[] getPbkdf2Hash(SecureString data, int cost) {
|
||||
private static char[] getPbkdf2Hash(SecureString data, int cost, String prefix) {
|
||||
try {
|
||||
// Base64 string length : (4*(n/3)) rounded up to the next multiple of 4 because of padding.
|
||||
// n is 32 (PBKDF2_KEY_LENGTH in bytes) and 2 is because of the dollar sign delimiters.
|
||||
CharBuffer result = CharBuffer.allocate(PBKDF2_PREFIX.length() + String.valueOf(cost).length() + 2 + 44 + 44);
|
||||
result.put(PBKDF2_PREFIX);
|
||||
CharBuffer result = CharBuffer.allocate(prefix.length() + String.valueOf(cost).length() + 2 + 44 + 44);
|
||||
result.put(prefix);
|
||||
result.put(String.valueOf(cost));
|
||||
result.put("$");
|
||||
byte[] salt = generateSalt(32);
|
||||
|
@ -517,7 +626,7 @@ public enum Hasher {
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean verifyPbkdf2Hash(SecureString data, char[] hash) {
|
||||
private static boolean verifyPbkdf2Hash(SecureString data, char[] hash, String prefix) {
|
||||
// Base64 string length : (4*(n/3)) rounded up to the next multiple of 4 because of padding.
|
||||
// n is 32 (PBKDF2_KEY_LENGTH in bytes), so tokenLength is 44
|
||||
final int tokenLength = 44;
|
||||
|
@ -525,12 +634,12 @@ public enum Hasher {
|
|||
char[] saltChars = null;
|
||||
char[] computedPwdHash = null;
|
||||
try {
|
||||
if (CharArrays.charsBeginsWith(PBKDF2_PREFIX, hash) == false) {
|
||||
if (CharArrays.charsBeginsWith(prefix, hash) == false) {
|
||||
return false;
|
||||
}
|
||||
hashChars = Arrays.copyOfRange(hash, hash.length - tokenLength, hash.length);
|
||||
saltChars = Arrays.copyOfRange(hash, hash.length - (2 * tokenLength + 1), hash.length - (tokenLength + 1));
|
||||
int cost = Integer.parseInt(new String(Arrays.copyOfRange(hash, PBKDF2_PREFIX.length(), hash.length - (2 * tokenLength + 2))));
|
||||
int cost = Integer.parseInt(new String(Arrays.copyOfRange(hash, prefix.length(), hash.length - (2 * tokenLength + 2))));
|
||||
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2withHMACSHA512");
|
||||
PBEKeySpec keySpec = new PBEKeySpec(data.getChars(), Base64.getDecoder().decode(CharArrays.toUtf8Bytes(saltChars)),
|
||||
cost, PBKDF2_KEY_LENGTH);
|
||||
|
@ -597,4 +706,10 @@ public enum Hasher {
|
|||
SECURE_RANDOM.nextBytes(salt);
|
||||
return salt;
|
||||
}
|
||||
|
||||
private static char[] hashSha512(SecureString text) {
|
||||
MessageDigest md = MessageDigests.sha512();
|
||||
md.update(CharArrays.toUtf8Bytes(text.getChars()));
|
||||
return MessageDigests.toHexCharArray(md.digest());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,13 @@ public class HasherTests extends ESTestCase {
|
|||
testHasherSelfGenerated(Hasher.PBKDF2_100000);
|
||||
testHasherSelfGenerated(Hasher.PBKDF2_500000);
|
||||
testHasherSelfGenerated(Hasher.PBKDF2_1000000);
|
||||
testHasherSelfGenerated(Hasher.PBKDF2_STRETCH);
|
||||
testHasherSelfGenerated(Hasher.PBKDF2_STRETCH_1000);
|
||||
testHasherSelfGenerated(Hasher.PBKDF2_STRETCH_10000);
|
||||
testHasherSelfGenerated(Hasher.PBKDF2_STRETCH_50000);
|
||||
testHasherSelfGenerated(Hasher.PBKDF2_STRETCH_100000);
|
||||
testHasherSelfGenerated(Hasher.PBKDF2_STRETCH_500000);
|
||||
testHasherSelfGenerated(Hasher.PBKDF2_STRETCH_1000000);
|
||||
}
|
||||
|
||||
public void testMd5SelfGenerated() throws Exception {
|
||||
|
@ -78,6 +85,13 @@ public class HasherTests extends ESTestCase {
|
|||
assertThat(Hasher.resolve("pbkdf2_100000"), sameInstance(Hasher.PBKDF2_100000));
|
||||
assertThat(Hasher.resolve("pbkdf2_500000"), sameInstance(Hasher.PBKDF2_500000));
|
||||
assertThat(Hasher.resolve("pbkdf2_1000000"), sameInstance(Hasher.PBKDF2_1000000));
|
||||
assertThat(Hasher.resolve("pbkdf2_stretch"), sameInstance(Hasher.PBKDF2_STRETCH));
|
||||
assertThat(Hasher.resolve("pbkdf2_stretch_1000"), sameInstance(Hasher.PBKDF2_STRETCH_1000));
|
||||
assertThat(Hasher.resolve("pbkdf2_stretch_10000"), sameInstance(Hasher.PBKDF2_STRETCH_10000));
|
||||
assertThat(Hasher.resolve("pbkdf2_stretch_50000"), sameInstance(Hasher.PBKDF2_STRETCH_50000));
|
||||
assertThat(Hasher.resolve("pbkdf2_stretch_100000"), sameInstance(Hasher.PBKDF2_STRETCH_100000));
|
||||
assertThat(Hasher.resolve("pbkdf2_stretch_500000"), sameInstance(Hasher.PBKDF2_STRETCH_500000));
|
||||
assertThat(Hasher.resolve("pbkdf2_stretch_1000000"), sameInstance(Hasher.PBKDF2_STRETCH_1000000));
|
||||
assertThat(Hasher.resolve("sha1"), sameInstance(Hasher.SHA1));
|
||||
assertThat(Hasher.resolve("md5"), sameInstance(Hasher.MD5));
|
||||
assertThat(Hasher.resolve("ssha256"), sameInstance(Hasher.SSHA256));
|
||||
|
@ -132,11 +146,35 @@ public class HasherTests extends ESTestCase {
|
|||
assertThat(Hasher.resolveFromHash(
|
||||
"{PBKDF2}1000000$UuyhtjDEzWmE2wyY80akZKPWWpy2r2X50so41YML82U=$WFasYLelqbjQwt3EqFlUcwHiC38EZC45Iu/Iz0xL1GQ=".toCharArray()),
|
||||
sameInstance(Hasher.PBKDF2_1000000));
|
||||
assertThat(Hasher.resolveFromHash(
|
||||
"{PBKDF2_STRETCH}1000$sTyix9e0zNINzq2aDZ+GD5+QlO94xVyf/bv4pWNhBxo=$4KuzGPy9HXnhY3ANHn8rcIRQuJHPB6cEtLwnOhDI5d4="
|
||||
.toCharArray()),
|
||||
sameInstance(Hasher.PBKDF2_STRETCH_1000));
|
||||
assertThat(Hasher.resolveFromHash(
|
||||
"{PBKDF2_STRETCH}10000$8M9+Ww0xkdY250CROEutsd8UP6CrJESw7ZAFu1NGORo=$ai0gxBPtHTfZU/nbNGwL5zjC+eo2/ANQM17L/tllVeo="
|
||||
.toCharArray()),
|
||||
sameInstance(Hasher.PBKDF2_STRETCH));
|
||||
assertThat(Hasher.resolveFromHash(
|
||||
"{PBKDF2_STRETCH}50000$uupwXiq8W0+jrLtC3/aqzuvyZlRarlmx1+CQGEnomlk=$by8q/+oRPPWwDE6an7B9/ndz7UZ1UQpaGY4CGurtPTI="
|
||||
.toCharArray()),
|
||||
sameInstance(Hasher.PBKDF2_STRETCH_50000));
|
||||
assertThat(Hasher.resolveFromHash(
|
||||
"{PBKDF2_STRETCH}100000$E9VqtV76PcrQuCZ6wOMMNvs4CMPcANTpzRw8Wjd24PU=$j56uKUvwbvmgQgNFkbV7SRQVZ2QOarokAgBeA8xcFD8="
|
||||
.toCharArray()),
|
||||
sameInstance(Hasher.PBKDF2_STRETCH_100000));
|
||||
assertThat(Hasher.resolveFromHash(
|
||||
"{PBKDF2_STRETCH}500000$4dpTEbu4jfjhDOjWY6xdsnxuQs4dg4QbNzZJ0Z1Tm4s=$Us/yrlCxVaW7mz0go1qIygFqGgcfUMgCZfIl2AvI4I8="
|
||||
.toCharArray()),
|
||||
sameInstance(Hasher.PBKDF2_STRETCH_500000));
|
||||
assertThat(Hasher.resolveFromHash(
|
||||
"{PBKDF2_STRETCH}1000000$eKeQvMztiIcqBynTNDFBseOBww3GBpHDZI6EPPVHYUw=$4587yrxUa02RZ1jeW1WOaMjRn5qT9iQ5/DIHk0nW2bE="
|
||||
.toCharArray()),
|
||||
sameInstance(Hasher.PBKDF2_STRETCH_1000000));
|
||||
assertThat(Hasher.resolveFromHash("notavalidhashformat".toCharArray()), sameInstance(Hasher.NOOP));
|
||||
}
|
||||
|
||||
private static void testHasherSelfGenerated(Hasher hasher) {
|
||||
SecureString passwd = new SecureString(randomAlphaOfLength(10).toCharArray());
|
||||
SecureString passwd = new SecureString(randomAlphaOfLength(between(6, 15)).toCharArray());
|
||||
char[] hash = hasher.hash(passwd);
|
||||
assertTrue(hasher.verify(passwd, hash));
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ public class UsersToolTests extends CommandTestCase {
|
|||
IOUtils.rm(homeDir);
|
||||
confDir = homeDir.resolve("config");
|
||||
Files.createDirectories(confDir);
|
||||
hasher = inFipsJvm() ? randomFrom(Hasher.PBKDF2, Hasher.PBKDF2_1000)
|
||||
hasher = inFipsJvm() ? randomFrom(Hasher.PBKDF2, Hasher.PBKDF2_1000, Hasher.PBKDF2_STRETCH)
|
||||
: randomFrom(Hasher.PBKDF2_1000, Hasher.PBKDF2, Hasher.BCRYPT, Hasher.BCRYPT9);
|
||||
String defaultPassword = SecuritySettingsSourceField.TEST_PASSWORD;
|
||||
Files.write(confDir.resolve("users"), Arrays.asList(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue