High speed, public-key cryptography in JavaScript (part 1)

In this article we will discuss through the basics how we can implement “end-2-end secure communications” in JavaScript. 
Using a state of art cryptographic library, here we present the basic foundations of a robust cryptographic system.

Photo courtesy of https://pexels.com

The basics

Let’s start by describing two introductory concepts that are required before we start implementing.

Public Key Cryptography

The “Public Key Cryptography” is the cryptographic mechanism that allows the Internet to be secure.

Public-key cryptography, or asymmetric cryptography, is any cryptographic system that uses pairs of keys: public keys which may be disseminated widely, and private keys which are known only to the owner. This accomplishes two functions: authentication, where the public key verifies that a holder of the paired private key sent the message, and encryption, where only the paired private key holder can decrypt the message encrypted with the public key.

https://en.wikipedia.org/wiki/Public-key_cryptography

Example of systems using Public Key Cryptography:

NaCL & TweetNaCL.js

NaCl (pronounced “salt”) is a new easy-to-use high-speed software library for network communication, encryption, decryption, signatures, etc. NaCl’s goal is to provide all of the core operations needed to build higher-level cryptographic tools.

http://nacl.cr.yp.to/

The NaCL project is being lead by Daniel J.Bernstein, one of the most prominent Computer Scientists of our era.

Optionally you can read Aaron Swartz comment on Daniel J. Bernstein: http://www.aaronsw.com/weblog/djb

Specifically, NaCl uses elliptic-curve cryptography, not RSA; it uses an elliptic curve, Curve25519, that has several advanced security features; it uses Salsa20, not AES (although it does include an AES implementation on the side); it uses Poly1305, not HMAC; and it uses EdDSA, not ECDSA.

NaCL is proven to be secure, as breaking every round of Salsa20 is theoretically more expensive than breaking correspondent AES rounds. 
In the other hand Salsa20 was designed with speed in mind, offering great performance even under low speed CPUs. A more detailed explanation of Salsa20 speed is available here: https://cr.yp.to/snuffle/speed.pdf

TweetNaCL

TweetNaCl is the world’s first auditable high-security cryptographic library. TweetNaCl fits into just 100 tweets while supporting all 25 of the C NaCl functions used by applications. TweetNaCl is a self-contained public-domain C library, so it can easily be integrated into applications.

http://tweetnacl.cr.yp.to/

The TweetNaCL.js project brings TweetNaCL to JavaScript and therefore to Node.js and the Web. It uses XSalsa20 (longer nonce) stream cipher instead of Salsa20.

JavaScript Benchmarks: https://github.com/dchest/tweetnacl-js/blob/master/README.md#benchmarks

Joining the JavaScript puzzle

Bob encrypts message for Alice

const nacl = require('tweetnacl')
nacl.util = require('tweetnacl-util')

// reading Bob key pair from secret key
const bob = nacl.box.keyPair.fromSecretKey(/* Uint8Array with 32-byte secret key */)
// reading Alice public key
const alice = {publicKey: /* Uint8Array with 32-byte secret key */}

// generating one time nonce for encryption
const nonce = nacl.randomBytes(24)
// message for Alice
const utf8 = 'Hello Alice'
// Bob encrypts message for Alice
const box = nacl.box(
  nacl.util.decodeUTF8(utf8),
  nonce,
  alice.publicKey,
  bob.secretKey
)
 
// somehow send this message to Alice
const message = {box, nonce} 

Alice decrypts message from Bob

const nacl = require('tweetnacl')
nacl.util = require('tweetnacl-util')

// reading Alice key pair from secret key
const alice = nacl.box.keyPair.fromSecretKey(/* Uint8Array with 32-byte secret key */)
// reading Bob public key
const bob = {publicKey: /* Uint8Array with 32-byte secret key */}
             
// const message = ... the message object from Bob
// Alice decrypts message from Bob
const payload = nacl.box.open(message.box, message.nonce, bob.publicKey, alice.secretKey)
const utf8 = nacl.util.encodeUTF8(payload) // <-- 'Hello Alice'

Using pre-computed shared keys

For encryption/decryption sessions between peers, using pre-computed shared keys is recommended:

// Bob precomputes shared key with Alice (one time)
const sharedKey = nacl.box.before(alice.publicKey, bob.secretKey)

// generating one time nonce for encryption
const nonce = nacl.randomBytes(24)

// Bob encrypt message for Alice
const box = nacl.box.after(
  nacl.util.decodeUTF8('Hello Alice'),
  nonce,
  sharedKey // <-- using shared key
)
const message = {box, nonce}

Maintaining the keys

Public Key

A “Public Key Infrastructure” requires proper solutions for the maintenance and authentication of the users public key. While this process is out of scope in this article, a common solution consist on maintaining the users public key as part of their profile page and make it accessible to their contacts through a directory-like API.

Private Key

Maintaining secret keys is a lot more complicated, as this is a very sensitive piece of information users want to keep in secret. Commonly this process is a user responsibility and somehow the applications implementing public-key cryptography are required to allow the users to enter their secret keys (never transmitting it to the server-side).

Secret keys are often stored using offline secure storage mechanisms or online, using strong symmetric encryption methods such as AES to protect the key. The second method simplifies the process of “injecting” the private key into the application(client-side decryption only), for instance: during the login phase.

Conclusions

In this article we have introduced Public-key Cryptography and how it can be implemented in JavaScript using the TweetNaCL.js library.

Using XSalsa20 instead of RSACPU usage and battery consumption are reduced to historical minimums, while keeping strong 256-bit security levels.
 — a message for your apps 😉

Digital Signatures using TweetNaCL.js will be discussed on a second post in this serie: read it here.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.