0

I have a encryption example from a 3rd party i need to integrate with ...

I am supposed to send them encrypted message and they does decrypt it on their end and performs needed operations.

They have provided me the example that's how they are expecting the string to be encrypted ..

echo -n ['String to encrypt'] | openssl enc -aes-128-cbc -A -a -nosalt -K [EncryptionKey in Hex] -iv 30303030303030303030303030303030

The sandbox encryptionKey Hex that i am given with is 313233343536373839

Currently i am not able to use above specified key and IV as is ... as the AES implementations in .Net throws me and error which says 'The specified key is not a Valid size for this algorithm'

then i just padded the key with 0s to match 32 bytes and truncated the IV to match 16 bytes..

then i am able to run the code atleast but the encrypted string from my c# code just couldn't get decrypted on openssl ..

Below is my code ..

public static string EncryptString(string plainText, string password)
    {

        byte[] key, iv;
        //converting key to hex
        byte[] ba = Encoding.ASCII.GetBytes("0123456789abcdef");
        string encryptionKeyHex = BitConverter.ToString(ba);
        encryptionKeyHex = encryptionKeyHex.Replace("-", "");

        // Padding key hex with zeros to match the size that .Net algo expects
        if (encryptionKeyHex.Length < 32)
        {
            while (encryptionKeyHex.Length < 32)
            {
                encryptionKeyHex += "0";
            }
        }

        var keyBytes = Encoding.ASCII.GetBytes(encryptionKeyHex);
        var ivBytes = Encoding.ASCII.GetBytes("3030303030303030"); // truncated the original IV specified in the question description to match the size.

        iv = ivBytes;
        key = keyBytes;

        var amAes = new AesManaged();
        amAes.Mode = CipherMode.CBC;
        amAes.Padding = PaddingMode.PKCS7;
        amAes.KeySize = 128;
        amAes.BlockSize = 128;
        amAes.Key = key;
         amAes.IV = iv;

        var icTransformer = amAes.CreateEncryptor();
        var msTemp = new MemoryStream();

        var csEncrypt = new CryptoStream(msTemp, icTransformer, CryptoStreamMode.Write);
        var sw = new StreamWriter(csEncrypt);
        sw.Write(plainText);
        sw.Close();
        sw.Dispose();

        csEncrypt.Clear();
        csEncrypt.Dispose();

        byte[] bResult = msTemp.ToArray();
        //var sha = new SHA1CryptoServiceProvider();
        //var result = sha.ComputeHash(bResult);
        string sResult = Convert.ToBase64String(bResult);
        sResult = HttpUtility.UrlEncode(sResult);

        if (System.Diagnostics.Debugger.IsAttached)
        {
            string debugDetails = "";
            debugDetails += "==> INPUT     : " + plainText + Environment.NewLine;
            debugDetails += "==> SECRET    : " + password + Environment.NewLine;
            //debugDetails += "==> SALT      : " + Program.ByteArrayToHexString(salt) + Environment.NewLine;
            debugDetails += "==> KEY       : " + Encoding.ASCII.GetString(amAes.Key) + " (" + amAes.KeySize.ToString() + ")" + Environment.NewLine;
            debugDetails += "==> IV        : " + Encoding.ASCII.GetString(amAes.IV) + Environment.NewLine;
            debugDetails += "==> ENCRYPTED : " + sResult;
            Console.WriteLine(debugDetails);
        }

        return sResult;
    }

OUTPUT:

==> INPUT : {"filter.accession_number.equals":"0987654321"}

==> SECRET : ==> KEY : 30313233343536373839000000000000 (256)

==> IV : 3030303030303030

==> ENCRYPTED : B2uDRjnekFAlRDEKDldTs09lWiE4u16ZunVwDGi6gKm6YsaRlW4HU6eKJqfYZc7b

Update

It has been noticed that we get different results when encrypting on a windows box than on a Linux Box, using the same method ..

On linux box using openssl we get ..

The command: echo -n '{"filter.accession_number.equals":"0987654321"}' | openssl enc -aes-128-cbc -A -a -nosalt -K 313233343536373839 -iv 30303030303030303030303030303030

The Result: MTAusb6rYkxYf9/REbFq9M1XwR+6Q58FfSJPTxDNwgs6z3jZ8ru+7ysnKuy2p3ox

That encrypted string works just fine .. i am able to decrypt it successfully.

While issuing the same command on windows box to openssl gives us ..

The command: echo -n '{"filter.accession_number.equals":"0987654321"}' | openssl enc -aes-128-cbc -A -a -nosalt -K 313233343536373839 -iv 30303030303030303030303030303030

The Result: Db9829q6QX6CPwLkE+rs6zqRJJQaGZ9xk7fbztaGqsKcHPcr7equz3yOJPLc+S6yvW4jXQTzoOk43F16GW7sPw==

This string doesn't work ...

2 Answers2

1

You're simply forgetting to decode the hexadecimals; Encoding.ASCII.GetBytes only gets the ASCII representation of the key and IV.

Check the answer here to convert correctly to bytes (i.e. replace Encoding.ASCII.GetBytes with StringToByteArray).

