0

I use solution from here:

public static byte[] getEncryptedPassword(String password, byte[] salt,  int iterations,  int derivedKeyLength) throws NoSuchAlgorithmException, InvalidKeySpecException {
    KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, derivedKeyLength * 8);
    SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
    return f.generateSecret(spec).getEncoded();
}

The problem is that when I do:

System.out.println(new String(getEncryptedPassword(p,s,i,l)));

I get a very strange string, something like ���:, but I want a normal string which I can save in DB. What is my mistake?

Pavel_K
  • 10,748
  • 13
  • 73
  • 186

1 Answers1

3

If you want to convert binary data like a byte[] to a String you usually encode it to Hex or Base64 format. Base64 is smaller than hex, therefore I would recommend you to use this one.

For Base64 you can use java.util.Base64 since Java 8:

String base64encoded = Base64.getEncoder().encodeToString(getEncryptedPassword(p,s,i,l)));

For Hex AFAIR Java does not contain the necessary code. You can use e.g. the Hex encode from Apache common codec :

String hexEncoded = Hex.encodeHexString(getEncryptedPassword(p,s,i,l)));

Robert
  • 39,162
  • 17
  • 99
  • 152
  • Thank you for your answer. I use Base64 as you wrote and got normal string. The only problem is that I pass length (l) as 128 but get base64encoded string with length 172. How to explain it? – Pavel_K Mar 31 '18 at 17:58
  • 1
    Base64 encoded messages are always longer because only printable characters can be used in a String (theerefore you are wasting some bits). With hex encoding the length is even longer: it is twice the input length. If you want to keep the data to a minimum don't encode it and save the `byte[]` as `BLOB` or `VARBINARY` in your database (if one of those types are supported as column type). – Robert Mar 31 '18 at 18:07
  • Could you say - my mistake is that PBEKeySpec takes (binary) bytes but not String, and return also bytes but not String. But I tried to make `normal` String with characters from these bytes. Am I right? – Pavel_K Mar 31 '18 at 18:35
  • 1
    The input to PBEKeySpec is totally irrelevant. It outputs always a byte[] which is exactly what it is designed to do. And yes, you tried to directly interpret a byte[] with binary data as String. This will never work for true binary data. – Robert Mar 31 '18 at 19:31
  • Thank you very much for detailed explanation. For hex encoding I found https://docs.oracle.com/javase/9/docs/api/javax/xml/bind/DatatypeConverter.html see printHexBinary. – Pavel_K Mar 31 '18 at 19:38
  • The xml bind module is not available by default in Java 9 (external module). I assume it will not be included in further Java releases. Therefore using it will cause problems in the future. Better directly use Apache commons codec - IMHO it is the defacto standard at the moment. – Robert Apr 01 '18 at 11:22
  • Suggest to do base64 encoding to char[] instead of String. – Sam Ginrich Jul 17 '23 at 18:25