Sunday, August 12, 2012

Digital Signature by Example

We use digital signature for two main purposes in message communication:

1. To guarantee the integrity of the content (i.e to ensure that message has not been changed during transmission from sender to receiver)
2. To authenticate the message origination (i.e to verify that the message was sent from the party that we think it is sent from)

We use cryptographic mechanisms to generate and verify digital signature.
Before going into the code level, let me briefly mention the steps involved in creating and verifying the digital signature.

Pre-requisites:

Have your keystore created with private key and public key. You can refer to the posts at here and here for the steps in creating a keystore with private/public key pair using java keytool.

Creating digital signature at the sender:

1. Computing the hash value of the content to be signed...

Here we use hash functions in cryptography to create a fixed length hash value such that it is impossible to calculate the original content or the length of the content from the hash value. This is called message digest or one-way encryption. Hence hash functions provide a digital fingerprint of the content to be signed.

2. Encrypting the hash value with his/her private key...

Here we use asymmetric key cryptography to encrypt the hash value computed from the message content.

Verifying digital signature at the receiver:

1. Decrypting the signature and obtaining the message digest..

Receiver once again applies asymmetric key cryptography to decrypt the message signature using sender's public key. 

How does the receiver obtain sender's public key?
It can happen in different ways according to the message communication protocol that you use. Usually communicating parties can exchange keys before the message communication, in a trusted way or the sender can send the certificate containing the public key along with the signed content and the signature. It is not recommended to send the public key itself since it is susceptible to MIM attacks. You can read more about it from here.

At this step, message origin authentication happens. Since only the one who owns the private key related to the public key used to decrypt the signature, can sign the message - we can identify who has sent the message.

2. Comparing the hash values to verify message integrity...
Receiver computes the hash value on the original message and compares it with the hash value sent by the sender, which was obtained in the above step after decrypting the digital signature. If the two values are identical, receiver can verify that the message integrity is protected during the transmission.

Now let us see how we can create and verify digital signature over some text content with an existing private/public key pair in the keystore named 'mykeystore.jks', using Java Security API.

I hope the comments in the following source code will help you understand each step performed in doing this.
package org.digital.signature.sample;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.*;
import java.security.cert.*;
import java.security.cert.Certificate;


public class Sample {
    //keystore related constants
    private static String keyStoreFile = "/home/hasini/Digital-Signature/sample/src/main/resources/mykeystore.jks";
    private static String password = "mypassword";
    private static String alias = "mycert";

    public static void main(String[] args) {

        try {
            KeyStore keystore = KeyStore.getInstance("JKS");
            char[] storePass = password.toCharArray();

            //load the key store from file system
            FileInputStream fileInputStream = new FileInputStream(keyStoreFile);
            keystore.load(fileInputStream, storePass);
            fileInputStream.close();

            /***************************signing********************************/
            //read the private key
            KeyStore.ProtectionParameter keyPass = new KeyStore.PasswordProtection(storePass);
            KeyStore.PrivateKeyEntry privKeyEntry = (KeyStore.PrivateKeyEntry) keystore.getEntry(alias, keyPass);
            PrivateKey privateKey = privKeyEntry.getPrivateKey();

            //initialize the signature with signature algorithm and private key
            Signature signature = Signature.getInstance("SHA256withRSA");
            signature.initSign(privateKey);

            //Read the string into a buffer
            String data = "{\n" +
                          "  \"schemas\":[\"urn:scim:schemas:core:1.0\"],\n" +
                          "  \"userName\":\"bjensen\",\n" +
                          "  \"externalId\":\"bjensen\",\n" +
                          "  \"name\":{\n" +
                          "    \"formatted\":\"Ms. Barbara J Jensen III\",\n" +
                          "    \"familyName\":\"Jensen\",\n" +
                          "    \"givenName\":\"Barbara\"\n" +
                          "  }\n" +
                          "}";

            byte[] dataInBytes = data.getBytes();

            //update signature with data to be signed
            signature.update(dataInBytes);

            //sign the data
            byte[] signedInfo = signature.sign();

            System.out.println(signedInfo.toString());

            /**************************verify the signature****************************/
            Certificate publicCert = keystore.getCertificate(alias);

            //create signature instance with signature algorithm and public cert, to verify the signature.
            Signature verifySig = Signature.getInstance("SHA256withRSA");
            verifySig.initVerify(publicCert);

            //update signature with signature data.
            verifySig.update(dataInBytes);

            //verify signature
            boolean isVerified = verifySig.verify(signedInfo);

            if (isVerified) {
                System.out.println("Signature verified successfully");
            }
            
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        } catch (UnrecoverableEntryException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();  
        }
    }
}

References:

[2] http://www.garykessler.net/library/crypto.html#intro

8 comments:

  1. Thank you for explaining this concept by using such a good example. After reading the complete information I wanted to know is it possible to deceive a digital signature. And how one can make sure if the digital signatures are authentic or not.
    digital signatures

    ReplyDelete
  2. Thanks for the beautiful explanation.This is one of the most well mannered post I have ever seen and after reading it most of the questions in my mind got the answer.
    digital signatures

    ReplyDelete
  3. Thank you,
    The information you shared is very informative
    Grow Your Business With Digital Marketing Agency In India

    ReplyDelete
  4. This is very good information.i think it's useful advice. really nice blog. keep it up!!!

    online signature

    ReplyDelete
  5. i am not able to understand the verification part; you wrote,
    "Verifying digital signature at the receiver:
    1. Decrypting the signature and obtaining the message digest..
    Receiver once again applies asymmetric key cryptography to decrypt the message signature using sender's public key."

    I am not sure, u can decrypt a signature/message with public key. As per my understanding, public/private key pair usage for encryption/decryption and sign/verify is different. I am in search of how....correct me

    ReplyDelete
  6. Thanks Hasini. Until I reached your post I was trying to understand why a "certificate" is needed. My take away is that it is purely to transfer the public key in an authentic way. Thanks :-)

    ReplyDelete
  7. I really liked your Digital Signature by Example blog. I’ve been looking around for some quality information, but I always used to end up finding a junk. I found yours content on Bing and I’ll surely be back soon to find some more excellent ideas. Thanks a lot for all the info.

    ReplyDelete

Note: Only a member of this blog may post a comment.