Reputation: 75
I have a problem decrypting an encrypted string that was encrypted in Java using the DES algorithm. I think my main problem is, that I don't see any salt or IV specifications in the java code.
I have following information: This HexSequence is the encrypted data I have to decrypt: 9465E19A6B9060D75C3F7256ED1F4D21EDC18BB185304B92061308A32725BE760F1847E3B19C1D3548F61165EA2E785E48F61165EA2E78
Algorithm: DES, Padding: DES/ECB/NoPadding, Key: TESTKEY123
After decryption I should get: 550000000018h000000273Al2011112214340600000000000000000000000000
The java-code used to encrypt the data looks like this:
public class Encryptor {
private SecretKey secretKey;
private Cipher cipher;
public Encryptor(String algorithmName, String paddingName, String key) {
String keyHexCode = StringUtils.convertUnicodeToHexCode(key.getBytes());
try {
byte[] desKeyData = StringUtils.convertHexStringToByteArray(keyHexCode);
DESKeySpec desKeySpec = null;
try {
desKeySpec = new DESKeySpec(desKeyData);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithmName);
try {
secretKey = keyFactory.generateSecret(desKeySpec);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
try {
cipher = Cipher.getInstance(paddingName);
} catch (NoSuchPaddingException e) {
// TODO: handle exception
}
} catch (NoSuchAlgorithmException e) {
// TODO: handle exception
}
}
private void initEncryptor(int mode) {
try {
cipher.init(mode, secretKey);
} catch (InvalidKeyException e) {
// TODO: handle exception
}
}
public String encrypt(String clearText) {
initEncryptor(Cipher.ENCRYPT_MODE);
try {
// Encrypt the cleartext
byte[] encryptedBytes = cipher.doFinal(clearText.getBytes());
return StringUtils.convertUnicodeToHexCode(encryptedBytes).toUpperCase();
} catch (IllegalBlockSizeException e) {
// TODO: handle exception
} catch (BadPaddingException e) {
// TODO: handle exception
}
return "";
}
public String decrypt(String encryptedTextHex) {
byte[] encryptedText = StringUtils.convertHexCodeSequenceToUnicode(encryptedTextHex);
initEncryptor(Cipher.DECRYPT_MODE);
try {
// Decrypt the encryptedTextHex
return new String(cipher.doFinal(encryptedText));
} catch (IllegalBlockSizeException e) {
// TODO: handle exception
} catch (BadPaddingException e) {
// TODO: handle exception
}
return "";
}
}
I tried to use following .net-code to decrypt the data:
public class URLDecryptor
{
public static string GetValue(string Data)
{
DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
byte[] bytes = System.Text.UnicodeEncoding.Unicode.GetBytes("TESTKEY123");
byte[] salt = new byte[8];
byte[] iv = new byte[8];
Rfc2898DeriveBytes password = new Rfc2898DeriveBytes("TESTKEY123", salt);
cryptoProvider.Key = password.GetBytes(8);
cryptoProvider.IV = iv;
cryptoProvider.Padding = PaddingMode.None;
cryptoProvider.Mode = CipherMode.ECB;
MemoryStream memStream = new MemoryStream(convertHexCodeSequenceToUnicode(Data));
CryptoStream cryptoStream = new CryptoStream(memStream, cryptoProvider.CreateDecryptor(cryptoProvider.Key, cryptoProvider.IV), CryptoStreamMode.Read);
StreamReader reader = new StreamReader(cryptoStream);
string value = reader.ReadToEnd;
reader.Close();
cryptoStream.Close();
return value;
}
private static byte[] convertHexCodeSequenceToUnicode(string hexCodeSequence)
{
byte[] bytes = new byte[(hexCodeSequence.Length / 2) + 1]; //This is strange
int index = 0;
int count = 0;
while (count < hexCodeSequence.Length) {
string hexCode = hexCodeSequence.Substring(count, 2);
bytes[index] = getHexValue(hexCode);
count += 2;
index += 1;
}
return bytes;
}
public static byte getHexValue(string hexCode)
{
return byte.Parse(hexCode, System.Globalization.NumberStyles.HexNumber);
}
}
What's strange is that line:
byte[] bytes = new byte[(hexCodeSequence.Length / 2) + 1];
The data is 55 bytes long but I have to put it in 56 bytes. It appends a 0-byte to the and of the array, but if I don't do this the cryptostream throws an error that the data to decrypt is too short.
If I try it this way I only get garbage as output. I'm using a empty salt and IV because I can't see which salt and IV the java code is using. Are there any default values I don't know?
EDIT: Java code to get the byte out of the hexCode:
private static byte getNegativeValueForHexConversion(String hexCode) {
int i = Integer.parseInt(hexCode, 16);
return (byte) (i > 127 ? i - 256 : i);
}
Looks like Java uses a signed byte and .Net uses an unsigned byte for all its functions. Is this maybe the problem?
Upvotes: 3
Views: 2909
Reputation: 72840
DES is a block cipher with a 64-bit block size. Thus (in ECB mode at least) the ciphertext you have to decrypt must be a multiple of 64 bits (8 bytes) long. Yours is 55 bytes, so you do not have the full ciphertext - this is why you're having to add a zero byte. Have you run the Java code yourself and seen that the output is 55 bytes long? Is this a copy and paste error?
The exception to this would be DES used in a mode which effectively creates a key stream, that is then XORed with the plaintext to produce the ciphertext. This would include CFB, OFB and CTR modes. So one possibility is that decrypting with one of these would work (off the top of my head, I can't remember whether the .NET crypto libraries support CTR). Are you sure that ECB was specified in the Java code?
But also, you have the problem that the Java code looks like it's doing a straightforward text to hex conversion from the key text to get the key bytes, whereas the .NET code is doing an RFC-2898 compatible conversion, which will not give you the same key bytes.
Upvotes: 2