简体   繁体   中英

C# triple DES wrapper problems: TransformFinalBlock throws 'Bad data'

I have a triple DES wrapper in C# that consists of two static functions, Encrypt and Decrypt . Occasionally, Decrypt fails with TransformFinalBlock(..., ...) throwing the error 'Bad data'.

  • Why is this happening?
  • What's the solution?

Thanks in advance.

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);
}

An example string that once encrypted causes Decrypt to fail would be:

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

However most strings do not cause it to fail. This must be something to do with special characters I'm guessing.

First, please provide the initial unencrypted key and string which generates that encrypted block that fails. Then we may have a better chance of figuring out why there's an issue. However, that being requested, I see a few potential pitfalls in your code, mostly related to not disposing of types which implement IDisposable . Here's a small refactoring of the code which takes that into account (amongst a few other small adjustments):

    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;
            }
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM