npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

blackchamber

v0.1.2

Published

Simple confidentiality and message integrity via NaCl as Express middleware.

Downloads

9

Readme

blackchamber

Simple confidentiality and message integrity via NaCl as Express middleware. MIT Licensed.

Installation

$ npm i blackchamber

Use

The intent of blackchamber is to provide message confidentiality and integrity with the minimal configuration and greatest ease-of-use within Express applications. To accomplish this, it uses Dan Bernstein's NaCl suite, implemented in libsodium and exposed to Node by libsodium.js. More specifically, it employs the ChaCha20-Poly1305 AEAD construction, with Diffie-Hellmann Exchange over Curve25519 as a key agreement scheme for its asymmetric mode. For more information, the linked pages on NaCl and libsodium are recommended sources. The library does not currently provide any mechanism for key management - as such, its recommended use is for securing communication between internal services or encryption of state information to be exposed over HTTP.

Key Generation

Although blackchamber does not provide key management, it does expose key generation wrappers for any desired use.

const blackchamber = require('blackchamber');

var symkey = blackchamber.symkg();
// { key: 'd905d138cf964a8debf75321340d4301f90839bc20926e9e79ab415aa5e65bac', keyType: 'chacha20poly1305' }

var asykey = blackchamber.asykg();
// { publicKey: '3e7f2e4680f56a59a48c091c723cf918f85d8090df65371cf6caaf141521ed62', privateKey:'c981761d12e0d616e092e2fd30cfc2e827ae025e6d039cb7dc51fbafb62873f9', keyType: 'curve25519' }
Configuration

The API for blackchamber exposed by the library is used to configure a symmetric and/or asymmetric 'cabinet' to be employed for the cryptographic operations. Although this may be done directly (and dynamically) on a specific route, the more common usage will be to set it globally.

const blackchamber = require('blackchamber');
const express = require('express');

const app = express();

app.use(blackchamber('crypto', { symmetric: { key: '3173a5188a421783a89b7f5910a57f42c830cb5bfe7c7174d1847655650fae4b' } }));

The first argument is optional, and specifies the name under which the functionality should be appended to the req object. So in the above example, the encrypt and decrypt functions will be available on req.crypto. If omitted, they are placed onto req.bc. The asymmetric cabinet is configured similarly, with a privateKey (alias secretKey or sk) and a publicKey (alias pk). Both symmetric and asymmetric cabinets may be configured at once, as well.

All keys must be hex encoded. It is of course recommended as well that they be properly secured, and not hardcoded or checked into version control.

Encryption

If only a symmetric or asymmetric cabinet is configured - but not both - then encrypting messages is straightforward.

// async
function(req, res, next) {
  var m = 'somemessage';

  req.crypto.encrypt(m, function(err, c) {
    if (err) { return next(err); }
    res.status(200).json({ ciphertext: c });
  });
}

// sync
function(req, res, next) {
  var m = 'somemessage';

  try {
    var c = req.crypto.encrypt(m);
  } catch(ex) {
    return next(ex);
  }

  res.status(200).json({ ciphertext: c });
}

It is recommended that the message be a string. However, if an object is sent, then the library will attempt to use JSON.stringify on it. The ciphertext will have the format ([0-9a-f])*([0-9a-f]{48}), where the star divides between the message and nonce components. Although they may be safely broken up, they will both be needed for the decryption process.

If multiple cabinets are configured simultaneously, then it is required to specify which one should be used. In such a case, the original function call will expose an internal function to actually handle the encryption.

// async
function(req, res, next) {
  var m = 'somemessage';

  function encrypted(err, c) {
    if (err) { return next(err); }
    res.status(200).json({ ciphertext: c });
  }

  return req.crypto.encrypt('sym', encrypted)(m);
}

// sync
function(req, res, next) {
  var m = 'somemessage';

  try {
    var c = req.crypto.encrypt('sym')(m);
  } catch(ex) {
    return next(ex);
  }

  res.status(200).json({ ciphertext: c });
}

The caller must provide sym for the symmetric cabinet, and asy for the asymmetric one. Whether or not this indicator must be programmatically provided can be checked by req[name]['direct']. If true, then it is unneccesary.

Decryption

Decryption is provided nearly identically, with the distinction that the function takes two arguments, message and nonce. However, if you provide them as a single string joined with a star (matching the output of the encryption function) then it'll properly parse it for you. Both the message and nonce components of the ciphertext must be hex encoded.

// together (async)
function(req, res, next) {
  var c = '0b0f658b7d8498fdfcb051b8a2dee4416e317b589a0ec32d29c31f9856c8d2b49057c633*14e44349261e3bb87a61a100a493d7a78aa43b83b66d7483';

  req.crypto.decrypt(c, function(err, m) {
    if (err) { return next(err); }
    res.status(200).json({ plaintext: m });
  });
}

// separated (sync)
function(req, res, next) {
  var c = '0b0f658b7d8498fdfcb051b8a2dee4416e317b589a0ec32d29c31f9856c8d2b49057c633';
  var n = '14e44349261e3bb87a61a100a493d7a78aa43b83b66d7483';

  try {
    var m = req.crypto.decrypt(c, n);
  } catch(ex) {
    return next(ex);
  }

  res.status(200).json({ plaintext: m });
}

Use with multiple cabinets is identical as in the Encryption example.

Incidentals

This library was written and is maintained by Samuel Judson. It is published under the MIT License. Pull requests and issues are welcome.