Community
  • 1
  • 1
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • I'm wondering what the value of `amAes.KeySize` is after setting the key. I wonder if it is reset to 256 bytes after you set the key, even though you set it to 128 right before that. Could you print it out and share that information with me? – Maarten Bodewes Dec 22 '16 at 13:50
  • ==> INPUT : {"filter.accession_number.equals":"0987654321"} ==> SECRET : ==> KEY : 30313233343536373839000000000000 (256) ==> IV : 3030303030303030 ==> ENCRYPTED : B2uDRjnekFAlRDEKDldTs09lWiE4u16ZunVwDGi6gKm6YsaRlW4HU6eKJqfYZc7b – perfect duffer Dec 22 '16 at 14:12
  • Updated the description with output ... further, sorry i don't get where are you pointing me to decode the key or IV ? i mean at what step ? i guess it's expecting the hex encoded string as in the openssl statement i did mention in the description... – perfect duffer Dec 22 '16 at 14:17
  • OpenSSL converts the data of the key *represented* in hexadecimals to bytes before using it as a key. You should do the same by decoding the hexadecimal encoded bytes, not by character-encoding the hexadecimals itself. Hex.decode != ASCII.encode. – Maarten Bodewes Dec 22 '16 at 14:30
  • Do You mean that i shouldn't supply the hex encoded key and IV to the encrypter but the original key and IV in bytes? – perfect duffer Dec 22 '16 at 14:38
  • Any example would be appreciated sir! – perfect duffer Dec 22 '16 at 14:39
  • Slightly altered answer. Please try yourself first. Better rename `StringToByteArray` to `HexStringToByteArray` though. – Maarten Bodewes Dec 22 '16 at 14:58
  • Marked it as answered because you pointed me in a direction which led to the solution perfectly :) Thank you .. Posting working code below .. for anyone who may need it... – perfect duffer Dec 26 '16 at 13:55
0

Here is the working code sample for anyone who gets stuck in to similar problem... @Maarten Bodewes You did point me in the right direction, just had to re-arrange the code to make it work. Thanks :)

    public static string EncryptString(string plainText)
    {
        byte[] key, iv;

        byte[] rawKey = Encoding.ASCII.GetBytes("123456789abcdef");
        string encryptionKeyHex = BitConverter.ToString(rawKey);

        byte[] hexKayBytes = FromHex(encryptionKeyHex); // convert to bytes with 'dashes'
        byte[] data = FromHex("30-30-30-30-30-30-30-30-30-30-30-30-30-30-30-30");

        encryptionKeyHex = ByteArrayToHexString(hexKayBytes);

// modifying key size to match the algorithm validation on key size

        if (encryptionKeyHex.Length < 32)
        {
            while (encryptionKeyHex.Length < 32)
            {
                encryptionKeyHex += "0";
            }
        }

        var ivOriginal = BitConverter.ToString(data);
        ivOriginal = ivOriginal.Replace("-", "");

        if (ivOriginal.Length < 16)
        {
            while (ivOriginal.Length < 16)
            {
                ivOriginal += "0";
            }
        }            

        var keyBytes = StringToByteArray(encryptionKeyHex);
        var ivBytes = StringToByteArray(ivOriginal);

        iv = ivBytes;
        key = keyBytes;

        var amAes = new AesManaged();
        amAes.Mode = CipherMode.CBC;
        amAes.Padding = PaddingMode.PKCS7;
        amAes.KeySize = 128;
        amAes.BlockSize = 128;
        amAes.Key = key;
         amAes.IV = iv;

        var icTransformer = amAes.CreateEncryptor();
        var msTemp = new MemoryStream();

        var csEncrypt = new CryptoStream(msTemp, icTransformer, CryptoStreamMode.Write);
        var sw = new StreamWriter(csEncrypt);
        sw.Write(plainText);
        sw.Close();
        sw.Dispose();

        csEncrypt.Clear();
        csEncrypt.Dispose();

        byte[] bResult = msTemp.ToArray();
        string sResult = Convert.ToBase64String(bResult);

        if (System.Diagnostics.Debugger.IsAttached)
        {
            string debugDetails = "";
            debugDetails += "==> INPUT     : " + plainText + Environment.NewLine;
            debugDetails += "==> SECRET    : " + password + Environment.NewLine;
            //debugDetails += "==> SALT      : " + Program.ByteArrayToHexString(salt) + Environment.NewLine;
            debugDetails += "==> KEY       : " + Encoding.ASCII.GetString(amAes.Key) + " (" + amAes.KeySize.ToString() + ")" + Environment.NewLine;
            debugDetails += "==> IV        : " + Encoding.ASCII.GetString(amAes.IV) + Environment.NewLine;
            debugDetails += "==> ENCRYPTED : " + sResult;
            Console.WriteLine(debugDetails);
        }

        return sResult;
    }

    public static byte[] FromHex(string hex)
    {
        hex = hex.Replace("-", "");
        byte[] raw = new byte[hex.Length / 2];
        for (int i = 0; i < raw.Length; i++)
        {
            raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
        }
        return raw;
    }

    private static string ByteArrayToHexString(byte[] bytes)
    {
        StringBuilder sbHex = new StringBuilder();

        foreach (byte b in bytes)
            sbHex.AppendFormat("{0:x2}", b);

        return sbHex.ToString();
    }

    public static byte[] StringToByteArray(String hex)
    {
        int NumberChars = hex.Length;
        byte[] bytes = new byte[NumberChars / 2];
        for (int i = 0; i < NumberChars; i += 2)
            bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
        return bytes;
    }