【问题标题】:Decrypting AES in C# where the file was encryped using OpenSSL -nosalt; the AES is expecting a size 16 byte array IV?在 C# 中解密使用 OpenSSL -nosalt 加密文件的 AES; AES 期望大小为 16 字节的数组 IV?
【发布时间】:2021-04-21 00:27:16
【问题描述】:

提前感谢您的阅读。

目标是从命令行加密并从 c# 解密,同时尽可能简单。我从文档开始:https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes?view=net-5.0

我有一个使用此 OpenSSL 命令加密的文件(无盐):

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

输出密钥和IV

key=2F77B7A1D3BBAA3304E53D791819958A
iv =9DD22E07DD38AF129D42E8CF3689EADD

一旦在 VS 中,这些被读入字节数组:

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

文件被读入字节数组:


这是从文档传递给阅读方法的:

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

设置aesAlg.IV 会引发以下错误:

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

看起来 aesAlg.IV 的默认值为 byte[16]。我知道这意味着我提供的 IV 是应有的两倍大,所以我认为我必须使用错误的解密器设置

Key 大小为 byte[32],我已经尝试在分配 aesAlg.IV 之前配置实例,但这些更改似乎没有效果:

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

我觉得我缺少一些非常明显的东西。此处的类似问题涉及加密,或者除非指定 -nosalt,否则 openssl 将自动添加“Salt__”这一事实。还有一个类似名称的问题“如何使用 C# 重新加密以便能够使用 OpenSSL CLI 工具进行解密?”但这并不能解决我遇到的错误(至少据我所知)。我觉得我离文档如此之近,以至于我不能成为唯一会遇到这种情况的人?

【问题讨论】:

  • 我看到你在配置上没有指定填充,而不是 ISO10126。不确定这是否与您的问题有关,但它对我来说很重要,但您不应该这样做。
  • OpenSSL 将 key 和 IV 输出为十六进制编码字符串,即它们不能在 C# 代码中进行 ASCII 编码,而是进行十六进制解码,请参阅 stackoverflow.com/questions/321370/…,它将您的值映射到 16 个字节。顺便说一句:在 OpenSSL 中,key 和 IV 也可以显式指定,参见 -K、-iv 选项、openssl.org/docs/man1.1.1/man1/openssl-enc.html。如果使用密码,出于安全原因,还应使用盐。在 C# 代码中,密钥和 IV 将从密码/盐派生(而不是直接指定)。
  • 谢谢@Topaco!这正是问题所在,我将字符串转换为二进制而不是十六进制字符串转换为二进制。对于任何想知道的人,这就是我转换为字节的方式:stackoverflow.com/questions/321370/…

标签: c# encryption openssl aes


【解决方案1】:

如果以后有人发现这个,@Topaco 在 cmets 中发布了答案。解决办法是改变

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

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

使用来自How can I convert a hex string to a byte array?的StringToByteArrayFastest()

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-16
    • 1970-01-01
    • 2020-02-12
    • 2013-08-12
    • 2013-08-11
    • 1970-01-01
    • 2020-04-28
    相关资源
    最近更新 更多