RSA encryption stopped working when server was joined to domain - c#

I had a working RSA encryption that was basically created like this
public string DecryptFormula( byte[] WholeData )
{
// Get from container the key used to encrypt entropy bytes
RSAParameters PublicKey = GetKeyFromContainer("CorroredKeys");
byte[] KeyLengthByte = new byte[4];
Array.Copy(WholeData, KeyLengthByte, 4);
int KeyLength = BitConverter.ToInt32(KeyLengthByte, 0);
// Encrypt entropy
byte[] encryptedKey = new byte[KeyLength];
Array.Copy(WholeData, 4, encryptedKey, 0, KeyLength);
//Pass the data to ENCRYPT, the public key information
//(using RSACryptoServiceProvider.ExportParameters(false),
//and a boolean flag specifying no OAEP padding.
byte[] PrivateKey = RSADecrypt(encryptedKey, PublicKey, false);
...
}
static public byte[] RSADecrypt(byte[] DataToDecrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
{
try
{
byte[] decryptedData;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Import the RSA Key information. This needs
//to include the private key information.
RSA.ImportParameters(RSAKeyInfo);
//Decrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
decryptedData = RSA.Decrypt(DataToDecrypt, DoOAEPPadding);
}
return decryptedData;
}
//Catch and display a CryptographicException
//to the console.
catch (CryptographicException ex)
{
return null;
}
}
However, after joining the server, where this code is running, to the domain the decryption suddenly stopped working. I have debugged this so far that I found that the problem seems to be with
RSA.Decrypt(DataToDecrypt, DoOAEPPadding)
that gives an exception
System.Security.Cryptography.CryptographicException: The parameter is incorrect.
at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
at System.Security.Cryptography.RSACryptoServiceProvider.DecryptKey(SafeKeyHandle pKeyContext, Byte[] pbEncryptedKey, Int32 cbEncryptedKey, Boolean fOAEP, ObjectHandleOnStack ohRetDecryptedKey)
at System.Security.Cryptography.RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP)
at MyCalculation.ProjectBase.RSADecrypt(Byte[] DataToDecrypt, RSAParameters RSAKeyInfo, Boolean DoOAEPPadding)
How to proceed with this and where to look for possible reason for this? Note: This code was working before the server was joined to domain.
Edit:
Alex K. asked if the key container I'm using is empty. That is what I also suspected. However, at least the Modulus field of my public key had some data. I'm not able to run debugger in the production environment, but I wrote some code that writes byte arrays into a log file.
RSAParameters PublicKey = GetKeyFromContainer("CorroredKeys");
WriteLog("PublicKey, modulus: " + BytesToString(PublicKey.Modulus));
Just for information, the public key is generated like this:
public static RSAParameters GenKey_SaveInContainer(string ContainerName)
{
// First, to get a fresh key, delete the key from the container.
DeleteKeyFromContainer(ContainerName);
// Create the CspParameters object and set the key container
// name used to store the RSA key pair.
CspParameters cp = new CspParameters();
cp.KeyContainerName = ContainerName;
// Create a new instance of RSACryptoServiceProvider that accesses
// the key container MyKeyContainerName and generates new public and private key data
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(cp))
{
byte[] Keyblob = RSA.ExportCspBlob(true);
// Return saved key information to the caller
return RSA.ExportParameters(false);
}
}
/// <summary>
/// Clears and deletes an asymmetric key pair from given key container
/// </summary>
/// <param name="ContainerName">Key container name where RSA key pair is saved</param>
public static void DeleteKeyFromContainer(string ContainerName)
{
// Create the CspParameters object and set the key container
// name used to store the RSA key pair.
CspParameters cp = new CspParameters();
cp.KeyContainerName = ContainerName;
// Create a new instance of RSACryptoServiceProvider that accesses
// the key container.
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);
// Delete the key entry in the container.
rsa.PersistKeyInCsp = false;
// Call Clear to release resources and delete the key from the container.
rsa.Clear();
}
The key is read from container like this:
public static RSAParameters GetKeyFromContainer(string ContainerName)
{
// Create the CspParameters object and set the key container
// name used to store the RSA key pair.
CspParameters cp = new CspParameters();
cp.KeyContainerName = ContainerName;
// Create a new instance of RSACryptoServiceProvider that accesses
// the key container MyKeyContainerName.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(cp))
{
// Return saved key information to the caller
return RSA.ExportParameters(true);
}
}

