An essential purpose of cryptography would be to ensure nonrepudiation of a delivered message. This is where the receiver of the message cannot deny that the message is genuine. A digital signature is a technique used to help demonstrate this authenticity and the integrity of the message. It is useful for demonstrating authenticity of documents and contracts, software downloads, and financial transactions.

Digital signatures are based on asymmetric cryptography. For the recipient of the message, a digital signature enables the recipient to think the message was sent by the proper sender. This can be thought of as a digital equivalent to a signature on a letter, except a digital signature is much harder to create.

A digital signature consists of the following three algorithms:

- Public and private key generation using RSA.
- A signing algorithm that uses the private key to create the signature.
- A signature verification algorithm that uses the public key to check if the message is authentic.

A digital signature requires two things. First, the signature is generated for a message using a private key and this signature can be verified using the associated public key. Second, you should not be able to generate a valid signature for a message without knowing the private key.

public void AssignNewKey() { using (var rsa = new RSACryptoServiceProvider(2048)) { rsa.PersistKeyInCsp = false; publicKey = rsa.ExportParameters(false); privateKey = rsa.ExportParameters(true) } }

For the digital signature example project, there is a class called DigitalSignature. The first method in this class is AssignNewKey. This method will generate a public and private key pair to be used for creating and verifying the digital signature. Next, there is the SignData method. This is actually the technique that’ll produce a signature. Let’s say you wish to sign some information that represents a document although what you are signing doesn’t matter as it is displayed as a byte array. You don’t sign the actual data itself; you sign a hash of the data.

public byte[] SignData(byte[]hashOfDataToSign) { using (var rsa = new RSACryptoServiceProvider(2048)) { rsa.PersistKeyInCsp = false; rsa.ImportParameters(privateKey); var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa) rsaFormatter.SetHashAlgorithm(“SHA256”); return rsaFormatter.CreateSignature(hashOfDataToSign); } }

The SignData method takes a byte array which is the hash of the data you wish to sign. The very first thing that occurs within method is an instance of the RSACryptoServiceProvider class is created and then the already created private key (from the AssignNewKey method) is packed into that instance. Subsequently, an instance of RSAPKCS1SignatureFormatter is created and the instance of RSACryptoServiceProvider is passed in.

After that, the hash algorithm has to be set on the RSAPKCS1SignatureFormatter instance. The algorithm set here has to match the hash algorithm you used to hash your data before creating the digital signature.

Once we are done with this, the final step is call CreateSignature on the RSAPKCS1SignatureFormatter instance. This will return a byte array which contain your digital signature. The next method in the DigitalSignature class is the VerifySignature method. This method is used to confirm that a digital signature is legitimate for a particular hash of the information you want to confirm.

public bool VerifySignature(byte[]hashOfDataToSign, byte[] signature) { using (var rsa = new RSACryptoServiceProvider(2048)) { rsa.ImportParameters(publicKey); var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa); rsaDeformatter.SetHashAlgorithm(“SHA256”); return rsaDeformatter.VerifySignature(hashOfDataToSign, signature); } }

The VerifySignature method takes two parameters, a byte array containing a hash of the data that the signature was originally created for, and a byte array of the digital signature itself. First, an instance of the RSACryptoServiceProvider class is created. Then, the public key that was generated with the AssignNewKey method is imported into the RSA instance. Next, an instance of the RSAPKCS1SignatureDeformatter is created and the hash algorithm is set to “SHA256”. After that, to confirm the signature, you call VeryifySignature on the RSAPKCS1SignatureDeformatter instance by providing the hash of the data that was signed and the actual signature itself. If the signature is legitimate, the method will return a True value, otherwise the value will be False.

The following is the complete code for the DigitalSignature example class.

using System.Security.Cryptography; namespace CryptographyInDotNet { public sealed class DigitalSignature { private RSAParameters publicKey; private RSAParameters privateKey; public void AssignNewKey() { using (var rsa = new RSACryptoServiceProvider(2048)) { rsa.PersistKeyInCsp = false; publicKey = rsa.ExportParameters(false); privateKey = rsa.ExportParameters(true) } } public byte[] SignData(byte[] hashOfDataToSign) { using (var rsa = new RSACryptoServiceProvider(2048)) { rsa.PersistKeyInCsp = false; rsa.ImportParameters(privateKey); var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa) rsaFormatter.SetHashAlgorithm(“SHA256”); return rsaFormatter.CreateSignature(hashOfDataToSign); } } public bool VerifySignature(byte[] hashOfDataToSign, byte[] signature) { using (var rsa = new RSACryptoServiceProvider(2048)) { rsa.ImportParameters(publicKey); var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa); rsaDeformatter.SetHashAlgorithm(“SHA256”); return rsaDeformatter.VerifySignature(hashOfDataToSign, signature); } } } }