introduction to jsrsasign

pure JavaScript cryptographic library

https://kjur.github.io/jsrsasign

slide r1.4 (2017 Sep 16 for jsrsasign 8.0.4)

@kjur / Kenji Urushima



press ← ↑ → ↓ key or right bottom buttons to move slides

Table of Contents

Overview

The "jsrsasign" (https://kjur.github.io/jsrsasign/) is a open source free cryptograhic library implemented by pure JavaScript. It supports a lot of features such as following:

  • strong RSA/DSA/ECDSA key utility
  • RSA/DSA/ECDSA digital signature
  • message authentication code(MAC)
  • hash (MD5,RIPEMD,SHA1,SHA2)
  • simple ASN.1 parser
  • ASN.1 object generator
  • X.509 certificate and CRL, OCSP
  • PKCS#1/5/8 private/public key
  • PKCS#10/CSR
  • CMS SignedData
  • RFC 3161 TimeStamp
  • CAdES long term signature
  • JWS (JSON Web Signatures)
  • JWT (JSON Web Token)
  • JWK (JSON Web Key)
  • string utility

Overview (cont'd)

  • well-documented
    "jsrsasign" has rich API reference and tutorial so that you can learn easily.
  • many samples and tools
    "jsrsasign" provides many samples and tools.
  • easy installation
    "jsrsasign" can be easily installed by "git clone", bower and npm. There is no dependency to other package or module.
  • works on most of browsers and Node.js
    "jsrsasign" doesn't require any special feature of JavaScript on the browser such like W3C Web Crypto or Promise. This works on most of browsers and Node.js as if old one.
  • MIT license
    "jsrsasign" is licensed under "MIT License" which is short and permissive for developers convenience.

jsrsasign architecture


How to use or install

For bower:
% bower install jsrsasign
For Node.js:
% npm install -g jsrsasign (for global installation)
Off course, you can use git:
% git clone https://github.com/kjur/jsrsasign.git
Or to use it in your web page, add following in your HTML:
<script src="https://kjur.github.io/jsrsasign/jsrsasign-all-min.js"></script>

RSA/DSA/ECDSA public key cryptography

KEYUTIL class: Features

  • supports RSA/DSA/ECC algorithm
  • generateKeypair() for RSA/ECC
  • getKey(): key loader
    • PKCS#1/5 plain/encrypted private/public PEM/HEX key
    • PKCS#8 plain/encrypted private/public PEM/HEX key
    • X.509 PEM certificate
    • public/private RFC 7517 JSON Web Key (JWK)
  • getPEM() to get plain/encrypted private/public PKCS#1/5/8 PEM
  • getJWKFromKey() to get RFC 7517 JSON Web Key (JWK)

KEYUTIL.generateKeypair()

generateKeypair method can be used to generate RSA/ECC key pair.


// RSA
keypair = KEYUTIL.generateKeypair("RSA", 2048);
// ECC
keypair = KEYUTIL.generateKeypair("EC", "secp256r1");
//
// private key object: keypair.prvKeyObj
// public key object: keypair.pubKeyObj

KEYUTIL.getKey()

getKey method can load a lot of format of public and private key such as PKCS#1/5/8 or JWK very easily.


// PKCS#8 public key
pub = KEYUTIL.getKey("-----BEGIN PUBLIC KEY...");
// public key from X.509 certificate
pub = KEYUTIL.getKey("-----BEGIN CERTIFICATE...");
// PKCS#8 encrypted private with password
prv = KEYUTIL.getKey("-----BEGIN ENCRYPTED PRIVATE KEY...", "pass");

sign data

sign a data with your private key using Signature object as like Java JCE.


// load private key
prv = KEYUTIL.getKey("-----BEGIN ENCRYPTED PRIVATE KEY...", "pass");
// generate Signature object
sig = new KJUR.crypto.Signature({"alg": "SHA256withRSA"});
// set private key for sign
sig.init(prv);
// update data
sig.updateString("aaa");
// calculate signature
sigHex = sig.sign();

verify signature

sign a data with your private key using Signature object as like Java JCE.


// load public key
pub = KEYUTIL.getKey("-----BEGIN CERTIFICATE...");
// generate Signature object
sig = new KJUR.crypto.Signature({"alg": "SHA256withRSA"});
// set private key for sign
sig.init(pub);
// update data
sig.updateString("aaa");
// verify signature
isValid = sig.verify(sigValueHex);

Cryptographic Hash
SHA1/SHA2/MD5/RIPEMD160

calculate hash by MessageDigest class

calculate hash using MessageDigest class just like Java JCE


// generate MessageDigest object for SHA384
md = new KJUR.crypto.MessageDigest({alg: "sha384"});
// append data for hash
md.updateString("aaa");
// calculate hash finally
mdHex = md.digest();

// or use Util class in short. These three will get the same result.
mdHex = KJUR.crypto.Util.sha384("aaa");
mdHex = KJUR.crypto.Util.hashString("aaa","sha384");
mdHex = KJUR.crypto.Util.hashHex("616161","sha384");

Message Authentication Code
(HmacSHA1/SHA2/MD5)

calculate Mac by Mac class

calculate message authentication code by Mac class just like Java JCE


// generate Mac class
mac = new KJUR.crypto.Mac({alg: "HmacSHA256", pass: "pass"});
// append data for Mac
mac.updateString('aaa');
// get Mac value
macHex = md.doFinal();

pass parameter supports some value formats like this:

hexadecimal{hex: "616161"}
UTF-8{utf8: "東京"}
Base64{b64: "Mi02/+...a=="}
Base64URL{b64u: "Mi02_-...a"}

short ASN.1 introduction

short ASN.1 introduction

ASN.1 is a binary encoding of structured data consists of a data type tag(T), byte length(L) and value(V).

ASN.1 encoding is used in network protocol or format such like X.509 certificate, private/public key formats, S/MIME data, digital time stamp, Radius.

FEATURE1: variable length data exceeds int or long.
FEATURE2: structured data is also available.

short ASN.1 introduction (cont'd)

Structured data can be represented by SEQUENCE or SET.

ASN1HEX

simple ASN.1 parser for hexadecimal string

ASN1HEX basic methods

ASN1HEX methods can be used for getting tag, length or value of ASN.1 object of hexadecimal string at specified position.

ASN1HEX basic methods (cont'd)

get a list of indexes of child elements.

ASN1HEX for descendant element

To refer a descendant element of nested structured ASN.1, use "List" which represent indexes for each nested layer. This is very useful to specify a deep nested element such like subject name of X.509 certificate.

SEQUENCE                     idx=0
    SET                      [0] idx=4
        INTEGER 4            [0,0] idx=8 ← You want to refer
        INTEGER 31           [0,1] idx=14
    SET                      [1]
        UTF8STRING "aaa"     [1,0]
        IA5STRING "bbb"      [1,1]
getTLVbyList(s,0,[0,0]) → "020104" getVbyList(s,0,[0,0]) → "04"
getIdxbyList(s,0,[0,0]) → 8 getLbyList(s,0,[0,0]) → "01"

X509

simple X.509 certificate parser as ASN.1

X509 class

Basic fields and extensions can be get by X509 class.


x = new X509();
x.readCertPEM(sCertPEM);
hex = pemtohex(sCertPEM);

// get subject
subject = x.getSubjectString(); // return like "/C=US/O=OTEST"

// get subjectAltName
san = x.getExtSubjectAltName(hex);
// return like ["example.com", "example.org"]

There are a lot of methods to get fields and extensions.
Please see manual in detail.

generate and encode ASN.1

generate and encode ASN.1 (cont'd)

Classes for ASN.1 primitives and structured types, as well as X.509 certificate, CRL, CSR, CMS signed data, digital time stamp and CAdES are defined in jsrsasign.


i1 = new KJUR.asn1.DERInteger({int: 234});
s1 = new KJUR.asn1.DERUTF8String({str: 'Tokyo'}});
seq = new KJUR.asn1.DERSequence({array: [i1, s1]});
hex = seq.getEncodedHex();


Please see manual in detail.
It's very similar to BouncyCastle or IAIK Java ASN.1 classes.
However, there is much more easy way...

generate and encode ASN.1 using newObject

It's very easy to generate complicated ASN.1 object by ASN1Util.newObject


var hex = new KJUR.asn1.ASN1Util.newObject(
  {seq: [              // SEQUENCE
     {int: 234},          // INTEGER
     {utf8str: 'Tokyo'}      // UTF8String
     ]}
).getEncodedHex();

get PEM of X.509 certificate by X509Util.newCertPEM

It's very easy to generate PEM of X.509 certificate by X509Util.newCertPEM.


pem = new KJUR.asn1.x509.X509Util.newCertPEM({
  serial: {int: 4},
  sigalg: {name: 'SHA256withECDSA', paramempty: true},
  issuer: {str: '/C=US/O=CA1'},
  notbefore: {str: '130504235959Z'}, notafter: {str: '140504235959Z'},
  subject: {str: '/C=US/O=T1'},
  sbjpubkey: "-----BEGIN PUBLIC KEY...",
  ext: [
    {basicConstraints: {cA: true, critical: true}},
    {keyUsage: {bin: '11'}},
  ],
  cakey: ["-----BEGIN PRIVATE KEY...", "pass"]
});

get PEM of PKCS#10/CSR by CSRUtil.newCSRPEM

It's very easy to generate PEM of CSR(certificate signing request) by CSRUtil.newCSRPEM.


kp = KEYUTIL.generateKeypair("RSA", 2048);
pem = new KJUR.asn1.csr.CSRUtil.newCSRPEM({
  subject: {str: '/C=US/O=Test/CN=example.com'},
  sbjpubkey: kp.pubKeyObj,
  sigalg: "SHA256withRSA",
  sbjprvkey: kp.prvKeyObj
});

OCSP Request

It's very easy to generate OCSP request by OCSPUtil.getRequestHex.


// generate OCSP request
hexRequest = KJUR.asn1.ocsp.OCSPUtil.getRequestHex(
  "-----BEGIN CERTIFICATE...",  // issuer Cert
  "-----BEGIN CERTIFICATE..."); // Cert to be verified

You can save this as binary and send it to OCSP responder like this:


% curl --verbose --data-binary @req.bin
  -H "Content-Type:application/ocsp-request" --url http://ocsp

JWK
JWS
JWT

JWK (JSON Web Key)

jsrsasign can load and export RFC 7517 JSON Web Key (JWK).


// load JWK
jwkPub = {kty: "EC", crv: "P-256", x: "f830J3..." ...};
keyObj = KEYUTIL.getKey(jwkPub);

// export to JWK
kp = KEYUTIL.generateKeypair("RSA", 2048);
jwkPrv = KEYUTIL.getJWKFromKey(kp.prvKeyObj);
jwkPub = KEYUTIL.getJWKFromKey(kp.pubKeyObj);

JWS (JSON Web Signatures)

jsrsasign can sign and verify RFC 7515 JSON Web Signatures (JWS).


// sign JWS
header = {alg: "HS256"};
payload = {fruit: "orange"};
jws = KJUR.jws.JWS.sign("HS256", header, payload, {utf8: "secret"});
// eyJhbGciOiJIUzI1NiJ9.eyJmcnVpdCI6Im9yYW5nZSJ9.
// qbIF5WMbXYMFMh_UXjL2CGts5KPVU7yF7AbOdoyoPZI

// verify JWS
isValid = KJUR.jws.JWS.verify(jws, {utf8: "secret"}, ["HS256"]);

This result can also be verified at jwt.io.

JWS signature generation flow

JWT (JSON Web Token)

jsrsasign can sign and verify RFC 7519 JSON Web Token (JWT).


// sign JWT
header = {alg: "HS256", typ: "JWT"};
payload = {sub: "123456789", name: "John Doe", admin: true};
jwt = KJUR.jws.JWS.sign("HS256", header, payload, {utf8: "secret"});
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY
// 3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95
// OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

// verify JWT
isValid = KJUR.jws.JWS.verifyJWT(jwt, {utf8: "secret"}, {
 alg: ["HS256"], sub: ["John Doe"]
});

This result can also be verified at jwt.io.

jsrsasign at jwt.io

jwt.io site have kindly listed jsrsasign. jwt.io provides JWT validator which uses old version of jsrsasign 4.1.5.

JWS-JS

jsrsasign supports IETF JWS-JS Internet Draft, a parallel signature of JWS. This figure shows how to generate JWS-JS.

JWS-JS

generate and verify JWS-JS.


// add a signature to JWS, then get JWS-JS JSON.
jwsjs1 = new KJUR.jws.JWSJWS();
jwsjs1.initWithJWS("eyJ...");
jwsjs1.addSignature(null, {alg: "HS256"}, {utf8: "secret"});
jwsjsJSON = jwsjs1.getJSON();

// verify JWS-JS signature
isValid = jwsjs1.verifyAll([
 ["-----BEGIN CERT...", ["RS256"]],[{utf8: "secret"}, ["HS256"]]]);

for Node.js

jsrsasign in Node.js

This generates a RSA key pair and save its private key as PEM.


var rs = require("jsrsasign");
var rsu = require("jsrsasign-util"); // for file I/O
var kp = rs.KEYUTIL.generateKeypair("RSA", 2048);
var prvPEM = rs.KEYUTIL.getPEM(kp.prvKeyObj, "PKCS8PRV", "password");
rsu.saveFile("foo.key", prvPEM);

You can see more Node samples at kjur.github.io/jsrsasign.

Tools, Demos, Tutorials and API Docs

Tools and demos


jsrsasign provides a lot of tools which use jsrsasign as example.
Please see the this list as for online tools.
Also see list as for Node tools.
As for demonstrations, please see this list.

Tutorials


jsrsasign provides tutorial documents to make it easy to learn jsrsasign programming.

API Reference


jsrsasign provides detailed API Reference document. API reference also has examples.

Thank you for your attention.

kjur.github.io/jsrsasign

jwt.io T-shirt and me at Senso-ji temple at Tokyo