QNimate

  • CoursesVideos
  • WP PremiumPlugins
  • DemosLab
  • Bitcoin BankingBuy, Sell, Store and Earn Interest
  • Home
  • QIdea
  • QTrack
Home Carbon Ads Digital Signature using Web Cryptography API

Digital Signature using Web Cryptography API

This post is a part 4 of Web Cryptography API Tutorial post series.
⎘ Next post in the series is Passphrase Based Encryption using Web Cryptography API.
⎗ Previous post in the series is Asymmetric Encryption using Web Cryptography API.

Suppose person A sends a document to person B. Person A doesn’t want Person B to alter the document but can read the document. In this case person A can sign the document with an digital signature and send to person B to make that the document integrity is protected.

Digital Signatures are used widely used in online agreement and contract signing. Its used make sure that the employer doesn’t alter the text/data of the document after employee has agreed to the terms and signed with ink signature. The idea behind digital signature is to avoid document forgery.

In this tutorial I will show how to sign a digital document with an digital signature and also how to verify a document’s digital signature.

What is an Digital Signature?

Digital signature is simply encrypted hash of the document. Person A generates the hash of the document and encrypts the hash with his/her private key. And then sends the document and the respective public key to person B. Now person B can use the public key to decrypt and verify the hash of the document. There is no way person B can change the document data and regenerate the same hash value. The document’s integrity is completely protected from person B and any other people who may have seen the document.

Converting String to Array Buffer

For signing and verifying text/binary data you need to provide it in form of an array buffer to web cryptography api.

Here is the code to convert a string to an array buffer

function convertStringToArrayBufferView(str)
{
    var bytes = new Uint8Array(str.length);
    for (var iii = 0; iii < str.length; iii++)
    {
        bytes[iii] = str.charCodeAt(iii);
    }

    return bytes;
}

Generating Public and Private Key

For signing(or generating digital signature) data we need private key and to verify digital signature we need public key.

Here is the code to generate public and private key

var crypto = window.crypto || window.msCrypto;

var promise_key = null;

var private_key_object = null;
var public_key_object = null;

if(crypto.subtle)
{
    alert("Cryptography API Supported");

    //Parameters:
    //1. Asymmetric Encryption algorithm name and its requirements
    //2. Boolean indicating extractable. which indicates whether or not the raw keying material may be exported by the application (http://www.w3.org/TR/WebCryptoAPI/#dfn-CryptoKey-slot-extractable)
    //3. Usage of the keys. (http://www.w3.org/TR/WebCryptoAPI/#cryptokey-interface-types)
    promise_key = crypto.subtle.generateKey({name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]), hash: {name: "SHA-256"}}, false, ["sign", "verify"]);

    promise_key.then(function(key){
        private_key_object = key.privateKey;
        public_key_object = key.publicKey;
    });

    promise_key.catch = function(e){

        console.log(e.message);
    }
   
   
}
else
{
    alert("Cryptography API not Supported");
}

Signing Data

Here is the code to generate digital signature

var data = "QNimate";

var encrypted_hash = null;
var encrypt_promise = null;

var signature = null;

function encrypt_data()
{
    encrypt_promise = crypto.subtle.sign({name: "RSASSA-PKCS1-v1_5"}, private_key_object, convertStringToArrayBufferView(data));

    encrypt_promise.then(
        function(result_signature){
            signature = result_signature; //signature generated
        },
        function(e){
            console.log(e);
        }
    );
}

Verifying Digital Signature

Here is the code to verify the digital signature

var decrypt_promise = null;

function decrypt_data()
{
    decrypt_promise = crypto.subtle.verify({name: "RSASSA-PKCS1-v1_5"}, public_key_object, signature, convertStringToArrayBufferView(data));

    decrypt_promise.then(
        function(result){
            console.log(result);//true or false
        },
        function(e){
            console.log(e.message);
        }
    );
}

Importing and Exporting Keys

Sometimes you may need to send the keys to the server. And also import keys from server and use it in browser.

You can use crypto.subtle.exportKey to convert the keys into many different exportable formats and then export them.

Similarly you can use crypto.subtle.importKey to convert the exported keys into an key objects for use.

