tags:

views:

478

answers:

3

I have the following code to encrypt a value (listed below). Now I would like to write a bool isEncrypted() method. Is there a fool proof and reliable way to check if a value has been encrypted using this function. I have the decrypt routine and can control the pass phrase, but not sure if that will help.

The reason is - when the app first runs, values in a configuration file are not encrypted, in this case the app should auto encrypt these values. On 2nd run I don't want to encrypt again because obviously that would cause havoc. Lastly I don't want to have to add an isEncrypted attribute to the config value. I want it to work and look as dynamic as possible.

So far I am leaning towards using the len (128) as deciding factor, but there is always a remote chance of the unencrypted value also being this length.

Thanks in advance.

public static string encrypt(string text)
    {
        // Locals
        var passphrase = "5ab394ed-3920-4932-8d70-9c1b08f4ba4e";
        byte[] results;
        var utf8 = new UTF8Encoding();

        // Step 1. We hash the passphrase using MD5
        // We use the MD5 hash generator as the result is a 128 bit byte array
        // which is a valid length for the TripleDES encoder we use below
        var hashProvider = new MD5CryptoServiceProvider();
        var tdesKey = hashProvider.ComputeHash(utf8.GetBytes(passphrase));

        // Step 2. Create a new TripleDESCryptoServiceProvider object
        // Step 3. Setup the encoder
        var tdesAlgorithm = new TripleDESCryptoServiceProvider
        {
            Key = tdesKey,
            Mode = CipherMode.ECB,
            Padding = PaddingMode.PKCS7
        };

        // Step 4. Convert the input string to a byte[]
        var dataToEncrypt = utf8.GetBytes(text);

        // Step 5. Attempt to encrypt the string
        try
        {
            var encryptor = tdesAlgorithm.CreateEncryptor();
            results = encryptor.TransformFinalBlock(dataToEncrypt, 0, dataToEncrypt.Length);
        }
        finally
        {
            // Clear the TripleDes and Hashprovider services of any sensitive information
            tdesAlgorithm.Clear();
            hashProvider.Clear();
        }

        // Step 6. Return the encrypted string as a base64 encoded string
        return Convert.ToBase64String(results);
    }
+2  A: 

What you could do in the isEncrypted method is to try to decrypt the message.
Since you are using PKCS7 padding most likely an unencrypted message will fail to decrypt since the padding does not conform to the set padding mode.

The decryption will throw an exception and you'll have to catch this and return false in this case.

There is a remote chance that the decryption will go through (when the message is not encrypted) if the data conforms to the padding mode. This is however most unlikely.

What I would do in this case would be to add some kind of flag in the encrypted data or append some data to encrypted message since I can then remove it in the decryption. This would be the most foolproof way.

Sani Huttunen
I like your suggestion. Thanks
JL
+1  A: 

As your function returns a string there's no reason you can't add a plaintext code to the beginning of the encrypted data that the IsEncrypted function can look for, say "MD5ENC"+ [ciphertext].

The disadvantage of this is that it will let anyone who has the raw string know what algorithm was used for encryption. But as we keep getting reminded security through obscurity is no security at all. Anyone should be allowed to know how something was encrypted and have no easy way of breaking that encryption.

Note my use of the word should.

Anyhow, to return to my original suggestion. The advantage of this is that the longer your introductory code on the string the more vanishingly tiny the chances of it being generated by accident in another unrelated Base64 encrypted string becomes.

Should the ciphertext need decrypting just snip off your standard length encryption ident code and away you go...

+3  A: 

First, as a serious issue, it's an exceedingly poor idea to use cryptographic primitives on your own. You've chosen to use the Electronic Codebook mode of encryption, which has the property that identical plaintext blocks produce identical cyphertext blocks. Check out the example at Wikipedia.

That said, a simple solution is to prepend a token such as 'ENC:' to the encrypted password. If you need to worry about malicious tampering with the config file, you should proceed to use a message authentication code, such as HMAC.

inklesspen
In this case the size of the plaintext is less than the block size so something like CBC would not be much better.
Sani Huttunen
+1, you're not wrong, but I need something mid level. All other ways to give excellent encryption required an enormous amount of effort. So I've settled for something that's usable and transferable to different systems, and cheap to implement, I know I'll get flamed for this, but time is money, and there is never enough of both.
JL