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

graphene-pk11

v2.3.6

Published

A simple layer for interacting with PKCS #11 / PKCS11 / CryptoKI for Node in TypeScript

Downloads

3,476

Readme

Graphene

license test Coverage Status npm version

NPM

A simple layer for interacting with PKCS #11 / PKCS11 / CryptoKI for Node in TypeScript

PKCS #11 (also known as CryptoKI or PKCS11) is the standard interface for interacting with hardware crypto devices such as Smart Cards and Hardware Security Modules (HSMs). It wraps the library closely, but uses attempts to look like 'node.crypto' where it makes sense.

It has been tested with :

We have also created a basic CLI for interacting with PKCS#11 devices based on this library we call graphene-cli.

NOTE: For testing purposes it may be easier to work with SoftHSM2 which is a software implementation of PKCS#11 based on OpenSSL or Botan.

var graphene = require("graphene-pk11");
var Module = graphene.Module;

var mod = Module.load("/usr/local/lib/softhsm/libsofthsm2.so", "SoftHSM");

mod.initialize();

var session = mod.getSlots(0).open();
session.login("password");

// Get a number of private key objects on token
console.log(session.find({class: graphene.ObjectClass.PRIVATE_KEY}).length);

session.logout();
mod.finalize();

Installation

$ npm install graphene-pk11

Documentation

https://peculiarventures.github.io/graphene/

Using the Package

Install the package

$ npm install graphene-pk11 --save

Install TypeScript definition using TSD package manager

$ tsd install graphene-pk11 --save

Load module

// file.js
var graphene = require("graphene-pk11");

Install SoftHSM2

Examples

Listing capabilities

var graphene = require("graphene-pk11");
var Module = graphene.Module;
var lib = "/usr/local/lib/softhsm/libsofthsm2.so";
var mod = Module.load(lib, "SoftHSM");
mod.initialize();
// get slots
var slots = mod.getSlots(true);
if (slots.length > 0) {
    for (var i = 0; i < slots.length; i++) {
        var slot = slots.items(i);
        console.log("Slot #" + slot.handle);
        console.log("\tDescription:", slot.slotDescription);
        console.log("\tSerial:", slot.getToken().serialNumber);
        console.log("\tPassword(min/max): %d/%d", slot.getToken().minPinLen, slot.getToken().maxPinLen);
        console.log("\tIs hardware:", !!(slot.flags & graphene.SlotFlag.HW_SLOT));
        console.log("\tIs removable:", !!(slot.flags & graphene.SlotFlag.REMOVABLE_DEVICE));
        console.log("\tIs initialized:", !!(slot.flags & graphene.SlotFlag.TOKEN_PRESENT));
        console.log("\n\nMechanisms:");
        console.log("Name                       h/s/v/e/d/w/u");
        console.log("========================================");
        function b(v) {
            return v ? "+" : "-";
        }

        function s(v) {
            v = v.toString();
            for (var i_1 = v.length; i_1 < 27; i_1++) {
                v += " ";
            }
            return v;
        }

        var mechs = slot.getMechanisms();
        for (var j = 0; j < mechs.length; j++) {
            var mech = mechs.items(j);
            console.log(s(mech.name) +
                b(mech.flags & graphene.MechanismFlag.DIGEST) + "/" +
                b(mech.flags & graphene.MechanismFlag.SIGN) + "/" +
                b(mech.flags & graphene.MechanismFlag.VERIFY) + "/" +
                b(mech.flags & graphene.MechanismFlag.ENCRYPT) + "/" +
                b(mech.flags & graphene.MechanismFlag.DECRYPT) + "/" +
                b(mech.flags & graphene.MechanismFlag.WRAP) + "/" +
                b(mech.flags & graphene.MechanismFlag.UNWRAP));
        }
    }
}
mod.finalize();

####Output

Slot #0
	Description: SoftHSM slot 0
	Serial: f89e34b310e83df2
	Password(min/max): 4/255
	Is hardware: false
	Is removable: false
	Is initialized: true
Mechanisms:
Name                       h/s/v/e/d/w/u
========================================
MD5                        +/-/-/-/-/-/-
SHA_1                      +/-/-/-/-/-/-
SHA224                     +/-/-/-/-/-/-
SHA256                     +/-/-/-/-/-/-
SHA384                     +/-/-/-/-/-/-
SHA512                     +/-/-/-/-/-/-
MD5_HMAC                   -/+/+/-/-/-/-
SHA_1_HMAC                 -/+/+/-/-/-/-
SHA224_HMAC                -/+/+/-/-/-/-
SHA256_HMAC                -/+/+/-/-/-/-
SHA384_HMAC                -/+/+/-/-/-/-
SHA512_HMAC                -/+/+/-/-/-/-
RSA_PKCS_KEY_PAIR_GEN      -/-/-/-/-/-/-
RSA_PKCS                   -/+/+/+/+/+/+
RSA_X_509                  -/+/+/+/+/-/-
MD5_RSA_PKCS               -/+/+/-/-/-/-
SHA1_RSA_PKCS              -/+/+/-/-/-/-
RSA_PKCS_OAEP              -/-/-/+/+/+/+

Hashing

var graphene = require("graphene-pk11");
var Module = graphene.Module;

var lib = "/usr/local/lib/softhsm/libsofthsm2.so";

var mod = Module.load(lib, "SoftHSM");
mod.initialize();

var slot = mod.getSlots(0);
if (slot.flags & graphene.SlotFlag.TOKEN_PRESENT) {
    var session = slot.open();
    var digest = session.createDigest("sha1");
    digest.update("simple text 1");
    digest.update("simple text 2");
    var hash = digest.final();
    console.log("Hash SHA1:", hash.toString("hex")); // Hash SHA1: e1dc1e52e9779cd69679b3e0af87d2e288190d34 
    session.close();
}
else {
    console.error("Slot is not initialized");
}

mod.finalize();

Generating keys

AES

var graphene = require("graphene-pk11");
var Module = graphene.Module;

var lib = "/usr/local/lib/softhsm/libsofthsm2.so";

var mod = Module.load(lib, "SoftHSM");
mod.initialize();

var slot = mod.getSlots(0);
if (slot.flags & graphene.SlotFlag.TOKEN_PRESENT) {
    var session = slot.open();
    session.login("12345");
    
    var k = session.generateKey(graphene.KeyGenMechanism.AES, {
        "class": graphene.ObjectClass.SECRET_KEY,
        "token": false,
        "valueLen": 256 / 8,
        "keyType": graphene.KeyType.AES,
        "label": "My AES secret key",
        "private": true
    });
    
    console.log("Key.handle:", k.handle);                 // Key.handle: 2
    console.log("Key.type:", graphene.KeyType[k.type]);   // Key.type: AES
    
    session.logout();
    session.close();
}
else {
    console.error("Slot is not initialized");
}

mod.finalize();

ECC

var graphene = require("graphene-pk11");
var Module = graphene.Module;

var lib = "/usr/local/lib/softhsm/libsofthsm2.so";

var mod = Module.load(lib, "SoftHSM");
mod.initialize();

var slot = mod.getSlots(0);
if (slot.flags & graphene.SlotFlag.TOKEN_PRESENT) {
    var session = slot.open();
    session.login("12345");
    
    // generate ECDSA key pair
    var keys = session.generateKeyPair(graphene.KeyGenMechanism.ECDSA, {
        keyType: graphene.KeyType.ECDSA,
        token: false,
        verify: true,
        paramsECDSA: graphene.NamedCurve.getByName("secp192r1").value
    }, {
        keyType: graphene.KeyType.ECDSA,
        token: false,
        sign: true
    });
    console.log("Key type:", graphene.KeyType[keys.privateKey.type]);            // Key type: ECDSA
    console.log("Object's class:", graphene.ObjectClass[keys.privateKey.class]); // Object's class: PRIVATE_KEY 
    
    session.logout();
    session.close();
}
else {
    console.error("Slot is not initialized");
}

mod.finalize();

Exporting public key

var graphene = require("graphene-pk11");
var Module = graphene.Module;

var lib = "/usr/local/lib/softhsm/libsofthsm2.so";

var mod = Module.load(lib, "SoftHSM");
mod.initialize();

var slot = mod.getSlots(0);
if (slot.flags & graphene.SlotFlag.TOKEN_PRESENT) {
    var session = slot.open();
    session.login("12345");
    
    // generate RSA key pair
    var keys = session.generateKeyPair(graphene.KeyGenMechanism.RSA, {
        keyType: graphene.KeyType.RSA,
        modulusBits: 1024,
        publicExponent: Buffer.from([3]),
        token: false,
        verify: true,
        encrypt: true,
        wrap: true
    }, {
        keyType: graphene.KeyType.RSA,
        token: false,
        sign: true,
        decrypt: true,
        unwrap: true
    });
    
    // get public key attributes
    var pubKey = keys.publicKey.getAttribute({
        modulus: null,
        publicExponent: null
    });
    
    // convert values to base64
    pubKey.modulus = pubKey.modulus.toString("base64");
    pubKey.publicExponent = pubKey.publicExponent.toString("base64");
    
    
    console.log(JSON.stringify(pubKey, null, 4));
    
    session.logout();
    session.close();
}
else {
    console.error("Slot is not initialized");
}

