65.9K
CodeProject is changing. Read more.
Home

Implementing Digital Signing in .NET

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.60/5 (33 votes)

Nov 25, 2004

4 min read

viewsIcon

295715

downloadIcon

9618

Implements digital signing using .NET framework.

Introduction

This tutorial will show how to achieve digital signing in .NET framework 1.1 using System.Security.Cryptography class.

Digital Signatures

Digital signatures are used to achieve Authentication, Non-repudiation, and Authorization.

Authentication is a technique by which a process verifies that its communication partner is who it is supposed to be and not an intruder, and deals with the question of whether or not you are actually communicating with a specific process. Non-repudiation is a mechanism which provides a way to prevent the author from falsely claming that he or she isn’t the author. Authorization is concerned with what that process is permitted to do.

Let’s say Alice and Bob decide to sign digitally, a contract between them which is highly confidential. Here’s the protocol they can use to digitally sign the contact:

Sample screenshot

  1. Alice and Bob each get a copy of the file containing the contract.
  2. Bob prepares a message and computes the hash of it and encrypts the hash value with his private key called Signature Block.
  3. Then he encrypts the message with Alice's Public Key.
  4. He sends two files to Alice: encrypted hash and message.
  5. Upon receiving, Alice decrypts hash value with Bob's public key.
  6. Then she decrypts message with her private key.
  7. She then computes the hash of this message.
  8. Finally, she compares the two hash values. If they are same, the signature is “good”, otherwise bad.

If Bob wants to cheat Alice, he has a big problem. Since Alice knows his RSA public key because she made it well private. Therefore, the entire encrypted message serves as a “digital signature”. So the message is authenticated both in terms of source and in terms of data integrity.

What is Hash?

Hashes are known as One way functions, that is their mathematical property of non reversibility. Further more, they are also known as Message digest functions because message is reduced or digest to a fixed-length number that is smaller than the message. Hashes are the actual sum of ASCII values of all letters of message, and no matter how long the input data is, the hash is always the same number of bits.

.NET provides us with following Hash algorithms:

  • MD5CryptoServiceProvider (Message digest 5)
  • SHA1CryptoServiceProvider (Secure hash algorithm with key size 160-bits)
  • SHA256Managed (Secure hash algorithm with key size 256-bits)
  • SHA384Managed (Secure hash algorithm with key size 384-bits)
  • SHA512Managed (Secure hash algorithm with key size 512-bits)
  • HMACSHA1 (Hash-based Message Authentication Code using the SHA1 hash function)
  • MACTripleDES (Message Authentication Code using the TripleDES for the input data)

Also, .NET provides us with following Digital Signature Algorithms:

  • DSACryptoServiceProvider (Digital Signature Algorithm)
  • RSACryptoServiceProvider (Rivest, Shamir and Adlemen)

We will use RSA algorithm since it can be used not only for digital signatures, but for also encryption and decryption. It is tiny but a bit faster than DSA algorithm which can only be used for digital signing, issued by NIST (National Institute of Standards and Technology).

Let us implement this concept in .NET framework 1.1.

Implementation

Start a new Windows Application project and assign a name “digital signing” and do the following”:

Add a new form names FORM1 with controls on it as: (Interface should be like the form as shown below: for more clarity, download code)

Sample screenshot

  1. GroupBox named Bob (sender) with following controls on it:
    • Label control, three TextBoxes for output.
    • A Button named Button1 with Text property as “&Encrypt Plaintext using Receiver's (Alice) Public Key”.
    • A Button named Button1 with Text property as “Generate &Signature Block using Sender's (Bob) Private Key”.
  2. GroupBox named Alice (receiver) with following controls on it:
    • A TextBox control for output.
    • A Button named Button3 with Text property as “Verify Signature block using sender's (Bob) Public Key”.
    • A Button named Button4 with Text property as “&Decrypt plaintext using receiver (Alice) private key”.
  3. A Button named Button5 which is the Exit button.

Form1

That’s all for the interface. Now, it's time for coding. Let’s start it:

Code listing for “Form1”:

Imports System.Text

