Search code examples
c#cryptographyrsa

Signing a byte array of 128 bytes with RSA in C sharp


I am completely new to cryptography and I need to sign a byte array of 128 bytes with an RSA key i have generated with C sharp. The key must be 1024 bits.

I have found a few examples of how to use RSA with C sharp and the code I'm currently trying to use is:

public static void AssignParameter()
{
    const int PROVIDER_RSA_FULL = 1;
    const string CONTAINER_NAME = "SpiderContainer";
    CspParameters cspParams;
    cspParams = new CspParameters(PROVIDER_RSA_FULL);
    cspParams.KeyContainerName = CONTAINER_NAME;
    cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
    cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";
    rsa = new RSACryptoServiceProvider(cspParams);
    rsa.KeySize = 1024;
}

public static string EncryptData(string data2Encrypt)
{
    AssignParameter();
    StreamReader reader = new StreamReader(path + "publickey.xml");
    string publicOnlyKeyXML = reader.ReadToEnd();
    rsa.FromXmlString(publicOnlyKeyXML);
    reader.Close();

    //read plaintext, encrypt it to ciphertext

    byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(data2Encrypt);
    byte[] cipherbytes = rsa.Encrypt(plainbytes, false);
    return Convert.ToBase64String(cipherbytes);
}

This code works fine with small strings (and thus short byte arrays) but when I try this with a string of 128 characters I get an error saying: CryptographicException was unhandled: Wrong length (OK, it might not precisely say 'Wrong length', I get the error in danish, and that is 'Forkert længde' which directly translates to 'Wrong length').

Can anyone tell me how I can encrypt a byte array of 128 bytes with a RSA key of 1024 bits in C sharp?

Thanks in advance, LordJesus

EDIT:

Ok, just to clarify things a bit: I have a message, from which i make a hash using SHA-256. This gives a 32 byte array. This array is padded using a custom padding, so it ends up being a 128 byte array. This padded hash should then be signed with my private key, so the receiver can use my public key to verify that the message received is the same as the message sent. Can this be done with a key of 1024 bits?


Solution

  • The minimum key size for encrypting 128 bytes would be 1112 bits, when you are calling Encrypt with OAEP off. Note that setting the key size like this rsa.KeySize = 1024 won't help, you need to actually generate they key of the right size and use them.

    This is what worked for me:

    using System;
    using System.IO;
    using System.Security.Cryptography;
    
    namespace SO6299460
    {
        class Program
        {
            static void Main()
            {
                GenerateKey();
                string data2Encrypt = string.Empty.PadLeft(128,'$');
                string encrypted = EncryptData(data2Encrypt);
                string decrypted = DecryptData(encrypted);
    
                Console.WriteLine(data2Encrypt);
                Console.WriteLine(encrypted);
                Console.WriteLine(decrypted);
            }
    
            private const string path = @"c:\";
        
            public static void GenerateKey()
            {
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1112);
                string publickKey = rsa.ToXmlString(false);
                string privateKey = rsa.ToXmlString(true);
    
                WriteStringToFile(publickKey, path + "publickey.xml");
                WriteStringToFile(privateKey, path + "privatekey.xml");
            }
    
            public static void WriteStringToFile(string value, string filename)
            {
                using (FileStream stream = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.Read))
                using (StreamWriter writer = new StreamWriter(stream))
                {
                    writer.Write(value);
                    writer.Flush();
                    stream.Flush();
                }
            }
        
            public static string EncryptData(string data2Encrypt)
            {
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                StreamReader reader = new StreamReader(path + "publickey.xml");
                string publicOnlyKeyXML = reader.ReadToEnd();
                rsa.FromXmlString(publicOnlyKeyXML);
                reader.Close();
    
                //read plaintext, encrypt it to ciphertext
    
                byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(data2Encrypt);
                byte[] cipherbytes = rsa.Encrypt(plainbytes,false);
    
                return Convert.ToBase64String(cipherbytes);
            }
    
            public static string DecryptData(string data2Decrypt)
            {
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                StreamReader reader = new StreamReader(path + "privatekey.xml");
                string key = reader.ReadToEnd();
                rsa.FromXmlString(key);
                reader.Close();
    
                byte[] plainbytes = rsa.Decrypt(Convert.FromBase64String(data2Decrypt), false);
                return System.Text.Encoding.UTF8.GetString(plainbytes);
    
            }
    
    
        }
    }
    

    Note however, that I'm not using a crypto container, and thus, I don't need your AssignParameter, but if you need to use it, modifying the code should be easy enough.

    If you ever need to encrypt large quantities of data (much larger than 128 bytes) this article has sample code on how to do this.