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

pkcs11js-modified

v1.0.0

Published

A Node.js implementation of the PKCS#11 2.3 interface

Downloads

192

Readme

LUNA - PKCS11-JS

NOTE: npm run build, the project and add it to npm repo to be used by PKCS11 HSM Clients. This requires a SafeNet Luna HSM with BIP32 support.

Init LUNA HSM Client

LUNACM

> source setenv
> lunacm
> > slot set -slot 3
> > partition init -label default
> > role login -name partition so
> > slot set -slot 3
> > role init -name crypto officer
> > role logout

> > slot set -slot 3
> > role login -name crypto officer
> > slot set -slot 3
> > role changepw -name crypto officer

Graphene

> graphene
> > module load -l /home/opc/lunacloudhsmclient/libs/64/libCryptoki2.so -n SoftHSMv2.0
> > slot open --slot 0 -p 1234567890
> > test sign -it 1 --slot 0x3

BIP32 Master and Child Key Pair Derivation

Performing BIP32 master and child key pair derivations.

var lib = "/home/opc/lunacloudhsmclient/libs/64/libCryptoki2.so";
var pin = "12345678";
var pkcs11js = require("pkcs11js");
var sha256 = require("sha256");
var BN = require('bn.js');

var pkcs11 = new pkcs11js.PKCS11();
var slot = 0;

