C# 三重 DES 包装器问题 : TransformFinalBlock throws 'Bad data'

标签 c# asp.net

我在 C# 中有一个三重 DES 包装器,它由两个静态函数组成,EncryptDecrypt。有时,Decrypt 会因 TransformFinalBlock(..., ...) 抛出错误“Bad data”而失败。

  • 为什么会这样?
  • 解决方案是什么?

提前致谢。

public static string Encrypt(string toencrypt, string key, bool usehashing = true)
{
    byte[] keyArray;
    byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toencrypt);
    byte[] resultArray;

    //If hashing use get hashcode regards to your key
    if (usehashing)
    {
        MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
        keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));

        //Always release the resources and flush data
        // of the Cryptographic service provide. Best Practice
        hashmd5.Clear();
    }
    else
        keyArray = UTF8Encoding.UTF8.GetBytes(key);

    TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();

    //set the secret key for the tripleDES algorithm
    tdes.Key = keyArray;

    //mode of operation. there are other 4 modes.
    //We choose ECB(Electronic code Book)
    tdes.Mode = CipherMode.ECB;

    //padding mode(if any extra byte added)
    tdes.Padding = PaddingMode.PKCS7;

    ICryptoTransform cTransform = tdes.CreateEncryptor();

    try
    {
        //transform the specified region of bytes array to resultArray
        resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
    }
    catch (System.Exception ex)
    {
        //Release resources held by TripleDes Encryptor
        tdes.Clear();
        return "";
    }

    //Release resources held by TripleDes Encryptor
    tdes.Clear();

    //Return the encrypted data into unreadable string format
    return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}

public static string Decrypt(string todecrypt, string key, bool usehashing = true)
{
    byte[] keyArray;
    byte[] toEncryptArray;
    byte[] resultArray;
    //get the byte code of the string

    try
    {
        toEncryptArray = Convert.FromBase64String(todecrypt.Replace(" ", "+"));//The replace happens only when spaces exist in the string (hence not a Base64 string in the first place).
    }
    catch (System.Exception ex)
    {
        return "";
    }

    if (usehashing)
    {
        //if hashing was used get the hash code with regards to your key
        MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
        keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));

        //release any resource held by the MD5CryptoServiceProvider
        hashmd5.Clear();
    }
    else
    {
        //if hashing was not implemented get the byte code of the key
        keyArray = UTF8Encoding.UTF8.GetBytes(key);
    }

    TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();

    //set the secret key for the tripleDES algorithm
    tdes.Key = keyArray;

    //mode of operation. there are other 4 modes. 
    //We choose ECB(Electronic code Book)
    tdes.Mode = CipherMode.ECB;

    //padding mode(if any extra byte added)
    tdes.Padding = PaddingMode.PKCS7;

    ICryptoTransform cTransform = tdes.CreateDecryptor();

    try
    {
        resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
    }
    catch (System.Exception ex)
    {
        //Release resources held by TripleDes Encryptor                
        tdes.Clear();
        return "";
    }

    //Release resources held by TripleDes Encryptor                
    tdes.Clear();

    //return the Clear decrypted TEXT
    return UTF8Encoding.UTF8.GetString(resultArray);
}

加密后导致 Decrypt 失败的示例字符串是:

AgAAAA*AQAAAA*aAAAAA*jfgGTw*nY+sHZ2PrBmdj6wVnY+sEZ2PrA2dj6wFk4GhCJOHoQqdj6x9nY+seQ*trIBAA*AAMAAA**+L7PHiJ76M8OTV4BjXCkuDgDG2u7AcW87p1KU7KTSCKI3fYTnYAcGk1gyS62AvZO4g1FrsVbzoAnsX9Y0Ju+V9YjaYr9+ Xr+pen4SEas0NjRvntv0gqU0QZOj9bjKXx1Izc9Dw1HCUqjUGBcwakQo6kBlvb2v2/pV9dM4B3RM6m7rmaW79CSc7CC3DQjnqA5HMHC5k65pOK0KT76MzTawYQotNOk0BabTO3HpVcI8BNNjSsIP7TvtxXBmbc6TfXahw1zLTvC4iTSPnsgz0jhxvHhHD+N0cblfQhAK/nt2IZQuWGL3jW0oPpPJnjhGMWQPDLXbNwp23WUv8GXIPKevXbushYKjutmsdqJT7C1mcB45XhbYCVUVbLIja1AV831YeHqqke2msSaisg37UM+urL9EFIueUHZgZryhQUSjAhZDiHXqosoQou92RqbTK5YTqYY+zyBBzRt2r7KS3v5u9smtWMNk8Xcn42a6pFFxd6g4u0/s/SVm7NFb2UbREvp75lBVxEQv5IIznPSHfDnLtuX8pLfrZ/AVQ+gM9AGvzBjHGNYDQJ6VhgkHOZMeuLISJXjfGX0ZPFYKd+CPObpbFlukOSlIB5epRDnuggTLnthpN06Kle+iDqz1Q96ty4mfzwuhRwxvQ7EMzTykHXxC8p9bLKMr86K/vart2D9w1g9RtyS+pekgW8lkutWWGdu1eZml/5abNmlW5VgSJiuA9Yyrd2UNjUl6/a0oMKHPk6b2gZkpmENpO7auC9HA2gO

