1

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.

5
  • What's the point of the empty "finally" clause? Commented Oct 1, 2009 at 17:02
  • Did you install the key in the same key container on the new machine? Crypto errors in .NET can be somewhat misleading, but it sounds like it can't find the key container you specified. Commented Oct 1, 2009 at 17:02
  • @Rob , since I didn't generate this key file, where can I find it? Commented Oct 1, 2009 at 17:26
  • If you specified a key container name it's persisted by default (user store by default, others mentioned switching to use machine store, depending on the usage needs) on the machine which generates it. Key management tools (if that's what you want to use) should be able to find it under that same key container name (and same user). It may have worked before because you were testing both encryption and decryption ends on the same machine, where it had the key it made for you for both parts. That's why I suggested one way of transfering the public key to the end needing to encrypt. Commented Oct 1, 2009 at 17:32
  • Still no idea how to get the key file.... but thanks, I think I will find another way to do the encryption. Commented Oct 1, 2009 at 17:41

5 Answers 5

2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

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.
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.
2

Note that you are not using the key parameter as a cipher but as the name for a container. This relies on the encryption function having stored the key earlier. Not suitable to transfer encrypted data across computers. Unless you transfer the keys as well.

1 Comment

I'm not familiar with this API. But step back a little, with this approach you are not getting any of the benefits of RSA but you do get the drawbacks (length limit, slow). You may want to use a symmetric encryption.
1

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

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

1 Comment

+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.
0

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;

Comments

0

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...

2 Comments

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.
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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.