RSA Big Data Encryption in C #

This is my first post, so I hope that I have not missed anything important. I am doing a C # project where I need to use public / private key encryption to encrypt a message, and then send it over an SSL connection.

I decided to use RSACryptoService , as per the documentation, it was the only asymmetric encryption scheme used to encrypt data. The problem is that I have a lot of problems with this. (I wanted to do symmetric encryption, but thatโ€™s not what my teacher wants me to do, and, according to him, it should be easy to just determine the size of the block, and then it should do all the work for you.) Well, not yet I was lucky and I tried different approaches, but now I returned to the basics and try again, this is my current code:

  public string[] GenerateKeysToStrings(string uniqueIdentifier) { string[] keys; using (var rsa = new RSACryptoServiceProvider(4096)) { try { string privateKey = rsa.ToXmlString(true); string publicKey = rsa.ToXmlString(false); this.pki.StoreKey(publicKey, uniqueIdentifier); keys = new string[2]; keys[0] = privateKey; keys[1] = publicKey; } finally { //// Clear the RSA key container, deleting generated keys. rsa.PersistKeyInCsp = false; } } return keys; } 

As you can see, I generate the keys, and I cheat on PKI by sending the public key to a simple class that stores it, and then the private key is written to the file (Note that I also have another method that does the same, but saves it to an array instead, simply because I wanted to check and simplify things, because I get No such key exceptions and sometimes cryptographic exceptions when I do it as shown in the example, so I wanted to simplify it just by saving the line rsa.ToXmlString , as a string in the array, but not behavior lo.)

Now I have an encryption and decryption method as follows:

  public string Encrypt(string keyString, string message) { string encryptedMessage; using (var rsa = new RSACryptoServiceProvider()) { try { //// Load the key from the specified path var encryptKey = new XmlDocument(); encryptKey.Load(@"C:\Test\PrivateKeyInfo.xml"); rsa.FromXmlString(encryptKey.OuterXml); //// Conver the string message to a byte array for encryption //// var encoder = new UTF8Encoding(); ASCIIEncoding byteConverter = new ASCIIEncoding(); byte[] dataToEncrypt = byteConverter.GetBytes(message); byte[] encryptedData = rsa.Encrypt(dataToEncrypt, false); //// Convert the byte array back to a string message encryptedMessage = byteConverter.GetString(encryptedData); } finally { //// Clear the RSA key container, deleting generated keys. rsa.PersistKeyInCsp = false; } } return encryptedMessage; } 

decryption:

  public string Decrypt(string keyString, string message) { string decryptedText; using (var rsa = new RSACryptoServiceProvider()) { try { //// Loads the keyinfo into the rsa parameters from the keyfile /* var privateKey = new XmlDocument(); privateKey.Load(keyString); */ rsa.FromXmlString(keyString); //// Convert the text from string to byte array for decryption ASCIIEncoding byteConverter = new ASCIIEncoding(); var encryptedBytes = byteConverter.GetBytes(message); //// Create an aux array to store all the encrypted bytes byte[] decryptedBytes = rsa.Decrypt(encryptedBytes, false); decryptedText = byteConverter.GetString(decryptedBytes); } finally { //// Clear the RSA key container, deleting generated keys. rsa.PersistKeyInCsp = false; } } return decryptedText; } 

I know this is a wall with text, but I hope you can help me because I have been banging my head on the wall for so long, it's not funny :)

The problem is how can I encrypt messages using RSA (or any other public / private key)

Here is a test client:

  public static void Main(string[] args) { PublicKeyInfrastructure pki = new PublicKeyInfrastructure(); Cryptograph crypto = new Cryptograph(); string[] keys = crypto.GenerateKeysToStrings(" simonlanghoff@gmail.com "); string plainText = "Hello play with me, please"; string publicKey = crypto.GetPublicKey(" simonlanghoff@gmail.com "); string encryptedText = crypto.Encrypt(keys[0], plainText); string decryptedText = crypto.Decrypt(keys[1], encryptedText); } 

As I mentioned, there are string arrays because I wanted to fix a bad parsing error from XML documents ...

When I run the test client, if I use the private key for encryption and the public key for decryption, I get โ€œThe key does not exist exceptionโ€, and if I do it the other way around, I get an exception for bad data.

Please help me guys, if you know about some good guidance or can tell me how to somewhat hide the public / private key encryption implementation in string messages, please help me.

I appreciate any help.

+6
source share
3 answers

This is not how RSA encryption should be performed.

RSA is math. What you are encrypting is a number, so it must be of finite length and match the length of the RSA key pair that you are using. Other length restrictions are imposed by the add-on used (either PKCS # 1 or OAEP).

If you want to encrypt big data using RSA, you need to do it indirectly - for example, use a symmetric key to encrypt big data and encrypt this key using the RSA public key.

You can read about it on my blog .

+5
source

Well, I finally came up with a solution to the problem that I talked about in my original post. This is something that I have not thoroughly tested or something else, but something I understood from a small trial and error process.

Here is the current code that I have:

  public static string Encrypt(string dataToEncrypt, RSAParameters publicKeyInfo) { //// Our bytearray to hold all of our data after the encryption byte[] encryptedBytes = new byte[0]; using (var RSA = new RSACryptoServiceProvider()) { try { //Create a new instance of RSACryptoServiceProvider. UTF8Encoding encoder = new UTF8Encoding(); byte[] encryptThis = encoder.GetBytes(dataToEncrypt); //// Importing the public key RSA.ImportParameters(publicKeyInfo); int blockSize = (RSA.KeySize / 8) - 32; //// buffer to write byte sequence of the given block_size byte[] buffer = new byte[blockSize]; byte[] encryptedBuffer = new byte[blockSize]; //// Initializing our encryptedBytes array to a suitable size, depending on the size of data to be encrypted encryptedBytes = new byte[encryptThis.Length + blockSize - (encryptThis.Length % blockSize) + 32]; for (int i = 0; i < encryptThis.Length; i += blockSize) { //// If there is extra info to be parsed, but not enough to fill out a complete bytearray, fit array for last bit of data if (2 * i > encryptThis.Length && ((encryptThis.Length - i) % blockSize != 0)) { buffer = new byte[encryptThis.Length - i]; blockSize = encryptThis.Length - i; } //// If the amount of bytes we need to decrypt isn't enough to fill out a block, only decrypt part of it if (encryptThis.Length < blockSize) { buffer = new byte[encryptThis.Length]; blockSize = encryptThis.Length; } //// encrypt the specified size of data, then add to final array. Buffer.BlockCopy(encryptThis, i, buffer, 0, blockSize); encryptedBuffer = RSA.Encrypt(buffer, false); encryptedBuffer.CopyTo(encryptedBytes, i); } } catch (CryptographicException e) { Console.Write(e); } finally { //// Clear the RSA key container, deleting generated keys. RSA.PersistKeyInCsp = false; } } //// Convert the byteArray using Base64 and returns as an encrypted string return Convert.ToBase64String(encryptedBytes); } /// <summary> /// Decrypt this message using this key /// </summary> /// <param name="dataToDecrypt"> /// The data To decrypt. /// </param> /// <param name="privateKeyInfo"> /// The private Key Info. /// </param> /// <returns> /// The decrypted data. /// </returns> public static string Decrypt(string dataToDecrypt, RSAParameters privateKeyInfo) { //// The bytearray to hold all of our data after decryption byte[] decryptedBytes; //Create a new instance of RSACryptoServiceProvider. using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider()) { try { byte[] bytesToDecrypt = Convert.FromBase64String(dataToDecrypt); //// Import the private key info RSA.ImportParameters(privateKeyInfo); //// No need to subtract padding size when decrypting (OR do I?) int blockSize = RSA.KeySize / 8; //// buffer to write byte sequence of the given block_size byte[] buffer = new byte[blockSize]; //// buffer containing decrypted information byte[] decryptedBuffer = new byte[blockSize]; //// Initializes our array to make sure it can hold at least the amount needed to decrypt. decryptedBytes = new byte[dataToDecrypt.Length]; for (int i = 0; i < bytesToDecrypt.Length; i += blockSize) { if (2 * i > bytesToDecrypt.Length && ((bytesToDecrypt.Length - i) % blockSize != 0)) { buffer = new byte[bytesToDecrypt.Length - i]; blockSize = bytesToDecrypt.Length - i; } //// If the amount of bytes we need to decrypt isn't enough to fill out a block, only decrypt part of it if (bytesToDecrypt.Length < blockSize) { buffer = new byte[bytesToDecrypt.Length]; blockSize = bytesToDecrypt.Length; } Buffer.BlockCopy(bytesToDecrypt, i, buffer, 0, blockSize); decryptedBuffer = RSA.Decrypt(buffer, false); decryptedBuffer.CopyTo(decryptedBytes, i); } } finally { //// Clear the RSA key container, deleting generated keys. RSA.PersistKeyInCsp = false; } } //// We encode each byte with UTF8 and then write to a string while trimming off the extra empty data created by the overhead. var encoder = new UTF8Encoding(); return encoder.GetString(decryptedBytes).TrimEnd(new[] { '\0' }); } 

As I said, I have not tested it much, except for sizes lower, block sizes and higher, but it looks like it is doing what it should. I'm still a beginner, so I would really like for you to carefully study my code :)

+1
source

Maybe something is missing me, but it looks like your Encrypt () function is not using the keyString parameter or the content of encryptKey .

0
source

Source: https://habr.com/ru/post/903302/


All Articles