tags:

views:

799

answers:

1

The class that produces "Bad Data" errors:


using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;

namespace MyNameSpace
{

  public class RSAcrypt
  {
    private string _encryptedData;
    private string _decryptedData;

    public string EncryptedData
    {
      get { return _encryptedData; }
      set { _encryptedData  = value; }
    }

    public string DecryptedData
    {
      get { return _decryptedData; }
      set { _decryptedData  = value; }
    }

    public RSAcrypt()
    {
    }
    /// <param name="CryptAction"> The action to perform on the string {Encrypt|Decrypt} </param >
    /// <param name="StringToCrypt"> A string to perform the Action on </param>
    public RSAcrypt(string CryptAction, string StringToCrypt)
    {
        UnicodeEncoding thisUnicodeEncoding = new UnicodeEncoding();
        RSACryptoServiceProvider thisRSACryptoServiceProvider = new RSACryptoServiceProvider();
        byte[] _stringToCrypt = thisUnicodeEncoding.GetBytes(StringToCrypt);

        switch (CryptAction)
        {
            case "Encrypt":
                byte[] encryptedData = Encrypt(_stringToCrypt, thisRSACryptoServiceProvider.ExportParameters(false));
                _encryptedData = thisUnicodeEncoding.GetString(encryptedData);
            break;

            case "Decrypt":
                byte[] decryptedData = Decrypt(_stringToCrypt, thisRSACryptoServiceProvider.ExportParameters(true));
                _decryptedData = thisUnicodeEncoding.GetString(decryptedData);
            break;

            default:

            break;
        }

    }

    static private byte[] Encrypt(byte[] DataToEncrypt, RSAParameters keyInfo)
    {
        RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
        RSA.ImportParameters(keyInfo);
        return RSA.Encrypt(DataToEncrypt, false);
    }

    static private byte[] Decrypt(byte[] DataToDecrypt, RSAParameters keyInfo)
    {
      #region Temporary Assignment - Remove before build

      byte[] tmpVal = null;

      #endregion

      RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();

      try
      {
          RSA.ImportParameters(keyInfo);

          #region Temporary Assignment - Remove before build

          tmpVal = RSA.Decrypt(DataToDecrypt, false);

          #endregion
      }
      catch (Exception ex)
      {

          MessageBox.Show("Error: " + ex.Message, "Exception Thrown");

      }

      #region Temporary Assignment - Remove before build

      return tmpVal;

      #endregion
    }
  }
}

Is there anything that I can change in this class that would allow me to check the encoding prior to passing the byte array to Encrypt / Decrypt?

It seems like I have a reference around here somewhere, but I am becoming frustrated, so I thought it would at least help if I stopped to do something other than reading and compiling...

BTW, I am calling this class to write to a password to an XML file using the Nini initialization framework. http://nini.sourceforge.net/manual.php#ASimpleExample

Also, I used Notepad2 to change the file encoding (UTF-8) before I wrote to the XML file.

That was after the program halted after I compiled the first time. Using the debugger, I was able to see that the encoding was different between the XML data in memory (UTF-8) and the data on disk (ANSI).

That does not appear to be the case now, but the program still halts, referencing bad data returned from the Decrypt portion of RSAcrypt().

(also note that Encrypt and Decrypt were identical methods before my frustration set in, they do function the same, but I wanted to try to capture addition exception information related to the bad data claim. Of course, you will notice that I allowed my frustration to handicap my code ;-) )

Any suggestions, ideas or references would be great.

TIA,

E

+2  A: 

Inside your constructor you generate a new RSA keypair each time when you do:

   RSACryptoServiceProvider thisRSACryptoServiceProvider = new RSACryptoServiceProvider();

Since your constructor is where you encrypt and decrypt, you are encrypting with an RSA Key, and decrypting with a completely different one.

To make this work, you have several options based on how you plan to use your code.

One option is to export the RSA key, and use that for all encryption/decryption operations. This is the only option if you plan on decrypting/encrypting data between different runs of your executable.

Of course this completely glosses over how you will store your public/private key (I recommend DPAPI on windows), for use by your application.

Alan
Alan, Then Encrypt and Decrypt methods also do an ImportParameters(), I think this solves the 'different keys' issue.
Henk Holterman
Right, however they RSA key that is passed in, is regenerated each time you call the non default RSAcrypt constructor. Since through the constructor is the only way to invoke encrypt/decrypt, everytime you do an encryption/decryption operation, you get a new RSA Keypair.
Alan