Public Class Form1 ‘Main interface form
    Inherits System.Windows.Forms.Form

    Private Sub Button3_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles Button3.Click
        'Verify the signature is authentic using 
        'the sender's public key(decrypt Signature block)
        If myReceiver.VerifyHash(mySender.PublicParameters, _
                                 encrypted, signature) Then
            MsgBox("Signature Valid", MsgBoxStyle.Information)
            Button4.Enabled = True
        Else
            MsgBox("Invalid Signature", MsgBoxStyle.Exclamation)
            Button4.Enabled = False

        End If
    End Sub

    Private Sub Button1_Click_1(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles Button1.Click
        If Me.TxtPlainText.Text = "" Then
            MsgBox("Please enter a string to sign", MsgBoxStyle.Information)
            Exit Sub
        End If
        'Convert the data string to a byte array.
        toEncrypt = enc.GetBytes(TxtPlainText.Text)
 
        'Encrypt data using receiver's public key.
        encrypted = mySender.EncryptData(myReceiver.PublicParameters, toEncrypt)
        'convert to base64/Radix output
        TextBox1.Text = Convert.ToBase64String(encrypted)
        Me.Button2.Enabled = True

    End Sub
 
    Private Sub Button2_Click_1(ByVal sender As System.Object, _
                ByVal e As System.EventArgs) Handles Button2.Click
        'Hash the encrypted data and generate a signature block on the hash
        ' using the sender's private key. (Signature Block)
        signature = mySender.HashAndSign(encrypted)
        'convert to base64/Radix output
        TextBox2.Text = Convert.ToBase64String(encrypted)
        Me.Button3.Enabled = True
    End Sub

    Private Sub Button4_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles Button4.Click
        TextBox3.Text = myReceiver.DecryptData(encrypted)
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles MyBase.Load
        Button2.Enabled = False
        Button3.Enabled = False
        Button4.Enabled = False
    End Sub

    Private Sub Button5_Click(ByVal sender As System.Object, _
                ByVal e As System.EventArgs) Handles Button5.Click
        myReceiver = Nothing
        mySender = Nothing
        End
    End Sub

End Class

Now, do the following:

  • Add a Class to project and name it “Bob” which plays a role of sender.
  • Add another Class and name it “Alice” which plays a role of receiver.
  • Add a Module named “Global” for global declarations of variables.

Code listing for Class “Bob”:

Imports System.Security.Cryptography
Imports System.Text

Public Class Bob
    '=======================================================
    ‘Bob Sender is who want to exchange and prepares a encrypted message
    '=======================================================
    Private rsaPubParams As RSAParameters          'stores public key
    Private rsaPrivateParams As RSAParameters     'stores private key

    Public Sub New()
     'create new instance of RSACryptoServiceProvider
        Dim rsaCSP As New RSACryptoServiceProvider
        'Generate public and private key data and allowing their exporting.
        'True to include private parameters; otherwise, false
        rsaPrivateParams = rsaCSP.ExportParameters(True)
        rsaPubParams = rsaCSP.ExportParameters(False)
    End Sub 'New

    Public ReadOnly Property PublicParameters() As RSAParameters
        Get
            'just return public key
            Return rsaPubParams
        End Get
    End Property

    'Manually performs hash and then signs hashed value.
    Public Function HashAndSign(ByVal encrypted() As Byte) As Byte()
        'create new instance of RSACryptoServiceProvider
        Dim rsaCSP As New RSACryptoServiceProvider
        'create new instance of SHA1 hash algorithm to compute hash
        Dim hash As New SHA1Managed
        'a byte array to store hash value        
        Dim hashedData() As Byte
        'import private key params into instance of RSACryptoServiceProvider
        rsaCSP.ImportParameters(rsaPrivateParams)
        'compute hash with algorithm specified as here we have SHA!
        hashedData = hash.ComputeHash(encrypted)
        ' Sign Data using private key and  OID is simple name
        ' of the algorithm for which to get the object identifier (OID)
        Return rsaCSP.SignHash(hashedData, CryptoConfig.MapNameToOID("SHA1"))
    End Function 'HashAndSign

    'Encrypts using only the public key data.
    Public Function EncryptData(ByVal rsaParams As RSAParameters, _
                    ByVal toEncrypt() As Byte) As Byte()
        'create new instance of RSACryptoServiceProvider
        Dim rsaCSP As New RSACryptoServiceProvider
        ''import private key params into instance of RSACryptoServiceProvider
        rsaCSP.ImportParameters(rsaParams)
        'true to use OAEP padding PKCS#1 v2  (only available on Windows XP or later)
        ' otherwise, false to use Direct Encryption using PKCS#1 v1.5 padding
        Return rsaCSP.Encrypt(toEncrypt, False)
    End Function 'EncryptData

End Class   'Bob

Code listing for Class “Alice”:

Imports System.Security.Cryptography
Imports System.Text
Public Class Alice
    '=========================================
    ' Alice is Receiver who will decrypt data from sender
    '========================================
    Private rsaPubParams As RSAParameters        ' stores public key
    Private rsaPrivateParams As RSAParameters    'stores private key

    Public Sub New()
        'create new instance of RSACryptoServiceProvider
        Dim rsaCSP As New RSACryptoServiceProvider
        'Generate public and private key data and allowing their exporting.
        'True to include private parameters; otherwise, false
        rsaPrivateParams = rsaCSP.ExportParameters(True)
        rsaPubParams = rsaCSP.ExportParameters(False)
    End Sub 'New

    Public ReadOnly Property PublicParameters() As RSAParameters
        Get
            'Just return public key
            Return rsaPubParams
        End Get
    End Property

    'Manually performs hash and then verifies hashed value.
    Public Function VerifyHash(ByVal rsaParams As RSAParameters, _
                    ByVal signedData() As Byte, _
                    ByVal signature() As Byte) As Boolean
        'create new instance of RSACryptoServiceProvider
        Dim rsaCSP As New RSACryptoServiceProvider
        'create new instance of SHA1 hash algorithm to compute hash
        Dim hash As New SHA1Managed
        'a byte array to store hash value
        Dim hashedData() As Byte
        'import  public key params into instance of RSACryptoServiceProvider
        rsaCSP.ImportParameters(rsaParams)
        'compute hash with algorithm specified as here we have SHA1
        hashedData = hash.ComputeHash(signedData)
        ' Sign Data using public key and OID is simple name
        ' of the algorithm for which to get the object identifier (OID)
        Return rsaCSP.VerifyHash(hashedData, _
               CryptoConfig.MapNameToOID("SHA1"), signature)
    End Function 'VerifyHash

    'Decrypt using the private key data.
    Public Function DecryptData(ByVal encrypted() As Byte) As String
        'a byte array to store decrypted bytes
        Dim fromEncrypt() As Byte
        ' holds orignal message
        Dim roundTrip As String
        'create new instance of RSACryptoServiceProvider
        Dim rsaCSP As New RSACryptoServiceProvider
        'import  private key params into instance of RSACryptoServiceProvider
        rsaCSP.ImportParameters(rsaPrivateParams)
        'store decrypted data into byte array
        fromEncrypt = rsaCSP.Decrypt(encrypted, False)
        'convert bytes to string
        roundTrip = enc.GetString(fromEncrypt)
        Return roundTrip
    End Function 'DecryptData

End Class ’ Alice

Code listing for Module “Global”:

Imports System.Text
Module Global
    'Hold message in bytes
    Public toEncrypt() As Byte
    'holds encrypted data
    Public encrypted() As Byte
    'holds signatures
    Public signature() As Byte
    'instance of class Bob
    Public mySender As New Bob
    'instance of class Alice
    Public myReceiver As New Alice
    'new instance of Unicode8 instance
    Public enc As New UTF8Encoding
End Module

Running the Sample

In the Visual Studio .NET IDE, press the <F5> key. When you are done, click Exit button to close the program.

Conclusion

I am always willing to help, so if you have any questions, suggestions, about my article and code, then feel free to email me. You can also reach me on MSN messenger with screen name “Maxima”.