[.Net] Signing and validating data using private and public key
In this article I will show how to sign string data with private key and validate it using public key.
All code examples you can find here.
First thing you have to do is to generate private key (PKCS8 RSA). You can do it using openssl. I’m using openssl already installed in git bash.
Open git bash in folder where keys should be placed and execute below commands.
openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -pubout -in private.pem -out public.pem

Now we can start writing code. Create the new ms-test project to be able test the solution easily.
Create your test class “SignTest” and “Crypto” class where you place your signing algorithm. You need also copy private and public key, that you generated before.

Remember also to check-in option to copy your keys to output folder. Click on key and select option properties. After that select “Copy to Output Directory” – “Copy always”

I will be using Portable.BouncyCastle nugget package – so install it in your project.

Now have a look to our code in Crypto class.
public string SignData(string message, string privateKeyPath)
{
var privateKey = ReadAsymmetricKeyParameter(privateKeyPath);
//Initialization
ISigner sig = SignerUtilities.GetSigner("SHA512withRSA");
sig.Init(true, privateKey);
//Get bytes from message
var bytes = Encoding.UTF8.GetBytes(message);
//Signing data
sig.BlockUpdate(bytes, 0, bytes.Length);
byte[] signature = sig.GenerateSignature();
//Return string from bytes as Base64
return Convert.ToBase64String(signature);
}
private AsymmetricKeyParameter ReadAsymmetricKeyParameter(string privateKeyPath)
{
using var fileStream = File.OpenText(privateKeyPath);
var pemReader = new PemReader(fileStream);
return (AsymmetricKeyParameter)pemReader.ReadObject();
}
Firstly, you need to read private key parameters. Next you need to convert your message to byte array and generate signature. After that you return your signature as Base64.
Now it’s time to verify signature.
private RSACryptoServiceProvider GetPublicKeyCryptoProvider(string publicKeyPath)
{
var publicKey = File.ReadAllText(publicKeyPath);
//Read public key params
var pr = new PemReader(new StringReader(publicKey));
var publicKeyParams = (AsymmetricKeyParameter)pr.ReadObject();
var rsaParams = DotNetUtilities.ToRSAParameters((RsaKeyParameters)publicKeyParams);
//Create provider
var rsaPublicKey = new RSACryptoServiceProvider();
rsaPublicKey.ImportParameters(rsaParams);
return rsaPublicKey;
}
public bool VerifyData(string originalMessage, string signature, string publicKeyPath)
{
var rsaPublicKey = GetPublicKeyCryptoProvider(publicKeyPath);
//Get message from Base64
var signatureBytes = Convert.FromBase64String(signature);
//Get bytes from original message
var bytesToVerify = new UTF8Encoding().GetBytes(originalMessage);
//Verify data
return rsaPublicKey.VerifyData(bytesToVerify, CryptoConfig.MapNameToOID("SHA512")!, signatureBytes);
}
Firstly you need to load your private key using method “GetPublicKeyCryptoProvider”. You need to convert back your signature from Base64 to byte array. Afther that you verify if signature match to message you expecting.
To prove the algorithm works properly I’ve created some tests.
Crypto crypto = new Crypto();
[TestMethod]
public void GivenPhrase_TextTheSame_ThenGoodValidation()
{
var signature = crypto.SignData("Text to validate", @".\Keys\private.pem");
var resultCheckGood = crypto.VerifyData("Text to validate", signature, @".\Keys\public.pem");
Assert.IsTrue(resultCheckGood);
}
[TestMethod]
public void GivenPhrase_TextDifferent_ThenBadValidation()
{
var signature = crypto.SignData("Text to validate", @".\Keys\private.pem");
var resultCheckBad = crypto.VerifyData("Different text to validate", signature, @".\Keys\public.pem");
Assert.IsFalse(resultCheckBad);
}
[TestMethod]
public void GivenPhrase_KeyDifferent_ThenBadValidation()
{
var signature = crypto.SignData("Text to validate", @".\Keys\private2.pem");
var resultCheckBad = crypto.VerifyData("Text to validate", signature, @".\Keys\public.pem");
Assert.IsFalse(resultCheckBad);
}
In first test you just give a sample of text signing it with private key and verifying if the signature match to this text.
Second test shows that if the message will be changed it cannot be verified.
Third test shows that text signed with different key cannot be verified also.
That’s it! Happy signing!
Great article ! Maybe we can add some example related with signing & verifying some data between languages C# vs Java ?
Thanks! Sure I will!
Good work!!!
Thanks!
DBlLjCyl4Pt
g5IOnSPaUAT
crVdmsbTjq7
MumgVhnPN5f
pUsrKgx2Dkb
wv56VgYJ2Sr
A48BeP2Sq5W
C9j7MtgZIc1
X4rmCJtH83h
UcJvT4wxSX3
DCuF6msaee1
0BVI7AqUBtM
aN8kwkyN6Ck
pf0TZscV0o0
czRIRx4RGag
wOeBZC1pXfL
4vKbcWOc9nx
KUZC6N6aP8l
9i7niyTrpIK
oM3yU7stg8B
TCOxR7uzS5d
wNxdKAuZARV
LaaACVwQN5c
jhSwTvIHCAK
VNmhfGUofFB
eMO9LUcqeJh
aIz6MNOMG1E
M1ilU0wxi3P
GTMOmUYdCct
WdYpaKBvhyF
vdBV2FdMsUw
z2X9OtRIzxS
G6xQrf17WHh
RjsAl30XcD5
v4zs10Kc3G0
nNLAO7ukUQJ