但是大多数字符串不会导致它失败。我猜这一定与特殊字符有关。

最佳答案

首先,请提供生成失败加密 block 的初始未加密 key 和字符串。然后我们可能有更好的机会找出问题的原因。但是,根据要求,我在您的代码中看到了一些潜在的陷阱,主要与不处理实现 IDisposable 的类型有关。这是考虑到这一点的代码的小重构(以及其他一些小的调整):

    public static string Encrypt(string toencrypt, string key, bool usehashing = true)
    {
        byte[] keyArray;

        // If hashing use get hash code regards to your key
        if (usehashing)
        {
            using (var hashmd5 = new MD5CryptoServiceProvider())
            {
                keyArray = hashmd5.ComputeHash(Encoding.UTF8.GetBytes(key));
            }
        }
        else
        {
            keyArray = Encoding.UTF8.GetBytes(key);
        }

        // set the secret key for the tripleDES algorithm
        // mode of operation. there are other 4 modes.
        // We choose ECB(Electronic code Book)
        // padding mode(if any extra byte added)
        using (var tdes = new TripleDESCryptoServiceProvider
        {
            Key = keyArray,
            Mode = CipherMode.ECB,
            Padding = PaddingMode.PKCS7
        })
        using (var transform = tdes.CreateEncryptor())
        {
            try
            {
                var toEncryptArray = Encoding.UTF8.GetBytes(toencrypt);

                // transform the specified region of bytes array to resultArray
                var resultArray = transform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

                // Return the encrypted data into unreadable string format
                return Convert.ToBase64String(resultArray, 0, resultArray.Length);
            }
            catch (Exception)
            {
                return string.Empty;
            }
        }
    }

    public static string Decrypt(string todecrypt, string key, bool usehashing = true)
    {
        byte[] toEncryptArray;

        // get the byte code of the string
        try
        {
            toEncryptArray = Convert.FromBase64String(todecrypt.Replace(" ", "+")); // The replace happens only when spaces exist in the string (hence not a Base64 string in the first place).
        }
        catch (Exception)
        {
            return string.Empty;
        }

        byte[] keyArray;

        if (usehashing)
        {
            // if hashing was used get the hash code with regards to your key
            using (var hashmd5 = new MD5CryptoServiceProvider())
            {
                keyArray = hashmd5.ComputeHash(Encoding.UTF8.GetBytes(key));
            }
        }
        else
        {
            // if hashing was not implemented get the byte code of the key
            keyArray = Encoding.UTF8.GetBytes(key);
        }

        // set the secret key for the tripleDES algorithm
        // mode of operation. there are other 4 modes. 
        // We choose ECB(Electronic code Book)
        // padding mode(if any extra byte added)
        using (var tdes = new TripleDESCryptoServiceProvider
        {
            Key = keyArray,
            Mode = CipherMode.ECB,
            Padding = PaddingMode.PKCS7
        })
        using (var transform = tdes.CreateDecryptor())
        {
            try
            {
                var resultArray = transform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

                // return the Clear decrypted TEXT
                return Encoding.UTF8.GetString(resultArray);
            }
            catch (Exception)
            {
                return string.Empty;
            }
        }
    }

关于C# 三重 DES 包装器问题 : TransformFinalBlock throws 'Bad data' ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11687214/

相关文章:

c# - 如何在开发环境中跳过设置Azure KeyVault?

asp.net - css帮助,用div显示图像

javascript - jQuery Accordion 不起作用

c# - MonoTouch - 创建一个在单个标签中同时包含粗体和纯文本的 UILabel

c# - MVVM 绑定(bind)双击到使用 telerik radtreecontrol 的方法

c# - 为我没有设置为 null 的对象释放内存

c# - 来自阵列的随机图像而不重复

c# - 带有 ASP.NET Web 应用程序的 Bluemix 服务

C# 使用多行发送 Outlook 电子邮件

asp.net - 如何确认异步 EF6 wait db.SaveChangesAsync() 是否按预期工作?