The problem was that after joining the server to the domain the two processes that encode and decode the data were running on two different user ids. When this was corrected and data first encoded again the encoded data could be decoded again.
This was so silly case, that I should have discovered this immediately. Lesson learned: Never trust that settings remain as they were.

Related

Asymetric encryption algorithm which allows to use public and private key for both encryption and decryption

I have the following working asymetric encryption implementation:
private static RSAParameters privateKey;
private static RSAParameters publicKey;
private static void RSA()
{
var rsa = new RSACryptoServiceProvider();
privateKey = rsa.ExportParameters(true);
publicKey = rsa.ExportParameters(false);
byte[] originalMessage = GenerateRandomData();
byte[] encryptedMessage = Using(publicKey).Encrypt(originalMessage, false);
byte[] decryptedMessage = Using(privateKey).Decrypt(encryptedMessage, false);
Debug.Assert(originalMessage.SequenceEqual(decryptedMessage));
}
private static RSACryptoServiceProvider Using(RSAParameters parameters)
{
RSACryptoServiceProvider encryptor = new RSACryptoServiceProvider();
encryptor.ImportParameters(parameters);
return encryptor;
}
private static byte[] GenerateRandomData()
{
Random rnd = new Random();
byte[] originalData = new byte[10];
rnd.NextBytes(originalData);
return originalData;
}
I use this to encrypt data with the recipient's public key [Using(publicKey).Encrypt(originalData)] so that the receiver only can decrypt the data [Using(privateKey).Decrypt(encryptedData)].
Now I want to reuse asymetric encryption for the following use case: The recipient publishes data and everyone who knows the recipient's public key (which is basically everyone in the system, but nobody outside the system e.g. a protection against leaking readable data to the public) can read it. The publisher uses his private key to encrypt and his public key would be used to decrypt:
byte[] originalData = GenerateRandomData();
byte[] publishedData = Using(privateKey).Encrypt(originalData, false);
byte[] retrievedData = Using(publicKey).Decrypt(publishedData, false);
Debug.Assert(originalData.SequenceEqual(retrievedData));
However this yields a
System.Security.Cryptography.CryptographicException
HResult=0x8009000D
Message=Keyset does not exist.
I do not want to use a different public-private-key-pair for data publishing part, especially in this scenario it means making public a private key. It already sound awkward when typing...
EDIT: Is there an asymetric encryption contained in .NET framework which allows me to use both keys (public and private) in both directions where if one key is used for encryption only the other one can be used to decrypt?
RSA signing is not the same as encrypting with the private key.
PKCS#1 v1.5 signature:
Hash the content with a chosen algorithm.
Create a DigestInfo value to represent the hash.
Apply padding to make a message almost, but not quite, the size of the modulus (details omitted here).
Apply the RSA primitive with the private key
Note that last step doesn’t say “encrypt”.
The RSA classes in .NET do the padding and such for you, so they expose Sign/Verify and Encrypt/Decrypt. You can’t use them for cross purposes, and you can’t use these classes for the RSA primitive (aka “raw RSA”).

c# Rsa Decryption throws "Bad Data" exception

