4

My question is pretty similar to the one form 2011, Signing and verifying signatures with RSA C#. Nevertheless, I also get false when I compare the signed data and the original message. Please point on my mistake.

Code:

 public static void Main(string[] args)
    {            

        //Generate a public/private key pair.  
        RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();

        //Save the public key information to an RSAParameters structure.
        RSAParameters RSAPublicKeyInfo = RSA.ExportParameters(false);
        RSAParameters RSAPrivateKeyInfo = RSA.ExportParameters(true);    

        string message = "2017-04-10T09:37:35.351Z";

        string signedMessage = SignData(message, RSAPrivateKeyInfo);

        bool success = VerifyData(message, signedMessage, RSAPublicKeyInfo);

        Console.WriteLine($"success {success}");

        Console.ReadLine();
    }   

Signing method:

 public static string SignData(string message, RSAParameters privateKey)
    {
        ASCIIEncoding byteConverter = new ASCIIEncoding();

        byte[] signedBytes;

        using (var rsa = new RSACryptoServiceProvider())
        {
            // Write the message to a byte array using ASCII as the encoding.
            byte[] originalData = byteConverter.GetBytes(message);                

            try
            {
                // Import the private key used for signing the message
                rsa.ImportParameters(privateKey);

                // Sign the data, using SHA512 as the hashing algorithm 
                signedBytes = rsa.SignData(originalData, CryptoConfig.MapNameToOID("SHA512"));
            }
            catch (CryptographicException e)
            {
                Console.WriteLine(e.Message);
                return null;
            }
            finally
            {
                // Set the keycontainer to be cleared when rsa is garbage collected.
                rsa.PersistKeyInCsp = false;
            }
        }
        // Convert the byte array back to a string message
        return byteConverter.GetString(signedBytes);
    }

Verification method:

public static bool VerifyData(string originalMessage, string signedMessage, RSAParameters publicKey)
    {
        bool success = false;
        using (var rsa = new RSACryptoServiceProvider())
        {
            ASCIIEncoding byteConverter = new ASCIIEncoding();

            byte[] bytesToVerify = byteConverter.GetBytes(originalMessage);
            byte[] signedBytes = byteConverter.GetBytes(signedMessage);

            try
            {
                rsa.ImportParameters(publicKey);

                success = rsa.VerifyData(bytesToVerify, CryptoConfig.MapNameToOID("SHA512"), signedBytes);
            }
            catch (CryptographicException e)
            {
                Console.WriteLine(e.Message);
            }
            finally
            {
                rsa.PersistKeyInCsp = false;
            }
        }
        return success;
    }

Basically the problem is with string to byte[] encoding. I get the same problem with ASCIIEncoding and with UTF8Encoding.

Thank you in advance!

Community
  • 1
  • 1
mibrl12
  • 454
  • 5
  • 21

1 Answers1

5

You cannot use ASCIIEncoding on the encoded message because it contains bytes which are invalid ASCII characters. The typical way you would store the encoded message is in a base64 string.

In SignData, use the following to encode the byte array into a string:

return Convert.ToBase64String(signedBytes);

and in VerifyData, use the following to decode the string back to the same byte array:

byte[] signedBytes = Convert.FromBase64String(signedMessage);
msitt
  • 1,237
  • 12
  • 27
  • thank you for your prompt reply! However, I get "System.FormatException: 'The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters. '" when I use FromBase64String for the message ""2017-04-10T09:37:35.351Z"". – mibrl12 Apr 12 '17 at 07:41
  • 1
    Is there anything happening to the string before you verify it? I ran your posted code with the 2 changes above and it worked. – msitt Apr 12 '17 at 12:50
  • you are right! My bad was that I also was trying to perform string to Base64 string of the original data before signing. – mibrl12 Apr 12 '17 at 14:35