I'm migrating/converting/rebuilding a Windows Phone 7.1 app to a Windows 8 Store App.
One method I am using in de WP7 app is giving me trouble:
private byte[] GetSHA256Key(string data, string secretKey)
{
byte[] value = Encoding.UTF8.GetBytes(data);
byte[] secretKeyBytes = Encoding.UTF8.GetBytes(secretKey);
HMACSHA256 hmacsha256 = new HMACSHA256(secretKeyBytes);
byte[] resultBytes = hmacsha256.ComputeHash(value);
return resultBytes;
}
Looking at the documentation for Windows Store Apps I came up with this new code which I hoped would give the same result. But, no. I'm doing something wrong. But what?
private byte[] GetSHA256Key(string value, string secretKey)
{
// Create a MacAlgorithmProvider object for the specified algorithm.
MacAlgorithmProvider objMacProv = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha256);
// Create a buffer that contains the message to be signed.
IBuffer valueBuffer = CryptographicBuffer.ConvertStringToBinary(value, BinaryStringEncoding.Utf8);
// Create a key to be signed with the message.
IBuffer buffKeyMaterial = CryptographicBuffer.ConvertStringToBinary(secretKey, BinaryStringEncoding.Utf8);
CryptographicKey cryptographicKey = objMacProv.CreateKey(buffKeyMaterial);
// Sign the key and message together.
IBuffer bufferProtected = CryptographicEngine.Sign(cryptographicKey, valueBuffer);
DataReader dataReader = DataReader.FromBuffer(bufferProtected);
byte[] bytes = new byte[bufferProtected.Length];
dataReader.ReadBytes(bytes);
return bytes;
}
I'm not an expert on Cryptography. I'm not sure what I'm doing. Maybe there is somebody out there who can help me.
Thanx,
JP
using System.Runtime.InteropServices.WindowsRuntime;
private string GetSHA256Key(byte[] secretKey, string value)
{
var objMacProv = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha256);
var hash = objMacProv.CreateHash(secretKey.AsBuffer());
hash.Append(CryptographicBuffer.ConvertStringToBinary(value, BinaryStringEncoding.Utf8));
return CryptographicBuffer.EncodeToBase64String(hash.GetValueAndReset());
}
new HMACSHA256(keydata) uses a key as input, while MacAlgorithmProvider.CreateKey() uses input as 'Random data used to help generate the key', which is not a key for HMAC algorithm.
Related
I am passing a public key from a UWP application:
// Open the algorithm provider for the specified asymmetric algorithm.
AsymmetricKeyAlgorithmProvider objAlgProv = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
// Create an asymmetric key pair.
CryptographicKey keyPair = objAlgProv.CreateKeyPair(512);
// Export the public key to a buffer for use by others.
// Default X509SubjectPublicKeyInfo format
IBuffer buffPublicKey = keyPair.ExportPublicKey();
byte[] publicKey = null;
CrytographicBuffer.CopyToByteArray(buffPublicKey, out publicKey);
Conver.ToBase64String(publicKey);
The above string is sent to my Azure function App.
Here is a snippet of my Azure function app code:
// Algorithm = RsaPkcs1
// Key Length = 512
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(512))
{
byte[] bPublicKey = Convert.FromBase64String(publickey);
byte[] bExponent = {1, 0, 1};
RSAParameters RSAKeyInfo = new RSAParameters() { Modulus = bPublicKey, Exponent = bExponent };
RSA.ImportParameters(RSAKeyInfo);
try
{
return RSA.Encrypt(sessionCode, System.Security.Cryptography.RSAEncryptionPadding.Pkcs1);
}
catch (Exception errenc)
{
}
return null;
}
I am trying to encrypt a value with public key and return.
I am running into issues with my Azure Function App and UWP Integration.
Azure side encrypts with the public key; no error is generated. Encrypted value is sent back to UWP. When I go to decrypt on the UWP side I get error "Value does not fall within the expected range."
Any help is appreciated. Having difficulty with the public key aspect on the azure side.
Thanks again
I've been reading this article from MSDN on Rfc2898DeriveBytes. Here is the sample encryption code they provide.
string pwd1 = passwordargs[0];
// Create a byte array to hold the random value.
byte[] salt1 = new byte[8];
using (RNGCryptoServiceProvider rngCsp = ne RNGCryptoServiceProvider())
{
// Fill the array with a random value.
rngCsp.GetBytes(salt1);
}
//data1 can be a string or contents of a file.
string data1 = "Some test data";
//The default iteration count is 1000 so the two methods use the same iteration count.
int myIterations = 1000;
try
{
Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pwd1,salt1,myIterations);
Rfc2898DeriveBytes k2 = new Rfc2898DeriveBytes(pwd1, salt1);
// Encrypt the data.
TripleDES encAlg = TripleDES.Create();
encAlg.Key = k1.GetBytes(16);
MemoryStream encryptionStream = new MemoryStream();
CryptoStream encrypt = newCryptoStream(encryptionStream, encAlg.CreateEncryptor(), CryptoStreamMode.Write);
byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(data1);
encrypt.Write(utfD1, 0, utfD1.Length);
encrypt.FlushFinalBlock();
encrypt.Close();
byte[] edata1 = encryptionStream.ToArray();
k1.Reset();
My question is, how would I properly Read/Write the hashed data to/from a text file?
My main goal is to do what this developer is doing. I need to store a password locally. When my application prompts the user for the password, the user will enter the password, then my application will read from the text file and verify if the password that the user entered is indeed correct. How would I go about doing it?
You typically store the hash of the password, then when user enters password, you compute hash over the entered password and compare it with the hash which was stored - that said, just hashing is usually not enough (from security point of view) and you should use a function such as PKBDF2 (Password-Based Key Derivation Function 2) instead. Here is article covering all that information in more elaborate way as well as sample code (bottom of the page): http://www.codeproject.com/Articles/704865/Salted-Password-Hashing-Doing-it-Right
Here is a link to codereview, which I guess refers to the same implementation as above article.
How to properly store password locally
Just don't do it. No really don't do it.
...But if you really really have to, never just implement it yourself. I would recommend reviewing how ASP.NET Identity hashes passwords. Version 3 is pretty rock solid at the moment:
note that the following is taken from github.com and may be changed at any time. For the latest, please refer to the previous link.
private static byte[] HashPasswordV3(string password, RandomNumberGenerator rng, KeyDerivationPrf prf, int iterCount, int saltSize, int numBytesRequested)
{
// Produce a version 3 (see comment above) text hash.
byte[] salt = new byte[saltSize];
rng.GetBytes(salt);
byte[] subkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, numBytesRequested);
var outputBytes = new byte[13 + salt.Length + subkey.Length];
outputBytes[0] = 0x01; // format marker
WriteNetworkByteOrder(outputBytes, 1, (uint)prf);
WriteNetworkByteOrder(outputBytes, 5, (uint)iterCount);
WriteNetworkByteOrder(outputBytes, 9, (uint)saltSize);
Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.Length);
Buffer.BlockCopy(subkey, 0, outputBytes, 13 + saltSize, subkey.Length);
return outputBytes;
}
You should store the password as a one-way hash and the salt used to create that password. This way you are absolutely sure that the password for the user can never be DECRYPTED. Never use any two-way encryption for this particular task, as you risk exposing user information to would-be attackers.
void Main()
{
string phrase, salt, result;
phrase = "test";
result = Sha256Hash(phrase, out salt);
Sha256Compare(phrase, result, salt);
}
public string Sha256Hash(string phrase, out string salt)
{
salt = Create256BitSalt();
string saltAndPwd = String.Concat(phrase, salt);
Encoding encoder = Encoding.Default;
SHA256Managed sha256hasher = new SHA256Managed();
byte[] hashedDataBytes = sha256hasher.ComputeHash(encoder.GetBytes(saltAndPwd));
string hashedPwd = Encoding.Default.GetString(hashedDataBytes);
return hashedPwd;
}
public bool Sha256Compare(string phrase, string hash, string salt)
{
string saltAndPwd = String.Concat(phrase, salt);
Encoding encoder = Encoding.Default;
SHA256Managed sha256hasher = new SHA256Managed();
byte[] hashedDataBytes = sha256hasher.ComputeHash(encoder.GetBytes(saltAndPwd));
string hashedPwd = Encoding.Default.GetString(hashedDataBytes);
return string.Compare(hash, hashedPwd, false) == 0;
}
public string Create256BitSalt()
{
int _saltSize = 32;
byte[] ba = new byte[_saltSize];
RNGCryptoServiceProvider.Create().GetBytes(ba);
return Encoding.Default.GetString(ba);
}
You could also figure out another method for obtaining the salt, but I have made mine to that it computes 2048 bits worth of random data. You could just use a random long you generate but that would be a lot less secure. You won't be able to use SecureString because SecureString isn't Serializable. Which the whole point of DPAPI. There are ways to get the data out but you end up having to jump a few hurdles to do it.
FWIW, PBKDF2 (Password-Based Key Derivation Function 2) is basically the same thing as SHA256 except slower (a good thing). On its own both are very secure. If you combined PBKDF2 with an SHA256 as your salt then you'd have a very secure system.
I am encrypting the message in .NET with RSACryptoServiceProvider with private key. (PKCS#1 v1.5)
When I try to decrypt in .NET with the following code that uses public key everything works fine:
private static string Decrypt(string key, string content)
{
byte[] rgb = Convert.FromBase64String(content);
var cryptoServiceProvider = new RSACryptoServiceProvider(new CspParameters()
{
ProviderType = 1
});
cryptoServiceProvider.ImportCspBlob(Convert.FromBase64String(key));
return Convert.ToBase64String(cryptoServiceProvider.Decrypt(rgb, false));
}
When on the other hand I try to find an algorithm to make the same decrypt method in Android, I am failing to decrypt it properly with public key. I exported the modulus and exponent from public key in .NET in order to load it properly on Android.
The method in Android is here:
public String Decrypt(String input) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
String modulusString = "mmGn1IXB+/NEm1ecLiUzgz7g2L6L5EE5DUcptppTNwZSqxeYKn0AuAccupL0iyX3LMPw6Dl9pjPXDjk93TQwYwyGgZaXOSRDQd/W2Y93g8erpGBRm/Olt7QN2GYhxP8Vn+cWUbNuikdD4yMfYX9NeD9UNt5WJGFf+jRkLk0zRK0A7ZIS+q0NvGJ/CgaRuoe3x4Mh1qYP9ZWNRw8rsDbZ6N2zyUa3Hk/WJkptRa6jrzc937r3QYF3eDTurVJZHwC7c3TJ474/8up3YNREnpK1p7hqwQ78fn35Tw4ZyTNxCevVJfYtc7pKHHiwfk36OxtOIesfKlMnHMs4vMWJm79ctixqAe3i9aFbbRj710dKAfZZ0FnwSnTpsoKO5g7N8mKY8nVpZej7tcLdTL44JqWEqnQkocRqgO/p3R8V/6To/OjQGf0r6ut9y/LnlM5qalnKJ1gFg1D7gCzZJ150TX4AO5kGSAFRyjkwGxnR0WLKf+BDZ8T/syOrFOrzg6b05OxiECwCvLWk0AaQiJkdu2uHbsFUj3J2BcwDYm/kZiD0Ri886xHqZMNExZshlIqiecqCskQhaMVC1+aCm+IFf16Qg/+eMYCd+3jm/deezT4rcMBOV/M+muownGYQ9WOdjEK53h9oVheahD3LqCW8MizABFimvXR3wAgkIUvhocVhSN0=";
String exponentString = "AQAB";
byte[] modulusBytes = Base64.decode(modulusString.getBytes("UTF-8"), Base64.DEFAULT);
byte[] dBytes = Base64.decode(exponentString.getBytes("UTF-8"), Base64.DEFAULT);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger d = new BigInteger(1, dBytes);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, d);
PublicKey key = keyFactory.generatePublic(keySpec);
//at one point I read somewhere that .net reverses the byte array so that it needs to be reversed for java, but who knows any more
/*byte[] inputArrayReversed = Base64.decode(input.getBytes("UTF-8"), Base64.DEFAULT);
for (int i = 0; i < inputArrayReversed.length / 2; i++) {
byte temp = inputArrayReversed[i];
inputArrayReversed[i] = inputArrayReversed[inputArrayReversed.length - 1];
inputArrayReversed[inputArrayReversed.length - 1] = temp;
}*/
byte[] decryptedText = null;
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
decryptedText = cipher.doFinal(Base64.decode(input.getBytes("UTF-8"), Base64.DEFAULT));
return Base64.encodeToString(decryptedText, Base64.NO_WRAP);
//return new String(decryptedText, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
Actually I tried also with different algorithms specified in Cypher class, also tried many other combinations, tried using SpongyCastle instead of built in Android RSA providers, but nothing worked. If anybody has any clue to point me in right direction, I would be absolutely grateful.
First hint is that decrypted string from .NET comes as around 25 characters long, and when I get Android to return decrypted string without exceptions it is usually much longer, around 500 bytes.
Second hint deleted
Third hint I also tried spongycastle, but it didn't help that much
Anyways, thank you in advance for any help!!!
UPDATE 1
Second hint is deleted because was wrong, disregard it. Now I have one question if the following can prove that the public key is loaded correctly, just to rule that problem out.
BigInteger modulus and exponent in the upper Android code and the following BigIntegers in .NET show equal integer values.
var parameters = csp.ExportParameters(false);
var modulusInteger = new BigInteger(parameters.Modulus.Reverse().Concat(new byte[] { 0 }).ToArray());
var exponentInteger = new BigInteger(parameters.Exponent.Reverse().Concat(new byte[] { 0 }).ToArray());
UPDATE 2
This and This SO answers provide some interesting clues
Heeh, the mistake was one of the basics, we had an architecture where we were doing encryption with public key and decryption with private key. The problem was in the architecture itself because as we initially set it up, we were sending private keys to all our client apps, which is big security flaw.
My mistake was that I assumed that on the client we have public key and actually from private key all the time I was trying to load the public key and then do decrypt.
If I knew the PKI in depth and communicated a bit better with my colleague, I could have noticed few things:
Decrypt can be done with private key only, while one the other hand verify can be done with public key, so when I saw Decrypt being used on client in .NET, I should have assumed that on the client we have private key (which is a security flaw in the end in the way we want to use PKI)
Few things that I already knew or learnt and want to share with others:
Private key should be kept secret, whether you want to have it on server or preferably only on one client because public key can easily be guessed from private key and then someone can easily repeat your whole encryption process easily and breach your security
PKI works for two scenarios:
First scenario is when you want to Encrypt something and that only specific person/computer can Decrypt it. In first scenario as you see, many stakeholders can have someone's Public key and send messages to him and that only he can read them with his Private key. Second scenario is when you want to be sure that the message that came to you was not altered and was sent by specific person/computer. In that case you Sign data with Private key and Verify it on the other end with Public key. The only process that is suitable for us is Sign <-> Verify because we send plain text license with signature in it, and thus on the client we want to be sure that nobody tampered with the plain text license and that it came from us.
In your code, if Decrypt or Verify functions throw exceptions in 50% of the time it is because of loading the incorrect key or incorrectly loading the correct key and in the other 50% it is because you are using the incorrect algorithm or because algorithm parameters are incorrectly set or because the algorithm implementations between platforms are incompatible (the last one is very rare)
.NET server code
public string Sign(string privateKey, string data)
{
_rsaProvider.ImportCspBlob(Convert.FromBase64String(privateKey));
//// Write the message to a byte array using UTF8 as the encoding.
var encoder = new UTF8Encoding();
byte[] byteData = encoder.GetBytes(data);
//// Sign the data, using SHA512 as the hashing algorithm
byte[] encryptedBytes = _rsaProvider.SignData(byteData, new SHA1CryptoServiceProvider());
return Convert.ToBase64String(encryptedBytes);
}
.NET client code (Win Mobile)
private bool Verify(string key, string signature, string data)
{
CspParameters cspParams = new CspParameters { ProviderType = 1 };
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(cspParams);
rsaProvider.ImportCspBlob(Convert.FromBase64String(key));
byte[] signatureBytes = Convert.FromBase64String(signature);
var encoder = new UTF8Encoding();
byte[] dataBytes = encoder.GetBytes(data);
return rsaProvider.VerifyData(dataBytes, new SHA1CryptoServiceProvider(), signatureBytes);
}
Android client code:
public boolean Verify(RSAPublicKey key, String signature, String data)
{
try
{
Signature sign = Signature.getInstance("SHA1withRSA");
sign.initVerify(key);
sign.update(data.getBytes("UTF-8"));
return sign.verify(Base64.decode(signature.getBytes("UTF-8"), Base64.NO_WRAP));
}
catch (Exception e)
{
e.printStackTrace();
}
return false;
}
in .NET public key is exported in xml format with following code:
public string ExportPublicToXML(string publicKey)
{
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(new CspParameters()
{
ProviderType = 1
});
csp.ImportCspBlob(Convert.FromBase64String(publicKey));
return csp.ToXmlString(false);
}
and then modulus and exponent are used in Android to load public key:
private RSAPublicKey GetPublicKey(String keyXmlString) throws InvalidKeySpecException, UnsupportedEncodingException, NoSuchAlgorithmException
{
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
String modulusString = keyXmlString.substring(keyXmlString.indexOf("<Modulus>"), keyXmlString.indexOf("</Modulus>")).replace("<Modulus>", "");
String exponentString = keyXmlString.substring(keyXmlString.indexOf("<Exponent>"), keyXmlString.indexOf("</Exponent>")).replace("<Exponent>", "");
byte[] modulusBytes = Base64.decode(modulusString.getBytes("UTF-8"), Base64.DEFAULT);
byte[] dBytes = Base64.decode(exponentString.getBytes("UTF-8"), Base64.DEFAULT);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger d = new BigInteger(1, dBytes);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, d);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}
We have a Windows Phone 8 app that needs to communicate with a web service that uses Chilkat to encrypt some data. As far as I know, Chilkat does not support the Windows Phone platform. I have the key and other info about how the data is encrypted (such as the encryption algorithm name, key-length etc.), but will I be able to encrypt/decrypt on Windows Phone without having this library? (We already have android/ios apps that use the same service and they use the chilkat library to crypt the data)
class Program
{
static readonly string keyString = "MyKey";
static readonly string iv = "MyIV";
static Encoding TheEncoding = Encoding.UTF8;
static void Main(string[] args)
{
//I got Chilkat and BouncyCastle via NuGet
//https://www.nuget.org/packages/WinRTBouncyCastle/0.1.1.1
//chilcat-win32
var original = "clear text";
var chilkatCrypt = GetChilkat3Des();
//this is equalent to an encrypted text I get from the service
var ckEncrypted = chilkatCrypt.EncryptStringENC(original);
var ckDecrypted = chilkatCrypt.DecryptStringENC(ckEncrypted);
if (!string.Equals(original, ckDecrypted)) throw new ArgumentException("chilkat encrypt/decrypt failure...");
//now comes the challenge, to decrypt the Chilkat encryption with BouncyCastle (or what ever crypto lib that runs on WP8)
//this is where i need help :)
byte[] chilkatEncBytes = System.Text.Encoding.UTF8.GetBytes(ckEncrypted);
var bouncyDecrypted = BouncyCastleDecrypt(chilkatEncBytes);
}
public static Chilkat.Crypt2 GetChilkat3Des()
{
var crypt = new Chilkat.Crypt2();
if (!crypt.UnlockComponent("Start my 30-day Trial"))
{
throw new Exception("Unlock Chilkat failed");
}
crypt.CryptAlgorithm = "3des";
crypt.CipherMode = "cbc";
crypt.KeyLength = 192;
crypt.PaddingScheme = 0;
// It may be "hex", "url", "base64", or "quoted-printable".
crypt.EncodingMode = "hex";
crypt.SetEncodedIV(iv, crypt.EncodingMode);
crypt.SetEncodedKey(keyString, crypt.EncodingMode);
return crypt;
}
//this code is more or less copied from here:
//http://nicksnettravels.builttoroam.com/post/2012/03/27/TripleDes-Encryption-with-Key-and-IV-for-Windows-Phone.aspx
public static byte[] RunBouncyCastleTripleDes(byte[] input, bool encrypt)
{
byte[] byteKey = new byte[24];
Buffer.BlockCopy(TheEncoding.GetBytes(keyString), 0, byteKey, 0, TheEncoding.GetBytes(keyString).Length);
var IV = new byte[8];
Buffer.BlockCopy(TheEncoding.GetBytes(iv), 0, IV, 0, TheEncoding.GetBytes(iv).Length);
var keyParam = new Org.BouncyCastle.Crypto.Parameters.DesEdeParameters(byteKey);
var ivParam = new Org.BouncyCastle.Crypto.Parameters.ParametersWithIV(keyParam, IV);
var engine = Org.BouncyCastle.Security.CipherUtilities.GetCipher("DESede/CBC/PKCS5Padding");
engine.Init(encrypt, ivParam);
var output = engine.DoFinal(input);
return output;
}
public static byte[] BouncyCastleEncrypt(byte[] input)
{
return RunBouncyCastleTripleDes(input, true);
}
public static byte[] BouncyCastleDecrypt(byte[] input)
{
return RunBouncyCastleTripleDes(input, false);
}
}
I have the key and other info about how the data is encrypted (such as the encryption algorithm name, key-length etc.), but will I be able to encrypt/decrypt on Windows Phone without having this library?
It depends, buts the answer is probably yes.
If they have a home-grown implementation of well known algorithms, then they might have a bug and the answer could be NO.
If they are using well-known algorithms form well vetted libraries and have fully specified the algorithms and parameters, the the answer is likely YES.
I have a requirement, where I need to encrypt my connection string in one application and decrypt it in another. With this in mind, I save the public key and private keys in App.Config of the application respectively.
Now, shouldn't RSA should give me same encrypted string with same keys which I use?
I get different encrypted strings all the time, with same keys used.!! Please help me to clear the confusion. I am not understanding how I can solve this problem, that I get BAD Data exception if I use the saved encrypted string, as every time the encryption gives me different encrypted strings.
Here is my code:
private string connecString;
private RSACryptoServiceProvider rsaEncryptDecrypt;
public EncryptAndDecrypt(string connecString)
{
this.connecString = connecString;
this.rsaEncryptDecrypt = new RSACryptoServiceProvider(4096);
}
public string EncryptTheConnecString(string publicKeyValue)
{
byte[] encryptedData;
rsaEncryptDecrypt.FromXmlString(publicKeyValue);
byte[] message = Encoding.UTF8.GetBytes(connecString);
encryptedData = rsaEncryptDecrypt.Encrypt(message, false);
return Convert.ToBase64String(encryptedData);
}
public string DecryptTheConnecString(string privateKeyValue, string encrystr)
{
byte[] decryptedData;
rsaEncryptDecrypt.FromXmlString(privateKeyValue);
byte[] message = Convert.FromBase64String(encrystr);
decryptedData = rsaEncryptDecrypt.Decrypt(message, false);
return Encoding.UTF8.GetString((decryptedData));
}
Thank you in advance.
Update 1:
I used
UnicodeEncoding ByteConverter = new UnicodeEncoding();
ByteConverter.GetBytes("data to encrypt");
//Which is not Connection string but a small test str
Still I see that the encrypted data is changing everytime.
But the Bad Data error is no more seen. Yet I cannot use UTF16(UnicodeEncoding) over Encoding.UTF8 because it cannot encrypt the huge string like connection string and throws an exception:
CryptographicException: Key not valid for use in specified state.
Update 2:
I could solve the problem of bad data by using UTF8Encoding ByteConverter = new UTF8Encoding(); and then doing ByteConverter .GetString("HUGE STRING");
It can happen because of Random Padding.
In general the answer to your question is yes, it should always produce the same result if the same parameters are given.
The best way to tackle these issues is to stay as close to the best practice code as possible, currently you a using the crypto provider slightly different than the framework docs propose, see the following:
static public byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
{
byte[] encryptedData;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Import the RSA Key information. This only needs
//toinclude the public key information.
RSA.ImportParameters(RSAKeyInfo);
//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;
}
This is an excerpt from the official MSDN doc:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx
First try and adopt the best practice and then see if this issue still comes up.