Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CryptographicException intermittently occurs when encrypting/decrypting with RSA

I'm trying to encrypt and decrypt data using RSA in C#. I have the following MSTest unit test:

const string rawPassword = "mypass";

// Encrypt
string publicKey, privateKey;
string encryptedPassword = RSAUtils.Encrypt(rawPassword, out publicKey, out privateKey);
Assert.AreNotEqual(rawPassword, encryptedPassword,
    "Raw password and encrypted password should not be equal");

// Decrypt
string decryptedPassword = RSAUtils.Decrypt(encryptedPassword, privateKey);
Assert.AreEqual(rawPassword, decryptedPassword,
    "Did not get expected decrypted password");

It fails during decryption, but only sometimes. It seems like whenever I set breakpoints and step through the test, it passes. This made me think perhaps something wasn't finishing in time for decryption to occur successfully, and me slowing stepping through it while debugging gave it enough time to complete. When it fails, the line it seems to fail at is decryptedBytes = rsa.Decrypt(bytesToDecrypt, false); in the following method:

public static string Decrypt(string textToDecrypt, string privateKeyXml)
{
    if (string.IsNullOrEmpty(textToDecrypt))
    {
        throw new ArgumentException(
            "Cannot decrypt null or blank string"
        );
    }
    if (string.IsNullOrEmpty(privateKeyXml))
    {
        throw new ArgumentException("Invalid private key XML given");
    }
    byte[] bytesToDecrypt = ByteConverter.GetBytes(textToDecrypt);
    byte[] decryptedBytes;
    using (var rsa = new RSACryptoServiceProvider())
    {
        rsa.FromXmlString(privateKeyXml);
        decryptedBytes = rsa.Decrypt(bytesToDecrypt, false); // fail here
    }
    return ByteConverter.GetString(decryptedBytes);
}

It fails with this exception:

System.Security.Cryptography.CryptographicException: Bad Data

My Encrypt method is as follows:

public static string Encrypt(string textToEncrypt, out string publicKey,
    out string privateKey)
{
    byte[] bytesToEncrypt = ByteConverter.GetBytes(textToEncrypt);
    byte[] encryptedBytes;
    using (var rsa = new RSACryptoServiceProvider())
    {
        encryptedBytes = rsa.Encrypt(bytesToEncrypt, false);
        publicKey = rsa.ToXmlString(false);
        privateKey = rsa.ToXmlString(true);
    }
    return ByteConverter.GetString(encryptedBytes);
}

The ByteConverter used throughout is just the following:

public static readonly UnicodeEncoding ByteConverter = new UnicodeEncoding();

I've seen a few questions on StackOverflow about RSA encryption and decryption with .NET. This one was due to encrypting with the private key and trying to decrypt with the public key, but I don't think I'm doing that. This question has the same exception as me, but the selected answer was to use OpenSSL.NET, which I would prefer not to do.

What am I doing wrong?

like image 477
Sarah Vessels Avatar asked Jun 30 '10 19:06

Sarah Vessels


1 Answers

Could you replace ByteConverter.GetBytes with Convert.FromBase64String and replace ByteConverter.GetString with Convert.ToBase64String and see if that helps. Bad Data exception usually means that you have an invalid character in the data or that the length is not the correct length for decrypting. I think using the Convert functions might fix your problems.

  public static readonly UnicodeEncoding ByteConverter = new UnicodeEncoding();

  public static string Encrypt(string textToEncrypt, out string publicKey,
    out string privateKey)
  {
     byte[] bytesToEncrypt = ByteConverter.GetBytes(textToEncrypt);
     byte[] encryptedBytes;
     using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
     {
        encryptedBytes = rsa.Encrypt(bytesToEncrypt, false);
        publicKey = rsa.ToXmlString(false);
        privateKey = rsa.ToXmlString(true);
     }
     return Convert.ToBase64String(encryptedBytes);
  }

  public static string Decrypt(string textToDecrypt, string privateKeyXml)
  {
     if (string.IsNullOrEmpty(textToDecrypt))
     {
        throw new ArgumentException(
            "Cannot decrypt null or blank string"
        );
     }
     if (string.IsNullOrEmpty(privateKeyXml))
     {
        throw new ArgumentException("Invalid private key XML given");
     }
     byte[] bytesToDecrypt = Convert.FromBase64String(textToDecrypt);
     byte[] decryptedBytes;
     using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
     {
        rsa.FromXmlString(privateKeyXml);
        decryptedBytes = rsa.Decrypt(bytesToDecrypt, false); // fail here
     }
     return ByteConverter.GetString(decryptedBytes);
  }
like image 159
SwDevMan81 Avatar answered Sep 19 '22 11:09

SwDevMan81