JavaScript: a very easy way to embed an electronic signature

Is there a very simple way in JS to make an electronic signature that can be dealt with as easily as checksums (or hash)?

So if this is a scenario:

------------------------------------ Locked section for client ------------------------------------ | YYYY.MM.DD ......................| | ........... ......................| | Bla bla bla ......................| | Bla bla bla Bla bla bla..Bla bla .| | Bla bla bla Bla bla bla..Bla bla .| | Bla bla bla Bla bla bla..Bla bla .| | Bla bla bla Bla bla bla..Bla bla .| | Bla bla bla ......................| | Bla bla bla ......................| ------------------------------------ | HASH: HA2S2EM3CA12EDIAJED | ------------------------------------ "Open" comment textfield for clients ------------------------------------ | HE34ADOV2DSASA452123 ...(signer A)| | GHEAVOED12dHSAV2123J ...(signer B)| 

HE34ADOV2DSASA452123 generated by the private key owned by the signatory.

Then decryption (with some kind of public key) HE34ADOV2DSASA452123 will give something like YYYY.MM.DD Bla bla bla or return the hash ( HA2S2EM3CA12EDIAJED ) of the section.

Similarly, decrypting GHEAVOED12dHSAV2123J will give something like YYYY.MM.DD Bla bla bla or return the hash ( HA2S2EM3CA12EDIAJED ) of the section.


Note that for this one cannot claim protection from the evil minds of the mind, just against the fraud of the "layman" ...

+5
source share
2 answers

Try the node module XML Advanced Electronic Signatures .

It uses Web Crypto for cryptographic operations. Therefore, it can be used both in browsers and in Node.js.

+3
source

Electronic signatures are by definition much more complex than a hash. Although you can simply generate a hash from a message, for a digital signature you usually need a secret key and enforcement that only someone who knows the private key can create a valid signature. Then you obviously need the appropriate public key to verify the message.

Typically, you have 3 steps to do this:

  • you need to create a public / private key pair.
  • you need to sign your message with the private key in a reliable system. Only this system should have a private key.
  • You are checking the public key message to make sure that the trusted system has signed it.

So, the first interesting question: how do you want to store / distribute your keys and what systems do you want to sign / verify? This is a common use case that you sign and verify in different programming languages. However, now let's assume that you want to do everything in JavaScript.

Also always remember a simple problem: If you cannot be sure that the message is from a valid sender, how can you make sure that the public key that you use to verify the message is a valid sender? You can distribute it using your software, but for the website to do this you need to trust your TLS connection, and if you trust your TLS connection, you can also use it to send the message itself.

I believe the best solution is to use the web cryptography API . Here you can find useful examples.


First you need to generate the keys:

 async function generateKey() { const key = await window.crypto.subtle.generateKey({ name: "RSASSA-PKCS1-v1_5", modulusLength: 4096, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: "SHA-512" }, }, true, ["sign", "verify"] ); return { privateKey: await window.crypto.subtle.exportKey( "jwk", key.privateKey, ), publicKey: await window.crypto.subtle.exportKey( "jwk", key.publicKey, ), }; } 

window.crypto.subtle.exportKey gives you JSON, which you can convert back and forth to a simple string using JSON.strinify / JSON.parse so you can save it somewhere.


The next step is to sign your message. Note that you probably want to do this at another time and then generate the keys.

 async function sign(privateKeyJwk, message) { const privateKey = await window.crypto.subtle.importKey("jwk", privateKeyJwk, { name: "RSASSA-PKCS1-v1_5", hash: {name: "SHA-512"}, }, false, ['sign']); const data = new TextEncoder().encode(message); const signature = await window.crypto.subtle.sign({ name: "RSASSA-PKCS1-v1_5", }, privateKey, data, ); // converts the signature to a colon seperated string return new Uint8Array(signature).join(':'); } 

This function accepts the jwk of the private key that we created in the first step, and a simple string as a message for signing. It returns the signature as a string, separated by a colon. This works now, even if Base64, for example, is more efficient.


Now the last step is to check your message. You will probably want to do this later on another machine, where you only have the public key and possibly a damaged message, and you want to check whether this message was damaged or not. It is absolutely essential that you can trust that the private key has not been damaged.

 async function verify(publicKeyJwk, signatureStr, message) { const signatureArr = signatureStr.split(':').map(x => +x); const signature = new Uint8Array(signatureArr).buffer const publicKey = await window.crypto.subtle.importKey("jwk", publicKeyJwk, { name: "RSASSA-PKCS1-v1_5", hash: {name: "SHA-512"}, }, false, ['verify']); const data = new TextEncoder().encode(message); const ok = await window.crypto.subtle.verify({ name: "RSASSA-PKCS1-v1_5", }, publicKey, signature, data ); return ok; } 

To do this, you need the jwk of the public key that we created in the first step, the message used in the second step, in the form of a string and the signature created in the second step, in the form of a string separated by a colon.

This will result in a logical display if the message is valid or not.

+2
source

All Articles