I'm using microsoft's RSACryptoServiceProvider class to Encrypt/Decrypt data.
However, decryption function throws an exception "Bad Data".
Is it something about creating new instance of the provider class everytime I use encryption/decryption?
RSA Provider Class
static public byte[] RSAEncrypt(byte[] byteEncrypt, RSAParameters RSAInfo, bool isOAEP)
{
try
{
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
RSA.ImportParameters(RSAInfo);
//Encrypt the passed byte array and specify OAEP padding.
return RSA.Encrypt(byteEncrypt, isOAEP);
}
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
return null;
}
}
static public byte[] RSADecrypt(byte[] byteDecrypt, RSAParameters RSAInfo, bool isOAEP)
{
try
{
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(4096))
{
//Import the RSA Key information. This needs
//to include the private key information.
RSA.ImportParameters(RSAInfo);
//Decrypt the passed byte array and specify OAEP padding.
return RSA.Decrypt(byteDecrypt, isOAEP);
}
}
catch (CryptographicException e)
{
Console.WriteLine(e.ToString());
return null;
}
}
}
Usage
UnicodeEncoding ByteConverter = new UnicodeEncoding();
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(4096);
byte[] plainPassword;
byte[] encryptedPassword;
plainPassword = ByteConverter.GetBytes(connectionStringPasswordTextBox.Text);
encryptedPassword = CryptoHelper.RSAEncrypt(plainPassword, RSA.ExportParameters(false), false);
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(4096);
byte[] decryptedPassword = CryptoHelper.RSADecrypt(Convert.FromBase64String(connectionString.password), RSA.ExportParameters(true), false);
EDIT
The exception has changed to "The parameter is incorrect" after giving a few more try. I think it has to do with creating only one instance for rsa class instaead of creating new one everytime I use it.
The RSACryptoServiceProvider(int) constructor generates a new key (unless CAPI returns a key for the null-name; which I'm not sure is possible). So this code is encrypting with one key and attempting to decrypt with another. The resulting answer makes so little sense that an exception is thrown.
Generate your key once, and save the RSAParameters from it.
To make your code more portable, avoid saying "RSACryptoServiceProvider"; just talk about RSA, when possible.
Unfortunately, key creation is a time it isn't possible since RSACryptoServiceProvider doesn't generate a new key when KeySize is changed.
So you should really use something more like this on .NET 4.6 or higher:
public static byte[] RSAEncrypt(
byte[] byteEncrypt,
RSAParameters rsaInfo,
RSAEncryptionPadding padding)
{
try
{
using (RSA rsa = RSA.Create())
{
rsa.ImportParameters(rsaInfo);
return rsa.Encrypt(byteEncrypt, padding);
}
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
return null;
}
}

Implementing RSA in C# when Public Key is Known

I'm trying to implement an RSA encryption function, but I'm new to cryptography. I know the public key and have data to encrypt, but I can't get the implementation correct in C#. I've tried using:
private byte[] RSAEncrypt(byte[] data, byte[] publicKey)
{
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
RSAParameters RSAKeyInfo = RSA.ExportParameters(false);
RSAKeyInfo.Modulus = publicKey;
RSA.ImportParameters(RSAKeyInfo);
data = RSA.Encrypt(data, false);
}
return data;
}
But this keeps giving me the error "Bad Length". The public key is 8 bytes long. The data is 254 bytes long. The similar questions about that error say that it occurs when the data is too long. Does an 8 byte long public key sound correct to encrypt 254 bytes?

RSA encryption by supplying modulus and exponent

