Closed mfaisaltariq closed 5 years ago
Can you share code how you derive key?
Here is a test example of key derivation https://github.com/PeculiarVentures/graphene/blob/master/test/ec.ts#L145-L162
I'm using the code example in the Readme.md file for the repo. Please find the link below. The test code pattern you shared above and the one given below on the link is some what same.
The error occurs on the following line.
var dKey = session.deriveKey(alg, keys.privateKey, template);
Are you using similar params? Error code says that your mechanism params are invalid
var alg = {
name: "ECDH1_DERIVE",
params: new graphene.EcdhParams(
graphene.EcKdf.SHA1,
null,
keys.publicKey.getAttribute({pointEC: null}).pointEC)
};
Yes, using exactly the same code. Just changed the PIN for my SoftHSM slot.
Can you suggest any other way I can generate the Public Key for the ECDSA and then verify the signature using that key.
I'm not fully aware of the working of this algorithm but if there is some other way to work around it like get the EC Point and generate public key from the x-y coordinate please do share it.
Thank you.
You can try node-webcrypto-p11. It's based on graphene-pk11
and implements WebCrypto interface.
You can use these examples for generating/signing/verifing
node-webcrypto-p11
extends WebCrypto and allows to put/get objects to/from tokens. See KeyStorage and CertStorage
And tests for examples
Using this package we have done the following things on RSA
Now we want to do the above following things using the ECDSA Challenges currently we are facing are given below.
You can try node-webcrypto-p11. It's based on
graphene-pk11
and implements WebCrypto interface.You can use these examples for generating/signing/verifing
node-webcrypto-p11
extends WebCrypto and allows to put/get objects to/from tokens. See KeyStorage and CertStorageAnd tests for examples
The above library that you have recommended has the same issue, the examples are broken. Broken Example Tried the above example returned error with 'unexpected token'
The samples work, they have all been tested and used regularly.
Their ability to function is dependent on the underlying P11. If they do not work with your P11
then there is something with your P11 that:
A) is needed and not supported
B) behaves inconsistently with our understanding of the P11 standard
Instead of working with you to reimplement it is better to debug the issue with the higher level library.
Please file a bug in that repro with details (code, environment, etc) to reproduce the problem along with logs and errors.
@rmhrisk I'm relatively new to cryptography so I'm not sure how can I test my p11, I'm using softHSM v2.5.0.
Thank you for the suggestion and I'll definitely open up an issue with all the details on the repo.
I also need to understand that once I have generated a keypair using this example, I suppose it gets stored in the softHSM. This example always generates an keypair on the fly whenever we call it. But lets say that I want to generate the key once and then when I need to sign something, how can I pull up the Private Key from softHSM to sign it. It there some kind of attribute that serves as a unique identifier and can be used to pull it up. Like can we set Label for the keys and then pull them out for signing using their Label.
const { Crypto } = require("node-webcrypto-p11");
async function main() {
const crypto = new Crypto({
library: "/usr/local/lib/softhsm/libsofthsm2.so",
name: "SoftHSMv2",
slot: 0,
pin: "12345",
});
const data = Buffer.from("Message to be signed");
const keys = await crypto.subtle.generateKey({name: "ECDSA", namedCurve: "P-256"}, false, ["sign", "verify"]);
// Sign
const signature = await crypto.subtle.sign({name: "ECDSA", hash: "SHA-256"}, keys.privateKey, data);
console.log("Signature:", Buffer.from(signature).toString("hex"));
// Verify
const ok = await crypto.subtle.verify({name: "ECDSA", hash: "SHA-256"}, keys.publicKey, signature, data);
console.log("Status:", ok);
// SPKI
const spki = await crypto.subtle.exportKey("spki", keys.publicKey);
console.log("SPKI:", Buffer.from(spki).toString("base64"));
}
main().catch(err => console.error(err));
Signature: c62915b263f7e8e8daa28ae6b5fb4637d127c6cce28a2d5076e761c97d433efa686dea787e93ab7a187605b2143da8b364782b66e17c16e11238f5e3c4ff4163
Status: true
SPKI: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER1G/uHT5IqM1sOJZB8mjd2cK4k8f45MR+lsF61yVPhSSgGA6x764+IvEfXRzBLQ/AtHOyVXlphjoO62lFgD61Q==
You can use PKIjs to create a public key PEM
const { Crypto } = require("node-webcrypto-p11");
const crypto = new Crypto({
library: "/usr/local/lib/softhsm/libsofthsm2.so",
name: "SoftHSMv2",
slot: 0,
readWrite: true,
pin: "12345",
});
async function generateKeysAndPushToSlot() {
// generate key
const keys = await crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, false, ["sign", "verify"]);
// Put private key to slot
const prvIndex = await crypto.keyStorage.setItem(keys.privateKey);
console.log("Private key was added to slot:", prvIndex);
// Put public key to slot
const pubIndex = await crypto.keyStorage.setItem(keys.publicKey);
console.log("Public key was added to slot:", pubIndex);
return prvIndex.split("-")[2]; // CKA_ID from the PKCS#11
}
async function getKey(type, id) {
const indexes = await crypto.keyStorage.keys();
for (const index of indexes) {
const indexParts = index.split("-");
if (indexParts[0] === type && indexParts[2] === id) {
return crypto.keyStorage.getItem(index);
}
}
return null;
}
async function printAllKeysInSlot() {
console.log("Keys from slot:");
const indexes = await crypto.keyStorage.keys();
indexes.forEach((index) => {
console.log(" ", index);
})
}
async function main() {
await printAllKeysInSlot();
const id = await generateKeysAndPushToSlot();
const key = await getKey("public", id);
console.log("Key from storage:", key);
}
main().catch(err => console.error(err));
Keys from slot:
private-0200000000000000-fe9a8e35bef4f03cedeaf28b08590bf5186a6449
public-0300000000000000-fe9a8e35bef4f03cedeaf28b08590bf5186a6449
Private key was added to slot: private-0600000000000000-75cfc3cda0043fa3f505dfd3ae9b650b7b452569
Public key was added to slot: public-0700000000000000-75cfc3cda0043fa3f505dfd3ae9b650b7b452569
Key from storage: EcCryptoKey {
usages: [ 'verify' ],
p11Object:
PublicKey {
handle: <Buffer 07 00 00 00 00 00 00 00>,
session:
Session {
handle: <Buffer 01 00 00 00 00 00 00 00>,
slot: [Slot],
state: 2,
flags: 6,
deviceError: 0 } },
type: 'public',
extractable: true,
algorithm: { name: 'ECDSA', namedCurve: 'P-256' },
id:
'public-0700000000000000-75cfc3cda0043fa3f505dfd3ae9b650b7b452569' }
Key uses a composite id <type>-<hex(handle)>-<hex(CKA_ID)>
. CKA_ID
propertis for assymetric private key and public key are equal
@microshine thank you very much for your input on this. Thank you for all your help and time.
1 thing that I'm curious about is that, do we have a quicker way to fetch the key using index from the HSM and reduce O(n) complexity.
node-webcrypto-p11
doesn't implement a mechanism to get PKCS#11 by CKA_ID
only. You can implement own method by using crypto.session
object
const { ObjectClass } = require("graphene-pk11");
const { Crypto } = require("node-webcrypto-p11");
const crypto = new Crypto({
library: "/usr/local/lib/softhsm/libsofthsm2.so",
name: "SoftHSMv2",
slot: 0,
readWrite: true,
pin: "12345",
});
async function main() {
const id = "fe9a8e35bef4f03cedeaf28b08590bf5186a6449";
const type = "public";
const keys = crypto.session.find({
class: type === "public"
? ObjectClass.PUBLIC_KEY
: ObjectClass.PRIVATE_KEY,
id: Buffer.from(id, "hex"),
});
if (keys.length > 0) {
console.log(keys.items(0).toType());
} else {
console.log("Key not found");
}
}
main().catch(err => console.error(err));
PublicKey {
handle: <Buffer 02 00 00 00 00 00 00 00>,
session:
Session {
handle: <Buffer 01 00 00 00 00 00 00 00>,
slot:
Slot {
handle: <Buffer 80 84 0a 69 00 00 00 00>,
module: [Module],
slotDescription: 'SoftHSM slot ID 0x690a8480',
manufacturerID: 'SoftHSM project',
flags: 1,
hardwareVersion: [Object],
firmwareVersion: [Object] },
state: 2,
flags: 6,
deviceError: 0 } }
You just need to wrap PKCS#11 key to CryptoKey after that
@microshine when we sign a message like below
const signature = await crypto.subtle.sign({name: "ECDSA", hash: "SHA-256"}, keys.privateKey, data);
the hash: 'SHA-256'
part means that our message will first be hashed using SHA-256 and then signed using the private key or is it something else?
Thank you
@mfaisaltariq You are right. First computes hash then signs using a private key
Hi @microshine ,
I hope you are well. Recently came across an error while retrieving a key from softHSM. Its actually a CKR_GENERAL_ERROR:5 for the function C_GetAttributeValue. I have searched for this error and didn't find any references for it. Please let me know the cause if you have any idea regarding this or how can I avoid it.
The logs can be found on the below link. I'm running it in a docker container on ubuntu:16.04
https://pasteboard.co/IA6gNx8.png
Thank you
On further investigation I found out that it corrupts the SLOT. When I initialised a new slot and changed the slot number in the code it started working fine. Now I'm trying to find out if I can move the keys in slot 0 to slot 1 or not.
The Derive Key example gives the following error and needs to be fixed.
Error: CKR_MECHANISM_PARAM_INVALID:113