0

使用 TripleDESCryptoServiceProvider 解密数据时遇到问题。问题是解密后的值除了原始值之外还包含一些额外的奇怪字符

例如,如果我提供要加密的“rastko”,我稍后会得到类似“rastko⥊㮶”的解密。对于其他值,它可能是不同数量的“虚拟”字符,或者在某些情况下我会得到确切的值。

然后,我看到所有加密数据的字节数组大小都可以被 8 整除。看起来任何提供的数据都是在可以被 8 整除的值上四舍五入的。只有在原始编码值可以被 8 整除的情况下,解密才会检索到适当的值.

以下是我正在使用的方法:

        public static byte[] EncryptPassword(string password, out byte[] cryptoKey, out byte[] cryptoIV)
    {
        try
        {
            UnicodeEncoding unicodeEncoding = new UnicodeEncoding();
            byte[] unicodePassword = unicodeEncoding.GetBytes(password);
            byte[] encryptedPassword;

            using (TripleDESCryptoServiceProvider tripleDes = new TripleDESCryptoServiceProvider())
            {
                tripleDes.Key = GetCryptoKey();
                tripleDes.Mode = CipherMode.CBC;
                tripleDes.Padding = PaddingMode.PKCS7;
                cryptoKey = tripleDes.Key;
                cryptoIV = tripleDes.IV;

                using (MemoryStream memoryStream = new MemoryStream())
                {
                    ICryptoTransform cryptoTransform = tripleDes.CreateEncryptor();

                    using (
                        CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write))
                    {
                        cryptoStream.Write(unicodePassword, 0, unicodePassword.Length);
                        ////cryptoStream.FlushFinalBlock();
                    }

                    encryptedPassword = memoryStream.ToArray();
                }
            }

            return encryptedPassword;
        }
        catch (Exception ex)
        {
            throw new Exception("Password encryption failed !", ex);
        }
    }

    public static string DecryptPassword(byte[] encryptedPassword, byte[] cryptoKey, byte[] cryptoIV)
    {
        try
        {
            UnicodeEncoding unicodeEncoding = new UnicodeEncoding();
            string readablePassword;

            using (TripleDESCryptoServiceProvider tripleDes = new TripleDESCryptoServiceProvider())
            {
                tripleDes.Key = cryptoKey;
                tripleDes.IV = cryptoIV;
                tripleDes.Mode = CipherMode.CBC;
                tripleDes.Padding = PaddingMode.PKCS7;

                // Create a new MemoryStream using the passed 
                // array of encrypted data.
                using (MemoryStream memoryStream = new MemoryStream(encryptedPassword))
                {
                    // Create crypto transform that defines the basic operations of cryptographic transformations.
                    ICryptoTransform cryptoTransform = tripleDes.CreateDecryptor();

                    // Create a CryptoStream using the MemoryStream and the passed key and initialization vector (IV).
                    using (CryptoStream decryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write))
                    {
                        decryptoStream.Write(encryptedPassword, 0, encryptedPassword.Length);
                        ///decryptoStream.FlushFinalBlock();
                    }

                    byte[] decryptedPassword = memoryStream.ToArray();

                    //Convert the buffer into a string and return it.
                    readablePassword = unicodeEncoding.GetString(decryptedPassword, 0, decryptedPassword.Length);
                }
            }

            return readablePassword;
        }
        catch (Exception ex)
        {
            throw new Exception("Password decryption failed !", ex);
        }
    }

    private static byte[] GetCryptoKey()
    {
        UnicodeEncoding unicodeEncoding = new UnicodeEncoding();
        string plainKey = "rastkoisajev2310982josipasenera153";
        byte[] encodedKey = unicodeEncoding.GetBytes(plainKey);

        // Prepares 192 bit key
        byte[] preparedKey = new byte[24];
        Array.Copy(encodedKey, preparedKey, 24);

        return preparedKey;
    }

这是示例测试调用:

       private static void CryptoTest()
    {
        string password = "rastko";

        byte[] cryptoKey;
        byte[] cryptoIV;

        byte[] encryptedPassword = Crypto.EncryptPassword(password, out cryptoKey, out cryptoIV);

        string decryptedPAssword = Crypto.DecryptPassword(encryptedPassword, cryptoKey, cryptoIV);
    }

我没有很好的安全经验。我看到的是 IV 向量是 8 字节大小,我发现它与 BlockSize 相关,比 IV 大小大 8 倍。IV 向量的 TripleDESCryptoServiceProvider 使用 8 字节值。我无法改变这一点。

你能告诉我我必须做什么还是我写错了什么?

4

3 回答 3

1

DES 是一个 64 位的块密码。任何不能完全划分为 64 位(=8 字节)块的文本都需要填充以构成整数块。您需要为加密和解密设置填充。如果您可以控制两端,则使用 PKCS#5 填充来加密和解密。如果您只能控制解密端,那么请询问加密端他们正在使用什么填充并期望得到。

于 2012-08-05T17:06:51.163 回答
0

请注意,加密密码通常不是可行的方法。请改用PBKDF2。不要混淆密码和密钥!

尝试确保您的 CryptoStreams 被关闭或刷新:

http://msdn.microsoft.com/en-us/library/system.security.cryptography.cryptostream.flushfinalblock.aspx

如果你不这样做,那么填充/取消填充可能不会被执行,而是你会得到垃圾。

于 2012-08-05T15:59:56.757 回答
0

经过详细调查,我找到了解决问题的方法。我改变了一点解密逻辑。

而不是 DecryptPassword 方法中的这一部分:

 // Create a CryptoStream using the MemoryStream and the passed key and initialization vector (IV).
                using (CryptoStream decryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write))
                {
                    decryptoStream.Write(encryptedPassword, 0, encryptedPassword.Length);
                    ///decryptoStream.FlushFinalBlock();
                }

                byte[] decryptedPassword = memoryStream.ToArray();

                //Convert the buffer into a string and return it.
                readablePassword = unicodeEncoding.GetString(decryptedPassword, 0, decryptedPassword.Length);
            }

我现在使用 CryptoStream 中的读取逻辑,然后我只是删除可空字符。现在是这样的:

                        // Create a CryptoStream using the MemoryStream and the passed key and initialization vector (IV).
                    using (CryptoStream decryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Read))
                    {
                        // Create buffer to hold the decrypted data.
                        byte[] fromEncrypt = new byte[encryptedPassword.Length];

                        decryptoStream.Read(fromEncrypt, 0, fromEncrypt.Length);

                        //Convert the buffer into a string and return it.
                        readablePassword = unicodeEncoding.GetString(fromEncrypt);
                        readablePassword = readablePassword.Replace("\0", string.Empty);
                    }

这对我来说非常有效!谢谢大家的时间。

于 2012-08-06T14:37:53.463 回答