PeculiarVentures/graphene

GitHub: PeculiarVentures/graphene

面向 Node.js 的 PKCS#11 接口层,让 TypeScript 应用能够与 HSM 硬件安全模块和智能卡进行交互,实现硬件级加密运算。

Stars: 181 | Forks: 33

# Graphene [![license](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://raw.githubusercontent.com/PeculiarVentures/graphene/master/LICENSE) ![test](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/acb7c6760b092421.svg) [![Coverage Status](https://coveralls.io/repos/github/PeculiarVentures/graphene/badge.svg?branch=master)](https://coveralls.io/github/PeculiarVentures/graphene?branch=master) [![npm version](https://badge.fury.io/js/graphene-pk11.svg)](https://badge.fury.io/js/graphene-pk11) [![NPM](https://nodei.co/npm/graphene-pk11.png)](https://nodei.co/npm/graphene-pk11/) 一个简单的层,用于在 TypeScript 中与 Node 的 PKCS #11 / PKCS11 / CryptoKI 进行交互 PKCS #11(也称为 CryptoKI 或 PKCS11)是与硬件加密设备(如智能卡和硬件安全模块 (HSM))进行交互的标准接口。它紧密封装了库,但在合理的地方尝试看起来像 'node.crypto'。 它已在以下设备上测试过: - [SoftHSM2](https://www.opendnssec.org/softhsm/) - [Thales nShield Solo+](https://www.thales-esecurity.com/products-and-services/products-and-services/hardware-security-modules/general-purpose-hsms/nshield-solo) - [Safenet Luna HSMs](http://www.safenet-inc.com/) - [RuToken](http://www.rutoken.ru/) 我们还基于此库创建了一个基本的 [CLI](https://github.com/PeculiarVentures/graphene-cli),用于与 PKCS#11 设备交互,我们称之为 [graphene-cli](https://github.com/PeculiarVentures/graphene-cli)。 **注意:** 出于测试目的,使用 SoftHSM2 可能更容易,它是基于 OpenSSL 或 Botan 的 PKCS#11 软件实现。 ``` 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(); ``` ## 安装 ``` $ npm install graphene-pk11 ``` ## 文档 [https://peculiarventures.github.io/graphene/](https://peculiarventures.github.io/graphene/) ## 使用该包 安装该包 ``` $ npm install graphene-pk11 --save ``` 使用 [TSD](https://www.npmjs.com/package/tsd) 包管理器安装 TypeScript 定义 ``` $ tsd install graphene-pk11 --save ``` 加载模块 ``` // file.js var graphene = require("graphene-pk11"); ``` ### 安装 SoftHSM2 - 对于 OSX,请参阅[此处的说明](https://github.com/opendnssec/SoftHSMv2/blob/develop/OSX-NOTES.md) - 对于 linux,请参阅[此处的说明](https://github.com/opendnssec/SoftHSMv2/blob/develop/README.md) ## 示例 ### 列出功能 ``` 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(); ``` ####输出 ``` 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 -/-/-/+/+/+/+ ``` ### 哈希 ``` 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(); ``` ### 生成密钥 #### 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(); ``` ### 导出公钥 ``` 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==" } */ ``` ### 签名 / 验证 ``` 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(); ``` ### 加密 / 解密 ``` 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(); ``` ### 派生密钥 ``` 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(); ``` ### 更改用户 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(); ``` ### 添加 x509 证书 ``` 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(); ``` ### 初始化 NSS 加密库 为 `Module::initialize` 方法使用 `options` 参数。 __类型__ ``` 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; } ``` __代码__ ``` 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(); ``` ## 开发 使用 npm 命令发布 graphene-pk11 模块 ``` > npm run pub ``` ## 适用性 目前,此解决方案应被认为适合用于研究和实验,在生产应用程序中使用之前,需要进一步的代码和安全审查。 ## Bug 报告 请以 pull requests 或 issue tracker 中的 issues 形式报告 bug。Graphene 拥有完全披露的漏洞政策。请勿尝试私下向任何人报告此代码中的任何安全漏洞。 ## 待办事项 * 为库添加测试 * 向 CLI 添加额外功能(设备初始化、文件签名、文件加密等) ## 相关 - [PKCS #11 2.40 规范](http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/pkcs11-curr-v2.40.html) - [许多 PKCS #11 规范](http://www.cryptsoft.com/pkcs11doc/) - [PERL PKCS #11 绑定](https://github.com/dotse/p5-crypt-pkcs11) - [.NET PKCS #11 绑定](https://github.com/jariq/Pkcs11Interop) - [Ruby PKCS #11 绑定](https://github.com/larskanis/pkcs11) - [OCaml PKCS #11 绑定](https://github.com/ANSSI-FR/caml-crush) - [OCaml PKCS #11 CLI](https://github.com/ANSSI-FR/opkcs11-tool) - [Go PKCS #11 绑定](https://github.com/miekg/pkcs11) - [PKCS #11 管理工具](http://www.pkcs11admin.net) - [Node.js 外部函数接口](https://github.com/node-ffi/node-ffi) - [GOST PKCS#11 常量](https://github.com/romanovskiy-k/pkcs11/blob/master/rtpkcs11t.h) - [PKCS#11 日志代理模块](https://github.com/jariq/pkcs11-logger) - [PKCS#11 代理](https://github.com/iksaif/pkcs11-proxy) - [PKCS#11 测试](https://github.com/google/pkcs11test) - [OpenCryptoKi](http://sourceforge.net/projects/opencryptoki/) - [SoftHSM](https://www.opendnssec.org/softhsm/) - [Windows 版 SoftHSM2](https://github.com/disig/SoftHSM2-for-Windows/) - [node-pcsc](https://github.com/santigimeno/node-pcsclite) - [PKCS#11 URI](https://tools.ietf.org/html/rfc7512) - [密钥长度建议](http://www.keylength.com/en/compare/)
标签:CMS安全, CryptoKI, CVE, GNU通用公共许可证, HSM, HTTP工具, JavaScript, MITM代理, Node.js, OpenSSL, PKCS#11, RuToken, SafeNet Luna, SamuraiWTF, SIEM, SoftHSM, Thales nShield, TypeScript, 加密, 后端开发, 安全插件, 密码学, 底层库, 手动系统调用, 数字签名, 智能卡, 漏洞扫描器, 硬件安全模块, 网络安全, 隐私保护