I am using the RSACryptoServiceProvider like this...
private byte[] RSAEncrypt(byte[] DataToEncrypt, string ContainerName, bool DoOAEPPadding)
{
try
{
byte[] encryptedData;
// Create a new instance of CspParameters. Pass
// 13 to specify a DSA container or 1 to specify
// an RSA container. The default is 1.
CspParameters cspParams = new CspParameters();
// Specify the container name using the passed variable.
cspParams.KeyContainerName = ContainerName;
cspParams.Flags = CspProviderFlags.UseDefaultKeyContainer;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(cspParams))
{
//Encrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
encryptedData = RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
}
return encryptedData;
}
//Catch and display a CryptographicException
//to the console.
catch (CryptographicException ex)
{
sl.Write(ex, MessageType.Error);
throw;
}
}
I then try to decrypt the data after turning off my Outlook Plugin Windows Form application and turning it back on which is what is using this peice of code. The decrypt code looks like this...
private byte[] RSAEncrypt(byte[] DataToEncrypt, string ContainerName, bool DoOAEPPadding)
{
try
{
byte[] encryptedData;
// Create a new instance of CspParameters. Pass
// 13 to specify a DSA container or 1 to specify
// an RSA container. The default is 1.
CspParameters cspParams = new CspParameters();
// Specify the container name using the passed variable.
cspParams.KeyContainerName = ContainerName;
cspParams.Flags = CspProviderFlags.UseDefaultKeyContainer;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(cspParams))
{
//Encrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
encryptedData = RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
}
return encryptedData;
}
//Catch and display a CryptographicException
//to the console.
catch (CryptographicException ex)
{
sl.Write(ex, MessageType.Error);
throw;
}
}
Works great until something comes up that I can not put my finger on. I don't know if it is like the date changes or what. What happens is that I try to decrypt the data and I get a "bad data" error. Now again it works great until some elapsed period of time, or turning off the app, or the user logging off. I just don't know and can't determine what causes it. The moment I blow away the encrypted data which comes from a text file and recreate it and decrypt it I have no problem. Even if I restart the application in between encrypting/saving to file and the reading from file/decrypting it will works great! Something happens and I just don't know KeyContainers well enough to understand what could possibly make the CspParameters expire is my best guess?
You could try using the bouncy castle crypto libraries if you're really stuck:
http://www.bouncycastle.org/csharp/
I ended up using the CspParameters flag and instead of using the Users KeyContainer store I used the Machine KeyContainer Store.
Yes, if you set:
cspParams.Flags = CspProviderFlags.UseDefaultKeyContainer;
then the key container is stored in the user's key container store, then logging on as another user will and using RSA with present you with an entirely different KeyContainer store.
Using this instead:
cspParams.Flags = CspProviderFlags.UseMachineKeyStore = true;
Will use the local machine's KeyContainer store, which is global for the machine, and will provide you with the same KeyContainer store, irregardless of which user is logged in. However, this only applies for that windows installation. Running your program under a different windows installation or machine will provide you with a different KeyContainer store. If you wish to decrypt the same data across multiple machines, you will need to persist your key to a file on the hard drive. Persisting a key to a plain text file is a huge security risk, so please encrypt your key before persisting it to a file, or put it in a password protected .rar files or something.
If your still having issues, try setting:
RSA.PersistKeyInCsp = true;
This will ensure that your key is persisted in the KeyContainer store. Persisting the file in the KeyContainer should be the default behavior if you use the CspParameters constructor such as:
CspParameters cspParams = new CspParameters();
In Microsoft's own words:
"This form of CspParameters initializes the ProviderType field to a value of 24, which specifies the PROV_RSA_AES provider."
Source: http://msdn.microsoft.com/en-us/library/xw9ywed4.aspx
So your comments in your code is incorrect and my be misleading you. I would advise you to correct them.
I am unsure about other ProviderTypes and their default settings regarding persisting the key in the KeyContainer store, so setting PersistKeyInCsp to TRUE might be necessary if your still having issues.
Hope this helps.
~Adam WhiteHat();
Related
I'm attempting to apply an rsa-sha512 signature to a message, using a certificate on the local HDD.
The final SignData raises a cryptographic exception "Invalid algorithm specified".
However, if I use SignData on a new instance of RSACryptoServiceProvider (created by importing an export of the original RSACryptoServiceProvider), I don't get that exception.
Is there some reason that the original version raises the exception? Since the "copy" is evidently different, I'd prefer to use the original.
The c# code I'm using is as follows:
X509Certificate2 cert = new X509Certificate2("C:\\Certs\\" + certName + ".p12", certPassword, X509KeyStorageFlags.Exportable);
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PrivateKey;
UTF8Encoding ByteConverter = new UTF8Encoding();
byte[] unsignedBytes = ByteConverter.GetBytes(unsignedText);
byte[] signature;
//This raises an exception, "Invalid algorithm specified."
signature = csp.SignData(unsignedBytes, new SHA512CryptoServiceProvider());
//But if I make a copy of the RSACryptoServiceProvider, no exception is raised
RSACryptoServiceProvider cspCopy = new RSACryptoServiceProvider();
RSAParameters Key = csp.ExportParameters(true);
cspCopy.ImportParameters(Key);
signature = cspCopy.SignData(unsignedBytes, new SHA512CryptoServiceProvider());
To quote myself from a previous answer:
Software-backed RSACryptoServiceProvider is only capable of doing RSA signature using a SHA-2 digest algorithm when the CSP ProviderType value is 24 (PROV_RSA_AES) and the ProviderName is "Microsoft Enhanced RSA and AES Cryptographic Provider" (MS_ENH_RSA_AES_PROV). Hardware may or may not require PROV_RSA_AES, just depends on the hardware.
In this case, the PFX identifies the private key to belong to an older CSP (or, maybe, it has no CSP identifier and the PFX import is picking bad defaults). For software keys it's possible to extract the CspParameterInfo data from the key and re-open it using ProviderType 24, which is one way to work around the problem. Exporting the raw RSA parameters and importing it into a new object (which defaults to ProviderType 24) is a more aggressive workaround.
The better way to work around the problem is to abandon RSACryptoServiceProvider. Instead of using cert.PrivateKey, use cert.GetRSAPrivateKey(), which will almost always return an RSACng instance, which doesn't have this problem (but don't cast it if you can avoid it (if nothing else, see "almost" always)).
byte[] signature;
using (RSA rsa = cert.GetRSAPrivateKey())
{
signature = rsa.SignData(
unsignedBytes,
HashAlgorithmName.SHA512,
RSASignaturePadding.Pkcs1);
}
The using statement is correct for GetRSAPrivateKey, because it returns a distinct object per call.
RSACng and GetRSAPrivateKey both require .NET 4.6, but that's more than two years old at this point (and 4 (and a half) newer releases have happened in that time), so shouldn't cause you difficulty as a dependency.
I'm a newbie to Windows Forms.
I'm designing an Windows Application in .Net Framework 2.0 in which,
I need to Store a UserName and Password somewhere in the System and access them every time I open My Application and Some times I need to change those credentials on User command.
I heard registry is the Best way in doing so. I know Nothing About Using Registry in C# .Net.
So Can you Help me in
How To Get Values which are In Registry, and how to Set a Value to Registry. ??
I'm Using .Net Framework 2.0
The subject is very broad. You should start reading on MSDN about the class
Microsoft.Win32.RegistryKey
But I really suggest to avoid the registry altogether.
Allowing the registry to store configuration info for normal applications has been a mistake from the start by Microsoft.
You could write a simple hashing function, apply it to your username and password and store the result in a file located in the ApplicationData folder.
At the next run check if the file exist, read it and compare its content with the hashing of username and password.
Here a rough example, just to let you start on your own code.
private void button1_Click(object sender, EventArgs e)
{
string user = "Steve";
string pass = "MyPass";
string hashedUser = GetHashedText(user);
string hashedPass = GetHashedText(pass);
string file = Path.Combine(Environment.GetFolderPath
(Environment.SpecialFolder.ApplicationData),
"MyKeys.txt");
if (File.Exists(file))
{
using (StreamReader sr = new StreamReader(file))
{
string recordedUser = sr.ReadLine();
string recordedPass = sr.ReadLine();
if (recordedUser == user && recordedPass == pass)
MessageBox.Show("User validated");
else
MessageBox.Show("Invalid user");
}
}
else
{
using (StreamWriter sw = new StreamWriter(file, false))
{
sw.WriteLine(hashedUser);
sw.WriteLine(hashedPass);
}
}
}
private string GetHashedText(string inputData)
{
byte[] tmpSource;
byte[] tmpData;
tmpSource = ASCIIEncoding.ASCII.GetBytes(inputData);
tmpData = new MD5CryptoServiceProvider().ComputeHash(tmpSource);
return Convert.ToBase64String(tmpData);
}
EDIT: Based on your comment, it seems that you need a crypt and decrypt function. The code below is taken and adapted from the Extension Overflow, where you can find other useful methods.
Now, before write to disk, call the Encrypt method with the string to encrypt and a key. After reading, call the Decrypt method passing the crypted text and the secret key.
string cryptedUser = Encrypt(user, "your_secret_key_ABCDEFG");
....
public string Encrypt(string stringToEncrypt, string key)
{
if (string.IsNullOrEmpty(stringToEncrypt))
throw new ArgumentException("An empty string value cannot be encrypted.");
if (string.IsNullOrEmpty(key))
throw new ArgumentException("Cannot encrypt using an empty key.");
CspParameters cspp = new CspParameters();
cspp.KeyContainerName = key;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cspp);
rsa.PersistKeyInCsp = true;
byte[] bytes = rsa.Encrypt(UTF8Encoding.UTF8.GetBytes(stringToEncrypt), true);
return BitConverter.ToString(bytes);
}
string clearText = Decrypt(cryptedText, "your_secret_key_ABCDEFG");
....
public 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");
try
{
CspParameters cspp = new CspParameters();
cspp.KeyContainerName = key;
RSACryptoServiceProvider rsa = new 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;
}
Of course, I assume that the security level required by your application allows that username ans passwords will be stored in the local system. (And as you know, everything that is stored on the local system is not very secure)
Check this tutorial with read, write and delete function for registry
Read, write and delete from registry with C#
Here is a good tutorial that will explain read/write to registry.
http://www.switchonthecode.com/tutorials/csharp-snippet-tutorial-editing-the-windows-registry
There are few more things you need to know about registry.
Registry consists of five sections of which HKEY_CURRENT_USER stores the settings of currently logged in user. It is recommended that you store the settings under this key. Settings are stored generally in HKEY_CURRENT_USER/Software//
You can store machine wide settings (applicable to all users using the computer) under HKEY_LOCAL_MACHINE key. However, read/write operations to this requires administrative rights. Your application must be running in administrator privilege to write to this key.
Make sure that your registry reading mechanism returns default values if it is not found in the registry as well as write the default values to registry. This way, you will never run out of setting values.
Registry can be edited and can be read. If you are planning to store username/password combination in registry, make sure you encrypt it before you store it. Further, to make sure that it is not used on any other computer also, you should encrypt it with some machine specific information.
Hope this helps you.
You could try using IsolatedStorage. MSDN Blurb, code sample, and (given you're storing user credentials) an encryption sample. I've linked .net 2.0 samples where possible.
Storing application data in the registry has become unpopular since there are easier alternatives and using the registry can hurt the performance of your users' computers.
I've never used the registry but first thing that comes up on google is this. Seems like fairly easy to understand so have fun with it :)
doing it the registry way is the wrong way to go, , i believe do a config file and read this config is much better way to go. but anyway here how you do registry thing
http://www.codeproject.com/Articles/3389/Read-write-and-delete-from-registry-with-C
You need to ask yourself a couple of questions:
Should only one user be able to use the uid/password?
How safe should the password be stored?
It's quite easy to store information in the registry.
http://msdn.microsoft.com/en-us/library/microsoft.win32.registry.aspx
If you just want to store it for one user, store it under HKEY_CURRENT_USER/software/your_company/your_product otherwize store it under HKEY_LOCAL_MACHINE/software/your_company/your_product.
If your password is to be stored safely, there are safer solutions than the registry.
A bit more background info as suggested:
I'm finsihing of an Intranet CMS web app where I have to use the products API (ASP.NET based). Because of time constraints and issues with Windows authen' I need another way to ensure staff do not need to re login everytime they visit the site to view personalised content. The way it works is that once a user logs in (username/password), a Session ID storing a new different Security context value is generated that is used to display the personalised content. The API login method called uses the username and password as parameters. The only way I can think of automatically logging in the next time the staff visits the site is by storing the password in a enrypted cookie and checking of its existing when the site is visited and then calling the API login method using the username and decrypted password cookie values.
Any other ideas as an alternative welcomed.
Mo
Hi,
I'm using some code found on the web to encrypt and decrypt a password string. It encrypts fine but when it calls the code below to decrypt the string it throws the error "Length of the data to decrypt is invalid" How can I resolve this?
Thanks in advance.
Mo
System.Text.Encoding enc = System.Text.Encoding.ASCII;
byte[] myByteArray = enc.GetBytes(_pword);
SymmetricAlgorithm sa = DES.Create();
MemoryStream msDecrypt = new MemoryStream(myByteArray);
CryptoStream csDecrypt = new CryptoStream(msDecrypt, sa.CreateDecryptor(), CryptoStreamMode.Read);
byte[] decryptedTextBytes = new Byte[myByteArray.Length];
csDecrypt.Read(decryptedTextBytes, 0, myByteArray.Length);
csDecrypt.Close();
msDecrypt.Close();
string decryptedTextString = (new UnicodeEncoding()).GetString(decryptedTextBytes);
A couple of things here...
You shouldn't encrypt passwords usually. You should hash them.
If you decide to continue down the road of encryption..
You are using the DES algorithm. This is considered insecure and flawed. I'd recommend looking at the AES algorithm.
Depending on how much data you are working with, the CryptoStream might be overkill.
Using the ASCII encoding can cause loss of data that isn't ASCII, like Cyrillic letters. The recommended fix is to use something else, like UTF8.
Here is an example:
string text = "Hello";
using (var aes = new AesManaged())
{
var bytes = System.Text.Encoding.UTF8.GetBytes(text);
byte[] encryptedBytes;
using (var encrypt = aes.CreateEncryptor())
{
encryptedBytes = encrypt.TransformFinalBlock(bytes, 0, bytes.Length);
}
byte[] decryptedBytes;
using (var decrypt = aes.CreateDecryptor())
{
decryptedBytes = decrypt.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
}
var decryptedText = System.Text.Encoding.UTF8.GetString(decryptedBytes);
Console.Out.WriteLine("decryptedText = {0}", decryptedText);
}
This will use a random key every time. It is likely that you will need to encrypt some data, then decrypt it at a later time. When you create the AesManaged object, you can store the Key and IV property. You can re-use the same Key if you'd like, but different data should always be encrypted with a different IV (Initialization Vector). Where you store that key, is up to you. That's why hashing might be a better alternative: there is no key, and no need to worry about storing the key safely.
If you want to go down the hashing route, here is a small example:
var textToHash = "hello";
using (SHA1 sha = new SHA1Managed())
{
var bytesToHash = System.Text.Encoding.UTF8.GetBytes(textToHash);
var hash = sha.ComputeHash(bytesToHash);
string base64hash = Convert.ToBase64String(hash);
}
This uses the SHA1 algorithm, which should work fine for passwords, however you may want to consider SHA256.
The concept is simple: a hash will produce a (mostly) unique output for an input, however the output cannot be converted back to the input - it's destructive. Whenever you want to check if a user should be authenticated, check hash the password they gave you, and check it against the hash of the correct password. That way you aren't storing anything sensitive.
I've actually had this error before and it took me 3 days to figure out the solution. The issue will be the fact that the machine key you need for descryption needs to be registered on your machine itself.
Read fully up on DES encryption, it works by an application key, and a machine-level key. The error you're getting is likely because of the machine key missing.
Compare the bytes used to create the _pword string (in the encryption method) to the bytes retrieved with GetBytes. Probably you will notice a change in the data there.
To store the encrypted bytes, I think you should use Convert.ToBase64String and Convert.FromBase64String turn the encrypted password to/from a string.
I also do not see the code where you set the Key and IV. So I guess you are using a different key to encrypt and decrypt the password.
If the current Key property is null,
the GenerateKey method is called to
create a new random Key. If the
current IV property is null, the
GenerateIV method is called to create
a new random IV.
DES is a block based cipher - only certain lengths of buffers are valid. If I remember correctly, the block size for DES is 64 bits, so you need to ensure that your byte array is a multiple of 8 bytes long.
(That should fix your immediate problem, but I'd reference other peoples advice here - you really ought not to be using DES for any new code, and for passwords it's usually more appropriate to hash than to encrypt).
I am trying to use the RSACryptoServiceProvider to encrypt/decrypt. Encrypting works fine, but the Decrypt method throws an exception with the message:
Unknown Error '80007005'.
This is the code:
Byte[] plainData = encoding.GetBytes(plainText);
Byte[] encryptedData;
RSAParameters rsap1;
Byte[] decryptedData;
using (RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider())
{
encryptedData = rsa1.Encrypt(plainData, false);
rsap1 = rsa1.ExportParameters(false);
}
using (RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider())
{
rsa2.ImportParameters(rsap1);
decryptedData = rsa2.Decrypt(encryptedData, false);
}
decryptedText = encoding.GetString(decryptedData, 0, decryptedData.Length);
Is anyone aware of a workaround?
Thanks!
Fixed the code! I guess I do not need to specify a container after all...
Byte[] plainData = encoding.GetBytes(plainText);
Byte[] encryptedData;
Byte[] decryptedData;
using (RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider())
{
RSAParameters rsap1 = rsa1.ExportParameters(false);
using (RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider())
{
rsa2.ImportParameters(rsap1);
encryptedData = rsa2.Encrypt(plainData, false);
}
decryptedData = rsa1.Decrypt(encryptedData, false);
}
decryptedText = encoding.GetString(decryptedData, 0, decryptedData.Length);
rsap1 = rsa1.ExportParameters(false);
By passing false to this method, you're choosing to not export the private key. Without the private key it will be difficult to decrypt the data. Try passing true to the export method.
When using RSA you need to understand the basics of key management. You did not specify what key container to use during encryption. What key do you expect to be used? The default user key? The machine key? Do you understand what the default user key and the machine keys are ? Not to mention the obvious question of why do you encrypt anything with RSA? RSA encryption is used solely for encrypting session keys, and there are dedicated key exchange protocols that take care of this out-of-the-box (stream oriented like TLS or document oriented like S/MIME). You should use one of these out-of-the-box protocols and not roll your own encryption scheme. You will screw up key management, that is guaranteed.
When you attempt to decrypt, does the decryptor has possession of the private key corresponding to the public key used during encryption?
See:
How to: Store Asymmetric Keys in a Key Container
Encrypting Data
Decrypting Data
Note that these are just simple code samples in MSDN and should never be used by anyone without a very deep understanding of cryptography, and specially key management.
I recommend you look into using a high level class like SslStream for encrypting data exchanges. For a document storage encryption scheme you better use the OS facilities or rely on ProtectedData class. Again, do not roll your own encryption unless you really know what you're doing (in which case you wouldn't be asking questions here).
it's late, I'm tired, and probably being quite dense....
I have written an application that I need to secure so it will only run on machines that I generate a key for.
What I am doing for now is getting the BIOS serial number and generating a hash from that, I then am encrypting it using a XML RSA private key. I then sign the XML to ensure that it is not tampered with.
I am trying to package the public key to decrypt and verify the signature with, but every time I try to execute the code as a different user than the one that generated the signature I get a failure on the signature.
Most of my code is modified from sample code I have found since I am not as familiar with RSA encryption as I would like to be. Below is the code I was using and the code I thought I needed to use to get this working right...
Any feedback would be greatly appreciated as I am quite lost at this point
the original code I was working with was this, this code works fine as long as the user launching the program is the same one that signed the document originally...
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = "XML_DSIG_RSA_KEY";
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
// Create a new RSA signing key and save it in the container.
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams)
{
PersistKeyInCsp = true,
};
This code is what I believe I should be doing but it's failing to verify the signature no matter what I do, regardless if it's the same user or a different one...
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider();
//Load the private key from xml file
XmlDocument xmlPrivateKey = new XmlDocument();
xmlPrivateKey.Load("KeyPriv.xml");
rsaKey.FromXmlString(xmlPrivateKey.InnerXml);
I believe this to have something to do with the key container name (Being a real dumbass here please excuse me) I am quite certain that this is the line that is both causing it to work in the first case and preventing it from working in the second case....
cspParams.KeyContainerName = "XML_DSIG_RSA_KEY";
Is there a way for me to sign/encrypt the XML with a private key when the application license is generated and then drop the public key in the app directory and use that to verify/decrypt the code? I can drop the encryption part if I can get the signature part working right. I was using it as a backup to obfuscate the origin of the license code I am keying from.
Does any of this make sense?
Am I a total dunce?
Thanks for any help anyone can give me in this..
I used this method to sign xml documents using a private key stored in an xml file that I then embedded into the application .dll as a resource. I think you may be struggling with permissions accessing the keystore, and this would also create hassles transferring the code to other servers etc.
Here is the code to get the private key as an embedded resource and sign the document:
(Sign is the name of the class this method is located in, Licensing.Private.Private.xml is a combination of the default namespace + folder + filename of the resource)
public static void SignDocument(XmlDocument xmldoc)
{
//Get the XML content from the embedded XML privatekey.
Stream s = null;
string xmlkey = string.Empty;
try
{
s = typeof(Sign).Assembly.GetManifestResourceStream("Licensing.Private.Private.xml");
// Read-in the XML content.
StreamReader reader = new StreamReader(s);
xmlkey = reader.ReadToEnd();
reader.Close();
}
catch (Exception e)
{
throw new Exception("Error: could not import key:",e);
}
// Create an RSA crypto service provider from the embedded
// XML document resource (the private key).
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
csp.FromXmlString(xmlkey);
//Creating the XML signing object.
SignedXml sxml = new SignedXml(xmldoc);
sxml.SigningKey = csp;
//Set the canonicalization method for the document.
sxml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigCanonicalizationUrl; // No comments.
//Create an empty reference (not enveloped) for the XPath transformation.
Reference r = new Reference("");
//Create the XPath transform and add it to the reference list.
r.AddTransform(new XmlDsigEnvelopedSignatureTransform(false));
//Add the reference to the SignedXml object.
sxml.AddReference(r);
//Compute the signature.
sxml.ComputeSignature();
// Get the signature XML and add it to the document element.
XmlElement sig = sxml.GetXml();
xmldoc.DocumentElement.AppendChild(sig);
}
Use the following code the generate the private.xml and public.xml keys. Keep the private.xml file secure, obviously.
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
File.WriteAllText(#"C:\privateKey.xml", rsa.ToXmlString(true)); // Private Key
File.WriteAllText(#"C:\publicKey.xml", rsa.ToXmlString(false)); // Public Key
Guess, the problem is that different users don't have access to the key that is stored for the 1st user (Please note: I am not a cryptography expert).