C#triple DES包装器问题:TransformFinalBlock抛出“错误数据”

时间:2012-07-27 11:51:01

标签: c# asp.net

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

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

提前致谢。

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

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

1 个答案:

答案 0 :(得分:0)

首先,请提供初始未加密密钥和字符串,该密钥和字符串会生成失败的加密块。然后我们可能有更好的机会弄清楚为什么会有问题。但是,在请求时,我发现代码中存在一些潜在的缺陷,主要与不处理实现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;
            }
        }
    }