Paragon Initiative Enterprises Blog

The latest information from the team that develops cryptographically secure PHP software.

Improving the Cryptography of the JavaScript Ecosystem

It's been more than eight years since Javascript Cryptography Considered Harmful was published.

It's just as true today as it was eight years ago that JavaScript cryptography in a web browser is dangerous. But the ecosystem itself has changed immensely in this time.

JavaScript Cryptography, Considered

Between the continued rise in popularity of JavaScript frameworks (e.g. React) and the prevalence of cross-platform development tools (Cordova, Electron), it's now possible to write JavaScript code once and deploy it on a web server, in a webpage, in a browser extension, in a native mobile app, and in desktop software... with no changes to your JavaScript code.

Despite eight years of transformative change to the programming landscape, the JavaScript ecosystem has been severely neglected by the security industry, especially with regards to usable cryptography.

What PIE Has Already Done for JavaScript Cryptography

Sodium-Plus - A Positive Experience for JS Cryptography

This month we released Sodium-Plus, a pluggable, cross-platform, type-safe interface for libsodium to make it easier to write safe and secure JavaScript cryptography code. Our initial announcement was posted on dev.to.

To be clear: This isn't a new libsodium binding. What sodium-plus does is wrap one of the existing bindings (e.g. sodium-native) and—regardless of how unpleasant the low-level binding's API is to work with—lets you interact with it using a sane and simple asynchronous API.

Instead of writing code like this:

const sodium = require('sodium-native');

// Key generation
let aliceSecret = Buffer.alloc(32);
let alicePublic = Buffer.alloc(32);
let bobSecret = Buffer.alloc(32);
let bobPublic = Buffer.alloc(32);
sodium.crypto_box_keypair(alicePublic, aliceSecret);
sodium.crypto_box_keypair(bobPublic, bobSecret);

// Nonce
let nonce = Buffer.alloc(24);
sodium.randombytes_buf(nonce);

// Plaintext
let message = 'A string I want to encrypt.';
let plaintext = Buffer.from(message);

// Encrypt
let ciphertext = Buffer.alloc(plaintext.length + 16);
sodium.crypto_box_easy(ciphertext, plaintext, nonce, bobPublic, aliceSecret);
console.log(ciphertext.toString('hex'));

// Decrypt
let decrypted = Buffer.alloc(ciphertext.length - 16);
sodium.crypto_box_open_easy(decrypted, ciphertext, nonce, alicePublic, bobSecret);
console.log(decrypted.toString());

...you can just write this:

const { SodiumPlus } = require('sodium-plus');
let sodium;

(async function () {
    if (!sodium) sodium = await SodiumPlus.auto();
    let aliceKeypair = await sodium.crypto_box_keypair();
        let aliceSecret = await sodium.crypto_box_secretkey(aliceKeypair);
        let alicePublic = await sodium.crypto_box_publickey(aliceKeypair);
    let bobKeypair = await sodium.crypto_box_keypair();
        let bobSecret = await sodium.crypto_box_secretkey(bobKeypair);
        let bobPublic = await sodium.crypto_box_publickey(bobKeypair);
    
    let nonce = await sodium.randombytes_buf(24);
    let plaintext = 'Your message goes here';
    let ciphertext = await sodium.crypto_box(plaintext, nonce, aliceSecret, bobPublic);    
    console.log(ciphertext.toString('hex'));

    let decrypted = await sodium.crypto_box_open(ciphertext, nonce, bobSecret, alicePublic);
    console.log(decrypted.toString());
})();

The second snippet works in browsers, browser extensions, mobile apps, desktop apps, and webservers, without requiring a C compiler be integrated into your JavaScript toolkit.

By default, Sodium-Plus uses libsodium-wrappers. However, if sodium-native is installed, it will opportunistically use that first, since sodium-native offers much better performance.

One of the many features included in Sodium-Plus is type-safety with cryptography keys. An Ed25519SecretKey cannot be used by crypto_box(), only by crypto_sign(). This prevents a whole host of usage mistakes that passing around bare Buffer objects cannot prevent.

Check out the Sodium-Plus documentation for more information.

Certainty.js: CACert Management for JavaScript Projects

We originally created Certainty to solve the problem of "developers disabling SSL/TLS verification", which was in many cases actually a symptom of the "unreliable/outdated CACert bundle" problem.

Until recently, there was no congruent means for auto-updating your CACert bundles for Node.js developers. So we decided to write certainty.js.

const {Certainty} = require('certainty-js');
const http = require('request-promise-native');

(async function () {
    let options = {
        'ca': await Certainty.getLatestCABundle('/path/to/directory'),
        'uri': 'https://php-chronicle.pie-hosted.com/chronicle/lasthash',
        'minVersion': 'TLSv1.2',
        'strictSSL': true,
        'timeout': 30000
    };

    // Send request...
    console.log(await http.get(options));
})();

The next releases of Certainty.js will include the LocalCACertBuilder features from the PHP version, as well as a refactor to use Sodium-Plus.

CipherSweet.js

Scenario: You need to encrypt some of your database fields, but you still need to use those fields in SELECT queries somehow. Is there a secure way to achieve this result without having to invoke a lot of new and experimental cryptography primitives?

It turns out: Yes, you can. Our proposed implementation is called CipherSweet.

CipherSweet has already been ported from PHP to Node.js, with other languages coming soon.

You can find CipherSweet-js on Github. The documentation is available on our website.

Our Work Continues

Like many other programming languages, JavaScript has its own needs and unique challenges. We remain committed to improving the security and usability of the languages, frameworks, and tools developers want to use, and strive towards a more private and secure Internet for everyone.

If your company relies on PHP or JavaScript code and needs expert assistance with solving cryptography problems in your application, reach out to us. We write code, audit code, and offer consultation for security designs.

About the Author

Scott Arciszewski

Chief Development Officer

With 15 years of software development, application security, and system administration experience, Scott aspires to help others attain a happier work-life balance by solving difficult problems and automating trivial tasks. He is mostly known in the community for his open source software security research and strong progressive positions on providing tools and frameworks that are secure by default. @CiPHPerCoder


Need Technology Consultants?

Will tomorrow bring costly and embarrassing data breaches? Or will it bring growth, success, and peace of mind?

Our team of technology consultants have extensive knowledge and experience with application security and web/application development.

We specialize in cryptography and secure PHP development.

Let's Work Together Towards Success

Our Security Newsletters

Want the latest from Paragon Initiative Enterprises delivered straight to your inbox? We have two newsletters to choose from.

The first mails quarterly and often showcases our behind-the-scenes projects.

The other is unscheduled and gives you a direct feed into the findings of our open source security research initiatives.

Quarterly Newsletter   Security Announcements