tags:

views:

658

answers:

4

I have this function I am using to decrypt values that works fine on my dev machine. But when run in production on another server - gives this exact error message :

The system cannot find the file specified.

Here is the function:

 public static string Decrypt(string stringToDecrypt, string key)
    {
        string result = null;

        if (string.IsNullOrEmpty(stringToDecrypt))
        {
            throw new ArgumentException("An empty string value cannot be encrypted.");
        }

        if (string.IsNullOrEmpty(key))
        {
            throw new ArgumentException("Cannot decrypt using an empty key. Please supply a decryption key.");
        }

        try
        {
            System.Security.Cryptography.CspParameters cspp = new System.Security.Cryptography.CspParameters();
            cspp.KeyContainerName = key;

            System.Security.Cryptography.RSACryptoServiceProvider rsa = new System.Security.Cryptography.RSACryptoServiceProvider(cspp);
            rsa.PersistKeyInCsp = true;

            string[] decryptArray = stringToDecrypt.Split(new string[] { "-" }, StringSplitOptions.None);
            byte[] decryptByteArray = Array.ConvertAll<string, byte>(decryptArray, (s => Convert.ToByte(byte.Parse(s, System.Globalization.NumberStyles.HexNumber))));


            byte[] bytes = rsa.Decrypt(decryptByteArray, true);

            result = System.Text.UTF8Encoding.UTF8.GetString(bytes);

        }
        finally
        {
            // no need for further processing
        }

        return result;
    }

Update

Guys, I originally went this route because after hours and hours of searching I got an answer on stackoverflow, that this method of encrypting / decrypting works purely on strings and no need to import / export keys.

So.... Now I am missing a key file? How is this possible I didn't even create a key file.

+1  A: 

Use FileMon from Sysinternals.com to see what file it's looking for?

My guess is that cspp.KeyContainerName = key; is the relevant line.

EricLaw -MSFT-
+1 for a good idea, however fileMon no longer exists, its been replaced by process explorer, really complicated to figure out, and I don't really have the time right this very minute.
JL
A: 

Well, did you install the key in the container named key in the crypto provider on the server? See How to: Use the X.509 Certificate Management Tools.

BTW, if you are able to decrypt on your machine something that should be a private key only on the server, that key is already compromised. You should change your keys asap.

After your Update

RSA cryptography is based on assymetric key. You encrypot with the public key, the destination decrypots with the private key. The keys are provisioned upfront, the destination of your generates or obtains a key pair and keeps the private part to himself and advertises the public part for others. Usually the keys are packed as X509 certificates because this utilizes the whole trust infrastructure around certificates (signatures, trusted authorities, certificate purpose etc etc). In that case the destination of the message must requests a certificate for encryption purposes from a trusted authority (ie. Verisign) etc etc. Or use a self signed certificate (makecert.exe) and establish the trust by some out of bands methods (ie. a phone call to validate the certificate hash or IssuerName/SerialNumber).

RSa cryptography is very far from 'just strings'. Closer to 'just strings' is symmetric key cryptography (AES, DES, XDES, RC4) where your application has a secret key used both to encrypt and decrypt.

Now, unless you really know what you're doing, steer clear of cryptography, use an off the shelf protocol like SSL/TLS (online) or S-MIME (offline). Better still, use some framework facilities like CryptoStream or ProtectedData. Don't create yet another pseudo-encryption based on newsgroup advice from people you never met...

Remus Rusanu
Had a look at CryptoStream, still stuck with the same fundamental problem thats driving me nuts, it will work locally, but when I port the code into production... it will break.
JL
Your problem is not encryption/decryption, is key management. You have to establish clearly for your product how are the keys to be provisioned and used. Then you will know in your code what key to use to encrypt and the decryption will work on the intended target. Note that on Windows key stores are both machine specific (available only to admins, so Vista LUA requires the RunAs Admin) and user specific.
Remus Rusanu
A: 

A problem might be that the RSA object tries to create CryptoContainer in the user profile.
You could try to add this:

rsa.UseMachineKeyStore = true;
Sani Huttunen
+1  A: 

If you need to copy the key from one machine to another you're going to have to export it from the key container. We found that the rsaCryptoServiceProvider.ImportCspBlob and ExportCspBlob methods work nicely for this; you get a single byte array which you can then Convert.ToBase64String and Convert.FromBase64String.

Of course, it has to be an exportable key (or better yet, export only the public key which is the way PKC is meant to be done so one end has the private key and the other only the public key). A non-exportable key can only export its public key. Once you get the system working, you could create a new non-exportable key where you need the private key to reside, and export the public key to transfer it to whereever else needs to encrypt to that single recipient.

Also, you need to make sure to Dispose the crypto provider when you're done (apparently Clear() isn't good enough). It's good to use a using statement to do this, if you're using it in one local scope, or you can do it in your finally block. Note that it implements IDisposable explicitly, so you have to cast it to IDisposable somewhat awkwardly to do it in a separate statement. A using statement handles the casting itself, so it's easier.

Rob Parker
Decryption requires the *private* key. The private key should be already provissioned, you cnanot provision the private key 'just in time'. Where would the private key be installed *from*? What is the security of that key store, how is protected? Besides, unless you write an explicit key management tool, you never have to isntall and remove keys in code, there are tools for that.
Remus Rusanu
Obviously, you have to know which end is which, and generate the private key on the end needing to decrypt (and perhaps a different private key at the other end). But you have to get the matching public key from there to other places. One way of doing that (which we use) to to export it yourself. Key management tools would be another (which I haven't used). Which one is appropriate depends on factors in the scenario which weren't originally mentioned.
Rob Parker