I am creating a C# Winforms application which POSTs data to a server over HTTPS.
The login mechanism is supposed to be like this:
I send the username to the server, it responds with rsa-modulus and rsa-exponent
I encrypt the password using these given parameters and send username + password to the server for authentication
I have tried the RSACryptoServiceProvider class, but I cannot find samples or anything said on how we can do the encryption using a given modulus and exponent?.
I think that without specifying any values, its doing default encryption parameters..
So if anybody has done this before, can they give me some hints please? thanks
UPDATE: according to the suggestion by Mr. Carsten Konig, . I have tried to do it with RSAParameters and RSA.ImportParameters, but it returns a "BAD DATA" error with cryptographic exception. My code is given below.
I have also tried RSA.FromXmlString(mykey); (where mykey contains an xml string with modulus and exp) but I also get a "BAD DATA" errror with cryptographic exception... any idea anybody? or if its some microsoft bug, can anyone suggest some other decent library to do this easily?
RSAParameters rsaparam = new RSAParameters();
rsaparam.Modulus = modbytes;
rsaparam.Exponent = expbytes;
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider() ;
RSA.ImportParameters(rsaparam);
byte[] encryptedData = RSA.Encrypt(dataToEncrypt, false)
You can do this by using the RSACryptoServiceProvider.Encrypt method. You will also need to use the RSACryptoServiceProvider.ImportParameters method and pass it an RSAParameters structure (this is where you set the exponent, modulus, etc).
Please have a look at the documentation in the link for the RSAParameters - it's very well documented what parameter you have to pass for what structure-field - should be no problem if you now the algorithm.
EDIT: here is the example straight from the MSDN-site:
class RSACSPSample
{
static void Main()
{
try
{ //initialze the byte arrays to the public key information.
byte[] PublicKey = {214,46,220,83,160,73,40,39,201,155,19,202,3,11,191,178,56,
74,90,36,248,103,18,144,170,163,145,87,54,61,34,220,222,
207,137,149,173,14,92,120,206,222,158,28,40,24,30,16,175,
108,128,35,230,118,40,121,113,125,216,130,11,24,90,48,194,
240,105,44,76,34,57,249,228,125,80,38,9,136,29,117,207,139,
168,181,85,137,126,10,126,242,120,247,121,8,100,12,201,171,
38,226,193,180,190,117,177,87,143,242,213,11,44,180,113,93,
106,99,179,68,175,211,164,116,64,148,226,254,172,147};
byte[] Exponent = {1,0,1};
//Values to store encrypted symmetric keys.
byte[] EncryptedSymmetricKey;
byte[] EncryptedSymmetricIV;
//Create a new instance of RSACryptoServiceProvider.
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
//Create a new instance of RSAParameters.
RSAParameters RSAKeyInfo = new RSAParameters();
//Set RSAKeyInfo to the public key values.
RSAKeyInfo.Modulus = PublicKey;
RSAKeyInfo.Exponent = Exponent;
//Import key parameters into RSA.
RSA.ImportParameters(RSAKeyInfo);
//Create a new instance of the RijndaelManaged class.
RijndaelManaged RM = new RijndaelManaged();
//Encrypt the symmetric key and IV.
EncryptedSymmetricKey = RSA.Encrypt(RM.Key, false);
EncryptedSymmetricIV = RSA.Encrypt(RM.IV, false);
Console.WriteLine("RijndaelManaged Key and IV have been encrypted with RSACryptoServiceProvider.");
}
//Catch and display a CryptographicException
//to the console.
catch(CryptographicException e)
{
Console.WriteLine(e.Message);
}
}
}
Please note that only the key/iv gets encrypted - not arbitrary bytes - the length of those bytes is important too!
The allowed length is described in MSDN an depends on the OS!
If you are using RSACryptoServiceProvider.ToXmlString to export the modulus and exponent that the server sends, you need to use Convert.FromBase64String.
public RSAParameters SetPublicKey(string modulus, string exponent)
{
RSAParameters result = new RSAParameters();
result.Modulus = Convert.FromBase64String(modulus);
result.Exponent = Convert.FromBase64String(exponent);
return result;
}
One additional hint that was very useful for me:
In this line,
//Set RSAKeyInfo to the public key values.
SAKeyInfo.Modulus = PublicKey;
PublicKey can also be a direct, straightforward, array of bytes that you can get from the "Public Key" field of a X509 Certificate (directly).

C# RSA encrypt/decrypt throws exception

I'm trying to set up a simple server side RSA encryption of a small chunk of info which is to be decrypted on the client side. Just as a proof of concept I wrote a few lines to ensure that the public and private key could be loaded from xml. However, I'm struggling to make even the most simple stuff work on my machine:
byte[] bytes = Encoding.UTF8.GetBytes("Some text");
bool fOAEP = true;
// seeding a public and private key
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
var publicKey = rsa.ToXmlString(false);
var privateKey = rsa.ToXmlString(true);
//server side
RSACryptoServiceProvider rsaServer = new RSACryptoServiceProvider();
rsaServer.FromXmlString(privateKey);
var encrypted = rsaServer.Encrypt(bytes, fOAEP);
//client side
RSACryptoServiceProvider rsaClient = new RSACryptoServiceProvider();
rsaClient.FromXmlString(publicKey);
var decrypted = rsaClient.Decrypt(encrypted, fOAEP);
The last call to Decrypt throw a CryptographicException with the message "Error occurred while decoding OAEP padding.". I must be missing something totally obvious here. Do I need more setup of the rsa instances or maybe the initial rsa seeding instance?
You should use public key for encryption and private key for decryption.
Take a look here: RSACryptoServiceProvider decrypt with public key
Now, let's get back to the
RSACryptoServiceProvider class. The
Encrypt method ONLY encrypts using
the public key and the Decrypt method
only decrypts using the private key.

Categories

Resources