PeculiarVentures / graphene

A simple layer for interacting with PKCS #11 / PKCS11 / CryptoKI for Node in TypeScript. (Keywords: Javascript, PKCS#11, Crypto, Smart Card, HSM)
MIT License
169 stars 34 forks source link

Ed25519 Support #123

Open Rtlagot opened 4 years ago

Rtlagot commented 4 years ago

Hello, I'd like to use this lib to first generate a Ed25519 keypair on HSM. I know that OpenSSL currently supports Ed25519, but i can't find it in the list of curve names here. Is there any way to create a keypair with Ed25519 ?

rmhrisk commented 4 years ago

There is not a standard ed25519 way to do ed25519 via PKCS11 yet. Are you sure your smartcard or HSM supports it?

What is your devices make and model?

Does their documentation say they support it?

Do they provide a sample? If so can you share it?

With more info we may be able to help.

Rtlagot commented 4 years ago

It is the Thales Luna 7 Network HSM, and it's clearly specified in the product presentation that it supports the PKCS11 API and the Ed25519 cryptography.

Unfortunately they don't provide a sample to start with.

rmhrisk commented 4 years ago

@Fizbanoide both of these statements can be true:

  1. It supports the PKCS11 API, and
  2. It supports Ed25519.

But the union of those does not mean that PKCS#11 defines how to do ed25519 via PKCS#11 which the current version of the specification does not.

This means that each vendor, should it wish to support ed25519 via PKCS#11 will do so via proprietary extensions to PKCS#11.

As a result, no common code that works cross-vendor can be made that works with this capability, it also means that we can not look at the PKCS#11 public specification to see how to implement the logic.

It is possible in most cases to use propietary mechanisms such as the ones we are discussing via graphene, however without:

There is not much we can do; I personally would love to see ed25519 in P11, and, see it work in graphene; but without the above assets there is not much we can do.

If you have a support contract with the vendor I would ask for a sample, they will provide it.

Ryan

Rtlagot commented 4 years ago

Alright, thanks for the answer, I'll check with Thales first to see if I can get any sample.

Rtlagot commented 4 years ago

I found a way to generate keypairs using the curve25519 with the Thales Luna 7 Network HSM and sign some data with it. Here is the code :

var keys = session.generateKeyPair(0x80000c01, { 
    token: true,
    private: false,
    encrypt: false,
    verify: true,
    derive: false,
    paramsECDSA: graphene.NamedCurve.getByName("curve25519").value,
    modifiable: false,
    label: "Generated EC Edwards pubK"
    }, { 
    token: true, 
    private: false,
    sensitive: true,
    decrypt: false,
    sign: true,
    derive: false,
    modifiable: false, 
    extractable: false,
    label: "Generated EC Edwards privK" 
});
var sign = session.createSign(0x80000c03, keys.privateKey);
sign.update("simple text 1");
sign.update("simple text 2");
var signature = sign.final();
console.log("Signature :", signature.toString("hex")); 

// verify content
var verify = session.createVerify(0x80000c03, keys.publicKey);
verify.update("simple text 1");
verify.update("simple text 2");
var verify_result = verify.final(signature);

I had to use the hexadecimal code for the mechanisms because they are not implemented so far on the 2.4 version of PKCS11.

zosocanuck commented 3 years ago

I found a way to generate keypairs using the curve25519 with the Thales Luna 7 Network HSM and sign some data with it. Here is the code :

var keys = session.generateKeyPair(0x80000c01, { 
    token: true,
    private: false,
    encrypt: false,
    verify: true,
    derive: false,
    paramsECDSA: graphene.NamedCurve.getByName("curve25519").value,
    modifiable: false,
    label: "Generated EC Edwards pubK"
    }, { 
    token: true, 
    private: false,
    sensitive: true,
    decrypt: false,
    sign: true,
    derive: false,
    modifiable: false, 
    extractable: false,
    label: "Generated EC Edwards privK" 
});
var sign = session.createSign(0x80000c03, keys.privateKey);
sign.update("simple text 1");
sign.update("simple text 2");
var signature = sign.final();
console.log("Signature :", signature.toString("hex")); 

// verify content
var verify = session.createVerify(0x80000c03, keys.publicKey);
verify.update("simple text 1");
verify.update("simple text 2");
var verify_result = verify.final(signature);

I had to use the hexadecimal code for the mechanisms because they are not implemented so far on the 2.4 version of PKCS11.

I attempted this code today with a Luna 7 and got the following error:

