Skip to content

Instantly share code, notes, and snippets.

@kevinmichaelchen
Created June 20, 2016 19:19
Show Gist options
  • Save kevinmichaelchen/6e9528e61160baf4bd1d64f52d46d4a5 to your computer and use it in GitHub Desktop.
Save kevinmichaelchen/6e9528e61160baf4bd1d64f52d46d4a5 to your computer and use it in GitHub Desktop.
Generates PBKDF2 userPassword values for OpenDJ
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.junit.Test;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
/**
* @author Kevin Chen
*/
public class OpenDJPBKDF2Test
{
@Test
public void testOpenAMPassword()
{
// OpenDJ PBKDF2 scheme uses a default salt length of 8 bytes
String saltString = "saltsalt";
// OpenDJ PBKDF2 scheme uses a default hash length of 20 bytes
int hashLength = 20;
// OpenDJ PBKDF2 scheme uses a default iteration count of 10000
int iterationCount = 10000;
String password = "mypassword";
SecretKeyFactory secretKeyFactory;
try
{
secretKeyFactory = SecretKeyFactory.getInstance( "PBKDF2WithHmacSHA1" );
}
catch ( NoSuchAlgorithmException nsae )
{
throw new RuntimeException( nsae );
}
byte[] value = password.getBytes( StandardCharsets.US_ASCII );
byte[] salt = saltString.getBytes( StandardCharsets.US_ASCII );
// Generate hash
byte[] actualHashBytes;
PBEKeySpec keySpecification =
new PBEKeySpec(
getCharacters( value ),
salt,
iterationCount,
hashLength * Byte.SIZE );
try
{
SecretKey secretKey = secretKeyFactory.generateSecret( keySpecification );
actualHashBytes = secretKey.getEncoded();
}
catch ( InvalidKeySpecException ikse )
{
throw new RuntimeException( ikse );
}
// Base64(Hash||Salt) - the concatenation of hash bytes and salt bytes, then Base64-encoded
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try
{
byteArrayOutputStream.write( actualHashBytes );
byteArrayOutputStream.write( salt );
}
catch ( IOException e )
{
e.printStackTrace();
}
byte[] hashSaltBytes = byteArrayOutputStream.toByteArray();
byte[] base64HashSaltBytes = Base64.encodeBase64( hashSaltBytes );
String base64HashSalt = new String( base64HashSaltBytes );
System.out.println( "{PBKDF2}10000:" + base64HashSalt );
}
private static char[] getCharacters( byte[] bytes )
{
// Unfortunately, as is the case with so many old cryptographic libraries, the PBEKeySpec
// class only accepts char[] input, despite practically all hashing algorithms being
// byte-based, including ours (PBKDF2). Fortunately, it seems the KeyFactory class does not
// emit upper bytes that are zero; that is, even though a Java character is two bytes, the
// value 5 is considered [ 0x05 ], not [ 0x00, 0x05 ], etc. I'm guessing that if you input
// a character with value 261, it'd yield [ 0x01, 0x05 ], not just [ 0x05 ]. Anyway, it
// doesn't matter, since we know the value range for one byte is necessarily from 0x00 to
// 0xFF. So we'll go ahead here and simply convert the byte array into a character array.
char[] characters;
characters = new char[bytes.length];
for ( int i = 0; i < bytes.length; i++ )
{
characters[i] = (char) bytes[i];
}
return characters;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment