Search code examples
javapythonhashcryptographypbkdf2

Java 8 vs Python 2.7 pbkdf2 hashing -- different output hash letter casing


I have written, previously in Python, a function to garble a target string using PBKDF2:

from hashlib import pbkdf2_hmac
from binascii import hexlify

def garbleString(string, salt, iterations, hash_algorithm):
    target = str.encode(string)
    dk = pbkdf2_hmac(hash_algorithm, target, salt, iterations)
    hash = hexlify(dk)
    return (hash, salt, iterations)

>>> garbleString("1000000000","salt",100000,'sha256')
('d973f4855206bd777b25355782f1b14bf06fb395bf49a26086035b3b8820a74b', 'salt',  100000)

Based on this page, this function is correct -- it yields the same hash for the same inputs. http://www.neurotechnics.com/tools/pbkdf2

I am now trying to implement the same in Java, here is where I am now:

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.xml.bind.DatatypeConverter;

public class GarbledStringFactory {

    private String algorithm;

    public GarbledStringFactory(String algorithm){
        this.algorithm = algorithm;
    }
    public String getGarbledString(String string, String salt,  int iterations,  int derivedKeyLength) throws NoSuchAlgorithmException, InvalidKeySpecException {
        SecretKeyFactory f = SecretKeyFactory.getInstance(this.algorithm);
        KeySpec spec = new PBEKeySpec(string.toCharArray(), salt.getBytes(), iterations, derivedKeyLength * 8);
        SecretKey key = f.generateSecret(spec);
        String hexStr = DatatypeConverter.printHexBinary(key.getEncoded());
        return hexStr;
    }

    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException {
        // TODO Auto-generated method stub
        GarbledStringFactory factory = new GarbledStringFactory("PBKDF2WithHmacSHA256");
        String hash = factory.getGarbledString("1000000000","salt",100000,32);
        System.out.println(hash);
    }
}

This yields the hash "D973F4855206BD777B25355782F1B14BF06FB395BF49A26086035B3B8820A74B", which is the same, just with different letter casing. Does the casing matter?


Solution

  • No, the casing doesn't matter.

    If you inspect the hashes you'll find that the only letters included are from A to F. This isn't really a string, but rather a hexadecimal (base 16) number equivalent to 98356763175438224738455306401383784358747884932620687880657531803811513935691 in decimal / base 10.

    • A₁₆ (A in base 16) is the same as 10₁₀ (10 in base 10)
    • B₁₆ is 11₁₀
    • C₁₆ is 12₁₀
    • D₁₆ is 13₁₀
    • E₁₆ is 14₁₀
    • F₁₆ is 15₁₀

    It doesn't matter whether the digits are shown in upper- or lower-case. The meaning is the same.

    You can see this in the Python interpreter, where a leading 0x indicates a hexadecimal number:

    >>> hex(12)
    '0xc'
    >>> 0xf
    15
    >>> 0xF
    15