2

我正在尝试使用 Rijndael 或 Aes 和下面的代码来加密/解密字符串。

public class Crypto
{
    private const string defaultVector = "asdfg123456789";
    private const CipherMode cipherMode = CipherMode.CBC;
    //Have tried PaddingMode.ISO10126, PaddingMode.None, and PaddingMode.PKCS7
    private const PaddingMode paddingMode = PaddingMode.ISO10126;
    private const int iterations = 2;
    private static Rijndael GetCrypto(string passphrase)
    {
        var crypt = Rijndael.Create();
        crypt.Mode = cipherMode;
        crypt.Padding = paddingMode;
        crypt.BlockSize = 256;
        crypt.KeySize = 256;
        crypt.Key =
            new Rfc2898DeriveBytes(passphrase, Encoding.Unicode.GetBytes(defaultVector), iterations).GetBytes(32);
        crypt.IV = new Rfc2898DeriveBytes(passphrase, Encoding.Unicode.GetBytes(defaultVector), iterations).GetBytes(32);
        return crypt;
    }
    public static string Encrypt(string plainText, string passphrase)
    {
        byte[] clearData = Encoding.Unicode.GetBytes(plainText);
        byte[] encryptedData;
        var crypt = GetCrypto(passphrase);
        using (var ms = new MemoryStream())
        {
            using (var cs = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cs.Write(clearData, 0, clearData.Length);
                //cs.FlushFinalBlock(); //Have tried this active and commented with no change.
            }
            encryptedData = ms.ToArray();
        }
        //Changed per Xint0's answer.
        return Convert.ToBase64String(encryptedData);
    }
    public static string Decrypt(string cipherText, string passphrase)
    {
        //Changed per Xint0's answer.
        byte[] encryptedData = Convert.FromBase64String(cipherText);
        byte[] clearData;
        var crypt = GetCrypto(passphrase);
        using (var ms = new MemoryStream())
        {
                using (var cs = new CryptoStream(ms, crypt.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(encryptedData, 0, encryptedData.Length);
                    //I have tried adding a cs.FlushFinalBlock(); here as well.
                }
                clearData = ms.ToArray();
        }
        return Encoding.Unicode.GetString(clearData);
    }
}

//编辑:我已经根据下面Xint0的答案更改了对Convert.ToBase64String的Unicode调用。

在 cs.Write in Decrypt 方法中,我收到“填充无效且无法删除”的错误消息。

我尝试将填充设置为 PaddingMode.None 但我得到“要加密的数据长度无效”。在 Encrypt 方法中的 cs.Write 上。

我看过这些,他们所说的似乎没有任何效果。

填充无效且无法移除

填充无效,无法删除?

堆栈跟踪显示 System.Security.CryptographicException 来自 RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast)。

4

3 回答 3

3

我花了很多时间来寻找导致CryptographicException的原因,我也在谷歌上搜索,包括 Stackoverflow。
这是一个愚蠢的错误(在使用复制粘贴编程时经常出现),如下所示:

它从CryptoStream的实例中抛出方法FlushFinalBlock()

查看错误代码:

CryptoStream cs = new CryptoStream(ms, rj.CreateDecryptor(rj.Key, rj.IV), CryptoStreamMode.Write);

我用它来加密所以你可以看到CryptoStreamMode。但在同一指令中,我正在创建解密器而不是加密器(请参阅构造函数中的第二个参数)。

小心检查,以免浪费您宝贵的时间;)

问候
布罗内克

于 2012-07-13T16:38:10.993 回答
2

我看到两个问题:

  1. 在调用ms.ToArray(). 将其更改为:

    ...
    using (var cs = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write))
    {
        cs.Write(clearData, 0, clearData.Length);
        cs.FlushFinalBlock();
        cs.Close();
    }
    
    ms.Close();
    encryptedData = ms.ToArray();
    ...
    
  2. Encrypt结果字节数组encryptedData不是Unicode字符串,但您正在使用 Unicode 编码器从字节数组中获取字符串。而不是使用System.Convert.ToBase64String()inEncryptSystem.Convert.FromBase64String()in Decrypt

Encrypt做:

return System.Convert.ToBase64String(encryptedData);

Decrypt做:

byte[] encryptedData = System.Convert.FromBase64String(cipherText);

编辑

最大的问题是返回值Encrypt。加密 Unicode 字符串的字节表示的结果不是Unicode 字符串的字节表示。您不应使用encryptedDatawith的值Encoding.Unicode.GetString()来获取加密数据的字符串表示形式。用于System.Convert.ToBase64String()获取加密数据的字符串表示形式。请参阅编码类MSDN 文档中的备注部分。

编辑 2

请注意,Rijndael 不完全是 AES,如果您与 AES 互操作,则块大小应始终为 128 位,与密钥大小无关。有关详细信息,您可以在此处阅读。

于 2012-03-05T22:43:45.847 回答
0

我有一个类似的问题,解密方法的问题是初始化一个空的内存流。当我用这样的密文字节数组初始化它时它起作用了:

MemoryStream ms = new MemoryStream(cipherText);
于 2015-02-02T12:14:53.740 回答