adding PBKDF2_SHA256 from 389-ds
This commit is contained in:
parent
893f44cf78
commit
3d1011ce71
2 changed files with 64 additions and 2 deletions
|
@ -1,7 +1,11 @@
|
||||||
package org.xbib.groovy.crypt
|
package org.xbib.groovy.crypt
|
||||||
|
|
||||||
import javax.crypto.Mac
|
import javax.crypto.Mac
|
||||||
|
import javax.crypto.SecretKeyFactory
|
||||||
|
import javax.crypto.spec.PBEKeySpec
|
||||||
import javax.crypto.spec.SecretKeySpec
|
import javax.crypto.spec.SecretKeySpec
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.nio.ByteOrder
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.security.NoSuchAlgorithmException
|
import java.security.NoSuchAlgorithmException
|
||||||
|
@ -79,6 +83,33 @@ class CryptUtil {
|
||||||
base64Digest(plainText, salt, 'SHA-512', 'ssha512')
|
base64Digest(plainText, salt, 'SHA-512', 'ssha512')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String pbkdf2(String plainText) {
|
||||||
|
// the 389-ds parameters for PBKDF2-SHA256
|
||||||
|
pbkdf2(plainText, randomHexString(64), 30000, 256)
|
||||||
|
}
|
||||||
|
|
||||||
|
static String pbkdf2(String plainText, String salt) {
|
||||||
|
// the 389-ds parameters for PBKDF2-SHA256: 30000 iterations, 64 bytes (128 hex) salt, 256 bytes hash length
|
||||||
|
if (salt.length() != 128) {
|
||||||
|
throw new IllegalArgumentException("salt must be 64 bytes")
|
||||||
|
}
|
||||||
|
pbkdf2(plainText, salt, 30000, 256)
|
||||||
|
}
|
||||||
|
|
||||||
|
static String pbkdf2(String plainText, String salt, int iterations, int hashLength) {
|
||||||
|
byte[] n = htonl(iterations).array() // 4 bytes for network byte order = native byte order
|
||||||
|
byte[] b = salt.decodeHex()
|
||||||
|
byte[] hash = pbkdf2(plainText.toCharArray(), b, iterations, hashLength * 8)
|
||||||
|
int len = n.length + b .length + hash.length
|
||||||
|
byte[] result = new byte[len]
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(result)
|
||||||
|
buffer.put(n)
|
||||||
|
buffer.put(b)
|
||||||
|
buffer.put(hash)
|
||||||
|
// 4 + 64 + 256 = 324 bytes
|
||||||
|
"{PBKDF2_SHA256}${result.encodeBase64()}"
|
||||||
|
}
|
||||||
|
|
||||||
static String hmacSHA1(String plainText, String secret) {
|
static String hmacSHA1(String plainText, String secret) {
|
||||||
hmac(plainText.getBytes(StandardCharsets.UTF_8), secret.getBytes(StandardCharsets.UTF_8), "HmacSHA1")
|
hmac(plainText.getBytes(StandardCharsets.UTF_8), secret.getBytes(StandardCharsets.UTF_8), "HmacSHA1")
|
||||||
}
|
}
|
||||||
|
@ -105,9 +136,32 @@ class CryptUtil {
|
||||||
mac.doFinal(plainText).encodeHex()
|
mac.doFinal(plainText).encodeHex()
|
||||||
}
|
}
|
||||||
|
|
||||||
static String random(int length) {
|
/**
|
||||||
|
* Computes the PBKDF2 hash of a password.
|
||||||
|
*
|
||||||
|
* @param password the password to hash.
|
||||||
|
* @param salt the salt
|
||||||
|
* @param iterations the iteration count (slowness factor)
|
||||||
|
* @param bytes the length of the hash to compute in bytes
|
||||||
|
* @return the PBDKF2 hash of the password
|
||||||
|
*/
|
||||||
|
static byte[] pbkdf2(char[] plainText, byte[] salt, int iterations, int len) {
|
||||||
|
PBEKeySpec spec = new PBEKeySpec(plainText, salt, iterations, len)
|
||||||
|
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
|
||||||
|
skf.generateSecret(spec).getEncoded()
|
||||||
|
}
|
||||||
|
|
||||||
|
static String randomHexString(int length) {
|
||||||
|
randomBytes(length).encodeHex()
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] randomBytes(int length) {
|
||||||
byte[] b = new byte[length]
|
byte[] b = new byte[length]
|
||||||
random.nextBytes(b)
|
random.nextBytes(b)
|
||||||
b.encodeHex()
|
b
|
||||||
|
}
|
||||||
|
|
||||||
|
static ByteBuffer htonl(int value) {
|
||||||
|
ByteBuffer.allocate(4).order(ByteOrder.nativeOrder()).putInt(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,4 +169,12 @@ class CryptTest {
|
||||||
String code = CryptUtil.ssha512(plaintext, salt)
|
String code = CryptUtil.ssha512(plaintext, salt)
|
||||||
assertEquals('{ssha512}jeWuCXRjsvKh/vK548GP9ZCs4q9Sh1u700C8eONyV+EL/P810C8vlx9Eu4vRjHq/TDoGW8FE1l/P2KG3w9lHITxo8fR/Qdgv', code,'test SSHA-512 method')
|
assertEquals('{ssha512}jeWuCXRjsvKh/vK548GP9ZCs4q9Sh1u700C8eONyV+EL/P810C8vlx9Eu4vRjHq/TDoGW8FE1l/P2KG3w9lHITxo8fR/Qdgv', code,'test SSHA-512 method')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPBKDF2() {
|
||||||
|
String plaintext = 'geheim'
|
||||||
|
String salt = "3c68f1f47f41d82f3c68f1f47f41d82f3c68f1f47f41d82f3c68f1f47f41d82f3c68f1f47f41d82f3c68f1f47f41d82f3c68f1f47f41d82f3c68f1f47f41d82f"
|
||||||
|
String code = CryptUtil.pbkdf2(plaintext, salt)
|
||||||
|
assertEquals("{PBKDF2_SHA256}MHUAADxo8fR/QdgvPGjx9H9B2C88aPH0f0HYLzxo8fR/QdgvPGjx9H9B2C88aPH0f0HYLzxo8fR/QdgvPGjx9H9B2C9DUj6t+vF3mSI5b6nExWWcUnA6DXTbEa25BIMZ5ERe9JIqjkBr2p0ot9D5x4LZx9evQNexOWb+ea/stJkmi3wWKwS/uzSpEc4NZSv/+W1ZWtnK6NMkxxRJPjXEOCrjbKCOktDwCjSelBAe/rt0DABUYoMw69c8qZ1toAIz1x6oN5y58ImMpVsPK/CkbmbeK0QtDbWYZK8V1SZ6cZlF6kngpGWnAcEilIHqCVjM1HZMI+mZz86h86ZHcbxp9twuENu3DHi3nIZRzILrRIsjWAkruSDw7W/jXseGmVeBj/22xbKSybZmXawFGM59k3U5fE+1WvudOfVzwFyVAxDxispF", code)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue