SkillAgentSearch skills...

Graphene

A simple layer for interacting with PKCS #11 / PKCS11 / CryptoKI for Node in TypeScript. (Keywords: Javascript, PKCS#11, Crypto, Smart Card, HSM)

Install / Use

/learn @PeculiarVentures/Graphene
About this skill

Quality Score

0/100

Supported Platforms

Universal

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=",
      "publicExp

Related Skills

View on GitHub
GitHub Stars181
CategoryDevelopment
Updated23d ago
Forks33

Languages

TypeScript

Security Score

95/100

Audited on Mar 10, 2026

No findings