none
RSACryptoServiceProvider Issue RRS feed

  • Question

  •  

    I am new to this technology so please bare with me. I have this two methods to encrypt and decrypt data using RSACryptoServiceProvide in the WCF service.

    Encrypting Data

    public byte[] RsaEncrypt(byte[] dataToEncrypt, RSAParameters rsaKeyInfo, bool doOaepPadding)
      {
       try
       {
        byte[] encryptedData;
    
        using (var rsaCryptoServiceProvider = new RSACryptoServiceProvider())
        {
         rsaCryptoServiceProvider.ImportParameters(rsaKeyInfo);
    
         encryptedData = rsaCryptoServiceProvider.Encrypt(dataToEncrypt, doOaepPadding);
        }
    
        return encryptedData;
       }
       catch (CryptographicException cryptographicException)
       {
        EventLog.WriteEntry(AppName, "[RsaEncrypt Error] CryptographicException: " + cryptographicException, EventLogEntryType.Error);
    
        return null;
       }
       catch (Exception exception)
       {
        EventLog.WriteEntry(AppName, "[RsaEncrypt Error] Exception: " + exception, EventLogEntryType.Error);
    
        return null;
       }
      }

     

    Decrypting Data

    public byte[] RsaDecrypt(byte[] dataToDecrypt, RSAParameters rsaKeyInfo, bool doOaepPadding)
      {
       try
       {
        byte[] decryptedData;
    
        using (var rsaCryptoServiceProvider = new RSACryptoServiceProvider())
        {
         rsaCryptoServiceProvider.ImportParameters(rsaKeyInfo);
    
         decryptedData = rsaCryptoServiceProvider.Decrypt(dataToDecrypt, doOaepPadding);
        }
    
        return decryptedData;
       }
       catch (CryptographicException cryptographicException)
       {
        EventLog.WriteEntry(AppName, "[RsaDecrypt Error] CryptographicException: " + cryptographicException, EventLogEntryType.Error);
    
        return null;
       }
       catch (Exception exception)
       {
        EventLog.WriteEntry(AppName, "[RsaDecrypt Error] Exception: " + exception, EventLogEntryType.Error);
    
        return null;
       }
      }

     


    We exposed the interface for encrypting data to the WPF client. So the WPF client encrypts data using the exposed method above andwith this, we tried encrypting the password during authentication.

     

    UnicodeEncoding byteConverter = new UnicodeEncoding();
    
    byte[] encryptedPassword;
    
    CspParameters parms = new CspParameters();
    parms.Flags = CspProviderFlags.NoFlags;
    parms.KeyContainerName = Guid.NewGuid().ToString().ToUpperInvariant();
    parms.ProviderType = ((Environment.OSVersion.Version.Major > 5) || ((Environment.OSVersion.Version.Major == 5) && (Environment.OSVersion.Version.Minor >= 1))) ? 0x18 : 1;
    
    using (var rsaKey = new RSACryptoServiceProvider(parms))
    {
     encryptedPassword = _myWcfService.RsaEncrypt(byteConverter.GetBytes(txtPassword.Text), 
      rsaKey.ExportParameters(false), false);
    }
    
    User user = _myWcfService.Authenticate(txtUsername.Text, 0, encryptedPassword, parms.KeyContainerName);
    


    And in the WCF service, we decrypt the password:

     

    public User Authenticate(string username, int testId, byte[] password, string keyContainerName)
    {
     Driver driver = null;
    
     UserSession session = AddUserSession();
    
     try
     {
      #region Decrypt Data
    
      _byteConverter = new UnicodeEncoding();
    
      byte[] decryptedPassword;
    
      var cspParameters = new CspParameters
            {
             KeyContainerName = keyContainerName
            };
    
      using (var rsaKey = new RSACryptoServiceProvider(cspParameters))
      {
       <strong>decryptedPassword </strong>= RsaDecrypt(password, rsaKey.ExportParameters(true), false);
      }
    
      #endregion
    
      // Problem: decryptedPassword is always null..
    
      // Connect to the database and authenticate user...
     }
     catch(SqlException sqlException)
     {
      EventLog.WriteEntry(AppName, "[Authenticate Error] SQLException: " + sqlException, EventLogEntryType.Error);
      
     }
     catch (Exception exception)
     {
      EventLog.WriteEntry(AppName, "[Authenticate Error] Exception: " + exception, EventLogEntryType.Error);
     }
    
     return user;
    }
    

    However, the decrypted password is always null which means there is something wrong with the decryption process (RsaDecrypt). In the host server where Wcf service is installed, I notice this error in the event log:

     

    [Authenticate Error] Exception: System.ArgumentNullException: Array cannot be null.
    Parameter name: bytes
       at System.Text.Encoding.GetString(Byte[] bytes)
       at SampleWcfService.Authenticate(String username, Int32 testId, Byte[] password, String keyContainerName)

    Also, I observed that when deploying the Wcf service on the same machine with the WPF client, everything seems to work fine. However, when WPF client is connecting from another machine then I get this error.

     

    Any thoughts why this is happening?

     

     

     


    Tuesday, August 2, 2011 9:01 AM

Answers

  • "When you say key container, does the code snippet below already saves the keys to the key container?"

    Almost. You have to call some method to ensure that the key is generated and stored. Say ExportParameters(false).

    "And by sharing the public key, can this code snippet do the trick?"

    Yes, or ToXmlString(false). It depends what's more convenient to you.

    "And using private key in the server, I just have to use the code below as private key for decryption."

    Hmm, no need for export. Just initialize the RSACryptoProvider with the CspParameters that have the same KeyContainerName that was use when you generated the key.

    • Marked as answer by TechNewb Wednesday, August 3, 2011 11:51 AM
    Wednesday, August 3, 2011 11:11 AM
    Moderator

