1

I'm trying to write the C# equivalent for the following Java code:

protected static final String DES_ECB_PKCS5PADDING = "DESede/ECB/PKCS5Padding";

 public static String decryptValueDirect(String value, String key)
            throws NoSuchAlgorithmException, NoSuchPaddingException,
            GeneralSecurityException, IllegalBlockSizeException,
            BadPaddingException {
        byte[] bytes = Base64.decodeBase64(value);
        Cipher cipher = Cipher.getInstance(DES_ECB_PKCS5PADDING);
        cipher.init(Cipher.DECRYPT_MODE, convertSecretKey(key.getBytes()));
        byte[] decryptedValue = cipher.doFinal(bytes);

        String nstr =  new String(decryptedValue);
        return nstr;
    }
protected static SecretKey convertSecretKey(byte[] encryptionKey) throws GeneralSecurityException {
        if (encryptionKey == null || encryptionKey.length == 0)
            throw new IllegalArgumentException("Encryption key must be specified");

        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(TRIPLEDES);
        KeySpec keySpec = new DESedeKeySpec(encryptionKey);
        return keyFactory.generateSecret(keySpec);
    }

The source text is a base64 encoded, then encrypted and then base64 encoded for transport on a rabbit queue. Our vendor who handles the encryption provided the above for decryption in Java, but has no idea about C#.

The only input on the encryption side is a key, a random string. We use the same string for encryption/decryption 012345678901234567890123456789 in our dev env. That is the only input, no salt, hashing (that i see) or pw iterations. The only requirement is that it is at least 24 chars long.

My C# code is below and a fiddle of my attempt is here.

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public class Program
{
    public static void Main()
    {
        //Message Data value
        //We are using encrypted multibyte.     
        string myData = @"ROE8oYeV7B6faUsvfIx0Xe55vSs9IR5DlWGRbSM+lmKmLcaJsA13VudwWlAEYtLUD8+nMXShky0grSxsk0Z9cQe5V45XnAIfUhnyzI9a0jtMFC8XnIZ5dbclPO/V73QnieIZDkbNV5cPo3BM+l79ai96KB/gkF3xuerFPxvWejtPyWbOyO+FfNyFps4gAYDITsYIAEH39VP4eipmQ5zc18BA39lajQ3UaVewSxz7H+x3Ooe2SzJT/TQWRkioJSEFwexqzkHiLOQ0MOCIVD9xTWpLYnsL3LMwyF6H8f0PY4Fc57LVGhvUZ7dsB9NWUAnmG3uqbsonNFVhuXyvJTWNyFOHwFzOMx6XDLJJFHGZhaHg2VrescfnpUtonQY08RgojBngyJNRqK8URAvI3bqKq8Y7F/9HmEtMIIQe6KuuTmU=";
        string myKey = "012345678901234567890123456789";//Development Env Key.
        Console.WriteLine("Decrypt1:");
        string s = Decrypt1(myData, myKey);
        Console.ReadLine();
    }

    public static string Decrypt1(string value, string decryptionKey)
    {
        string decryptString = "";
        TripleDESCryptoServiceProvider tDESalg = new TripleDESCryptoServiceProvider();
        MD5CryptoServiceProvider hashMD5Provider = new MD5CryptoServiceProvider();
        try
        {
            byte[] decodedData = Convert.FromBase64String(value);
            tDESalg.Mode = CipherMode.ECB;
            tDESalg.Padding = PaddingMode.PKCS7;//According to MS, same as PKCS5PADDING

            byte[] Key = hashMD5Provider.ComputeHash(Encoding.UTF8.GetBytes(decryptionKey));
            //byte[] IV = tDESalg.IV;
            byte[] IV = new byte[tDESalg.BlockSize / 8]; //The size of the IV property must be the same as the BlockSize property divided by 8

            var memoryStream = new MemoryStream(decodedData);
            var cryptoStream = new CryptoStream(memoryStream, tDESalg.CreateDecryptor(Key, IV), CryptoStreamMode.Read);
            var reader = new StreamReader(cryptoStream);
            decryptString = reader.ReadToEnd();
            byte[] decryptData = Convert.FromBase64String(decryptString);
        }
        catch (Exception e)
        {
            Console.WriteLine("A Cryptographic error occurred: {0}", e.Message + e.StackTrace);
            return null;
        }

        return decryptString;
    }

}

Searching seems to point to the same answer, the key, encoding, ... all must be the same. I just don't know what that would be the equivalent for the Java source provided. :) Any suggestions will be helpful.

zaph
  • 111,848
  • 21
  • 189
  • 228
  • 2
    If you have a problem with your code, then you should provide a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) that demonstrates your problem. Help us help you without wasting time on guessing. Also, don't provide a link to your code. Instead, [edit] your question to include the code. Links break all the time and if it does, this question will lose all value. – Artjom B. Aug 14 '17 at 21:00
  • 1
    Of course you realize that 3DES and ECB mode are a poor security choice. – zaph Aug 14 '17 at 22:44
  • Well, the key is decoded in a defective manner that loses half the entropy. However, to get the same effect in C# simply throw away the last 8 characters of the key, and decode the same way, using Encoding.UTF8.GetBytes(), and not using MD5. – President James K. Polk Aug 14 '17 at 22:48
  • @JamesKPolk You seem to think the key is not a hex representation. It is more likley a hex representation of a 2-key 3DES key, sometimes known as 2TDEA. – zaph Aug 14 '17 at 22:52
  • I think it was supposed to be a hex representation, but was decoded incorrectly. If the C# must match the defective Java code I am showing how to do so. Of course it's better not to do it wrongly, if that's possible. – President James K. Polk Aug 14 '17 at 22:59
  • This statement: **"The only input on the encryption side is a key, a random string. We use the same string for encryption/decryption 012345678901234567890123456789. That is the only input, no salt, hashing (that i see) or pw iterations."** relates to the Encryption/Decryption key for encrypting/dencrypting replicator content shared. It is a random GUID string, but could be any string 24 chars long. Hope this helps. – bruce neiman Aug 15 '17 at 14:17
  • Well, I already gave you the answer. – President James K. Polk Aug 15 '17 at 20:13
  • @zaph: I forgot to mention, I actually decrypted the string by treating the key the way I described. – President James K. Polk Aug 15 '17 at 20:22

1 Answers1

0

MD5 has a 16-byte output, Triple DES (3DES) requires a 24-byte key. There is a key size mis-match.

The C# and Java key derivations are substantially different:

C#:
byte[] Key = hashMD5Provider.ComputeHash(Encoding.UTF8.GetBytes(decryptionKey));
returns 16-bytes.

Java:
SecretKeyFactory.getInstance(TRIPLEDES)
returns 24-bytes.

There is a key option (2TDEA) where a 16-byte key is used and the first 8-bytes will be duplicated to create the last 8-bytes. NIST has deprecated this option.

Some implementations will accept a 16-byte key and extend the key to 24-bytes and some will not. You should provide all 24-bytes to 3DES, do not rely on an implementation to create the 24-byte key.

Note: The question was updated so it is not clear that the the actual encrytpion key is derived.

zaph
  • 111,848
  • 21
  • 189
  • 228
  • The above is a great explanation of Jame's comment. I followed what James K Polk wrote above and made this change: From this: byte[] Key = hashMD5Provider.ComputeHash(Encoding.UTF8.GetBytes(decryptionKey)); To this: **byte[] Key = Encoding.UTF8.GetBytes(decryptionKey.Substring(0,24));** It works now without an error. Thank you Zaph and @James K Polk – bruce neiman Aug 16 '17 at 01:04