Purpose of RijndaelManaged instance? - c#

I have Found following Code Sample on MSDN when i was searching for RSACypthyServiceProvider.I couldn't understand some part of thecode with the help of comment.
What is modulus and Exponent ?
What is IV?
Why they are using RijndaelManagedclass to do asymmetric encryption? Based on my search RSACryptoServiceProvider provides Asymmetric encryption functionality and it will automatically creates Private and Public key when we create the object .So What is the Purpose of RijndaelManaged instance here?
Can any one please explain?
Code Sample:
class Class1
{
static void Main()
{
//Initialize the byte arrays to the public key information.
byte[] PublicKey = {Somethink in byte}
byte[] Exponent = {1,0,1};
//Create values to store encrypted symmetric keys.
byte[] EncryptedSymmetricKey;
byte[] EncryptedSymmetricIV;
//Create a new instance of the RSACryptoServiceProvider class.
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
//Create a new instance of the RSAParameters structure.
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);
}
}

RSA is very slow, and has overhead for padding. So it's common to generate a random symmetric key, encrypt it with RSA, and encrypt the message with the symmetric key. This approach is known as hybrid cryptosystem.
IVs are important if a single key is used to encrypt multiple messages, but since this code creates a new key for each message, the IV isn't really important here. Still using an IV can prevent multi-target attacks, so it's not completely useless with unique keys, especially if the key only has 128 bits.
This code is pretty inefficient too: It encrypts IV and key separately, instead of concatenating them. This doubles the RSA overhead.
Modulus and exponent are the two parts of an RSA public key. Look up wikipedia for details. The exponent is often chosen to be 2^16 + 1 = 65537, which corresponds to the {1,0,1} in this code.

Related

Compare two RSA encrypted strings which uses different encoding

I have a string "test_string", which is encrypted using RSA algorithm using two different encodings as shown in the below C# code. I want to check if the encrypted value in both the cases are the same, since I am using the same key in both cases. But due to RSA padding, the encrypted value changes every time even if I am using the same key and the same data "test_string" and same encoding. So, is there any way I can make sure that the encrypted value is same/different by avoid the padding? Any other recommendations are welcome.
string encryptedUTF16;
string encryptedUTF8;
RSA rsa = RSA.Create();
RSAParameters rsaParams = rsa.ExportParameters(true);
using (var rsa1 = new RSACryptoServiceProvider())
{
rsa1.ImportParameters(rsaParams);
byte[] bytesEncrytedKeyUTF16 = Encoding.Unicode.GetBytes("test_string".ToCharArray());
byte[] encrytedKeyUTF16 = rsa1.Encrypt(bytesEncrytedKeyUTF16, true);
encryptedUTF16 = Convert.ToBase64String(encrytedKeyUTF16);
Console.WriteLine(encryptedUTF16);
}
using (var rsa2 = new RSACryptoServiceProvider())
{
rsa2.ImportParameters(rsaParams);
byte[] bytesEncrytedKeyUTF8 = Encoding.UTF8.GetBytes("test_string".ToCharArray());
byte[] encrytedKeyUTF8 = rsa2.Encrypt(bytesEncrytedKeyUTF8, true);
encryptedUTF8 = Convert.ToBase64String(encrytedKeyUTF8);
Console.WriteLine(encryptedUTF8);
}
I tried using OpenSSl and BouncyCastle as well. But ran into technical issues running them.

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”).

Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException when Decrypting RSA in C#