All replies

  • I don't understand what you are trying to do. Your client generates an RSA key pair and sends the plain text password and the public key to the service which does the encryption. I do hope you're connecting to the WS over HTTPS because otherwise you just sent your plain text password over the network. And if you're using HTTPS, why bother encrypting the password to begin with?

    Then your client tries to authenticate by sending the encrypted password and the key container name. But the key container name is valid only on the client machine, it's not valid on the server machine. So no surprises it only works when the client and server are on the same machine.

     

    Tuesday, August 2, 2011 4:15 PM
    Moderator
  • Thanks for the response Mike. So you're saying that the WS over HTTPS would be enough to secure the message and there is no need to encrypt the password or some other data? Right now, we are using just basicHtttpBinding since some other machine cannot connect to the server (WCF) if we use wsHttpBinding but some can (don't understand why yet) but definitely we need to change this to WS over HTTPS.

    Now that you have mentioned that the key container name is valid only on the client machine, I'm enlightened.

    I have tried using x509Certificate where the server generates the key value pair and I just expose the interface to encrypt data where public key is being shared to the WPF client and it works on two dev machines as simulation but my problem is when I am about to install the certificate in the server, I do not see any Visual Studio Command Prompt (2010) that I use in installing the self signed certificate in my local box.

    Any thoughts how can I install the certificate if VS 2010 command prompt is missing?

    Tuesday, August 2, 2011 6:17 PM
  • Well, yes, HTTPS encrypts all the data sent between the client and the server. That means it will also have more overhead but if you want to encrypt more than the password this won't matter too much, your encryption will add some overhead anyway.

    "I have tried using x509Certificate where the server generates"

    I think this can be made simpler. Since the client only needs to encrypt the password all it needs is the public key. So the server can generate (and store in a key container) the RSA key pair and expose the public key through a WS call. Then the client tries to authenticate it will get the public key from the server, use it to intialize the RSACryptoProvider and encrypt the password. Then the encrypted password is sent to the server and the server will decrypt it using the private key from the stored key pair.

     

    Tuesday, August 2, 2011 6:54 PM
    Moderator
  • That make sense Mike, thanks. But if I use this technique by generating the RSA key pair then I do not need to have the certificate installation in the server itself, right?

    I have been reading these MSDN articles regarding encryption:

     

    http://msdn.microsoft.com/en-us/library/5e9ft273%28v=VS.85%29.aspx

    http://msdn.microsoft.com/en-us/library/tswxhw92%28v=VS.85%29.aspx

    http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider%28v=VS.90%29.aspx

     

    But could not get a solid knowledge or example on how to make this work especially in WCF, so the questions that I have in mind are:

    • How and where do I store the generated RSA key pair if it is not secured to do so in a text file? 
    • Using HTTPS, how do I install SSL certificate in our dev server (Windows Server 2003)? When I check the server, I tried to execute this command in the command prompt "httpcfg query ssl" but it is giving me this error: "'httpcfg' is not recognized as an internal or external command, operable program or batch file.".

     

    http://msdn.microsoft.com/en-us/library/ms733791.aspx

    http://msdn.microsoft.com/en-us/library/ms788967.aspx

     

    Thanks for the help.

    Wednesday, August 3, 2011 2:54 AM
  • "But if I use this technique by generating the RSA key pair then I do not need to have the certificate installation in the server itself, right?"

    Nope, no need.

    "How and where do I store the generated RSA key pair if it is not secured to do so in a text file?"

    In the key container of course. The key pair is generated on the server and it's stored in a key container on the server. Since it never leaves the server the key container can be used to store it. The public key doesn't require security because it's a public key after all.

    "'httpcfg' is not recognized as an internal or external command"

    AFAIR, httpcfg was included in some "support tools" download: http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=7911

    Wednesday, August 3, 2011 7:40 AM
    Moderator
  • Thanks Mike. Just some clarifications to make things clear..

    "In the key container of course. The key pair is generated on the server and it's stored in a key container on the server. Since it never leaves the server the key container can be used to store it. The public key doesn't require security because it's a public key after all."

     

    When you say key container, does the code snippet below already saves the keys to the key container?

     CspParameters cp = new CspParameters();
    cp.KeyContainerName = ContainerName;
    
     RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);

    And by sharing the public key, can this code snippet do the trick?

    RSAParameters RSAKeyInfo = rsa.ExportParameters(false);

    and return the RSAParameters to the calling WPF client for encryption.

    And using private key in the server, I just have to use the code below as private key for decryption.

    rsa.ExportParameters(true);

     

    Please advise if above is correct. Thank you for your help!

     

    Wednesday, August 3, 2011 10:31 AM
  • "When you say key container, does the code snippet below already saves the keys to the key container?"

    Almost. You have to call some method to ensure that the key is generated and stored. Say ExportParameters(false).

    "And by sharing the public key, can this code snippet do the trick?"

    Yes, or ToXmlString(false). It depends what's more convenient to you.

    "And using private key in the server, I just have to use the code below as private key for decryption."

    Hmm, no need for export. Just initialize the RSACryptoProvider with the CspParameters that have the same KeyContainerName that was use when you generated the key.

    • Marked as answer by TechNewb Wednesday, August 3, 2011 11:51 AM
    Wednesday, August 3, 2011 11:11 AM
    Moderator
  • Thanks Mike. I really appreciate your help. I will try this out and update our WCF service to use the same. Again thank you!
    Wednesday, August 3, 2011 11:51 AM