`workspaces/micronaut-devcontainer/graphene/node_modules/graphene-pk11/build/cjs/session.js:193 throw e; ^

TypeError: Cannot read property 'toUpperCase' of undefined at Function.create (/workspaces/micronaut-devcontainer/graphene/node_modules/graphene-pk11/build/cjs/mech.js:48:57) at Session.generateKeyPair (/workspaces/micronaut-devcontainer/graphene/node_modules/graphene-pk11/build/cjs/session.js:155:44) at Object. (/workspaces/micronaut-devcontainer/graphene/test.js:10:20) at Module._compile (internal/modules/cjs/loader.js:1063:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10) at Module.load (internal/modules/cjs/loader.js:928:32) at Function.Module._load (internal/modules/cjs/loader.js:769:14) at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12) at internal/main/run_main_module.js:17:47`

I assume it doesn't like the hex mechanism with out some additional code changes.

microshine commented 3 years ago

0x80000c01 is a vendor mechanism. You need to register that mechanism in graphene first.

Mechanism.vendor("CustomName", 0x80000c01);

But I think it's an issue. graphene must work with a direct mechanism value

microshine commented 3 years ago

I opened issue #144 to solve the mechanism problem

microshine commented 3 years ago

@zosocanuck I published the new version. Please try graphene-pk11@2.2.2

sonkkeli commented 1 year ago

For the ones running into this same issue, one can use raw values like this to support ed25519 signing using graphene:

Also note that update() is not supported for ed25519 keys and signing has to be done once only.

And SoftHSM2 needs to be configured and compiled locally with the following flags: ./configure --with-openssl=/usr/lib/ssl --enable-eddsa=yes

// https://github.com/opendnssec/SoftHSMv2/blob/35938595f83923504751b40535570342f706a634/src/lib/pkcs11/pkcs11.h#L405
const CKK_EC_EDWARDS = 0x40;

// https://github.com/opendnssec/SoftHSMv2/blob/35938595f83923504751b40535570342f706a634/src/lib/pkcs11/pkcs11.h#L888
const CKM_EC_EDWARDS_KEY_PAIR_GEN = 0x1055;

// https://github.com/opendnssec/SoftHSMv2/blob/35938595f83923504751b40535570342f706a634/src/lib/pkcs11/pkcs11.h#L809
const CKM_EDDSA = 0x1057;

// https://github.com/opendnssec/SoftHSMv2/blob/35938595f83923504751b40535570342f706a634/src/lib/crypto/OSSLUtil.cpp#L190
const NAMED_CURVE_FOR_EDWARDS_25519 = Buffer.from("130C656477617264733235353139", "hex"); 

var keys = session.generateKeyPair(
    CKM_EC_EDWARDS_KEY_PAIR_GEN,
    {
      keyType: CKK_EC_EDWARDS,
      token: true,
      private: false,
      encrypt: false,
      verify: true,
      derive: false,
      paramsEC: NAMED_CURVE_FOR_EDWARDS_25519,
      modifiable: false,
      label: "Generated EC Edwards pubK",
    },
    {
      keyType: CKK_EC_EDWARDS,
      token: true,
      private: false,
      sensitive: true,
      decrypt: false,
      sign: true,
      derive: false,
      modifiable: false,
      extractable: false,
      label: "Generated EC Edwards privK",
    }
  );

  // sign content
  const dataToSign = "helloworld";
  var sign = session.createSign(CKM_EDDSA, keys.privateKey);
  var signature = sign.once(dataToSign);

  // verify content
  var verify = session.createVerify(CKM_EDDSA, keys.publicKey);
  var verify_result = verify.once(dataToSign, signature);
  console.log("Signature:", signature.toString("hex"), " isVerified= ", verify_result);

  session.logout();
  session.close();
PadaliaIsha commented 10 months ago

@sonkkeli, your code is working and I get keypair using the ed25519 algo. But can I get this key in Solana blockchain keypair format? Below is the code.

            const pkcs11PublicKey = keys.publicKey.toString('hex'); // Convert to string
            const publicKeyBytes = Buffer.from(pkcs11PublicKey, 'hex');
            console.log(publicKeyBytes.toString('utf8'));
            const publicKey = publicKeyBytes.slice(1); // Remove the first byte (0x40)
            // console.log(publicKeyBytes.toString('utf8'));

            // Convert PKCS11 private key to Solana readable form
            const pkcs11PrivateKey = keys.privateKey.toString('hex'); // Convert to string
            const privateKeyBytes = Buffer.from(pkcs11PrivateKey, 'hex');
            const privateKey = privateKeyBytes.slice(1); // Remove the first byte (0x40)

            console.log(privateKeyBytes.toString('utf8'));