I have a strange reoccuring error relating to "Invalid paramerers" which is thrown when I try to use RSA.Decrypt() however this error is not persistent and sometimes the string is decrypted so I'm unsure as to what could be causing this as I'm fairly certain the keys are not changing from when it is encrypted to when it is decrypted
public static string RSADecrypt(byte[] data,string XMLString)
{
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
try
{
// Import the RSA Key information. This needs
// to include the private key information.
RSA.FromXmlString(XMLString);
// Decrypt the passed byte array and specify OAEP padding.
// OAEP padding is only available on Microsoft Windows XP or
// later.
MessageBox.Show(data.Length.ToString());
MessageBox.Show("Public key: " + Cuserdata.RSA_PublicKey);
MessageBox.Show("Private key: " + Cuserdata.RSA_PrivateKey);
byte[] decryptedData = RSA.Decrypt(data, false);
string decryptedString = Encoding.Unicode.GetString(decryptedData);
// Return the decrypted byte array.
return decryptedString;
}
// Catch and display a CryptographicException
// to the console.
catch (CryptographicException e)
{
MessageBox.Show(e.ToString());
return null;
}
}
}
Error image
I have attempted to output the keys and they appear to be the same so Im unsure as to what else could be throwing this exception
Related
I have some code that creates a digital signature. The message as well as the signature is passed from one system to another. When its received, the signature is verified. This code has been run through Fortify, a service that analyzes code for security vulnerabilities. Fortify is reporting that "The method CreateDigitalSignature() in RSACryptography.cs performs public key RSA encryption without OAEP padding".
I see a parameter on the RSACryptoServiceProvider.Encrypt() method that if true, means to use OAEP padding. But I'm not using Encrypt(). I'm using a RSAPKCS1SignatureFormatter to generate and a RSAPKCS1SignatureDeformatter to verify the signature. So my question is how do I add the padding? Am I supposed to Encrypt the signature before sending it back? See my code where I have marked "IS WHAT I NEED TO DO" where I have added Encrypt and Decrypt calls. Is that what I need to do or something else?
// create a digital signature
// returns true if successful. Also, the public key (as an xml string) that can be sent to the other party to verify messages sent
public bool CreateDigitalSignature(string msgToSend, out string publicKey, out string signature)
{
bool rc = false;
publicKey = null;
signature = null;
try
{
// get the hash of the message to send
byte[] hashValue = GetHashedBytes(msgToSend);
// Load or generate a public/private key pair.
// If it already exists in the key container it will be loaded, otherwise, a new key pair is created
CspParameters cp = new CspParameters();
cp.KeyContainerName = KeyStoreContainerName;
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(cp);
// get some info about the key:
CspKeyContainerInfo info = new CspKeyContainerInfo(cp);
//Create an RSAPKCS1SignatureFormatter object and pass it the RSACryptoServiceProvider to transfer the private key.
RSAPKCS1SignatureFormatter RSAFormatter = new RSAPKCS1SignatureFormatter(RSA);
// Set the hash algorithm
RSAFormatter.SetHashAlgorithm(hashAlgorithm); // "SHA256", "SHA1", etc.
//Create a signature for the hashed value of the data
byte[] signedHashValue = RSAFormatter.CreateSignature(hashValue);
// fortify says I need to use OAEP padding
// IS THIS WHAT I NEED TO DO? Encrypt the signature before I convert it to a string?
signedHashValue = RSA.Encrypt(signedHashValue, true);
// convert the signature to a string
signature = Convert.ToBase64String(signedHashValue);
// get the public key to return so it can be pased to the receiver and used to verify the signature
// There are two ways - either export the parameters or create an xml string
// Using export: This gets public key inforation only (specify true to get both public and private keys)
// RSAParameters RSAKeyInfo = RSA.ExportParameters(false);
// get a string value of the public key
publicKey = RSA.ToXmlString(false);
// demonstration only. how to get the private key
//string privateKey = RSA.ToXmlString(true);
rc = true;
}
catch (Exception ex)
{
throw ex;
}
return rc;
}
And then to verify the signature:
public bool VerifySignature(string origintalData, string publicKeyXml, string signature)
{
bool verified = false;
try
{
// get the hashed value of the original data. used the specified algoritm stored in the this class
byte[] hashValue = GetHashedBytes(origintalData);
// get a byte array of the signature
byte[] signaturebytes = Convert.FromBase64String(signature);
// create a crypto provider
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
// set the public key of the crypto service provider
RSA.FromXmlString(publicKeyXml);
// create a deformatter
RSAPKCS1SignatureDeformatter RSADeformatter = new RSAPKCS1SignatureDeformatter(RSA);
// set the hash algorithm. The sender must use the same algorithm
RSADeformatter.SetHashAlgorithm(hashAlgorithm);
// As per Fortify, need to use OAEP padding
// IS THIS WHAT i NEED TO DO - decrypt the signature before veryfying it?
signaturebytes = RSA.Decrypt(signaturebytes, true);
// verify the signature
verified = RSADeformatter.VerifySignature(hashValue, signaturebytes);
}
catch (Exception ex)
{
throw ex;
}
return verified;
}
Update:
After upgrading from .Net 4.5.1 to 4.6.1. I can use
byte[] signedHashValue = RSA.SignData(bytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)
and the corresponding method
RSA.VerifyData(System.Text.Encoding.UTF8.GetBytes(originalData), signaturebytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)
but I can't specify RSASignaturePadding.Pss. If I do I get an exception "Specified padding mode is not valid for this algorithm."
Also I get the same signature as before, so I feel I haven't really accomplished anything. No way to use AOEP padding?
I am trying to access the private key from a key container and then use it to decrypt a previously encrypted byte[] message. My code appears capable of encrypting that byte[], but when I try to decrypt it, I get the following message:
An unhandled exception of type 'System.ObjectDisposedException' occurred in mscorlib.dll
I am using C# in Visual Studios.
My main function looks like this:
try
{
string testValue = "TestKeyContainer";
string message = "This is the test message!";
UnicodeEncoding ByteConverter = new UnicodeEncoding();
byte[] originalData = ByteConverter.GetBytes(message);
byte[] encryptedData;
byte[] decryptedData;
RSACryptoServiceProvider rsa = null;
//Create a public-private key pair and store them in a key container.
MakeAndSaveKey(testValue);
//[Attempt to] retrieve the key from the container
rsa = GetKeyFromContainer(testValue);
//Read message
Console.WriteLine("Reading the test message... *ahem*...\n{0}", ByteConverter.GetString(originalData));
//Encrypt, then read message
encryptedData = encrypt(originalData, rsa);
Console.WriteLine("Reading the encrypted message...\n....\n{0}", ByteConverter.GetString(encryptedData));
//Decrypt, then read message
decryptedData = decrypt(encryptedData, rsa);
Console.WriteLine("Reading the decrypted message...\n{0}", ByteConverter.GetString(decryptedData));
//Delete key from the container
//DeleteKey("TestKeyContainer");
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
}
DeleteKey(string) being unfinished, and thus commented out. Code for MakeAndSaveKey(string) is:
private static void MakeAndSaveKey(string containerName)
{
CspParameters cp = new CspParameters();
cp.KeyContainerName = containerName;
CspParameters cp = new CspParameters();
cp.KeyContainerName = containerName;
return;
}
GetKeyFromContainer(string) is:
private static RSACryptoServiceProvider GetKeyFromContainer(string containerName)
{
CspParameters cp = new CspParameters();
cp.KeyContainerName = containerName;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);
return rsa;
}
It should be noted that MakeAndSaveKey and GetKeyFromContainer are literally just a C# translation of Microsoft's code from their How to: Store Asymmetric Keys in a Key Container.
The code for encrypt(byte[], RSACryptoServiceProvider) is:
private static byte[] encrypt(byte[] message, RSACryptoServiceProvider rsa)
{
using (rsa)
{
message = RSAEncrypt(message, rsa.ExportParameters(false), false);
}
return message;
}
And for decrypt(byte[], RSACryptoServiceProvider):
private static byte[] decrypt(byte[] message, RSACryptoServiceProvider rsa)
{
using (rsa)
{
try
{
message = RSADecrypt(message, rsa.ExportParameters(true), false);
}
catch (CryptographicException e)
{
Console.WriteLine("Couldn't decrypt the message. \n:ERROR: {0}", e.Message);
}
}
return message;
}
The program outputs the following before it stalls:
Reading the test message... ahem...
This is the test message!
Reading the encrypted message...
....
??????????????????????????u?????????????????=?????????s???????h?
, except that the '=' has three lines instead of two. I just don't know where to find that symbol.
After that, I get the exception described at the top of this post. Specifically, it points to the statement
message = RSADecrypt(message, rsa.ExportParameters(true), false);
from decrypt(byte[], RSACryptoServiceProvider) definition. Does anybody know why this is happening, or how to fix it?
using (resource)
{
// do something
}
is syntactic sugar for:
try
{
// do something
}
finally
{
if (resource!= null)
resource.Dispose();
}
So it means that decrypt tries to use already disposed object.
If you hold the resource(s) in your own container, it means you are managing it by yourself and you should not use using. Remove the use of using and make sure to dispose all the resources manually when done. It should work.
So, what I need is next:
Create certifiactes for development, get one for the client and one for server
Retrieve password through API that is encoded from client and decode it on server
Now, I managed to create certifiactes following this link. The girl there gave step by step instructions on how to get self signed certifiactes, put them in store, etc... Now, the part I'm having problem with:
I've managed to encrypt my data using this code:
public static string Encrypt(string stringForEncription, string PathToPrivateKey)
{
X509Certificate2 myCertificate;
try
{
myCertificate = new X509Certificate2(PathToPrivateKey, "Test123");
}
catch (Exception e)
{
throw new CryptographicException("Unable to open key file.");
}
RSACryptoServiceProvider rsaObj;
if (myCertificate.HasPrivateKey)
{
rsaObj = (RSACryptoServiceProvider)myCertificate.PrivateKey;
}
else
throw new CryptographicException("Private key not contained within certificate.");
if (rsaObj == null)
return String.Empty;
byte[] decryptedBytes;
byte[] array = Encoding.UTF8.GetBytes(stringForEncription);
try
{
decryptedBytes = rsaObj.Encrypt(array, false);
//decryptedBytes = rsaObj.Encrypt(Convert.FromBase64String(Base64EncryptedData), false);
}
catch (Exception e)
{
throw new CryptographicException("Unable to encrypt data.");
}
// Check to make sure we decrpyted the string
if (decryptedBytes.Length == 0)
return String.Empty;
else
return System.Text.Encoding.UTF8.GetString(decryptedBytes);
}
For PathToPrivate key variable I am using the path to my client ClientCert.pfx. I don't know if I should use any other, but here is the snap of the folder with all the certificates that I made:
Now, for the decryption, I'm using next code:
public static string DecryptEncryptedData(string Base64EncryptedData, string PathToPrivateKey)
{
X509Certificate2 myCertificate;
try
{
myCertificate = new X509Certificate2(PathToPrivateKey, "Test123");
}
catch (Exception e)
{
throw new CryptographicException("Unable to open key file.");
}
RSACryptoServiceProvider rsaObj;
if (myCertificate.HasPrivateKey)
{
rsaObj = (RSACryptoServiceProvider)myCertificate.PrivateKey;
}
else
throw new CryptographicException("Private key not contained within certificate.");
if (rsaObj == null)
return String.Empty;
byte[] decryptedBytes;
try
{
decryptedBytes = rsaObj.Decrypt(Convert.FromBase64String(Base64EncryptedData), false);
}
catch (Exception e)
{
throw new CryptographicException("Unable to decrypt data.");
}
// Check to make sure we decrpyted the string
if (decryptedBytes.Length == 0)
return String.Empty;
else
return System.Text.Encoding.UTF8.GetString(decryptedBytes);
}
And whatever I try to do, it gives me exception:
{"The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters. "}
Would really apreciate somebody helping me out.
The reason you are getting the error is the string you are trying to Convert.FromBase64String from a value that is not actually a base-64 string.
After encrypting your data, you should convert the byte array to a base-64 string.
Use Convert.ToBase64String for this.
return Convert.ToBase64String(decryptedBytes);
Then your decrypt line will work:
decryptedBytes =
rsaObj.Decrypt(Convert.FromBase64String(Base64EncryptedData), false);
This is not the exact answer which you might expected but I write here as it's too long as a comment.
I think the decryption itself has no problem at all (I've found the example blog of your code with php encryption) That's why I commented I was curious on the encryptedstring which is the target of decryption.
I also struggled in understanding Security for months and now I use symmetric(AES) and asymmetric(RSA) together. Understanding is really important and everybody takes time..
RSA is asymmetric and one-way which means the Encryption can be done only by public key and the Decryption can be done only by private key.
You're using private key in Encryption method and it seems just copied from Decryption.
The answer by Zesty is right only in terms of formatting. You're also needed to understand the formatting. We need Convert.ToBase64String and Convert.FromBase64String in Encryption and Decryption from byte to base64string and vice versa. However this base64string is not just plain like 'hello' but
'SABlAGwAbABvACAAVwBvAHIAbABkAA==' as you see here
And I kindly recommend to use complete solution(not half one like php encryption) like this blog so that Encryption and Decryption and all are in harmony.
And as last as I commented also, you're needed to think about how to prevent the black users if encryption is done from client side and you don't have only good users.
I hope my experience helps to understand Security which is of most importance.
I am starting to use encryption and decryption in my web service. I am using the RSACryptoServiceProvider and when using the Encrypt & Decrypt methods, I have no problem.
However, as soon as I try to use the SignData method with new SHA1CryptoServiceProvider() as encryption method, I am unable to recover the original data. I am only able to verify them.
Is it really not possible to retrieve the signed data? If so, what is the purpose of the whole signing process? And is there another possibility how to encrypt data by a certain algorithm?
EDIT: I am posting the code, which is just an altered example from MSDN
static void Main()
{
try
{
//Create a UnicodeEncoder to convert between byte array and string.
ASCIIEncoding ByteConverter = new ASCIIEncoding();
string dataString = "Data to Encrypt";
//Create byte arrays to hold original, encrypted, and decrypted data.
byte[] dataToEncrypt = ByteConverter.GetBytes(dataString);
byte[] encryptedData;
byte[] signedData;
byte[] decryptedData;
byte[] unsignedData;
var fileName = ConfigurationManager.AppSettings["certificate"];
var password = ConfigurationManager.AppSettings["password"];
var certificate = new X509Certificate2(fileName, password);
//Create a new instance of the RSACryptoServiceProvider class
// and automatically create a new key-pair.
RSACryptoServiceProvider RSAalg = (RSACryptoServiceProvider)certificate.PrivateKey;
//RSAPKCS1SignatureDeformatter def = (RSAPKCS1SignatureDeformatter)certificate.PrivateKey;
//Display the origianl data to the console.
Console.WriteLine("Original Data: {0}", dataString);
//Encrypt the byte array and specify no OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
encryptedData = RSAalg.Encrypt(dataToEncrypt, false);
signedData = RSAalg.SignData(dataToEncrypt, new SHA1CryptoServiceProvider());
//Display the encrypted data to the console.
Console.WriteLine("Encrypted Data: {0}", ByteConverter.GetString(encryptedData));
Console.WriteLine("Signed Data: {0}", ByteConverter.GetString(signedData));
//Pass the data to ENCRYPT and boolean flag specifying
//no OAEP padding.
decryptedData = RSAalg.Decrypt(encryptedData, false);
//In the next line I get the error of wrong data
unsignedData = RSAalg.Decrypt(signedData, false);
//Display the decrypted plaintext to the console.
Console.WriteLine("Decrypted plaintext: {0}", ByteConverter.GetString(decryptedData));
Console.WriteLine("Unsigned plaintext: {0}", ByteConverter.GetString(unsignedData));
}
catch (CryptographicException e)
{
//Catch this exception in case the encryption did
//not succeed.
Console.WriteLine(e.Message);
}
Console.Read();
}
SHA1 is a hash function, so you cant compute a message that has a given hash. In other words, you cant sign/unsign the message, you only can sign and verify it.
I am developing an application in java for a mobile platform. The program uses data from a Windows C# application which encrypts passwords in an online database which the mobile app will use.
The mobile app needs to connect to the database and retrieve the encrypted string from the database and decrypt it.
I have the decryption working fine using the following code
public String decrypt(String encryptedPassword)
{
String plainPassword = "";
try
{
SecretKeySpec key = new SecretKeySpec("hcxilkqbbhczfeultgbskdmaunivmfuo".getBytes("US-ASCII"), "AES");
IvParameterSpec iv = new IvParameterSpec("ryojvlzmdalyglrj".getBytes("US_ASCII"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] encoded = cipher.doFinal(Base64.decodeBase64(encryptedPassword.getBytes()));
plainPassword = new String(encoded);
}
catch (Exception ex)
{
Log.d("Decryption Error", ex.toString());
}
return plainPassword;
}
The decryption works absolutely fine so I have used the same code from the decryption for the encryption but changed the cipher mode from decrypt to encrypt. However, when I print to the console the encrypted password it prints a load of rubbish which shows no resemblance the string that should be stored in the database.
I have used the following code in order to do the encryption
public String encrypt(String plainPasword)
{
String password = "";
try
{
SecretKeySpec key = new SecretKeySpec("hcxilkqbbhczfeultgbskdmaunivmfuo".getBytes("US-ASCII"), "AES");
IvParameterSpec iv = new IvParameterSpec("ryojvlzmdalyglrj".getBytes("US_ASCII"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] encoded = cipher.doFinal(plainPasword.getBytes());
password = new String(encoded);
}
catch (Exception ex)
{
Log.d("Encryption Error", ex.toString());
}
return password;
}
Thanks for any help you can give me
In the decryption function you are calling
byte[] encoded = cipher.doFinal(Base64.decodeBase64(encryptedPassword.getBytes()));
so you are converting ASCII bytes to Base64 bytes, then decrypting them.
Wouldn't you do the same in the reverse, when you actually call only
byte[] encoded = cipher.doFinal(plainPasword.getBytes());
You also are creating new String() from byte[] array without specifying encoding, that uses platform's default encoding, not ASCII. That might break stuff too.
If you look at the bytes returned by cipher.doFinal() that's supposed to be gibberish, don't they have any resemblance to the expected data?