I'm testing RSA in C# dotnet core. I create two RSA objects, one for encrypting and the other for decrypting. I export the public key from the first rsa object and import it for the other object. When the second one decrypt the cipher array, it throws Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException.
The code is below:
String plainstr = "Hello World";
RSA rsa1 = RSA.Create();
RSA rsa2 = RSA.Create();
rsa1.KeySize = 1024;
rsa2.KeySize = 1024;
byte[] cipherbytes = rsa1.Encrypt(Encoding.ASCII.GetBytes(plainstr), RSAEncryptionPadding.Pkcs1);
//If the parameter is true, it works well. But when I use it in an actual project, I won't pass the private key.
RSAParameters parameters = rsa1.ExportParameters(false);
rsa2.ImportParameters(parameters);
//Exception is here.
byte[] plaintbytes = rsa2.Decrypt(cipherbytes, RSAEncryptionPadding.Pkcs1);
Console.WriteLine(Encoding.ASCII.GetString(plaintbytes));
Console.ReadKey();
This is how RSA Encryption works. You can Encrypt with the public key but you can only Decrypt with the private key.
In your example you are encrypting the string with the private key of the rsa1 object, you are copying the public parameters of it to rsa2 and you are trying to decrypt with it.
Maybe you want to do the opposite?

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).

How to use c# to decrypt an MD5 hash that is encrypted using RSA1024

I trying to verify the integrity of a file at work and an having a hard time of it. I'm not very well versed with encryption and hashing, so bear with me.
I have some files that have an MD5 hash located at the end of them. I have written code to grab the bytes that I think are the hash and they seen to be uniformly 128 bytes long. In the file, just before the hash, is the keyword "RSA1024", which I have taken to mean the hash is encrypted using RSA 1024.
I have what I know is the RSA key in a file, and have read out the bytes (always 258 bytes long). I have seen many tutorials which use FromXmlString() to pull in the key, but this RSA key was not generated using the .net framework, and is not in an XML format.
I have written the following method to decrypt the hash data using the key, and it throws this error when executing ImportCspBlob() - System.Security.Cryptography.CryptographicException: Bad Version of provider.
Any ideas?
public byte[] DecryptRSA(byte[] encryptedData, byte[] keyData)
{
CspParameters param = new CspParameters();
param.Flags = CspProviderFlags.UseExistingKey;
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(param);
rsaProvider.ImportCspBlob(keyData);
byte[] decryptedData = rsaProvider.Decrypt(encryptedData, false);
return decryptedData;
}
Basic Algorithm
It may sound strange to want to "decrypt an MD5 hash", and especially when one says that they want to "decrypt it with a public key". But that is how digital signatures work. With RSA you can:
encrypt with private key
decrypt with the public key
The message digest is encrypted with the private key, and can then only be decrypted with the public key. That way you know that only the person with the private key could have signed the message.
Your key is most likely not a CSP-type key (it is most likely DER encoded). You can decrypt it using Bouncy Castle with the DER key like this:
RsaPrivateCrtKeyParameters privateKey = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(key);
byte[] rv = null;
RsaEngine eng = new RsaEngine();
eng.Init(false, privateKey);
int size = eng.GetOutputBlockSize();
rv = eng.ProcessBlock(cipher, 0, cipher.Length);
EDIT: to addressing GregS scenario that it may be a signature verify operation
If you are trying to verify a signature, you would need a certificate used to verify a message, the original message text, and the existing message signature to compare against.
What you do is pass in the original message text (minus the signature), the bytes of the message signature, and the path to the certificate you will use to verify the passed in signature.
Then, you will hash the original message and compare the result against the passed in signature.
Here is some code to illustrate:
private bool VerifySignature(string messageText, byte[] messageSignature, string certificatePath)
{
// Load the certificate from a file
X509Certificate2 cert = new X509Certificate2(certificatePath);
// Get public key
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PublicKey.Key;
// Next, hash the messageText
SHA1Managed sha1 = new SHA1Managed();
byte[] messageBytes = Encoding.Unicode.GetBytes(messageText);
byte[] hash = sha1.ComputeHash(messageBytes);
// Verify the signature with the hash
return csp.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"), messageSignature);
}
MD5 is one-way hash. But you might check out hashing algorithm. There are some ways to break this hash, just do some research ;)

Categories

Resources