I recently posted about issues with encrypting large data with RSA, I am finally done with that and now I am moving on to implementing signing with a user's private key and verifying with the corresponding public key. However, whenever I compare the signed data and the original message I basically just get false returned. I am hoping some of your could see what I am doing wrong.
Here is the code:
public static string SignData(string message, RSAParameters privateKey) { //// The array to store the signed message in bytes byte[] signedBytes; using (var rsa = new RSACryptoServiceProvider()) { //// Write the message to a byte array using UTF8 as the encoding. var encoder = new UTF8Encoding(); byte[] originalData = encoder.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 a base64 string before returning return Convert.ToBase64String(signedBytes); }
So that is the first step, to sign the data, next I move on to verifying the data:
public static bool VerifyData(string originalMessage, string signedMessage, RSAParameters publicKey) { bool success = false; using (var rsa = new RSACryptoServiceProvider()) { byte[] bytesToVerify = Convert.FromBase64String(originalMessage); byte[] signedBytes = Convert.FromBase64String(signedMessage); try { rsa.ImportParameters(publicKey); SHA512Managed Hash = new SHA512Managed(); byte[] hashedData = Hash.ComputeHash(signedBytes); success = rsa.VerifyData(bytesToVerify, CryptoConfig.MapNameToOID("SHA512"), signedBytes); } catch (CryptographicException e) { Console.WriteLine(e.Message); } finally { rsa.PersistKeyInCsp = false; } } return success; }
And here is the test client:
public static void Main(string[] args) { PublicKeyInfrastructure pki = new PublicKeyInfrastructure(); Cryptograph crypto = new Cryptograph(); RSAParameters privateKey = crypto.GenerateKeys("[email protected]"); const string PlainText = "This is really sent by me, really!"; RSAParameters publicKey = crypto.GetPublicKey("[email protected]"); string encryptedText = Cryptograph.Encrypt(PlainText, publicKey); Console.WriteLine("This is the encrypted Text:" + "\n " + encryptedText); string decryptedText = Cryptograph.Decrypt(encryptedText, privateKey); Console.WriteLine("This is the decrypted text: " + decryptedText); string messageToSign = encryptedText; string signedMessage = Cryptograph.SignData(messageToSign, privateKey); //// Is this message really, really, REALLY sent by me? bool success = Cryptograph.VerifyData(messageToSign, signedMessage, publicKey); Console.WriteLine("Is this message really, really, REALLY sent by me? " + success); }
Am I missing a step here? According to the Cryptography API and the examples there, I shouldn't manually compute any hashes, since I supply the algorithm within the method call itself.
Any help will be greatly appreciated.
RSA Digital Signatures To sign a message m, just apply the RSA function with the private key to produce a signature s; to verify, apply the RSA function with the public key to the signature, and check that the result equals the expected message.
Signatures are created using the RSA algorithm by applying the RSA algorithm using the private key and then distributing the result as the signature. Because of the way the RSA algorithm works, this means the signature can be decrypted using the public key.
To verify a signature, the recipient first decrypts the signature using a public key that matches with the senders private key. This produces a digest. Then the recipient calculates a digest from the received data and verifies that it matches with the one in the signature. If the digest match, the signature is valid.
Your problem is at the beginning of the VerifyData
method:
public static bool VerifyData(string originalMessage, string signedMessage, RSAParameters publicKey) { bool success = false; using (var rsa = new RSACryptoServiceProvider()) { //Don't do this, do the same as you did in SignData: //byte[] bytesToVerify = Convert.FromBase64String(originalMessage); var encoder = new UTF8Encoding(); byte[] bytesToVerify = encoder.GetBytes(originalMessage); byte[] signedBytes = Convert.FromBase64String(signedMessage); try ...
For some reason you switched to FromBase64String
instead of UTF8Encoding.GetBytes
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With