加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 如果丢弃,PasswordDeriveBytes(System.Security.Cryptogra

发布时间:2020-12-15 21:31:35 所属栏目:百科 来源:网络整理
导读:在使用块中使用PasswordDeriveBytes类(因为它实现了IDisposable,它会处理它)会在第二次使用该类时产生问题.这是代码: public class AES{ protected static CryptoData localCryptoData; static AES() { localCryptoData = new CryptoData(); } public stati
在使用块中使用PasswordDeriveBytes类(因为它实现了IDisposable,它会处理它)会在第二次使用该类时产生问题.这是代码:

public class AES
{
    protected static CryptoData localCryptoData;

    static AES()
    {
        localCryptoData = new CryptoData();
    }

    public static string Encrypt(CryptoData cryptoData)
    {
        using (PasswordDeriveBytes pass = new PasswordDeriveBytes(cryptoData.Password,cryptoData.Salt,"SHA1",2))
        using (RijndaelManaged symmetricKey = new RijndaelManaged())
        {
            byte[] keyBytes = pass.GetBytes(cryptoData.KeySize / 8);
            symmetricKey.Padding = PaddingMode.PKCS7;
            symmetricKey.Mode = CipherMode.CBC;

            using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes,cryptoData.InitVector))
            using (MemoryStream memoryStream = new MemoryStream())
            using (CryptoStream cryptoStream = new CryptoStream(memoryStream,encryptor,CryptoStreamMode.Write))
            {
                cryptoStream.Write(cryptoData.ByteText,cryptoData.ByteText.Length);
                cryptoStream.FlushFinalBlock();
                return Convert.ToBase64String(memoryStream.ToArray());
            }
        }
    }

    public static string Decrypt(CryptoData cryptoData)
    {
        using (PasswordDeriveBytes pass = new PasswordDeriveBytes(cryptoData.Password,2))
        using (RijndaelManaged symmetricKey = new RijndaelManaged())
        {
            byte[] cipherTextBytes = Convert.FromBase64String(cryptoData.Text);
            byte[] keyBytes = pass.GetBytes(cryptoData.KeySize / 8);
            symmetricKey.Padding = PaddingMode.PKCS7;
            symmetricKey.Mode = CipherMode.CBC;

            using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes,cryptoData.InitVector))
            using (MemoryStream memoryStream = new MemoryStream(cipherTextBytes))
            using (CryptoStream cryptoStream = new CryptoStream(memoryStream,decryptor,CryptoStreamMode.Read))
            {
                byte[] textBytes = new byte[cipherTextBytes.Length];
                int count = cryptoStream.Read(textBytes,textBytes.Length); //throws CryptographicException - Padding is invalid and cannot be removed.
                return Encoding.UTF8.GetString(textBytes,count);
            }
        }
    }

如果以这种方式使用此类:

AES.Encrypt(cryptoData);
?AES.Decrypt(cryptoData);

首次使用会为您提供正确的AES加密字符串,但如果在尝试解密相同的字符串时失败并出现异常.问题在于,当通过字节数组给出此密码时,从PasswordDeriveBytes类中分配第一个参数(用于从中派生密钥的密码).如果它是一个字符串(由于过载),它可以正常工作.

助手CryptoData类:

public class CryptoData
{
    private string text;
    public string Text
    {
        get { return text; }
        set
        {
            text = value;

            if (value != null)
            {
                ByteText = Encoding.ASCII.GetBytes(value);
            }
            else
            {
                ByteText = null;
            }
        }
    }

    public byte[] ByteText { get; private set; }
    public byte[] Password { get; set; }
    public int KeySize { get; set; }
    public byte[] InitVector { get; set; }
    public byte[] Salt { get; set; }
}

如果您只是在方法中更改此行:

using (PasswordDeriveBytes pass = new PasswordDeriveBytes(cryptoData.Password,2))

using (PasswordDeriveBytes pass = new PasswordDeriveBytes("somePassword",2))

一切正常.问题是,由于using语句,PasswordDeriveBytes的实例在第二次使用时没有得到密码的字节数组.如果传递了一个字符串,而不是一个字节数组,它就可以工作.

编辑:仔细检查后,似乎密码参数的默认属性设置器中存在问题.它获取数组的指针,这就是它处理它的原因.它应该创建数组的value.clone(),就像salt数组的情况一样.这是一个明确的错误.

我是对的,还是我做错了什么?

编辑:

*使用此更改AES.Encrypt()和AES.Decrypt方法中的第一行,它可以工作:*

using (PasswordDeriveBytes pass = new PasswordDeriveBytes(
        (byte[])cryptoData.Password.Clone(),2))

解决方法

这当然是反直觉和无证的行为,尽管它是否是一个bug可能会被辩论.基本上,当您将密码字节数组传递给构造函数时,PasswordDeriveBytes实例将获得该数组的所有权.这类似于StreamReader获取传递给它的Stream的所有权的方式,并且当它被Disposed时将它Dispose它(此行为也是 criticized,基于类似的理由,这导致在StreamReader构造函数中添加一个布尔参数.NET 4.0,可以防止底层流被处置).

在传递之前克隆字节数组可能是您的最佳选择.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读