0
votes

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

2 Answers

1
votes

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).

0
votes

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;
    }