0
votes

I am using symmetric TripleDES encryption from the class TripleDESCryptoServiceProvider (.Net 2.0) to encrypt the contents of a file. The data gets encrypted perfectly but during decryption it throws the CryptographyException: Bad data


I am using key from current date time and IV from the randomly generated value by .Net class. Then I pass the same key and IV to the decryption method but it fails for some reason.
Here is my code :

static void Main(string[] args){
    string fileName = "input.exe";
    string newFileName = fileName + "crypted.exe";
    byte[] iv;
    var fileToEncrypt = File.ReadAllBytes(fileName);
    var encryptionKey = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(DateTime.Now.ToString("ddMMyyHmmss")));
    File.WriteAllBytes(newFileName, EncryptTripleDES(fileToEncrypt, encryptionKey, out iv));
    File.WriteAllBytes(fileName + "decrypted.exe", DecryptTripleDES(File.ReadAllBytes(newFileName), encryptionKey,iv));
}

public static byte[] EncryptTripleDES(byte[] dataToEncrypt, byte[] key, out byte[] iv){
    byte[] result;
    var tdes = new TripleDESCryptoServiceProvider { Key = key, KeySize = 128, Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7 };
    iv = tdes.IV;
    using(ICryptoTransform cTransform = tdes.CreateEncryptor()){
        result = cTransform.TransformFinalBlock(dataToEncrypt, 0, dataToEncrypt.Length);
        tdes.Clear();
    }

    return result;
}

public static byte[] DecryptTripleDES(byte[] dataToDecrypt, byte[] key, byte[] iv){
    byte[] result;
    var tdes = new TripleDESCryptoServiceProvider { Key = key, KeySize = 128, Mode = CipherMode.CBC,IV = iv,Padding = PaddingMode.PKCS7 };

    using (ICryptoTransform cTransform = tdes.CreateDecryptor()){
        result = cTransform.TransformFinalBlock(dataToDecrypt, 0, dataToDecrypt.Length);
        tdes.Clear();
    }

    return result;
}



UPDATE:
1. I have checked the value of IV being passed is valid and same as used in encryption.
2. Changing the padding to zero or none doesn't raise the exception but then the data isn't decrypted correctly. It comes out to be different than original.

1
Note, that 3DES is about the worst algorithm you can choose, and that an attacker can modify your encrypted data without you noticing.usr
Yes I know. Using it for some secret reason :)Harsh Maurya
Using the MD5 sum of the current time is also a bad practice. Keys should be generated from a cryptographically secure random number generator and filtered against DES weak keys.initramfs
Well thanks again but currently I am just interested in the solution, I'll handle the good practices later, and my use case is slightly different where all these things doesn't matter anywaysHarsh Maurya
Check the returned IV of the EncryptTripleDES() function to make sure that the IV isn't being zeroed out by the Clear() function. If it is, you need to explicitly make a copy of the IV byte array at tdes.initramfs

1 Answers

1
votes

The problem is in the way that you're constructing the TripleDESCryptoServiceProviders using an initializer. The Key is set first in the initializer, but then you set the KeySize, which causes the Key to be reset to a new (randomly generated) key, as a result, you're encrypting and decrypting with different keys (neither of which are the key you generate).

You can fix this by re-ordering the initializer so that KeySize is set first, or perhaps move the setting of the Key outside the initializer entirely to avoid any ambiguity:

public static byte[] EncryptTripleDES(byte[] dataToEncrypt, byte[] key, out byte[] iv){
    byte[] result;
    var tdes = new TripleDESCryptoServiceProvider { KeySize = 128, Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7 };
    // Key explicitly set here, not in the initializer:
    tdes.Key = key;
    iv = tdes.IV;

    using(ICryptoTransform cTransform = tdes.CreateEncryptor()){
        result = cTransform.TransformFinalBlock(dataToEncrypt, 0, dataToEncrypt.Length);
        tdes.Clear();
    }

    return result;
}

public static byte[] DecryptTripleDES(byte[] dataToDecrypt, byte[] key, byte[] iv){
    byte[] result;
    var tdes = new TripleDESCryptoServiceProvider { KeySize = 128, Mode = CipherMode.CBC,IV = iv,Padding = PaddingMode.PKCS7 };
    // Key explicitly set here, not in the initializer:
    tdes.Key = key;

    using (ICryptoTransform cTransform = tdes.CreateDecryptor()){
        result = cTransform.TransformFinalBlock(dataToDecrypt, 0, dataToDecrypt.Length);
        tdes.Clear();
    }

    return result;
}