Let’s assume we want to generate encryption key and initialization vector (IV) for AES encryption based on some passphrase. And we want to be able to generate the same key and IV for the same passphrase in .NET and Java – maybe we have Android app written in Java that needs to decrypt message from ASP.NET web app.
In .NET, Rfc2898DeriveBytes class is often used to derive keys of specified length according to given passphrase, salt, and iteration count (RFC2898 / PBKDF2). For 256-bit key and 128-bit key it is as simple as this:
var keyGen = new Rfc2898DeriveBytes(passwordBytes, saltBytes, iterationCount); byte key = keyGen.GetBytes(256 / 8); byte iv = keyGen.GetBytes(128 / 8);
Fortunately, PBKDF2 implementation is also built-in in Java:
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); KeySpec spec = new PBEKeySpec(passwordChars, saltBytes, iterationCount, 256); SecretKey secretKey = factory.generateSecret(spec); byte key = secretKey.getEncoded();
We have the same key byte array, albeit with some more typing. And how about the initialization vector now? One could think that creating new PBEKeySpec with a length of 128 is the way to go. I know I did.
However, you would just get the same bytes as for the key (the first half of them). This key derivation algorithm is deterministic so for the same inputs you get the same output. Each call of
GetBytes of .NET’s
Rfc2898DeriveBytes just returns more and more bytes generated by the algorithm whereas Java implementation needs to know the total output length upfront. So for 256-bit key and 128-bit IV we need to create PBEKeySpec with the length of 384 and split the result between key and IV:
KeySpec spec = new PBEKeySpec(passwordChars, saltBytes, iterationCount, 256 + 128); SecretKey secretKey = factory.generateSecret(spec); byte data = secretKey.getEncoded(); byte keyBytes = new byte[256 / 8]; byte ivBytes = new byte[128 / 8]; System.arraycopy(data, 0, keyBytes, 0, 256 / 8); System.arraycopy(data, 256 / 8, ivBytes, 0, 128 / 8);
Note: All the Java stuff was tested only with Android.