mod.finalize();

/*
  Result
  ------------------
  
  {
      "modulus": "21HTpGsKn3lQh4fqhYkZ/NprzKZqCnUIs0Ekbg8Y0M0Er4yJ4tKVFLlaxUkym6nRBQuS2tzwSQcvuKVUNeK3k6AiPitlQs5CRc8csqL6BYMU+rme3L0w/d+1OryH/pMrDGOmkWXTrzBWoRgulXHX92jK6CcXKBeS/yUSgCLP/MM=",
      "publicExponent": "Aw=="
  }

*/

Signing / Verifying

var graphene = require("graphene-pk11");
var Module = graphene.Module;

var lib = "/usr/local/lib/softhsm/libsofthsm2.so";

var mod = Module.load(lib, "SoftHSM");
mod.initialize();

var slot = mod.getSlots(0);
if (slot.flags & graphene.SlotFlag.TOKEN_PRESENT) {
    var session = slot.open();
    session.login("12345");
    
    // generate RSA key pair
    var keys = session.generateKeyPair(graphene.KeyGenMechanism.RSA, {
        keyType: graphene.KeyType.RSA,
        modulusBits: 1024,
        publicExponent: Buffer.from([3]),
        token: false,
        verify: true,
        encrypt: true,
        wrap: true
    }, {
        keyType: graphene.KeyType.RSA,
        token: false,
        sign: true,
        decrypt: true,
        unwrap: true
    });
    
    // sign content
    var sign = session.createSign("SHA1_RSA_PKCS", keys.privateKey);
    sign.update("simple text 1");
    sign.update("simple text 2");
    var signature = sign.final();
    console.log("Signature RSA-SHA1:", signature.toString("hex")); // Signature RSA-SHA1: 6102a66dc0d97fadb5...
    
    // verify content
    var verify = session.createVerify("SHA1_RSA_PKCS", keys.publicKey);
    verify.update("simple text 1");
    verify.update("simple text 2");
    var verify_result = verify.final(signature);
    console.log("Signature RSA-SHA1 verify:", verify_result);      // Signature RSA-SHA1 verify: true
    
    session.logout();
    session.close();
}
else {
    console.error("Slot is not initialized");
}

mod.finalize();

Encrypting / Decrypting

var graphene = require("graphene-pk11");
var Module = graphene.Module;

var lib = "/usr/local/lib/softhsm/libsofthsm2.so";

var mod = Module.load(lib, "SoftHSM");
mod.initialize();

var slot = mod.getSlots(0);
if (slot.flags & graphene.SlotFlag.TOKEN_PRESENT) {
    var session = slot.open();
    session.login("12345");

    // generate AES key
    var key = session.generateKey(graphene.KeyGenMechanism.AES, {
        "class": graphene.ObjectClass.SECRET_KEY,
        "token": false,
        "valueLen": 256 / 8,
        "keyType": graphene.KeyType.AES,
        "label": "My AES secret key",
        "encrypt": true,
        "decrypt": true
    });
    
    // enc algorithm
    var alg = {
        name: "AES_CBC_PAD",
        params: Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6]) // IV
    };
    var MESSAGE = "Encrypted message";
    
    // encrypting
    var cipher = session.createCipher(alg, key);
    var enc = cipher.update(MESSAGE);
    enc = Buffer.concat([enc, cipher.final()]);
    console.log("Enc:", enc.toString("hex"));           // Enc: eb21e15b896f728a4...
    
    // decrypting
    var decipher = session.createDecipher(alg, key);
    var dec = decipher.update(enc);
    var msg = Buffer.concat([dec, decipher.final()]).toString();
    console.log("Message:", msg.toString());            // Message: Encrypted message
    
    session.logout();
    session.close();
}
else {
    console.error("Slot is not initialized");
}

mod.finalize();

Derive key

var graphene = require("graphene-pk11");
var Module = graphene.Module;

var lib = "/usr/local/lib/softhsm/libsofthsm2.so";

var mod = Module.load(lib, "SoftHSM");
mod.initialize();

