Return to HomePage



Generate an RSA signature of a given message (VB.NET)


Applies to

* .NET 2.0
* VB.NET


Summary

This code demonstrates generation of an RSA signature on a given message which can be used to perform integrity checking and provides non-repudiation for the message sent by another entity.


Objectives

* To create a cryptographic public key signature of a given message, to be used in providing integrity checks on data stored for periods of time or on transmitted data.
* To provide non-repudiation of a message or piece of data which can be independently validated by users who posess the RSA public key.


Scenarios

* Two entities in a client-server or client-client architecture need to transmit data with a mechanism to validate the authenticity of the sender and provide non-repududiation.
* An application stores files for prolonged periods of time. The developer wants to provide non-repudiation of files stored to ensure they aren't altered over time.

Solution Example

		    Public Function [SignMessage(ByVal] message() As Byte, [ByVal] privkey As [RSAParameters)] As Byte()
		        Dim signature() As Byte
		        ' Create an RSA Crypto provider, by default creating a new [RSACryptoServiceProvider]
		        ' causes a public / private key pair to be generated.
		        Dim [myRsaProvider] As [RSACryptoServiceProvider] = New [RSACryptoServiceProvider()]
		        ' Import our private key so we can perform the signing operation
		        [myRsaProvider.ImportParameters(privkey)]
		        signature = [myRsaProvider.SignData(message,] New [SHA1CryptoServiceProvider())]
		        Return signature
	

		    End Function
	


Problem Example

Perhaps the most common pitfall developers encounter when communicating with a remote node over a public communications channel is the failure to perform any message signing such as that implemented by our Solution Example.

The next most common pitfall is to simply perform a hashed digest of the message using a public hashing algortihm demonstrated below:


		        Public Shared Function [GenerateDigest(ByVal] input As String) As String
	

		            ' Instantiate the SHA1 Digest
		            Dim sha As SHA1 =  New [SHA1CryptoServiceProvider()] 
		            Return [ASCIIEncoding.ASCII.GetString(sha.ComputeHash(ASCIIEncoding.ASCII.GetBytes(input)))]
		        End Function
	

* If a message is intercepted in transit or modified in storage, an attacker may simply perform their own hash representation of the value to be included in the communications or stored along with the file on disk.

Test Case

The following classes must be included in any project making use of the sample code provided above:

Imports System.Text
Imports System.Security
Imports System.Security.Cryptography

		        static void Main(string[] args)
		        {
		            // Create a test keypair with a strong keysize of 2048 bits. In a production application 
		            // we would load this value from a DPAPI protected registry value
		            [RSACryptoServiceProvider] rsaProvider = new [RSACryptoServiceProvider(2048);]
	

		            // The [ExportParameters] method below takes a boolean, which determines whether
		            // to export the private key data within the parameters. When exporting parameters
		            // ensure that only the public key parameter is shared with the remote party:
		            [RSAParameters] [rsaPubKeyParams] = [rsaProvider.ExportParameters(false);]
	

		            // We'll also export the private key for our signing operations
		            [RSAParameters] [rsaPrivKeyParams] = [rsaProvider.ExportParameters(true);]
	


		            string message1 = "the quick brown fox jumped over the lazy dog";
		            string message2 = "the quick brown dog jumped over the lazy fox";
	

		            byte[] sig = [SignMessage(ASCIIEncoding.ASCII.GetBytes(message1),] [rsaPrivKeyParams);]
		            Console.Out.WriteLine("MSG: "+message1);
		            Console.Out.WriteLine("\nRSA Sig: " +Convert.ToBase64String(sig));
	

		            Console.Out.WriteLine("\nTest Case #1:");
		            Console.Out.WriteLine("Validating signature for MSG: " + message1);
		            if [(VerifyMessageSignature(ASCIIEncoding.ASCII.GetBytes(message1),] sig, [rsaPubKeyParams))] {
		                Console.Out.WriteLine("Valid signature.");
		            } else {
		                Console.Out.WriteLine("Invalid signature.");
		            }
	

		            Console.Out.WriteLine("\nTest Case #2:");
		            Console.Out.WriteLine("Validating signature for MSG: " + message2);
		            if [(VerifyMessageSignature(ASCIIEncoding.ASCII.GetBytes(message2),] sig, [rsaPubKeyParams))]
		            {
		                Console.Out.WriteLine("Valid signature.");
		            }
		            else
		            {
		                Console.Out.WriteLine("Invalid signature.");
		            }
		        }
	


Expected Result

Running the test case above will result in the following output:

MSG: the quick brown fox jumped over the lazy dog

RSA Sig: E1uGW7OmhpoP9LgnjfLA7IWUQhlrxL87tmHnkqGPowCssX70ftT78T4mE5lF5iog4elIgBTUH5miVJdsqKXzTBK64V+
W5gCUqsESiqcmJztchpbeyc0E9tqNBaFlo+8yiSp6aIsDsS9W5OsNgnj0Tn3vT2vnRqWA8qORLmifVrPXtQU4gm60sHO2RKiTsiM
u81m3MfNI3Is/MadLn6bwxnnvDNxJFpDADENaihVdBSrIDeEV4CBaQE59GbJJSBBfY15xC5X0ufNske0eG+k3LURJeQDSg03oFNB
HMi8ZL7oTaWHw0xRygh/aBqZCTEtTjj+RsLPxv5NsrxhzSFXlDw==

Test Case #1:
Validating signature for MSG: the quick brown fox jumped over the lazy dog
Valid signature.

Test Case #2:
Validating signature for MSG: the quick brown dog jumped over the lazy fox
Invalid signature.


More Information

Potential pitfalls in secure communications include session replay attacks. Session replay may be mitigated through use of RSA signatures in which a message includes a timestamp or session identifier to be used once. By performing an RSA signature on the message it is possible to protect against session replay because only the sender can generate a valid signature of a message given the properties of asymmetric encryption algorithms.

Perhaps the single most important design consideration in a secure communication protocol is to include message signing altogether. However, Asymmetric encryption routines are expensive and generally performed during the initial key exchange process during which two entities agree on a common shared (secret - symmetric) key to be used in a more efficient HMAC algorithm.

Care should be taken in storage of the private key pair. Ensure that keys are stored within a container (for more information please refer to: http://msdn2.microsoft.com/en-us/library/system.security.cryptography.cspparameters(VS.80).aspx).

When sharing keys with a remote entity always ensure only the public key data is exported rather than the full RSA key. To export only the private key one may call the following methods:

		 ' The [ExportParameters] method below takes a boolean, which determines whether
		 ' to export the private key data within the parameters. When exporting 
		 ' parameters ensure that only the public key parameter is shared with the 
		 ' remote party:
		            [rsaPubKeyParams] = [rsaProvider.ExportParameters(false)]
	

Or alternatively export just the public key data as XML:

' Setting the argument to false ensures that the private
' key is not exported.
		            [rsaPubString] = [myRsaProvider.ToXmlString(false)]
	

Additional Resources

* RSA Encrycryption / Signing: http://en.wikipedia.org/wiki/RSA
* Crytopgraphy (.NET): http://msdn.microsoft.com/library/en-us/dnpag2/html/PAGGuidelines0003.asp?frame=true#pagguidelines0003_cryptography


Attributes

* Applies To: .NET Framework 2.0, C#
* Category: Cryptography
* Author: George Gal



Return to HomePage
Microsoft Communities