views:

905

answers:

2

I would like to use Public/Private encryption where my web app would sign an xml document or a piece of data using a private key and it will be verified in the application using the public key,

Is it possible to use RSACryptoServiceProvider in .net 2.0 hosted environment if not what are other possible workarounds?

+1  A: 

Yes, quite possible.

If you export the cert you will use for data-signing into a .pfx file, you can get a digsig this way.

using System;
using System.Xml;
using System.Reflection;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography.X509Certificates;
// ...

static void SignWithPfxPrivateKey()
{
    X509Certificate2 certificate = new X509Certificate2(certFile, pfxPassword);
    RSACryptoServiceProvider rsaCsp = (RSACryptoServiceProvider) certificate.PrivateKey;   

    XmlDocument xmlDoc = new XmlDocument();

    xmlDoc.PreserveWhitespace = true;
    if (loadFromString)
      xmlDoc.LoadXml(rawXml);   // load from a string
    else 
      xmlDoc.Load("test.xml");  // load from a document 

    // Sign the XML document. 
    SignXml(xmlDoc, rsaCsp);

    // Save the document.
    xmlDoc.Save("RsaSigningWithCert.xml");

    xmlDoc.Save(new XTWFND(Console.Out));
}

public static void SignXml(XmlDocument Doc, RSA Key)
{
    // Check arguments.
    if (Doc == null)
        throw new ArgumentException("Doc");
    if (Key == null)
        throw new ArgumentException("Key");

    // Create a SignedXml object.
    SignedXml signedXml = new SignedXml(Doc);

    // Add the key to the SignedXml document.
    signedXml.SigningKey = Key;

    // Create a reference to be signed.
    Reference reference = new Reference();
    reference.Uri = "";

    // Add an enveloped transformation to the reference.
    XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
    reference.AddTransform(env);

    // Add the reference to the SignedXml object.
    signedXml.AddReference(reference);

    // Compute the signature.
    signedXml.ComputeSignature();

    // Get the XML representation of the signature and save
    // it to an XmlElement object.
    XmlElement xmlDigitalSignature = signedXml.GetXml();

    // Append the element to the XML document.
    Doc.DocumentElement.AppendChild(Doc.ImportNode(xmlDigitalSignature, true));
}

To use this, you will have to upload a .pfx file to the hosted server. You also need a password for that pfx file, which you should store securely in application config settings. You can do something similar with a .cer file.

You can also load the RSA key from regular XML. If you have an RSACryptoServiceProvider that you instantiated by loading a key from your local machine store, like this:

  // Get the key pair from the key store.
  CspParameters parms = new CspParameters(1);
  parms.Flags = CspProviderFlags.UseMachineKeyStore;
  parms.KeyContainerName = "SnapConfig";
  parms.KeyNumber = 2;
  RsaCsp = new RSACryptoServiceProvider(parms);

...then you can export that key with

RsaCsp.ToXmlString(true);

The result is a string, containing an XML document that you can save to a file, and then upload to the hosted server. An alternative to the .pfx file as a store for your key pair. Be careful. This xml document is not protected with a password, and is insecure. (read the doc on ToXmlString()) You can encrypt this XML doc, just as you would encrypt any other settings. (search)

In that case you can do this to get your csp:

  RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
  csp.FromXmlString(keyPairXml);
Cheeso
Thanks for your answer and code.Do you mean that I would have to ask the shared hosting provider to install the certificate onto their server? or I just put it in one of my directories and it should work?CspProviderFlags.UseMachineKeyStore is disabled on most shared hosts. I think RSACryptoServiceProvider can not be instantiated otherwise I could simply generate public private key on my machine and do an ImportFromXml on the service provider, how does that differentiate from using a certificate?
AppDeveloper
If it is a pfx file or .xml file then of course you could just upload it like any other file. This is an alternative to the "machine store" which is what you use with UseMachineKeyStore. You *think* RSACryptoServiceProvider cannot be instantiated? It's easy to test. Take my code and compile it and run it. yes, it's true: you can generate a keypair on your machine, upload it in xml form to the host, and then ImportFromXml on the hosted app. That works fine.
Cheeso
A: 

See here: http://www.codeproject.com/KB/security/EZRSA.aspx

Jens