首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Rijndael算法出错

Rijndael算法出错
EN

Stack Overflow用户
提问于 2017-04-03 13:14:46
回答 1查看 920关注 0票数 0

我找到了一篇文章:链接到msdn

我要做的是:加密Byte()数组,然后解密它。它可以工作,但解密的结果并不等于原始数组。地雷代码:

代码语言:javascript
复制
Dim RMCrypto As New RijndaelManaged()
RMCrypto.Key = Key
RMCrypto.IV = IV
RMCrypto.Padding = PaddingMode.Zeros

Dim dataToDecrypt As Byte() = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}

Dim encrypted As Byte() = Encrypt(dataToDecrypt, RMCrypto)
Dim roundtrip As Byte() = Decrypt(encrypted, RMCrypto)

哪里

代码语言:javascript
复制
Private Function Encrypt(ByVal plainText As Byte(), RMCrypto As RijndaelManaged) As Byte()

Dim encrypted() As Byte
Using RMCrypto
    ' Create a decrytor to perform the stream transform.
    Dim encryptor As ICryptoTransform = RMCrypto.CreateEncryptor(RMCrypto.Key, RMCrypto.IV)
    ' Create the streams used for encryption.
    Using msEncrypt As New MemoryStream()
        Using csEncrypt As New CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)
            Using swEncrypt As New StreamWriter(csEncrypt)

                'Write all data to the stream.
                swEncrypt.Write(plainText)
            End Using
            encrypted = msEncrypt.ToArray()
        End Using
    End Using
End Using

    ' Return the encrypted bytes from the memory stream.
    Return encrypted

End Function 'Encrypt

代码语言:javascript
复制
Private Function Decrypt(ByVal cipherText() As Byte, RMCrypto As RijndaelManaged) As Byte()
Dim plaintext As Byte()

Using RMCrypto 

' Create a decrytor to perform the stream transform.
Dim decryptor As ICryptoTransform = RMCrypto.CreateDecryptor(RMCrypto.Key, RMCrypto.IV)

' Create the streams used for decryption.
    Using msDecrypt As New MemoryStream(cipherText)
        Using csDecrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)
            Using srDecrypt As New StreamReader(csDecrypt)
                ' Read the decrypted bytes from the decrypting stream
                ' and place them in a string.
                plaintext = Encoding.UTF8.GetBytes(srDecrypt.ReadToEnd())
            End Using
        End Using
    End Using
End Using

Return plaintext

End Function 'Decrypt

它的工作原理:

代码语言:javascript
复制
Input: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
encrypted: 221 54 108 65 95 233 31 124 101 181 205 176 13 233 85 252
decrypted: 15 45 15 239 191 189 239 191 189 14 58 239 191 189 9 118 37 239 191 189 212 149 239 191 189 58

正如我们所看到的,加密看起来是正确的,但是解密是完全错误的--它甚至还有其他成员!

由于Decrypt函数中字符串到Byte()的转换不正确,它会在其中吗?还有一个有趣的时刻:decrypted改变了它的大小,每次都给出一个新的答案!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-04-03 15:36:27

好吧,真的你的代码有很多问题。

我的代码片段将使用C#,因为我已经超过15年没有编写VB了。虽然他们可以类似地阅读,但我不想最后给出无效的语法。

1)通过using释放对象,然后再使用它。

显然,对于RijndaelManaged来说,这只会使它回到“我从未被使用过的状态”,这将导致下一次使用时生成一个随机密钥和IV,这可能是您最大的问题。

因此,您的加密和解密方法应该删除对称算法对象(当前名为RMCrypto)的using语句。通常,对象的创建者拥有生命周期,有时生存期被传递给新对象;但是,生命周期几乎从未被您调用的方法终止。

2)你在使用RijndaelManaged。别。

您需要AES ( Rijndael的一种受限形式,但它的互操作要好得多)。您“可以”切换到AesManaged,但不应该使用Aes.Create() (一些Aes派生类型只在特定(特定版本)操作系统上工作)。Aes.Create()应该总是起作用的。

3)在MemoryStream完成之前,您正在阅读CryptoStream。

您对msEncrypt.ToArray()的调用在CryptoStream的using中,但是您希望它在外部。把这两行翻过来。

4)你在使用PaddingMode.Zeros。

AES (和Rijndael)是一种分组密码算法,块密码需要完整的块才能操作。当最后一个块有缺陷时,它就会得到“填充(https://en.wikipedia.org/wiki/Padding_(cryptography%29#Byte_padding))”来完成。PKCS7是“标准”填充模式,解密可以删除它(因为它有足够强的规则)。在解密过程中,还可以删除ANSI X.923和ISO 10126。零不能,因为“解加法器”不能判断零是实数零还是填充零。

5)您将变量命名为dataToDecrypt

你把它传递给加密,然后输出加密到解密。所以这就是data

6)您在解密中应用了UTF-8解码。

你的文本是从1到16的字节,那绝对不是UTF-8文本。

您使用的StreamReader/StreamWriter表明您试图对字符串执行加密。不要。加密/解密是对字节的。(除了像凯撒密码这样的新奇事物)。

总括而言:

代码语言:javascript
复制
// The using goes here, with the Create call. Not in anything it gets passed to.
using (Aes aes = Aes.Create())
{
    aes.Key = key;
    aes.IV = iv;
    // PKCS7 is the default padding mode,
    // if you don't like trusting defaults you can set it here.

    byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };

    byte[] encrypted = Encrypt(data, aes);
    byte[] roundtrip = Decrypt(encrypted, aes);
}

private static byte[] Encrypt(byte[] data, SymmetricAlgorithm alg)
{
    // You didn't have a using for this, but should have:
    using (ICryptoTransform encryptor = alg.CreateEncryptor())
    using (MemoryStream msEncrypt = new MemoryStream())
    {
        using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
        {
            csEncrypt.Write(data, 0, data.Length);
        }

        // Now that the CryptoStream has closed the data has been padded.
        return msEncrypt.ToArray();
    }
}

private static byte[] Decrypt(byte[] data, SymmetricAlgorithm alg)
{
    using (ICryptoTransform decryptor = alg.CreateDecryptor())
    using (MemoryStream msDecrypt = new MemoryStream())
    {
        // Just keep using this in write mode. All it does is say whether
        // You'll be explicitly loading data via Write, or implicitly via Read.
        using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write))
        {
            csDecrypt.Write(data, 0, data.Length);
        }

        // Now that the CryptoStream has closed the data has been de-padded.
        return msDecrypt.ToArray();
    }
}
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43185646

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档