openssl返回Bad Magic Number

时间:2017-01-04 23:23:06

标签: c# encryption openssl aes rijndaelmanaged

在我的Linux机器上,我有一个二进制AES加密文件:

head -c 100 Leela_Turanga.plr
�|�XѨ��>��c��N�Ώڤ�LW�M��t�p5=c.4���ᑸ�#Owl����M�d��>�ٷa�L�r|��ć�ڐ,��:����#�����\

我也知道该文件已使用密码加密:

h3y_gUyZ

我可以使用.NET的RijndaelManaged类在以下例程中解密此文件:

public static bool decryptFile(string inputFile, string outputFile)
    {
        string s = "h3y_gUyZ";
        UnicodeEncoding unicodeEncoding = new UnicodeEncoding();
        byte[] bytes = unicodeEncoding.GetBytes(s);
        FileStream fileStream = new FileStream(inputFile, FileMode.Open);
        RijndaelManaged rijndaelManaged = new RijndaelManaged();
        CryptoStream cryptoStream = new CryptoStream(fileStream, rijndaelManaged.CreateDecryptor(bytes, bytes), CryptoStreamMode.Read);
        FileStream fileStream2 = new FileStream(outputFile, FileMode.Create);
        try
        {
            int num;
            while ((num = cryptoStream.ReadByte()) != -1)
            {
            fileStream2.WriteByte((byte)num);
            }
            fileStream2.Close();
            cryptoStream.Close();
            fileStream.Close();
        }
        catch
        {
            fileStream2.Close();
            fileStream.Close();
            File.Delete(outputFile);
            return true;
        }
            return false;
    }

因为在Linux上我把这个代码嵌入到一个c#程序中,我用 mono 运行后,用mcs编译它。

mcs *.cs -out:mybinary.exe
mono mybinary.exe d Leela_Turanga.plr outputfile.dat

d 参数执行上述功能时, Leela_Turanga.plr 是要解密的文件, outputfile.dat 是生成的解密文件。 这工作正常:我可以正确解密文件,我可以这样说,因为人类可读文本出现在解密文件中。 现在我想用 openssl 解密同一个文件。 首先,我需要获取算法参数,并且由于上面的代码有效,我修改它以给我这些信息:

  • 密钥大小
  • AES操作模式(cbc,ecb,pcbc,cfb ...)
  • 填充(不知道那是什么)

添加一些代码:

public static bool decryptFile(string inputFile, string outputFile)
    {
        string s = "h3y_gUyZ";
        UnicodeEncoding unicodeEncoding = new UnicodeEncoding();
        byte[] bytes = unicodeEncoding.GetBytes(s);
        FileStream fileStream = new FileStream(inputFile, FileMode.Open);
        RijndaelManaged rijndaelManaged = new RijndaelManaged();
        CryptoStream cryptoStream = new CryptoStream(fileStream, rijndaelManaged.CreateDecryptor(bytes, bytes), CryptoStreamMode.Read);
        FileStream fileStream2 = new FileStream(outputFile, FileMode.Create);


        //=======DEBUG INFO=======
        //PRINT ALGORITHM SETTINGS
        Console.WriteLine(rijndaelManaged.Mode);    //what AES mode are we using?
        Console.WriteLine(rijndaelManaged.KeySize); //what is the keysize?
        Console.WriteLine(rijndaelManaged.Padding); //what is the padding?
        //========================


        try
        {
            int num;
            while ((num = cryptoStream.ReadByte()) != -1)
            {
            fileStream2.WriteByte((byte)num);
            }
            fileStream2.Close();
            cryptoStream.Close();
            fileStream.Close();
        }
        catch
        {
            fileStream2.Close();
            fileStream.Close();
            File.Delete(outputFile);
            return true;
        }
            return false;
    }

它出现的是RijndaelManaged正在CBC模式下工作,具有256位密钥和PKCS7填充(再次不知道这是否重要)。 现在我可以尝试使用openssl来解密:

openssl enc -aes-256-cbc -d -in Leela_Turanga.plr -out out.bin

然后出现密码提示,我输入通行证,以及一个"坏幻数"错误被返回"

enter aes-256-cbc decryption password:
bad magic number

我没有解密文件。

为什么openssl这么说?我在互联网上搜索过,但我找不到答案。

此外: 因为在c#中字符串是以UTF-16编码的(因此在字符中是16位),而密钥是" h3y_gUyZ"哪个是8个字符,键不应该是16 x 8 = 128位宽?而不是256 rijndaelManaged.KeySize返回。

1 个答案:

答案 0 :(得分:1)

  

为什么openssl这么说?

OpenSSL使用它自己的名为EVP_BytesToKey的密钥派生例程,该例程需要一个盐。这个盐的前缀为8字节魔术:ASCII码编码Salted__。密码不应该直接用作密钥,因此OpenSSL首先将它们转换为密钥。

您可以使用-K然后使用字符串的十六进制表示来提供密钥(请继续阅读以进行编码)。您还需要提供IV(在您的情况下为相同的字节)。

  

由于C#字符串是以UTF-16编码的(因此在字符中为16位),而密钥是"h3y_gUyZ",它们是8个字符,所以密钥不应该是16 x 8 = 128位宽而不是256 rijndaelManaged.KeySize返回?

是的,可能您在使用密钥初始化之前向Rijndael类询问密钥大小。请注意,.NET使用UTF-16LE(little-endian),因为整个生态系统都是(愚蠢的)小端。

PKCS#7是包含填充方案的标准。它既被.NET和OpenSSL使用,所以很好。由于ECB和CBC模式要求密码的输入大小是密码的块大小的N倍,因此是必需的。因此,PKCS#7将{1}的{1}增加到\x01,增加1到16个字节(AES的块大小)。 Unpadding删除了这些。