简体   繁体   中英

C# RSA Decryption issue

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.

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.

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.

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

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

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

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;

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