adding PBKDF2_SHA256 from 389-ds

This commit is contained in:
Jörg Prante 2022-04-19 17:28:30 +02:00
parent afde7b4e37
commit 46611904ba
2 changed files with 64 additions and 2 deletions

View file

@ -1,7 +1,11 @@
package org.xbib.groovy.crypt
import javax.crypto.Mac
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.PBEKeySpec
import javax.crypto.spec.SecretKeySpec
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
@ -79,6 +83,33 @@ class CryptUtil {
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) {
hmac(plainText.getBytes(StandardCharsets.UTF_8), secret.getBytes(StandardCharsets.UTF_8), "HmacSHA1")
}
@ -105,9 +136,32 @@ class CryptUtil {
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]
random.nextBytes(b)
b.encodeHex()
b
}
static ByteBuffer htonl(int value) {
ByteBuffer.allocate(4).order(ByteOrder.nativeOrder()).putInt(value)
}
}

View file

@ -169,4 +169,12 @@ class CryptTest {
String code = CryptUtil.ssha512(plaintext, salt)
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)
}
}