我从Ruby中提供的示例开始:
cipher = OpenSSL::Cipher::AES.new(128, :CBC)
cipher.encrypt
cipher.key = "wB\x14=\r\xC3\xC1\x84$\x10\xCE\xC0\x10\x03\xFE\x18"
cipher.iv = "\xD8a\"\xFAs\xBD\xE4\xF9\xA4\xA1\x1E\xA5l\xA6@\xFD"
尝试在c#中复制:
string AesKey = "wB\x14=\r\xC3\xC1\x84$\x10\xCE\xC0\x10\x03\xFE\x18";
string AesIV = "\xD8a\"\xFAs\xBD\xE4\xF9\xA4\xA1\x1E\xA5l\xA6@\xFD";
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.BlockSize = 128;
aes.KeySize = 128;
aes.IV = Encoding.UTF8.GetBytes(AesIV);
aes.Key = Encoding.UTF8.GetBytes(AesKey);
aes.Mode = CipherMode.CBC;
byte[] src = Encoding.Unicode.GetBytes(text);
using (ICryptoTransform encrypt = aes.CreateEncryptor())
{
byte[] dest = encrypt.TransformFinalBlock(src, 0, src.Length);
string EncryptedResult = Convert.ToBase64String(dest);
EncryptedValue.Text = EncryptedResult;
}
我收到了错误:
“指定的初始化向量(IV)与此算法的块大小不匹配。”
我是否误解了原始密钥的格式以及我未能解释的iv值?
答案 0 :(得分:1)
Ruby和C#字符串不同,因此您的C#IV会在其中添加额外的字节。
在Ruby中,字符串实际上只是一个字节序列。每个\x
后跟两个十六进制数字。因此,\xD8a
实际上是字节0xD8 0x61的文本表示。当这个"字符串"时,不需要字符编码。用作初始化向量;它已经是伪装成文本的字节序列。
在C#中,字符串是一系列字符。要将字符串转换为字节数组,请使用字符编码 - 在这种情况下,您选择了UTF-8。为了表示数百万个不同的字符,在C#中,每个\x
escape后跟1到4个十六进制数字。因此,例如,子串\xD8a
不代表两个字节,而是单个字符ඊ
(U + 0D8A),当您使用UTF-8对其进行编码时,它会转换为3字节序列0xE0 0xB6 0x8A而不是两字节0xD8 0x61 Ruby等效。
如果您需要可打印的表单,可以对IV进行base-64编码。或者你可以用C#编写一个字节数组文字:
aes.IV = new byte[] { 0xD8, 0x61, ... };
然而,这一点可能没有实际意义,因为真正的应用程序需要安全性,硬编码的IV不安全。
答案 1 :(得分:0)
确保使用相同的填充技术,例如PKCS5填充或仅使用纯零。几个星期前我在php / java / c#中遇到了这个问题,而这是造成这个问题的填充。
数据存储在块中,最后一个块通常不会是其他块的确切大小,因此必须填充它的末尾以使其成为正确的块大小。在C#中你可以很容易地设置它,但在ruby中你可能需要自己编写代码来附加填充。
编辑:看起来Ruby默认使用PKCS5似乎是here,所以只需在C#中设置填充,看看会发生什么。
aes.Padding = PaddingMode.PKCS5;
在将数据交给算法之前,还要尝试对数据进行base64编码,然后对解密方法中获得的数据进行base64解码。我也必须这样做,否则来自解密的数据有时会被破坏。
我还建议使用256位密钥,因为它更安全,并且与128位密钥一样易于使用。