10

I am trying to implement the following code in java:

var keyGenerator = new Rfc2898DeriveBytes(password, salt, 1000);
byte[] key = keyGenerator.GetBytes(32);
byte[] iv = keyGenerator.GetBytes(16);
using (AesManaged aes = new AesManaged())
{
    using (ICryptoTransform encryptor = aes.CreateEncryptor(key, iv)) 
    {
        byte[] result = encryptor.TransformFinalBlock(content, 0, content.Length);
    }
}

By using the following one:

SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec keyspec = new PBEKeySpec(password, salt, 1000, 256);
Key key = factory.generateSecret(keyspec);
SecretKeySpec secret = new SecretKeySpec(key.getEncoded(), "AES");
byte[] iv = "how_to_generate_in_java_as_in_c".getBytes();
AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret, ivSpec);
byte[] result = cipher.doFinal("asdfasdf".getBytes("UTF-8"));

I looked through a lot of examples and questions of SO and did not find a way to generate correctly iv[] (in the same value as in C). And it seems there is not way to do it, as java allow to create this value only as random (not pseudo random as available in C). Is this right? Could somebody please help with this issue?

Artemkller545
  • 979
  • 3
  • 21
  • 55
rgolovakha
  • 518
  • 2
  • 5
  • 17
  • Use this one: https://raw.githubusercontent.com/claudius108/crypto-java-lib/master/src/main/java/ro/kuberam/libs/java/crypto/toDo/Rfc2898DeriveBytes.java – M-Razavi Aug 19 '18 at 21:24

2 Answers2

8

Got a prompt from crypt specialist and found the right solution:

SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec pbeKeySpec = new PBEKeySpec(password, salt, 1000, 384);
Key secretKey = factory.generateSecret(pbeKeySpec);
byte[] key = new byte[32];
byte[] iv = new byte[16];
System.arraycopy(secretKey.getEncoded(), 0, key, 0, 32);
System.arraycopy(secretKey.getEncoded(), 32, iv, 0, 16);
rgolovakha
  • 518
  • 2
  • 5
  • 17
  • I'm not sure if this is correct since calling .getEncoded in java will return subsequent values while in .net it will return the same value. If the result isn't correct, consider taking all the bytes (48 of them) and then splitting them after 1 call. – arviman Sep 11 '18 at 08:15
  • @arviman: getEncoded() does not return *subsequent* values, it returns the same value. – President James K. Polk Sep 11 '18 at 19:36
6

I want to make sure people understand that the final code should be:

SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec pbeKeySpec = new PBEKeySpec(password, salt, 1000, 384);
Key secretKey = factory.generateSecret(pbeKeySpec);
byte[] key = new byte[32];
byte[] iv = new byte[16];
System.arraycopy(secretKey.getEncoded(), 0, key, 0, 32);
System.arraycopy(secretKey.getEncoded(), 32, iv, 0, 16);

SecretKeySpec secret = new SecretKeySpec(key, "AES");
AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret, ivSpec);
byte[] result = cipher.doFinal("asdfasdf".getBytes("UTF-8"));

if you want to turn result to a string using new String(result) is best if you use new String(result,Charset), if you don't you may get the string in formatted incorrectly.

Ivan Olmos
  • 69
  • 1
  • 1