Topic: Raw Koblitz PrivateKey to ecc_key?

Apologies if this has been answered here before..

I'm having trouble figuring out how to create an`ecc_key` from a Raw Koblitz/SECP256K1 PrivateKey 32-byte-array.

I'm able to generate new keypairs and perform Ecdsa signing operations just fine,
but I'm absolutely stumped on how I can get an `ecc_key` from a raw privateKey.

My use case doesn't involve cert files, and typically sees the privateKey being derived from a Sha256 hash of a given input.

e.g.
[code]
const char *passphrase = "this is a top secret passphrase";

// Sha256(passphrase) -> privateKey[32];

// pkHex = "d8839c2432bfd0a67ef10a804ba991eabba19f154a3d707917681d45822a5712"
const uint8_t privateKey[32] = { 216, 131, 156, 36, 50, 191, 208, 166, 126, 241, 10, 128, 75, 169, 145, 234, 187, 161, 159, 21, 74, 61, 112, 121, 23, 104, 29, 69, 130, 42, 87, 18 };

ecc_key key;

//  <-- Where my brain throws an exception and I stare blankly at the API

Share

Re: Raw Koblitz PrivateKey to ecc_key?

Hi @sleepdefic1t,

Thanks for reaching out to wolfSSL. To get you started down the correct path I would suggest looking at wc_PBKD2. This is a password based key derivation function.

You could use it to generate ECC k value and then read k in with

ret = mp_read_unsigned_bin(&key->k, key, keySz);)

NOTE: You will want to add a sanity check that the generated K is less than the curve order (See "ecc_set_type" in ecc.h)

Next you'll need to call

wc_ecc_make_pub

to make the public portion of the key.

Finally since you are using any old passphrase and hashing it, using the hash to generate K with password based key derivation and then reading that into the key you can't really be sure that it's a valid K that lands somewhere on the curve right? So now you'll want to check the key you created is valid. For that use

wc_ecc_check_key

. Fail condition is if wc_ecc_check_key fails, need to either ask user for new input or come up with a method for adjusting the hash of the user input when used to generate K will more consistently fall on the curve.

Hope this helps.

Warm Regards,

K

Re: Raw Koblitz PrivateKey to ecc_key?

@Kaleb

Thank you for the advice!

I had some time to loop back around and see what I can come up with.

I'm able to import the PrivateKey successfully, but am not able to generate Signatures deterministically.


I'm using RFC6979, and I am able to generate the nonce32 successfully.

The PrivateKey is now importing successfully.

Making the PublicKey appears to complete successfully as `wc_ecc_check_key` passes.

Signing and Verifying are successful, but the signatures are non-deterministic/change with every run.


No signatures have matched my test fixtures, which pass on libs like SECP256K1, BCrypto, BCL, etc.


Here's the example method I'm working on.

int signEcdsa(const uint8_t *hash32, const uint8_t* privateKeyBytes, uint8_t *outSignature) {
    WC_RNG      rng;
    byte*       keyBuf = (byte*)privateKeyBytes;
    ecc_key     keys;

    int ret     = 0;

    byte nonce32[32];
    nonce_function_rfc6979(nonce32,hash32, privateKeyBytes);
    // for (uint8_t i = 0U; i < 32; ++i) {
    //     printf("%02x", nonce32[i]);
    // }
    // nonce32: f698e12b30c6b7f3f44af3400c870911e8083061d7a0220df010efb97f560fc8


    ret = wc_InitRngNonce(&rng, nonce32, 32);
    printf("\nwc_InitRngNonce | ret: %d\n", ret);
    if (ret != 0) {
        return ret;
    }

    ret = wc_ecc_init(&keys);
    printf("\nwc_ecc_init | ret: %d\n", ret);
    if (ret != 0) {
        return ret;
    }

    ret = wc_ecc_import_private_key(privateKeyBytes, 32, NULL, 0, &keys);
    printf("\nwc_ecc_import_private_key | ret: %d\n", ret);
    if (ret != 0) {
        return ret;
    }


    // byte eccPrivKeyBuf[ECC_BUFSIZE];
    // word32 pkLen = 32;
    // ret = wc_ecc_export_private_only(&keys, eccPrivKeyBuf, &pkLen);
    // if (ret != 0) {
    //     printf("\nwc_ecc_export_private_only - ret: %d\n", ret);
    //     return ret;
    // }
    // for (uint8_t i = 0U; i < 32; ++i) {
    //     printf("%02x", eccPrivKeyBuf[i]);
    // }
    // privateKey Hex: d8839c2432bfd0a67ef10a804ba991eabba19f154a3d707917681d45822a5712


    ret = wc_ecc_make_pub(&keys, &keys.pubkey);
    printf("\nwc_ecc_make_pub | ret: %d\n", ret);
    if (ret != 0) {
        return ret;
    }

    ret = wc_ecc_check_key(&keys);
    printf("\nwc_ecc_check_key | ret: %d\n", ret);
    if (ret != 0) {
        return ret;
    }

    word32 sigLen = 72;
    ret = wc_ecc_sign_hash(hash32, 32, outSignature, &sigLen, &rng, &keys);
    printf("\nwc_ecc_sign_hash | ret %d | sigLen %d\n", ret, sigLen);
    if (ret != 0) {
        return ret;
    }

    int is_valid_sig = 0;
    ret = wc_ecc_verify_hash(outSignature, sigLen, hash32, 32, &is_valid_sig, &keys);
    printf("\nwc_ecc_verify_hash | ret %d | is_valid_sig %d\n", ret, is_valid_sig);
    if (ret != 0) {
        return ret;
    }

    wc_FreeRng(&rng);

    return ret;
}

There are a lot more checks that would need to be in place in a final implementation, but I have no idea where to go next.

Thank you again, and I'm open to any advice!!

Share

4 (edited by Kaleb J. Himes 2019-10-31 15:52:32)

Re: Raw Koblitz PrivateKey to ecc_key?

Hi @sleepdefic1t,

I'm able to import the PrivateKey successfully, but am not able to generate Signatures deterministically.

Great! That indicates it is working. If the signature were deterministic that would be cause for concern.

ECC (unlike RSA) does not produce the same output every time, nor does it produce the same length every time! ECC signatures can vary by as much as 5-bytes (sometime more). IE you might sign the same data 100 times and see signatures that range from 70 - 75 bytes in length. This is expected and common with ECC. I see you are already doing a sanity check using the verify to double-check the signature, that is good! Below are a series of signature generation/verification calls on the same exact input data I ran locally. (You can also use a third party verify operation if you want to triple check it.)


Hexdump: Signature of length 71
Should output 4 lines
3045022073e648793a98424f345c06f0a6
63f406b82a3321702e692c0d6926fefa
681183022100a2fb9275f9b61f253564
26c745e6be56e43f134953931b54edbd
cefd802bf17c

Signature verification was successful!
Hexdump: Signature of length 70
Should output 4 lines
30440220106f09553c87c6a6622403503d
28b6469280d735207d29f614ec0da823
33608702204f0549bb242fb69e9939f5
f269f0720f624288ce9ae4d5dd27a304
fc84c63f8a

Signature verification was successful!
Hexdump: Signature of length 72
Should output 4 lines
304602210092aa287e79f309f686e98108
d11a0851b91ea9556e55954c7cfd2c49
97f6ca1c022100b3876fec6dcddc6546
a57d12fc0bd8e17930fd2af9f1049c77
fead7eba57e9c6

Signature verification was successful!
Hexdump: Signature of length 70
Should output 4 lines
304402205268f74dec640c683a92bde39c
a3125fa3b52cf54ab8f4439676a7bf9d
87a11a022065ab167156d580a328068f
1acd4de3fc35cf61e5b8df41c618466e
a9637cea3c

Signature verification was successful!
Hexdump: Signature of length 71
Should output 4 lines
304502207819fa3c308d7337b13c232fc9
a0b4d6ae7d1432fcdbd57b116d1a9aef
6da855022100ad65c70fd7fec03b70a7
5708d1512f08c98e3b7ecf84b4974ab3
7d0c3053f0ad

Signature verification was successful!

Warm Regards,

K