For our current project we need to send encripted data in TripleDES MD5 CBC mode to another company. The values for the pass, salt and init vector are given by the company and are not the ones given here (but with the same length).
They have sent us the code they use to encript it (in .Net C#) which is the following:
//Encription parameter def
static private string _pass = "12345678901234";
static private string _salt = "123456";
static private string _alg = "MD5";
static private string _iv = "1234567890123456";
public static string EncriptString(string textPlain)
{
return EncriptString(textPlain, _pass, _salt, _alg, 1, _iv, 128);
}
public static string EncriptString(string textPlain, string passBase, string saltValue, string hashAlgorithm, int passwordIterations, string initVector, int keySize)
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(textPlain);
PasswordDeriveBytes password = new PasswordDeriveBytes(passBase, saltValueBytes, hashAlgorithm, passwordIterations);
byte[] keyBytes = password.GetBytes(keySize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
string cipherText = Convert.ToBase64String(cipherTextBytes);
return cipherText;
}
I've being searching for a day on Google and Stackoverflow trying to translate this into JAVA and I'm not able. This is my current approach:
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
/**
* @author alvaro
*/
public class Encriptor {
// Constants -----------------------------------------------------
private static final String PASS_PHRASE = "12345678901234";//says wrong length
private static final String SALT_VALUE = "123456";
private static final int PASSWORD_ITERATIONS = 1;
private static final String INIT_VECTOR = "1234567890123456";
private static final int KEY_SIZE = 128;
// Attributes ----------------------------------------------------
// Static --------------------------------------------------------
// Constructors --------------------------------------------------
// Public --------------------------------------------------------
public String encrypt(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidKeySpecException {
MessageDigest digest = MessageDigest.getInstance(DIGEST);
digest.update(SALT_VALUE.getBytes());
byte[] bytes = digest.digest(PASS_PHRASE.getBytes(ENCODING));
SecretKey password = new SecretKeySpec(bytes, "AES");
//Initialize objects
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] IV = INIT_VECTOR.getBytes();
IvParameterSpec ivParamSpec = new IvParameterSpec(IV);
cipher.init(Cipher.ENCRYPT_MODE, password, ivParamSpec);
byte[] encryptedData = cipher.doFinal(text.getBytes(ENCODING));
return new BASE64Encoder().encode(encryptedData).replaceAll("\n", "");
}
// Package protected ---------------------------------------------
// Protected -----------------------------------------------------
// Private -------------------------------------------------------
// Inner classes -------------------------------------------------
}
The problem is that the MD5 hash is not done the same way in Java than in C#.
Test code:
import org.junit.Test;
import static org.junit.Assert.*;
public class EncriptorTest {
@Test
public void shouldEncriptTextCorrectly() {
// GIVEN
String input = '<xml><oficina>1234</oficina><empleado>123456</empleado></xml>'
String expected = 'Lz1aG3CFYoyzjGcMzJXDB7DQgscrv9scP+d5JY8/fiUN6LV2RsnSPqDU/E5BGKz3QbeSl3RyhUgnYyN3uBBRJA=='
// WHEN
String output = new Encriptor().encrypt(input)
//THEN
assertEquals('Wrong encription', expected, output)
}
}
SOLUTION
At the end I used a solution given in another Stackoverlow question in which a port of PasswordDeriveBytes to Java is given.