简体   繁体   中英

Decrypting AES in C# where the file was encryped using OpenSSL -nosalt; the AES is expecting a size 16 byte array IV?

thanks in advance for reading.

The goal was to encrypt from command line and decrypt from c# while being as simple as possible. I'm starting from the docs: https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes?view=net-5.0

I have a file encrypted with this OpenSSL command (no salt):

openssl enc -nosalt -aes-128-cbc -in my_file.txt -out my_file.txt.enc -p -pass pass:hello_this_is_pass

and that outputs the Key and IV

key=2F77B7A1D3BBAA3304E53D791819958A
iv =9DD22E07DD38AF129D42E8CF3689EADD

Once in VS these were read into byte arrays with:

byte[] key = Encoding.ASCII.GetBytes("2F77B7A1D3BBAA3304E53D791819958A");
byte[] iv = Encoding.ASCII.GetBytes("9DD22E07DD38AF129D42E8CF3689EADD");
var encodedBytes = File.ReadAllBytes("myEncFile.txt.enc");

The file is read into a byte array with:


This is passed to the reading method from the docs:

static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
    {
            // Declare the string used to hold
            // the decrypted text.
            string plaintext = null;

            // Create an Aes object
            // with the specified key and IV.
            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = Key;
                aesAlg.IV = IV;  // **This is the line that errors**

                // Create a decryptor to perform the stream transform.
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

                // Create the streams used for decryption.
                using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {

                            // Read the decrypted bytes from the decrypting stream
                            // and place them in a string.
                            plaintext = srDecrypt.ReadToEnd();
                        }
                    }
                }
            }

            return plaintext;
        }

Setting aesAlg.IV throws the following error:

System.Security.Cryptography.CryptographicException: 'Specified initialization vector (IV) does not match the block size for this algorithm.'

It looks like the default value of aesAlg.IV is byte[16]. I understand that this means the IV I'm providing is twice as big as it should be, so I assumed I must be using the wrong decryptor settings

The Key size is byte[32], and I've tried configuring the instance prior to assigning aesAlg.IV, but these changes seemed to have no effect:

aesAlg.Mode = CipherMode.CBC;
aesAlg.IVSize = 128;
aesAlg.BlockSize = 128;
aesAlg.FeedbackSize = 128;
aesAlg.Padding = PaddingMode.None;

I feel like there is something very obvious I'm missing. The similar questions on here deal with encryption, or the fact that openssl will auto add "Salt__" unless -nosalt is specified. There is also a similary named question "How I could re-encrypt in using C# so that I'd be able to decrypt with OpenSSL CLI tools?" but this does not address the error I am encountering (at least as far as I can tell). I feel like I've stuck so close to the docs that I can't be the only person who would run into this?

If anyone in the future finds this, @Topaco posted the answer in the comments. The solution is to change

byte[] key = Encoding.ASCII.GetBytes("2F77B7A1D3BBAA3304E53D791819958A");
byte[] iv = Encoding.ASCII.GetBytes("9DD22E07DD38AF129D42E8CF3689EADD");

to

byte[] key = StringToByteArrayFastest("2F77B7A1D3BBAA3304E53D791819958A");
byte[] iv = StringToByteArrayFastest("9DD22E07DD38AF129D42E8CF3689EADD");

Using StringToByteArrayFastest() from How can I convert a hex string to a byte array?

        public static byte[] StringToByteArrayFastest(string hex)
        {
            if (hex.Length % 2 == 1)
                throw new Exception("The binary key cannot have an odd number of digits");

            byte[] arr = new byte[hex.Length >> 1];

            for (int i = 0; i < hex.Length >> 1; ++i)
            {
                arr[i] = (byte)((GetHexVal(hex[i << 1]) << 4) + (GetHexVal(hex[(i << 1) + 1])));
            }

            return arr;
        }

        public static int GetHexVal(char hex)
        {
            int val = (int)hex;
            //For uppercase A-F letters:
            //return val - (val < 58 ? 48 : 55);
            //For lowercase a-f letters:
            //return val - (val < 58 ? 48 : 87);
            //Or the two combined, but a bit slower:
            return val - (val < 58 ? 48 : (val < 97 ? 55 : 87));
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM