construction of ES256KSigner throws mis-match private key length

87 Views Asked by At

I tried to build a siger to sign a verifiable credential using jwt format. But the construct of ES256KSigner fails Invalid private key format. Expecting 32 bytes, but got 43. I am not familar with cryption, and only guess there is some wrong understanding for hte d in the privateJwk. Thanks if you can help correct me.

My sample code:

import { anchor, DID, generateKeyPair } from '@decentralized-identity/ion-tools';
import { ES256KSigner, hexToBytes } from 'did-jwt';
  let authKeys = await generateKeyPair();
  console.log("generate key: ", authKeys)
   //The d field in the privaeteJwk is private key and used for signer construction.
  let signer = ES256KSigner(authKeys.privateJwk.d)

And the output:

generate key:  {
  publicJwk: {
    kty: 'EC',
    crv: 'secp256k1',
    x: 'AgykbSMim_qMMlo0Lh2DucKZ3XwpvGh6qv4BXQo1lxE',
    y: 'X_7mp4aTLjYQuxdSgEpb-3RtCgLeevp6FG34HwC5XjQ'
  },
  privateJwk: {
    kty: 'EC',
    crv: 'secp256k1',
    x: 'AgykbSMim_qMMlo0Lh2DucKZ3XwpvGh6qv4BXQo1lxE',
    y: 'X_7mp4aTLjYQuxdSgEpb-3RtCgLeevp6FG34HwC5XjQ',
    d: 'tcGhsoByPlNppNLQxr_hFNAR7lGhB1JW_SFo4rxTZpo'
  }
}
file:///work/did/did_demo/node_modules/did-jwt/lib/index.module.js:184
    throw new Error(`bad_key: Invalid private key format. Expecting 32 bytes, but got ${privateKeyBytes.length}`);
          ^

Error: bad_key: Invalid private key format. Expecting 32 bytes, but got 43
    at ES256KSigner (file:///work/did/did_demo/node_modules/did-jwt/lib/index.module.js:184:11)
    at file:///work/did/did_demo/issuer.js:13:16

The version information:

   "@decentralized-identity/ion-tools": "^1.0.7",
    "did-jwt": "^7.2.2",
    "did-jwt-vc": "^3.2.3",
    "elliptic": "^6.5.4",
    "express": "^4.18.2"

After checking generateKeypair in https://github.com/decentralized-identity/ion-tools/blob/main/src/utils.js and conform it uses secp256k1 Code to generate key

And the construction of ES256KSigner from the link https://github.com/decentralized-identity/did-jwt/blob/master/docs/guides/index.md#signer-functions

=================Workaround===========

After checking the source code further, I findally use the Workaround like this:

import { base64url } from 'multiformats/bases/base64';
let privateKey = base64url.baseDecode(this.authnKeys.privateJwk.d);
let signer = ES256KSigner(privateKey)

This is caused by some inconsistence as talked by Topaco.

1

There are 1 best solutions below

0
On BEST ANSWER

In the JWK the raw private key (d) is Base64url encoded, so your code should work, since according to the documentation for version 7.2.2 the key can also be passed Base64url encoded to ES256KSigner().

Unfortunately, the documentation is not consistent with the code for version 7.2.2, which states that the key can only be passed as a Uint8Array. This leads to the exception, which is thrown directly in ES256KSigner(), after a failed length check of the key.

Note that in earlier versions it was indeed possible to pass a Base64url encoded key (e.g. in version 5.12.4), but this has been changed as of version 6.0.0. Apparently, the documentation was simply not adapted in this process.

The Base64url decoding required in version 7.2.2 is supported with the helper function base64ToBytes():

let signer = ES256KSigner(base64ToBytes(authKeys.privateJwk.d)); 

With this fix the key import works.