var secp256k1_N = new BN("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16);

function dbg(...args) {
    let vargs = ['⏰', new Date().toLocaleString(), '→ '];
    vargs.push.apply(vargs, args);
    console.log.apply(null, vargs);
}

function generateSeed(session) {
    var seedTemplate = [
        {type: pkcs11js.CKA_KEY_TYPE, value: pkcs11js.CKK_GENERIC_SECRET},
        {type: pkcs11js.CKA_TOKEN, value: false},
        {type: pkcs11js.CKA_DERIVE, value: true},
        {type: pkcs11js.CKA_PRIVATE, value: true},
        {type: pkcs11js.CKA_EXTRACTABLE, value: false},
        {type: pkcs11js.CKA_MODIFIABLE, value: false},
        {type: pkcs11js.CKA_VALUE_LEN, value: 32}
    ];

    return pkcs11.C_GenerateKey(session, { mechanism: pkcs11js.CKM_GENERIC_SECRET_KEY_GEN }, seedTemplate);
}

function deriveMaster(session, seed) {
    var publicKeyTemplate = [
                        { type: pkcs11js.CKA_TOKEN, value: false },
                        { type: pkcs11js.CKA_PRIVATE, value: true },
                        { type: pkcs11js.CKA_VERIFY, value: true },
                        { type: pkcs11js.CKA_DERIVE, value: true },
                        { type: pkcs11js.CKA_MODIFIABLE, value: false },
    ];
    var privateKeyTemplate = [
                        { type: pkcs11js.CKA_TOKEN, value: false },
                        { type: pkcs11js.CKA_PRIVATE, value: true },
                        { type: pkcs11js.CKA_SIGN, value: true },
                        { type: pkcs11js.CKA_DERIVE, value: true },
                        { type: pkcs11js.CKA_MODIFIABLE, value: false },
                        { type: pkcs11js.CKA_EXTRACTABLE, value: false },
    ];

    return pkcs11.DeriveBIP32Master(session, seed, publicKeyTemplate, privateKeyTemplate);
}

function deriveChild(session, masterPrivate, path) {
    var publicKeyTemplate = [
                        { type: pkcs11js.CKA_TOKEN, value: false },
                        { type: pkcs11js.CKA_PRIVATE, value: true },
                        { type: pkcs11js.CKA_VERIFY, value: true },
                        { type: pkcs11js.CKA_DERIVE, value: false },
                        { type: pkcs11js.CKA_MODIFIABLE, value: false },
    ];
    var privateKeyTemplate = [
                        { type: pkcs11js.CKA_TOKEN, value: false },
                        { type: pkcs11js.CKA_PRIVATE, value: true },
                        { type: pkcs11js.CKA_SIGN, value: true },
                        { type: pkcs11js.CKA_DERIVE, value: false },
                        { type: pkcs11js.CKA_MODIFIABLE, value: false },
                        { type: pkcs11js.CKA_EXTRACTABLE, value: false },
    ];

    return pkcs11.DeriveBIP32Child(session, masterPrivate, publicKeyTemplate, privateKeyTemplate, path);
}

function sign(session, privateKey, data) {
    var mech = {
        mechanism: pkcs11js.CKM_ECDSA,
    };
    pkcs11.C_SignInit(session, mech, privateKey)
    return pkcs11.C_Sign(session, data, Buffer.alloc(64));
}

function verify(session, publicKey, data, signature) {
    var mech = {
        mechanism: pkcs11js.CKM_ECDSA,
    };
    pkcs11.C_VerifyInit(session, mech, publicKey)
    return pkcs11.C_Verify(session, data, signature)
}

function signatureLowS(sig) {
    var r = new BN(sig.slice(0, sig.length / 2).toString('hex'), 16);
    var s = new BN(sig.slice(sig.length / 2).toString('hex'), 16);
    var halfOrder =  secp256k1_N.shrn(1);
    if (s.cmp(halfOrder) == 1) {
        s = secp256k1_N.sub(s);
    }
    return Buffer.concat([r.toBuffer("be", 32), s.toBuffer("be", 32)]);
}


pkcs11.load(lib);
pkcs11.C_Initialize();
dbg('C_Initialize ✅');
var session;

try {

    var slots = pkcs11.C_GetSlotList(true);
    slot = slots[slot];
    dbg('C_GetSlotList ✅');

    session = pkcs11.C_OpenSession(slot, pkcs11js.CKF_RW_SESSION | pkcs11js.CKF_SERIAL_SESSION);
    dbg('C_OpenSession ✅');

    pkcs11.C_Login(session, 1, pin);
    dbg('C_Login ✅');

    var seed = generateSeed(session);
    dbg('generateSeed ✅');

    var master = deriveMaster(session, seed);
    dbg('deriveMaster ✅');

    /* 
        https://thalesdocs.com/gphsm/luna/7/docs/network/Content/sdk/extensions/BIP32.htm#
    
        The path generates a key pair that follows the BIP44 convention and can be used to receive BTC.
        This mechanism can be used to generate keys that are several levels deep in the key hierarchy.
        The path of the key is specified with pulPath and ulPathLen.
        The path is an array of 32-bit unsigned integers (key indices).
        The highest bit (0x80000000) is used to indicate a hardened key.
        So a path value for a normal key must be <= 0x7FFFFFFF (decimal 2147483647).
        For a hardened key, 0x80000000 <= path value <= 0xFFFFFFFF.
        The path is relative to the input key. 
        
        BIP32: If the key index is greater than or equal to 2^31 (0x80000000 in hexadecimal), the derived key is considered hardened.

        For example, if the path is [5, 1, 4] and the path of the input key is m/0 then the resulting path is m/0/5/1/4.    

        CK_ULONG path[] = { 
                CKF_BIP32_HARDENED | CKG_BIP44_PURPOSE, 
                CKF_BIP32_HARDENED | CKG_BIP44_COIN_TYPE_BTC, 
                CKF_BIP32_HARDENED | 1, 
                CKG_BIP32_EXTERNAL_CHAIN,
                0 
        };

        BIP32 Serialization Format
            Extended public and private keys are serialized as follows:
            >4 byte: version bytes (mainnet: 0x0488B21E public, 0x0488ADE4 private; testnet: 0x043587CF public, 0x04358394 private)
            >1 byte: depth: 0x00 for master nodes, 0x01 for level-1 derived keys, ....
            >4 bytes: the fingerprint of the parent's key (0x00000000 if master key)
            >4 bytes: child number (index) – 32-bit unsigned integer with most significant byte first (0x00000000 if master key)
            >32 bytes: the chain code
            >33 bytes: the public key or private key data

        This 78 byte structure is encoded like other Bitcoin data in Base58, 
        by first adding 32 checksum bits (derived from the double SHA-256 checksum), 
        and then converting to the Base58 representation. 
        This results in a Base58-encoded string of up to CKG_BIP32_MAX_SERIALIZED_LEN characters. 
        Because of the choice of the version bytes:
        The Base58 representation will start with "xprv" or "xpub" on mainnet, "tprv" or "tpub" on testnet.

        CKF_BIP32_HARDENED: 0x80000000
        CKG_BIP44_PURPOSE:  0x0000002C (44)
        
        CKG_BIP44_COIN_TYPE_BTC: 0x00000000 (0)
        CKG_BIP44_COIN_TYPE_ETC: 0x0000003C (60)
    */

    // m / purpose' / coin_type' / account' / change / address_index
    // Bitcoin has a 0' coin type, Ethereum has a 60 
    var path = [0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0];

    var child = deriveChild(session, master['privateKey'], path);
    dbg('deriveChild ✅');

    var hash = sha256("BIP32 Message")
    var data = new Buffer(hash, "hex");
    dbg({hash});

    var signature = sign(session, master['privateKey'], data);
    signature = signatureLowS(signature);
    dbg({signature});

    verify(session, master['publicKey'], data, signature);
    dbg('verification done ✅');
}
catch(e){
    console.error(' ❌ ERROR ❌ \n', e);
}
finally {
    if(session) {
        pkcs11.C_Logout(session);
        dbg('C_Logout ✅');
        pkcs11.C_CloseSession(session);
        dbg('C_CloseSession ✅');
    }
    pkcs11.C_Finalize();
    dbg('C_Finalize ✅');
}

Outputs: