• Stars
    star
    700
  • Rank 64,671 (Top 2 %)
  • Language
    JavaScript
  • License
    Apache License 2.0
  • Created over 9 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

node-jose

Greenkeeper badge Build Status

A JavaScript implementation of the JSON Object Signing and Encryption (JOSE) for current web browsers and node.js-based servers. This library implements (wherever possible) all algorithms, formats, and options in JWS, JWE, JWK, and JWA and uses native cryptographic support (WebCrypto API or node.js' "crypto" module) where feasible.

Installing

To install the latest from NPM:

  npm install node-jose

Or to install a specific release:

  npm install [email protected]

Alternatively, the latest unpublished code can be installed directly from the repository:

  npm install git+https://github.com/cisco/node-jose.git

Basics

Require the library as normal:

var jose = require('node-jose');

This library uses Promises for nearly every operation.

This library supports Browserify and Webpack. To use in a web browser, require('node-jose') and bundle with the rest of your app.

The content to be signed/encrypted -- or returned from being verified/decrypted -- are Buffer objects.

Keys and Key Stores

The jose.JWK namespace deals with JWK and JWK-sets.

  • jose.JWK.Key is a logical representation of a JWK, and is the "raw" entry point for various cryptographic operations (e.g., sign, verify, encrypt, decrypt).
  • jose.JWK.KeyStore represents a collection of Keys.

Creating a JWE or JWS ultimately require one or more explicit Key objects.

Processing a JWE or JWS relies on a KeyStore.

Obtaining a KeyStore

To create an empty keystore:

keystore = jose.JWK.createKeyStore();

To import a JWK-set as a keystore:

// {input} is a String or JSON object representing the JWK-set
jose.JWK.asKeyStore(input).
     then(function(result) {
       // {result} is a jose.JWK.KeyStore
       keystore = result;
     });

Exporting a KeyStore

To export the public keys of a keystore as a JWK-set:

output = keystore.toJSON();

To export all the keys of a keystore:

output = keystore.toJSON(true);

Retrieving Keys

To retrieve a key from a keystore:

// by 'kid'
key = keystore.get(kid);

This retrieves the first key that matches the given {kid}. If multiple keys have the same {kid}, you can further narrow what to retrieve:

// ... and by 'kty'
key = keystore.get(kid, { kty: 'RSA' });

// ... and by 'use'
key = keystore.get(kid, { use: 'enc' });

// ... and by 'alg'
key = keystore.get(kid, { use: 'RSA-OAEP' });

// ... and by 'kty' and 'use'
key = keystore.get(kid, { kty: 'RSA', use: 'enc' });

// same as above, but with a single {props} argument
key = keystore.get({ kid: kid, kty: 'RSA', use: 'enc' });

Searching for Keys

To retrieve all the keys from a keystore:

everything = keystore.all();

all() can be filtered much like get():

// filter by 'kid'
everything = keystore.all({ kid: kid });

// filter by 'kty'
everything = keystore.all({ kty: 'RSA' });

// filter by 'use'
everything = keystore.all({ use: 'enc' });

// filter by 'alg'
everything = keystore.all({ alg: 'RSA-OAEP' });

// filter by 'kid' + 'kty' + 'alg'
everything = keystore.all({ kid: kid, kty: 'RSA', alg: 'RSA-OAEP' });

Managing Keys

To import an existing Key (as a JSON object or Key instance):

// input is either a:
// *  jose.JWK.Key to copy from; or
// *  JSON object representing a JWK; or
keystore.add(input).
        then(function(result) {
          // {result} is a jose.JWK.Key
          key = result;
        });

To import and existing Key from a PEM or DER:

// input is either a:
// *  String serialization of a JSON JWK/(base64-encoded) PEM/(binary-encoded) DER
// *  Buffer of a JSON JWK/(base64-encoded) PEM/(binary-encoded) DER
// form is either a:
// * "json" for a JSON stringified JWK
// * "private" for a DER encoded 'raw' private key
// * "pkcs8" for a DER encoded (unencrypted!) PKCS8 private key
// * "public" for a DER encoded SPKI public key (alternate to 'spki')
// * "spki" for a DER encoded SPKI public key
// * "pkix" for a DER encoded PKIX X.509 certificate
// * "x509" for a DER encoded PKIX X.509 certificate
// * "pem" for a PEM encoded of PKCS8 / SPKI / PKIX
keystore.add(input, form).
        then(function(result) {
          // {result} is a jose.JWK.Key
        });

To generate a new Key:

// first argument is the key type (kty)
// second is the key size (in bits) or named curve ('crv') for "EC"
keystore.generate("oct", 256).
        then(function(result) {
          // {result} is a jose.JWK.Key
          key = result;
        });

// ... with properties
var props = {
  kid: 'gBdaS-G8RLax2qgObTD94w',
  alg: 'A256GCM',
  use: 'enc'
};
keystore.generate("oct", 256, props).
        then(function(result) {
          // {result} is a jose.JWK.Key
          key = result;
        });

To remove a Key from its Keystore:

keystore.remove(key);
// NOTE: key.keystore does not change!!

Importing and Exporting a Single Key

To create a single "stand alone" key:

jose.JWK.createKey("oct", 256, { alg: "A256GCM" }).
         then(function(result) {
           // {result} is a jose.JWK.Key
           // {result.keystore} is a unique jose.JWK.KeyStore
         });

To import a single Key:

// where input is either a:
// *  jose.JWK.Key instance
// *  JSON Object representation of a JWK
jose.JWK.asKey(input).
        then(function(result) {
          // {result} is a jose.JWK.Key
          // {result.keystore} is a unique jose.JWK.KeyStore
        });

// where input is either a:
// *  String serialization of a JSON JWK/(base64-encoded) PEM/(binary-encoded) DER
// *  Buffer of a JSON JWK/(base64-encoded) PEM/(binary-encoded) DER
// form is either a:
// * "json" for a JSON stringified JWK
// * "pkcs8" for a DER encoded (unencrypted!) PKCS8 private key
// * "spki" for a DER encoded SPKI public key
// * "pkix" for a DER encoded PKIX X.509 certificate
// * "x509" for a DER encoded PKIX X.509 certificate
// * "pem" for a PEM encoded of PKCS8 / SPKI / PKIX
jose.JWK.asKey(input, form).
        then(function(result) {
          // {result} is a jose.JWK.Key
          // {result.keystore} is a unique jose.JWK.KeyStore
        });

To export the public portion of a Key as a JWK:

var output = key.toJSON();

To export the public and private portions of a Key:

var output = key.toJSON(true);

Obtaining a Key's Thumbprint

To get or calculate a RFC 7638 thumbprint for a key:

// where hash is a supported algorithm, currently one of:
// * SHA-1
// * SHA-256
// * SHA-384
// * SHA-512
key.thumbprint(hash).
    then(function(print) {
      // {print} is a Buffer containing the thumbprint binary value
    });

When importing or generating a key that does not have a "kid" defined, a "SHA-256" thumbprint is calculated and used as the "kid".

Signatures

Keys Used for Signing and Verifying

When signing content, the key is expected to meet one of the following:

  1. A secret key (e.g, "kty":"oct")
  2. The private key from a PKI ("kty":"EC" or "kty":"RSA") key pair

When verifying content, the key is expected to meet one of the following:

  1. A secret key (e.g, "kty":"oct")
  2. The public key from a PKI ("kty":"EC" or "kty":"RSA") key pair

Signing Content

At its simplest, to create a JWS:

// {input} is a Buffer
jose.JWS.createSign(key).
        update(input).
        final().
        then(function(result) {
          // {result} is a JSON object -- JWS using the JSON General Serialization
        });

The JWS is signed using the preferred algorithm appropriate for the given Key. The preferred algorithm is the first item returned by key.algorithms("sign").

To create a JWS using another serialization format:

jose.JWS.createSign({ format: 'flattened' }, key).
        update(input).
        final().
        then(function(result) {
          // {result} is a JSON object -- JWS using the JSON Flattened Serialization
        });

jose.JWS.createSign({ format: 'compact' }, key).
        update(input).
        final().
        then(function(result) {
          // {result} is a String -- JWS using the Compact Serialization
        });

To create a JWS using a specific algorithm:

jose.JWS.createSign({ fields: { alg: 'PS256' } }, key).
        update(input).
        final().
        then(function(result) {
          // ....
        });

To create a JWS for a specified content type:

jose.JWS.createSign({ fields: { cty: 'jwk+json' } }, key).
        update(input).
        final().
        then(function(result) {
          // ....
        });

To create a JWS from String content:

jose.JWS.createSign(key).
        update(input, "utf8").
        final().
        then(function(result) {
          // ....
        });

To create a JWS with multiple signatures:

// {keys} is an Array of jose.JWK.Key instances
jose.JWS.createSign(keys).
        update(input).
        final().
        then(function(result) {
          // ....
        });

Verifying a JWS

To verify a JWS, and retrieve the payload:

jose.JWS.createVerify(keystore).
        verify(input).
        then(function(result) {
          // {result} is a Object with:
          // *  header: the combined 'protected' and 'unprotected' header members
          // *  payload: Buffer of the signed content
          // *  signature: Buffer of the verified signature
          // *  key: The key used to verify the signature
        });

To verify using an implied Key:

// {key} can be:
// *  jose.JWK.Key
// *  JSON object representing a JWK
jose.JWS.createVerify(key).
        verify(input).
        then(function(result) {
          // ...
        });

To verify using a key embedded in the JWS:

jose.JWS.createVerify().
        verify(input, { allowEmbeddedKey: true }).
        then(function(result) {
          // ...
        });

Alternatively, a cached createVerify() can be configured to allow an embedded key:

var verifier = jose.JWS.createVerify({ allowEmbeddedKey: true });

verifier.verify(input).
         then(function(result) {
           // ...
         });

The key can be embedded using either 'jwk' or 'x5c', and can be located in either the JWS Unprotected Header or JWS Protected Header.

NOTE: verify() will use the embedded key (if found and permitted) instead of any other key.

Allowing (or Disallowing) Signature Algorithms

To restrict what signature algorithms are allowed when verifying, add the algorithms member to the options Object. The algorithms member is either a string or an array of strings, where the string value(s) can be one of the following:

  • "*": accept all supported algorithms
  • <alg name> (e.g., "PS256"): accept the specific algorithm (can have a single '*' to match a range of algorithms)
  • !<alg name> (e.g., "!RS256"): do not accept the specific algorithm (can have a single '*' to match a range of algorithms)

The negation is intended to be used with the wildcard accept string, and disallow takes precedence over allowed.

To only accept RSA-PSS sigatures:

var opts = {
  algorithms: ["PS*"]
};
jose.JWS.createVerify(key, opts).
        verify(input).
        then(function(result) {
          // ...
        });

To accept any algorithm, but disallow HMAC-based signatures:

var opts = {
  algorithms: ["*", "!HS*"]
};
jose.JWS.createVerify(key, opts).
        verify(input).
        then(function(result) {
          // ...
        });

Handling crit Header Members

To accept 'crit' field members, add the handlers member to the options Object. The handlers member is itself an Object, where its member names are the crit header member, and the value is one of:

  • Function: takes the JWE decrypt output (just prior to decrypting) and returns a Promise for the processing of the member.
  • Object: An object with the following Function members:
    • "prepare" -- takes the JWE decrypt output (just prior to decrypting) and returns a Promise for the processing of the member.
    • "complete" -- takes the JWE decrypt output (immediately after decrypting) and returns a Promise for the processing of the member.

NOTE If the handler function returns a promise, the fulfilled value is ignored. It is expected these handler functions will modify the provided value directly.

To perform additional (pre-verify) processing on a crit header member:

var opts = {
  handlers: {
    "exp": function(jws) {
      // {jws} is the JWS verify output, pre-verification
      jws.header.exp = new Date(jws.header.exp);
    }
  }
};
jose.JWS.createVerify(key, opts).
        verify(input).
        then(function(result) {
          // ...
        });

To perform additional (post-verify) processing on a crit header member:

var opts = {
  handlers: {
    "exp": {
      complete: function(jws) {
        // {jws} is the JWS verify output, post-verification
        jws.header.exp = new Date(jws.header.exp);
      }
    }
  }
};
jose.JWS.createVerify(key, opts).
        verify(input).
        then(function(result) {
          // ...
        });

Encryption

Keys Used for Encrypting and Decrypting

When encrypting content, the key is expected to meet one of the following:

  1. A secret key (e.g, "kty":"oct")
  2. The public key from a PKI ("kty":"EC" or "kty":"RSA") key pair

When decrypting content, the key is expected to meet one of the following:

  1. A secret key (e.g, "kty":"oct")
  2. The private key from a PKI ("kty":"EC" or "kty":"RSA") key pair

Encrypting Content

At its simplest, to create a JWE:

// {input} is a Buffer
jose.JWE.createEncrypt(key).
        update(input).
        final().
        then(function(result) {
          // {result} is a JSON Object -- JWE using the JSON General Serialization
        });

How the JWE content is encrypted depends on the provided Key.

  • If the Key only supports content encryption algorithms, then the preferred algorithm is used to encrypt the content and the key encryption algorithm (i.e., the "alg" member) is set to "dir". The preferred algorithm is the first item returned by key.algorithms("encrypt").
  • If the Key supports key management algorithms, then the JWE content is encrypted using "A128CBC-HS256" by default, and the Content Encryption Key is encrypted using the preferred algorithms for the given Key. The preferred algorithm is the first item returned by key.algorithms("wrap").

To create a JWE using a different serialization format:

jose.JWE.createEncrypt({ format: 'compact' }, key).
        update(input).
        final().
        then(function(result) {
          // {result} is a String -- JWE using the Compact Serialization
        });

jose.JWE.createEncrypt({ format: 'flattened' }, key).
        update(input).
        final().
        then(function(result) {
          // {result} is a JSON Object -- JWE using the JSON Flattened Serialization
        });

To create a JWE and compressing the content before encrypting:

jose.JWE.createEncrypt({ zip: true }, key).
        update(input).
        final().
        then(function(result) {
          // ....
        });

To create a JWE for a specific content type:

jose.JWE.createEncrypt({ fields: { cty : 'jwk+json' } }, key).
        update(input).
        final().
        then(function(result) {
          // ....
        });

To create a JWE with multiple recipients:

// {keys} is an Array of jose.JWK.Key instances
jose.JWE.createEncrypt(keys).
        update(input).
        final().
        then(function(result) {
          // ....
        });

Decrypting a JWE

To decrypt a JWE, and retrieve the plaintext:

jose.JWE.createDecrypt(keystore).
        decrypt(input).
        then(function(result) {
          // {result} is a Object with:
          // *  header: the combined 'protected' and 'unprotected' header members
          // *  protected: an array of the member names from the "protected" member
          // *  key: Key used to decrypt
          // *  payload: Buffer of the decrypted content
          // *  plaintext: Buffer of the decrypted content (alternate)
        });

To decrypt a JWE using an implied key:

jose.JWE.createDecrypt(key).
        decrypt(input).
        then(function(result) {
          // ....
        });

Allowing (or Disallowing) Encryption Algorithms

To restrict what encryption algorithms are allowed when verifying, add the algorithms member to the options Object. The algorithms member is either a string or an array of strings, where the string value(s) can be one of the following:

  • "*": accept all supported algorithms
  • <alg name> (e.g., "A128KW"): accept the specific algorithm (can have a single '*' to match a range of similar algorithms)
  • !<alg name> (e.g., "!RSA1_5"): do not accept the specific algorithm (can have a single '*' to match a range of similar algorithms)

The negation is intended to be used with the wildcard accept string, and disallow takes precedence over allowed.

To only accept "dir" and AES-GCM encryption:

var opts = {
  algorithms: ["dir", "A*GCM"]
};
jose.JWE.createDecrypt(key, opts).
        decrypt(input).
        then(function(result) {
          // ...
        });

To accept any algorithm, but disallow RSA-based encryption:

var opts = {
  algorithms: ["*", "!RSA*"]
};
jose.JWS.createVerify(key, opts).
        verify(input).
        then(function(result) {
          // ...
        });

Handling crit Header Members

To accept 'crit' field members, add the handlers member to the options Object. The handlers member is itself an Object, where its member names are the crit header member, and the value is one of:

  • Function: takes the JWE decrypt output (just prior to decrypting) and returns a Promise for the processing of the member.
  • Object: An object with the following Function members:
    • "prepare" -- takes the JWE decrypt output (just prior to decrypting) and returns a Promise for the processing of the member.
    • "complete" -- takes the JWE decrypt output (immediately after decrypting) and returns a Promise for the processing of the member.

NOTE If the handler function returns a promise, the fulfilled value is ignored. It is expected these handler functions will modify the provided value directly.

To perform additional (pre-decrypt) processing on a crit header member:

var opts = {
  handlers: {
    "exp": function(jwe) {
      // {jwe} is the JWE decrypt output, pre-decryption
      jwe.header.exp = new Date(jwe.header.exp);
    }
  }
};
jose.JWE.createDecrypt(key, opts).
        decrypt(input).
        then(function(result) {
          // ...
        });

To perform additional (post-decrypt) processing on a crit header member:

var opts = {
  handlers: {
    "exp": {
      complete: function(jwe) {
        // {jwe} is the JWE decrypt output, post-decryption
        jwe.header.exp = new Date(jwe.header.exp);
      }
    }
  }
};
jose.JWE.createDecrypt(key, opts).
        decrypt(input).
        then(function(result) {
          // ...
        });

Useful Utilities

Converting to Buffer

To convert a Typed Array, ArrayBuffer, or Array of Numbers to a Buffer:

buff = jose.util.asBuffer(input);

URI-Safe Base64

This exposes urlsafe-base64's encode and decode methods as encode and decode (respectively).

To convert from a Buffer to a base64uri-encoded String:

var output = jose.util.base64url.encode(input);

To convert a String to a base64uri-encoded String:

// explicit encoding
output = jose.util.base64url.encode(input, "utf8");

// implied "utf8" encoding
output = jose.util.base64url.encode(input);

To convert a base64uri-encoded String to a Buffer:

var output = jose.util.base64url.decode(input);

Random Bytes

To generate a Buffer of octets, regardless of platform:

// argument is size (in bytes)
var rnd = jose.util.randomBytes(32);

This function uses:

  • crypto.randomBytes() on node.js
  • crypto.getRandomValues() on modern browsers
  • A PRNG based on AES and SHA-1 for older platforms

More Repositories

1

ChezScheme

Chez Scheme
Scheme
6,965
star
2

openh264

Open Source H.264 Codec
C++
5,527
star
3

joy

A package for capturing and analyzing network flow data and intraflow data, for network research, forensics, and security monitoring.
C
1,301
star
4

libsrtp

Library for SRTP (Secure Realtime Transport Protocol)
C
1,209
star
5

thor

Thor Video Codec
C
697
star
6

mindmeld

An Open Source Conversational AI Platform for Deep-Domain Voice Interfaces and Chatbots.
Python
673
star
7

mercury

Mercury: network metadata capture and analysis
C++
437
star
8

cisco-mibs

Various SNMP MIBs from Cisco
HTML
144
star
9

exanic-software

ExaNIC drivers, utilities and development libraries
C
138
star
10

mlspp

Implementation of Messaging Layer Security
C++
108
star
11

cjose

C library implementing the Javascript Object Signing and Encryption (JOSE)
C
105
star
12

libest

C
97
star
13

elsy

An opinionated, multi-language, build tool based on Docker and Docker Compose
Go
79
star
14

lal-build-manager

Project dependency manager
Rust
75
star
15

libacvp

The libacvp library is a client-side implementation of the draft ACVP protocol (github.com/usnistgov/ACVP).
C
65
star
16

ns3-802.11ax-simulator

NS3 Simulator of 802.11ax
C++
58
star
17

cisco-network-puppet-module

Ruby
55
star
18

open-nFAPI

An open source implementation of the Small Cell Forum's Network Functional API (nFAPI)
C
54
star
19

ns3-rmcat

Simulator of IETF RMCAT congestion control protocols
C++
50
star
20

go-mls

Message Layer Security
Go
48
star
21

cisco.github.io

Public Github Pages for Cisco
JavaScript
45
star
22

libfnr

FNR is a small domain block cipher to encrypt small objects ( < 128 bits )
C
40
star
23

senml

Tool to convert senml between formats and act as gateway server to other services
Go
39
star
24

opus

Cisco work on the Opus codec
C
31
star
25

hash-sigs

A full-featured implementation of of the LMS and HSS Hash Based Signature Schemes from draft-mcgrew-hash-sigs-07.
C
31
star
26

go-hpke

Implementation of draft-irtf-cfrg-hpke
Go
30
star
27

cisco-network-node-utils

Ruby
29
star
28

systemf

Prepared statement support for the system command
C
29
star
29

cisco-network-chef-cookbook

Ruby
27
star
30

OpenOSC

Open Object Size Checking: Library to detect buffer overflows in C/C++ code
C
27
star
31

NATTools

NAT Tools
C
26
star
32

ActionOrchestratorContent

A repository for Action Orchestrator content definitions. Includes workflows and Atomic Workflow Adapters as well as general adapter definitions.
25
star
33

exact-capture

Exablaze High Rate Capture Software
C
23
star
34

oraf

Optimized RAndom Forests
Scala
22
star
35

node-kms

node-scr
JavaScript
21
star
36

JabberWerxC

A C API for XMPP connectivity
C
18
star
37

zepster

Generate database schema, documentation, and other artifacts from an Entity-Relationship diagram, which is created as a GraphML file using the yEd graph editor.
Python
17
star
38

firepower-ngfw

Firepower Threat Defense Virtual templates and artifacts
13
star
39

cisco-yang-puppet-module

Puppet module to allow configuration of IOS-XR via YANG
Ruby
11
star
40

anyconnect-kdf

Cisco AnyConnect Linux Kernel Module
C
11
star
41

webex-assistant-sdk

An SDK for developing Webex Assistant Skills based on the MindMeld platform.
Python
11
star
42

xr-telemetry-m2m-web

A small web app to explore the IOS-XR internal data model, for streaming telemetry or other automation uses
Python
10
star
43

herisson

C++
10
star
44

goFish

Finding Fish
C++
9
star
45

cisco-nxapi

Ruby
8
star
46

asav

ASAv templates and artifacts
8
star
47

syncodecs

Synthetic codecs for evaluation of RMCAT work
C++
7
star
48

ciscohls

C
7
star
49

multilingual-speech-testing

Test software and data for evaluation of speech processing algorithms in multiple languages
Python
7
star
50

sframe

Implementation of draft-omara-sframe
C++
6
star
51

hyperledger-est-ca

EST CA for Hyperledger Fabric
Go
6
star
52

SSMAMTtools

C
6
star
53

ciscoacipuppet

Ruby
6
star
54

gse

Game State Encoder and Decoder for RTP
C++
6
star
55

go-tls-syntax

Encode and decode messages in TLS 1.3 syntax
Go
6
star
56

jfnr

Java bindings for FNR block cipher
Java
5
star
57

usnic_tools

usNIC tools
C
4
star
58

ampfsm

Cisco AMP Filesystem Module
C
4
star
59

arc

Go
4
star
60

xr-telemetry-m2m-lib

Libraries for interacting with the IOS-XR M2M service.
Python
3
star
61

JdbcDecorator

Java
3
star
62

gst-plugin-dlnasrc

A fork of the original gst-dlna-src plugin, these modifications make the plugin work with the RDK server
C
3
star
63

ampnetworkflow

Cisco AMP Device Flow Control
C
3
star
64

libamvp

A client-side implementation of the AMVP protocol.
C
2
star
65

guppi

Grand Unified Platform for Process Interactions: A DevOps Environment for Data Scientists
Python
2
star
66

cisco-otel-java

Cisco Distribution of OpenTelemetry Java
1
star
67

WXM-Invitations

Optional module for dispatching SMS and Email invitations for Cisco Webex Experience Management Surveys from your private cloud
C#
1
star
68

cgmi

C
1
star
69

libusnic_verbs

Perl
1
star
70

node-scr

JavaScript
1
star
71

pam_mpa

PAM module providing Multi-Person Authentication against local (/etc/shadow)
C
1
star