在我的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 解密同一个文件。 首先,我需要获取算法参数,并且由于上面的代码有效,我修改它以给我这些信息:
添加一些代码:
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返回。
答案 0 :(得分:1)
为什么openssl这么说?
OpenSSL使用它自己的名为EVP_BytesToKey的密钥派生例程,该例程需要一个盐。这个盐的前缀为8字节魔术:ASCII码编码Salted__
。密码不应该直接用作密钥,因此OpenSSL首先将它们转换为密钥。
您可以使用-K然后使用字符串的十六进制表示来提供密钥(请继续阅读以进行编码)。您还需要提供IV(在您的情况下为相同的字节)。
由于C#字符串是以UTF-16编码的(因此在字符中为16位),而密钥是
"h3y_gUyZ"
,它们是8个字符,所以密钥不应该是16 x 8 = 128位宽而不是256rijndaelManaged.KeySize
返回?
是的,可能您在使用密钥初始化之前向Rijndael类询问密钥大小。请注意,.NET使用UTF-16LE(little-endian),因为整个生态系统都是(愚蠢的)小端。
PKCS#7是包含填充方案的标准。它既被.NET和OpenSSL使用,所以很好。由于ECB和CBC模式要求密码的输入大小是密码的块大小的N倍,因此是必需的。因此,PKCS#7将{1}的{1}增加到\x01
,增加1到16个字节(AES的块大小)。 Unpadding删除了这些。