Here is an sample code showing how to import and export the generated private key

var json_private_key = null;
var string_private_key = null;

crypto.subtle.exportKey("jwk", private_key_object).then(function(result){
   
    json_private_key = result;
    string_private_key = JSON.stringify(json_private_key);

    crypto.subtle.importKey("jwk", JSON.parse(string_private_key), {name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]), hash: {name: "SHA-256"}}, true, ["sign"]).then(function(e){
        console.log(e);
    }, function(e){
        console.log(e);
    });

}, function(e){
    console.log(e.message);
});

Here we first converted the private key to JWK format and then to an string. You can send the string_private_key to server which is the string representation of the private key.

Complete Code

Here is complete code together for testing or to play with

function convertStringToArrayBufferView(str)
{
    var bytes = new Uint8Array(str.length);
    for (var iii = 0; iii < str.length; iii++)
    {
        bytes[iii] = str.charCodeAt(iii);
    }

    return bytes;
}  

var crypto = window.crypto || window.msCrypto;

var promise_key = null;

var private_key_object = null;
var public_key_object = null;

var data = "QNimate";

var encrypted_hash = null;
var encrypt_promise = null;

var signature = null;

var decrypt_promise = null;


if(crypto.subtle)
{
    alert("Cryptography API Supported");

    promise_key = crypto.subtle.generateKey({name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]), hash: {name: "SHA-256"}}, false, ["sign", "verify"]);

    promise_key.then(function(key){
        private_key_object = key.privateKey;
        public_key_object = key.publicKey;
        encrypt_data();
    });

    promise_key.catch = function(e){

        console.log(e.message);
    }
   
   
}
else
{
    alert("Cryptography API not Supported");
}

function encrypt_data()
{
    encrypt_promise = crypto.subtle.sign({name: "RSASSA-PKCS1-v1_5"}, private_key_object, convertStringToArrayBufferView(data));

    encrypt_promise.then(
        function(result_signature){
            signature = result_signature; //signature generated
            decrypt_data();
        },
        function(e){
            console.log(e);
        }
    );
}

function decrypt_data()
{
    decrypt_promise = crypto.subtle.verify({name: "RSASSA-PKCS1-v1_5"}, public_key_object, signature, convertStringToArrayBufferView(data));

    decrypt_promise.then(
        function(result){
            console.log(result);//true or false
        },
        function(e){
            console.log(e.message);
        }
    );
}
Feb 10, 2015Narayan Prusty
Asymmetric Encryption using Web Cryptography APIJavaScript "let" Keyword
Comments: 3
  1. stelio pizzolatto
    3 years ago

    is there a way to get the private key from a smart card using just JS and webcrypto API?

    ReplyCancel
  2. simon
    3 years ago

    an digital signature or a digital signature??
    shouldn’t it be with just the letter a?

    ReplyCancel
    • simon
      3 years ago

      good post btw

      ReplyCancel

Leave a Reply Cancel reply

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

Narayan Prusty

I am a full-stack web developer. I specialize in Blockchain and JavaScript. This is my personal blog where I write about programming and technologies that I learn and feel interesting to share.

6 years ago 5 Comments Web Security
Share this
0
GooglePlus
0
Facebook
0
Twitter
0
Linkedin
  • What is an Digital Signature?
  • Converting String to Array Buffer
  • Generating Public and Private Key
  • Signing Data
  • Verifying Digital Signature
  • Importing and Exporting Keys
  • Complete Code
Related Articles
  • Asymmetric Encryption using Web Cryptography API
  • Symmetric Encryption using Web Cryptography API
  • Hashing using Web Cryptography API
  • Introduction to Subresource Integrity
  • Passphrase Based Encryption using Web Cryptography API
Our Sponsor
Freelance: I am available
@narayanprusty
Hi, I am a full-stack developer - focusing on JavaScript, WordPress, Blockchain, DevOps, Serverless and Cordova. You can outsource your app development to me.





Will get back to you soon!!!
WordPress
ReactJS
Meteor
Blockchain
Serverless
Kubernetes
DevOps
DB & Storage
Ejabberd
Let's get started
My Books

2014 - 2015 © QNimate
All tutorials MIT license