var slot = mod.getSlots(0);
if (slot.flags & graphene.SlotFlag.TOKEN_PRESENT) {
    var session = slot.open();
    session.login("12345");

    // generate EC key
    var keys = session.generateKeyPair(graphene.KeyGenMechanism.ECDSA, {
        keyType: graphene.KeyType.ECDSA,
        token: false,
        derive: true,
        paramsECDSA: graphene.NamedCurve.getByName("secp192r1").value
    }, {
        keyType: graphene.KeyType.ECDSA,
        token: false,
        derive: true
    });
    
    // derive algorithm
    var alg = {
        name: "ECDH1_DERIVE",
        params: new graphene.EcdhParams(
            graphene.EcKdf.SHA1,
            null,
            keys.publicKey.getAttribute({pointEC: null}).pointEC)
        };
    
    // Template for derived key
    var template = {
        "class": graphene.ObjectClass.SECRET_KEY,
        "token": false,
        "keyType": graphene.KeyType.AES,
        "valueLen": 256 / 8,
        "encrypt": true,
        "decrypt": true
    }
    
    // Key derivation
    var dKey = session.deriveKey(alg, keys.privateKey, template)
    console.log("Derived key handle:", dKey.handle);
    
    session.logout();
    session.close();
}
else {
    console.error("Slot is not initialized");
}

mod.finalize();

Change User's PIN

var graphene = require("graphene-pk11");
var Module = graphene.Module;

var lib = "/usr/local/lib/softhsm/libsofthsm2.so";

var mod = Module.load(lib, "SoftHSM");
mod.initialize();

try {
    var slot = mod.getSlots(0);
    if (slot.flags & graphene.SlotFlag.TOKEN_PRESENT) {
        var session = slot.open();
        session.login("12345", graphene.UserType.USER);
        session.setPin("12345", "new pin");
        session.logout();
        session.close();
        console.log("User's PIN was changed successfully");
    }
}
catch(e) {
    console.error(e);
}
mod.finalize();

Adding x509 certificate

const graphene = require("graphene-pk11");

const mod = graphene.Module.load("/usr/local/lib/softhsm/libsofthsm2.so", "SoftHSM");

mod.initialize();

try {
    const slot = mod.getSlots(0);
    const session = slot.open(2 | 4)
    session.login("password");

    const template = {
        class: graphene.ObjectClass.CERTIFICATE,
        certType: graphene.CertificateType.X_509,
        private: false,
        token: false,
        id: Buffer.from([1, 2, 3, 4, 5]), // Should be the same as Private/Public key has
        label: "My certificate",
        subject: Buffer.from("3034310B300906035504...", "hex"),
        value: Buffer.from("308203A830820290A003...", "hex"),
    };

    const objCert = session.create(template).toType();

    console.log("Certificate: created\n");
    console.log("Certificate info:\n===========================");
    console.log("Handle:", objCert.handle.toString("hex"));
    console.log("ID:", objCert.id.toString("hex"));
    console.log("Label:", objCert.label);
    console.log("category:", graphene.CertificateCategory[objCert.category]);
    console.log("Subject:", objCert.subject.toString("hex"));
    console.log("Value:", objCert.value.toString("hex"));
} catch (err) {
    console.error(err);
}

mod.finalize();

Initializing NSS crypto library

Use options parameter for Module::initialize method.

Type

interface InitializationOptions {
    /**
     * NSS library parameters
     */
    libraryParameters?: string;
    /**
     * bit flags specifying options for `C_Initialize`
     * - CKF_LIBRARY_CANT_CREATE_OS_THREADS. True if application threads which are executing calls to the library
     *   may not use native operating system calls to spawn new threads; false if they may
     * - CKF_OS_LOCKING_OK. True if the library can use the native operation system threading model for locking;
     *   false otherwise
     */
    flags?: number;
}

Code

const mod = Module.load("/usr/local/opt/nss/lib/libsoftokn3.dylib", "NSS");

mod.initialize({
    libraryParameters: "configdir='' certPrefix='' keyPrefix='' secmod='' flags=readOnly,noCertDB,noModDB,forceOpen,optimizeSpace",
});

// Your code here

mod.finalize();

Developing

Use npm command to publish graphene-pk11 module

> npm run pub

Suitability

At this time this solution should be considered suitable for research and experimentation, further code and security review is needed before utilization in a production application.

Bug Reporting

Please report bugs either as pull requests or as issues in the issue tracker. Graphene has a full disclosure vulnerability policy. Please do NOT attempt to report any security vulnerability in this code privately to anybody.

TODO

  • Add tests to the library
  • Add additional capabilities to CLI (device initialization, file signing, file encryption, etc)

Related